P0.1: scaffold m3te sx project from the proven game structure
Stand up build.sx (macos + ios/ios-sim targets, bundle id co.swipelab.m3te, output sx-out/ios/M3te.app, assets dir) and a minimal main.sx that brings up the platform (UIKit+Metal on iOS, SDL3+GL on macOS) and renders a solid-clear frame. Add assets/ and goldens/ directories and a .gitignore for build artifacts. Modeled on game/build.sx and game/main.sx; modules resolve from the compiler binary with no -L flag.
This commit is contained in:
10
.gitignore
vendored
Normal file
10
.gitignore
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
.DS_Store
|
||||
.sx-cache
|
||||
.sx-tmp/
|
||||
sx-out/
|
||||
# iOS/macOS .app bundles land inside the ignored sx-out/ dir.
|
||||
*.app/
|
||||
# Built binaries from `sx build main.sx` at repo root.
|
||||
/main
|
||||
# Flow scaffolding (nested working copy).
|
||||
current/
|
||||
0
assets/.gitkeep
Normal file
0
assets/.gitkeep
Normal file
35
build.sx
Normal file
35
build.sx
Normal file
@@ -0,0 +1,35 @@
|
||||
#import "modules/compiler.sx";
|
||||
#import "modules/platform/bundle.sx";
|
||||
|
||||
configure_build :: () {
|
||||
opts := build_options();
|
||||
opts.set_bundle_id("co.swipelab.m3te");
|
||||
opts.set_post_link_callback(bundle_main);
|
||||
if OS == {
|
||||
case .macos: {
|
||||
opts.set_output_path("sx-out/macos/M3te");
|
||||
opts.set_bundle_path("sx-out/macos/M3te.app");
|
||||
// Ad-hoc sign (empty identity) so a local `open` launch isn't
|
||||
// Gatekeeper-rejected. SDL3 comes from Homebrew.
|
||||
opts.add_link_flag("-L/opt/homebrew/lib");
|
||||
opts.add_link_flag("-lSDL3");
|
||||
opts.add_asset_dir("assets", "assets");
|
||||
}
|
||||
case .ios: {
|
||||
opts.set_output_path("sx-out/ios/M3te");
|
||||
opts.set_bundle_path("sx-out/ios/M3te.app");
|
||||
// Device-only: the simulator is ad-hoc signed by the bundler,
|
||||
// which also grants get-task-allow for lldb. Embedding a device
|
||||
// identity / profile in a sim build blocks install + launch.
|
||||
if opts.is_ios_device() {
|
||||
opts.set_codesign_identity("Apple Development: Alexandru Agrapine (DC8VVHJ9W4)");
|
||||
opts.set_provisioning_profile("/Users/agra/Downloads/SwipeS32DevProfile.mobileprovision");
|
||||
}
|
||||
opts.add_framework("UIKit");
|
||||
opts.add_framework("OpenGLES");
|
||||
opts.add_framework("QuartzCore");
|
||||
opts.add_framework("Metal");
|
||||
opts.add_asset_dir("assets", "assets");
|
||||
}
|
||||
}
|
||||
}
|
||||
0
goldens/.gitkeep
Normal file
0
goldens/.gitkeep
Normal file
91
main.sx
Normal file
91
main.sx
Normal file
@@ -0,0 +1,91 @@
|
||||
#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();
|
||||
}
|
||||
Reference in New Issue
Block a user