cleanup
This commit is contained in:
parent
9f96626ea7
commit
6a02b24ae6
29 changed files with 653 additions and 583 deletions
|
|
@ -3,44 +3,76 @@
|
||||||
(var time 0)
|
(var time 0)
|
||||||
(var current-effect 1)
|
(var current-effect 1)
|
||||||
(var particles nil)
|
(var particles nil)
|
||||||
(var starfield-init false)
|
|
||||||
(var fire-init false)
|
(var fire-init false)
|
||||||
(var rain-init false)
|
(var rain-init false)
|
||||||
(var snow-init false)
|
(var snow-init false)
|
||||||
|
|
||||||
|
(var logo-x 256)
|
||||||
|
(var logo-y 148)
|
||||||
|
(var logo-dx 100)
|
||||||
|
(var logo-dy 80)
|
||||||
|
(var logo-sprite nil)
|
||||||
|
|
||||||
(global init (fn []
|
(global init (fn []
|
||||||
(pxl8.load_palette "palettes/gruvbox.ase")
|
(pxl8.load_palette "palettes/gruvbox.ase")
|
||||||
(set particles (pxl8.particles_new 1000))))
|
(set particles (pxl8.particles_new 1000))
|
||||||
|
(set logo-sprite (pxl8.load_sprite "sprites/pxl8.ase"))))
|
||||||
|
|
||||||
(global update (fn [dt]
|
(global update (fn [dt]
|
||||||
(set time (+ time dt))
|
(set time (+ time dt))
|
||||||
|
|
||||||
(when (pxl8.key_pressed "1")
|
(when (pxl8.key_pressed "1")
|
||||||
(set current-effect 1))
|
(set current-effect 1))
|
||||||
(when (pxl8.key_pressed "2")
|
(when (pxl8.key_pressed "2")
|
||||||
(set current-effect 2))
|
(set current-effect 2))
|
||||||
(when (pxl8.key_pressed "3")
|
(when (pxl8.key_pressed "3")
|
||||||
(set current-effect 3)
|
(set current-effect 3))
|
||||||
(set fire-init false))
|
(when (pxl8.key_pressed "4")
|
||||||
(when (pxl8.key_pressed "4")
|
|
||||||
(set current-effect 4))
|
(set current-effect 4))
|
||||||
(when (pxl8.key_pressed "5")
|
(when (pxl8.key_pressed "5")
|
||||||
(set current-effect 5)
|
(set current-effect 5)
|
||||||
(set rain-init false))
|
(set fire-init false))
|
||||||
(when (pxl8.key_pressed "6")
|
(when (pxl8.key_pressed "6")
|
||||||
(set current-effect 6)
|
(set current-effect 6)
|
||||||
|
(set rain-init false))
|
||||||
|
(when (pxl8.key_pressed "7")
|
||||||
|
(set current-effect 7)
|
||||||
(set snow-init false))
|
(set snow-init false))
|
||||||
|
|
||||||
|
(when (= current-effect 1)
|
||||||
|
(set logo-x (+ logo-x (* logo-dx dt)))
|
||||||
|
(set logo-y (+ logo-y (* logo-dy dt)))
|
||||||
|
|
||||||
|
(when (or (< logo-x 0) (> logo-x 512))
|
||||||
|
(set logo-dx (- logo-dx)))
|
||||||
|
(when (or (< logo-y 0) (> logo-y 296))
|
||||||
|
(set logo-dy (- logo-dy))))
|
||||||
|
|
||||||
(when particles
|
(when particles
|
||||||
(pxl8.particles_update particles dt))))
|
(pxl8.particles_update particles dt))))
|
||||||
|
|
||||||
(global draw (fn []
|
(global draw (fn []
|
||||||
(match current-effect
|
(match current-effect
|
||||||
1 (pxl8.vfx_plasma time 0.10 0.04 0)
|
1 (do
|
||||||
|
(pxl8.clr 0)
|
||||||
2 (pxl8.vfx_tunnel time 2.0 0.25)
|
(when logo-sprite
|
||||||
|
(pxl8.sprite logo-sprite logo-x logo-y 128 64))
|
||||||
3 (do
|
(pxl8.text "Bouncing Logo" 200 10 15)
|
||||||
|
(pxl8.text "Press 1-7 for effects" 10 150 7))
|
||||||
|
|
||||||
|
2 (pxl8.vfx_plasma time 0.10 0.04 0)
|
||||||
|
|
||||||
|
3 (pxl8.vfx_tunnel time 2.0 0.25)
|
||||||
|
|
||||||
|
4 (do
|
||||||
|
(pxl8.clr 0)
|
||||||
|
(local bars [{:base_y 40 :amplitude 20 :height 16 :speed 2.0 :phase 0 :color 14 :fade_color 11}
|
||||||
|
{:base_y 80 :amplitude 15 :height 16 :speed 2.5 :phase 1.5 :color 20 :fade_color 11}
|
||||||
|
{:base_y 120 :amplitude 25 :height 16 :speed 1.8 :phase 3.0 :color 26 :fade_color 11}])
|
||||||
|
(pxl8.vfx_raster_bars bars time)
|
||||||
|
(pxl8.text "Raster Bars" 200 10 15))
|
||||||
|
|
||||||
|
5 (do
|
||||||
(pxl8.clr 0)
|
(pxl8.clr 0)
|
||||||
(when particles
|
(when particles
|
||||||
(when (not fire-init)
|
(when (not fire-init)
|
||||||
|
|
@ -49,16 +81,8 @@
|
||||||
(set fire-init true))
|
(set fire-init true))
|
||||||
(pxl8.particles_render particles))
|
(pxl8.particles_render particles))
|
||||||
(pxl8.text "Fire Effect Test" 200 10 15))
|
(pxl8.text "Fire Effect Test" 200 10 15))
|
||||||
|
|
||||||
4 (do
|
6 (do
|
||||||
(pxl8.clr 0)
|
|
||||||
(local bars [{:base_y 40 :amplitude 20 :height 16 :speed 2.0 :phase 0 :color 14 :fade_color 11}
|
|
||||||
{:base_y 80 :amplitude 15 :height 16 :speed 2.5 :phase 1.5 :color 20 :fade_color 11}
|
|
||||||
{:base_y 120 :amplitude 25 :height 16 :speed 1.8 :phase 3.0 :color 26 :fade_color 11}])
|
|
||||||
(pxl8.vfx_copper_bars bars time)
|
|
||||||
(pxl8.text "Copper Bars" 200 10 15))
|
|
||||||
|
|
||||||
5 (do
|
|
||||||
(pxl8.clr 0)
|
(pxl8.clr 0)
|
||||||
(when particles
|
(when particles
|
||||||
(when (not rain-init)
|
(when (not rain-init)
|
||||||
|
|
@ -67,8 +91,8 @@
|
||||||
(set rain-init true))
|
(set rain-init true))
|
||||||
(pxl8.particles_render particles))
|
(pxl8.particles_render particles))
|
||||||
(pxl8.text "Rain" 200 10 15))
|
(pxl8.text "Rain" 200 10 15))
|
||||||
|
|
||||||
6 (do
|
7 (do
|
||||||
(pxl8.clr 0)
|
(pxl8.clr 0)
|
||||||
(when particles
|
(when particles
|
||||||
(when (not snow-init)
|
(when (not snow-init)
|
||||||
|
|
|
||||||
Binary file not shown.
Binary file not shown.
|
Before Width: | Height: | Size: 1.3 KiB |
Binary file not shown.
Binary file not shown.
Binary file not shown.
254
pxl8.sh
254
pxl8.sh
|
|
@ -39,21 +39,21 @@ if [[ "$(uname)" == "Linux" ]]; then
|
||||||
CFLAGS="$CFLAGS -D_GNU_SOURCE"
|
CFLAGS="$CFLAGS -D_GNU_SOURCE"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
print_info() {
|
compile_source_file() {
|
||||||
echo -e "${BLUE}${BOLD}info:${NC} $1"
|
local src_file="$1"
|
||||||
}
|
local obj_file="$2"
|
||||||
|
local compile_flags="$3"
|
||||||
|
|
||||||
print_success() {
|
print_info "Compiling: $src_file"
|
||||||
echo -e "${GREEN}${BOLD}✓${NC} $1"
|
if ! $CC -c $compile_flags "$src_file" -o "$obj_file"; then
|
||||||
}
|
print_error "Compilation failed for $src_file"
|
||||||
|
exit 1
|
||||||
print_error() {
|
fi
|
||||||
echo -e "${RED}${BOLD}error:${NC} $1" >&2
|
|
||||||
}
|
}
|
||||||
|
|
||||||
detect_simd() {
|
detect_simd() {
|
||||||
local simd_flags=""
|
local simd_flags=""
|
||||||
|
|
||||||
case "$(uname -m)" in
|
case "$(uname -m)" in
|
||||||
x86_64|amd64)
|
x86_64|amd64)
|
||||||
if $CC -mavx2 -c -x c /dev/null -o /dev/null 2>/dev/null; then
|
if $CC -mavx2 -c -x c /dev/null -o /dev/null 2>/dev/null; then
|
||||||
|
|
@ -68,10 +68,26 @@ detect_simd() {
|
||||||
fi
|
fi
|
||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
|
|
||||||
echo "$simd_flags"
|
echo "$simd_flags"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
make_lib_dirs() {
|
||||||
|
mkdir -p lib/linenoise lib/fennel lib/microui/src lib/miniz
|
||||||
|
}
|
||||||
|
|
||||||
|
print_error() {
|
||||||
|
echo -e "${RED}${BOLD}error:${NC} $1" >&2
|
||||||
|
}
|
||||||
|
|
||||||
|
print_info() {
|
||||||
|
echo -e "${BLUE}${BOLD}info:${NC} $1"
|
||||||
|
}
|
||||||
|
|
||||||
|
print_success() {
|
||||||
|
echo -e "${GREEN}${BOLD}✓${NC} $1"
|
||||||
|
}
|
||||||
|
|
||||||
print_usage() {
|
print_usage() {
|
||||||
echo -e "${BOLD}pxl8${NC} - framework build tool"
|
echo -e "${BOLD}pxl8${NC} - framework build tool"
|
||||||
echo
|
echo
|
||||||
|
|
@ -80,15 +96,18 @@ print_usage() {
|
||||||
echo
|
echo
|
||||||
echo -e "${BOLD}COMMANDS:${NC}"
|
echo -e "${BOLD}COMMANDS:${NC}"
|
||||||
echo " build Build pxl8"
|
echo " build Build pxl8"
|
||||||
echo " run Build and run pxl8 [script.fnl|script.lua]"
|
|
||||||
echo " clean Remove build artifacts"
|
echo " clean Remove build artifacts"
|
||||||
|
echo " run Build and run pxl8 (optional: cart.pxc or folder)"
|
||||||
|
echo
|
||||||
echo " update Download/update all dependencies"
|
echo " update Download/update all dependencies"
|
||||||
echo " vendor Fetch source for dependencies (ex. sdl3)"
|
echo " vendor Fetch source for dependencies (ex. SDL3)"
|
||||||
|
echo
|
||||||
echo " help Show this help message"
|
echo " help Show this help message"
|
||||||
echo
|
echo
|
||||||
echo -e "${BOLD}OPTIONS:${NC}"
|
echo -e "${BOLD}OPTIONS:${NC}"
|
||||||
echo " --all Remove all artifacts including dependencies when cleaning"
|
echo " --all Clean both build artifacts and dependencies"
|
||||||
echo " --release Build/run in release mode"
|
echo " --deps Clean only dependencies"
|
||||||
|
echo " --release Build/run/clean in release mode (default: debug)"
|
||||||
}
|
}
|
||||||
|
|
||||||
COMMAND="$1"
|
COMMAND="$1"
|
||||||
|
|
@ -115,6 +134,34 @@ else
|
||||||
BINDIR="$BINDIR/debug"
|
BINDIR="$BINDIR/debug"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
build_luajit() {
|
||||||
|
if [[ ! -f "lib/luajit/src/libluajit.a" ]]; then
|
||||||
|
print_info "Building LuaJIT"
|
||||||
|
cd lib/luajit
|
||||||
|
|
||||||
|
if [[ "$(uname)" == "Darwin" ]]; then
|
||||||
|
export MACOSX_DEPLOYMENT_TARGET="10.11"
|
||||||
|
fi
|
||||||
|
|
||||||
|
make clean >/dev/null 2>&1 || true
|
||||||
|
make -j$(nproc 2>/dev/null || echo 4) > /dev/null 2>&1
|
||||||
|
cd - > /dev/null
|
||||||
|
print_success "Built LuaJIT"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
build_sdl() {
|
||||||
|
if [[ ! -f "lib/SDL/build/libSDL3.so" ]] && [[ ! -f "lib/SDL/build/libSDL3.a" ]] && [[ ! -f "lib/SDL/build/libSDL3.dylib" ]]; then
|
||||||
|
print_info "Building SDL3"
|
||||||
|
mkdir -p lib/SDL/build
|
||||||
|
cd lib/SDL/build
|
||||||
|
cmake .. -DCMAKE_BUILD_TYPE=Release > /dev/null 2>&1
|
||||||
|
cmake --build . --parallel $(nproc 2>/dev/null || echo 4) > /dev/null 2>&1
|
||||||
|
cd - > /dev/null
|
||||||
|
print_success "Built SDL3"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
setup_sdl3() {
|
setup_sdl3() {
|
||||||
if [[ -d "lib/SDL/build" ]]; then
|
if [[ -d "lib/SDL/build" ]]; then
|
||||||
SDL3_CFLAGS="-Ilib/SDL/include"
|
SDL3_CFLAGS="-Ilib/SDL/include"
|
||||||
|
|
@ -125,49 +172,52 @@ setup_sdl3() {
|
||||||
SDL3_CFLAGS=$(pkg-config --cflags sdl3 2>/dev/null || echo "")
|
SDL3_CFLAGS=$(pkg-config --cflags sdl3 2>/dev/null || echo "")
|
||||||
SDL3_LIBS=$(pkg-config --libs sdl3 2>/dev/null || echo "")
|
SDL3_LIBS=$(pkg-config --libs sdl3 2>/dev/null || echo "")
|
||||||
SDL3_RPATH=""
|
SDL3_RPATH=""
|
||||||
|
|
||||||
if [[ -z "$SDL3_LIBS" ]]; then
|
if [[ -z "$SDL3_LIBS" ]]; then
|
||||||
case "$(uname)" in
|
case "$(uname)" in
|
||||||
Darwin)
|
Darwin)
|
||||||
SDL3_CFLAGS="-I/usr/local/include/SDL3"
|
if [[ -f "/usr/local/include/SDL3/SDL.h" ]]; then
|
||||||
SDL3_LIBS="-L/usr/local/lib -lSDL3"
|
SDL3_CFLAGS="-I/usr/local/include/SDL3"
|
||||||
|
SDL3_LIBS="-L/usr/local/lib -lSDL3"
|
||||||
|
fi
|
||||||
;;
|
;;
|
||||||
Linux)
|
Linux)
|
||||||
SDL3_CFLAGS="-I/usr/include/SDL3"
|
if [[ -f "/usr/include/SDL3/SDL.h" ]]; then
|
||||||
SDL3_LIBS="-lSDL3"
|
SDL3_CFLAGS="-I/usr/include/SDL3"
|
||||||
|
SDL3_LIBS="-lSDL3"
|
||||||
|
fi
|
||||||
;;
|
;;
|
||||||
MINGW*|MSYS*|CYGWIN*)
|
MINGW*|MSYS*|CYGWIN*)
|
||||||
SDL3_CFLAGS="-I/mingw64/include/SDL3"
|
if [[ -f "/mingw64/include/SDL3/SDL.h" ]]; then
|
||||||
SDL3_LIBS="-lSDL3"
|
SDL3_CFLAGS="-I/mingw64/include/SDL3"
|
||||||
|
SDL3_LIBS="-lSDL3"
|
||||||
|
fi
|
||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
fi
|
fi
|
||||||
print_info "Using system SDL3"
|
|
||||||
|
if [[ -z "$SDL3_LIBS" ]]; then
|
||||||
|
print_info "System SDL3 not found, vendoring SDL3..."
|
||||||
|
update_sdl
|
||||||
|
build_sdl
|
||||||
|
SDL3_CFLAGS="-Ilib/SDL/include"
|
||||||
|
SDL3_LIBS="-Llib/SDL/build -lSDL3"
|
||||||
|
SDL3_RPATH="-Wl,-rpath,$(pwd)/lib/SDL/build"
|
||||||
|
print_info "Using vendored SDL3"
|
||||||
|
else
|
||||||
|
print_info "Using system SDL3"
|
||||||
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
CFLAGS="$CFLAGS $SDL3_CFLAGS"
|
CFLAGS="$CFLAGS $SDL3_CFLAGS"
|
||||||
LIBS="$LIBS $SDL3_LIBS $SDL3_RPATH"
|
LIBS="$LIBS $SDL3_LIBS $SDL3_RPATH"
|
||||||
}
|
}
|
||||||
|
|
||||||
update_linenoise() {
|
|
||||||
print_info "Fetching linenoise"
|
|
||||||
mkdir -p lib/linenoise
|
|
||||||
|
|
||||||
if curl -s --max-time 5 -o lib/linenoise/linenoise.c https://raw.githubusercontent.com/antirez/linenoise/master/linenoise.c 2>/dev/null && \
|
|
||||||
curl -s --max-time 5 -o lib/linenoise/linenoise.h https://raw.githubusercontent.com/antirez/linenoise/master/linenoise.h 2>/dev/null; then
|
|
||||||
print_success "Updated linenoise"
|
|
||||||
else
|
|
||||||
print_error "Failed to download linenoise"
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
update_fennel() {
|
update_fennel() {
|
||||||
print_info "Fetching Fennel"
|
print_info "Fetching Fennel"
|
||||||
mkdir -p lib/fennel
|
|
||||||
|
|
||||||
local version="1.5.3"
|
local version="1.5.3"
|
||||||
|
|
||||||
if curl -s --max-time 5 -o lib/fennel/fennel.lua "https://fennel-lang.org/downloads/fennel-${version}.lua" 2>/dev/null; then
|
if curl -s --max-time 5 -o lib/fennel/fennel.lua "https://fennel-lang.org/downloads/fennel-${version}.lua" 2>/dev/null; then
|
||||||
if [[ -f "lib/fennel/fennel.lua" ]] && [[ -s "lib/fennel/fennel.lua" ]]; then
|
if [[ -f "lib/fennel/fennel.lua" ]] && [[ -s "lib/fennel/fennel.lua" ]]; then
|
||||||
print_success "Updated Fennel (${version})"
|
print_success "Updated Fennel (${version})"
|
||||||
|
|
@ -181,6 +231,18 @@ update_fennel() {
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
|
update_linenoise() {
|
||||||
|
print_info "Fetching linenoise"
|
||||||
|
|
||||||
|
if curl -s --max-time 5 -o lib/linenoise/linenoise.c https://raw.githubusercontent.com/antirez/linenoise/master/linenoise.c 2>/dev/null && \
|
||||||
|
curl -s --max-time 5 -o lib/linenoise/linenoise.h https://raw.githubusercontent.com/antirez/linenoise/master/linenoise.h 2>/dev/null; then
|
||||||
|
print_success "Updated linenoise"
|
||||||
|
else
|
||||||
|
print_error "Failed to download linenoise"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
update_luajit() {
|
update_luajit() {
|
||||||
print_info "Fetching LuaJIT"
|
print_info "Fetching LuaJIT"
|
||||||
|
|
||||||
|
|
@ -198,25 +260,8 @@ update_luajit() {
|
||||||
print_success "Updated LuaJIT (${version})"
|
print_success "Updated LuaJIT (${version})"
|
||||||
}
|
}
|
||||||
|
|
||||||
build_luajit() {
|
|
||||||
if [[ ! -f "lib/luajit/src/libluajit.a" ]]; then
|
|
||||||
print_info "Building LuaJIT"
|
|
||||||
cd lib/luajit
|
|
||||||
|
|
||||||
if [[ "$(uname)" == "Darwin" ]]; then
|
|
||||||
export MACOSX_DEPLOYMENT_TARGET="10.11"
|
|
||||||
fi
|
|
||||||
|
|
||||||
make clean >/dev/null 2>&1 || true
|
|
||||||
make -j$(nproc 2>/dev/null || echo 4) > /dev/null 2>&1
|
|
||||||
cd - > /dev/null
|
|
||||||
print_success "Built LuaJIT"
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
update_microui() {
|
update_microui() {
|
||||||
print_info "Fetching microui"
|
print_info "Fetching microui"
|
||||||
mkdir -p lib/microui/src
|
|
||||||
|
|
||||||
if curl -s --max-time 5 -o lib/microui/src/microui.c https://raw.githubusercontent.com/rxi/microui/master/src/microui.c 2>/dev/null && \
|
if curl -s --max-time 5 -o lib/microui/src/microui.c https://raw.githubusercontent.com/rxi/microui/master/src/microui.c 2>/dev/null && \
|
||||||
curl -s --max-time 5 -o lib/microui/src/microui.h https://raw.githubusercontent.com/rxi/microui/master/src/microui.h 2>/dev/null; then
|
curl -s --max-time 5 -o lib/microui/src/microui.h https://raw.githubusercontent.com/rxi/microui/master/src/microui.h 2>/dev/null; then
|
||||||
|
|
@ -229,11 +274,10 @@ update_microui() {
|
||||||
|
|
||||||
update_miniz() {
|
update_miniz() {
|
||||||
print_info "Fetching miniz"
|
print_info "Fetching miniz"
|
||||||
mkdir -p lib/miniz
|
|
||||||
|
|
||||||
local version="3.0.2"
|
local version="3.0.2"
|
||||||
|
|
||||||
if curl -sL --max-time 10 -o /tmp/miniz.zip "https://github.com/richgel999/miniz/releases/download/${version}/miniz-${version}.zip" 2>/dev/null; then
|
if curl -sL --max-time 5 -o /tmp/miniz.zip "https://github.com/richgel999/miniz/releases/download/${version}/miniz-${version}.zip" 2>/dev/null; then
|
||||||
unzip -qjo /tmp/miniz.zip miniz.c miniz.h -d lib/miniz/ 2>/dev/null
|
unzip -qjo /tmp/miniz.zip miniz.c miniz.h -d lib/miniz/ 2>/dev/null
|
||||||
rm -f /tmp/miniz.zip
|
rm -f /tmp/miniz.zip
|
||||||
|
|
||||||
|
|
@ -249,7 +293,7 @@ update_miniz() {
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
vendor_sdl() {
|
update_sdl() {
|
||||||
print_info "Fetching SDL3"
|
print_info "Fetching SDL3"
|
||||||
|
|
||||||
if [[ -d "lib/SDL/.git" ]]; then
|
if [[ -d "lib/SDL/.git" ]]; then
|
||||||
|
|
@ -263,18 +307,6 @@ vendor_sdl() {
|
||||||
print_success "Updated SDL3"
|
print_success "Updated SDL3"
|
||||||
}
|
}
|
||||||
|
|
||||||
build_sdl() {
|
|
||||||
if [[ ! -f "lib/SDL/build/libSDL3.so" ]] && [[ ! -f "lib/SDL/build/libSDL3.a" ]] && [[ ! -f "lib/SDL/build/libSDL3.dylib" ]]; then
|
|
||||||
print_info "Building SDL3"
|
|
||||||
mkdir -p lib/SDL/build
|
|
||||||
cd lib/SDL/build
|
|
||||||
cmake .. -DCMAKE_BUILD_TYPE=Release > /dev/null 2>&1
|
|
||||||
cmake --build . --parallel $(nproc 2>/dev/null || echo 4) > /dev/null 2>&1
|
|
||||||
cd - > /dev/null
|
|
||||||
print_success "Built SDL3"
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
case "$COMMAND" in
|
case "$COMMAND" in
|
||||||
build)
|
build)
|
||||||
mkdir -p "$BUILDDIR"
|
mkdir -p "$BUILDDIR"
|
||||||
|
|
@ -286,9 +318,10 @@ case "$COMMAND" in
|
||||||
[[ ! -f "lib/miniz/miniz.c" ]] || \
|
[[ ! -f "lib/miniz/miniz.c" ]] || \
|
||||||
[[ ! -f "lib/fennel/fennel.lua" ]]; then
|
[[ ! -f "lib/fennel/fennel.lua" ]]; then
|
||||||
print_info "Missing dependencies, fetching..."
|
print_info "Missing dependencies, fetching..."
|
||||||
|
|
||||||
update_linenoise
|
make_lib_dirs
|
||||||
update_fennel
|
update_fennel
|
||||||
|
update_linenoise
|
||||||
update_luajit
|
update_luajit
|
||||||
update_microui
|
update_microui
|
||||||
update_miniz
|
update_miniz
|
||||||
|
|
@ -341,7 +374,7 @@ case "$COMMAND" in
|
||||||
|
|
||||||
LIB_SOURCE_FILES="lib/linenoise/linenoise.c lib/miniz/miniz.c"
|
LIB_SOURCE_FILES="lib/linenoise/linenoise.c lib/miniz/miniz.c"
|
||||||
|
|
||||||
SRC_SOURCE_FILES="
|
PXL8_SOURCE_FILES="
|
||||||
src/pxl8.c
|
src/pxl8.c
|
||||||
src/pxl8_ase.c
|
src/pxl8_ase.c
|
||||||
src/pxl8_blit.c
|
src/pxl8_blit.c
|
||||||
|
|
@ -367,32 +400,24 @@ case "$COMMAND" in
|
||||||
obj_name=$(basename "$src_file" .c).o
|
obj_name=$(basename "$src_file" .c).o
|
||||||
obj_file="$OBJECT_DIR/$obj_name"
|
obj_file="$OBJECT_DIR/$obj_name"
|
||||||
OBJECTS="$OBJECTS $obj_file"
|
OBJECTS="$OBJECTS $obj_file"
|
||||||
|
|
||||||
if [[ "$src_file" -nt "$obj_file" ]]; then
|
if [[ "$src_file" -nt "$obj_file" ]]; then
|
||||||
NEED_LINK=true
|
NEED_LINK=true
|
||||||
print_info "Compiling: $src_file"
|
compile_source_file "$src_file" "$obj_file" "$COMPILE_FLAGS"
|
||||||
if ! $CC -c $COMPILE_FLAGS "$src_file" -o "$obj_file"; then
|
|
||||||
print_error "Compilation failed for $src_file"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
SOURCES_COMPILED="yes"
|
SOURCES_COMPILED="yes"
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
|
|
||||||
for src_file in $SRC_SOURCE_FILES; do
|
for src_file in $PXL8_SOURCE_FILES; do
|
||||||
obj_name=$(basename "$src_file" .c).o
|
obj_name=$(basename "$src_file" .c).o
|
||||||
obj_file="$OBJECT_DIR/$obj_name"
|
obj_file="$OBJECT_DIR/$obj_name"
|
||||||
OBJECTS="$OBJECTS $obj_file"
|
OBJECTS="$OBJECTS $obj_file"
|
||||||
|
|
||||||
if [[ "$src_file" -nt "$obj_file" ]] || \
|
if [[ "$src_file" -nt "$obj_file" ]] || \
|
||||||
[[ "src/pxl8_types.h" -nt "$obj_file" ]] || \
|
[[ "src/pxl8_types.h" -nt "$obj_file" ]] || \
|
||||||
[[ "src/pxl8_macros.h" -nt "$obj_file" ]]; then
|
[[ "src/pxl8_macros.h" -nt "$obj_file" ]]; then
|
||||||
NEED_LINK=true
|
NEED_LINK=true
|
||||||
print_info "Compiling: $src_file"
|
compile_source_file "$src_file" "$obj_file" "$COMPILE_FLAGS"
|
||||||
if ! $CC -c $COMPILE_FLAGS "$src_file" -o "$obj_file"; then
|
|
||||||
print_error "Compilation failed for $src_file"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
SOURCES_COMPILED="yes"
|
SOURCES_COMPILED="yes"
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
|
|
@ -413,31 +438,58 @@ case "$COMMAND" in
|
||||||
|
|
||||||
run)
|
run)
|
||||||
"$0" build "$@" || exit 1
|
"$0" build "$@" || exit 1
|
||||||
|
|
||||||
SCRIPT=""
|
CART=""
|
||||||
for arg in "$@"; do
|
for arg in "$@"; do
|
||||||
if [[ "$arg" != "--release" ]]; then
|
if [[ "$arg" != "--release" ]]; then
|
||||||
SCRIPT="$arg"
|
CART="$arg"
|
||||||
break
|
break
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
|
|
||||||
if [[ -z "$SCRIPT" ]]; then
|
if [[ -z "$CART" ]]; then
|
||||||
SCRIPT="src/fnl/demo.fnl"
|
"$BINDIR/pxl8"
|
||||||
|
else
|
||||||
|
"$BINDIR/pxl8" "$CART"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
"$BINDIR/pxl8" "$SCRIPT"
|
|
||||||
;;
|
;;
|
||||||
|
|
||||||
clean)
|
clean)
|
||||||
if [[ "$1" == "--all" ]] || [[ "$1" == "--deps" ]]; then
|
CLEAN_ALL=false
|
||||||
print_info "Removing all build artifacts and dependencies"
|
CLEAN_DEPS=false
|
||||||
rm -rf "$BUILDDIR" "$BINDIR" lib
|
CLEAN_RELEASE=false
|
||||||
|
|
||||||
|
for arg in "$@"; do
|
||||||
|
case "$arg" in
|
||||||
|
--all) CLEAN_ALL=true ;;
|
||||||
|
--deps) CLEAN_DEPS=true ;;
|
||||||
|
--release) CLEAN_RELEASE=true ;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
|
||||||
|
if [[ "$CLEAN_RELEASE" == true ]]; then
|
||||||
|
BUILD_PATH=".build/release"
|
||||||
|
BIN_PATH="bin/release"
|
||||||
|
MODE="release"
|
||||||
|
else
|
||||||
|
BUILD_PATH=".build/debug"
|
||||||
|
BIN_PATH="bin/debug"
|
||||||
|
MODE="debug"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ "$CLEAN_ALL" == true ]]; then
|
||||||
|
print_info "Removing build artifacts and dependencies"
|
||||||
|
rm -rf "$BUILD_PATH" "$BIN_PATH" lib
|
||||||
|
print_success "Cleaned all"
|
||||||
|
elif [[ "$CLEAN_DEPS" == true ]]; then
|
||||||
|
print_info "Removing dependencies"
|
||||||
|
rm -rf lib
|
||||||
|
print_success "Cleaned dependencies"
|
||||||
else
|
else
|
||||||
print_info "Removing build artifacts"
|
print_info "Removing build artifacts"
|
||||||
rm -rf "$BUILDDIR" "$BINDIR"
|
rm -rf "$BUILD_PATH" "$BIN_PATH"
|
||||||
|
print_success "Cleaned"
|
||||||
fi
|
fi
|
||||||
print_success "Cleaned"
|
|
||||||
;;
|
;;
|
||||||
|
|
||||||
update)
|
update)
|
||||||
|
|
@ -450,7 +502,7 @@ case "$COMMAND" in
|
||||||
;;
|
;;
|
||||||
|
|
||||||
vendor)
|
vendor)
|
||||||
vendor_sdl
|
update_sdl
|
||||||
;;
|
;;
|
||||||
|
|
||||||
help|--help|-h|"")
|
help|--help|-h|"")
|
||||||
|
|
|
||||||
|
|
@ -100,8 +100,8 @@ function pxl8.key_pressed(key)
|
||||||
return C.pxl8_key_pressed(input, key)
|
return C.pxl8_key_pressed(input, key)
|
||||||
end
|
end
|
||||||
|
|
||||||
function pxl8.vfx_copper_bars(bars, time)
|
function pxl8.vfx_raster_bars(bars, time)
|
||||||
local c_bars = ffi.new("pxl8_copper_bar[?]", #bars)
|
local c_bars = ffi.new("pxl8_raster_bar[?]", #bars)
|
||||||
for i, bar in ipairs(bars) do
|
for i, bar in ipairs(bars) do
|
||||||
c_bars[i-1].base_y = bar.base_y or 0
|
c_bars[i-1].base_y = bar.base_y or 0
|
||||||
c_bars[i-1].amplitude = bar.amplitude or 10
|
c_bars[i-1].amplitude = bar.amplitude or 10
|
||||||
|
|
@ -111,7 +111,7 @@ function pxl8.vfx_copper_bars(bars, time)
|
||||||
c_bars[i-1].color = bar.color or 15
|
c_bars[i-1].color = bar.color or 15
|
||||||
c_bars[i-1].fade_color = bar.fade_color or bar.color or 15
|
c_bars[i-1].fade_color = bar.fade_color or bar.color or 15
|
||||||
end
|
end
|
||||||
C.pxl8_vfx_copper_bars(gfx, c_bars, #bars, time)
|
C.pxl8_vfx_raster_bars(gfx, c_bars, #bars, time)
|
||||||
end
|
end
|
||||||
|
|
||||||
function pxl8.vfx_plasma(time, scale1, scale2, palette_offset)
|
function pxl8.vfx_plasma(time, scale1, scale2, palette_offset)
|
||||||
|
|
|
||||||
75
src/pxl8.c
75
src/pxl8.c
|
|
@ -32,13 +32,13 @@ typedef struct pxl8_repl_state {
|
||||||
bool running;
|
bool running;
|
||||||
} pxl8_repl_state;
|
} pxl8_repl_state;
|
||||||
|
|
||||||
typedef struct pxl8_app_state {
|
typedef struct pxl8_state {
|
||||||
|
pxl8_cart* cart;
|
||||||
pxl8_color_mode color_mode;
|
pxl8_color_mode color_mode;
|
||||||
pxl8_gfx_ctx gfx;
|
pxl8_gfx_ctx gfx;
|
||||||
lua_State* lua;
|
lua_State* lua;
|
||||||
pxl8_repl_state repl;
|
pxl8_repl_state repl;
|
||||||
pxl8_resolution resolution;
|
pxl8_resolution resolution;
|
||||||
pxl8_cart* cart;
|
|
||||||
|
|
||||||
f32 fps_timer;
|
f32 fps_timer;
|
||||||
i32 frame_count;
|
i32 frame_count;
|
||||||
|
|
@ -52,7 +52,7 @@ typedef struct pxl8_app_state {
|
||||||
time_t script_mod_time;
|
time_t script_mod_time;
|
||||||
|
|
||||||
pxl8_input_state input;
|
pxl8_input_state input;
|
||||||
} pxl8_app_state;
|
} pxl8_state;
|
||||||
|
|
||||||
static void pxl8_repl_completion(const char* buf, linenoiseCompletions* lc) {
|
static void pxl8_repl_completion(const char* buf, linenoiseCompletions* lc) {
|
||||||
const char* fennel_keywords[] = {
|
const char* fennel_keywords[] = {
|
||||||
|
|
@ -183,7 +183,7 @@ static pxl8_repl_command* pxl8_repl_pop_command(pxl8_repl_state* repl) {
|
||||||
return cmd;
|
return cmd;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void load_script(pxl8_app_state* app) {
|
static void load_script(pxl8_state* app) {
|
||||||
const char* ext = strrchr(app->script_path, '.');
|
const char* ext = strrchr(app->script_path, '.');
|
||||||
|
|
||||||
if (ext && strcmp(ext, ".fnl") == 0) {
|
if (ext && strcmp(ext, ".fnl") == 0) {
|
||||||
|
|
@ -233,7 +233,7 @@ static time_t get_file_mod_time(const char* path) {
|
||||||
}
|
}
|
||||||
|
|
||||||
SDL_AppResult SDL_AppInit(void** appstate, int argc, char* argv[]) {
|
SDL_AppResult SDL_AppInit(void** appstate, int argc, char* argv[]) {
|
||||||
static pxl8_app_state app = {0};
|
static pxl8_state app = {0};
|
||||||
|
|
||||||
if (!SDL_Init(SDL_INIT_VIDEO | SDL_INIT_EVENTS)) {
|
if (!SDL_Init(SDL_INIT_VIDEO | SDL_INIT_EVENTS)) {
|
||||||
pxl8_error("SDL_Init failed: %s", SDL_GetError());
|
pxl8_error("SDL_Init failed: %s", SDL_GetError());
|
||||||
|
|
@ -299,36 +299,40 @@ SDL_AppResult SDL_AppInit(void** appstate, int argc, char* argv[]) {
|
||||||
return SDL_APP_FAILURE;
|
return SDL_APP_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (script_arg) {
|
const char* cart_path = script_arg ? script_arg : "demo";
|
||||||
struct stat st;
|
|
||||||
bool is_cart = (stat(script_arg, &st) == 0 && S_ISDIR(st.st_mode)) ||
|
|
||||||
strstr(script_arg, ".pxc");
|
|
||||||
|
|
||||||
if (is_cart) {
|
struct stat st;
|
||||||
char* original_cwd = getcwd(NULL, 0);
|
bool is_cart = (stat(cart_path, &st) == 0 && S_ISDIR(st.st_mode)) ||
|
||||||
app.cart = pxl8_cart_new();
|
(cart_path && strstr(cart_path, ".pxc"));
|
||||||
if (pxl8_cart_load(app.cart, script_arg) == PXL8_OK) {
|
|
||||||
pxl8_lua_setup_cart_path(app.lua, app.cart->base_path, original_cwd);
|
if (is_cart) {
|
||||||
pxl8_cart_mount(app.cart);
|
char* original_cwd = getcwd(NULL, 0);
|
||||||
strcpy(app.script_path, "main.fnl");
|
app.cart = calloc(1, sizeof(pxl8_cart));
|
||||||
pxl8_info("Loaded cart: %s", app.cart->name);
|
if (!app.cart) {
|
||||||
} else {
|
pxl8_error("Failed to allocate memory for cart");
|
||||||
pxl8_error("Failed to load cart: %s", script_arg);
|
return false;
|
||||||
return SDL_APP_FAILURE;
|
|
||||||
}
|
|
||||||
free(original_cwd);
|
|
||||||
} else {
|
|
||||||
strncpy(app.script_path, script_arg, sizeof(app.script_path) - 1);
|
|
||||||
app.script_path[sizeof(app.script_path) - 1] = '\0';
|
|
||||||
}
|
}
|
||||||
} else {
|
if (pxl8_cart_load(app.cart, cart_path) == PXL8_OK) {
|
||||||
strcpy(app.script_path, "src/fnl/demo.fnl");
|
pxl8_lua_setup_cart_path(app.lua, app.cart->base_path, original_cwd);
|
||||||
|
pxl8_cart_mount(app.cart);
|
||||||
|
strcpy(app.script_path, "main.fnl");
|
||||||
|
pxl8_info("Loaded cart: %s", app.cart->name);
|
||||||
|
} else {
|
||||||
|
pxl8_error("Failed to load cart: %s", cart_path);
|
||||||
|
return SDL_APP_FAILURE;
|
||||||
|
}
|
||||||
|
free(original_cwd);
|
||||||
|
} else if (script_arg) {
|
||||||
|
strncpy(app.script_path, script_arg, sizeof(app.script_path) - 1);
|
||||||
|
app.script_path[sizeof(app.script_path) - 1] = '\0';
|
||||||
}
|
}
|
||||||
|
|
||||||
pxl8_lua_setup_contexts(app.lua, &app.gfx, &app.input);
|
pxl8_lua_setup_contexts(app.lua, &app.gfx, &app.input);
|
||||||
|
|
||||||
app.script_mod_time = get_file_mod_time(app.script_path);
|
if (app.script_path[0] != '\0') {
|
||||||
load_script(&app);
|
app.script_mod_time = get_file_mod_time(app.script_path);
|
||||||
|
load_script(&app);
|
||||||
|
}
|
||||||
|
|
||||||
if (app.repl_mode) {
|
if (app.repl_mode) {
|
||||||
pxl8_repl_init(&app.repl);
|
pxl8_repl_init(&app.repl);
|
||||||
|
|
@ -353,7 +357,7 @@ SDL_AppResult SDL_AppInit(void** appstate, int argc, char* argv[]) {
|
||||||
}
|
}
|
||||||
|
|
||||||
SDL_AppResult SDL_AppIterate(void* appstate) {
|
SDL_AppResult SDL_AppIterate(void* appstate) {
|
||||||
pxl8_app_state* app = (pxl8_app_state*)appstate;
|
pxl8_state* app = (pxl8_state*)appstate;
|
||||||
int width, height;
|
int width, height;
|
||||||
|
|
||||||
SDL_GetWindowSize(app->gfx.window, &width, &height);
|
SDL_GetWindowSize(app->gfx.window, &width, &height);
|
||||||
|
|
@ -465,7 +469,7 @@ SDL_AppResult SDL_AppIterate(void* appstate) {
|
||||||
}
|
}
|
||||||
|
|
||||||
SDL_AppResult SDL_AppEvent(void* appstate, SDL_Event* event) {
|
SDL_AppResult SDL_AppEvent(void* appstate, SDL_Event* event) {
|
||||||
pxl8_app_state* app = (pxl8_app_state*)appstate;
|
pxl8_state* app = (pxl8_state*)appstate;
|
||||||
|
|
||||||
switch (event->type) {
|
switch (event->type) {
|
||||||
case SDL_EVENT_QUIT:
|
case SDL_EVENT_QUIT:
|
||||||
|
|
@ -502,7 +506,7 @@ SDL_AppResult SDL_AppEvent(void* appstate, SDL_Event* event) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void SDL_AppQuit(void* appstate, SDL_AppResult result) {
|
void SDL_AppQuit(void* appstate, SDL_AppResult result) {
|
||||||
pxl8_app_state* app = (pxl8_app_state*)appstate;
|
pxl8_state* app = (pxl8_state*)appstate;
|
||||||
(void)result;
|
(void)result;
|
||||||
|
|
||||||
if (app) {
|
if (app) {
|
||||||
|
|
@ -511,7 +515,8 @@ void SDL_AppQuit(void* appstate, SDL_AppResult result) {
|
||||||
pxl8_repl_shutdown(&app->repl);
|
pxl8_repl_shutdown(&app->repl);
|
||||||
}
|
}
|
||||||
if (app->cart) {
|
if (app->cart) {
|
||||||
pxl8_cart_destroy(app->cart);
|
pxl8_cart_unload(app->cart);
|
||||||
|
free(app->cart);
|
||||||
app->cart = NULL;
|
app->cart = NULL;
|
||||||
}
|
}
|
||||||
pxl8_lua_shutdown(app->lua);
|
pxl8_lua_shutdown(app->lua);
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
|
#include <SDL3/SDL.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <SDL3/SDL.h>
|
|
||||||
|
|
||||||
#define MINIZ_NO_STDIO
|
#define MINIZ_NO_STDIO
|
||||||
#define MINIZ_NO_TIME
|
#define MINIZ_NO_TIME
|
||||||
|
|
@ -89,8 +89,7 @@ static pxl8_result parse_old_palette_chunk(const u8* data, pxl8_ase_palette* pal
|
||||||
u8 r = packet_data[0];
|
u8 r = packet_data[0];
|
||||||
u8 g = packet_data[1];
|
u8 g = packet_data[1];
|
||||||
u8 b = packet_data[2];
|
u8 b = packet_data[2];
|
||||||
|
|
||||||
// Store in ABGR format for GPU
|
|
||||||
palette->colors[color_index] = 0xFF000000 | (b << 16) | (g << 8) | r;
|
palette->colors[color_index] = 0xFF000000 | (b << 16) | (g << 8) | r;
|
||||||
packet_data += 3;
|
packet_data += 3;
|
||||||
}
|
}
|
||||||
|
|
@ -100,16 +99,12 @@ static pxl8_result parse_old_palette_chunk(const u8* data, pxl8_ase_palette* pal
|
||||||
}
|
}
|
||||||
|
|
||||||
static pxl8_result parse_layer_chunk(const u8* data, pxl8_ase_layer* layer) {
|
static pxl8_result parse_layer_chunk(const u8* data, pxl8_ase_layer* layer) {
|
||||||
layer->flags = read_u16_le(data); // Offset 0: flags (2 bytes)
|
layer->flags = read_u16_le(data);
|
||||||
layer->layer_type = read_u16_le(data + 2); // Offset 2: layer_type (2 bytes)
|
layer->layer_type = read_u16_le(data + 2);
|
||||||
layer->child_level = read_u16_le(data + 4); // Offset 4: child_level (2 bytes)
|
layer->child_level = read_u16_le(data + 4);
|
||||||
// Offset 6: default_width (2 bytes) - skip
|
layer->blend_mode = read_u16_le(data + 10);
|
||||||
// Offset 8: default_height (2 bytes) - skip
|
layer->opacity = data[12];
|
||||||
layer->blend_mode = read_u16_le(data + 10); // Offset 10: blend_mode (2 bytes)
|
|
||||||
layer->opacity = data[12]; // Offset 12: opacity (1 byte)
|
|
||||||
// Offset 13-15: reserved (3 bytes) - skip
|
|
||||||
|
|
||||||
// Offset 16: name length (2 bytes), then name string at offset 18
|
|
||||||
u16 name_len = read_u16_le(data + 16);
|
u16 name_len = read_u16_le(data + 16);
|
||||||
if (name_len > 0) {
|
if (name_len > 0) {
|
||||||
layer->name = (char*)SDL_malloc(name_len + 1);
|
layer->name = (char*)SDL_malloc(name_len + 1);
|
||||||
|
|
@ -124,9 +119,9 @@ static pxl8_result parse_layer_chunk(const u8* data, pxl8_ase_layer* layer) {
|
||||||
}
|
}
|
||||||
|
|
||||||
static pxl8_result parse_palette_chunk(const u8* data, pxl8_ase_palette* palette) {
|
static pxl8_result parse_palette_chunk(const u8* data, pxl8_ase_palette* palette) {
|
||||||
palette->entry_count = read_u32_le(data); // Offset 0: entry_count (4 bytes)
|
palette->entry_count = read_u32_le(data);
|
||||||
palette->first_color = read_u32_le(data + 4); // Offset 4: first_color (4 bytes)
|
palette->first_color = read_u32_le(data + 4);
|
||||||
palette->last_color = read_u32_le(data + 8); // Offset 8: last_color (4 bytes)
|
palette->last_color = read_u32_le(data + 8);
|
||||||
|
|
||||||
u32 color_count = palette->entry_count;
|
u32 color_count = palette->entry_count;
|
||||||
palette->colors = (u32*)SDL_malloc(color_count * sizeof(u32));
|
palette->colors = (u32*)SDL_malloc(color_count * sizeof(u32));
|
||||||
|
|
@ -134,15 +129,14 @@ static pxl8_result parse_palette_chunk(const u8* data, pxl8_ase_palette* palette
|
||||||
return PXL8_ERROR_OUT_OF_MEMORY;
|
return PXL8_ERROR_OUT_OF_MEMORY;
|
||||||
}
|
}
|
||||||
|
|
||||||
const u8* color_data = data + 20; // Skip palette header (20 bytes)
|
const u8* color_data = data + 20;
|
||||||
for (u32 i = 0; i < color_count; i++) {
|
for (u32 i = 0; i < color_count; i++) {
|
||||||
u16 flags = read_u16_le(color_data); // Offset 0: flags (2 bytes)
|
u16 flags = read_u16_le(color_data);
|
||||||
u8 r = color_data[2]; // Offset 2: red (1 byte)
|
u8 r = color_data[2];
|
||||||
u8 g = color_data[3]; // Offset 3: green (1 byte)
|
u8 g = color_data[3];
|
||||||
u8 b = color_data[4]; // Offset 4: blue (1 byte)
|
u8 b = color_data[4];
|
||||||
u8 a = color_data[5]; // Offset 5: alpha (1 byte)
|
u8 a = color_data[5];
|
||||||
|
|
||||||
// Store in ABGR format for GPU
|
|
||||||
palette->colors[i] = (a << 24) | (b << 16) | (g << 8) | r;
|
palette->colors[i] = (a << 24) | (b << 16) | (g << 8) | r;
|
||||||
color_data += 6;
|
color_data += 6;
|
||||||
|
|
||||||
|
|
@ -160,21 +154,19 @@ static pxl8_result parse_cel_chunk(const u8* data, u32 chunk_size, pxl8_ase_cel*
|
||||||
return PXL8_ERROR_ASE_MALFORMED_CHUNK;
|
return PXL8_ERROR_ASE_MALFORMED_CHUNK;
|
||||||
}
|
}
|
||||||
|
|
||||||
cel->layer_index = read_u16_le(data); // Offset 0: layer_index (2 bytes)
|
cel->layer_index = read_u16_le(data);
|
||||||
cel->x = read_i16_le(data + 2); // Offset 2: x (2 bytes)
|
cel->x = read_i16_le(data + 2);
|
||||||
cel->y = read_i16_le(data + 4); // Offset 4: y (2 bytes)
|
cel->y = read_i16_le(data + 4);
|
||||||
cel->opacity = data[6]; // Offset 6: opacity (1 byte)
|
cel->opacity = data[6];
|
||||||
cel->cel_type = read_u16_le(data + 7); // Offset 7: cel_type (2 bytes)
|
cel->cel_type = read_u16_le(data + 7);
|
||||||
|
|
||||||
if (cel->cel_type == 2) {
|
if (cel->cel_type == 2) {
|
||||||
if (chunk_size < 20) {
|
if (chunk_size < 20) {
|
||||||
return PXL8_ERROR_ASE_MALFORMED_CHUNK;
|
return PXL8_ERROR_ASE_MALFORMED_CHUNK;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Offset 9: Z-Index (2 bytes) - skip
|
cel->width = read_u16_le(data + 16);
|
||||||
// Offset 11: Reserved (5 bytes) - skip
|
cel->height = read_u16_le(data + 18);
|
||||||
cel->width = read_u16_le(data + 16); // Offset 16: width (2 bytes)
|
|
||||||
cel->height = read_u16_le(data + 18); // Offset 18: height (2 bytes)
|
|
||||||
|
|
||||||
u32 pixel_data_size = cel->width * cel->height;
|
u32 pixel_data_size = cel->width * cel->height;
|
||||||
u32 compressed_data_size = chunk_size - 20;
|
u32 compressed_data_size = chunk_size - 20;
|
||||||
|
|
@ -183,8 +175,7 @@ static pxl8_result parse_cel_chunk(const u8* data, u32 chunk_size, pxl8_ase_cel*
|
||||||
if (!cel->pixel_data) {
|
if (!cel->pixel_data) {
|
||||||
return PXL8_ERROR_OUT_OF_MEMORY;
|
return PXL8_ERROR_OUT_OF_MEMORY;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Decompress ZLIB data
|
|
||||||
mz_ulong dest_len = pixel_data_size;
|
mz_ulong dest_len = pixel_data_size;
|
||||||
int result = mz_uncompress(cel->pixel_data, &dest_len, data + 20, compressed_data_size);
|
int result = mz_uncompress(cel->pixel_data, &dest_len, data + 20, compressed_data_size);
|
||||||
if (result != MZ_OK) {
|
if (result != MZ_OK) {
|
||||||
|
|
@ -274,16 +265,17 @@ pxl8_result pxl8_ase_load(const char* filepath, pxl8_ase_file* ase_file) {
|
||||||
case PXL8_ASE_CHUNK_OLD_PALETTE: // 0x0004
|
case PXL8_ASE_CHUNK_OLD_PALETTE: // 0x0004
|
||||||
if (!ase_file->palette.colors) {
|
if (!ase_file->palette.colors) {
|
||||||
result = parse_old_palette_chunk(chunk_payload, &ase_file->palette);
|
result = parse_old_palette_chunk(chunk_payload, &ase_file->palette);
|
||||||
pxl8_debug("Parsed old palette: %d colors, indices %d-%d", ase_file->palette.entry_count, ase_file->palette.first_color, ase_file->palette.last_color);
|
pxl8_debug("Parsed old palette: %d colors, indices %d-%d",
|
||||||
|
ase_file->palette.entry_count, ase_file->palette.first_color, ase_file->palette.last_color);
|
||||||
} else {
|
} else {
|
||||||
pxl8_debug("Ignoring old palette (0x0004) - new palette (0x2019) already loaded");
|
pxl8_debug("Ignoring old palette (0x0004) - new palette (0x2019) already loaded");
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case PXL8_ASE_CHUNK_LAYER: { // 0x2004
|
case PXL8_ASE_CHUNK_LAYER: { // 0x2004
|
||||||
// Need to allocate or reallocate layers array
|
ase_file->layers =
|
||||||
ase_file->layers = (pxl8_ase_layer*)SDL_realloc(ase_file->layers,
|
(pxl8_ase_layer*)SDL_realloc(ase_file->layers,
|
||||||
(ase_file->layer_count + 1) * sizeof(pxl8_ase_layer));
|
(ase_file->layer_count + 1) * sizeof(pxl8_ase_layer));
|
||||||
if (!ase_file->layers) {
|
if (!ase_file->layers) {
|
||||||
result = PXL8_ERROR_OUT_OF_MEMORY;
|
result = PXL8_ERROR_OUT_OF_MEMORY;
|
||||||
break;
|
break;
|
||||||
|
|
@ -315,15 +307,12 @@ pxl8_result pxl8_ase_load(const char* filepath, pxl8_ase_file* ase_file) {
|
||||||
u32 src_offset = y * cel.width;
|
u32 src_offset = y * cel.width;
|
||||||
u32 dst_offset = (y + cel.y) * frame->width + cel.x;
|
u32 dst_offset = (y + cel.y) * frame->width + cel.x;
|
||||||
if (dst_offset + copy_width <= pixel_count) {
|
if (dst_offset + copy_width <= pixel_count) {
|
||||||
// Composite layers: only copy non-transparent pixels
|
|
||||||
// Check if palette color is transparent (#00000000)
|
|
||||||
for (u32 x = 0; x < copy_width; x++) {
|
for (u32 x = 0; x < copy_width; x++) {
|
||||||
u8 src_pixel = cel.pixel_data[src_offset + x];
|
u8 src_pixel = cel.pixel_data[src_offset + x];
|
||||||
bool is_transparent = false;
|
bool is_transparent = false;
|
||||||
|
|
||||||
if (src_pixel < ase_file->palette.entry_count && ase_file->palette.colors) {
|
if (src_pixel < ase_file->palette.entry_count && ase_file->palette.colors) {
|
||||||
u32 color = ase_file->palette.colors[src_pixel];
|
u32 color = ase_file->palette.colors[src_pixel];
|
||||||
// Check if color is fully transparent (alpha = 0)
|
|
||||||
is_transparent = ((color >> 24) & 0xFF) == 0;
|
is_transparent = ((color >> 24) & 0xFF) == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -331,9 +320,9 @@ pxl8_result pxl8_ase_load(const char* filepath, pxl8_ase_file* ase_file) {
|
||||||
frame->pixels[dst_offset + x] = src_pixel;
|
frame->pixels[dst_offset + x] = src_pixel;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Debug: check first few pixels of each row
|
|
||||||
if (y < 3) {
|
if (y < 3) {
|
||||||
pxl8_debug("Row %d: cel[%d]=%d, frame[%d]=%d", y, src_offset, cel.pixel_data[src_offset], dst_offset, frame->pixels[dst_offset]);
|
pxl8_debug("Row %d: cel[%d]=%d, frame[%d]=%d",
|
||||||
|
y, src_offset, cel.pixel_data[src_offset], dst_offset, frame->pixels[dst_offset]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -347,7 +336,8 @@ pxl8_result pxl8_ase_load(const char* filepath, pxl8_ase_file* ase_file) {
|
||||||
SDL_free(ase_file->palette.colors);
|
SDL_free(ase_file->palette.colors);
|
||||||
}
|
}
|
||||||
result = parse_palette_chunk(chunk_payload, &ase_file->palette);
|
result = parse_palette_chunk(chunk_payload, &ase_file->palette);
|
||||||
pxl8_debug("Parsed new palette: %d colors, indices %d-%d", ase_file->palette.entry_count, ase_file->palette.first_color, ase_file->palette.last_color);
|
pxl8_debug("Parsed new palette: %d colors, indices %d-%d",
|
||||||
|
ase_file->palette.entry_count, ase_file->palette.first_color, ase_file->palette.last_color);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
|
@ -355,10 +345,12 @@ pxl8_result pxl8_ase_load(const char* filepath, pxl8_ase_file* ase_file) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (result != PXL8_OK) break;
|
if (result != PXL8_OK) break;
|
||||||
|
|
||||||
chunk_data += chunk_header.chunk_size;
|
chunk_data += chunk_header.chunk_size;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (result != PXL8_OK) break;
|
if (result != PXL8_OK) break;
|
||||||
|
|
||||||
frame_data += frame_header.frame_bytes;
|
frame_data += frame_header.frame_bytes;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,4 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "pxl8_types.h"
|
#include "pxl8_types.h"
|
||||||
|
|
||||||
#define PXL8_ASE_MAGIC 0xA5E0
|
#define PXL8_ASE_MAGIC 0xA5E0
|
||||||
|
|
|
||||||
|
|
@ -1,33 +1,6 @@
|
||||||
#include "pxl8_blit.h"
|
#include "pxl8_blit.h"
|
||||||
#include "pxl8_simd.h"
|
#include "pxl8_simd.h"
|
||||||
|
|
||||||
void pxl8_blit_simd_indexed(u8* fb, u32 fb_width, const u8* sprite, u32 atlas_width,
|
|
||||||
i32 x, i32 y, u32 w, u32 h) {
|
|
||||||
u8* dest_base = fb + y * fb_width + x;
|
|
||||||
const u8* src_base = sprite;
|
|
||||||
|
|
||||||
for (u32 row = 0; row < h; row++) {
|
|
||||||
u8* dest_row = dest_base + row * fb_width;
|
|
||||||
const u8* src_row = src_base + row * atlas_width;
|
|
||||||
|
|
||||||
u32 col = 0;
|
|
||||||
for (; col + PXL8_SIMD_WIDTH_U8 <= w; col += PXL8_SIMD_WIDTH_U8) {
|
|
||||||
pxl8_simd_vec src_vec = pxl8_simd_load_u8(src_row + col);
|
|
||||||
pxl8_simd_vec dest_vec = pxl8_simd_load_u8(dest_row + col);
|
|
||||||
pxl8_simd_vec zero = pxl8_simd_zero_u8();
|
|
||||||
pxl8_simd_vec mask = pxl8_simd_cmpeq_u8(src_vec, zero);
|
|
||||||
pxl8_simd_vec result = pxl8_simd_blendv_u8(src_vec, dest_vec, mask);
|
|
||||||
pxl8_simd_store_u8(dest_row + col, result);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (; col < w; col++) {
|
|
||||||
if (src_row[col] != 0) {
|
|
||||||
dest_row[col] = src_row[col];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void pxl8_blit_simd_hicolor(u32* fb, u32 fb_width, const u32* sprite, u32 atlas_width,
|
void pxl8_blit_simd_hicolor(u32* fb, u32 fb_width, const u32* sprite, u32 atlas_width,
|
||||||
i32 x, i32 y, u32 w, u32 h) {
|
i32 x, i32 y, u32 w, u32 h) {
|
||||||
u32* dest_base = fb + y * fb_width + x;
|
u32* dest_base = fb + y * fb_width + x;
|
||||||
|
|
@ -56,3 +29,30 @@ void pxl8_blit_simd_hicolor(u32* fb, u32 fb_width, const u32* sprite, u32 atlas_
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void pxl8_blit_simd_indexed(u8* fb, u32 fb_width, const u8* sprite, u32 atlas_width,
|
||||||
|
i32 x, i32 y, u32 w, u32 h) {
|
||||||
|
u8* dest_base = fb + y * fb_width + x;
|
||||||
|
const u8* src_base = sprite;
|
||||||
|
|
||||||
|
for (u32 row = 0; row < h; row++) {
|
||||||
|
u8* dest_row = dest_base + row * fb_width;
|
||||||
|
const u8* src_row = src_base + row * atlas_width;
|
||||||
|
|
||||||
|
u32 col = 0;
|
||||||
|
for (; col + PXL8_SIMD_WIDTH_U8 <= w; col += PXL8_SIMD_WIDTH_U8) {
|
||||||
|
pxl8_simd_vec src_vec = pxl8_simd_load_u8(src_row + col);
|
||||||
|
pxl8_simd_vec dest_vec = pxl8_simd_load_u8(dest_row + col);
|
||||||
|
pxl8_simd_vec zero = pxl8_simd_zero_u8();
|
||||||
|
pxl8_simd_vec mask = pxl8_simd_cmpeq_u8(src_vec, zero);
|
||||||
|
pxl8_simd_vec result = pxl8_simd_blendv_u8(src_vec, dest_vec, mask);
|
||||||
|
pxl8_simd_store_u8(dest_row + col, result);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (; col < w; col++) {
|
||||||
|
if (src_row[col] != 0) {
|
||||||
|
dest_row[col] = src_row[col];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -7,13 +7,21 @@ static inline bool pxl8_is_simd_aligned(u32 w) {
|
||||||
return w >= PXL8_SIMD_WIDTH_U8 && (w % PXL8_SIMD_WIDTH_U8 == 0);
|
return w >= PXL8_SIMD_WIDTH_U8 && (w % PXL8_SIMD_WIDTH_U8 == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void pxl8_blit_simd_indexed(
|
#ifdef __cplusplus
|
||||||
u8* fb, u32 fb_width,
|
extern "C" {
|
||||||
const u8* sprite, u32 atlas_width,
|
#endif
|
||||||
i32 x, i32 y, u32 w, u32 h
|
|
||||||
);
|
|
||||||
void pxl8_blit_simd_hicolor(
|
void pxl8_blit_simd_hicolor(
|
||||||
u32* fb, u32 fb_width,
|
u32* fb, u32 fb_width,
|
||||||
const u32* sprite, u32 atlas_width,
|
const u32* sprite, u32 atlas_width,
|
||||||
i32 x, i32 y, u32 w, u32 h
|
i32 x, i32 y, u32 w, u32 h
|
||||||
);
|
);
|
||||||
|
void pxl8_blit_simd_indexed(
|
||||||
|
u8* fb, u32 fb_width,
|
||||||
|
const u8* sprite, u32 atlas_width,
|
||||||
|
i32 x, i32 y, u32 w, u32 h
|
||||||
|
);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
|
||||||
130
src/pxl8_cart.c
130
src/pxl8_cart.c
|
|
@ -8,17 +8,38 @@
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include "../lib/miniz/miniz.h"
|
#include "../lib/miniz/miniz.h"
|
||||||
|
|
||||||
static pxl8_cart* s_current_cart = NULL;
|
static pxl8_cart* __pxl8_current_cart = NULL;
|
||||||
static char* s_original_cwd = NULL;
|
static char* __pxl8_original_cwd = NULL;
|
||||||
|
|
||||||
static bool is_directory(const char* path) {
|
static void pxl8_add_file_recursive(mz_zip_archive* zip, const char* dir_path, const char* prefix) {
|
||||||
struct stat st;
|
DIR* dir = opendir(dir_path);
|
||||||
return stat(path, &st) == 0 && S_ISDIR(st.st_mode);
|
if (!dir) return;
|
||||||
}
|
|
||||||
|
|
||||||
static bool is_pxc_file(const char* path) {
|
struct dirent* entry;
|
||||||
size_t len = strlen(path);
|
while ((entry = readdir(dir)) != NULL) {
|
||||||
return len > 4 && strcmp(path + len - 4, ".pxc") == 0;
|
if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) continue;
|
||||||
|
|
||||||
|
char full_path[1024];
|
||||||
|
char zip_path[1024];
|
||||||
|
snprintf(full_path, sizeof(full_path), "%s/%s", dir_path, entry->d_name);
|
||||||
|
snprintf(zip_path, sizeof(zip_path), "%s%s", prefix, entry->d_name);
|
||||||
|
|
||||||
|
struct stat st;
|
||||||
|
if (stat(full_path, &st) == 0) {
|
||||||
|
if (S_ISDIR(st.st_mode)) {
|
||||||
|
char new_prefix[1025];
|
||||||
|
snprintf(new_prefix, sizeof(new_prefix), "%s/", zip_path);
|
||||||
|
pxl8_add_file_recursive(zip, full_path, new_prefix);
|
||||||
|
} else {
|
||||||
|
pxl8_info("Adding: %s", zip_path);
|
||||||
|
if (!mz_zip_writer_add_file(zip, zip_path, full_path, NULL, 0, MZ_BEST_COMPRESSION)) {
|
||||||
|
pxl8_warn("Failed to add file: %s", zip_path);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
closedir(dir);
|
||||||
}
|
}
|
||||||
|
|
||||||
static char* get_cart_name(const char* path) {
|
static char* get_cart_name(const char* path) {
|
||||||
|
|
@ -39,19 +60,18 @@ static char* get_cart_name(const char* path) {
|
||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
|
|
||||||
pxl8_cart* pxl8_cart_new(void) {
|
static bool is_directory(const char* path) {
|
||||||
pxl8_cart* cart = calloc(1, sizeof(pxl8_cart));
|
struct stat st;
|
||||||
if (!cart) {
|
return stat(path, &st) == 0 && S_ISDIR(st.st_mode);
|
||||||
pxl8_error("Failed to allocate cart");
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
return cart;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void pxl8_cart_destroy(pxl8_cart* cart) {
|
static bool is_pxc_file(const char* path) {
|
||||||
if (!cart) return;
|
size_t len = strlen(path);
|
||||||
pxl8_cart_unload(cart);
|
return len > 4 && strcmp(path + len - 4, ".pxc") == 0;
|
||||||
free(cart);
|
}
|
||||||
|
|
||||||
|
pxl8_cart* pxl8_cart_current(void) {
|
||||||
|
return __pxl8_current_cart;
|
||||||
}
|
}
|
||||||
|
|
||||||
pxl8_result pxl8_cart_load(pxl8_cart* cart, const char* path) {
|
pxl8_result pxl8_cart_load(pxl8_cart* cart, const char* path) {
|
||||||
|
|
@ -128,7 +148,7 @@ pxl8_result pxl8_cart_load(pxl8_cart* cart, const char* path) {
|
||||||
mz_zip_archive_file_stat file_stat;
|
mz_zip_archive_file_stat file_stat;
|
||||||
if (!mz_zip_reader_file_stat(&zip, i, &file_stat)) continue;
|
if (!mz_zip_reader_file_stat(&zip, i, &file_stat)) continue;
|
||||||
|
|
||||||
char extract_path[512];
|
char extract_path[1024];
|
||||||
snprintf(extract_path, sizeof(extract_path), "%s/%s", temp_dir, file_stat.m_filename);
|
snprintf(extract_path, sizeof(extract_path), "%s/%s", temp_dir, file_stat.m_filename);
|
||||||
|
|
||||||
if (file_stat.m_is_directory) {
|
if (file_stat.m_is_directory) {
|
||||||
|
|
@ -171,6 +191,8 @@ void pxl8_cart_unload(pxl8_cart* cart) {
|
||||||
system(cmd);
|
system(cmd);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
char* cart_name = cart->name ? strdup(cart->name) : NULL;
|
||||||
|
|
||||||
if (cart->base_path) {
|
if (cart->base_path) {
|
||||||
free(cart->base_path);
|
free(cart->base_path);
|
||||||
cart->base_path = NULL;
|
cart->base_path = NULL;
|
||||||
|
|
@ -189,26 +211,31 @@ void pxl8_cart_unload(pxl8_cart* cart) {
|
||||||
cart->archive_size = 0;
|
cart->archive_size = 0;
|
||||||
cart->is_folder = false;
|
cart->is_folder = false;
|
||||||
cart->is_mounted = false;
|
cart->is_mounted = false;
|
||||||
|
|
||||||
|
if (cart_name) {
|
||||||
|
pxl8_info("Unloaded cart: %s", cart_name);
|
||||||
|
free(cart_name);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pxl8_result pxl8_cart_mount(pxl8_cart* cart) {
|
pxl8_result pxl8_cart_mount(pxl8_cart* cart) {
|
||||||
if (!cart || !cart->base_path) return PXL8_ERROR_NULL_POINTER;
|
if (!cart || !cart->base_path) return PXL8_ERROR_NULL_POINTER;
|
||||||
if (cart->is_mounted) return PXL8_OK;
|
if (cart->is_mounted) return PXL8_OK;
|
||||||
|
|
||||||
if (s_current_cart) {
|
if (__pxl8_current_cart) {
|
||||||
pxl8_cart_unmount(s_current_cart);
|
pxl8_cart_unmount(__pxl8_current_cart);
|
||||||
}
|
}
|
||||||
|
|
||||||
s_original_cwd = getcwd(NULL, 0);
|
__pxl8_original_cwd = getcwd(NULL, 0);
|
||||||
if (chdir(cart->base_path) != 0) {
|
if (chdir(cart->base_path) != 0) {
|
||||||
pxl8_error("Failed to change to cart directory: %s", cart->base_path);
|
pxl8_error("Failed to change to cart directory: %s", cart->base_path);
|
||||||
free(s_original_cwd);
|
free(__pxl8_original_cwd);
|
||||||
s_original_cwd = NULL;
|
__pxl8_original_cwd = NULL;
|
||||||
return PXL8_ERROR_FILE_NOT_FOUND;
|
return PXL8_ERROR_FILE_NOT_FOUND;
|
||||||
}
|
}
|
||||||
|
|
||||||
cart->is_mounted = true;
|
cart->is_mounted = true;
|
||||||
s_current_cart = cart;
|
__pxl8_current_cart = cart;
|
||||||
|
|
||||||
pxl8_info("Mounted cart: %s", cart->name);
|
pxl8_info("Mounted cart: %s", cart->name);
|
||||||
return PXL8_OK;
|
return PXL8_OK;
|
||||||
|
|
@ -217,15 +244,15 @@ pxl8_result pxl8_cart_mount(pxl8_cart* cart) {
|
||||||
void pxl8_cart_unmount(pxl8_cart* cart) {
|
void pxl8_cart_unmount(pxl8_cart* cart) {
|
||||||
if (!cart || !cart->is_mounted) return;
|
if (!cart || !cart->is_mounted) return;
|
||||||
|
|
||||||
if (s_original_cwd) {
|
if (__pxl8_original_cwd) {
|
||||||
chdir(s_original_cwd);
|
chdir(__pxl8_original_cwd);
|
||||||
free(s_original_cwd);
|
free(__pxl8_original_cwd);
|
||||||
s_original_cwd = NULL;
|
__pxl8_original_cwd = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
cart->is_mounted = false;
|
cart->is_mounted = false;
|
||||||
if (s_current_cart == cart) {
|
if (__pxl8_current_cart == cart) {
|
||||||
s_current_cart = NULL;
|
__pxl8_current_cart = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
pxl8_info("Unmounted cart: %s", cart->name);
|
pxl8_info("Unmounted cart: %s", cart->name);
|
||||||
|
|
@ -252,37 +279,6 @@ bool pxl8_cart_file_exists(const pxl8_cart* cart, const char* path) {
|
||||||
return exists;
|
return exists;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void pxl8_add_files_recursive(mz_zip_archive* zip, const char* dir_path, const char* prefix) {
|
|
||||||
DIR* dir = opendir(dir_path);
|
|
||||||
if (!dir) return;
|
|
||||||
|
|
||||||
struct dirent* entry;
|
|
||||||
while ((entry = readdir(dir)) != NULL) {
|
|
||||||
if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) continue;
|
|
||||||
|
|
||||||
char full_path[512];
|
|
||||||
char zip_path[512];
|
|
||||||
snprintf(full_path, sizeof(full_path), "%s/%s", dir_path, entry->d_name);
|
|
||||||
snprintf(zip_path, sizeof(zip_path), "%s%s", prefix, entry->d_name);
|
|
||||||
|
|
||||||
struct stat st;
|
|
||||||
if (stat(full_path, &st) == 0) {
|
|
||||||
if (S_ISDIR(st.st_mode)) {
|
|
||||||
char new_prefix[512];
|
|
||||||
snprintf(new_prefix, sizeof(new_prefix), "%s/", zip_path);
|
|
||||||
pxl8_add_files_recursive(zip, full_path, new_prefix);
|
|
||||||
} else {
|
|
||||||
pxl8_info("Adding: %s", zip_path);
|
|
||||||
if (!mz_zip_writer_add_file(zip, zip_path, full_path, NULL, 0, MZ_BEST_COMPRESSION)) {
|
|
||||||
pxl8_warn("Failed to add file: %s", zip_path);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
closedir(dir);
|
|
||||||
}
|
|
||||||
|
|
||||||
pxl8_result pxl8_cart_pack(const char* folder_path, const char* output_path) {
|
pxl8_result pxl8_cart_pack(const char* folder_path, const char* output_path) {
|
||||||
if (!folder_path || !output_path) return PXL8_ERROR_NULL_POINTER;
|
if (!folder_path || !output_path) return PXL8_ERROR_NULL_POINTER;
|
||||||
|
|
||||||
|
|
@ -308,7 +304,7 @@ pxl8_result pxl8_cart_pack(const char* folder_path, const char* output_path) {
|
||||||
}
|
}
|
||||||
|
|
||||||
pxl8_info("Packing cart: %s -> %s", folder_path, output_path);
|
pxl8_info("Packing cart: %s -> %s", folder_path, output_path);
|
||||||
pxl8_add_files_recursive(&zip, folder_path, "");
|
pxl8_add_file_recursive(&zip, folder_path, "");
|
||||||
|
|
||||||
if (!mz_zip_writer_finalize_archive(&zip)) {
|
if (!mz_zip_writer_finalize_archive(&zip)) {
|
||||||
pxl8_error("Failed to finalize archive");
|
pxl8_error("Failed to finalize archive");
|
||||||
|
|
@ -320,7 +316,3 @@ pxl8_result pxl8_cart_pack(const char* folder_path, const char* output_path) {
|
||||||
pxl8_info("Cart packed successfully!");
|
pxl8_info("Cart packed successfully!");
|
||||||
return PXL8_OK;
|
return PXL8_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
pxl8_cart* pxl8_cart_current(void) {
|
|
||||||
return s_current_cart;
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -3,33 +3,26 @@
|
||||||
#include "pxl8_types.h"
|
#include "pxl8_types.h"
|
||||||
|
|
||||||
typedef struct pxl8_cart {
|
typedef struct pxl8_cart {
|
||||||
char* base_path;
|
|
||||||
char* name;
|
|
||||||
void* archive_data;
|
void* archive_data;
|
||||||
size_t archive_size;
|
size_t archive_size;
|
||||||
|
char* base_path;
|
||||||
bool is_folder;
|
bool is_folder;
|
||||||
bool is_mounted;
|
bool is_mounted;
|
||||||
|
char* name;
|
||||||
} pxl8_cart;
|
} pxl8_cart;
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
pxl8_result pxl8_cart_load(pxl8_cart* cart, const char* path);
|
|
||||||
void pxl8_cart_unload(pxl8_cart* cart);
|
|
||||||
|
|
||||||
pxl8_result pxl8_cart_mount(pxl8_cart* cart);
|
|
||||||
void pxl8_cart_unmount(pxl8_cart* cart);
|
|
||||||
|
|
||||||
char* pxl8_cart_resolve_path(const pxl8_cart* cart, const char* relative_path);
|
|
||||||
bool pxl8_cart_file_exists(const pxl8_cart* cart, const char* path);
|
|
||||||
|
|
||||||
pxl8_cart* pxl8_cart_new(void);
|
|
||||||
void pxl8_cart_destroy(pxl8_cart* cart);
|
|
||||||
|
|
||||||
pxl8_result pxl8_cart_pack(const char* folder_path, const char* output_path);
|
|
||||||
|
|
||||||
pxl8_cart* pxl8_cart_current(void);
|
pxl8_cart* pxl8_cart_current(void);
|
||||||
|
bool pxl8_cart_file_exists(const pxl8_cart* cart, const char* path);
|
||||||
|
pxl8_result pxl8_cart_load(pxl8_cart* cart, const char* path);
|
||||||
|
pxl8_result pxl8_cart_mount(pxl8_cart* cart);
|
||||||
|
pxl8_result pxl8_cart_pack(const char* folder_path, const char* output_path);
|
||||||
|
char* pxl8_cart_resolve_path(const pxl8_cart* cart, const char* relative_path);
|
||||||
|
void pxl8_cart_unload(pxl8_cart* cart);
|
||||||
|
void pxl8_cart_unmount(pxl8_cart* cart);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,18 +2,6 @@
|
||||||
#include <SDL3/SDL.h>
|
#include <SDL3/SDL.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
const pxl8_glyph* pxl8_font_find_glyph(const pxl8_font* font, u32 codepoint) {
|
|
||||||
if (!font || !font->glyphs) return NULL;
|
|
||||||
|
|
||||||
for (u32 i = 0; i < font->glyph_count; i++) {
|
|
||||||
if (font->glyphs[i].codepoint == codepoint) {
|
|
||||||
return &font->glyphs[i];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
pxl8_result pxl8_font_create_atlas(const pxl8_font* font, u8** atlas_data, i32* atlas_width, i32* atlas_height) {
|
pxl8_result pxl8_font_create_atlas(const pxl8_font* font, u8** atlas_data, i32* atlas_width, i32* atlas_height) {
|
||||||
if (!font || !atlas_data || !atlas_width || !atlas_height) {
|
if (!font || !atlas_data || !atlas_width || !atlas_height) {
|
||||||
return PXL8_ERROR_NULL_POINTER;
|
return PXL8_ERROR_NULL_POINTER;
|
||||||
|
|
@ -58,3 +46,15 @@ pxl8_result pxl8_font_create_atlas(const pxl8_font* font, u8** atlas_data, i32*
|
||||||
|
|
||||||
return PXL8_OK;
|
return PXL8_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const pxl8_glyph* pxl8_font_find_glyph(const pxl8_font* font, u32 codepoint) {
|
||||||
|
if (!font || !font->glyphs) return NULL;
|
||||||
|
|
||||||
|
for (u32 i = 0; i < font->glyph_count; i++) {
|
||||||
|
if (font->glyphs[i].codepoint == codepoint) {
|
||||||
|
return &font->glyphs[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -122,8 +122,8 @@ static const pxl8_font pxl8_default_font = {
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
const pxl8_glyph* pxl8_font_find_glyph(const pxl8_font* font, u32 codepoint);
|
|
||||||
pxl8_result pxl8_font_create_atlas(const pxl8_font* font, u8** atlas_data, i32* atlas_width, i32* atlas_height);
|
pxl8_result pxl8_font_create_atlas(const pxl8_font* font, u8** atlas_data, i32* atlas_width, i32* atlas_height);
|
||||||
|
const pxl8_glyph* pxl8_font_find_glyph(const pxl8_font* font, u32 codepoint);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -153,6 +153,7 @@ void pxl8_gfx_shutdown(pxl8_gfx_ctx* ctx) {
|
||||||
ctx->initialized = false;
|
ctx->initialized = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// resource loading
|
||||||
pxl8_result pxl8_gfx_init_atlas(pxl8_gfx_ctx* ctx, u32 width, u32 height) {
|
pxl8_result pxl8_gfx_init_atlas(pxl8_gfx_ctx* ctx, u32 width, u32 height) {
|
||||||
if (!ctx || !ctx->initialized) return PXL8_ERROR_INVALID_ARGUMENT;
|
if (!ctx || !ctx->initialized) return PXL8_ERROR_INVALID_ARGUMENT;
|
||||||
|
|
||||||
|
|
@ -328,6 +329,7 @@ pxl8_result pxl8_gfx_load_font_atlas(pxl8_gfx_ctx* ctx) {
|
||||||
return PXL8_OK;
|
return PXL8_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// rendering pipeline
|
||||||
void pxl8_gfx_upload_framebuffer(pxl8_gfx_ctx* ctx) {
|
void pxl8_gfx_upload_framebuffer(pxl8_gfx_ctx* ctx) {
|
||||||
if (!ctx || !ctx->initialized || !ctx->framebuffer_texture) return;
|
if (!ctx || !ctx->initialized || !ctx->framebuffer_texture) return;
|
||||||
|
|
||||||
|
|
@ -405,6 +407,7 @@ void pxl8_gfx_project(pxl8_gfx_ctx* ctx, f32 left, f32 right, f32 top, f32 botto
|
||||||
(void)ctx; (void)left; (void)right; (void)top; (void)bottom;
|
(void)ctx; (void)left; (void)right; (void)top; (void)bottom;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// drawing primitives
|
||||||
void pxl8_clr(pxl8_gfx_ctx* ctx, u32 color) {
|
void pxl8_clr(pxl8_gfx_ctx* ctx, u32 color) {
|
||||||
if (!ctx || !ctx->framebuffer) return;
|
if (!ctx || !ctx->framebuffer) return;
|
||||||
|
|
||||||
|
|
@ -590,6 +593,7 @@ void pxl8_sprite(pxl8_gfx_ctx* ctx, u32 sprite_id, i32 x, i32 y, i32 w, i32 h) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// palette effects
|
||||||
void pxl8_gfx_cycle_palette(pxl8_gfx_ctx* ctx, u8 start, u8 count, i32 step) {
|
void pxl8_gfx_cycle_palette(pxl8_gfx_ctx* ctx, u8 start, u8 count, i32 step) {
|
||||||
if (!ctx || !ctx->palette || count == 0) return;
|
if (!ctx || !ctx->palette || count == 0) return;
|
||||||
|
|
||||||
|
|
|
||||||
114
src/pxl8_gfx.h
114
src/pxl8_gfx.h
|
|
@ -17,32 +17,30 @@ typedef struct pxl8_gfx_ctx {
|
||||||
SDL_Texture* framebuffer_texture;
|
SDL_Texture* framebuffer_texture;
|
||||||
SDL_Texture* sprite_atlas_texture;
|
SDL_Texture* sprite_atlas_texture;
|
||||||
SDL_Window* window;
|
SDL_Window* window;
|
||||||
|
|
||||||
u8* framebuffer;
|
u8* framebuffer;
|
||||||
|
bool initialized;
|
||||||
u32* palette;
|
u32* palette;
|
||||||
u32 palette_size;
|
u32 palette_size;
|
||||||
|
|
||||||
i32 framebuffer_width;
|
i32 framebuffer_width;
|
||||||
i32 framebuffer_height;
|
i32 framebuffer_height;
|
||||||
pxl8_color_mode color_mode;
|
pxl8_color_mode color_mode;
|
||||||
|
|
||||||
|
u8* atlas;
|
||||||
|
bool atlas_dirty;
|
||||||
|
pxl8_atlas_entry* atlas_entries;
|
||||||
|
u32 atlas_entries_len;
|
||||||
|
u32 atlas_entries_cap;
|
||||||
|
|
||||||
u32 sprite_atlas_width;
|
u32 sprite_atlas_width;
|
||||||
u32 sprite_atlas_height;
|
u32 sprite_atlas_height;
|
||||||
u32 sprite_frame_width;
|
u32 sprite_frame_width;
|
||||||
u32 sprite_frame_height;
|
u32 sprite_frame_height;
|
||||||
u32 sprite_frames_per_row;
|
u32 sprite_frames_per_row;
|
||||||
|
|
||||||
pxl8_atlas_entry* atlas_entries;
|
|
||||||
u32 atlas_entries_len;
|
|
||||||
u32 atlas_entries_cap;
|
|
||||||
|
|
||||||
u8* atlas;
|
|
||||||
bool atlas_dirty;
|
|
||||||
|
|
||||||
i32 viewport_x, viewport_y;
|
i32 viewport_x, viewport_y;
|
||||||
i32 viewport_width, viewport_height;
|
i32 viewport_width, viewport_height;
|
||||||
|
|
||||||
bool initialized;
|
|
||||||
} pxl8_gfx_ctx;
|
} pxl8_gfx_ctx;
|
||||||
|
|
||||||
typedef enum pxl8_blend_mode {
|
typedef enum pxl8_blend_mode {
|
||||||
|
|
@ -52,6 +50,14 @@ typedef enum pxl8_blend_mode {
|
||||||
PXL8_BLEND_MULTIPLY
|
PXL8_BLEND_MULTIPLY
|
||||||
} pxl8_blend_mode;
|
} pxl8_blend_mode;
|
||||||
|
|
||||||
|
typedef struct pxl8_mode7_params {
|
||||||
|
f32 horizon;
|
||||||
|
f32 scale_x, scale_y;
|
||||||
|
f32 rotation;
|
||||||
|
f32 offset_x, offset_y;
|
||||||
|
bool active;
|
||||||
|
} pxl8_mode7_params;
|
||||||
|
|
||||||
typedef struct pxl8_palette_cycle {
|
typedef struct pxl8_palette_cycle {
|
||||||
u8 start_index;
|
u8 start_index;
|
||||||
u8 end_index;
|
u8 end_index;
|
||||||
|
|
@ -65,21 +71,17 @@ typedef struct pxl8_scanline_effect {
|
||||||
bool active;
|
bool active;
|
||||||
} pxl8_scanline_effect;
|
} pxl8_scanline_effect;
|
||||||
|
|
||||||
typedef struct pxl8_mode7_params {
|
|
||||||
f32 horizon;
|
|
||||||
f32 scale_x, scale_y;
|
|
||||||
f32 rotation;
|
|
||||||
f32 offset_x, offset_y;
|
|
||||||
bool active;
|
|
||||||
} pxl8_mode7_params;
|
|
||||||
|
|
||||||
typedef struct pxl8_effects {
|
typedef struct pxl8_effects {
|
||||||
pxl8_palette_cycle palette_cycles[8];
|
pxl8_palette_cycle palette_cycles[8];
|
||||||
pxl8_scanline_effect scanline_effects[4];
|
pxl8_scanline_effect scanline_effects[4];
|
||||||
|
|
||||||
f32 time;
|
f32 time;
|
||||||
} pxl8_effects;
|
} pxl8_effects;
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void pxl8_gfx_get_resolution_dimensions(pxl8_resolution resolution, i32* width, i32* height);
|
||||||
pxl8_result pxl8_gfx_init(
|
pxl8_result pxl8_gfx_init(
|
||||||
pxl8_gfx_ctx* ctx,
|
pxl8_gfx_ctx* ctx,
|
||||||
pxl8_color_mode mode,
|
pxl8_color_mode mode,
|
||||||
|
|
@ -88,36 +90,54 @@ pxl8_result pxl8_gfx_init(
|
||||||
i32 window_width,
|
i32 window_width,
|
||||||
i32 window_height
|
i32 window_height
|
||||||
);
|
);
|
||||||
|
|
||||||
void pxl8_gfx_shutdown(pxl8_gfx_ctx* ctx);
|
|
||||||
|
|
||||||
pxl8_result pxl8_gfx_init_atlas(pxl8_gfx_ctx* ctx, u32 width, u32 height);
|
pxl8_result pxl8_gfx_init_atlas(pxl8_gfx_ctx* ctx, u32 width, u32 height);
|
||||||
pxl8_result pxl8_gfx_load_sprite(pxl8_gfx_ctx* ctx, const char* path);
|
|
||||||
pxl8_result pxl8_gfx_load_palette(pxl8_gfx_ctx* ctx, const char* path);
|
|
||||||
pxl8_result pxl8_gfx_load_font_atlas(pxl8_gfx_ctx* ctx);
|
pxl8_result pxl8_gfx_load_font_atlas(pxl8_gfx_ctx* ctx);
|
||||||
|
pxl8_result pxl8_gfx_load_palette(pxl8_gfx_ctx* ctx, const char* path);
|
||||||
void pxl8_gfx_get_resolution_dimensions(pxl8_resolution resolution, i32* width, i32* height);
|
pxl8_result pxl8_gfx_load_sprite(pxl8_gfx_ctx* ctx, const char* path);
|
||||||
void pxl8_gfx_upload_framebuffer(pxl8_gfx_ctx* ctx);
|
|
||||||
void pxl8_gfx_upload_atlas(pxl8_gfx_ctx* ctx);
|
|
||||||
void pxl8_gfx_present(pxl8_gfx_ctx* ctx);
|
void pxl8_gfx_present(pxl8_gfx_ctx* ctx);
|
||||||
|
|
||||||
void pxl8_gfx_viewport(pxl8_gfx_ctx* ctx, i32 x, i32 y, i32 width, i32 height);
|
|
||||||
void pxl8_gfx_project(pxl8_gfx_ctx* ctx, f32 left, f32 right, f32 top, f32 bottom);
|
void pxl8_gfx_project(pxl8_gfx_ctx* ctx, f32 left, f32 right, f32 top, f32 bottom);
|
||||||
|
void pxl8_gfx_shutdown(pxl8_gfx_ctx* ctx);
|
||||||
|
void pxl8_gfx_upload_atlas(pxl8_gfx_ctx* ctx);
|
||||||
|
void pxl8_gfx_upload_framebuffer(pxl8_gfx_ctx* ctx);
|
||||||
|
void pxl8_gfx_viewport(pxl8_gfx_ctx* ctx, i32 x, i32 y, i32 width, i32 height);
|
||||||
|
|
||||||
void pxl8_clr(pxl8_gfx_ctx* ctx, u32 color);
|
void pxl8_gfx_color_ramp(
|
||||||
void pxl8_pixel(pxl8_gfx_ctx* ctx, i32 x, i32 y, u32 color);
|
pxl8_gfx_ctx* ctx,
|
||||||
u32 pxl8_get_pixel(pxl8_gfx_ctx* ctx, i32 x, i32 y);
|
u8 start,
|
||||||
void pxl8_line(pxl8_gfx_ctx* ctx, i32 x0, i32 y0, i32 x1, i32 y1, u32 color);
|
u8 count,
|
||||||
void pxl8_rect(pxl8_gfx_ctx* ctx, i32 x, i32 y, i32 w, i32 h, u32 color);
|
u32 from_color,
|
||||||
void pxl8_rect_fill(pxl8_gfx_ctx* ctx, i32 x, i32 y, i32 w, i32 h, u32 color);
|
u32 to_color
|
||||||
void pxl8_circle(pxl8_gfx_ctx* ctx, i32 cx, i32 cy, i32 radius, u32 color);
|
);
|
||||||
void pxl8_circle_fill(pxl8_gfx_ctx* ctx, i32 cx, i32 cy, i32 radius, u32 color);
|
|
||||||
void pxl8_text(pxl8_gfx_ctx* ctx, const char* text, i32 x, i32 y, u32 color);
|
|
||||||
void pxl8_sprite(pxl8_gfx_ctx* ctx, u32 sprite_id, i32 x, i32 y, i32 w, i32 h);
|
|
||||||
|
|
||||||
void pxl8_gfx_color_ramp(pxl8_gfx_ctx* ctx, u8 start, u8 count, u32 from_color, u32 to_color);
|
|
||||||
void pxl8_gfx_cycle_palette(pxl8_gfx_ctx* ctx, u8 start, u8 count, i32 step);
|
void pxl8_gfx_cycle_palette(pxl8_gfx_ctx* ctx, u8 start, u8 count, i32 step);
|
||||||
void pxl8_gfx_fade_palette(pxl8_gfx_ctx* ctx, u8 start, u8 count, f32 amount, u32 target_color);
|
void pxl8_gfx_fade_palette(
|
||||||
void pxl8_gfx_interpolate_palettes(pxl8_gfx_ctx* ctx, u32* palette1, u32* palette2, u8 start, u8 count, f32 t);
|
pxl8_gfx_ctx* ctx,
|
||||||
|
u8 start,
|
||||||
|
u8 count,
|
||||||
|
f32 amount,
|
||||||
|
u32 target_color
|
||||||
|
);
|
||||||
|
void pxl8_gfx_interpolate_palettes(
|
||||||
|
pxl8_gfx_ctx* ctx,
|
||||||
|
u32* palette1,
|
||||||
|
u32* palette2,
|
||||||
|
u8 start,
|
||||||
|
u8 count,
|
||||||
|
f32 t
|
||||||
|
);
|
||||||
void pxl8_gfx_process_effects(pxl8_gfx_ctx* ctx, pxl8_effects* effects, f32 dt);
|
void pxl8_gfx_process_effects(pxl8_gfx_ctx* ctx, pxl8_effects* effects, f32 dt);
|
||||||
void pxl8_gfx_swap_palette(pxl8_gfx_ctx* ctx, u8 start, u8 count, u32* new_colors);
|
void pxl8_gfx_swap_palette(pxl8_gfx_ctx* ctx, u8 start, u8 count, u32* new_colors);
|
||||||
|
|
||||||
|
void pxl8_circle(pxl8_gfx_ctx* ctx, i32 cx, i32 cy, i32 radius, u32 color);
|
||||||
|
void pxl8_circle_fill(pxl8_gfx_ctx* ctx, i32 cx, i32 cy, i32 radius, u32 color);
|
||||||
|
void pxl8_clr(pxl8_gfx_ctx* ctx, u32 color);
|
||||||
|
u32 pxl8_get_pixel(pxl8_gfx_ctx* ctx, i32 x, i32 y);
|
||||||
|
void pxl8_line(pxl8_gfx_ctx* ctx, i32 x0, i32 y0, i32 x1, i32 y1, u32 color);
|
||||||
|
void pxl8_pixel(pxl8_gfx_ctx* ctx, i32 x, i32 y, u32 color);
|
||||||
|
void pxl8_rect(pxl8_gfx_ctx* ctx, i32 x, i32 y, i32 w, i32 h, u32 color);
|
||||||
|
void pxl8_rect_fill(pxl8_gfx_ctx* ctx, i32 x, i32 y, i32 w, i32 h, u32 color);
|
||||||
|
void pxl8_sprite(pxl8_gfx_ctx* ctx, u32 sprite_id, i32 x, i32 y, i32 w, i32 h);
|
||||||
|
void pxl8_text(pxl8_gfx_ctx* ctx, const char* text, i32 x, i32 y, u32 color);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -11,17 +11,15 @@
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
pxl8_result pxl8_io_read_file(const char* path, char** content, size_t* size);
|
|
||||||
pxl8_result pxl8_io_write_file(const char* path, const char* content, size_t size);
|
|
||||||
pxl8_result pxl8_io_read_binary_file(const char* path, u8** data, size_t* size);
|
|
||||||
pxl8_result pxl8_io_write_binary_file(const char* path, const u8* data, size_t size);
|
|
||||||
|
|
||||||
bool pxl8_io_file_exists(const char* path);
|
|
||||||
f64 pxl8_io_get_file_modified_time(const char* path);
|
|
||||||
pxl8_result pxl8_io_create_directory(const char* path);
|
pxl8_result pxl8_io_create_directory(const char* path);
|
||||||
|
bool pxl8_io_file_exists(const char* path);
|
||||||
void pxl8_io_free_file_content(char* content);
|
|
||||||
void pxl8_io_free_binary_data(u8* data);
|
void pxl8_io_free_binary_data(u8* data);
|
||||||
|
void pxl8_io_free_file_content(char* content);
|
||||||
|
f64 pxl8_io_get_file_modified_time(const char* path);
|
||||||
|
pxl8_result pxl8_io_read_binary_file(const char* path, u8** data, size_t* size);
|
||||||
|
pxl8_result pxl8_io_read_file(const char* path, char** content, size_t* size);
|
||||||
|
pxl8_result pxl8_io_write_binary_file(const char* path, const u8* data, size_t size);
|
||||||
|
pxl8_result pxl8_io_write_file(const char* path, const char* content, size_t size);
|
||||||
|
|
||||||
bool pxl8_key_down(const pxl8_input_state* input, i32 key);
|
bool pxl8_key_down(const pxl8_input_state* input, i32 key);
|
||||||
bool pxl8_key_pressed(const pxl8_input_state* input, i32 key);
|
bool pxl8_key_pressed(const pxl8_input_state* input, i32 key);
|
||||||
|
|
|
||||||
|
|
@ -104,9 +104,9 @@ static const char* pxl8_ffi_cdefs =
|
||||||
" float phase;\n"
|
" float phase;\n"
|
||||||
" unsigned int color;\n"
|
" unsigned int color;\n"
|
||||||
" unsigned int fade_color;\n"
|
" unsigned int fade_color;\n"
|
||||||
"} pxl8_copper_bar;\n"
|
"} pxl8_raster_bar;\n"
|
||||||
"\n"
|
"\n"
|
||||||
"void pxl8_vfx_copper_bars(pxl8_gfx_ctx* ctx, pxl8_copper_bar* bars, u32 bar_count, f32 time);\n"
|
"void pxl8_vfx_raster_bars(pxl8_gfx_ctx* ctx, pxl8_raster_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_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_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_tunnel(pxl8_gfx_ctx* ctx, f32 time, f32 speed, f32 twist);\n"
|
||||||
|
|
@ -327,4 +327,3 @@ pxl8_result pxl8_lua_eval_fennel(lua_State* lua_state, const char* code) {
|
||||||
lua_remove(lua_state, -2);
|
lua_remove(lua_state, -2);
|
||||||
return PXL8_OK;
|
return PXL8_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -13,12 +13,13 @@ extern "C" {
|
||||||
|
|
||||||
pxl8_result pxl8_lua_init(lua_State** lua_state);
|
pxl8_result pxl8_lua_init(lua_State** lua_state);
|
||||||
void pxl8_lua_shutdown(lua_State* lua_state);
|
void pxl8_lua_shutdown(lua_State* lua_state);
|
||||||
|
pxl8_result pxl8_lua_setup_contexts(lua_State* lua_state, pxl8_gfx_ctx* gfx_ctx, pxl8_input_state* input);
|
||||||
|
void pxl8_lua_setup_cart_path(lua_State* lua_state, const char* cart_path, const char* original_cwd);
|
||||||
|
|
||||||
pxl8_result pxl8_lua_eval_fennel(lua_State* lua_state, const char* code);
|
pxl8_result pxl8_lua_eval_fennel(lua_State* lua_state, const char* code);
|
||||||
pxl8_result pxl8_lua_run_fennel_file(lua_State* lua_state, const char* filename);
|
pxl8_result pxl8_lua_run_fennel_file(lua_State* lua_state, const char* filename);
|
||||||
pxl8_result pxl8_lua_run_file(lua_State* lua_state, const char* filename);
|
pxl8_result pxl8_lua_run_file(lua_State* lua_state, const char* filename);
|
||||||
pxl8_result pxl8_lua_run_string(lua_State* lua_state, const char* code);
|
pxl8_result pxl8_lua_run_string(lua_State* lua_state, const char* code);
|
||||||
pxl8_result pxl8_lua_setup_contexts(lua_State* lua_state, pxl8_gfx_ctx* gfx_ctx, pxl8_input_state* input);
|
|
||||||
void pxl8_lua_setup_cart_path(lua_State* lua_state, const char* cart_path, const char* original_cwd);
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -192,8 +192,8 @@ void pxl8_tilemap_render_layer(const pxl8_tilemap* tilemap, pxl8_gfx_ctx* gfx, u
|
||||||
|
|
||||||
u32 chunk_left = pxl8_max(0, view_left >> 4);
|
u32 chunk_left = pxl8_max(0, view_left >> 4);
|
||||||
u32 chunk_top = pxl8_max(0, view_top >> 4);
|
u32 chunk_top = pxl8_max(0, view_top >> 4);
|
||||||
u32 chunk_right = pxl8_min((tilemap->width + 15) >> 4, (view_right >> 4) + 1);
|
u32 chunk_right = pxl8_min((tilemap->width + 15) >> 4, (u32)((view_right >> 4) + 1));
|
||||||
u32 chunk_bottom = pxl8_min((tilemap->height + 15) >> 4, (view_bottom >> 4) + 1);
|
u32 chunk_bottom = pxl8_min((tilemap->height + 15) >> 4, (u32)((view_bottom >> 4) + 1));
|
||||||
|
|
||||||
for (u32 cy = chunk_top; cy < chunk_bottom; cy++) {
|
for (u32 cy = chunk_top; cy < chunk_bottom; cy++) {
|
||||||
for (u32 cx = chunk_left; cx < chunk_right; cx++) {
|
for (u32 cx = chunk_left; cx < chunk_right; cx++) {
|
||||||
|
|
@ -277,29 +277,6 @@ bool pxl8_tilemap_check_collision(const pxl8_tilemap* tilemap, i32 x, i32 y, i32
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
pxl8_tilemap* pxl8_tilemap_new(u32 width, u32 height, u32 tile_size) {
|
|
||||||
pxl8_tilemap* tilemap = calloc(1, sizeof(pxl8_tilemap));
|
|
||||||
if (!tilemap) {
|
|
||||||
pxl8_error("Failed to allocate tilemap");
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
pxl8_result result = pxl8_tilemap_init(tilemap, width, height, tile_size);
|
|
||||||
if (result != PXL8_OK) {
|
|
||||||
pxl8_error("Failed to initialize tilemap");
|
|
||||||
free(tilemap);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
return tilemap;
|
|
||||||
}
|
|
||||||
|
|
||||||
void pxl8_tilemap_destroy(pxl8_tilemap* tilemap) {
|
|
||||||
if (!tilemap) return;
|
|
||||||
pxl8_tilemap_free(tilemap);
|
|
||||||
free(tilemap);
|
|
||||||
}
|
|
||||||
|
|
||||||
u16 pxl8_tilemap_get_tile_id(const pxl8_tilemap* tilemap, u32 layer, u32 x, u32 y) {
|
u16 pxl8_tilemap_get_tile_id(const pxl8_tilemap* tilemap, u32 layer, u32 x, u32 y) {
|
||||||
if (!tilemap) return 0;
|
if (!tilemap) return 0;
|
||||||
pxl8_tile tile = pxl8_tilemap_get_tile(tilemap, layer, x, y);
|
pxl8_tile tile = pxl8_tilemap_get_tile(tilemap, layer, x, y);
|
||||||
|
|
|
||||||
|
|
@ -108,35 +108,56 @@ typedef struct pxl8_tilemap_view {
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
pxl8_result pxl8_tilemap_init(pxl8_tilemap* tilemap, u32 width, u32 height, u32 tile_size);
|
bool pxl8_tilemap_check_collision(const pxl8_tilemap* tilemap, i32 x, i32 y, i32 w, i32 h);
|
||||||
pxl8_result pxl8_tilemap_set_tilesheet(pxl8_tilemap* tilemap, pxl8_tilesheet* tilesheet);
|
void pxl8_tilemap_compress(pxl8_tilemap* tilemap);
|
||||||
void pxl8_tilemap_free(pxl8_tilemap* tilemap);
|
void pxl8_tilemap_free(pxl8_tilemap* tilemap);
|
||||||
|
u32 pxl8_tilemap_get_memory_usage(const pxl8_tilemap* tilemap);
|
||||||
pxl8_result pxl8_tilemap_set_tile(pxl8_tilemap* tilemap, u32 layer, u32 x, u32 y, u16 tile_id, u8 flags);
|
|
||||||
pxl8_tile pxl8_tilemap_get_tile(const pxl8_tilemap* tilemap, u32 layer, u32 x, u32 y);
|
pxl8_tile pxl8_tilemap_get_tile(const pxl8_tilemap* tilemap, u32 layer, u32 x, u32 y);
|
||||||
|
u16 pxl8_tilemap_get_tile_id(const pxl8_tilemap* tilemap, u32 layer, u32 x, u32 y);
|
||||||
void pxl8_tilemap_set_camera(pxl8_tilemap* tilemap, i32 x, i32 y);
|
void pxl8_tilemap_get_view(
|
||||||
void pxl8_tilemap_get_view(const pxl8_tilemap* tilemap, const pxl8_gfx_ctx* gfx, pxl8_tilemap_view* view);
|
const pxl8_tilemap* tilemap,
|
||||||
|
const pxl8_gfx_ctx* gfx,
|
||||||
|
pxl8_tilemap_view* view
|
||||||
|
);
|
||||||
|
pxl8_result pxl8_tilemap_init(pxl8_tilemap* tilemap, u32 width, u32 height, u32 tile_size);
|
||||||
|
bool pxl8_tilemap_is_solid(const pxl8_tilemap* tilemap, u32 x, u32 y);
|
||||||
void pxl8_tilemap_render(const pxl8_tilemap* tilemap, pxl8_gfx_ctx* gfx);
|
void pxl8_tilemap_render(const pxl8_tilemap* tilemap, pxl8_gfx_ctx* gfx);
|
||||||
void pxl8_tilemap_render_layer(const pxl8_tilemap* tilemap, pxl8_gfx_ctx* gfx, u32 layer);
|
void pxl8_tilemap_render_layer(const pxl8_tilemap* tilemap, pxl8_gfx_ctx* gfx, u32 layer);
|
||||||
void pxl8_tilemap_render_tile(const pxl8_tilemap* tilemap, pxl8_gfx_ctx* gfx, u16 tile_id, i32 x, i32 y, u8 flags);
|
void pxl8_tilemap_render_tile(
|
||||||
|
const pxl8_tilemap* tilemap,
|
||||||
bool pxl8_tilemap_is_solid(const pxl8_tilemap* tilemap, u32 x, u32 y);
|
pxl8_gfx_ctx* gfx,
|
||||||
bool pxl8_tilemap_check_collision(const pxl8_tilemap* tilemap, i32 x, i32 y, i32 w, i32 h);
|
u16 tile_id,
|
||||||
|
i32 x,
|
||||||
pxl8_tilemap* pxl8_tilemap_new(u32 width, u32 height, u32 tile_size);
|
i32 y,
|
||||||
void pxl8_tilemap_destroy(pxl8_tilemap* tilemap);
|
u8 flags
|
||||||
u16 pxl8_tilemap_get_tile_id(const pxl8_tilemap* tilemap, u32 layer, u32 x, u32 y);
|
);
|
||||||
|
void pxl8_tilemap_set_camera(pxl8_tilemap* tilemap, i32 x, i32 y);
|
||||||
|
pxl8_result pxl8_tilemap_set_tile(
|
||||||
|
pxl8_tilemap* tilemap,
|
||||||
|
u32 layer,
|
||||||
|
u32 x,
|
||||||
|
u32 y,
|
||||||
|
u16 tile_id,
|
||||||
|
u8 flags
|
||||||
|
);
|
||||||
|
pxl8_result pxl8_tilemap_set_tile_auto(
|
||||||
|
pxl8_tilemap* tilemap,
|
||||||
|
u32 layer,
|
||||||
|
u32 x,
|
||||||
|
u32 y,
|
||||||
|
u16 base_tile_id,
|
||||||
|
u8 flags
|
||||||
|
);
|
||||||
|
pxl8_result pxl8_tilemap_set_tilesheet(pxl8_tilemap* tilemap, pxl8_tilesheet* tilesheet);
|
||||||
void pxl8_tilemap_update(pxl8_tilemap* tilemap, f32 delta_time);
|
void pxl8_tilemap_update(pxl8_tilemap* tilemap, f32 delta_time);
|
||||||
|
void pxl8_tilemap_update_autotiles(
|
||||||
pxl8_result pxl8_tilemap_set_tile_auto(pxl8_tilemap* tilemap, u32 layer, u32 x, u32 y,
|
pxl8_tilemap* tilemap,
|
||||||
u16 base_tile_id, u8 flags);
|
u32 layer,
|
||||||
void pxl8_tilemap_update_autotiles(pxl8_tilemap* tilemap, u32 layer, u32 x, u32 y, u32 w, u32 h);
|
u32 x,
|
||||||
|
u32 y,
|
||||||
u32 pxl8_tilemap_get_memory_usage(const pxl8_tilemap* tilemap);
|
u32 w,
|
||||||
void pxl8_tilemap_compress(pxl8_tilemap* tilemap);
|
u32 h
|
||||||
|
);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,16 +5,6 @@
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
pxl8_result pxl8_tilesheet_init(pxl8_tilesheet* tilesheet, u32 tile_size) {
|
|
||||||
if (!tilesheet) return PXL8_ERROR_NULL_POINTER;
|
|
||||||
|
|
||||||
memset(tilesheet, 0, sizeof(pxl8_tilesheet));
|
|
||||||
tilesheet->tile_size = tile_size ? tile_size : PXL8_TILE_SIZE;
|
|
||||||
tilesheet->ref_count = 1;
|
|
||||||
|
|
||||||
return PXL8_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
void pxl8_tilesheet_free(pxl8_tilesheet* tilesheet) {
|
void pxl8_tilesheet_free(pxl8_tilesheet* tilesheet) {
|
||||||
if (!tilesheet) return;
|
if (!tilesheet) return;
|
||||||
|
|
||||||
|
|
@ -186,28 +176,6 @@ bool pxl8_tilesheet_is_tile_valid(const pxl8_tilesheet* tilesheet, u16 tile_id)
|
||||||
return tilesheet->tile_valid ? tilesheet->tile_valid[tile_id] : true;
|
return tilesheet->tile_valid ? tilesheet->tile_valid[tile_id] : true;
|
||||||
}
|
}
|
||||||
|
|
||||||
pxl8_tilesheet* pxl8_tilesheet_new(u32 tile_size) {
|
|
||||||
pxl8_tilesheet* tilesheet = calloc(1, sizeof(pxl8_tilesheet));
|
|
||||||
if (!tilesheet) {
|
|
||||||
pxl8_error("Failed to allocate tilesheet");
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
pxl8_result result = pxl8_tilesheet_init(tilesheet, tile_size);
|
|
||||||
if (result != PXL8_OK) {
|
|
||||||
pxl8_error("Failed to initialize tilesheet");
|
|
||||||
free(tilesheet);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
return tilesheet;
|
|
||||||
}
|
|
||||||
|
|
||||||
void pxl8_tilesheet_destroy(pxl8_tilesheet* tilesheet) {
|
|
||||||
if (!tilesheet) return;
|
|
||||||
pxl8_tilesheet_unref(tilesheet);
|
|
||||||
}
|
|
||||||
|
|
||||||
void pxl8_tilesheet_ref(pxl8_tilesheet* tilesheet) {
|
void pxl8_tilesheet_ref(pxl8_tilesheet* tilesheet) {
|
||||||
if (!tilesheet) return;
|
if (!tilesheet) return;
|
||||||
tilesheet->ref_count++;
|
tilesheet->ref_count++;
|
||||||
|
|
@ -218,7 +186,6 @@ void pxl8_tilesheet_unref(pxl8_tilesheet* tilesheet) {
|
||||||
|
|
||||||
if (--tilesheet->ref_count == 0) {
|
if (--tilesheet->ref_count == 0) {
|
||||||
pxl8_tilesheet_free(tilesheet);
|
pxl8_tilesheet_free(tilesheet);
|
||||||
free(tilesheet);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -31,33 +31,44 @@ typedef struct pxl8_tilesheet {
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
pxl8_result pxl8_tilesheet_init(pxl8_tilesheet* tilesheet, u32 tile_size);
|
pxl8_result pxl8_tilesheet_add_animation(
|
||||||
pxl8_result pxl8_tilesheet_load(pxl8_tilesheet* tilesheet, const char* filepath, pxl8_gfx_ctx* gfx);
|
pxl8_tilesheet* tilesheet,
|
||||||
void pxl8_tilesheet_free(pxl8_tilesheet* tilesheet);
|
u16 base_tile_id,
|
||||||
|
const u16* frames,
|
||||||
void pxl8_tilesheet_render_tile(const pxl8_tilesheet* tilesheet, pxl8_gfx_ctx* gfx,
|
u16 frame_count,
|
||||||
u16 tile_id, i32 x, i32 y, u8 flags);
|
f32 frame_duration
|
||||||
|
);
|
||||||
bool pxl8_tilesheet_is_tile_valid(const pxl8_tilesheet* tilesheet, u16 tile_id);
|
pxl8_result pxl8_tilesheet_add_autotile_rule(
|
||||||
|
pxl8_tilesheet* tilesheet,
|
||||||
pxl8_tilesheet* pxl8_tilesheet_new(u32 tile_size);
|
u16 base_tile_id,
|
||||||
void pxl8_tilesheet_destroy(pxl8_tilesheet* tilesheet);
|
u8 neighbor_mask,
|
||||||
|
u16 result_tile_id
|
||||||
void pxl8_tilesheet_ref(pxl8_tilesheet* tilesheet);
|
);
|
||||||
void pxl8_tilesheet_unref(pxl8_tilesheet* tilesheet);
|
|
||||||
|
|
||||||
pxl8_result pxl8_tilesheet_add_animation(pxl8_tilesheet* tilesheet, u16 base_tile_id,
|
|
||||||
const u16* frames, u16 frame_count, f32 frame_duration);
|
|
||||||
void pxl8_tilesheet_update_animations(pxl8_tilesheet* tilesheet, f32 delta_time);
|
|
||||||
u16 pxl8_tilesheet_get_animated_frame(const pxl8_tilesheet* tilesheet, u16 tile_id);
|
|
||||||
|
|
||||||
void pxl8_tilesheet_set_tile_property(pxl8_tilesheet* tilesheet, u16 tile_id,
|
|
||||||
const pxl8_tile_properties* props);
|
|
||||||
const pxl8_tile_properties* pxl8_tilesheet_get_tile_property(const pxl8_tilesheet* tilesheet, u16 tile_id);
|
|
||||||
|
|
||||||
pxl8_result pxl8_tilesheet_add_autotile_rule(pxl8_tilesheet* tilesheet, u16 base_tile_id,
|
|
||||||
u8 neighbor_mask, u16 result_tile_id);
|
|
||||||
u16 pxl8_tilesheet_apply_autotile(const pxl8_tilesheet* tilesheet, u16 base_tile_id, u8 neighbors);
|
u16 pxl8_tilesheet_apply_autotile(const pxl8_tilesheet* tilesheet, u16 base_tile_id, u8 neighbors);
|
||||||
|
void pxl8_tilesheet_free(pxl8_tilesheet* tilesheet);
|
||||||
|
u16 pxl8_tilesheet_get_animated_frame(const pxl8_tilesheet* tilesheet, u16 tile_id);
|
||||||
|
const pxl8_tile_properties* pxl8_tilesheet_get_tile_property(
|
||||||
|
const pxl8_tilesheet* tilesheet,
|
||||||
|
u16 tile_id
|
||||||
|
);
|
||||||
|
bool pxl8_tilesheet_is_tile_valid(const pxl8_tilesheet* tilesheet, u16 tile_id);
|
||||||
|
pxl8_result pxl8_tilesheet_load(pxl8_tilesheet* tilesheet, const char* filepath, pxl8_gfx_ctx* gfx);
|
||||||
|
void pxl8_tilesheet_ref(pxl8_tilesheet* tilesheet);
|
||||||
|
void pxl8_tilesheet_render_tile(
|
||||||
|
const pxl8_tilesheet* tilesheet,
|
||||||
|
pxl8_gfx_ctx* gfx,
|
||||||
|
u16 tile_id,
|
||||||
|
i32 x,
|
||||||
|
i32 y,
|
||||||
|
u8 flags
|
||||||
|
);
|
||||||
|
void pxl8_tilesheet_set_tile_property(
|
||||||
|
pxl8_tilesheet* tilesheet,
|
||||||
|
u16 tile_id,
|
||||||
|
const pxl8_tile_properties* props
|
||||||
|
);
|
||||||
|
void pxl8_tilesheet_unref(pxl8_tilesheet* tilesheet);
|
||||||
|
void pxl8_tilesheet_update_animations(pxl8_tilesheet* tilesheet, f32 delta_time);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,8 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <SDL3/SDL.h>
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <SDL3/SDL.h>
|
|
||||||
|
|
||||||
typedef uint8_t u8;
|
typedef uint8_t u8;
|
||||||
typedef uint16_t u16;
|
typedef uint16_t u16;
|
||||||
|
|
@ -21,13 +21,28 @@ typedef __int128_t i128;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
typedef enum pxl8_color_mode {
|
typedef enum pxl8_color_mode {
|
||||||
PXL8_COLOR_MODE_FAMI, // NES-style 4 colors per sprite, 64 color palette
|
PXL8_COLOR_MODE_FAMI,
|
||||||
PXL8_COLOR_MODE_MEGA, // Genesis-style 64 colors, 512 color palette
|
PXL8_COLOR_MODE_MEGA,
|
||||||
PXL8_COLOR_MODE_GBA, // GBA-style 64 colors, 32K color palette
|
PXL8_COLOR_MODE_GBA,
|
||||||
PXL8_COLOR_MODE_SUPERFAMI, // SNES-style 256 colors, 32K color palette
|
PXL8_COLOR_MODE_SUPERFAMI,
|
||||||
PXL8_COLOR_MODE_HICOLOR, // 16-bit high color mode
|
PXL8_COLOR_MODE_HICOLOR,
|
||||||
} pxl8_color_mode;
|
} pxl8_color_mode;
|
||||||
|
|
||||||
|
typedef enum pxl8_resolution {
|
||||||
|
PXL8_RESOLUTION_240x160,
|
||||||
|
PXL8_RESOLUTION_320x180,
|
||||||
|
PXL8_RESOLUTION_320x240,
|
||||||
|
PXL8_RESOLUTION_640x360,
|
||||||
|
PXL8_RESOLUTION_640x480,
|
||||||
|
PXL8_RESOLUTION_800x600,
|
||||||
|
PXL8_RESOLUTION_960x540,
|
||||||
|
} pxl8_resolution;
|
||||||
|
|
||||||
|
typedef struct pxl8_input_state {
|
||||||
|
bool keys[256];
|
||||||
|
bool keys_pressed[256];
|
||||||
|
} pxl8_input_state;
|
||||||
|
|
||||||
typedef struct pxl8_point {
|
typedef struct pxl8_point {
|
||||||
i32 x, y;
|
i32 x, y;
|
||||||
} pxl8_point;
|
} pxl8_point;
|
||||||
|
|
@ -55,18 +70,3 @@ typedef enum pxl8_result {
|
||||||
PXL8_ERROR_ASE_TRUNCATED_FILE,
|
PXL8_ERROR_ASE_TRUNCATED_FILE,
|
||||||
PXL8_ERROR_ASE_MALFORMED_CHUNK,
|
PXL8_ERROR_ASE_MALFORMED_CHUNK,
|
||||||
} pxl8_result;
|
} pxl8_result;
|
||||||
|
|
||||||
typedef enum pxl8_resolution {
|
|
||||||
PXL8_RESOLUTION_240x160,
|
|
||||||
PXL8_RESOLUTION_320x180,
|
|
||||||
PXL8_RESOLUTION_320x240,
|
|
||||||
PXL8_RESOLUTION_640x360,
|
|
||||||
PXL8_RESOLUTION_640x480,
|
|
||||||
PXL8_RESOLUTION_800x600,
|
|
||||||
PXL8_RESOLUTION_960x540,
|
|
||||||
} pxl8_resolution;
|
|
||||||
|
|
||||||
typedef struct pxl8_input_state {
|
|
||||||
bool keys[256];
|
|
||||||
bool keys_pressed[256];
|
|
||||||
} pxl8_input_state;
|
|
||||||
|
|
|
||||||
|
|
@ -4,31 +4,6 @@
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <SDL3/SDL.h>
|
#include <SDL3/SDL.h>
|
||||||
|
|
||||||
void pxl8_vfx_copper_bars(pxl8_gfx_ctx* ctx, pxl8_copper_bar* bars, u32 bar_count, f32 time) {
|
|
||||||
if (!ctx || !bars) return;
|
|
||||||
|
|
||||||
for (u32 i = 0; i < bar_count; i++) {
|
|
||||||
pxl8_copper_bar* bar = &bars[i];
|
|
||||||
f32 y = bar->base_y + bar->amplitude * sinf(time * bar->speed + bar->phase);
|
|
||||||
i32 y_int = (i32)y;
|
|
||||||
|
|
||||||
for (i32 dy = 0; dy <= bar->height; dy++) {
|
|
||||||
f32 position = (f32)dy / (f32)bar->height;
|
|
||||||
f32 gradient = 1.0f - 2.0f * fabsf(position - 0.5f);
|
|
||||||
|
|
||||||
u8 color_idx;
|
|
||||||
if (gradient > 0.8f) {
|
|
||||||
color_idx = bar->fade_color;
|
|
||||||
} else {
|
|
||||||
u8 range = bar->fade_color - bar->color;
|
|
||||||
color_idx = bar->color + (u8)(gradient * range);
|
|
||||||
}
|
|
||||||
|
|
||||||
pxl8_rect_fill(ctx, 0, y_int + dy, ctx->framebuffer_width, 1, color_idx);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void pxl8_vfx_plasma(pxl8_gfx_ctx* ctx, f32 time, f32 scale1, f32 scale2, u8 palette_offset) {
|
void pxl8_vfx_plasma(pxl8_gfx_ctx* ctx, f32 time, f32 scale1, f32 scale2, u8 palette_offset) {
|
||||||
if (!ctx || !ctx->framebuffer) return;
|
if (!ctx || !ctx->framebuffer) return;
|
||||||
|
|
||||||
|
|
@ -50,6 +25,31 @@ void pxl8_vfx_plasma(pxl8_gfx_ctx* ctx, f32 time, f32 scale1, f32 scale2, u8 pal
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void pxl8_vfx_raster_bars(pxl8_gfx_ctx* ctx, pxl8_raster_bar* bars, u32 bar_count, f32 time) {
|
||||||
|
if (!ctx || !bars) return;
|
||||||
|
|
||||||
|
for (u32 i = 0; i < bar_count; i++) {
|
||||||
|
pxl8_raster_bar* bar = &bars[i];
|
||||||
|
f32 y = bar->base_y + bar->amplitude * sinf(time * bar->speed + bar->phase);
|
||||||
|
i32 y_int = (i32)y;
|
||||||
|
|
||||||
|
for (i32 dy = 0; dy <= bar->height; dy++) {
|
||||||
|
f32 position = (f32)dy / (f32)bar->height;
|
||||||
|
f32 gradient = 1.0f - 2.0f * fabsf(position - 0.5f);
|
||||||
|
|
||||||
|
u8 color_idx;
|
||||||
|
if (gradient > 0.8f) {
|
||||||
|
color_idx = bar->fade_color;
|
||||||
|
} else {
|
||||||
|
u8 range = bar->fade_color - bar->color;
|
||||||
|
color_idx = bar->color + (u8)(gradient * range);
|
||||||
|
}
|
||||||
|
|
||||||
|
pxl8_rect_fill(ctx, 0, y_int + dy, ctx->framebuffer_width, 1, color_idx);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void pxl8_vfx_rotozoom(pxl8_gfx_ctx* ctx, f32 angle, f32 zoom, i32 cx, i32 cy) {
|
void pxl8_vfx_rotozoom(pxl8_gfx_ctx* ctx, f32 angle, f32 zoom, i32 cx, i32 cy) {
|
||||||
if (!ctx || !ctx->framebuffer) return;
|
if (!ctx || !ctx->framebuffer) return;
|
||||||
|
|
||||||
|
|
@ -141,15 +141,16 @@ void pxl8_vfx_water_ripple(pxl8_gfx_ctx* ctx, f32* height_map, i32 drop_x, i32 d
|
||||||
|
|
||||||
void pxl8_vfx_particles_clear(pxl8_particle_system* sys) {
|
void pxl8_vfx_particles_clear(pxl8_particle_system* sys) {
|
||||||
if (!sys || !sys->particles) return;
|
if (!sys || !sys->particles) return;
|
||||||
|
|
||||||
for (u32 i = 0; i < sys->max_count; i++) {
|
for (u32 i = 0; i < sys->max_count; i++) {
|
||||||
sys->particles[i].life = 0;
|
sys->particles[i].life = 0;
|
||||||
sys->particles[i].flags = 0;
|
sys->particles[i].flags = 0;
|
||||||
}
|
}
|
||||||
sys->alive_count = 0;
|
sys->alive_count = 0;
|
||||||
|
sys->spawn_timer = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void pxl8_vfx_particles_destroy(pxl8_particle_system* sys) {
|
void pxl8_vfx_particles_free(pxl8_particle_system* sys) {
|
||||||
if (!sys) return;
|
if (!sys) return;
|
||||||
|
|
||||||
if (sys->particles) {
|
if (sys->particles) {
|
||||||
|
|
@ -272,13 +273,14 @@ void pxl8_vfx_particles_update(pxl8_particle_system* sys, f32 dt) {
|
||||||
|
|
||||||
void pxl8_vfx_explosion(pxl8_particle_system* sys, i32 x, i32 y, u32 color, f32 force) {
|
void pxl8_vfx_explosion(pxl8_particle_system* sys, i32 x, i32 y, u32 color, f32 force) {
|
||||||
if (!sys) return;
|
if (!sys) return;
|
||||||
|
|
||||||
sys->x = x;
|
sys->x = x;
|
||||||
sys->y = y;
|
sys->y = y;
|
||||||
sys->spread_x = sys->spread_y = 2.0f;
|
sys->spread_x = sys->spread_y = 2.0f;
|
||||||
sys->gravity_x = 0;
|
sys->gravity_x = 0;
|
||||||
sys->gravity_y = 200.0f;
|
sys->gravity_y = 200.0f;
|
||||||
sys->drag = 0.95f;
|
sys->drag = 0.95f;
|
||||||
|
sys->update_fn = NULL;
|
||||||
|
|
||||||
for (u32 i = 0; i < 50 && i < sys->max_count; i++) {
|
for (u32 i = 0; i < 50 && i < sys->max_count; i++) {
|
||||||
pxl8_particle* p = &sys->particles[i];
|
pxl8_particle* p = &sys->particles[i];
|
||||||
|
|
@ -353,7 +355,7 @@ static void rain_spawn(pxl8_particle* p, void* userdata) {
|
||||||
|
|
||||||
void pxl8_vfx_rain(pxl8_particle_system* sys, i32 width, f32 wind) {
|
void pxl8_vfx_rain(pxl8_particle_system* sys, i32 width, f32 wind) {
|
||||||
if (!sys) return;
|
if (!sys) return;
|
||||||
|
|
||||||
sys->x = width / 2.0f;
|
sys->x = width / 2.0f;
|
||||||
sys->y = -10;
|
sys->y = -10;
|
||||||
sys->spread_x = width;
|
sys->spread_x = width;
|
||||||
|
|
@ -363,6 +365,7 @@ void pxl8_vfx_rain(pxl8_particle_system* sys, i32 width, f32 wind) {
|
||||||
sys->drag = 1.0f;
|
sys->drag = 1.0f;
|
||||||
sys->spawn_rate = 100.0f;
|
sys->spawn_rate = 100.0f;
|
||||||
sys->spawn_fn = rain_spawn;
|
sys->spawn_fn = rain_spawn;
|
||||||
|
sys->update_fn = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void smoke_spawn(pxl8_particle* p, void* userdata) {
|
static void smoke_spawn(pxl8_particle* p, void* userdata) {
|
||||||
|
|
@ -388,12 +391,13 @@ void pxl8_vfx_smoke(pxl8_particle_system* sys, i32 x, i32 y, u8 color) {
|
||||||
sys->drag = 0.96f;
|
sys->drag = 0.96f;
|
||||||
sys->spawn_rate = 20.0f;
|
sys->spawn_rate = 20.0f;
|
||||||
sys->spawn_fn = smoke_spawn;
|
sys->spawn_fn = smoke_spawn;
|
||||||
|
sys->update_fn = NULL;
|
||||||
sys->userdata = (void*)(uintptr_t)color;
|
sys->userdata = (void*)(uintptr_t)color;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void snow_spawn(pxl8_particle* p, void* userdata) {
|
static void snow_spawn(pxl8_particle* p, void* userdata) {
|
||||||
(void)userdata;
|
(void)userdata;
|
||||||
p->start_color = 15 + (rand() % 2);
|
p->start_color = 8 + (rand() % 3);
|
||||||
p->end_color = 10;
|
p->end_color = 10;
|
||||||
p->color = p->start_color;
|
p->color = p->start_color;
|
||||||
p->max_life = 4.0f;
|
p->max_life = 4.0f;
|
||||||
|
|
@ -403,16 +407,17 @@ static void snow_spawn(pxl8_particle* p, void* userdata) {
|
||||||
|
|
||||||
void pxl8_vfx_snow(pxl8_particle_system* sys, i32 width, f32 wind) {
|
void pxl8_vfx_snow(pxl8_particle_system* sys, i32 width, f32 wind) {
|
||||||
if (!sys) return;
|
if (!sys) return;
|
||||||
|
|
||||||
sys->x = width / 2.0f;
|
sys->x = width / 2.0f;
|
||||||
sys->y = -10;
|
sys->y = -10;
|
||||||
sys->spread_x = width;
|
sys->spread_x = width;
|
||||||
sys->spread_y = 0;
|
sys->spread_y = 0;
|
||||||
sys->gravity_x = wind;
|
sys->gravity_x = wind;
|
||||||
sys->gravity_y = 30.0f;
|
sys->gravity_y = 30.0f;
|
||||||
sys->drag = 0.99f;
|
sys->drag = 1.0f;
|
||||||
sys->spawn_rate = 30.0f;
|
sys->spawn_rate = 30.0f;
|
||||||
sys->spawn_fn = snow_spawn;
|
sys->spawn_fn = snow_spawn;
|
||||||
|
sys->update_fn = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void sparks_spawn(pxl8_particle* p, void* userdata) {
|
static void sparks_spawn(pxl8_particle* p, void* userdata) {
|
||||||
|
|
@ -440,6 +445,7 @@ void pxl8_vfx_sparks(pxl8_particle_system* sys, i32 x, i32 y, u32 color) {
|
||||||
sys->drag = 0.97f;
|
sys->drag = 0.97f;
|
||||||
sys->spawn_rate = 40.0f;
|
sys->spawn_rate = 40.0f;
|
||||||
sys->spawn_fn = sparks_spawn;
|
sys->spawn_fn = sparks_spawn;
|
||||||
|
sys->update_fn = NULL;
|
||||||
sys->userdata = (void*)(uintptr_t)color;
|
sys->userdata = (void*)(uintptr_t)color;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -450,6 +456,7 @@ void pxl8_vfx_starfield(pxl8_particle_system* sys, f32 speed, f32 spread) {
|
||||||
sys->gravity_x = sys->gravity_y = 0;
|
sys->gravity_x = sys->gravity_y = 0;
|
||||||
sys->drag = 1.0f;
|
sys->drag = 1.0f;
|
||||||
sys->spawn_rate = 0;
|
sys->spawn_rate = 0;
|
||||||
|
sys->update_fn = NULL;
|
||||||
|
|
||||||
for (u32 i = 0; i < sys->max_count; i++) {
|
for (u32 i = 0; i < sys->max_count; i++) {
|
||||||
pxl8_particle* p = &sys->particles[i];
|
pxl8_particle* p = &sys->particles[i];
|
||||||
|
|
|
||||||
|
|
@ -3,16 +3,6 @@
|
||||||
#include "pxl8_types.h"
|
#include "pxl8_types.h"
|
||||||
#include "pxl8_gfx.h"
|
#include "pxl8_gfx.h"
|
||||||
|
|
||||||
typedef struct pxl8_copper_bar {
|
|
||||||
f32 base_y;
|
|
||||||
f32 amplitude;
|
|
||||||
i32 height;
|
|
||||||
f32 speed;
|
|
||||||
f32 phase;
|
|
||||||
u32 color;
|
|
||||||
u32 fade_color;
|
|
||||||
} pxl8_copper_bar;
|
|
||||||
|
|
||||||
typedef struct pxl8_particle {
|
typedef struct pxl8_particle {
|
||||||
f32 x, y, z;
|
f32 x, y, z;
|
||||||
f32 vx, vy, vz;
|
f32 vx, vy, vz;
|
||||||
|
|
@ -46,15 +36,19 @@ typedef struct pxl8_particle_system {
|
||||||
void* userdata;
|
void* userdata;
|
||||||
} pxl8_particle_system;
|
} pxl8_particle_system;
|
||||||
|
|
||||||
void pxl8_vfx_copper_bars(pxl8_gfx_ctx* ctx, pxl8_copper_bar* bars, u32 bar_count, f32 time);
|
typedef struct pxl8_raster_bar {
|
||||||
void pxl8_vfx_plasma(pxl8_gfx_ctx* ctx, f32 time, f32 scale1, f32 scale2, u8 palette_offset);
|
f32 base_y;
|
||||||
void pxl8_vfx_rotozoom(pxl8_gfx_ctx* ctx, f32 angle, f32 zoom, i32 cx, i32 cy);
|
f32 amplitude;
|
||||||
void pxl8_vfx_tunnel(pxl8_gfx_ctx* ctx, f32 time, f32 speed, f32 twist);
|
i32 height;
|
||||||
void pxl8_vfx_water_ripple(pxl8_gfx_ctx* ctx, f32* height_map, i32 drop_x, i32 drop_y, f32 damping);
|
f32 speed;
|
||||||
|
f32 phase;
|
||||||
|
u32 color;
|
||||||
|
u32 fade_color;
|
||||||
|
} pxl8_raster_bar;
|
||||||
|
|
||||||
void pxl8_vfx_particles_clear(pxl8_particle_system* sys);
|
void pxl8_vfx_particles_clear(pxl8_particle_system* sys);
|
||||||
void pxl8_vfx_particles_destroy(pxl8_particle_system* sys);
|
|
||||||
void pxl8_vfx_particles_emit(pxl8_particle_system* sys, u32 count);
|
void pxl8_vfx_particles_emit(pxl8_particle_system* sys, u32 count);
|
||||||
|
void pxl8_vfx_particles_free(pxl8_particle_system* sys);
|
||||||
void pxl8_vfx_particles_init(pxl8_particle_system* sys, u32 max_count);
|
void pxl8_vfx_particles_init(pxl8_particle_system* sys, u32 max_count);
|
||||||
void pxl8_vfx_particles_render(pxl8_particle_system* sys, pxl8_gfx_ctx* ctx);
|
void pxl8_vfx_particles_render(pxl8_particle_system* sys, pxl8_gfx_ctx* ctx);
|
||||||
void pxl8_vfx_particles_update(pxl8_particle_system* sys, f32 dt);
|
void pxl8_vfx_particles_update(pxl8_particle_system* sys, f32 dt);
|
||||||
|
|
@ -66,3 +60,9 @@ void pxl8_vfx_smoke(pxl8_particle_system* sys, i32 x, i32 y, u8 color);
|
||||||
void pxl8_vfx_snow(pxl8_particle_system* sys, i32 width, f32 wind);
|
void pxl8_vfx_snow(pxl8_particle_system* sys, i32 width, f32 wind);
|
||||||
void pxl8_vfx_sparks(pxl8_particle_system* sys, i32 x, i32 y, u32 color);
|
void pxl8_vfx_sparks(pxl8_particle_system* sys, i32 x, i32 y, u32 color);
|
||||||
void pxl8_vfx_starfield(pxl8_particle_system* sys, f32 speed, f32 spread);
|
void pxl8_vfx_starfield(pxl8_particle_system* sys, f32 speed, f32 spread);
|
||||||
|
|
||||||
|
void pxl8_vfx_plasma(pxl8_gfx_ctx* ctx, f32 time, f32 scale1, f32 scale2, u8 palette_offset);
|
||||||
|
void pxl8_vfx_raster_bars(pxl8_gfx_ctx* ctx, pxl8_raster_bar* bars, u32 bar_count, f32 time);
|
||||||
|
void pxl8_vfx_rotozoom(pxl8_gfx_ctx* ctx, f32 angle, f32 zoom, i32 cx, i32 cy);
|
||||||
|
void pxl8_vfx_tunnel(pxl8_gfx_ctx* ctx, f32 time, f32 speed, f32 twist);
|
||||||
|
void pxl8_vfx_water_ripple(pxl8_gfx_ctx* ctx, f32* height_map, i32 drop_x, i32 drop_y, f32 damping);
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue