pxl8/src/pxl8_lua.c

280 lines
9 KiB
C
Raw Normal View History

2025-08-13 15:04:49 -05:00
#include "pxl8_lua.h"
#include "pxl8_vfx.h"
#include "pxl8_macros.h"
static const char* pxl8_ffi_cdefs =
"typedef uint8_t u8;\n"
"typedef uint16_t u16;\n"
"typedef uint32_t u32;\n"
"typedef uint64_t u64;\n"
"typedef int8_t i8;\n"
"typedef int16_t i16;\n"
"typedef int32_t i32;\n"
"typedef int64_t i64;\n"
"typedef float f32;\n"
"typedef double f64;\n"
"typedef struct pxl8_gfx_ctx pxl8_gfx_ctx;\n"
"typedef struct { int x, y, w, h; } pxl8_rect;\n"
"typedef struct { int x, y; } pxl8_point;\n"
"typedef struct {\n"
" int width, height;\n"
" int color_mode;\n"
" unsigned char* pixels;\n"
"} pxl8_screen;\n"
"\n"
"void pxl8_clr(pxl8_gfx_ctx* ctx, u32 color);\n"
"void pxl8_pixel(pxl8_gfx_ctx* ctx, i32 x, i32 y, u32 color);\n"
"u32 pxl8_get_pixel(pxl8_gfx_ctx* ctx, i32 x, i32 y);\n"
"void pxl8_line(pxl8_gfx_ctx* ctx, i32 x0, i32 y0, i32 x1, i32 y1, u32 color);\n"
"void pxl8_rect(pxl8_gfx_ctx* ctx, i32 x, i32 y, i32 w, i32 h, u32 color);\n"
"void pxl8_rect_fill(pxl8_gfx_ctx* ctx, i32 x, i32 y, i32 w, i32 h, u32 color);\n"
"void pxl8_circle(pxl8_gfx_ctx* ctx, i32 x, i32 y, i32 r, u32 color);\n"
"void pxl8_circle_fill(pxl8_gfx_ctx* ctx, i32 x, i32 y, i32 r, u32 color);\n"
"void pxl8_text(pxl8_gfx_ctx* ctx, const char* str, i32 x, i32 y, u32 color);\n"
"void pxl8_sprite(pxl8_gfx_ctx* ctx, i32 id, i32 x, i32 y, i32 w, i32 h, bool flip_x, bool flip_y);\n"
"pxl8_screen* pxl8_get_screen(pxl8_gfx_ctx* ctx);\n"
"i32 pxl8_gfx_load_palette(pxl8_gfx_ctx* ctx, const char* filepath);\n"
"i32 pxl8_gfx_load_sprite(pxl8_gfx_ctx* ctx, const char* filepath, u32* sprite_id);\n"
"void pxl8_gfx_color_ramp(pxl8_gfx_ctx* ctx, u8 start, u8 count, u32 from_color, u32 to_color);\n"
"void pxl8_gfx_fade_palette(pxl8_gfx_ctx* ctx, u8 start, u8 count, f32 amount, u32 target_color);\n"
"void pxl8_lua_info(const char* msg);\n"
"void pxl8_lua_warn(const char* msg);\n"
"void pxl8_lua_error(const char* msg);\n"
"void pxl8_lua_debug(const char* msg);\n"
"void pxl8_lua_trace(const char* msg);\n"
"typedef struct pxl8_input_state pxl8_input_state;\n"
"bool pxl8_key_down(const pxl8_input_state* input, i32 key);\n"
"bool pxl8_key_pressed(const pxl8_input_state* input, i32 key);\n"
"\n"
"typedef struct {\n"
" float x, y, z;\n"
" float vx, vy, vz;\n"
" float ax, ay, az;\n"
" float life;\n"
" float max_life;\n"
" unsigned int color;\n"
" unsigned int start_color;\n"
" unsigned int end_color;\n"
" float size;\n"
" float angle;\n"
" float spin;\n"
" unsigned char flags;\n"
"} pxl8_particle;\n"
"\n"
"typedef struct {\n"
" pxl8_particle* particles;\n"
" unsigned int count;\n"
" unsigned int max_count;\n"
" unsigned int alive_count;\n"
" float spawn_rate;\n"
" float spawn_timer;\n"
" float x, y;\n"
" float spread_x, spread_y;\n"
" float gravity_x, gravity_y;\n"
" float drag;\n"
" float turbulence;\n"
" void* spawn_fn;\n"
" void* update_fn;\n"
" void* render_fn;\n"
" void* userdata;\n"
"} pxl8_particle_system;\n"
"\n"
"typedef struct {\n"
" float base_y;\n"
" float amplitude;\n"
" int height;\n"
" float speed;\n"
" float phase;\n"
" unsigned int color;\n"
" unsigned int fade_color;\n"
"} pxl8_copper_bar;\n"
"\n"
"void pxl8_vfx_copper_bars(pxl8_gfx_ctx* ctx, pxl8_copper_bar* bars, u32 bar_count, f32 time);\n"
"void pxl8_vfx_plasma(pxl8_gfx_ctx* ctx, f32 time, f32 scale1, f32 scale2, u8 palette_offset);\n"
"void pxl8_vfx_rotozoom(pxl8_gfx_ctx* ctx, f32 angle, f32 zoom, i32 cx, i32 cy);\n"
"void pxl8_vfx_tunnel(pxl8_gfx_ctx* ctx, f32 time, f32 speed, f32 twist);\n"
"void pxl8_vfx_water_ripple(pxl8_gfx_ctx* ctx, f32* height_map, i32 drop_x, i32 drop_y, f32 damping);\n"
"\n"
"void pxl8_vfx_particles_clear(pxl8_particle_system* sys);\n"
"void pxl8_vfx_particles_destroy(pxl8_particle_system* sys);\n"
"void pxl8_vfx_particles_emit(pxl8_particle_system* sys, u32 count);\n"
"void pxl8_vfx_particles_init(pxl8_particle_system* sys, unsigned int max_count);\n"
"void pxl8_vfx_particles_render(pxl8_particle_system* sys, pxl8_gfx_ctx* ctx);\n"
"void pxl8_vfx_particles_update(pxl8_particle_system* sys, float dt);\n"
"\n"
"void pxl8_vfx_explosion(pxl8_particle_system* sys, int x, int y, unsigned int color, float force);\n"
"void pxl8_vfx_fire(pxl8_particle_system* sys, int x, int y, int width, unsigned char palette_start);\n"
"void pxl8_vfx_rain(pxl8_particle_system* sys, int width, float wind);\n"
"void pxl8_vfx_smoke(pxl8_particle_system* sys, int x, int y, unsigned char color);\n"
"void pxl8_vfx_snow(pxl8_particle_system* sys, int width, float wind);\n"
"void pxl8_vfx_sparks(pxl8_particle_system* sys, int x, int y, unsigned int color);\n"
"void pxl8_vfx_starfield(pxl8_particle_system* sys, float speed, float spread);\n";
typedef struct {
int width, height;
int color_mode;
unsigned char* pixels;
} pxl8_screen;
pxl8_screen* pxl8_get_screen(pxl8_gfx_ctx* ctx) {
if (!ctx) return NULL;
static pxl8_screen screen = {0};
screen.width = ctx->framebuffer_width;
screen.height = ctx->framebuffer_height;
screen.color_mode = ctx->color_mode;
screen.pixels = ctx->framebuffer;
return &screen;
}
void pxl8_lua_info(const char* msg) {
pxl8_info("%s", msg);
}
void pxl8_lua_warn(const char* msg) {
pxl8_warn("%s", msg);
}
void pxl8_lua_error(const char* msg) {
pxl8_error("%s", msg);
}
void pxl8_lua_debug(const char* msg) {
pxl8_debug("%s", msg);
}
void pxl8_lua_trace(const char* msg) {
pxl8_trace("%s", msg);
}
pxl8_result pxl8_lua_init(lua_State** lua_state) {
if (!lua_state) return PXL8_ERROR_NULL_POINTER;
*lua_state = luaL_newstate();
if (!*lua_state) {
return PXL8_ERROR_OUT_OF_MEMORY;
}
luaL_openlibs(*lua_state);
lua_getglobal(*lua_state, "require");
lua_pushstring(*lua_state, "ffi");
if (lua_pcall(*lua_state, 1, 1, 0) != 0) {
lua_close(*lua_state);
*lua_state = NULL;
return PXL8_ERROR_SYSTEM_FAILURE;
}
lua_getfield(*lua_state, -1, "cdef");
lua_pushstring(*lua_state, pxl8_ffi_cdefs);
if (lua_pcall(*lua_state, 1, 0, 0) != 0) {
lua_close(*lua_state);
*lua_state = NULL;
return PXL8_ERROR_SYSTEM_FAILURE;
}
lua_pop(*lua_state, 1);
lua_getglobal(*lua_state, "package");
lua_getfield(*lua_state, -1, "path");
const char* current_path = lua_tostring(*lua_state, -1);
lua_pop(*lua_state, 1);
lua_pushfstring(*lua_state, "%s;src/lua/?.lua", current_path);
lua_setfield(*lua_state, -2, "path");
lua_pop(*lua_state, 1);
if (luaL_dofile(*lua_state, "lib/fennel/fennel.lua") == 0) {
lua_setglobal(*lua_state, "fennel");
}
return PXL8_OK;
}
void pxl8_lua_shutdown(lua_State* lua_state) {
if (lua_state) {
lua_close(lua_state);
}
}
pxl8_result pxl8_lua_setup_contexts(lua_State* lua_state, pxl8_gfx_ctx* gfx_ctx, pxl8_input_state* input) {
if (!lua_state || !gfx_ctx || !input) return PXL8_ERROR_NULL_POINTER;
lua_pushlightuserdata(lua_state, gfx_ctx);
lua_setglobal(lua_state, "_pxl8_gfx_ctx");
lua_pushlightuserdata(lua_state, input);
lua_setglobal(lua_state, "_pxl8_input_ctx");
return PXL8_OK;
}
pxl8_result pxl8_lua_run_file(lua_State* lua_state, const char* filename) {
if (!lua_state || !filename) return PXL8_ERROR_NULL_POINTER;
if (luaL_dofile(lua_state, filename) != 0) {
printf("Lua error: %s\n", lua_tostring(lua_state, -1));
lua_pop(lua_state, 1);
return PXL8_ERROR_SCRIPT_ERROR;
}
return PXL8_OK;
}
pxl8_result pxl8_lua_run_string(lua_State* lua_state, const char* code) {
if (!lua_state || !code) return PXL8_ERROR_NULL_POINTER;
if (luaL_dostring(lua_state, code) != 0) {
printf("Lua error: %s\n", lua_tostring(lua_state, -1));
lua_pop(lua_state, 1);
return PXL8_ERROR_SCRIPT_ERROR;
}
return PXL8_OK;
}
pxl8_result pxl8_lua_run_fennel_file(lua_State* lua_state, const char* filename) {
if (!lua_state || !filename) return PXL8_ERROR_NULL_POINTER;
lua_getglobal(lua_state, "fennel");
if (lua_isnil(lua_state, -1)) {
lua_pop(lua_state, 1);
return PXL8_ERROR_SCRIPT_ERROR;
}
lua_getfield(lua_state, -1, "dofile");
lua_pushstring(lua_state, filename);
if (lua_pcall(lua_state, 1, 0, 0) != 0) {
printf("Fennel error: %s\n", lua_tostring(lua_state, -1));
lua_pop(lua_state, 1);
return PXL8_ERROR_SCRIPT_ERROR;
}
lua_pop(lua_state, 1);
return PXL8_OK;
}
pxl8_result pxl8_lua_eval_fennel(lua_State* lua_state, const char* code) {
if (!lua_state || !code) return PXL8_ERROR_NULL_POINTER;
lua_getglobal(lua_state, "fennel");
if (lua_isnil(lua_state, -1)) {
lua_pop(lua_state, 1);
return PXL8_ERROR_SCRIPT_ERROR;
}
lua_getfield(lua_state, -1, "eval");
lua_pushstring(lua_state, code);
if (lua_pcall(lua_state, 1, 1, 0) != 0) {
lua_remove(lua_state, -2);
return PXL8_ERROR_SCRIPT_ERROR;
}
lua_remove(lua_state, -2);
return PXL8_OK;
}