add ui module

This commit is contained in:
asrael 2025-10-04 11:55:04 -05:00
parent 1744e689b5
commit 6008ebf5ed
12 changed files with 703 additions and 215 deletions

View file

@ -18,6 +18,7 @@
#include "pxl8_macros.h"
#include "pxl8_script.h"
#include "pxl8_types.h"
#include "pxl8_ui.h"
#define PXL8_MAX_REPL_COMMANDS 4096
@ -41,7 +42,9 @@ typedef struct pxl8_state {
pxl8_repl_state repl;
pxl8_resolution resolution;
pxl8_script* script;
pxl8_ui* ui;
f32 current_fps;
f32 fps_timer;
i32 frame_count;
u64 last_time;
@ -50,6 +53,7 @@ typedef struct pxl8_state {
bool repl_mode;
bool running;
bool script_loaded;
bool show_fps;
char script_path[256];
pxl8_input_state input;
@ -246,6 +250,13 @@ SDL_AppResult SDL_AppInit(void** appstate, int argc, char* argv[]) {
return SDL_APP_FAILURE;
}
app.ui = pxl8_ui_create(app.gfx);
if (!app.ui) {
pxl8_error("Failed to create UI");
pxl8_gfx_destroy(app.gfx);
return SDL_APP_FAILURE;
}
app.script = pxl8_script_create();
if (!app.script) {
pxl8_error("Failed to initialize scripting: %s", pxl8_script_get_last_error(app.script));
@ -283,6 +294,7 @@ SDL_AppResult SDL_AppInit(void** appstate, int argc, char* argv[]) {
pxl8_script_set_gfx(app.script, app.gfx);
pxl8_script_set_input(app.script, &app.input);
pxl8_script_set_ui(app.script, app.ui);
if (app.script_path[0] != '\0') {
pxl8_result result = pxl8_script_load_main(app.script, app.script_path);
@ -317,11 +329,8 @@ SDL_AppResult SDL_AppIterate(void* appstate) {
app->last_time = current_time;
app->time += dt;
if (app->fps_timer >= 3.0f) {
if (!app->repl_mode) {
f32 avg_fps = app->frame_count / app->fps_timer;
pxl8_info("FPS: %.1f", avg_fps);
}
if (app->fps_timer >= 1.0f) {
app->current_fps = app->frame_count / app->fps_timer;
app->frame_count = 0;
app->fps_timer = 0.0f;
}
@ -339,6 +348,29 @@ SDL_AppResult SDL_AppIterate(void* appstate) {
}
}
if (app->ui) {
pxl8_ui_frame_begin(app->ui);
for (i32 i = 0; i < 3; i++) {
if (app->input.mouse_buttons[i] && app->input.mouse_buttons_pressed[i]) {
pxl8_ui_input_mousedown(app->ui, app->input.mouse_x, app->input.mouse_y, i + 1);
}
if (!app->input.mouse_buttons[i]) {
pxl8_ui_input_mouseup(app->ui, app->input.mouse_x, app->input.mouse_y, i + 1);
}
}
pxl8_ui_input_mousemove(app->ui, app->input.mouse_x, app->input.mouse_y);
for (i32 key = 0; key < 256; key++) {
if (app->input.keys_pressed[key]) {
pxl8_ui_input_keydown(app->ui, key);
}
if (!app->input.keys[key] && app->input.keys_pressed[key]) {
pxl8_ui_input_keyup(app->ui, key);
}
}
}
if (app->script_loaded) {
pxl8_script_call_function_f32(app->script, "update", dt);
@ -348,10 +380,10 @@ SDL_AppResult SDL_AppIterate(void* appstate) {
}
} else {
pxl8_clr(app->gfx, 32);
i32 render_width, render_height;
pxl8_gfx_get_resolution_dimensions(app->resolution, &render_width, &render_height);
for (i32 y = 0; y < render_height; y += 24) {
for (i32 x = 0; x < render_width; x += 32) {
u32 color = ((x / 32) + (y / 24) + (i32)(app->time * 2)) % 8;
@ -359,22 +391,29 @@ SDL_AppResult SDL_AppIterate(void* appstate) {
}
}
}
i32 render_width, render_height;
pxl8_gfx_get_resolution_dimensions(app->resolution, &render_width, &render_height);
f32 scale = fminf(bounds.w / (f32)render_width, bounds.h / (f32)render_height);
i32 scaled_width = (i32)(render_width * scale);
i32 scaled_height = (i32)(render_height * scale);
i32 offset_x = (bounds.w - scaled_width) / 2;
i32 offset_y = (bounds.h - scaled_height) / 2;
pxl8_gfx_viewport(app->gfx, offset_x, offset_y, scaled_width, scaled_height);
if (app->show_fps && app->current_fps > 0.0f) {
char fps_text[32];
SDL_snprintf(fps_text, sizeof(fps_text), "FPS: %d", (i32)(app->current_fps + 0.5f));
pxl8_text(app->gfx, fps_text, render_width - 80, 10, 15);
}
if (app->ui) {
pxl8_ui_frame_end(app->ui);
}
pxl8_gfx_set_viewport(app->gfx, pxl8_gfx_viewport(bounds, render_width, render_height));
pxl8_gfx_upload_framebuffer(app->gfx);
pxl8_gfx_upload_atlas(app->gfx);
pxl8_gfx_present(app->gfx);
SDL_memset(app->input.keys_pressed, 0, sizeof(app->input.keys_pressed));
SDL_memset(app->input.mouse_buttons_pressed, 0, sizeof(app->input.mouse_buttons_pressed));
app->input.mouse_wheel_x = 0;
app->input.mouse_wheel_y = 0;
return app->running ? SDL_APP_CONTINUE : SDL_APP_SUCCESS;
}
@ -392,7 +431,11 @@ SDL_AppResult SDL_AppEvent(void* appstate, SDL_Event* event) {
app->running = false;
return SDL_APP_SUCCESS;
}
if (event->key.key == SDLK_F3) {
app->show_fps = !app->show_fps;
}
SDL_Keycode key = event->key.key;
if (key < 256) {
if (!app->input.keys[key]) {
@ -411,8 +454,46 @@ SDL_AppResult SDL_AppEvent(void* appstate, SDL_Event* event) {
}
break;
}
case SDL_EVENT_MOUSE_BUTTON_DOWN: {
u8 button = event->button.button - 1;
if (button < 3) {
if (!app->input.mouse_buttons[button]) {
app->input.mouse_buttons_pressed[button] = true;
}
app->input.mouse_buttons[button] = true;
}
break;
}
case SDL_EVENT_MOUSE_BUTTON_UP: {
u8 button = event->button.button - 1;
if (button < 3) {
app->input.mouse_buttons[button] = false;
}
break;
}
case SDL_EVENT_MOUSE_MOTION: {
i32 window_mouse_x = (i32)event->motion.x;
i32 window_mouse_y = (i32)event->motion.y;
i32 render_width, render_height;
pxl8_gfx_get_resolution_dimensions(app->resolution, &render_width, &render_height);
pxl8_viewport vp = pxl8_gfx_viewport(pxl8_gfx_get_bounds(app->gfx), render_width, render_height);
app->input.mouse_x = (i32)((window_mouse_x - vp.offset_x) / vp.scale);
app->input.mouse_y = (i32)((window_mouse_y - vp.offset_y) / vp.scale);
break;
}
case SDL_EVENT_MOUSE_WHEEL: {
app->input.mouse_wheel_x = (i32)event->wheel.x;
app->input.mouse_wheel_y = (i32)event->wheel.y;
break;
}
}
return SDL_APP_CONTINUE;
}
@ -431,6 +512,9 @@ void SDL_AppQuit(void* appstate, SDL_AppResult result) {
app->cart = NULL;
}
pxl8_script_destroy(app->script);
if (app->ui) {
pxl8_ui_destroy(app->ui);
}
pxl8_gfx_destroy(app->gfx);
}