This commit is contained in:
agra
2026-03-03 13:25:25 +02:00
parent 6ffe22acb0
commit 343ea4bf08
9 changed files with 736 additions and 169 deletions

76
main.sx
View File

@@ -1,40 +1,24 @@
#import "modules/std.sx";
#import "build.sx";
#import "modules/compiler.sx";
#import "modules/sdl3.sx";
#import "modules/opengl.sx";
#import "modules/math";
#import "modules/stb.sx";
#import "modules/stb_truetype.sx";
#import "modules/wasm.sx";
#import "ui";
configure_build :: () {
opts := build_options();
inline if OS == {
case .wasm: {
opts.set_output_path(if POINTER_SIZE == 4 then "sx-out/wasm32/index.html" else "sx-out/wasm32/index.html");
opts.add_link_flag("-sUSE_SDL=3");
opts.add_link_flag("-sMAX_WEBGL_VERSION=2");
opts.add_link_flag("-sFULL_ES3=1");
opts.add_link_flag("--preload-file assets");
opts.add_link_flag("-sALLOW_MEMORY_GROWTH=1");
}
case .macos: {
opts.set_output_path("sx-out/macos/game");
}
}
}
#run configure_build();
libc :: #library "c";
emscripten_set_main_loop :: (func: *void, fps: s32, sim_infinite: s32) #foreign libc;
WIDTH :f32: 800;
HEIGHT :f32: 600;
// --- Frame state (globals for emscripten callback) ---
g_window : *void = ---;
g_pipeline : *UIPipeline = ---;
g_running : bool = true;
g_width : s32 = 800; // logical window size
g_height : s32 = 600;
g_pixel_w : s32 = 800; // physical pixel size
g_pixel_h : s32 = 600;
load_texture :: (path: [:0]u8) -> u32 {
w : s32 = 0;
@@ -141,13 +125,13 @@ run_ui_tests :: (pipeline: *UIPipeline) {
// Render after tests and save snapshot to see scrolled state
glClear(GL_COLOR_BUFFER_BIT);
pipeline.tick();
save_snapshot("goldens/test_after_drag.png", xx WIDTH, xx HEIGHT);
save_snapshot("goldens/test_after_drag.png", g_pixel_w, g_pixel_h);
}
// One frame of the main loop — called repeatedly by emscripten or desktop while-loop
frame :: () {
sdl_event : SDL_Event = .none;
while SDL_PollEvent(sdl_event) {
while SDL_PollEvent(@sdl_event) {
print("SDL event: {}\n", sdl_event.tag);
if sdl_event == {
@@ -155,17 +139,24 @@ frame :: () {
case .key_up: (e) {
if e.key == { case .escape: { g_running = false; } }
}
case .window_resized: (data) {
g_width = data.data1;
g_height = data.data2;
SDL_GetWindowSizeInPixels(g_window, @g_pixel_w, @g_pixel_h);
g_pipeline.resize(xx g_width, xx g_height);
}
}
ui_event := translate_sdl_event(@sdl_event);
if ui_event != .none {
print(" ui event dispatched\n");
g_pipeline.*.dispatch_event(@ui_event);
g_pipeline.dispatch_event(@ui_event);
} else {
print(" -> .none\n");
}
}
glViewport(0, 0, g_pixel_w, g_pixel_h);
glClearColor(0.12, 0.12, 0.15, 1.0);
glClear(GL_COLOR_BUFFER_BIT);
@@ -189,17 +180,42 @@ main :: () -> void {
SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24);
window := SDL_CreateWindow("SX UI Demo", xx WIDTH, xx HEIGHT, SDL_WINDOW_OPENGL);
// Auto-size: on desktop use 75% of usable display, on WASM SDL picks up canvas size
init_w : s32 = 800;
init_h : s32 = 600;
inline if OS == .wasm {
init_w = emscripten_run_script_int("window.innerWidth");
init_h = emscripten_run_script_int("window.innerHeight");
} else {
display_id := SDL_GetPrimaryDisplay();
bounds : SDL_Rect = ---;
if SDL_GetDisplayUsableBounds(display_id, @bounds) {
init_w = bounds.w * 3 / 4;
init_h = bounds.h * 3 / 4;
}
}
window := SDL_CreateWindow("SX UI Demo", init_w, init_h, SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE | SDL_WINDOW_HIGH_PIXEL_DENSITY);
gl_ctx := SDL_GL_CreateContext(window);
SDL_GL_MakeCurrent(window, gl_ctx);
SDL_GL_SetSwapInterval(1);
load_gl(xx SDL_GL_GetProcAddress);
// Query actual window size (may differ from requested, especially on WASM)
SDL_GetWindowSize(window, @g_width, @g_height);
SDL_GetWindowSizeInPixels(window, @g_pixel_w, @g_pixel_h);
width_f : f32 = xx g_width;
height_f : f32 = xx g_height;
dpi_scale : f32 = if width_f > 0.0 then xx g_pixel_w / width_f else 1.0;
// Set viewport to physical pixel dimensions
glViewport(0, 0, g_pixel_w, g_pixel_h);
// --- Build UI ---
pipeline : UIPipeline = ---;
pipeline.init(WIDTH, HEIGHT);
pipeline.init_font("assets/fonts/default.ttf", 32.0);
pipeline.init(width_f, height_f);
pipeline.init_font("assets/fonts/default.ttf", 32.0, dpi_scale);
scroll_content := VStack.{ spacing = 10.0, alignment = .center } {
self.add(
@@ -220,7 +236,7 @@ main :: () -> void {
});
self.add(
RectView.{ color = COLOR_DARK_GRAY, preferred_height = 60.0 }
|> padding(EdgeInsets.symmetric(16.0, 8.0))
|> padding(.symmetric(16.0, 8.0))
|> background(COLOR_BLUE, 8.0)
);
self.add(RectView.{ color = COLOR_ORANGE, preferred_height = 120.0, corner_radius = 12.0 });
@@ -243,6 +259,8 @@ main :: () -> void {
}
}
save_snapshot("goldens/last_frame.png", g_pixel_w, g_pixel_h);
SDL_GL_DestroyContext(gl_ctx);
SDL_DestroyWindow(window);
SDL_Quit();