#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; }