Files
game/main.sx
2026-02-24 19:22:05 +02:00

121 lines
3.6 KiB
Plaintext

#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 = xx (w * 4);
buf_size : s64 = stride * xx 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();
}