add anim and transitions and re-org lua api scripts

This commit is contained in:
asrael 2025-11-15 11:40:27 -06:00
parent a15d0db902
commit 27b6459b9a
24 changed files with 1857 additions and 573 deletions

View file

@ -1,534 +1,174 @@
local ffi = require("ffi")
local C = ffi.C
local game = _pxl8_game
local gfx = _pxl8_gfx
local input = _pxl8_input
local ui = _pxl8_ui
local core = require("pxl8.core")
local graphics = require("pxl8.graphics")
local input = require("pxl8.input")
local vfx = require("pxl8.vfx")
local particles = require("pxl8.particles")
local tilemap = require("pxl8.tilemap")
local gfx3d = require("pxl8.gfx3d")
local math3d = require("pxl8.math")
local ui = require("pxl8.ui")
local world = require("pxl8.world")
local transition = require("pxl8.transition")
local anim = require("pxl8.anim")
core.init(_pxl8_game, _pxl8_gfx, _pxl8_input, _pxl8_ui)
local pxl8 = {}
function pxl8.clr(color)
C.pxl8_clr(gfx, color or 0)
end
function pxl8.pixel(x, y, color)
if color then
C.pxl8_pixel(gfx, x, y, color)
else
return C.pxl8_get_pixel(gfx, x, y)
end
end
function pxl8.line(x0, y0, x1, y1, color)
C.pxl8_line(gfx, x0, y0, x1, y1, color)
end
function pxl8.rect(x, y, w, h, color)
C.pxl8_rect(gfx, x, y, w, h, color)
end
function pxl8.rect_fill(x, y, w, h, color)
C.pxl8_rect_fill(gfx, x, y, w, h, color)
end
function pxl8.circle(x, y, r, color)
C.pxl8_circle(gfx, x, y, r, color)
end
function pxl8.circle_fill(x, y, r, color)
C.pxl8_circle_fill(gfx, x, y, r, color)
end
function pxl8.text(str, x, y, color)
C.pxl8_text(gfx, str, x or 0, y or 0, color or 15)
end
function pxl8.sprite(id, x, y, w, h, flip_x, flip_y)
C.pxl8_sprite(gfx, id or 0, x or 0, y or 0, w or 16, h or 16, flip_x or false, flip_y or false)
end
function pxl8.get_fps()
return C.pxl8_game_get_fps(game)
end
function pxl8.get_width()
return C.pxl8_gfx_get_width(gfx)
end
function pxl8.get_height()
return C.pxl8_gfx_get_height(gfx)
end
function pxl8.load_palette(filepath)
return C.pxl8_gfx_load_palette(gfx, filepath)
end
function pxl8.load_sprite(filepath)
local sprite_id = ffi.new("unsigned int[1]")
local result = C.pxl8_gfx_load_sprite(gfx, filepath, sprite_id)
if result == 0 then
return sprite_id[0]
else
return nil, result
end
end
function pxl8.create_texture(pixels, width, height)
local pixel_data = ffi.new("u8[?]", width * height)
for i = 0, width * height - 1 do
pixel_data[i] = pixels[i + 1] or 0
end
local result = C.pxl8_gfx_create_texture(gfx, pixel_data, width, height)
if result < 0 then
return nil
end
return result
end
function pxl8.upload_atlas()
C.pxl8_gfx_upload_atlas(gfx)
end
function pxl8.info(msg)
C.pxl8_lua_info(msg)
end
function pxl8.warn(msg)
C.pxl8_lua_warn(msg)
end
function pxl8.error(msg)
C.pxl8_lua_error(msg)
end
function pxl8.debug(msg)
C.pxl8_lua_debug(msg)
end
function pxl8.trace(msg)
C.pxl8_lua_trace(msg)
end
function pxl8.key_down(key)
return C.pxl8_key_down(input, key)
end
function pxl8.key_pressed(key)
return C.pxl8_key_pressed(input, key)
end
function pxl8.key_released(key)
return C.pxl8_key_released(input, key)
end
function pxl8.mouse_wheel_x()
return C.pxl8_mouse_wheel_x(input)
end
function pxl8.mouse_wheel_y()
return C.pxl8_mouse_wheel_y(input)
end
function pxl8.mouse_x()
return C.pxl8_mouse_x(input)
end
function pxl8.mouse_y()
return C.pxl8_mouse_y(input)
end
function pxl8.vfx_raster_bars(bars, time)
local c_bars = ffi.new("pxl8_raster_bar[?]", #bars)
for i, bar in ipairs(bars) do
c_bars[i-1].base_y = bar.base_y or 0
c_bars[i-1].amplitude = bar.amplitude or 10
c_bars[i-1].height = bar.height or 5
c_bars[i-1].speed = bar.speed or 1.0
c_bars[i-1].phase = bar.phase or 0
c_bars[i-1].color = bar.color or 15
c_bars[i-1].fade_color = bar.fade_color or bar.color or 15
end
C.pxl8_vfx_raster_bars(gfx, c_bars, #bars, time)
end
function pxl8.vfx_plasma(time, scale1, scale2, palette_offset)
C.pxl8_vfx_plasma(gfx, time, scale1 or 0.05, scale2 or 0.03, palette_offset or 0)
end
function pxl8.vfx_rotozoom(angle, zoom, cx, cy)
C.pxl8_vfx_rotozoom(gfx, angle, zoom, cx or pxl8.get_width()/2, cy or pxl8.get_height()/2)
end
function pxl8.vfx_tunnel(time, speed, twist)
C.pxl8_vfx_tunnel(gfx, time, speed or 2.0, twist or 0.5)
end
function pxl8.particles_new(max_count)
return C.pxl8_particles_create(max_count or 1000)
end
function pxl8.particles_destroy(ps)
C.pxl8_particles_destroy(ps)
end
function pxl8.particles_clear(ps)
C.pxl8_particles_clear(ps)
end
function pxl8.particles_emit(ps, count)
C.pxl8_particles_emit(ps, count or 1)
end
function pxl8.particles_update(ps, dt)
C.pxl8_particles_update(ps, dt)
end
function pxl8.particles_render(ps)
C.pxl8_particles_render(ps, gfx)
end
function pxl8.vfx_explosion(ps, x, y, color, force)
C.pxl8_vfx_explosion(ps, x, y, color or 15, force or 200.0)
end
function pxl8.vfx_fire(ps, x, y, width, palette_start)
C.pxl8_vfx_fire(ps, x, y, width or 50, palette_start or 64)
end
function pxl8.vfx_rain(ps, width, wind)
C.pxl8_vfx_rain(ps, width or pxl8.get_width(), wind or 0.0)
end
function pxl8.vfx_smoke(ps, x, y, color)
C.pxl8_vfx_smoke(ps, x, y, color or 8)
end
function pxl8.vfx_snow(ps, width, wind)
C.pxl8_vfx_snow(ps, width or pxl8.get_width(), wind or 10.0)
end
function pxl8.vfx_sparks(ps, x, y, color)
C.pxl8_vfx_sparks(ps, x, y, color or 15)
end
function pxl8.vfx_starfield(ps, speed, spread)
C.pxl8_vfx_starfield(ps, speed or 5.0, spread or 500.0)
end
function pxl8.gfx_color_ramp(start, count, from_color, to_color)
C.pxl8_gfx_color_ramp(gfx, start, count, from_color, to_color)
end
function pxl8.gfx_fade_palette(start, count, amount, target_color)
C.pxl8_gfx_fade_palette(gfx, start, count, amount, target_color)
end
function pxl8.tilesheet_new(tile_size)
return C.pxl8_tilesheet_create(tile_size or 16)
end
function pxl8.tilesheet_destroy(tilesheet)
C.pxl8_tilesheet_destroy(tilesheet)
end
function pxl8.tilesheet_load(tilesheet, filepath)
return C.pxl8_tilesheet_load(tilesheet, filepath, gfx)
end
function pxl8.tilemap_new(width, height, tile_size)
return C.pxl8_tilemap_create(width, height, tile_size or 16)
end
function pxl8.tilemap_destroy(tilemap)
C.pxl8_tilemap_destroy(tilemap)
end
function pxl8.tilemap_set_tilesheet(tilemap, tilesheet)
return C.pxl8_tilemap_set_tilesheet(tilemap, tilesheet)
end
function pxl8.tilemap_set_tile(tilemap, layer, x, y, tile_id, flags)
C.pxl8_tilemap_set_tile(tilemap, layer or 0, x, y, tile_id or 0, flags or 0)
end
function pxl8.tilemap_get_tile_id(tilemap, layer, x, y)
return C.pxl8_tilemap_get_tile_id(tilemap, layer or 0, x, y)
end
function pxl8.tilemap_set_camera(tilemap, x, y)
C.pxl8_tilemap_set_camera(tilemap, x, y)
end
function pxl8.tilemap_render(tilemap)
C.pxl8_tilemap_render(tilemap, gfx)
end
function pxl8.tilemap_render_layer(tilemap, layer)
C.pxl8_tilemap_render_layer(tilemap, gfx, layer)
end
function pxl8.tilemap_is_solid(tilemap, x, y)
return C.pxl8_tilemap_is_solid(tilemap, x, y)
end
function pxl8.tilemap_check_collision(tilemap, x, y, w, h)
return C.pxl8_tilemap_check_collision(tilemap, x, y, w, h)
end
local tile_data = setmetatable({}, {__mode = "k"})
function pxl8.tilemap_get_tile_data(tilemap, tile_id)
if not tilemap or tile_id == 0 then return nil end
if not tile_data[tilemap] then return nil end
return tile_data[tilemap][tile_id]
end
function pxl8.tilemap_load_ase(tilemap, filepath, layer)
return C.pxl8_tilemap_load_ase(tilemap, filepath, layer or 0)
end
function pxl8.tilemap_set_tile_data(tilemap, tile_id, data)
if not tilemap or tile_id == 0 then return end
if not tile_data[tilemap] then tile_data[tilemap] = {} end
tile_data[tilemap][tile_id] = data
end
pxl8.TILE_FLIP_X = 1
pxl8.TILE_FLIP_Y = 2
pxl8.TILE_SOLID = 4
pxl8.TILE_TRIGGER = 8
function pxl8.clear_zbuffer()
C.pxl8_3d_clear_zbuffer(gfx)
end
function pxl8.set_model(mat)
C.pxl8_3d_set_model(gfx, mat)
end
function pxl8.set_view(mat)
C.pxl8_3d_set_view(gfx, mat)
end
function pxl8.set_projection(mat)
C.pxl8_3d_set_projection(gfx, mat)
end
function pxl8.set_wireframe(wireframe)
C.pxl8_3d_set_wireframe(gfx, wireframe)
end
function pxl8.set_affine_textures(affine)
C.pxl8_3d_set_affine_textures(gfx, affine)
end
function pxl8.set_backface_culling(culling)
C.pxl8_3d_set_backface_culling(gfx, culling)
end
function pxl8.draw_triangle_3d(v0, v1, v2, color)
local vec0 = ffi.new("pxl8_vec3", {x = v0[1], y = v0[2], z = v0[3]})
local vec1 = ffi.new("pxl8_vec3", {x = v1[1], y = v1[2], z = v1[3]})
local vec2 = ffi.new("pxl8_vec3", {x = v2[1], y = v2[2], z = v2[3]})
C.pxl8_3d_draw_triangle_raw(gfx, vec0, vec1, vec2, color)
end
function pxl8.draw_triangle_3d_textured(v0, v1, v2, uv0, uv1, uv2, texture_id)
local vec0 = ffi.new("pxl8_vec3", {x = v0[1], y = v0[2], z = v0[3]})
local vec1 = ffi.new("pxl8_vec3", {x = v1[1], y = v1[2], z = v1[3]})
local vec2 = ffi.new("pxl8_vec3", {x = v2[1], y = v2[2], z = v2[3]})
C.pxl8_3d_draw_triangle_textured(gfx, vec0, vec1, vec2,
uv0[1], uv0[2], uv1[1], uv1[2], uv2[1], uv2[2], texture_id)
end
function pxl8.draw_line_3d(p0, p1, color)
local vec0 = ffi.new("pxl8_vec3", {x = p0[1], y = p0[2], z = p0[3]})
local vec1 = ffi.new("pxl8_vec3", {x = p1[1], y = p1[2], z = p1[3]})
C.pxl8_3d_draw_line_3d(gfx, vec0, vec1, color)
end
function pxl8.mat4_identity()
return C.pxl8_mat4_identity()
end
function pxl8.mat4_multiply(a, b)
return C.pxl8_mat4_multiply(a, b)
end
function pxl8.mat4_translate(x, y, z)
return C.pxl8_mat4_translate(x, y, z)
end
function pxl8.mat4_rotate_x(angle)
return C.pxl8_mat4_rotate_x(angle)
end
function pxl8.mat4_rotate_y(angle)
return C.pxl8_mat4_rotate_y(angle)
end
function pxl8.mat4_rotate_z(angle)
return C.pxl8_mat4_rotate_z(angle)
end
function pxl8.mat4_scale(x, y, z)
return C.pxl8_mat4_scale(x, y, z)
end
function pxl8.mat4_ortho(left, right, bottom, top, near, far)
return C.pxl8_mat4_ortho(left, right, bottom, top, near, far)
end
function pxl8.mat4_perspective(fov, aspect, near, far)
return C.pxl8_mat4_perspective(fov, aspect, near, far)
end
function pxl8.mat4_lookat(eye, center, up)
local eye_vec = ffi.new("pxl8_vec3", {x = eye[1], y = eye[2], z = eye[3]})
local center_vec = ffi.new("pxl8_vec3", {x = center[1], y = center[2], z = center[3]})
local up_vec = ffi.new("pxl8_vec3", {x = up[1], y = up[2], z = up[3]})
return C.pxl8_mat4_lookat(eye_vec, center_vec, up_vec)
end
function pxl8.bounds(x, y, w, h)
return ffi.new("pxl8_bounds", {x = x, y = y, w = w, h = h})
end
function pxl8.ui_button(label)
return C.pxl8_ui_button(ui, label)
end
function pxl8.ui_checkbox(label, state)
local state_ptr = ffi.new("bool[1]", state)
local changed = C.pxl8_ui_checkbox(ui, label, state_ptr)
return changed, state_ptr[0]
end
function pxl8.ui_has_mouse_focus()
return C.pxl8_ui_has_mouse_focus(ui)
end
function pxl8.ui_indent(amount)
C.pxl8_ui_indent(ui, amount)
end
function pxl8.ui_label(text)
C.pxl8_ui_label(ui, text)
end
function pxl8.ui_layout_row(item_count, widths, height)
local widths_array = widths
if type(widths) == "table" then
widths_array = ffi.new("int[?]", #widths, widths)
elseif type(widths) == "number" then
widths_array = ffi.new("int[1]", widths)
end
C.pxl8_ui_layout_row(ui, item_count, widths_array, height)
end
function pxl8.ui_window_begin(title, x, y, w, h, options)
local rect = ffi.new("pxl8_bounds", {x = x, y = y, w = w, h = h})
return C.pxl8_ui_window_begin(ui, title, rect, options or 0)
end
function pxl8.ui_window_end()
C.pxl8_ui_window_end(ui)
end
function pxl8.ui_window_set_open(title, open)
C.pxl8_ui_window_set_open(ui, title, open)
end
function pxl8.world_new()
return C.pxl8_world_create()
end
function pxl8.world_destroy(world)
C.pxl8_world_destroy(world)
end
function pxl8.world_load(world, filepath)
return C.pxl8_world_load(world, filepath)
end
function pxl8.world_render(world, camera_pos)
local vec = ffi.new("pxl8_vec3", {x = camera_pos[1], y = camera_pos[2], z = camera_pos[3]})
C.pxl8_world_render(world, gfx, vec)
end
function pxl8.world_unload(world)
C.pxl8_world_unload(world)
end
function pxl8.world_is_loaded(world)
return C.pxl8_world_is_loaded(world)
end
function pxl8.world_generate(world, params)
local c_params = ffi.new("pxl8_procgen_params")
c_params.type = params.type or C.PXL8_PROCGEN_CAVE
c_params.width = params.width or 32
c_params.height = params.height or 32
c_params.depth = params.depth or 0
c_params.seed = params.seed or 0
c_params.density = params.density or 0.45
c_params.iterations = params.iterations or 4
c_params.type_params = nil
return C.pxl8_world_generate(world, gfx, c_params)
end
pxl8.PROCGEN_CAVE = C.PXL8_PROCGEN_CAVE
pxl8.PROCGEN_DUNGEON = C.PXL8_PROCGEN_DUNGEON
pxl8.PROCGEN_TERRAIN = C.PXL8_PROCGEN_TERRAIN
function pxl8.procgen_tex(params)
local width = params.width or 64
local height = params.height or 64
local buffer = ffi.new("u8[?]", width * height)
local tex_params = ffi.new("pxl8_procgen_tex_params")
local name = params.name or ""
ffi.copy(tex_params.name, name, math.min(#name, 15))
tex_params.seed = params.seed or 0
tex_params.width = width
tex_params.height = height
tex_params.scale = params.scale or 1.0
tex_params.roughness = params.roughness or 0.0
tex_params.base_color = params.base_color or 0
tex_params.variation = params.variation or 0
C.pxl8_procgen_tex(buffer, tex_params)
local tex_id = C.pxl8_gfx_create_texture(gfx, buffer, width, height)
if tex_id < 0 then
return nil
end
return tex_id
end
function pxl8.world_apply_textures(world, texture_defs)
local count = #texture_defs
local textures = ffi.new("pxl8_world_texture[?]", count)
for i, def in ipairs(texture_defs) do
local idx = i - 1
ffi.copy(textures[idx].name, def.name or "", math.min(#(def.name or ""), 15))
textures[idx].texture_id = def.texture_id or 0
if def.rule then
textures[idx].rule = ffi.cast("bool (*)(const pxl8_vec3*, const pxl8_bsp_face*, const pxl8_bsp*)",
function(normal, face, bsp)
return def.rule(normal[0], face, bsp)
end)
else
textures[idx].rule = nil
end
end
local result = C.pxl8_world_apply_textures(world, textures, count)
return result
end
pxl8.get_fps = core.get_fps
pxl8.get_width = core.get_width
pxl8.get_height = core.get_height
pxl8.info = core.info
pxl8.warn = core.warn
pxl8.error = core.error
pxl8.debug = core.debug
pxl8.trace = core.trace
pxl8.clr = graphics.clr
pxl8.pixel = graphics.pixel
pxl8.line = graphics.line
pxl8.rect = graphics.rect
pxl8.rect_fill = graphics.rect_fill
pxl8.circle = graphics.circle
pxl8.circle_fill = graphics.circle_fill
pxl8.text = graphics.text
pxl8.sprite = graphics.sprite
pxl8.load_palette = graphics.load_palette
pxl8.load_sprite = graphics.load_sprite
pxl8.create_texture = graphics.create_texture
pxl8.upload_atlas = graphics.upload_atlas
pxl8.gfx_color_ramp = graphics.color_ramp
pxl8.gfx_fade_palette = graphics.fade_palette
pxl8.key_down = input.key_down
pxl8.key_pressed = input.key_pressed
pxl8.key_released = input.key_released
pxl8.mouse_wheel_x = input.mouse_wheel_x
pxl8.mouse_wheel_y = input.mouse_wheel_y
pxl8.mouse_x = input.mouse_x
pxl8.mouse_y = input.mouse_y
pxl8.vfx_raster_bars = vfx.raster_bars
pxl8.vfx_plasma = vfx.plasma
pxl8.vfx_rotozoom = vfx.rotozoom
pxl8.vfx_tunnel = vfx.tunnel
pxl8.vfx_explosion = vfx.explosion
pxl8.vfx_fire = vfx.fire
pxl8.vfx_rain = vfx.rain
pxl8.vfx_smoke = vfx.smoke
pxl8.vfx_snow = vfx.snow
pxl8.vfx_sparks = vfx.sparks
pxl8.vfx_starfield = vfx.starfield
pxl8.particles_new = particles.new
pxl8.particles_destroy = particles.destroy
pxl8.particles_clear = particles.clear
pxl8.particles_emit = particles.emit
pxl8.particles_update = particles.update
pxl8.particles_render = particles.render
pxl8.tilesheet_new = tilemap.tilesheet_new
pxl8.tilesheet_destroy = tilemap.tilesheet_destroy
pxl8.tilesheet_load = tilemap.tilesheet_load
pxl8.tilemap_new = tilemap.new
pxl8.tilemap_destroy = tilemap.destroy
pxl8.tilemap_set_tilesheet = tilemap.set_tilesheet
pxl8.tilemap_set_tile = tilemap.set_tile
pxl8.tilemap_get_tile_id = tilemap.get_tile_id
pxl8.tilemap_set_camera = tilemap.set_camera
pxl8.tilemap_render = tilemap.render
pxl8.tilemap_render_layer = tilemap.render_layer
pxl8.tilemap_is_solid = tilemap.is_solid
pxl8.tilemap_check_collision = tilemap.check_collision
pxl8.tilemap_get_tile_data = tilemap.get_tile_data
pxl8.tilemap_load_ase = tilemap.load_ase
pxl8.tilemap_set_tile_data = tilemap.set_tile_data
pxl8.TILE_FLIP_X = tilemap.TILE_FLIP_X
pxl8.TILE_FLIP_Y = tilemap.TILE_FLIP_Y
pxl8.TILE_SOLID = tilemap.TILE_SOLID
pxl8.TILE_TRIGGER = tilemap.TILE_TRIGGER
pxl8.clear_zbuffer = gfx3d.clear_zbuffer
pxl8.set_model = gfx3d.set_model
pxl8.set_view = gfx3d.set_view
pxl8.set_projection = gfx3d.set_projection
pxl8.set_wireframe = gfx3d.set_wireframe
pxl8.set_affine_textures = gfx3d.set_affine_textures
pxl8.set_backface_culling = gfx3d.set_backface_culling
pxl8.draw_triangle_3d = gfx3d.draw_triangle
pxl8.draw_triangle_3d_textured = gfx3d.draw_triangle_textured
pxl8.draw_line_3d = gfx3d.draw_line
pxl8.mat4_identity = math3d.mat4_identity
pxl8.mat4_multiply = math3d.mat4_multiply
pxl8.mat4_translate = math3d.mat4_translate
pxl8.mat4_rotate_x = math3d.mat4_rotate_x
pxl8.mat4_rotate_y = math3d.mat4_rotate_y
pxl8.mat4_rotate_z = math3d.mat4_rotate_z
pxl8.mat4_scale = math3d.mat4_scale
pxl8.mat4_ortho = math3d.mat4_ortho
pxl8.mat4_perspective = math3d.mat4_perspective
pxl8.mat4_lookat = math3d.mat4_lookat
pxl8.bounds = math3d.bounds
pxl8.ui_button = ui.button
pxl8.ui_checkbox = ui.checkbox
pxl8.ui_has_mouse_focus = ui.has_mouse_focus
pxl8.ui_indent = ui.indent
pxl8.ui_label = ui.label
pxl8.ui_layout_row = ui.layout_row
pxl8.ui_window_begin = ui.window_begin
pxl8.ui_window_end = ui.window_end
pxl8.ui_window_set_open = ui.window_set_open
pxl8.world_new = world.new
pxl8.world_destroy = world.destroy
pxl8.world_load = world.load
pxl8.world_render = world.render
pxl8.world_unload = world.unload
pxl8.world_is_loaded = world.is_loaded
pxl8.world_generate = world.generate
pxl8.world_apply_textures = world.apply_textures
pxl8.procgen_tex = world.procgen_tex
pxl8.PROCGEN_CAVE = world.PROCGEN_CAVE
pxl8.PROCGEN_DUNGEON = world.PROCGEN_DUNGEON
pxl8.PROCGEN_TERRAIN = world.PROCGEN_TERRAIN
pxl8.transition_create = transition.create
pxl8.transition_destroy = transition.destroy
pxl8.transition_get_progress = transition.get_progress
pxl8.transition_is_active = transition.is_active
pxl8.transition_is_complete = transition.is_complete
pxl8.transition_render = transition.render
pxl8.transition_reset = transition.reset
pxl8.transition_set_color = transition.set_color
pxl8.transition_set_reverse = transition.set_reverse
pxl8.transition_start = transition.start
pxl8.transition_stop = transition.stop
pxl8.transition_update = transition.update
pxl8.anim_create = anim.create
pxl8.anim_create_from_ase = anim.create_from_ase
pxl8.anim_destroy = anim.destroy
pxl8.anim_add_state = anim.add_state
pxl8.anim_get_current_frame = anim.get_current_frame
pxl8.anim_get_current_frame_id = anim.get_current_frame_id
pxl8.anim_get_state = anim.get_state
pxl8.anim_has_state_machine = anim.has_state_machine
pxl8.anim_is_complete = anim.is_complete
pxl8.anim_is_playing = anim.is_playing
pxl8.anim_pause = anim.pause
pxl8.anim_play = anim.play
pxl8.anim_render_sprite = anim.render_sprite
pxl8.anim_reset = anim.reset
pxl8.anim_set_frame = anim.set_frame
pxl8.anim_set_loop = anim.set_loop
pxl8.anim_set_reverse = anim.set_reverse
pxl8.anim_set_speed = anim.set_speed
pxl8.anim_set_state = anim.set_state
pxl8.anim_stop = anim.stop
pxl8.anim_update = anim.update
return pxl8

110
src/lua/pxl8/anim.lua Normal file
View file

@ -0,0 +1,110 @@
local ffi = require("ffi")
local C = ffi.C
local core = require("pxl8.core")
local anim = {}
function anim.create(frame_ids, frame_durations)
local frame_count = #frame_ids
local c_frame_ids = ffi.new("u32[?]", frame_count)
local c_frame_durations = nil
for i = 1, frame_count do
c_frame_ids[i-1] = frame_ids[i]
end
if frame_durations then
c_frame_durations = ffi.new("u16[?]", frame_count)
for i = 1, frame_count do
c_frame_durations[i-1] = frame_durations[i]
end
end
return C.pxl8_anim_create(c_frame_ids, c_frame_durations, frame_count)
end
function anim.create_from_ase(filepath)
return C.pxl8_anim_create_from_ase(core.gfx, filepath)
end
function anim.destroy(a)
C.pxl8_anim_destroy(a)
end
function anim.add_state(a, name, state_anim)
return C.pxl8_anim_add_state(a, name, state_anim)
end
function anim.get_current_frame(a)
return C.pxl8_anim_get_current_frame(a)
end
function anim.get_current_frame_id(a)
return C.pxl8_anim_get_current_frame_id(a)
end
function anim.get_state(a)
local state_name = C.pxl8_anim_get_state(a)
if state_name ~= nil then
return ffi.string(state_name)
end
return nil
end
function anim.has_state_machine(a)
return C.pxl8_anim_has_state_machine(a)
end
function anim.is_complete(a)
return C.pxl8_anim_is_complete(a)
end
function anim.is_playing(a)
return C.pxl8_anim_is_playing(a)
end
function anim.pause(a)
C.pxl8_anim_pause(a)
end
function anim.play(a)
C.pxl8_anim_play(a)
end
function anim.render_sprite(a, x, y, w, h)
C.pxl8_anim_render_sprite(a, core.gfx, x, y, w, h)
end
function anim.reset(a)
C.pxl8_anim_reset(a)
end
function anim.set_frame(a, frame)
C.pxl8_anim_set_frame(a, frame)
end
function anim.set_loop(a, loop)
C.pxl8_anim_set_loop(a, loop)
end
function anim.set_reverse(a, reverse)
C.pxl8_anim_set_reverse(a, reverse)
end
function anim.set_speed(a, speed)
C.pxl8_anim_set_speed(a, speed)
end
function anim.set_state(a, name)
return C.pxl8_anim_set_state(a, name)
end
function anim.stop(a)
C.pxl8_anim_stop(a)
end
function anim.update(a, dt)
C.pxl8_anim_update(a, dt)
end
return anim

45
src/lua/pxl8/core.lua Normal file
View file

@ -0,0 +1,45 @@
local ffi = require("ffi")
local C = ffi.C
local core = {}
function core.init(game_ptr, gfx_ptr, input_ptr, ui_ptr)
core.game = game_ptr
core.gfx = gfx_ptr
core.input = input_ptr
core.ui = ui_ptr
end
function core.get_fps()
return C.pxl8_game_get_fps(core.game)
end
function core.get_width()
return C.pxl8_gfx_get_width(core.gfx)
end
function core.get_height()
return C.pxl8_gfx_get_height(core.gfx)
end
function core.info(msg)
C.pxl8_lua_info(msg)
end
function core.warn(msg)
C.pxl8_lua_warn(msg)
end
function core.error(msg)
C.pxl8_lua_error(msg)
end
function core.debug(msg)
C.pxl8_lua_debug(msg)
end
function core.trace(msg)
C.pxl8_lua_trace(msg)
end
return core

56
src/lua/pxl8/gfx3d.lua Normal file
View file

@ -0,0 +1,56 @@
local ffi = require("ffi")
local C = ffi.C
local core = require("pxl8.core")
local gfx3d = {}
function gfx3d.clear_zbuffer()
C.pxl8_3d_clear_zbuffer(core.gfx)
end
function gfx3d.set_model(mat)
C.pxl8_3d_set_model(core.gfx, mat)
end
function gfx3d.set_view(mat)
C.pxl8_3d_set_view(core.gfx, mat)
end
function gfx3d.set_projection(mat)
C.pxl8_3d_set_projection(core.gfx, mat)
end
function gfx3d.set_wireframe(wireframe)
C.pxl8_3d_set_wireframe(core.gfx, wireframe)
end
function gfx3d.set_affine_textures(affine)
C.pxl8_3d_set_affine_textures(core.gfx, affine)
end
function gfx3d.set_backface_culling(culling)
C.pxl8_3d_set_backface_culling(core.gfx, culling)
end
function gfx3d.draw_triangle(v0, v1, v2, color)
local vec0 = ffi.new("pxl8_vec3", {x = v0[1], y = v0[2], z = v0[3]})
local vec1 = ffi.new("pxl8_vec3", {x = v1[1], y = v1[2], z = v1[3]})
local vec2 = ffi.new("pxl8_vec3", {x = v2[1], y = v2[2], z = v2[3]})
C.pxl8_3d_draw_triangle_raw(core.gfx, vec0, vec1, vec2, color)
end
function gfx3d.draw_triangle_textured(v0, v1, v2, uv0, uv1, uv2, texture_id)
local vec0 = ffi.new("pxl8_vec3", {x = v0[1], y = v0[2], z = v0[3]})
local vec1 = ffi.new("pxl8_vec3", {x = v1[1], y = v1[2], z = v1[3]})
local vec2 = ffi.new("pxl8_vec3", {x = v2[1], y = v2[2], z = v2[3]})
C.pxl8_3d_draw_triangle_textured(core.gfx, vec0, vec1, vec2,
uv0[1], uv0[2], uv1[1], uv1[2], uv2[1], uv2[2], texture_id)
end
function gfx3d.draw_line(p0, p1, color)
local vec0 = ffi.new("pxl8_vec3", {x = p0[1], y = p0[2], z = p0[3]})
local vec1 = ffi.new("pxl8_vec3", {x = p1[1], y = p1[2], z = p1[3]})
C.pxl8_3d_draw_line_3d(core.gfx, vec0, vec1, color)
end
return gfx3d

85
src/lua/pxl8/graphics.lua Normal file
View file

@ -0,0 +1,85 @@
local ffi = require("ffi")
local C = ffi.C
local core = require("pxl8.core")
local graphics = {}
function graphics.clr(color)
C.pxl8_clr(core.gfx, color or 0)
end
function graphics.pixel(x, y, color)
if color then
C.pxl8_pixel(core.gfx, x, y, color)
else
return C.pxl8_get_pixel(core.gfx, x, y)
end
end
function graphics.line(x0, y0, x1, y1, color)
C.pxl8_line(core.gfx, x0, y0, x1, y1, color)
end
function graphics.rect(x, y, w, h, color)
C.pxl8_rect(core.gfx, x, y, w, h, color)
end
function graphics.rect_fill(x, y, w, h, color)
C.pxl8_rect_fill(core.gfx, x, y, w, h, color)
end
function graphics.circle(x, y, r, color)
C.pxl8_circle(core.gfx, x, y, r, color)
end
function graphics.circle_fill(x, y, r, color)
C.pxl8_circle_fill(core.gfx, x, y, r, color)
end
function graphics.text(str, x, y, color)
C.pxl8_text(core.gfx, str, x or 0, y or 0, color or 15)
end
function graphics.sprite(id, x, y, w, h, flip_x, flip_y)
C.pxl8_sprite(core.gfx, id or 0, x or 0, y or 0, w or 16, h or 16, flip_x or false, flip_y or false)
end
function graphics.load_palette(filepath)
return C.pxl8_gfx_load_palette(core.gfx, filepath)
end
function graphics.load_sprite(filepath)
local sprite_id = ffi.new("unsigned int[1]")
local result = C.pxl8_gfx_load_sprite(core.gfx, filepath, sprite_id)
if result == 0 then
return sprite_id[0]
else
return nil, result
end
end
function graphics.create_texture(pixels, width, height)
local pixel_data = ffi.new("u8[?]", width * height)
for i = 0, width * height - 1 do
pixel_data[i] = pixels[i + 1] or 0
end
local result = C.pxl8_gfx_create_texture(core.gfx, pixel_data, width, height)
if result < 0 then
return nil
end
return result
end
function graphics.upload_atlas()
C.pxl8_gfx_upload_atlas(core.gfx)
end
function graphics.color_ramp(start, count, from_color, to_color)
C.pxl8_gfx_color_ramp(core.gfx, start, count, from_color, to_color)
end
function graphics.fade_palette(start, count, amount, target_color)
C.pxl8_gfx_fade_palette(core.gfx, start, count, amount, target_color)
end
return graphics

35
src/lua/pxl8/input.lua Normal file
View file

@ -0,0 +1,35 @@
local ffi = require("ffi")
local C = ffi.C
local core = require("pxl8.core")
local input = {}
function input.key_down(key)
return C.pxl8_key_down(core.input, key)
end
function input.key_pressed(key)
return C.pxl8_key_pressed(core.input, key)
end
function input.key_released(key)
return C.pxl8_key_released(core.input, key)
end
function input.mouse_wheel_x()
return C.pxl8_mouse_wheel_x(core.input)
end
function input.mouse_wheel_y()
return C.pxl8_mouse_wheel_y(core.input)
end
function input.mouse_x()
return C.pxl8_mouse_x(core.input)
end
function input.mouse_y()
return C.pxl8_mouse_y(core.input)
end
return input

53
src/lua/pxl8/math.lua Normal file
View file

@ -0,0 +1,53 @@
local ffi = require("ffi")
local C = ffi.C
local math3d = {}
function math3d.mat4_identity()
return C.pxl8_mat4_identity()
end
function math3d.mat4_multiply(a, b)
return C.pxl8_mat4_multiply(a, b)
end
function math3d.mat4_translate(x, y, z)
return C.pxl8_mat4_translate(x, y, z)
end
function math3d.mat4_rotate_x(angle)
return C.pxl8_mat4_rotate_x(angle)
end
function math3d.mat4_rotate_y(angle)
return C.pxl8_mat4_rotate_y(angle)
end
function math3d.mat4_rotate_z(angle)
return C.pxl8_mat4_rotate_z(angle)
end
function math3d.mat4_scale(x, y, z)
return C.pxl8_mat4_scale(x, y, z)
end
function math3d.mat4_ortho(left, right, bottom, top, near, far)
return C.pxl8_mat4_ortho(left, right, bottom, top, near, far)
end
function math3d.mat4_perspective(fov, aspect, near, far)
return C.pxl8_mat4_perspective(fov, aspect, near, far)
end
function math3d.mat4_lookat(eye, center, up)
local eye_vec = ffi.new("pxl8_vec3", {x = eye[1], y = eye[2], z = eye[3]})
local center_vec = ffi.new("pxl8_vec3", {x = center[1], y = center[2], z = center[3]})
local up_vec = ffi.new("pxl8_vec3", {x = up[1], y = up[2], z = up[3]})
return C.pxl8_mat4_lookat(eye_vec, center_vec, up_vec)
end
function math3d.bounds(x, y, w, h)
return ffi.new("pxl8_bounds", {x = x, y = y, w = w, h = h})
end
return math3d

View file

@ -0,0 +1,31 @@
local ffi = require("ffi")
local C = ffi.C
local core = require("pxl8.core")
local particles = {}
function particles.new(max_count)
return C.pxl8_particles_create(max_count or 1000)
end
function particles.destroy(ps)
C.pxl8_particles_destroy(ps)
end
function particles.clear(ps)
C.pxl8_particles_clear(ps)
end
function particles.emit(ps, count)
C.pxl8_particles_emit(ps, count or 1)
end
function particles.update(ps, dt)
C.pxl8_particles_update(ps, dt)
end
function particles.render(ps)
C.pxl8_particles_render(ps, core.gfx)
end
return particles

82
src/lua/pxl8/tilemap.lua Normal file
View file

@ -0,0 +1,82 @@
local ffi = require("ffi")
local C = ffi.C
local core = require("pxl8.core")
local tilemap = {}
tilemap.TILE_FLIP_X = 1
tilemap.TILE_FLIP_Y = 2
tilemap.TILE_SOLID = 4
tilemap.TILE_TRIGGER = 8
local tile_data = setmetatable({}, {__mode = "k"})
function tilemap.tilesheet_new(tile_size)
return C.pxl8_tilesheet_create(tile_size or 16)
end
function tilemap.tilesheet_destroy(tilesheet)
C.pxl8_tilesheet_destroy(tilesheet)
end
function tilemap.tilesheet_load(tilesheet, filepath)
return C.pxl8_tilesheet_load(tilesheet, filepath, core.gfx)
end
function tilemap.new(width, height, tile_size)
return C.pxl8_tilemap_create(width, height, tile_size or 16)
end
function tilemap.destroy(tm)
C.pxl8_tilemap_destroy(tm)
end
function tilemap.set_tilesheet(tm, tilesheet)
return C.pxl8_tilemap_set_tilesheet(tm, tilesheet)
end
function tilemap.set_tile(tm, layer, x, y, tile_id, flags)
C.pxl8_tilemap_set_tile(tm, layer or 0, x, y, tile_id or 0, flags or 0)
end
function tilemap.get_tile_id(tm, layer, x, y)
return C.pxl8_tilemap_get_tile_id(tm, layer or 0, x, y)
end
function tilemap.set_camera(tm, x, y)
C.pxl8_tilemap_set_camera(tm, x, y)
end
function tilemap.render(tm)
C.pxl8_tilemap_render(tm, core.gfx)
end
function tilemap.render_layer(tm, layer)
C.pxl8_tilemap_render_layer(tm, core.gfx, layer)
end
function tilemap.is_solid(tm, x, y)
return C.pxl8_tilemap_is_solid(tm, x, y)
end
function tilemap.check_collision(tm, x, y, w, h)
return C.pxl8_tilemap_check_collision(tm, x, y, w, h)
end
function tilemap.get_tile_data(tm, tile_id)
if not tm or tile_id == 0 then return nil end
if not tile_data[tm] then return nil end
return tile_data[tm][tile_id]
end
function tilemap.load_ase(tm, filepath, layer)
return C.pxl8_tilemap_load_ase(tm, filepath, layer or 0)
end
function tilemap.set_tile_data(tm, tile_id, data)
if not tm or tile_id == 0 then return end
if not tile_data[tm] then tile_data[tm] = {} end
tile_data[tm][tile_id] = data
end
return tilemap

View file

@ -0,0 +1,68 @@
local ffi = require("ffi")
local C = ffi.C
local core = require("pxl8.core")
local transition = {}
local transition_types = {
fade = 0,
wipe_left = 1,
wipe_right = 2,
wipe_up = 3,
wipe_down = 4,
circle_open = 5,
circle_close = 6,
dissolve = 7,
pixelate = 8
}
function transition.create(type_name, duration)
local type_id = transition_types[type_name] or 0
return C.pxl8_transition_create(type_id, duration or 1.0)
end
function transition.destroy(t)
C.pxl8_transition_destroy(t)
end
function transition.get_progress(t)
return C.pxl8_transition_get_progress(t)
end
function transition.is_active(t)
return C.pxl8_transition_is_active(t)
end
function transition.is_complete(t)
return C.pxl8_transition_is_complete(t)
end
function transition.render(t)
C.pxl8_transition_render(t, core.gfx)
end
function transition.reset(t)
C.pxl8_transition_reset(t)
end
function transition.set_color(t, color)
C.pxl8_transition_set_color(t, color)
end
function transition.set_reverse(t, reverse)
C.pxl8_transition_set_reverse(t, reverse)
end
function transition.start(t)
C.pxl8_transition_start(t)
end
function transition.stop(t)
C.pxl8_transition_stop(t)
end
function transition.update(t, dt)
C.pxl8_transition_update(t, dt)
end
return transition

52
src/lua/pxl8/ui.lua Normal file
View file

@ -0,0 +1,52 @@
local ffi = require("ffi")
local C = ffi.C
local core = require("pxl8.core")
local ui = {}
function ui.button(label)
return C.pxl8_ui_button(core.ui, label)
end
function ui.checkbox(label, state)
local state_ptr = ffi.new("bool[1]", state)
local changed = C.pxl8_ui_checkbox(core.ui, label, state_ptr)
return changed, state_ptr[0]
end
function ui.has_mouse_focus()
return C.pxl8_ui_has_mouse_focus(core.ui)
end
function ui.indent(amount)
C.pxl8_ui_indent(core.ui, amount)
end
function ui.label(text)
C.pxl8_ui_label(core.ui, text)
end
function ui.layout_row(item_count, widths, height)
local widths_array = widths
if type(widths) == "table" then
widths_array = ffi.new("int[?]", #widths, widths)
elseif type(widths) == "number" then
widths_array = ffi.new("int[1]", widths)
end
C.pxl8_ui_layout_row(core.ui, item_count, widths_array, height)
end
function ui.window_begin(title, x, y, w, h, options)
local rect = ffi.new("pxl8_bounds", {x = x, y = y, w = w, h = h})
return C.pxl8_ui_window_begin(core.ui, title, rect, options or 0)
end
function ui.window_end()
C.pxl8_ui_window_end(core.ui)
end
function ui.window_set_open(title, open)
C.pxl8_ui_window_set_open(core.ui, title, open)
end
return ui

65
src/lua/pxl8/vfx.lua Normal file
View file

@ -0,0 +1,65 @@
local ffi = require("ffi")
local C = ffi.C
local core = require("pxl8.core")
local vfx = {}
function vfx.raster_bars(bars, time)
local c_bars = ffi.new("pxl8_raster_bar[?]", #bars)
for i, bar in ipairs(bars) do
c_bars[i-1].base_y = bar.base_y or 0
c_bars[i-1].amplitude = bar.amplitude or 10
c_bars[i-1].height = bar.height or 5
c_bars[i-1].speed = bar.speed or 1.0
c_bars[i-1].phase = bar.phase or 0
c_bars[i-1].color = bar.color or 15
c_bars[i-1].fade_color = bar.fade_color or bar.color or 15
end
C.pxl8_vfx_raster_bars(core.gfx, c_bars, #bars, time)
end
function vfx.plasma(time, scale1, scale2, palette_offset)
C.pxl8_vfx_plasma(core.gfx, time, scale1 or 0.05, scale2 or 0.03, palette_offset or 0)
end
function vfx.rotozoom(angle, zoom, cx, cy)
local width = C.pxl8_gfx_get_width(core.gfx)
local height = C.pxl8_gfx_get_height(core.gfx)
C.pxl8_vfx_rotozoom(core.gfx, angle, zoom, cx or width/2, cy or height/2)
end
function vfx.tunnel(time, speed, twist)
C.pxl8_vfx_tunnel(core.gfx, time, speed or 2.0, twist or 0.5)
end
function vfx.explosion(ps, x, y, color, force)
C.pxl8_vfx_explosion(ps, x, y, color or 15, force or 200.0)
end
function vfx.fire(ps, x, y, width, palette_start)
C.pxl8_vfx_fire(ps, x, y, width or 50, palette_start or 64)
end
function vfx.rain(ps, width, wind)
local w = width or C.pxl8_gfx_get_width(core.gfx)
C.pxl8_vfx_rain(ps, w, wind or 0.0)
end
function vfx.smoke(ps, x, y, color)
C.pxl8_vfx_smoke(ps, x, y, color or 8)
end
function vfx.snow(ps, width, wind)
local w = width or C.pxl8_gfx_get_width(core.gfx)
C.pxl8_vfx_snow(ps, w, wind or 10.0)
end
function vfx.sparks(ps, x, y, color)
C.pxl8_vfx_sparks(ps, x, y, color or 15)
end
function vfx.starfield(ps, speed, spread)
C.pxl8_vfx_starfield(ps, speed or 5.0, spread or 500.0)
end
return vfx

99
src/lua/pxl8/world.lua Normal file
View file

@ -0,0 +1,99 @@
local ffi = require("ffi")
local C = ffi.C
local core = require("pxl8.core")
local world = {}
world.PROCGEN_CAVE = C.PXL8_PROCGEN_CAVE
world.PROCGEN_DUNGEON = C.PXL8_PROCGEN_DUNGEON
world.PROCGEN_TERRAIN = C.PXL8_PROCGEN_TERRAIN
function world.new()
return C.pxl8_world_create()
end
function world.destroy(w)
C.pxl8_world_destroy(w)
end
function world.load(w, filepath)
return C.pxl8_world_load(w, filepath)
end
function world.render(w, camera_pos)
local vec = ffi.new("pxl8_vec3", {x = camera_pos[1], y = camera_pos[2], z = camera_pos[3]})
C.pxl8_world_render(w, core.gfx, vec)
end
function world.unload(w)
C.pxl8_world_unload(w)
end
function world.is_loaded(w)
return C.pxl8_world_is_loaded(w)
end
function world.generate(w, params)
local c_params = ffi.new("pxl8_procgen_params")
c_params.type = params.type or C.PXL8_PROCGEN_CAVE
c_params.width = params.width or 32
c_params.height = params.height or 32
c_params.depth = params.depth or 0
c_params.seed = params.seed or 0
c_params.density = params.density or 0.45
c_params.iterations = params.iterations or 4
c_params.type_params = nil
return C.pxl8_world_generate(w, core.gfx, c_params)
end
function world.procgen_tex(params)
local width = params.width or 64
local height = params.height or 64
local buffer = ffi.new("u8[?]", width * height)
local tex_params = ffi.new("pxl8_procgen_tex_params")
local name = params.name or ""
ffi.copy(tex_params.name, name, math.min(#name, 15))
tex_params.seed = params.seed or 0
tex_params.width = width
tex_params.height = height
tex_params.scale = params.scale or 1.0
tex_params.roughness = params.roughness or 0.0
tex_params.base_color = params.base_color or 0
tex_params.variation = params.variation or 0
C.pxl8_procgen_tex(buffer, tex_params)
local tex_id = C.pxl8_gfx_create_texture(core.gfx, buffer, width, height)
if tex_id < 0 then
return nil
end
return tex_id
end
function world.apply_textures(w, texture_defs)
local count = #texture_defs
local textures = ffi.new("pxl8_world_texture[?]", count)
for i, def in ipairs(texture_defs) do
local idx = i - 1
ffi.copy(textures[idx].name, def.name or "", math.min(#(def.name or ""), 15))
textures[idx].texture_id = def.texture_id or 0
if def.rule then
textures[idx].rule = ffi.cast("bool (*)(const pxl8_vec3*, const pxl8_bsp_face*, const pxl8_bsp*)",
function(normal, face, bsp)
return def.rule(normal[0], face, bsp)
end)
else
textures[idx].rule = nil
end
end
local result = C.pxl8_world_apply_textures(w, textures, count)
return result
end
return world