What works on iOS sim now:
- pure-UIKit boot via UIApplicationMain (no SDL3 on iOS)
- SxGLView (CAEAGLLayer) + EAGLContext(GLES3) + CADisplayLink
- GLES3 shader path in modules/ui/renderer.sx (was wasm-only; now
wasm-OR-ios)
- UITouch -> ui.Event translation (mouse_down/moved/up) on touchesBegan/
Moved/Ended/Cancelled. Verified by tapping the chess board: the
expected pawn highlights and its legal moves show as green dots.
- chdir to NSBundle.mainBundle.resourcePath inside UIKitPlatform.init so
the game's relative fopen("assets/...") calls resolve.
Required restructuring to fix four problems discovered along the way:
1. GL context + load_gl must happen BEFORE UIApplicationMain so the
game's pipeline.init (which compiles shaders) doesn't crash on null
function pointers. Pulled EAGLContext creation + load_gl out of
didFinishLaunching: into UIKitPlatform.init via uikit_create_gl_context.
2. UIScreen.nativeScale returns CGFloat (=double on 64-bit Apple).
Reading it through a `(*void, *void) -> f32` msgSend signature
clobbers the value to 0 — the upper 32 bits of d0 land where the f32
reads from. Replaced msg_f with msg_d returning f64 (and added
msg_odbl for setContentScaleFactor: which takes CGFloat).
3. `xx <f64-call-result>` directly assigned to an f32 field through a
sema path lowers as `sitofp` (integer→float) on the double — LLVM
verification rejects it. Workaround: hoist into an `f64` local first.
4. The renderer was selecting the GLSL 330 core shader on every non-wasm
target, including iOS GLES3 where it silently fails to compile and
no quads render. Added OS == .ios to the GLES branch.
Game changes:
- main.sx: g_plat is now a boxed `Platform` (not concrete *SdlPlatform).
Backend chosen per-target via `inline if OS == .ios { ... }`. The
ESC-to-stop handling is OS-guarded (mobile apps don't quit on key
press, and SDL_Keycode references would force-link SDL on iOS).
- build.sx: iOS no longer adds SDL3; it adds UIKit + OpenGLES +
QuartzCore instead.
- delta_time and viewport dims are now mirrored to free globals so the
dock subsystem (`g_dock_delta_time = @g_delta_time`) and build_ui
layout decisions don't need a pointer through the boxed protocol.
Other:
- Added `stop()` to the Platform protocol (no-op on UIKitPlatform).
- examples/66-uikit-platform.sx updated: taps advance the clear color
(red → green → blue) — smoke test for the touch IMP wiring.
- shutdown() on UIKitPlatform is a no-op (mobile apps don't tear down).
Outstanding for next session:
- The Dynamic Island notch overlaps the top of the board because we
haven't read UIView.safeAreaInsets yet (CGRect/UIEdgeInsets struct
returns require a different msgSend ABI than we currently express).
- Keyboard observer (UIKeyboardWillChangeFrameNotification + animation
duration) — the load-bearing iOS feature.
- Real-device codesigning workflow for the new build.
Two more sx compiler bugs to file out of this work:
- xx(f64 call result) → f32 emits sitofp (problem #3 above).
- Inline `#import` inside `inline if` fails to parse (we worked around
by importing both backends unconditionally; the unused-backend's
Obj-C calls are gated by `inline if OS == .ios`).
53 lines
1.6 KiB
Plaintext
53 lines
1.6 KiB
Plaintext
// UIKitPlatform end-to-end smoke: boots the AppDelegate, installs an
|
|
// SxGLView with a CAEAGLLayer + GLES3 context + CADisplayLink, polls
|
|
// UITouch events into ui.Event, and on every vsync clears the screen
|
|
// to a color that advances on each tap.
|
|
//
|
|
// Build + run:
|
|
// sx build --target ios-sim examples/66-uikit-platform.sx \
|
|
// -o /tmp/SxUIKitBoot --bundle /tmp/SxUIKitBoot.app \
|
|
// --bundle-id co.swipelab.sxuikit -F ~/Library/Frameworks
|
|
// xcrun simctl install booted /tmp/SxUIKitBoot.app
|
|
// xcrun simctl launch --console booted co.swipelab.sxuikit
|
|
// xcrun simctl io booted screenshot /tmp/screen.png
|
|
|
|
#import "modules/std.sx";
|
|
#import "modules/std/uikit.sx";
|
|
#framework "OpenGLES";
|
|
#framework "QuartzCore";
|
|
#import "modules/opengl.sx";
|
|
#import "modules/ui/types.sx";
|
|
#import "modules/ui/events.sx";
|
|
#import "modules/platform/uikit.sx";
|
|
|
|
g_color_index : s64 = 0;
|
|
|
|
tap_frame :: () {
|
|
fc := g_uikit_plat.begin_frame();
|
|
|
|
events := g_uikit_plat.poll_events();
|
|
i : s64 = 0;
|
|
while i < events.len {
|
|
ev := events.ptr[i];
|
|
if ev == {
|
|
case .mouse_down: { g_color_index += 1; }
|
|
}
|
|
i += 1;
|
|
}
|
|
|
|
phase := g_color_index % 3;
|
|
r : f32 = if phase == 0 then 0.8 else 0.1;
|
|
g : f32 = if phase == 1 then 0.8 else 0.1;
|
|
b : f32 = if phase == 2 then 0.8 else 0.1;
|
|
glViewport(0, 0, fc.pixel_w, fc.pixel_h);
|
|
glClearColor(r, g, b, 1.0);
|
|
glClear(GL_COLOR_BUFFER_BIT);
|
|
g_uikit_plat.end_frame();
|
|
}
|
|
|
|
main :: () -> void {
|
|
plat : *UIKitPlatform = xx malloc(size_of(UIKitPlatform));
|
|
plat.init("SxUIKitPlatform", 0, 0);
|
|
plat.run_frame_loop(closure(tap_frame));
|
|
}
|