121 lines
3.6 KiB
Plaintext
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 = 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();
|
|
}
|