1
0
Fork 0
mirror of https://github.com/luanti-org/luanti.git synced 2025-09-30 19:22:14 +00:00

Make Luanti buildable for iOS (iPhoneSimulator) with ANGLE and basic CI.

This commit is contained in:
SFENCE 2024-11-18 13:21:02 +01:00
parent 5672b93007
commit 803870e0d2
28 changed files with 568 additions and 36 deletions

61
.github/workflows/ios.yml vendored Normal file
View file

@ -0,0 +1,61 @@
name: iOS
# build on c/cpp changes or workflow changes
on:
push:
paths:
- 'lib/**.[ch]'
- 'lib/**.cpp'
- 'src/**.[ch]'
- 'src/**.cpp'
- 'irr/**.[ch]'
- 'irr/**.cpp'
- '**/CMakeLists.txt'
- 'cmake/Modules/**'
- 'po/**.po'
- '.github/workflows/ios.yml'
pull_request:
paths:
- 'lib/**.[ch]'
- 'lib/**.cpp'
- 'src/**.[ch]'
- 'src/**.cpp'
- 'irr/**.[ch]'
- 'irr/**.cpp'
- '**/CMakeLists.txt'
- 'cmake/Modules/**'
- 'po/**.po'
- '.github/workflows/ios.yml'
jobs:
build-ios:
strategy:
matrix:
osver: [18.2]
xcodever: [16.2]
runs-on: macos-15
steps:
- uses: actions/checkout@v4
- name: Prepare environment
run: |
echo "REPDIR=$(pwd)" >> $GITHUB_ENV
echo "osver=${{matrix.osver}}" >> $GITHUB_ENV
echo "xcodever=${{matrix.xcodever}}" >> $GITHUB_ENV
- name: Install deps
run: |
source ./util/ci/common.sh
install_ios_deps $osver
- name: Build and Archive with Xcode
run: |
mkdir build
cd build
export DEPS_DIR=${REPDIR}/ios${osver}_deps/iPhoneSimulator
../util/ci/build_ios.sh
- name: Run in iPhoneSimulator
run: |
./util/ci/run_ios.sh "iPad Air 13-inch (M2)" 150
cat log.txt

View file

@ -1,5 +1,8 @@
mark_as_advanced(ZSTD_LIBRARY ZSTD_INCLUDE_DIR) mark_as_advanced(ZSTD_LIBRARY ZSTD_INCLUDE_DIR)
message(STATUS "ZSTD_LIBRARY: ${ZSTD_LIBRARY}")
message(STATUS "ZSTD_INCLUDE_DIR: ${ZSTD_INCLUDE_DIR}")
find_path(ZSTD_INCLUDE_DIR NAMES zstd.h) find_path(ZSTD_INCLUDE_DIR NAMES zstd.h)
find_library(ZSTD_LIBRARY NAMES zstd) find_library(ZSTD_LIBRARY NAMES zstd)

View file

@ -24,6 +24,7 @@ General options and their default values:
PRECOMPILED_HEADERS_PATH= - Path to a file listing all headers to precompile (default points to src/precompiled_headers.txt) PRECOMPILED_HEADERS_PATH= - Path to a file listing all headers to precompile (default points to src/precompiled_headers.txt)
USE_SDL2=TRUE - Build with SDL2; Enables IrrlichtMt device SDL2 USE_SDL2=TRUE - Build with SDL2; Enables IrrlichtMt device SDL2
USE_SDL2_STATIC=TRUE - Links with SDL2::SDL2-static instead of SDL2::SDL2 USE_SDL2_STATIC=TRUE - Links with SDL2::SDL2-static instead of SDL2::SDL2
USE_ANGLE=TRUE - Build with Google ANGLE; IrrlichMt device SDL2 on iOS
ENABLE_CURL=ON - Build with cURL; Enables use of online mod repo, public serverlist and remote media fetching via http ENABLE_CURL=ON - Build with cURL; Enables use of online mod repo, public serverlist and remote media fetching via http
ENABLE_CURSES=ON - Build with (n)curses; Enables a server side terminal (command line option: --terminal) ENABLE_CURSES=ON - Build with (n)curses; Enables a server side terminal (command line option: --terminal)
ENABLE_GETTEXT=ON - Build with Gettext; Allows using translations ENABLE_GETTEXT=ON - Build with Gettext; Allows using translations

34
doc/compiling/ios.md Normal file
View file

@ -0,0 +1,34 @@
# Compiling for iOS
THIS DOCUMENT IS NOT FINISHED!!!
## Requirements
- macOS
- [Homebrew](https://brew.sh/)
- XCode
- iOS/IPhoneSimulator SDK
- iOS Simulator for newest iOS is supported only on Apple Silicon deviecs.
Install dependencies with homebrew:
```
brew install cmake git
```
## Generate Xcode project
This script will download and build all requested dependencies for iOS or IPhoneSimulator and generate Xcode project for Luanti.
```bash
/path/to/ios_build_with_deps.sh https://github.com/luanti-org/luanti.git master ../luanti_ios ../luanti_ios_deps Debug "iPhoneSimulator" "18.2" "all"
```
### Build and Run
* Open generated Xcode project
* Select scheme `luanti`
* Configure signing Team etc.
* Run Build command
* Open application from `build/build/Debug/` directory or run it from Xcode

View file

@ -32,6 +32,7 @@ We aim to support these platforms:
* Windows via MinGW * Windows via MinGW
* Linux (GL or GLES) * Linux (GL or GLES)
* macOS * macOS
* iOS (GLES)
* Android * Android
This doesn't mean other platforms don't work or won't be supported, if you find something that doesn't work contributions are welcome. This doesn't mean other platforms don't work or won't be supported, if you find something that doesn't work contributions are welcome.
@ -51,7 +52,7 @@ Driver (rows) vs Device (columns)
Notes: Notes:
* [1] `CIrrDeviceSDL`: supports Android, Linux, macOS, Windows * [1] `CIrrDeviceSDL`: supports Android, Linux, macOS, iOS, Windows
* [2] `CIrrDeviceLinux`: supports Linux * [2] `CIrrDeviceLinux`: supports Linux
* [3] `CIrrDeviceOSX`: supports macOS * [3] `CIrrDeviceOSX`: supports macOS
* [4] `CIrrDeviceWin32`: supports Windows * [4] `CIrrDeviceWin32`: supports Windows

View file

@ -22,7 +22,7 @@
#include <direct.h> // for _chdir #include <direct.h> // for _chdir
#include <io.h> // for _access #include <io.h> // for _access
#include <tchar.h> #include <tchar.h>
#elif (defined(_IRR_POSIX_API_) || defined(_IRR_OSX_PLATFORM_) || defined(_IRR_ANDROID_PLATFORM_)) #elif (defined(_IRR_POSIX_API_) || defined(_IRR_OSX_PLATFORM_) || defined(_IRR_IOS_PLATFORM_) || defined(_IRR_ANDROID_PLATFORM_) )
#include <cstdio> #include <cstdio>
#include <cstdlib> #include <cstdlib>
#include <cstring> #include <cstring>

View file

@ -1,4 +1,5 @@
// Copyright (C) 2002-2012 Nikolaus Gebhardt // Copyright (C) 2002-2012 Nikolaus Gebhardt
// Copyright (C) 2025 Luanti contributors
// This file is part of the "Irrlicht Engine". // This file is part of the "Irrlicht Engine".
// For conditions of distribution and use, see copyright notice in irrlicht.h // For conditions of distribution and use, see copyright notice in irrlicht.h
@ -29,6 +30,13 @@
#include "CSDLManager.h" #include "CSDLManager.h"
#ifdef _IRR_COMPILE_WITH_ANGLE_
#include <EGL/egl.h>
#include <EGL/eglext.h>
#include <GLES2/gl2.h>
#include <GLES3/gl3.h>
#endif
// Since SDL doesn't have mouse keys as keycodes we need to fall back to EKEY_CODE in some cases. // Since SDL doesn't have mouse keys as keycodes we need to fall back to EKEY_CODE in some cases.
static inline bool is_fake_key(EKEY_CODE key) { static inline bool is_fake_key(EKEY_CODE key) {
switch (key) { switch (key) {
@ -409,13 +417,32 @@ CIrrDeviceSDL::~CIrrDeviceSDL()
for (u32 i = 0; i < numJoysticks; ++i) for (u32 i = 0; i < numJoysticks; ++i)
SDL_JoystickClose(Joysticks[i]); SDL_JoystickClose(Joysticks[i]);
#endif #endif
#ifndef _IRR_COMPILE_WITH_ANGLE_
if (Window && Context) { if (Window && Context) {
SDL_GL_MakeCurrent(Window, NULL); SDL_GL_MakeCurrent(Window, NULL);
SDL_GL_DeleteContext(Context); SDL_GL_DeleteContext(Context);
} }
#else
if (Display != EGL_NO_DISPLAY) {
eglMakeCurrent(Display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
}
if (Surface != EGL_NO_SURFACE) {
eglDestroySurface(Display, Surface);
}
if (Context != EGL_NO_CONTEXT) {
eglDestroyContext(Display, Context);
}
if (Display != EGL_NO_DISPLAY) {
eglTerminate(Display);
}
if (View) {
SDL_Metal_DestroyView(View);
}
if (Window) { if (Window) {
SDL_DestroyWindow(Window); SDL_DestroyWindow(Window);
} }
#endif
if (--SDLDeviceInstances == 0) { if (--SDLDeviceInstances == 0) {
SDL_Quit(); SDL_Quit();
@ -529,21 +556,9 @@ bool CIrrDeviceSDL::createWindow()
return false; return false;
} }
bool CIrrDeviceSDL::createWindowWithContext()
{
u32 SDL_Flags = 0;
SDL_Flags |= SDL_WINDOW_ALLOW_HIGHDPI;
SDL_Flags |= getFullscreenFlag(CreationParams.Fullscreen);
if (Resizable)
SDL_Flags |= SDL_WINDOW_RESIZABLE;
if (CreationParams.WindowMaximized)
SDL_Flags |= SDL_WINDOW_MAXIMIZED;
SDL_Flags |= SDL_WINDOW_OPENGL;
SDL_GL_ResetAttributes();
#ifdef _IRR_EMSCRIPTEN_PLATFORM_ #ifdef _IRR_EMSCRIPTEN_PLATFORM_
bool CIrrDeviceSDL::createWindowWithContextEmscripten()
{
if (Width != 0 || Height != 0) if (Width != 0 || Height != 0)
emscripten_set_canvas_size(Width, Height); emscripten_set_canvas_size(Width, Height);
else { else {
@ -581,7 +596,11 @@ bool CIrrDeviceSDL::createWindowWithContext()
emscripten_set_mouseleave_callback("#canvas", (void *)this, false, MouseLeaveCallback); emscripten_set_mouseleave_callback("#canvas", (void *)this, false, MouseLeaveCallback);
return true; return true;
#else // !_IRR_EMSCRIPTEN_PLATFORM_ }
#else // _IRR_EMSCRIPTEN_PLATFORM_
#ifndef _IRR_COMPILE_WITH_ANGLE_
bool CIrrDeviceSDL::createWindowWithContextSDL()
{
switch (CreationParams.DriverType) { switch (CreationParams.DriverType) {
case video::EDT_OPENGL: case video::EDT_OPENGL:
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 2); SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 2);
@ -629,7 +648,12 @@ bool CIrrDeviceSDL::createWindowWithContext()
SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, 0); SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, 0);
} }
Window = SDL_CreateWindow("", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, Width, Height, SDL_Flags); if (!SDL_GL_LoadLibrary(NULL)) {
os::Printer::log("Could not load OpenGL ES library", SDL_GetError(), ELL_WARNING);
return false;
}
Window = SDL_CreateWindow("", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, Width, Height, SDL_WINDOW_OPENGL | SDL_WINDOW_ALLOW_HIGHDPI);
if (!Window) { if (!Window) {
os::Printer::log("Could not create window", SDL_GetError(), ELL_WARNING); os::Printer::log("Could not create window", SDL_GetError(), ELL_WARNING);
return false; return false;
@ -643,6 +667,121 @@ bool CIrrDeviceSDL::createWindowWithContext()
return false; return false;
} }
int major, minor;
SDL_GL_GetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, &major);
SDL_GL_GetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, &minor);
os::Printer::log("OpenGL ES version", std::to_string(major) + "." + std::to_string(minor), ELL_INFORMATION);
const char* error = SDL_GetError();
if (*error != '\0') {
os::Printer::log("SDL Error", error, ELL_WARNING);
SDL_ClearError();
}
}
#else // _IRR_COMPILE_WITH_ANGLE_
bool CIrrDeviceSDL::createWindowWithContextANGLE()
{
Window = SDL_CreateWindow("", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, Width, Height, SDL_WINDOW_METAL | SDL_WINDOW_ALLOW_HIGHDPI);
if (!Window) {
os::Printer::log("Could not create window", SDL_GetError(), ELL_WARNING);
return false;
}
auto metal_view = SDL_Metal_CreateView(Window);
auto metal_layer = SDL_Metal_GetLayer(metal_view);
EGLAttrib egl_display_attribs[] = {
EGL_PLATFORM_ANGLE_TYPE_ANGLE, EGL_PLATFORM_ANGLE_TYPE_METAL_ANGLE,
EGL_POWER_PREFERENCE_ANGLE, EGL_HIGH_POWER_ANGLE,
EGL_NONE
};
Display = eglGetPlatformDisplay(EGL_PLATFORM_ANGLE_ANGLE, (void*) EGL_DEFAULT_DISPLAY, egl_display_attribs);
if (Display == EGL_NO_DISPLAY)
{
os::Printer::log("Failed to get EGL display");
return false;
}
if (eglInitialize(Display, NULL, NULL) == false)
{
os::Printer::log("Failed to initialize EGL");
return false;
}
EGLint egl_config_attribs[] = {
EGL_RED_SIZE, (CreationParams.Bits == 16 ? 5 : 8),
EGL_GREEN_SIZE, (CreationParams.Bits == 16 ? 5 : 8),
EGL_BLUE_SIZE, (CreationParams.Bits == 16 ? 5 : 8),
EGL_ALPHA_SIZE, (CreationParams.WithAlphaChannel ? (CreationParams.Bits == 16 ? 1 : 8) : 0),
EGL_DEPTH_SIZE, CreationParams.ZBufferBits,
EGL_STENCIL_SIZE, CreationParams.Stencilbuffer ? 8 : 0,
EGL_SAMPLE_BUFFERS, CreationParams.AntiAlias > 1 ? 1 : 0,
EGL_SAMPLES, CreationParams.AntiAlias > 1 ? CreationParams.AntiAlias : 0,
EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
EGL_RENDERABLE_TYPE, EGL_OPENGL_ES3_BIT,
EGL_NONE
};
EGLConfig config;
EGLint configs_count;
if (!eglChooseConfig(Display, egl_config_attribs, &config, 1, &configs_count))
{
os::Printer::log("Failed to choose EGL config");
return false;
}
EGLint egl_context_attribs[] = {
EGL_CONTEXT_CLIENT_VERSION, 3,
EGL_NONE
};
Context = eglCreateContext(Display, config, EGL_NO_CONTEXT, egl_context_attribs);
if (Context == EGL_NO_CONTEXT) {
os::Printer::log("Failed to create EGL context");
return false;
}
Surface = eglCreateWindowSurface(Display, config, metal_layer, NULL);
if (Surface == EGL_NO_SURFACE)
{
os::Printer::log("Failed to create EGL surface");
return false;
}
if (!eglMakeCurrent(Display, Surface, Surface, Context))
{
os::Printer::log("Failed to make EGL context current");
return false;
}
}
#endif // _IRR_COMPILE_WITH_ANGLE_
#endif // _IRR_EMSCRIPTEN_PLATFORM_
bool CIrrDeviceSDL::createWindowWithContext()
{
u32 SDL_Flags = 0;
SDL_Flags |= SDL_WINDOW_ALLOW_HIGHDPI;
SDL_Flags |= getFullscreenFlag(CreationParams.Fullscreen);
if (Resizable)
SDL_Flags |= SDL_WINDOW_RESIZABLE;
if (CreationParams.WindowMaximized)
SDL_Flags |= SDL_WINDOW_MAXIMIZED;
SDL_Flags |= SDL_WINDOW_OPENGL;
//SDL_Flags |= SDL_WINDOW_METAL;
SDL_GL_ResetAttributes();
#ifdef _IRR_EMSCRIPTEN_PLATFORM_
createWindowWithContextEmscripten();
#else // !_IRR_EMSCRIPTEN_PLATFORM_
#ifndef _IRR_COMPILE_WITH_ANGLE_
createWindowWithContextSDL();
#else
createWindowWithContextANGLE();
#endif
updateSizeAndScale(); updateSizeAndScale();
if (ScaleX != 1.0f || ScaleY != 1.0f) { if (ScaleX != 1.0f || ScaleY != 1.0f) {
// The given window size is in pixels, not in screen coordinates. // The given window size is in pixels, not in screen coordinates.
@ -1161,7 +1300,11 @@ float CIrrDeviceSDL::getDisplayDensity() const
void CIrrDeviceSDL::SwapWindow() void CIrrDeviceSDL::SwapWindow()
{ {
#ifndef _IRR_COMPILE_WITH_ANGLE_
SDL_GL_SwapWindow(Window); SDL_GL_SwapWindow(Window);
#else
eglSwapBuffers(Display, Surface);
#endif
} }
//! pause execution temporarily //! pause execution temporarily

View file

@ -23,6 +23,10 @@
#undef SDL_VIDEO_DRIVER_DIRECTFB #undef SDL_VIDEO_DRIVER_DIRECTFB
#include <SDL_syswm.h> #include <SDL_syswm.h>
#ifdef _IRR_COMPILE_WITH_ANGLE_
#include <EGL/egl.h>
#endif
#include <memory> #include <memory>
#include <unordered_map> #include <unordered_map>
@ -302,13 +306,30 @@ private:
void createDriver(); void createDriver();
bool createWindow(); bool createWindow();
#ifdef _IRR_EMSCRIPTEN_PLATFORM_
bool createWindowWithContextEmscripten();
#else // _IRR_EMSCRIPTEN_PLATFORM_
#ifndef _IRR_COMPILE_WITH_ANGLE_
bool createWindowWithContextSDL();
#else // _IRR_COMPILE_WITH_ANGLE_
bool createWindowWithContextANGLE();
#endif // _IRR_COMPILE_WITH_ANGLE_
#endif // _IRR_EMSCRIPTEN_PLATFORM_
bool createWindowWithContext(); bool createWindowWithContext();
void createKeyMap(); void createKeyMap();
void logAttributes(); void logAttributes();
SDL_GLContext Context;
SDL_Window *Window; SDL_Window *Window;
#ifndef _IRR_COMPILE_WITH_ANGLE_
SDL_GLContext Context;
#else
SDL_MetalView View;
EGLSurface Surface;
EGLContext Context;
EGLDisplay Display;
#endif
#if defined(_IRR_COMPILE_WITH_JOYSTICK_EVENTS_) #if defined(_IRR_COMPILE_WITH_JOYSTICK_EVENTS_)
core::array<SDL_Joystick *> Joysticks; core::array<SDL_Joystick *> Joysticks;
#endif #endif

View file

@ -1,6 +1,11 @@
set(DEFAULT_SDL2 ON) set(DEFAULT_SDL2 ON)
if(APPLE AND CMAKE_SYSTEM_NAME STREQUAL "iOS")
set(DEFAULT_ANGLE ON)
endif()
option(USE_SDL2 "Use the SDL2 backend" ${DEFAULT_SDL2}) option(USE_SDL2 "Use the SDL2 backend" ${DEFAULT_SDL2})
option(USE_ANGLE "Use the Google ANGLE EGL and OpenGL ES" ${DEFAULT_ANGLE})
option(USE_SDL2_STATIC "Link with SDL2 static libraries" FALSE) option(USE_SDL2_STATIC "Link with SDL2 static libraries" FALSE)
@ -64,8 +69,17 @@ if(WIN32)
add_compile_definitions(_IRR_WINDOWS_ _IRR_WINDOWS_API_) add_compile_definitions(_IRR_WINDOWS_ _IRR_WINDOWS_API_)
set(DEVICE "WINDOWS") set(DEVICE "WINDOWS")
elseif(APPLE) elseif(APPLE)
add_compile_definitions(_IRR_OSX_PLATFORM_) if(CMAKE_SYSTEM_NAME STREQUAL "Darwin")
add_compile_definitions(-D_IRR_OSX_PLATFORM_)
set(DEVICE "OSX") set(DEVICE "OSX")
elseif(CMAKE_SYSTEM_NAME STREQUAL "iOS")
add_compile_definitions(-D_IRR_IOS_PLATFORM_)
if(NOT USE_SDL2)
message(FATAL_ERROR "The iOS build requires SDL2")
endif()
else()
message(FATAL_ERROR "Not supported Apple device.")
endif()
elseif(ANDROID) elseif(ANDROID)
add_compile_definitions(_IRR_ANDROID_PLATFORM_) add_compile_definitions(_IRR_ANDROID_PLATFORM_)
if(NOT USE_SDL2) if(NOT USE_SDL2)
@ -100,6 +114,10 @@ endif()
add_compile_definitions("_IRR_COMPILE_WITH_${DEVICE}_DEVICE_") add_compile_definitions("_IRR_COMPILE_WITH_${DEVICE}_DEVICE_")
if(USE_ANGLE)
add_definitions("-D_IRR_COMPILE_WITH_ANGLE_")
endif()
# X11 # X11
if(DEVICE STREQUAL "X11") if(DEVICE STREQUAL "X11")
@ -125,7 +143,7 @@ endif()
# OpenGL # OpenGL
if(USE_SDL2) if(USE_SDL2)
if(NOT ANDROID) if(NOT ANDROID AND NOT USE_ANGLE)
set(DEFAULT_OPENGL3 TRUE) set(DEFAULT_OPENGL3 TRUE)
endif() endif()
else() else()
@ -133,17 +151,17 @@ else()
endif() endif()
option(ENABLE_OPENGL3 "Enable OpenGL 3+" ${DEFAULT_OPENGL3}) option(ENABLE_OPENGL3 "Enable OpenGL 3+" ${DEFAULT_OPENGL3})
if(ANDROID OR EMSCRIPTEN) if(ANDROID OR EMSCRIPTEN OR USE_ANGLE)
set(ENABLE_OPENGL FALSE) set(ENABLE_OPENGL FALSE)
else() else()
option(ENABLE_OPENGL "Enable OpenGL" TRUE) option(ENABLE_OPENGL "Enable OpenGL" TRUE)
endif() endif()
if(APPLE) if(APPLE AND NOT CMAKE_SYSTEM_NAME STREQUAL "iOS")
set(ENABLE_GLES2 FALSE) set(ENABLE_GLES2 FALSE)
set(ENABLE_WEBGL1 FALSE) set(ENABLE_WEBGL1 FALSE)
else() else()
if(ANDROID OR EMSCRIPTEN) if(ANDROID OR EMSCRIPTEN OR USE_ANGLE)
set(DEFAULT_GLES2 TRUE) set(DEFAULT_GLES2 TRUE)
endif() endif()
if(EMSCRIPTEN) if(EMSCRIPTEN)
@ -231,10 +249,10 @@ if(USE_SDL2)
if(NOT USE_SDL2_STATIC) if(NOT USE_SDL2_STATIC)
set(USE_SDL2_SHARED TRUE) set(USE_SDL2_SHARED TRUE)
endif() endif()
if(NOT ANDROID) if(NOT ANDROID AND NOT CMAKE_SYSTEM_NAME STREQUAL "iOS")
find_package(SDL2 REQUIRED) find_package(SDL2 REQUIRED)
else() else()
# provided by AndroidLibs.cmake # provided by AndroidLibs.cmake or from cmake call
endif() endif()
message(STATUS "Found SDL2: ${SDL2_LIBRARIES}") message(STATUS "Found SDL2: ${SDL2_LIBRARIES}")
@ -280,7 +298,7 @@ endif()
if(ANDROID) if(ANDROID)
enable_language(C) enable_language(C)
elseif(APPLE) elseif(APPLE AND NOT CMAKE_SYSTEM_NAME STREQUAL "iOS")
find_library(COCOA_LIB Cocoa REQUIRED) find_library(COCOA_LIB Cocoa REQUIRED)
find_library(IOKIT_LIB IOKit REQUIRED) find_library(IOKIT_LIB IOKit REQUIRED)
@ -600,6 +618,26 @@ target_link_libraries(IrrlichtMt PRIVATE
"$<$<BOOL:${USE_X11}>:${X11_Xi_LIB}>" "$<$<BOOL:${USE_X11}>:${X11_Xi_LIB}>"
) )
if(CMAKE_SYSTEM_NAME STREQUAL "iOS")
target_link_libraries(IrrlichtMt PRIVATE
"-framework UIKit"
"-framework Foundation"
"-framework CoreGraphics"
"-framework QuartzCore"
"-framework AudioToolbox"
"-framework AVFoundation"
"-framework CoreAudio"
"-framework CoreMotion"
"-framework IOSurface"
${OPENGLES2_LIBRARY}
${SDL2_LIBRARIES}
)
else()
target_link_libraries(IrrlichtMt PRIVATE
"$<$<BOOL:${USE_SDL2}>:SDL2::SDL2>"
)
endif()
if(WIN32) if(WIN32)
target_compile_definitions(IrrlichtMt INTERFACE _IRR_WINDOWS_API_) target_compile_definitions(IrrlichtMt INTERFACE _IRR_WINDOWS_API_)
endif() endif()

View file

@ -11,7 +11,7 @@
#include <unistd.h> #include <unistd.h>
#ifndef _IRR_ANDROID_PLATFORM_ #ifndef _IRR_ANDROID_PLATFORM_
#include <sys/types.h> #include <sys/types.h>
#ifdef _IRR_OSX_PLATFORM_ #if defined(_IRR_OSX_PLATFORM_) || defined(_IRR_IOS_PLATFORM_)
#include <sys/sysctl.h> #include <sys/sysctl.h>
#endif #endif
#endif #endif

View file

@ -33,7 +33,11 @@ bool CSDLManager::activateContext(const SExposedVideoData &videoData, bool resto
void *CSDLManager::getProcAddress(const std::string &procName) void *CSDLManager::getProcAddress(const std::string &procName)
{ {
#ifndef _IRR_COMPILE_WITH_ANGLE_
return SDL_GL_GetProcAddress(procName.c_str()); return SDL_GL_GetProcAddress(procName.c_str());
#else
return (void *)eglGetProcAddress(procName.c_str());
#endif
} }
bool CSDLManager::swapBuffers() bool CSDLManager::swapBuffers()

View file

@ -7,7 +7,7 @@
#include "irrTypes.h" #include "irrTypes.h"
// even though we have mt_opengl.h our driver code still uses GL_* constants // even though we have mt_opengl.h our driver code still uses GL_* constants
#if defined(_IRR_COMPILE_WITH_SDL_DEVICE_) #if defined(_IRR_COMPILE_WITH_SDL_DEVICE_) && !defined(_IRR_COMPILE_WITH_ANGLE_)
#include <SDL_video.h> #include <SDL_video.h>
#include <SDL_opengl.h> #include <SDL_opengl.h>
#else #else

View file

@ -23,6 +23,8 @@
#include "mt_opengl.h" #include "mt_opengl.h"
#include <iostream>
namespace video namespace video
{ {
@ -214,14 +216,20 @@ void COpenGL3DriverBase::initQuadsIndices(u32 max_vertex_count)
void COpenGL3DriverBase::initVersion() void COpenGL3DriverBase::initVersion()
{ {
TEST_GL_ERROR(this);
Name = GL.GetString(GL_VERSION); Name = GL.GetString(GL_VERSION);
TEST_GL_ERROR(this);
printVersion(); printVersion();
// print renderer information // print renderer information
TEST_GL_ERROR(this);
VendorName = GL.GetString(GL_RENDERER); VendorName = GL.GetString(GL_RENDERER);
TEST_GL_ERROR(this);
os::Printer::log("Renderer", VendorName.c_str(), ELL_INFORMATION); os::Printer::log("Renderer", VendorName.c_str(), ELL_INFORMATION);
TEST_GL_ERROR(this);
Version = getVersionFromOpenGL(); Version = getVersionFromOpenGL();
TEST_GL_ERROR(this);
} }
bool COpenGL3DriverBase::isVersionAtLeast(int major, int minor) const noexcept bool COpenGL3DriverBase::isVersionAtLeast(int major, int minor) const noexcept
@ -235,9 +243,13 @@ bool COpenGL3DriverBase::isVersionAtLeast(int major, int minor) const noexcept
bool COpenGL3DriverBase::genericDriverInit(const core::dimension2d<u32> &screenSize, bool stencilBuffer) bool COpenGL3DriverBase::genericDriverInit(const core::dimension2d<u32> &screenSize, bool stencilBuffer)
{ {
TEST_GL_ERROR(this);
initVersion(); initVersion();
TEST_GL_ERROR(this);
initFeatures(); initFeatures();
TEST_GL_ERROR(this);
printTextureFormats(); printTextureFormats();
TEST_GL_ERROR(this);
if (EnableErrorTest) { if (EnableErrorTest) {
if (KHRDebugSupported) { if (KHRDebugSupported) {
@ -259,6 +271,7 @@ bool COpenGL3DriverBase::genericDriverInit(const core::dimension2d<u32> &screenS
StencilBuffer = stencilBuffer; StencilBuffer = stencilBuffer;
TEST_GL_ERROR(this);
GL.PixelStorei(GL_PACK_ALIGNMENT, 1); GL.PixelStorei(GL_PACK_ALIGNMENT, 1);
for (s32 i = 0; i < ETS_COUNT; ++i) for (s32 i = 0; i < ETS_COUNT; ++i)
@ -266,15 +279,19 @@ bool COpenGL3DriverBase::genericDriverInit(const core::dimension2d<u32> &screenS
GL.ClearDepthf(1.0f); GL.ClearDepthf(1.0f);
TEST_GL_ERROR(this);
GL.FrontFace(GL_CW); GL.FrontFace(GL_CW);
// create material renderers // create material renderers
TEST_GL_ERROR(this);
createMaterialRenderers(); createMaterialRenderers();
TEST_GL_ERROR(this);
// set the renderstates // set the renderstates
setRenderStates3DMode(); setRenderStates3DMode();
// set fog mode // set fog mode
TEST_GL_ERROR(this);
setFog(FogColor, FogType, FogStart, FogEnd, FogDensity, PixelFog, RangeFog); setFog(FogColor, FogType, FogStart, FogEnd, FogDensity, PixelFog, RangeFog);
// We need to reset once more at the beginning of the first rendering. // We need to reset once more at the beginning of the first rendering.
@ -725,6 +742,7 @@ void COpenGL3DriverBase::draw2DImage(const video::ITexture *texture, const core:
const core::rect<s32> &sourceRect, const core::rect<s32> *clipRect, const core::rect<s32> &sourceRect, const core::rect<s32> *clipRect,
const video::SColor *const colors, bool useAlphaChannelOfTexture) const video::SColor *const colors, bool useAlphaChannelOfTexture)
{ {
TEST_GL_ERROR(this);
if (!texture) if (!texture)
return; return;
@ -896,6 +914,7 @@ void COpenGL3DriverBase::draw2DImageBatch(const video::ITexture *texture,
if (clipRect) if (clipRect)
GL.Disable(GL_SCISSOR_TEST); GL.Disable(GL_SCISSOR_TEST);
TEST_GL_ERROR(this);
} }
//! draw a 2d rectangle //! draw a 2d rectangle
@ -976,13 +995,16 @@ void COpenGL3DriverBase::drawArrays(GLenum primitiveType, const VertexType &vert
beginDraw(vertexType, reinterpret_cast<uintptr_t>(vertices)); beginDraw(vertexType, reinterpret_cast<uintptr_t>(vertices));
GL.DrawArrays(primitiveType, 0, vertexCount); GL.DrawArrays(primitiveType, 0, vertexCount);
endDraw(vertexType); endDraw(vertexType);
TEST_GL_ERROR(this);
} }
void COpenGL3DriverBase::drawElements(GLenum primitiveType, const VertexType &vertexType, const void *vertices, int vertexCount, const u16 *indices, int indexCount) void COpenGL3DriverBase::drawElements(GLenum primitiveType, const VertexType &vertexType, const void *vertices, int vertexCount, const u16 *indices, int indexCount)
{ {
TEST_GL_ERROR(this);
beginDraw(vertexType, reinterpret_cast<uintptr_t>(vertices)); beginDraw(vertexType, reinterpret_cast<uintptr_t>(vertices));
GL.DrawRangeElements(primitiveType, 0, vertexCount - 1, indexCount, GL_UNSIGNED_SHORT, indices); GL.DrawRangeElements(primitiveType, 0, vertexCount - 1, indexCount, GL_UNSIGNED_SHORT, indices);
endDraw(vertexType); endDraw(vertexType);
TEST_GL_ERROR(this);
} }
void COpenGL3DriverBase::drawGeneric(const void *vertices, const void *indexList, void COpenGL3DriverBase::drawGeneric(const void *vertices, const void *indexList,
@ -1189,6 +1211,7 @@ void COpenGL3DriverBase::setRenderStates3DMode()
//! Can be called by an IMaterialRenderer to make its work easier. //! Can be called by an IMaterialRenderer to make its work easier.
void COpenGL3DriverBase::setBasicRenderStates(const SMaterial &material, const SMaterial &lastmaterial, bool resetAllRenderStates) void COpenGL3DriverBase::setBasicRenderStates(const SMaterial &material, const SMaterial &lastmaterial, bool resetAllRenderStates)
{ {
TEST_GL_ERROR(this);
// ZBuffer // ZBuffer
switch (material.ZBuffer) { switch (material.ZBuffer) {
case ECFN_DISABLED: case ECFN_DISABLED:
@ -1341,6 +1364,7 @@ void COpenGL3DriverBase::setBasicRenderStates(const SMaterial &material, const S
// Texture parameters // Texture parameters
setTextureRenderStates(material, resetAllRenderStates); setTextureRenderStates(material, resetAllRenderStates);
TEST_GL_ERROR(this);
} }
//! Compare in SMaterial doesn't check texture parameters, so we should call this on each OnRender call. //! Compare in SMaterial doesn't check texture parameters, so we should call this on each OnRender call.
@ -1491,6 +1515,7 @@ void COpenGL3DriverBase::setRenderStates2DMode(bool alpha, bool texture, bool al
} }
MaterialRenderer2DActive->OnRender(this, video::EVT_STANDARD); MaterialRenderer2DActive->OnRender(this, video::EVT_STANDARD);
TEST_GL_ERROR(this);
} }
void COpenGL3DriverBase::chooseMaterial2D() void COpenGL3DriverBase::chooseMaterial2D()

View file

@ -163,6 +163,8 @@ public:
inline void irrGlObjectLabel(GLenum identifier, GLuint name, const char *label) inline void irrGlObjectLabel(GLenum identifier, GLuint name, const char *label)
{ {
// KHR_debug implements ObjectLabelKHR in OpenGL ES
#ifndef _IRR_COMPILE_WITH_OGLES2_
if (KHRDebugSupported) { if (KHRDebugSupported) {
u32 len = static_cast<u32>(strlen(label)); u32 len = static_cast<u32>(strlen(label));
// Since our texture strings can get quite long we also truncate // Since our texture strings can get quite long we also truncate
@ -170,6 +172,7 @@ public:
len = std::min(len, std::min(MaxLabelLength, 82U)); len = std::min(len, std::min(MaxLabelLength, 82U));
GL.ObjectLabel(identifier, name, len, label); GL.ObjectLabel(identifier, name, len, label);
} }
#endif
} }
bool LODBiasSupported = false; bool LODBiasSupported = false;

View file

@ -8,6 +8,8 @@
#include "mt_opengl.h" #include "mt_opengl.h"
#include "CColorConverter.h" #include "CColorConverter.h"
#include <iostream>
namespace video namespace video
{ {

View file

@ -111,7 +111,7 @@
#endif #endif
#endif #endif
#if defined(__APPLE__) && !defined(HAVE_ENDIAN_H) #if defined(__APPLE__)
#include <libkern/OSByteOrder.h> #include <libkern/OSByteOrder.h>
#define be16toh(x) OSSwapBigToHostInt16((x)) #define be16toh(x) OSSwapBigToHostInt16((x))
#define htobe16(x) OSSwapHostToBigInt16((x)) #define htobe16(x) OSSwapHostToBigInt16((x))
@ -119,7 +119,7 @@
#define be32toh(x) OSSwapBigToHostInt32((x)) #define be32toh(x) OSSwapBigToHostInt32((x))
#define htole32(x) OSSwapHostToLittleInt32(x) #define htole32(x) OSSwapHostToLittleInt32(x)
#define htobe32(x) OSSwapHostToBigInt32(x) #define htobe32(x) OSSwapHostToBigInt32(x)
#endif /* __APPLE__ && !HAVE_ENDIAN_H */ #endif /* __APPLE__ */
#if defined(_WIN32) && !defined(HAVE_ENDIAN_H) #if defined(_WIN32) && !defined(HAVE_ENDIAN_H)
#include <winsock2.h> #include <winsock2.h>

30
misc/ios/Info.plist.in Normal file
View file

@ -0,0 +1,30 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleDevelopmentRegion</key>
<string>English</string>
<key>CFBundleExecutable</key>
<string>luanti</string>
<key>CFBundleIconFile</key>
<string>luanti-icon.icns</string>
<key>CFBundleName</key>
<string>@PROJECT_NAME_CAPITALIZED@</string>
<key>CFBundleDisplayName</key>
<string>@PROJECT_NAME_CAPITALIZED@</string>
<key>CFBundleIdentifier</key>
<string>org.luanti.luanti</string>
<key>CFBundleVersion</key>
<string>@VERSION_STRING@</string>
<key>CFBundleShortVersionString</key>
<string>@VERSION_MAJOR@.@VERSION_MINOR@.@VERSION_PATCH@</string>
<key>LSApplicationCategoryType</key>
<string>public.app-category.games</string>
<key>NSHighResolutionCapable</key>
<false/>
<key>UIApplicationSupportsIndirectInputEvents</key>
<true/>
</dict>
</plist>

View file

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
</dict>
</plist>

View file

@ -18,6 +18,8 @@
<string>org.luanti.luanti</string> <string>org.luanti.luanti</string>
<key>CFBundleVersion</key> <key>CFBundleVersion</key>
<string>@VERSION_STRING@</string> <string>@VERSION_STRING@</string>
<key>CFBundleShortVersionString</key>
<string>@VERSION_MAJOR@.@VERSION_MINOR@.@VERSION_PATCH@</string>
<key>LSApplicationCategoryType</key> <key>LSApplicationCategoryType</key>
<string>public.app-category.games</string> <string>public.app-category.games</string>
<key>NSHighResolutionCapable</key> <key>NSHighResolutionCapable</key>

View file

@ -492,6 +492,10 @@ if(ANDROID)
list(APPEND common_SRCS porting_android.cpp) list(APPEND common_SRCS porting_android.cpp)
endif() endif()
if(CMAKE_SYSTEM_NAME STREQUAL "iOS")
list(APPEND common_SRCS porting_ios.mm)
endif()
if(BUILD_UNITTESTS) if(BUILD_UNITTESTS)
add_subdirectory(unittest) add_subdirectory(unittest)
list(APPEND common_SRCS ${UNITTEST_SRCS}) list(APPEND common_SRCS ${UNITTEST_SRCS})
@ -626,10 +630,17 @@ endif()
if(APPLE) if(APPLE)
# Configure the Info.plist file # Configure the Info.plist file
if(NOT CMAKE_SYSTEM_NAME STREQUAL "iOS")
configure_file( configure_file(
"${CMAKE_SOURCE_DIR}/misc/macos/Info.plist.in" "${CMAKE_SOURCE_DIR}/misc/macos/Info.plist.in"
"${CMAKE_BINARY_DIR}/Info.plist" "${CMAKE_BINARY_DIR}/Info.plist"
) )
else()
configure_file(
"${CMAKE_SOURCE_DIR}/misc/ios/Info.plist.in"
"${CMAKE_BINARY_DIR}/Info.plist"
)
endif()
endif() endif()
if(BUILD_CLIENT) if(BUILD_CLIENT)
@ -704,6 +715,9 @@ if(BUILD_CLIENT)
# on Android, Luanti depends on SDL2 directly # on Android, Luanti depends on SDL2 directly
# on other platforms, only IrrlichtMt depends on SDL2 # on other platforms, only IrrlichtMt depends on SDL2
"$<$<PLATFORM_ID:Android>:${SDL2_LIBRARIES}>" "$<$<PLATFORM_ID:Android>:${SDL2_LIBRARIES}>"
#"$<$<PLATFORM_ID:iOS>:-framework UIKit -framework Foundation -framework CoreGraphics -framework QuartzCore -framework AudioToolbox -framework AVFoundation -framework CoreAudio -framework CoreMotion -framework Security>"
"$<$<PLATFORM_ID:iOS>:-framework Security -framework CoreHaptics -framework CoreBluetooth -framework GameController -framework Metal -framework Foundation>"
"$<$<PLATFORM_ID:iOS>:${OPENGLES2_LIBRARY}>"
) )
target_compile_definitions(${PROJECT_NAME} PRIVATE "MT_BUILDTARGET=1") target_compile_definitions(${PROJECT_NAME} PRIVATE "MT_BUILDTARGET=1")
if(NOT USE_LUAJIT) if(NOT USE_LUAJIT)

View file

@ -49,6 +49,10 @@ extern "C" {
#endif #endif
} }
#if TARGET_OS_IPHONE
#include <SDL2/SDL.h>
#endif
#if !defined(__cpp_rtti) || !defined(__cpp_exceptions) #if !defined(__cpp_rtti) || !defined(__cpp_exceptions)
#error Luanti cannot be built without exceptions or RTTI #error Luanti cannot be built without exceptions or RTTI
#endif #endif

View file

@ -38,11 +38,15 @@
#include <android/api-level.h> #include <android/api-level.h>
#endif #endif
#if defined(__APPLE__) #if defined(__APPLE__)
#include <TargetConditionals.h>
#include <mach-o/dyld.h> #include <mach-o/dyld.h>
#include <CoreFoundation/CoreFoundation.h> #include <CoreFoundation/CoreFoundation.h>
// For _NSGetEnviron() // For _NSGetEnviron()
// Related: https://gitlab.haskell.org/ghc/ghc/issues/2458 // Related: https://gitlab.haskell.org/ghc/ghc/issues/2458
#include <crt_externs.h> #include <crt_externs.h>
#if TARGET_OS_IPHONE
#include "porting_ios.h"
#endif
#endif #endif
#if defined(__HAIKU__) #if defined(__HAIKU__)
@ -538,6 +542,7 @@ bool setSystemPaths()
} }
CFRelease(resources_url); CFRelease(resources_url);
#if TARGET_OS_MAC
const char *const minetest_user_path = getenv("MINETEST_USER_PATH"); const char *const minetest_user_path = getenv("MINETEST_USER_PATH");
if (minetest_user_path && minetest_user_path[0] != '\0') { if (minetest_user_path && minetest_user_path[0] != '\0') {
path_user = std::string(minetest_user_path); path_user = std::string(minetest_user_path);
@ -547,6 +552,11 @@ bool setSystemPaths()
+ "/Library/Application Support/" + "/Library/Application Support/"
+ "minetest"; + "minetest";
} }
#elif TARGET_OS_IPHONE
path_user = getAppleDocumentsDirectory();
#else
#error "Not supported Apple OS."
#endif
return true; return true;
} }

8
src/porting_ios.h Normal file
View file

@ -0,0 +1,8 @@
// Luanti
// SPDX-License-Identifier: LGPL-2.1-or-later
// Copyright (C) 2025 SFENCE <sfence.software@gmail.com>
#include <string>
std::string getAppleDocumentsDirectory();
std::string getAppleLibraryDirectory();

17
src/porting_ios.mm Normal file
View file

@ -0,0 +1,17 @@
// Luanti
// SPDX-License-Identifier: LGPL-2.1-or-later
// Copyright (C) 2025 SFENCE <sfence.software@gmail.com>
#include "porting_ios.h"
#import <Foundation/Foundation.h>
std::string getAppleDocumentsDirectory() {
NSString *documentsDirectory = [NSHomeDirectory() stringByAppendingPathComponent:@"Documents"];
return std::string([documentsDirectory UTF8String]);
}
std::string getAppleLibraryDirectory() {
NSString *libraryDirectory = [NSHomeDirectory() stringByAppendingPathComponent:@"Library"];
return std::string([libraryDirectory UTF8String]);
}

View file

@ -38,6 +38,7 @@
#elif !defined(BYTE_ORDER) && defined(__BYTE_ORDER) #elif !defined(BYTE_ORDER) && defined(__BYTE_ORDER)
#define BYTE_ORDER __BYTE_ORDER #define BYTE_ORDER __BYTE_ORDER
#endif #endif
#undef HAVE_ENDIAN_H
#define FIXEDPOINT_FACTOR 1000.0f #define FIXEDPOINT_FACTOR 1000.0f

49
util/ci/build_ios.sh Executable file
View file

@ -0,0 +1,49 @@
#!/bin/bash -e
sudo xcode-select -s /Applications/Xcode_${xcodever}.app/Contents/Developer
sdkroot="$(realpath $(xcrun --sdk iphonesimulator --show-sdk-path)/../iPhoneSimulator${osver}.sdk)"
export CMAKE_PREFIX_PATH=${DEPS_DIR}
export SDKROOT="$sdkroot"
cmake .. -DCMAKE_SYSTEM_NAME=iOS -DCMAKE_OSX_DEPLOYMENT_TARGET=$osver -DCMAKE_FIND_FRAMEWORK=LAST -DCMAKE_OSX_ARCHITECTURES=arm64 \
-DCMAKE_INSTALL_PREFIX=../build/ios/ -DRUN_IN_PLACE=FALSE -DENABLE_GETTEXT=TRUE -DCMAKE_BUILD_TYPE=Release \
-DCMAKE_PREFIX_PATH=${DEPS_DIR} \
-DENABLE_OPENGL=OFF \
-DENABLE_OPENGL3=OFF \
-DENABLE_GLES2=ON \
-DUSE_SDL2=ON \
-DSDL2_LIBRARIES="${DEPS_DIR}/lib/libSDL2.a;${DEPS_DIR}/lib/libSDL2main.a" \
-DSDL2_INCLUDE_DIRS=${DEPS_DIR}/include/SDL2 \
-DOPENGLES2_LIBRARY=${DEPS_DIR}/lib/libGLESv2_static.a \
-DOPENGLES2_INCLUDE_DIR=${DEPS_DIR}/include/ANGLE \
-DCURL_LIBRARY=${DEPS_DIR}/lib/libcurl.a \
-DCURL_INCLUDE_DIR=${DEPS_DIR}/include \
-DFREETYPE_LIBRARY=${DEPS_DIR}/lib/libfreetype.a \
-DFREETYPE_INCLUDE_DIRS=${DEPS_DIR}/include/freetype2 \
-DGETTEXT_INCLUDE_DIR=${DEPS_DIR}/include \
-DGETTEXT_LIBRARY=${DEPS_DIR}/lib/libintl.a \
-DLUA_LIBRARY=${DEPS_DIR}/lib/libluajit-5.1.a \
-DLUA_INCLUDE_DIR=${DEPS_DIR}/include/luajit-2.1 \
-DOGG_LIBRARY=${DEPS_DIR}/lib/libogg.a \
-DOGG_INCLUDE_DIR=${DEPS_DIR}/include \
-DVORBIS_LIBRARY=${DEPS_DIR}/lib/libvorbis.a \
-DVORBISFILE_LIBRARY=${DEPS_DIR}/lib/libvorbisfile.a \
-DVORBIS_INCLUDE_DIR=${DEPS_DIR}/include \
-DZSTD_LIBRARY=${DEPS_DIR}/lib/libzstd.a \
-DZSTD_INCLUDE_DIR=${DEPS_DIR}/include \
-DGMP_LIBRARY=${DEPS_DIR}/lib/libgmp.a \
-DGMP_INCLUDE_DIR=${DEPS_DIR}/include \
-DJSON_LIBRARY=${DEPS_DIR}/lib/libjsoncpp.a \
-DJSON_INCLUDE_DIR=${DEPS_DIR}/include \
-DENABLE_LEVELDB=OFF \
-DENABLE_POSTGRESQL=OFF \
-DENABLE_REDIS=OFF \
-DJPEG_LIBRARY=${DEPS_DIR}/lib/libjpeg.a \
-DJPEG_INCLUDE_DIR=${DEPS_DIR}/include \
-DPNG_LIBRARY=${DEPS_DIR}/lib/libpng.a \
-DPNG_PNG_INCLUDE_DIR=${DEPS_DIR}/include \
-DCMAKE_EXE_LINKER_FLAGS="-lbz2 ${DEPS_DIR}/lib/libANGLE_static.a ${DEPS_DIR}/lib/libEGL_static.a" \
-DXCODE_CODE_SIGN_ENTITLEMENTS=${REPDIR}/misc/ios/entitlements/release.entitlements \
-GXcode
xcodebuild -project luanti.xcodeproj -scheme luanti -configuration Release build

View file

@ -49,3 +49,22 @@ install_macos_deps() {
brew unlink $(brew ls --formula) brew unlink $(brew ls --formula)
brew link "${pkgs[@]}" brew link "${pkgs[@]}"
} }
# iOS build only
install_ios_deps() {
osver=$1
local pkgs=(
cmake gettext wget
)
export HOMEBREW_NO_INSTALLED_DEPENDENTS_CHECK=1
export HOMEBREW_NO_INSTALL_CLEANUP=1
# contrary to how it may look --auto-update makes brew do *less*
brew update --auto-update
brew install --display-times "${pkgs[@]}"
brew unlink $(brew ls --formula)
brew link "${pkgs[@]}"
wget ios${osver}_deps.tar.gz https://github.com/luanti-org/luanti_ios_deps/releases/download/latest/ios${osver}_deps.tar.gz || echo "Ignore stupid error number 4: $?"
tar -xf ios${osver}_deps.tar.gz
}

36
util/ci/run_ios.sh Executable file
View file

@ -0,0 +1,36 @@
#!/bin/sh
DEVICE_NAME=$1
TIMEOUT=$2
xcrun simctl boot "$DEVICE_NAME"
xcrun simctl install booted build/build/Release-iphonesimulator/luanti.app
# Run the iOS app in the background
xcrun simctl launch --console booted org.luanti.luanti --run-unittests 2> log.txt &
APP_PID=$!
# Initialize variables
CHECK_INTERVAL=15
ELAPSED_TIME=0
FOUND_RESULT=false
# Monitor the log file
while [ $ELAPSED_TIME -lt $TIMEOUT ]; do
if grep -q "Unit Test Results:" log.txt; then
FOUND_RESULT=true
break
fi
sleep $CHECK_INTERVAL
ELAPSED_TIME=$((ELAPSED_TIME + CHECK_INTERVAL))
done
# Terminate the app
if $FOUND_RESULT; then
echo "Unit test results found. Terminating the app."
else
echo "Timeout reached. Terminating the app."
fi
xcrun simctl terminate booted org.luanti.luanti
xcrun simctl shutdown booted