#import "modules/std.sx"; #import "modules/sdl3.sx"; #import "modules/opengl.sx"; #import "modules/math"; #import "modules/stb.sx"; #import "ui"; WIDTH :f32: 800; HEIGHT :f32: 600; save_snapshot :: (path: [:0]u8, w: s32, h: s32) { stride : s64 = w * 4; buf_size : s64 = stride * h; pixels : [*]u8 = xx context.allocator.alloc(buf_size); glReadPixels(0, 0, w, h, GL_RGBA, GL_UNSIGNED_BYTE, pixels); // Flip vertically (GL reads bottom-up, PNG expects top-down) row_buf : [*]u8 = xx context.allocator.alloc(stride); i : s32 = 0; while i < h / 2 { top : s64 = xx i * stride; bot : s64 = xx (h - 1 - i) * stride; memcpy(row_buf, @pixels[top], stride); memcpy(@pixels[top], @pixels[bot], stride); memcpy(@pixels[bot], row_buf, stride); i += 1; } stbi_write_png(path, w, h, 4, pixels, xx stride); out("Saved "); out(path); out("\n"); } main :: () -> void { SDL_Init(SDL_INIT_VIDEO); SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3); SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 3); SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE); SDL_GL_SetAttribute(SDL_GL_CONTEXT_FLAGS, SDL_GL_CONTEXT_FORWARD_COMPATIBLE_FLAG); 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); gl_ctx := SDL_GL_CreateContext(window); SDL_GL_MakeCurrent(window, gl_ctx); SDL_GL_SetSwapInterval(1); load_gl(SDL_GL_GetProcAddress); load_gl_ui(SDL_GL_GetProcAddress); // --- Build UI --- pipeline : UIPipeline = ---; pipeline.init(WIDTH, HEIGHT); // Create a simple layout: VStack with colored rects and a button root := VStack.{ spacing = 10.0, alignment = .center }; header := RectView.{ color = COLOR_YELLOW, preferred_height = 80.0, corner_radius = 8.0 }; root.add(xx header); btn := Button.{ label = "Click Me", font_size = 14.0, style = ButtonStyle.default(), on_tap = null }; root.add(xx btn); body := HStack.{ spacing = 10.0, alignment = .center }; left := RectView.{ color = COLOR_RED, preferred_width = 200.0, preferred_height = 300.0, corner_radius = 4.0 }; body.add(xx left); right := RectView.{ color = COLOR_GREEN, preferred_width = 200.0, preferred_height = 300.0, corner_radius = 4.0 }; body.add(xx right); root.add(xx body); footer := RectView.{ color = COLOR_DARK_GRAY, preferred_height = 60.0 }; root.add(xx footer); pipeline.set_root(xx root); // --- Main loop --- running := true; sdl_event : SDL_Event = .none; while running { while SDL_PollEvent(sdl_event) { if sdl_event == { case .quit: running = false; case .key_up: (e) { if e.key == { case .escape: running = false; } } } // Forward to UI ui_event := translate_sdl_event(@sdl_event); if ui_event.type != .none { pipeline.dispatch_event(@ui_event); } } glClearColor(0.12, 0.12, 0.15, 1.0); glClear(GL_COLOR_BUFFER_BIT); pipeline.tick(); SDL_GL_SwapWindow(window); } // Re-render one frame for snapshot (back buffer is stale after swap) glClearColor(0.12, 0.12, 0.15, 1.0); glClear(GL_COLOR_BUFFER_BIT); pipeline.tick(); save_snapshot("goldens/last_frame.png", xx WIDTH, xx HEIGHT); SDL_GL_DestroyContext(gl_ctx); SDL_DestroyWindow(window); SDL_Quit(); }