#import "modules/std.sx"; #import "build.sx"; #import "modules/compiler.sx"; #import "modules/opengl.sx"; #import "modules/sdl3.sx"; #import "modules/gpu/api.sx"; #import "modules/gpu/types.sx"; #import "modules/gpu/metal.sx"; #import "modules/platform/api.sx"; #import "modules/platform/sdl3.sx"; #import "modules/platform/uikit.sx"; #run configure_build(); g_plat : Platform = ---; g_viewport_w : f32 = 800.0; g_viewport_h : f32 = 600.0; // iOS-only concrete handles kept alongside the boxed `g_plat` so the frame // loop can reach the CAMetalLayer pointer / pixel dims without going through // the protocol box. g_uikit_plat : *UIKitPlatform = null; g_metal_gpu : *MetalGPU = null; frame :: () { fc := g_plat.begin_frame(); g_viewport_w = fc.viewport_w; g_viewport_h = fc.viewport_h; for g_plat.poll_events(): (*ev) { inline if OS != .ios { if ev == { case .key_up: (e) { if e.key == .escape { g_plat.stop(); } } } } } inline if OS == .ios { // Lazy-attach Metal once -[SxAppDelegate didFinishLaunching:] has // installed the SxMetalView and its bounds have been measured; both // can lag the first CADisplayLink tick, and a zero-sized drawable // aborts via XPC. if g_uikit_plat.gl_layer == null { return; } if g_uikit_plat.pixel_w <= 0 or g_uikit_plat.pixel_h <= 0 { return; } if g_metal_gpu.layer == null { g_metal_gpu.init(g_uikit_plat.gl_layer, g_uikit_plat.pixel_w, g_uikit_plat.pixel_h); } else if g_metal_gpu.pixel_w != g_uikit_plat.pixel_w or g_metal_gpu.pixel_h != g_uikit_plat.pixel_h { g_metal_gpu.resize(g_uikit_plat.pixel_w, g_uikit_plat.pixel_h); } clear : ClearColor = .{ r = 0.12, g = 0.12, b = 0.15, a = 1.0 }; if !g_metal_gpu.begin_frame(clear) { return; } g_metal_gpu.end_frame(fc.target_present_time); } else { glViewport(0, 0, fc.pixel_w, fc.pixel_h); glClearColor(0.12, 0.12, 0.15, 1.0); glClear(GL_COLOR_BUFFER_BIT); } g_plat.end_frame(); } main :: () -> void { inline if OS == .ios { u : *UIKitPlatform = xx context.allocator.alloc(size_of(UIKitPlatform)); u.gpu_mode = .metal; if !u.init("m3te", 800, 600) { return; } g_plat = xx u; g_uikit_plat = u; // The CAMetalLayer doesn't exist until didFinishLaunching: runs after // we return into UIApplicationMain, so attach lazily on the first // frame. init(null, 0, 0) only needs the MTLDevice. g_metal_gpu = xx context.allocator.alloc(size_of(MetalGPU)); // alloc returns uninitialized memory; struct field defaults are NOT // applied, so List caps/lens would be garbage without this memset. memset(xx g_metal_gpu, 0, size_of(MetalGPU)); if !g_metal_gpu.init(null, 0, 0) { return; } } else { s : *SdlPlatform = xx context.allocator.alloc(size_of(SdlPlatform)); if !s.init("m3te", 800, 600) { return; } g_plat = xx s; } fc := g_plat.begin_frame(); g_viewport_w = fc.viewport_w; g_viewport_h = fc.viewport_h; g_plat.run_frame_loop(closure(frame)); g_plat.shutdown(); }