raylib icon indicating copy to clipboard operation
raylib copied to clipboard

[rcore] Porting raylib to iOS and implement `rcore_ios.c`

Open blueloveTH opened this issue 11 months ago • 25 comments

I would like to take the initial step to add iOS support for raylib. I am going to add rcore_ios.c and implement an iOS's platform layer. I will update this pr on my progress.

Current Demo (iPhone 8)

https://github.com/raysan5/raylib/assets/28104173/2f890d7e-bf00-44da-9285-2c73bb5c2e1e

Steps

  • [x] Create an empty iOS game project in XCode
  • [x] Compile ANGLE and get libEGL.xcframework and libGLESv2.xcframework
  • [x] Fill rcore_ios.c and compile raylib
  • [x] Link all of the above with an example source file

Functions

  • [x] void PollInputEvents(void)
  • [x] int InitPlatform(void)
  • [x] void ClosePlatform(void)

Prebuilt ANGLE libraries for iOS

Users need to add the following ANGLE libraries into Xcode. libEGL.xcframework.zip libGLESv2.xcframework.zip

References

  • https://github.com/raysan5/raylib/discussions/2681
  • https://github.com/raysan5/raylib/discussions/2998
  • https://medium.com/@grplyler/building-and-linking-googles-angle-with-raylib-on-macos-67b07cd380a3
  • https://github.com/raysan5/raylib/issues/330
  • https://github.com/levinli303/ANGLESwiftUI/tree/main

blueloveTH avatar Mar 22 '24 12:03 blueloveTH

I found a repository https://github.com/levinli303/ANGLESwiftUI/tree/main which made ANGLE working on iOS.

Now I grab the prebuilt libEGL.xcframework and libGLESv2.xcframework from the repo directly. I will figure out how to compile ANGLE from scratch later.

blueloveTH avatar Mar 23 '24 09:03 blueloveTH

Hi @raysan5 . I need your help. iOS always use a UIApplicationMain function to start the game. UIApplicationMain is an extern function which is hidden for me. It runs forever.

int main(int argc, char * argv[]) {
    return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
}

It seems does not expose detailed control to allow us to achieve the following:

int main() {
  library_init();
  // game init code here
  while(we_have_not_quit_the_game) {
    library_message_loop();
    library_init_render();
    // render stuff
    library_end_render();
    // update game state
  }
  library_shutdown();
}

See https://stackoverflow.com/questions/2187684/how-can-i-remove-uiapplicationmain-from-an-iphone-application.

What we can do is registering render callbacks via CADisplayLink. I cannot find a way to give users full control of the game loop.

I can try a callback-based api like this. However, this requires a minor change of existing raylib projects if they want to run on iOS.

extern void ios_ready();
extern void ios_update();
extern void ios_destroy();

Old project should adapt their main function into this in order to be cross-platform between iOS and other platforms:

#ifndef PLATFORM_IOS
int main(int argc, char** argv){
    // store as global variables if you need
    ios_ready();
    while(!WindowShouldClose()) ios_update();
    ios_destroy();
    return 0;
}
#endif

blueloveTH avatar Mar 23 '24 15:03 blueloveTH

Default shader seems does not compile on iOS [OpenGL ES GLSL ES 3.00 (ANGLE 2.1.22473 git hash: 07e41ef0e070)].

Click to see logs
INFO: Initializing raylib 5.1-dev
INFO: Platform backend: CUSTOM
INFO: Supported raylib modules:
INFO:     > rcore:..... loaded (mandatory)
INFO:     > rlgl:...... loaded (mandatory)
INFO:     > rshapes:... loaded (optional)
INFO:     > rtextures:. loaded (optional)
INFO:     > rtext:..... loaded (optional)
INFO:     > rmodels:... loaded (optional)
INFO:     > raudio:.... loaded (optional)
INFO: DISPLAY: Device initialized successfully
INFO:     > Display size: 0 x 0
INFO:     > Screen size:  800 x 450
INFO:     > Render size:  800 x 450
INFO:     > Viewport offsets: 0, 0
INFO: DISPLAY: Device initialized successfully
INFO:     > Display size: 0 x 0
INFO:     > Screen size:  800 x 450
INFO:     > Render size:  800 x 450
INFO:     > Viewport offsets: 0, 0
INFO: GLAD: OpenGL extensions loaded successfully
INFO: GL: Supported extensions count: 99
INFO: GL: OpenGL device information:
INFO:     > Vendor:   Google Inc. (Apple)
INFO:     > Renderer: ANGLE (Apple, ANGLE Metal Renderer: Apple iOS simulator GPU, Version 17.2 (Build 21C62))
INFO:     > Version:  OpenGL ES 3.0.0 (ANGLE 2.1.22473 git hash: 07e41ef0e070)
INFO:     > GLSL:     OpenGL ES GLSL ES 3.00 (ANGLE 2.1.22473 git hash: 07e41ef0e070)
INFO: GL: VAO extension detected, VAO functions loaded successfully
INFO: GL: NPOT textures extension detected, full NPOT textures supported
INFO: PLATFORM: CUSTOM: Initialized successfully
INFO: TEXTURE: [ID 1] Texture loaded successfully (1x1 | R8G8B8A8 | 1 mipmaps)
INFO: TEXTURE: [ID 1] Default texture loaded successfully
WARNING: SHADER: [ID 1] Failed to compile vertex shader code
WARNING: SHADER: [ID 1] Compile error: ERROR: 0:1: '
' : invalid version directive
ERROR: 0:2: 'in' : storage qualifier supported in GLSL ES 3.00 and above only
ERROR: 0:3: 'in' : storage qualifier supported in GLSL ES 3.00 and above only
ERROR: 0:4: 'in' : storage qualifier supported in GLSL ES 3.00 and above only
ERROR: 0:5: 'out' : storage qualifier supported in GLSL ES 3.00 and above only
ERROR: 0:6: 'out' : storage qualifier supported in GLSL ES 3.00 and above only

WARNING: SHADER: [ID 2] Failed to compile fragment shader code
WARNING: SHADER: [ID 2] Compile error: ERROR: 0:1: '
' : invalid version directive
ERROR: 0:2: 'in' : storage qualifier supported in GLSL ES 3.00 and above only
ERROR: 0:2: '' : No precision specified for (float)
ERROR: 0:3: 'in' : storage qualifier supported in GLSL ES 3.00 and above only
ERROR: 0:3: '' : No precision specified for (float)
ERROR: 0:4: 'out' : storage qualifier supported in GLSL ES 3.00 and above only
ERROR: 0:4: '' : No precision specified for (float)
ERROR: 0:6: '' : No precision specified for (float)
ERROR: 0:9: '' : No precision specified for (float)
ERROR: 0:9: 'texture' : no matching overloaded function found
ERROR: 0:9: '=' : dimension mismatch
ERROR: 0:9: '=' : cannot convert from 'const mediump float' to '4-component vector of float'

WARNING: SHADER: [ID 3] Failed to link shader program
WARNING: SHADER: [ID 3] Link error: Vertex shader is not compiled.

WARNING: SHADER: [ID 0] Failed to load default shader
INFO: RLGL: Render batch vertex buffers loaded successfully in RAM (CPU)
INFO: RLGL: Render batch vertex buffers loaded successfully in VRAM (GPU)
INFO: RLGL: Default OpenGL state initialized successfully

blueloveTH avatar Mar 23 '24 16:03 blueloveTH

The initial rcore_ios.c is starting to work!! (with simple touch support)

https://github.com/raysan5/raylib/assets/28104173/ad64965e-d587-47aa-b08b-96762c9809c2

blueloveTH avatar Mar 23 '24 17:03 blueloveTH

Question: I see there is a feature: InitWindow(0, 0, "title") will set as full screen. How is it achieved?

Should I override CORE.Window.screen.width and CORE.Window.screen.height in InitPlatform with device width and height?

blueloveTH avatar Mar 23 '24 17:03 blueloveTH

Now rcore_ios.c has basic functionalities including graphics, audio and touch input. I've marked this PR as ready for review. I will continue to work for more details and wait for raysan5's comment.

blueloveTH avatar Mar 24 '24 05:03 blueloveTH

I request a change in CoreData structure. On iOS, I need to use a void* as "Point identifiers" (which is the UITouch object's address). However, current int pointId[MAX_TOUCH_POINTS]; uses int, which cannot be used to safely store a void*.

        struct {
            int pointCount;
            int pointId[MAX_TOUCH_POINTS];              // Point identifiers
            Vector2 position[MAX_TOUCH_POINTS];
            char currentTouchState[MAX_TOUCH_POINTS];
            char previousTouchState[MAX_TOUCH_POINTS];

        } Touch;

Can we change it to long long pointId[MAX_TOUCH_POINTS];?

Update: I have used a custom void* to int mapping to avoid the change of CoreData

blueloveTH avatar Mar 24 '24 06:03 blueloveTH

Added iOS build workflow to CI.

blueloveTH avatar Mar 25 '24 13:03 blueloveTH

@blueloveTH Excuse my late response and thank you very much for working on this great improvement. iOS platform has been missing from raylib for +10 years and I'm happy to see that some user implemented it.

My main concern is the iOS application approach that completely differs from all the other platforms. All raylib examples work exactly as they are on all the supported platforms and requiring a complete re-design for iOS is not the ideal situation.

Is it possible to use a similar approach to Android one? Embedding the App management inside raylib?

Also note that the provided rcore_ios.c implementation does not follow raylib code conventions. It would be nice to follow them when possible.

raysan5 avatar Apr 01 '24 16:04 raysan5

Thanks for your review. I am going to resolve them soon.

blueloveTH avatar Apr 02 '24 02:04 blueloveTH

Interesting.. will colaborate soon

neondeex avatar May 02 '24 15:05 neondeex

Any new progress?

zeroxer avatar May 25 '24 02:05 zeroxer

also interested :D?

jonpittock avatar May 26 '24 14:05 jonpittock

I am a bit busy recently :/ It works on my branch. I may sync it with the latest raylib if I have time.

blueloveTH avatar May 26 '24 14:05 blueloveTH

@blueloveTH do you have local changes on your branch?

I have this running on my mac/iphone now and planning on allocating some free time on this as I also need raylib ios for a project I'm working on.

Anything you need for collaboration?

Do you have your Makefile/CMake changes to compile Raylib to ios local?

celioreyes avatar Jun 13 '24 15:06 celioreyes

To use raylib with Emscripten it's already necessary to give up the main loop control(unless one's willing to add ASYNCIFY which has a nonnegligible overhead).

So I like the idea of a callback based design. Maybe something along the lines of SDL3 main callback functions.

Here's how they handle the quirks of each platform, including iOS.

lzralbu avatar Jun 15 '24 21:06 lzralbu

Definitely interested in this. This is the dream, being able to make cross platform mobile apps and games with raylib would be amazing.

leftbones avatar Aug 23 '24 17:08 leftbones

@leftbones Unfortunately the code structure required for this iOS implementation is hardly compatible with raylib structure, not sure if it's possible to use another structure, more similar to Android one.

raysan5 avatar Aug 23 '24 20:08 raysan5

There may be internal functions that Apple does not expose allowing us to take full control of the main loop.

blueloveTH avatar Aug 24 '24 06:08 blueloveTH

Perhaps the newly merged SDL_GPU as a backend would be a better approach for targeting iOS, and consoles!!!

jackwlee01 avatar Aug 30 '24 08:08 jackwlee01