refactor pxl8 repl

This commit is contained in:
asrael 2025-12-02 11:02:23 -06:00
parent 04d3af11a9
commit 3313c800a9
No known key found for this signature in database
GPG key ID: 2786557804DFAE24
25 changed files with 537 additions and 424 deletions

View file

@ -12,7 +12,8 @@
#include "pxl8_cart.h"
#include "pxl8_game.h"
#include "pxl8_hal.h"
#include "pxl8_macros.h"
#include "pxl8_log.h"
#include "pxl8_repl.h"
#include "pxl8_script.h"
#include "pxl8_sys.h"
#include "pxl8_types.h"
@ -20,19 +21,21 @@
struct pxl8 {
pxl8_cart* cart;
pxl8_game* game;
pxl8_repl* repl;
pxl8_log log;
const pxl8_hal* hal;
void* platform_data;
};
pxl8* pxl8_create(const pxl8_hal* hal) {
if (!hal) {
pxl8_error("HAL cannot be NULL");
return NULL;
}
pxl8* sys = (pxl8*)calloc(1, sizeof(pxl8));
if (!sys) {
pxl8_error("Failed to allocate pxl8 system");
if (!sys) return NULL;
pxl8_log_init(&sys->log);
if (!hal) {
pxl8_error("hal cannot be null");
free(sys);
return NULL;
}
@ -40,7 +43,7 @@ pxl8* pxl8_create(const pxl8_hal* hal) {
sys->game = (pxl8_game*)calloc(1, sizeof(pxl8_game));
if (!sys->game) {
pxl8_error("Failed to allocate game");
pxl8_error("failed to allocate game");
free(sys);
return NULL;
}
@ -51,31 +54,19 @@ pxl8* pxl8_create(const pxl8_hal* hal) {
void pxl8_destroy(pxl8* sys) {
if (!sys) return;
if (sys->game) {
free(sys->game);
}
if (sys->cart) {
pxl8_cart_destroy(sys->cart);
}
if (sys->hal && sys->platform_data) {
sys->hal->destroy(sys->platform_data);
}
if (sys->game) free(sys->game);
if (sys->cart) pxl8_cart_destroy(sys->cart);
if (sys->hal && sys->platform_data) sys->hal->destroy(sys->platform_data);
free(sys);
}
pxl8_result pxl8_init(pxl8* sys, i32 argc, char* argv[]) {
if (!sys || !sys->game) {
return PXL8_ERROR_INVALID_ARGUMENT;
}
if (!sys || !sys->game) return PXL8_ERROR_INVALID_ARGUMENT;
pxl8_game* game = sys->game;
pxl8_pixel_mode pixel_mode = PXL8_PIXEL_INDEXED;
pxl8_resolution resolution = PXL8_RESOLUTION_640x360;
const char* script_arg = NULL;
bool bundle_mode = false;
bool pack_mode = false;
@ -112,7 +103,7 @@ pxl8_result pxl8_init(pxl8* sys, i32 argc, char* argv[]) {
char exe_path[1024];
ssize_t len = readlink("/proc/self/exe", exe_path, sizeof(exe_path) - 1);
if (len == -1) {
pxl8_error("Failed to resolve executable path");
pxl8_error("failed to resolve executable path");
return PXL8_ERROR_SYSTEM_FAILURE;
}
exe_path[len] = '\0';
@ -126,31 +117,31 @@ pxl8_result pxl8_init(pxl8* sys, i32 argc, char* argv[]) {
}
if (game->repl_mode) {
fprintf(stderr, "\033[38;2;184;187;38m[pxl8]\033[0m Starting in REPL mode with script: %s\n", game->script_path);
pxl8_info("starting in REPL mode with script: %s", game->script_path);
}
pxl8_info("Starting up");
pxl8_info("starting up");
sys->platform_data = sys->hal->create(pixel_mode, resolution, "pxl8", 1280, 720);
if (!sys->platform_data) {
pxl8_error("Failed to create platform context");
pxl8_error("failed to create platform context");
return PXL8_ERROR_INITIALIZATION_FAILED;
}
game->gfx = pxl8_gfx_create(sys->hal, sys->platform_data, pixel_mode, resolution);
if (!game->gfx) {
pxl8_error("Failed to create graphics context");
pxl8_error("failed to create graphics context");
return PXL8_ERROR_INITIALIZATION_FAILED;
}
if (pxl8_gfx_load_font_atlas(game->gfx) != PXL8_OK) {
pxl8_error("Failed to load font atlas");
pxl8_error("failed to load font atlas");
return PXL8_ERROR_INITIALIZATION_FAILED;
}
game->script = pxl8_script_create(game->repl_mode);
if (!game->script) {
pxl8_error("Failed to initialize scripting: %s", pxl8_script_get_last_error(game->script));
pxl8_error("failed to initialize scripting: %s", pxl8_script_get_last_error(game->script));
return PXL8_ERROR_INITIALIZATION_FAILED;
}
@ -160,16 +151,16 @@ pxl8_result pxl8_init(pxl8* sys, i32 argc, char* argv[]) {
if (has_embedded && !script_arg) {
sys->cart = pxl8_cart_create();
if (!sys->cart) {
pxl8_error("Failed to create cart");
pxl8_error("failed to create cart");
return PXL8_ERROR_INITIALIZATION_FAILED;
}
if (pxl8_cart_load_embedded(sys->cart, argv[0]) == PXL8_OK) {
pxl8_cart_mount(sys->cart);
strncpy(game->script_path, "main.fnl", sizeof(game->script_path) - 1);
game->script_path[sizeof(game->script_path) - 1] = '\0';
pxl8_info("Running embedded cart");
pxl8_info("running embedded cart");
} else {
pxl8_error("Failed to load embedded cart");
pxl8_error("failed to load embedded cart");
return PXL8_ERROR_INITIALIZATION_FAILED;
}
} else if (cart_path || !has_embedded) {
@ -183,7 +174,7 @@ pxl8_result pxl8_init(pxl8* sys, i32 argc, char* argv[]) {
char* original_cwd = getcwd(NULL, 0);
sys->cart = pxl8_cart_create();
if (!sys->cart) {
pxl8_error("Failed to create cart");
pxl8_error("failed to create cart");
return PXL8_ERROR_INITIALIZATION_FAILED;
}
if (pxl8_cart_load(sys->cart, cart_path) == PXL8_OK) {
@ -192,7 +183,7 @@ pxl8_result pxl8_init(pxl8* sys, i32 argc, char* argv[]) {
strncpy(game->script_path, "main.fnl", sizeof(game->script_path) - 1);
game->script_path[sizeof(game->script_path) - 1] = '\0';
} else {
pxl8_error("Failed to load cart: %s", cart_path);
pxl8_error("failed to load cart: %s", cart_path);
return PXL8_ERROR_INITIALIZATION_FAILED;
}
free(original_cwd);
@ -227,19 +218,22 @@ pxl8_result pxl8_update(pxl8* sys) {
}
pxl8_game* game = sys->game;
u64 current_time = sys->hal->get_ticks();
f32 dt = (f32)(current_time - game->last_time) / 1000000000.0f;
game->last_time = current_time;
game->time += dt;
game->fps_accumulator += dt;
game->fps_frame_count++;
if (game->fps_accumulator >= 1.0f) {
game->fps = (f32)game->fps_frame_count / game->fps_accumulator;
if (!game->repl_mode) {
pxl8_debug("FPS: %.1f (%.2fms)", game->fps, (game->fps_accumulator / game->fps_frame_count) * 1000.0f);
pxl8_debug(
"FPS: %.1f (%.2fms)",
game->fps,
(game->fps_accumulator / game->fps_frame_count) * 1000.0f
);
}
game->fps_accumulator = 0.0f;
game->fps_frame_count = 0;
@ -252,37 +246,30 @@ pxl8_result pxl8_update(pxl8* sys) {
pxl8_script_call_function(game->script, "init");
}
game->repl = pxl8_script_repl_create();
if (game->repl) {
fprintf(stderr, "\033[38;2;184;187;38m[pxl8 REPL]\033[0m Fennel %s - Tab for completions, Ctrl-D to exit\n", "1.5.1");
if (pxl8_script_load_module(game->script, "pxl8") != PXL8_OK) {
fprintf(stderr, "Warning: Failed to setup pxl8 global: %s\n", pxl8_script_get_last_error(game->script));
}
pxl8_script_repl_init(game->repl);
game->repl_started = true;
if (pxl8_script_load_module(game->script, "pxl8") != PXL8_OK) {
const char* err_msg = pxl8_script_get_last_error(game->script);
pxl8_error("failed to setup pxl8 global: %s", err_msg);
}
sys->repl = pxl8_repl_create();
game->repl_started = true;
}
if (game->repl_mode && game->repl) {
if (pxl8_script_repl_should_quit(game->repl)) {
game->running = false;
}
if (game->repl_mode && sys->repl) {
if (pxl8_repl_should_quit(sys->repl)) game->running = false;
pxl8_script_repl_command* cmd = pxl8_script_repl_pop_command(game->repl);
pxl8_repl_command* cmd = pxl8_repl_pop_command(sys->repl);
if (cmd) {
pxl8_result result = pxl8_script_eval_repl(game->script, pxl8_script_repl_command_buffer(cmd));
pxl8_result result = pxl8_script_eval_repl(game->script, pxl8_repl_command_buffer(cmd));
if (result != PXL8_OK) {
if (pxl8_script_is_incomplete_input(game->script)) {
} else {
pxl8_error("%s", pxl8_script_get_last_error(game->script));
pxl8_script_repl_clear_accumulator(game->repl);
pxl8_repl_clear_accumulator(sys->repl);
}
} else {
pxl8_script_repl_clear_accumulator(game->repl);
pxl8_repl_clear_accumulator(sys->repl);
}
pxl8_script_repl_eval_complete(game->repl);
}
}
@ -296,9 +283,7 @@ pxl8_result pxl8_update(pxl8* sys) {
}
pxl8_result pxl8_frame(pxl8* sys) {
if (!sys || !sys->game) {
return PXL8_ERROR_INVALID_ARGUMENT;
}
if (!sys || !sys->game) return PXL8_ERROR_INVALID_ARGUMENT;
pxl8_game* game = sys->game;
pxl8_bounds bounds = pxl8_gfx_get_bounds(game->gfx);
@ -306,7 +291,7 @@ pxl8_result pxl8_frame(pxl8* sys) {
if (game->script_loaded) {
pxl8_result frame_result = pxl8_script_call_function(game->script, "frame");
if (frame_result == PXL8_ERROR_SCRIPT_ERROR) {
pxl8_error("Error calling frame: %s", pxl8_script_get_last_error(game->script));
pxl8_error("error calling frame: %s", pxl8_script_get_last_error(game->script));
}
} else {
pxl8_clear(game->gfx, 32);
@ -331,13 +316,13 @@ pxl8_result pxl8_frame(pxl8* sys) {
memset(game->input.keys_released, 0, sizeof(game->input.keys_released));
memset(game->input.mouse_buttons_pressed, 0, sizeof(game->input.mouse_buttons_pressed));
memset(game->input.mouse_buttons_released, 0, sizeof(game->input.mouse_buttons_released));
game->frame_count++;
game->input.mouse_dx = 0;
game->input.mouse_dy = 0;
game->input.mouse_wheel_x = 0;
game->input.mouse_wheel_y = 0;
game->frame_count++;
return PXL8_OK;
}
@ -346,14 +331,7 @@ void pxl8_quit(pxl8* sys) {
pxl8_game* game = sys->game;
if (game->repl_mode && game->repl) {
fprintf(stderr, "\r\033[K");
fflush(stderr);
pxl8_script_repl_shutdown(game->repl);
pxl8_script_repl_destroy(game->repl);
}
pxl8_info("Shutting down");
pxl8_info("shutting down");
if (sys->cart) {
pxl8_cart_unmount(sys->cart);
@ -361,6 +339,10 @@ void pxl8_quit(pxl8* sys) {
pxl8_gfx_destroy(game->gfx);
pxl8_script_destroy(game->script);
if (sys->repl) {
pxl8_repl_destroy(sys->repl);
}
}
bool pxl8_is_running(const pxl8* sys) {