From 6a02b24ae6cfcf5a0bc6ebc7eba0223d079a0aed Mon Sep 17 00:00:00 2001 From: asrael Date: Sun, 28 Sep 2025 13:10:29 -0500 Subject: [PATCH] cleanup --- demo/main.fnl | 84 ++++++---- demo/palettes/sweaft-64.ase | Bin 904 -> 0 bytes demo/sprites/pxl8.png | Bin 1381 -> 0 bytes demo/sprites/trees.ase | Bin 802 -> 0 bytes demo/tiles/tilesheet-dungeon.ase | Bin 1715 -> 0 bytes demo/tiles/tilesheet-world.ase | Bin 6336 -> 0 bytes pxl8.sh | 254 +++++++++++++++++++------------ src/lua/pxl8.lua | 6 +- src/pxl8.c | 75 ++++----- src/pxl8_ase.c | 82 +++++----- src/pxl8_ase.h | 1 - src/pxl8_blit.c | 54 +++---- src/pxl8_blit.h | 18 ++- src/pxl8_cart.c | 130 ++++++++-------- src/pxl8_cart.h | 25 ++- src/pxl8_font.c | 24 +-- src/pxl8_font.h | 2 +- src/pxl8_gfx.c | 4 + src/pxl8_gfx.h | 114 ++++++++------ src/pxl8_io.h | 16 +- src/pxl8_lua.c | 5 +- src/pxl8_lua.h | 5 +- src/pxl8_tilemap.c | 27 +--- src/pxl8_tilemap.h | 69 ++++++--- src/pxl8_tilesheet.c | 33 ---- src/pxl8_tilesheet.h | 63 ++++---- src/pxl8_types.h | 42 ++--- src/pxl8_vfx.c | 71 +++++---- src/pxl8_vfx.h | 32 ++-- 29 files changed, 653 insertions(+), 583 deletions(-) delete mode 100644 demo/palettes/sweaft-64.ase delete mode 100755 demo/sprites/pxl8.png delete mode 100644 demo/sprites/trees.ase delete mode 100644 demo/tiles/tilesheet-dungeon.ase delete mode 100644 demo/tiles/tilesheet-world.ase diff --git a/demo/main.fnl b/demo/main.fnl index 51b77fe..c6c8d41 100644 --- a/demo/main.fnl +++ b/demo/main.fnl @@ -3,44 +3,76 @@ (var time 0) (var current-effect 1) (var particles nil) -(var starfield-init false) (var fire-init false) (var rain-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 [] (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] (set time (+ time dt)) - - (when (pxl8.key_pressed "1") + + (when (pxl8.key_pressed "1") (set current-effect 1)) - (when (pxl8.key_pressed "2") + (when (pxl8.key_pressed "2") (set current-effect 2)) - (when (pxl8.key_pressed "3") - (set current-effect 3) - (set fire-init false)) - (when (pxl8.key_pressed "4") + (when (pxl8.key_pressed "3") + (set current-effect 3)) + (when (pxl8.key_pressed "4") (set current-effect 4)) - (when (pxl8.key_pressed "5") + (when (pxl8.key_pressed "5") (set current-effect 5) - (set rain-init false)) - (when (pxl8.key_pressed "6") + (set fire-init false)) + (when (pxl8.key_pressed "6") (set current-effect 6) + (set rain-init false)) + (when (pxl8.key_pressed "7") + (set current-effect 7) (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 (pxl8.particles_update particles dt)))) (global draw (fn [] (match current-effect - 1 (pxl8.vfx_plasma time 0.10 0.04 0) - - 2 (pxl8.vfx_tunnel time 2.0 0.25) - - 3 (do + 1 (do + (pxl8.clr 0) + (when logo-sprite + (pxl8.sprite logo-sprite logo-x logo-y 128 64)) + (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) (when particles (when (not fire-init) @@ -49,16 +81,8 @@ (set fire-init true)) (pxl8.particles_render particles)) (pxl8.text "Fire Effect Test" 200 10 15)) - - 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_copper_bars bars time) - (pxl8.text "Copper Bars" 200 10 15)) - - 5 (do + + 6 (do (pxl8.clr 0) (when particles (when (not rain-init) @@ -67,8 +91,8 @@ (set rain-init true)) (pxl8.particles_render particles)) (pxl8.text "Rain" 200 10 15)) - - 6 (do + + 7 (do (pxl8.clr 0) (when particles (when (not snow-init) diff --git a/demo/palettes/sweaft-64.ase b/demo/palettes/sweaft-64.ase deleted file mode 100644 index 2a48de009fa97f5ca96500d83f4719ce3d8654bf..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 904 zcmcJN&r1|x7{}kST}yC7gk4$LbqB&icGpGGgamQ4gdz~PQV$A>E95~BmRJW5(H^uA zs)Hm}N>M}|1R*;`gmmc=iC~w&2t0HNZ?eLS-_Pc+f4~{$!|=SrJn#GcJd-Dk*?4W4 zW@8y!k1-iNhnHh4il#*Oaa^a=Key$}clD`3NY6<--||Si1r@@!vsY<8vaL0%aq;Ug`*Ab2_#^3vxeFQbSJ$w3W2QyidBon{X9vZ(piYu2V#cQ)vN@iBX+y7i~Vg9lBJ%hpeEb=wm?*Y%=`(q~KM!KDS`H&^@b4vtpJjo<#i;uY+F!NA>lW*N(K z@r4^QBPI4qe|qtEc0}5E!Y8gVjWLoWHPRxJdW>e%?E0Z^)sIWS|DE% z9) zkiS>^)#=UGieg5K8DKGS&I9Kajf=yss(qh-v+$}9J%BH1r zIV=xj$kVe+PCK_MigCxzA3ZZIS7)&%99W&|&TnbTFg5PvPo@hiMH?8I0_q#Q)<3BM zx`XS0Q@Q=K)yH=jzrL0J^xW0Dm$Sqe1sE73b{21q-?hw@f#tz(&I5CQeQ{n|Ciiyw zx=g`_v)29JysvNJIPh$)`|qXMQ7j3c&n^CY$yC>$@yFY{?^)N|o$A^(@z>3Jt06in z_v~cI+3_`Re~E85L(VQ##_4j|hKuz}Du4V)*EU}Uv%+`#J&0ZCj7qKp`tR#>E4~JX zUAg-<^yT*C=j~w~?&Uus;%EK`1~|vrm0yGzKpqfiNM<&;RSgVmj&qSWG3hhQ8UB2I z_r58d``*gmKbU=s+V9D&wA8L%KkFyh9ISetGTtaX^NQcpNd4yT+uSE-G6~F?{6?4I zp=?@J|2fZZVhtbojQ6@fSE;V|WcXL{J>Bu`PW#)Y+lwBbIFkbO{^`eOSrtr-Z|cWh zR$@3f^CUR1InMcjf>Ve8z-sxlb(4xO1C7V7gu|gAZ4)q3o@z4u-}8I>gRAZZQoC9 z-p+ks8PJM*%If*|4Ig_kSZ$r^zVhC_?CVwT jjng6dU6W9e;c&A)JNowPS#Q&uKuSGb{an^LB{Ts5$ohvx diff --git a/demo/sprites/trees.ase b/demo/sprites/trees.ase deleted file mode 100644 index 95c65d73ae3117ce7c178086be71ca678fd878d2..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 802 zcmY#lW?*=*l##)JL4kpTfsuiMAq9vLK!Je~B*-8DgtP#Qm>3v-ePjdM$_BJR42ank zz*Ztzmjz_AfLy1r&rAP$ne(eFtDYrDPVPfR}U zYuD+a7ULvoV<+U-$uRS_&Wo@A|NlR5`cC)kEm4^rRxW93+Ab0zs{a{WGAweo26TKY zt$MM2+M(7=8IVmV_WuXlU67fVDvec+nIS(hdp1ytRe=HIM27!BFF^nwg91avoZ1VP zVuuYlSOTP0GcB9T52%S>|W=xj%n! zCaT!*{MR*^Kh1C7baAY1b=tp|-Q;QDGp||IYyY%7Fc(prH6wD~m|dfu_cvqtOp!ejna%RneQ)FSezH;oIlj13r>prty`nH#_}rW6s6}jb9VhI*v%% z_HA9o&eq9suk-E9$m}z2Qa6mM&g6B+PSx>#W2qogto)75^gBoYt{YN|e8RS_3vrTo zaK*p*T=z^J`>x=Pu6s*ADM!!AZ_nAkuwz%khj)&LUOm0Yukqv0p4-=s{XHc0aQTwN zS=qO{wf?!DdHFm%Nmk&6z{NHEPr9G8rHe{(tw|L)xarr;#!oDoFZjI9#u=xaZ|8Jf ok@&>(SgWN|<_Atmq1&@1w#|GhWmQxxoHO&=D)Udw?X23*0e#U7O8@`> diff --git a/demo/tiles/tilesheet-dungeon.ase b/demo/tiles/tilesheet-dungeon.ase deleted file mode 100644 index 573598af117483b83e2edb8f145798690ff71a5d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1715 zcmcJLk2}+O9KgTJ&su)WG`Y;ylZ);o%#S0?lDp#+JExEu(J@yOrTmx)SG2JFIB`d= zAC!xP;8ayf1da2c|Y&>`+2{f=hLJO0OM5% zARGt)bO8ha08#4vH;@2gwFwxi-~SN=wSPsX`KMJ=Ex@Q#2mhz?Jzbc(HpL_V?yP%n z@?Hr8fKLdZW-@7&ocL8TnX81auF{sAsV1qAqh`dANX@IT9LB0oXyP^gdkD}1{34Q% zBou1_fENC*8NBA7oz>4uDsK+CP*VGeZrB?BJs8e%4)8QjneXpvDx)6ov;JIWTkVtI zu(r+~XC}7x<5SiVS(NEWnsb@_?u(~VsO>9{S3_VBW|_^)-W}OJq6)pf?{>3lT;)^D zt_2r`wZsSh$H1x*v5eq0BN{24wjo%!+k!Rg>d;AML@Tr)t|Vlsi1%5)K=N6~N1zDO zw{gW$V`b$0ID4E+q!kk)6wPEdnFaFRX3j%;?QSeeR3~ITamA-xc0lPI`n&X$ z)fTJ^qhJW<&a*^;@h8xu*r4x{7%zJ2kEeIVJ+I*!!cIF7D$?~Hxg6{mXO(3vH*_0B zYqW>5rcyS-xx%k*CG)#9-gu@3$ghOS^bSF(Zh0LOoLS8NIj_y;?kcQT^PQEZhu@?- zUQDES)+v*s&NCcxgPx!ZuQ;B6Dn(6(7SG7+Z2f1FE!xl7Uc;xxBb8UbBgypHzvNP+ zE@1oz4m;)&cJhr;{=w`GU-H-EA7oE@c!cYC|HxgdaXD}66waUz&x{RU<7}m!M*ns0 zc@=aXzE(Xv5iOZT*p9PXB22i~&IuZ9aG6oZZW@WZ7=LK zJ`_2Al5PqX+!emOYoCL{QYJ2(aNvZbADoIXe=NCiv&DBX;$0Nv81wO9S6Vg0c>A5+ zV2O+*D}S9I!L&D*BRovooMumbbb?;Q#26}Wl%=CmVvoPv=uTXJc{2l}tTp)@b3@o_ zEkO-(dPH*5zmd!@V9;^e0%z&=RiiOu_J9Xn};aF z8~3*`L>0BEeZp=Av#WA;zw&Mb?Uvc=VN1n*Tv2f@(T=`jx_qC{XgxQ(1yE_cb}2#<^~_LGkm5Qeiep9M~?AmRLEW`JZsf2AS4av?3J|FtrTt&}g9 ze=Dxso}=&DBHeKL_JB(#3lto<=&qDIloGZ|A;u1lYHaS3o)S%nS!a_4U9K}dHFOQ+ z7)9z3%?5dKf#7UIygbOemwyma_;|;vwCNp)~p_ z#e!ZUM}@9NACw-Kcb=`WYLm(H;h{lC&k7^)&E=(U(~sFv=RHzY-nuoAE?kfEXW}oWzR>O6#aq{C^$oqK!U3xBU8N-D7%ul3|kS>h*=qELFs5fpZlhfN}L{T zp3l>2>xrguWhIa*!DMkukmB}*9?LH%05qn$V^(i#ebcFd;TLMwG{!!ASdRg6yz@v~K*bps28PI*`V-H8>4hsYC;rJ_W vN^P+3_8X1k>ZN@tqg7fF4MFGc2Mous#)Xq&r0c@zrH*E}Q(;1x2tfP+o-h+4 diff --git a/demo/tiles/tilesheet-world.ase b/demo/tiles/tilesheet-world.ase deleted file mode 100644 index e28fab20c230359a2ca544b871a75a9f63774381..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6336 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 lv&2 + print_info "Compiling: $src_file" + if ! $CC -c $compile_flags "$src_file" -o "$obj_file"; then + print_error "Compilation failed for $src_file" + exit 1 + fi } detect_simd() { local simd_flags="" - + case "$(uname -m)" in x86_64|amd64) if $CC -mavx2 -c -x c /dev/null -o /dev/null 2>/dev/null; then @@ -68,10 +68,26 @@ detect_simd() { fi ;; esac - + 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() { echo -e "${BOLD}pxl8${NC} - framework build tool" echo @@ -80,15 +96,18 @@ print_usage() { echo echo -e "${BOLD}COMMANDS:${NC}" echo " build Build pxl8" - echo " run Build and run pxl8 [script.fnl|script.lua]" echo " clean Remove build artifacts" + echo " run Build and run pxl8 (optional: cart.pxc or folder)" + echo 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 echo -e "${BOLD}OPTIONS:${NC}" - echo " --all Remove all artifacts including dependencies when cleaning" - echo " --release Build/run in release mode" + echo " --all Clean both build artifacts and dependencies" + echo " --deps Clean only dependencies" + echo " --release Build/run/clean in release mode (default: debug)" } COMMAND="$1" @@ -115,6 +134,34 @@ else BINDIR="$BINDIR/debug" 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() { if [[ -d "lib/SDL/build" ]]; then SDL3_CFLAGS="-Ilib/SDL/include" @@ -125,49 +172,52 @@ setup_sdl3() { SDL3_CFLAGS=$(pkg-config --cflags sdl3 2>/dev/null || echo "") SDL3_LIBS=$(pkg-config --libs sdl3 2>/dev/null || echo "") SDL3_RPATH="" - + if [[ -z "$SDL3_LIBS" ]]; then case "$(uname)" in Darwin) - SDL3_CFLAGS="-I/usr/local/include/SDL3" - SDL3_LIBS="-L/usr/local/lib -lSDL3" + if [[ -f "/usr/local/include/SDL3/SDL.h" ]]; then + SDL3_CFLAGS="-I/usr/local/include/SDL3" + SDL3_LIBS="-L/usr/local/lib -lSDL3" + fi ;; Linux) - SDL3_CFLAGS="-I/usr/include/SDL3" - SDL3_LIBS="-lSDL3" + if [[ -f "/usr/include/SDL3/SDL.h" ]]; then + SDL3_CFLAGS="-I/usr/include/SDL3" + SDL3_LIBS="-lSDL3" + fi ;; MINGW*|MSYS*|CYGWIN*) - SDL3_CFLAGS="-I/mingw64/include/SDL3" - SDL3_LIBS="-lSDL3" + if [[ -f "/mingw64/include/SDL3/SDL.h" ]]; then + SDL3_CFLAGS="-I/mingw64/include/SDL3" + SDL3_LIBS="-lSDL3" + fi ;; esac 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 CFLAGS="$CFLAGS $SDL3_CFLAGS" 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() { print_info "Fetching Fennel" - mkdir -p lib/fennel - + 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 [[ -f "lib/fennel/fennel.lua" ]] && [[ -s "lib/fennel/fennel.lua" ]]; then print_success "Updated Fennel (${version})" @@ -181,6 +231,18 @@ update_fennel() { 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() { print_info "Fetching LuaJIT" @@ -198,25 +260,8 @@ update_luajit() { 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() { 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 && \ 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() { print_info "Fetching miniz" - mkdir -p lib/miniz 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 rm -f /tmp/miniz.zip @@ -249,7 +293,7 @@ update_miniz() { fi } -vendor_sdl() { +update_sdl() { print_info "Fetching SDL3" if [[ -d "lib/SDL/.git" ]]; then @@ -263,18 +307,6 @@ vendor_sdl() { 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 build) mkdir -p "$BUILDDIR" @@ -286,9 +318,10 @@ case "$COMMAND" in [[ ! -f "lib/miniz/miniz.c" ]] || \ [[ ! -f "lib/fennel/fennel.lua" ]]; then print_info "Missing dependencies, fetching..." - - update_linenoise + + make_lib_dirs update_fennel + update_linenoise update_luajit update_microui update_miniz @@ -341,7 +374,7 @@ case "$COMMAND" in LIB_SOURCE_FILES="lib/linenoise/linenoise.c lib/miniz/miniz.c" - SRC_SOURCE_FILES=" + PXL8_SOURCE_FILES=" src/pxl8.c src/pxl8_ase.c src/pxl8_blit.c @@ -367,32 +400,24 @@ case "$COMMAND" in obj_name=$(basename "$src_file" .c).o obj_file="$OBJECT_DIR/$obj_name" OBJECTS="$OBJECTS $obj_file" - + if [[ "$src_file" -nt "$obj_file" ]]; then NEED_LINK=true - print_info "Compiling: $src_file" - if ! $CC -c $COMPILE_FLAGS "$src_file" -o "$obj_file"; then - print_error "Compilation failed for $src_file" - exit 1 - fi + compile_source_file "$src_file" "$obj_file" "$COMPILE_FLAGS" SOURCES_COMPILED="yes" fi 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_file="$OBJECT_DIR/$obj_name" OBJECTS="$OBJECTS $obj_file" - + if [[ "$src_file" -nt "$obj_file" ]] || \ [[ "src/pxl8_types.h" -nt "$obj_file" ]] || \ [[ "src/pxl8_macros.h" -nt "$obj_file" ]]; then NEED_LINK=true - print_info "Compiling: $src_file" - if ! $CC -c $COMPILE_FLAGS "$src_file" -o "$obj_file"; then - print_error "Compilation failed for $src_file" - exit 1 - fi + compile_source_file "$src_file" "$obj_file" "$COMPILE_FLAGS" SOURCES_COMPILED="yes" fi done @@ -413,31 +438,58 @@ case "$COMMAND" in run) "$0" build "$@" || exit 1 - - SCRIPT="" + + CART="" for arg in "$@"; do if [[ "$arg" != "--release" ]]; then - SCRIPT="$arg" + CART="$arg" break fi done - - if [[ -z "$SCRIPT" ]]; then - SCRIPT="src/fnl/demo.fnl" + + if [[ -z "$CART" ]]; then + "$BINDIR/pxl8" + else + "$BINDIR/pxl8" "$CART" fi - - "$BINDIR/pxl8" "$SCRIPT" ;; clean) - if [[ "$1" == "--all" ]] || [[ "$1" == "--deps" ]]; then - print_info "Removing all build artifacts and dependencies" - rm -rf "$BUILDDIR" "$BINDIR" lib + CLEAN_ALL=false + CLEAN_DEPS=false + 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 print_info "Removing build artifacts" - rm -rf "$BUILDDIR" "$BINDIR" + rm -rf "$BUILD_PATH" "$BIN_PATH" + print_success "Cleaned" fi - print_success "Cleaned" ;; update) @@ -450,7 +502,7 @@ case "$COMMAND" in ;; vendor) - vendor_sdl + update_sdl ;; help|--help|-h|"") diff --git a/src/lua/pxl8.lua b/src/lua/pxl8.lua index 30e422b..553403b 100644 --- a/src/lua/pxl8.lua +++ b/src/lua/pxl8.lua @@ -100,8 +100,8 @@ function pxl8.key_pressed(key) return C.pxl8_key_pressed(input, key) end -function pxl8.vfx_copper_bars(bars, time) - local c_bars = ffi.new("pxl8_copper_bar[?]", #bars) +function pxl8.vfx_raster_bars(bars, time) + local c_bars = ffi.new("pxl8_raster_bar[?]", #bars) for i, bar in ipairs(bars) do c_bars[i-1].base_y = bar.base_y or 0 c_bars[i-1].amplitude = bar.amplitude or 10 @@ -111,7 +111,7 @@ function pxl8.vfx_copper_bars(bars, time) c_bars[i-1].color = bar.color or 15 c_bars[i-1].fade_color = bar.fade_color or bar.color or 15 end - C.pxl8_vfx_copper_bars(gfx, c_bars, #bars, time) + C.pxl8_vfx_raster_bars(gfx, c_bars, #bars, time) end function pxl8.vfx_plasma(time, scale1, scale2, palette_offset) diff --git a/src/pxl8.c b/src/pxl8.c index 83d76f2..e721826 100644 --- a/src/pxl8.c +++ b/src/pxl8.c @@ -32,13 +32,13 @@ typedef struct pxl8_repl_state { bool running; } pxl8_repl_state; -typedef struct pxl8_app_state { +typedef struct pxl8_state { + pxl8_cart* cart; pxl8_color_mode color_mode; pxl8_gfx_ctx gfx; lua_State* lua; pxl8_repl_state repl; pxl8_resolution resolution; - pxl8_cart* cart; f32 fps_timer; i32 frame_count; @@ -52,7 +52,7 @@ typedef struct pxl8_app_state { time_t script_mod_time; pxl8_input_state input; -} pxl8_app_state; +} pxl8_state; static void pxl8_repl_completion(const char* buf, linenoiseCompletions* lc) { const char* fennel_keywords[] = { @@ -183,7 +183,7 @@ static pxl8_repl_command* pxl8_repl_pop_command(pxl8_repl_state* repl) { return cmd; } -static void load_script(pxl8_app_state* app) { +static void load_script(pxl8_state* app) { const char* ext = strrchr(app->script_path, '.'); 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[]) { - static pxl8_app_state app = {0}; + static pxl8_state app = {0}; if (!SDL_Init(SDL_INIT_VIDEO | SDL_INIT_EVENTS)) { 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; } - if (script_arg) { - struct stat st; - bool is_cart = (stat(script_arg, &st) == 0 && S_ISDIR(st.st_mode)) || - strstr(script_arg, ".pxc"); + const char* cart_path = script_arg ? script_arg : "demo"; - if (is_cart) { - char* original_cwd = getcwd(NULL, 0); - app.cart = pxl8_cart_new(); - if (pxl8_cart_load(app.cart, script_arg) == PXL8_OK) { - 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", script_arg); - 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'; + struct stat st; + bool is_cart = (stat(cart_path, &st) == 0 && S_ISDIR(st.st_mode)) || + (cart_path && strstr(cart_path, ".pxc")); + + if (is_cart) { + char* original_cwd = getcwd(NULL, 0); + app.cart = calloc(1, sizeof(pxl8_cart)); + if (!app.cart) { + pxl8_error("Failed to allocate memory for cart"); + return false; } - } else { - strcpy(app.script_path, "src/fnl/demo.fnl"); + if (pxl8_cart_load(app.cart, cart_path) == PXL8_OK) { + 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); - - app.script_mod_time = get_file_mod_time(app.script_path); - load_script(&app); + + if (app.script_path[0] != '\0') { + app.script_mod_time = get_file_mod_time(app.script_path); + load_script(&app); + } if (app.repl_mode) { 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) { - pxl8_app_state* app = (pxl8_app_state*)appstate; + pxl8_state* app = (pxl8_state*)appstate; int 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) { - pxl8_app_state* app = (pxl8_app_state*)appstate; + pxl8_state* app = (pxl8_state*)appstate; switch (event->type) { 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) { - pxl8_app_state* app = (pxl8_app_state*)appstate; + pxl8_state* app = (pxl8_state*)appstate; (void)result; if (app) { @@ -511,7 +515,8 @@ void SDL_AppQuit(void* appstate, SDL_AppResult result) { pxl8_repl_shutdown(&app->repl); } if (app->cart) { - pxl8_cart_destroy(app->cart); + pxl8_cart_unload(app->cart); + free(app->cart); app->cart = NULL; } pxl8_lua_shutdown(app->lua); diff --git a/src/pxl8_ase.c b/src/pxl8_ase.c index 186230f..359b6e4 100644 --- a/src/pxl8_ase.c +++ b/src/pxl8_ase.c @@ -1,6 +1,6 @@ +#include #include #include -#include #define MINIZ_NO_STDIO #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 g = packet_data[1]; u8 b = packet_data[2]; - - // Store in ABGR format for GPU + palette->colors[color_index] = 0xFF000000 | (b << 16) | (g << 8) | r; 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) { - layer->flags = read_u16_le(data); // Offset 0: flags (2 bytes) - layer->layer_type = read_u16_le(data + 2); // Offset 2: layer_type (2 bytes) - layer->child_level = read_u16_le(data + 4); // Offset 4: child_level (2 bytes) - // Offset 6: default_width (2 bytes) - skip - // Offset 8: default_height (2 bytes) - skip - 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 + layer->flags = read_u16_le(data); + layer->layer_type = read_u16_le(data + 2); + layer->child_level = read_u16_le(data + 4); + layer->blend_mode = read_u16_le(data + 10); + layer->opacity = data[12]; + u16 name_len = read_u16_le(data + 16); if (name_len > 0) { 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) { - palette->entry_count = read_u32_le(data); // Offset 0: entry_count (4 bytes) - palette->first_color = read_u32_le(data + 4); // Offset 4: first_color (4 bytes) - palette->last_color = read_u32_le(data + 8); // Offset 8: last_color (4 bytes) + palette->entry_count = read_u32_le(data); + palette->first_color = read_u32_le(data + 4); + palette->last_color = read_u32_le(data + 8); u32 color_count = palette->entry_count; 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; } - 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++) { - u16 flags = read_u16_le(color_data); // Offset 0: flags (2 bytes) - u8 r = color_data[2]; // Offset 2: red (1 byte) - u8 g = color_data[3]; // Offset 3: green (1 byte) - u8 b = color_data[4]; // Offset 4: blue (1 byte) - u8 a = color_data[5]; // Offset 5: alpha (1 byte) - - // Store in ABGR format for GPU + u16 flags = read_u16_le(color_data); + u8 r = color_data[2]; + u8 g = color_data[3]; + u8 b = color_data[4]; + u8 a = color_data[5]; + palette->colors[i] = (a << 24) | (b << 16) | (g << 8) | r; 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; } - cel->layer_index = read_u16_le(data); // Offset 0: layer_index (2 bytes) - cel->x = read_i16_le(data + 2); // Offset 2: x (2 bytes) - cel->y = read_i16_le(data + 4); // Offset 4: y (2 bytes) - cel->opacity = data[6]; // Offset 6: opacity (1 byte) - cel->cel_type = read_u16_le(data + 7); // Offset 7: cel_type (2 bytes) + cel->layer_index = read_u16_le(data); + cel->x = read_i16_le(data + 2); + cel->y = read_i16_le(data + 4); + cel->opacity = data[6]; + cel->cel_type = read_u16_le(data + 7); if (cel->cel_type == 2) { if (chunk_size < 20) { return PXL8_ERROR_ASE_MALFORMED_CHUNK; } - // Offset 9: Z-Index (2 bytes) - skip - // Offset 11: Reserved (5 bytes) - skip - cel->width = read_u16_le(data + 16); // Offset 16: width (2 bytes) - cel->height = read_u16_le(data + 18); // Offset 18: height (2 bytes) + cel->width = read_u16_le(data + 16); + cel->height = read_u16_le(data + 18); u32 pixel_data_size = cel->width * cel->height; 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) { return PXL8_ERROR_OUT_OF_MEMORY; } - - // Decompress ZLIB data + mz_ulong dest_len = pixel_data_size; int result = mz_uncompress(cel->pixel_data, &dest_len, data + 20, compressed_data_size); 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 if (!ase_file->palette.colors) { 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 { pxl8_debug("Ignoring old palette (0x0004) - new palette (0x2019) already loaded"); } break; case PXL8_ASE_CHUNK_LAYER: { // 0x2004 - // Need to allocate or reallocate layers array - ase_file->layers = (pxl8_ase_layer*)SDL_realloc(ase_file->layers, - (ase_file->layer_count + 1) * sizeof(pxl8_ase_layer)); + ase_file->layers = + (pxl8_ase_layer*)SDL_realloc(ase_file->layers, + (ase_file->layer_count + 1) * sizeof(pxl8_ase_layer)); if (!ase_file->layers) { result = PXL8_ERROR_OUT_OF_MEMORY; 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 dst_offset = (y + cel.y) * frame->width + cel.x; 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++) { u8 src_pixel = cel.pixel_data[src_offset + x]; bool is_transparent = false; if (src_pixel < ase_file->palette.entry_count && ase_file->palette.colors) { u32 color = ase_file->palette.colors[src_pixel]; - // Check if color is fully transparent (alpha = 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; } } - // Debug: check first few pixels of each row 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); } 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; default: @@ -355,10 +345,12 @@ pxl8_result pxl8_ase_load(const char* filepath, pxl8_ase_file* ase_file) { } if (result != PXL8_OK) break; + chunk_data += chunk_header.chunk_size; } if (result != PXL8_OK) break; + frame_data += frame_header.frame_bytes; } diff --git a/src/pxl8_ase.h b/src/pxl8_ase.h index 2ff3460..efaf9ed 100644 --- a/src/pxl8_ase.h +++ b/src/pxl8_ase.h @@ -1,5 +1,4 @@ #pragma once - #include "pxl8_types.h" #define PXL8_ASE_MAGIC 0xA5E0 diff --git a/src/pxl8_blit.c b/src/pxl8_blit.c index 23e6682..f56ee50 100644 --- a/src/pxl8_blit.c +++ b/src/pxl8_blit.c @@ -1,33 +1,6 @@ #include "pxl8_blit.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, i32 x, i32 y, u32 w, u32 h) { 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]; + } + } + } +} diff --git a/src/pxl8_blit.h b/src/pxl8_blit.h index 39c8004..26576a8 100644 --- a/src/pxl8_blit.h +++ b/src/pxl8_blit.h @@ -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); } -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 +extern "C" { +#endif + void pxl8_blit_simd_hicolor( u32* fb, u32 fb_width, const u32* sprite, u32 atlas_width, 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 diff --git a/src/pxl8_cart.c b/src/pxl8_cart.c index 9501e2f..c7bf437 100644 --- a/src/pxl8_cart.c +++ b/src/pxl8_cart.c @@ -8,17 +8,38 @@ #include #include "../lib/miniz/miniz.h" -static pxl8_cart* s_current_cart = NULL; -static char* s_original_cwd = NULL; +static pxl8_cart* __pxl8_current_cart = NULL; +static char* __pxl8_original_cwd = NULL; -static bool is_directory(const char* path) { - struct stat st; - return stat(path, &st) == 0 && S_ISDIR(st.st_mode); -} +static void pxl8_add_file_recursive(mz_zip_archive* zip, const char* dir_path, const char* prefix) { + DIR* dir = opendir(dir_path); + if (!dir) return; -static bool is_pxc_file(const char* path) { - size_t len = strlen(path); - return len > 4 && strcmp(path + len - 4, ".pxc") == 0; + struct dirent* entry; + while ((entry = readdir(dir)) != NULL) { + 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) { @@ -39,19 +60,18 @@ static char* get_cart_name(const char* path) { return name; } -pxl8_cart* pxl8_cart_new(void) { - pxl8_cart* cart = calloc(1, sizeof(pxl8_cart)); - if (!cart) { - pxl8_error("Failed to allocate cart"); - return NULL; - } - return cart; +static bool is_directory(const char* path) { + struct stat st; + return stat(path, &st) == 0 && S_ISDIR(st.st_mode); } -void pxl8_cart_destroy(pxl8_cart* cart) { - if (!cart) return; - pxl8_cart_unload(cart); - free(cart); +static bool is_pxc_file(const char* path) { + size_t len = strlen(path); + return len > 4 && strcmp(path + len - 4, ".pxc") == 0; +} + +pxl8_cart* pxl8_cart_current(void) { + return __pxl8_current_cart; } 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; 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); if (file_stat.m_is_directory) { @@ -171,6 +191,8 @@ void pxl8_cart_unload(pxl8_cart* cart) { system(cmd); } + char* cart_name = cart->name ? strdup(cart->name) : NULL; + if (cart->base_path) { free(cart->base_path); cart->base_path = NULL; @@ -189,26 +211,31 @@ void pxl8_cart_unload(pxl8_cart* cart) { cart->archive_size = 0; cart->is_folder = 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) { if (!cart || !cart->base_path) return PXL8_ERROR_NULL_POINTER; if (cart->is_mounted) return PXL8_OK; - if (s_current_cart) { - pxl8_cart_unmount(s_current_cart); + if (__pxl8_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) { pxl8_error("Failed to change to cart directory: %s", cart->base_path); - free(s_original_cwd); - s_original_cwd = NULL; + free(__pxl8_original_cwd); + __pxl8_original_cwd = NULL; return PXL8_ERROR_FILE_NOT_FOUND; } cart->is_mounted = true; - s_current_cart = cart; + __pxl8_current_cart = cart; pxl8_info("Mounted cart: %s", cart->name); return PXL8_OK; @@ -217,15 +244,15 @@ pxl8_result pxl8_cart_mount(pxl8_cart* cart) { void pxl8_cart_unmount(pxl8_cart* cart) { if (!cart || !cart->is_mounted) return; - if (s_original_cwd) { - chdir(s_original_cwd); - free(s_original_cwd); - s_original_cwd = NULL; + if (__pxl8_original_cwd) { + chdir(__pxl8_original_cwd); + free(__pxl8_original_cwd); + __pxl8_original_cwd = NULL; } cart->is_mounted = false; - if (s_current_cart == cart) { - s_current_cart = NULL; + if (__pxl8_current_cart == cart) { + __pxl8_current_cart = NULL; } 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; } -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) { 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_add_files_recursive(&zip, folder_path, ""); + pxl8_add_file_recursive(&zip, folder_path, ""); if (!mz_zip_writer_finalize_archive(&zip)) { 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!"); return PXL8_OK; } - -pxl8_cart* pxl8_cart_current(void) { - return s_current_cart; -} diff --git a/src/pxl8_cart.h b/src/pxl8_cart.h index 25e2880..52b101c 100644 --- a/src/pxl8_cart.h +++ b/src/pxl8_cart.h @@ -3,33 +3,26 @@ #include "pxl8_types.h" typedef struct pxl8_cart { - char* base_path; - char* name; void* archive_data; size_t archive_size; + char* base_path; bool is_folder; bool is_mounted; + char* name; } pxl8_cart; #ifdef __cplusplus extern "C" { #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); +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 } diff --git a/src/pxl8_font.c b/src/pxl8_font.c index d3b7ab2..5ae5466 100644 --- a/src/pxl8_font.c +++ b/src/pxl8_font.c @@ -2,18 +2,6 @@ #include #include -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) { if (!font || !atlas_data || !atlas_width || !atlas_height) { 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; } + +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; +} diff --git a/src/pxl8_font.h b/src/pxl8_font.h index dec8429..82d1c20 100644 --- a/src/pxl8_font.h +++ b/src/pxl8_font.h @@ -122,8 +122,8 @@ static const pxl8_font pxl8_default_font = { extern "C" { #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); +const pxl8_glyph* pxl8_font_find_glyph(const pxl8_font* font, u32 codepoint); #ifdef __cplusplus } diff --git a/src/pxl8_gfx.c b/src/pxl8_gfx.c index 084a154..ab0cf62 100644 --- a/src/pxl8_gfx.c +++ b/src/pxl8_gfx.c @@ -153,6 +153,7 @@ void pxl8_gfx_shutdown(pxl8_gfx_ctx* ctx) { ctx->initialized = false; } +// resource loading pxl8_result pxl8_gfx_init_atlas(pxl8_gfx_ctx* ctx, u32 width, u32 height) { 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; } +// rendering pipeline void pxl8_gfx_upload_framebuffer(pxl8_gfx_ctx* ctx) { 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; } +// drawing primitives void pxl8_clr(pxl8_gfx_ctx* ctx, u32 color) { 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) { if (!ctx || !ctx->palette || count == 0) return; diff --git a/src/pxl8_gfx.h b/src/pxl8_gfx.h index bc3b2cd..5b33ab2 100644 --- a/src/pxl8_gfx.h +++ b/src/pxl8_gfx.h @@ -17,32 +17,30 @@ typedef struct pxl8_gfx_ctx { SDL_Texture* framebuffer_texture; SDL_Texture* sprite_atlas_texture; SDL_Window* window; - + u8* framebuffer; + bool initialized; u32* palette; u32 palette_size; - + i32 framebuffer_width; i32 framebuffer_height; 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_height; u32 sprite_frame_width; u32 sprite_frame_height; 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_width, viewport_height; - - bool initialized; } pxl8_gfx_ctx; typedef enum pxl8_blend_mode { @@ -52,6 +50,14 @@ typedef enum pxl8_blend_mode { PXL8_BLEND_MULTIPLY } 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 { u8 start_index; u8 end_index; @@ -65,21 +71,17 @@ typedef struct pxl8_scanline_effect { bool active; } 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 { pxl8_palette_cycle palette_cycles[8]; pxl8_scanline_effect scanline_effects[4]; - f32 time; } 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_gfx_ctx* ctx, pxl8_color_mode mode, @@ -88,36 +90,54 @@ pxl8_result pxl8_gfx_init( i32 window_width, 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_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); - -void pxl8_gfx_get_resolution_dimensions(pxl8_resolution resolution, i32* width, i32* height); -void pxl8_gfx_upload_framebuffer(pxl8_gfx_ctx* ctx); -void pxl8_gfx_upload_atlas(pxl8_gfx_ctx* ctx); +pxl8_result pxl8_gfx_load_palette(pxl8_gfx_ctx* ctx, const char* path); +pxl8_result pxl8_gfx_load_sprite(pxl8_gfx_ctx* ctx, const char* path); 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_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_pixel(pxl8_gfx_ctx* ctx, i32 x, i32 y, 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_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_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_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_fade_palette(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_fade_palette( + 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_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 diff --git a/src/pxl8_io.h b/src/pxl8_io.h index fe9557f..c15045c 100644 --- a/src/pxl8_io.h +++ b/src/pxl8_io.h @@ -11,17 +11,15 @@ extern "C" { #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); - -void pxl8_io_free_file_content(char* content); +bool pxl8_io_file_exists(const char* path); 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_pressed(const pxl8_input_state* input, i32 key); diff --git a/src/pxl8_lua.c b/src/pxl8_lua.c index fe87043..8a18ac2 100644 --- a/src/pxl8_lua.c +++ b/src/pxl8_lua.c @@ -104,9 +104,9 @@ static const char* pxl8_ffi_cdefs = " float phase;\n" " unsigned int color;\n" " unsigned int fade_color;\n" -"} pxl8_copper_bar;\n" +"} pxl8_raster_bar;\n" "\n" -"void pxl8_vfx_copper_bars(pxl8_gfx_ctx* ctx, pxl8_copper_bar* bars, u32 bar_count, f32 time);\n" +"void pxl8_vfx_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_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" @@ -327,4 +327,3 @@ pxl8_result pxl8_lua_eval_fennel(lua_State* lua_state, const char* code) { lua_remove(lua_state, -2); return PXL8_OK; } - diff --git a/src/pxl8_lua.h b/src/pxl8_lua.h index d7d872a..90a3667 100644 --- a/src/pxl8_lua.h +++ b/src/pxl8_lua.h @@ -13,12 +13,13 @@ extern "C" { pxl8_result pxl8_lua_init(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_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_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 } diff --git a/src/pxl8_tilemap.c b/src/pxl8_tilemap.c index f3ecf1e..ced7c65 100644 --- a/src/pxl8_tilemap.c +++ b/src/pxl8_tilemap.c @@ -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_top = pxl8_max(0, view_top >> 4); - u32 chunk_right = pxl8_min((tilemap->width + 15) >> 4, (view_right >> 4) + 1); - u32 chunk_bottom = pxl8_min((tilemap->height + 15) >> 4, (view_bottom >> 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, (u32)((view_bottom >> 4) + 1)); for (u32 cy = chunk_top; cy < chunk_bottom; cy++) { 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; } -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) { if (!tilemap) return 0; pxl8_tile tile = pxl8_tilemap_get_tile(tilemap, layer, x, y); diff --git a/src/pxl8_tilemap.h b/src/pxl8_tilemap.h index d612cc5..2bc08b5 100644 --- a/src/pxl8_tilemap.h +++ b/src/pxl8_tilemap.h @@ -108,35 +108,56 @@ typedef struct pxl8_tilemap_view { extern "C" { #endif -pxl8_result pxl8_tilemap_init(pxl8_tilemap* tilemap, u32 width, u32 height, u32 tile_size); -pxl8_result pxl8_tilemap_set_tilesheet(pxl8_tilemap* tilemap, pxl8_tilesheet* tilesheet); +bool pxl8_tilemap_check_collision(const pxl8_tilemap* tilemap, i32 x, i32 y, i32 w, i32 h); +void pxl8_tilemap_compress(pxl8_tilemap* tilemap); void pxl8_tilemap_free(pxl8_tilemap* tilemap); - -pxl8_result pxl8_tilemap_set_tile(pxl8_tilemap* tilemap, u32 layer, u32 x, u32 y, u16 tile_id, u8 flags); +u32 pxl8_tilemap_get_memory_usage(const pxl8_tilemap* tilemap); pxl8_tile pxl8_tilemap_get_tile(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(const pxl8_tilemap* tilemap, const pxl8_gfx_ctx* gfx, pxl8_tilemap_view* view); - +u16 pxl8_tilemap_get_tile_id(const pxl8_tilemap* tilemap, u32 layer, u32 x, u32 y); +void pxl8_tilemap_get_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_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); - -bool pxl8_tilemap_is_solid(const pxl8_tilemap* tilemap, u32 x, u32 y); -bool pxl8_tilemap_check_collision(const pxl8_tilemap* tilemap, i32 x, i32 y, i32 w, i32 h); - -pxl8_tilemap* pxl8_tilemap_new(u32 width, u32 height, u32 tile_size); -void pxl8_tilemap_destroy(pxl8_tilemap* tilemap); -u16 pxl8_tilemap_get_tile_id(const pxl8_tilemap* tilemap, u32 layer, u32 x, u32 y); - +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_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); - -pxl8_result pxl8_tilemap_set_tile_auto(pxl8_tilemap* tilemap, u32 layer, u32 x, u32 y, - u16 base_tile_id, u8 flags); -void pxl8_tilemap_update_autotiles(pxl8_tilemap* tilemap, u32 layer, u32 x, u32 y, u32 w, u32 h); - -u32 pxl8_tilemap_get_memory_usage(const pxl8_tilemap* tilemap); -void pxl8_tilemap_compress(pxl8_tilemap* tilemap); +void pxl8_tilemap_update_autotiles( + pxl8_tilemap* tilemap, + u32 layer, + u32 x, + u32 y, + u32 w, + u32 h +); #ifdef __cplusplus } diff --git a/src/pxl8_tilesheet.c b/src/pxl8_tilesheet.c index a9ecb46..1bbc686 100644 --- a/src/pxl8_tilesheet.c +++ b/src/pxl8_tilesheet.c @@ -5,16 +5,6 @@ #include #include -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) { 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; } -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) { if (!tilesheet) return; tilesheet->ref_count++; @@ -218,7 +186,6 @@ void pxl8_tilesheet_unref(pxl8_tilesheet* tilesheet) { if (--tilesheet->ref_count == 0) { pxl8_tilesheet_free(tilesheet); - free(tilesheet); } } diff --git a/src/pxl8_tilesheet.h b/src/pxl8_tilesheet.h index b7432df..fd94bf2 100644 --- a/src/pxl8_tilesheet.h +++ b/src/pxl8_tilesheet.h @@ -31,33 +31,44 @@ typedef struct pxl8_tilesheet { extern "C" { #endif -pxl8_result pxl8_tilesheet_init(pxl8_tilesheet* tilesheet, u32 tile_size); -pxl8_result pxl8_tilesheet_load(pxl8_tilesheet* tilesheet, const char* filepath, pxl8_gfx_ctx* gfx); -void pxl8_tilesheet_free(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); - -bool pxl8_tilesheet_is_tile_valid(const pxl8_tilesheet* tilesheet, u16 tile_id); - -pxl8_tilesheet* pxl8_tilesheet_new(u32 tile_size); -void pxl8_tilesheet_destroy(pxl8_tilesheet* tilesheet); - -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); +pxl8_result pxl8_tilesheet_add_animation( + pxl8_tilesheet* tilesheet, + u16 base_tile_id, + const u16* frames, + u16 frame_count, + f32 frame_duration +); +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); +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 } diff --git a/src/pxl8_types.h b/src/pxl8_types.h index b1a8edb..60d4022 100644 --- a/src/pxl8_types.h +++ b/src/pxl8_types.h @@ -1,8 +1,8 @@ #pragma once +#include #include #include -#include typedef uint8_t u8; typedef uint16_t u16; @@ -21,13 +21,28 @@ typedef __int128_t i128; #endif typedef enum pxl8_color_mode { - PXL8_COLOR_MODE_FAMI, // NES-style 4 colors per sprite, 64 color palette - PXL8_COLOR_MODE_MEGA, // Genesis-style 64 colors, 512 color palette - PXL8_COLOR_MODE_GBA, // GBA-style 64 colors, 32K color palette - PXL8_COLOR_MODE_SUPERFAMI, // SNES-style 256 colors, 32K color palette - PXL8_COLOR_MODE_HICOLOR, // 16-bit high color mode + PXL8_COLOR_MODE_FAMI, + PXL8_COLOR_MODE_MEGA, + PXL8_COLOR_MODE_GBA, + PXL8_COLOR_MODE_SUPERFAMI, + PXL8_COLOR_MODE_HICOLOR, } 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 { i32 x, y; } pxl8_point; @@ -55,18 +70,3 @@ typedef enum pxl8_result { PXL8_ERROR_ASE_TRUNCATED_FILE, PXL8_ERROR_ASE_MALFORMED_CHUNK, } 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; diff --git a/src/pxl8_vfx.c b/src/pxl8_vfx.c index 119bf06..2b598a6 100644 --- a/src/pxl8_vfx.c +++ b/src/pxl8_vfx.c @@ -4,31 +4,6 @@ #include #include -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) { 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) { 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) { if (!sys || !sys->particles) return; - + for (u32 i = 0; i < sys->max_count; i++) { sys->particles[i].life = 0; sys->particles[i].flags = 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->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) { if (!sys) return; - + sys->x = x; sys->y = y; sys->spread_x = sys->spread_y = 2.0f; sys->gravity_x = 0; sys->gravity_y = 200.0f; sys->drag = 0.95f; + sys->update_fn = NULL; for (u32 i = 0; i < 50 && i < sys->max_count; 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) { if (!sys) return; - + sys->x = width / 2.0f; sys->y = -10; 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->spawn_rate = 100.0f; sys->spawn_fn = rain_spawn; + sys->update_fn = NULL; } 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->spawn_rate = 20.0f; sys->spawn_fn = smoke_spawn; + sys->update_fn = NULL; sys->userdata = (void*)(uintptr_t)color; } static void snow_spawn(pxl8_particle* p, void* userdata) { (void)userdata; - p->start_color = 15 + (rand() % 2); + p->start_color = 8 + (rand() % 3); p->end_color = 10; p->color = p->start_color; 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) { if (!sys) return; - + sys->x = width / 2.0f; sys->y = -10; sys->spread_x = width; sys->spread_y = 0; sys->gravity_x = wind; sys->gravity_y = 30.0f; - sys->drag = 0.99f; + sys->drag = 1.0f; sys->spawn_rate = 30.0f; sys->spawn_fn = snow_spawn; + sys->update_fn = NULL; } 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->spawn_rate = 40.0f; sys->spawn_fn = sparks_spawn; + sys->update_fn = NULL; 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->drag = 1.0f; sys->spawn_rate = 0; + sys->update_fn = NULL; for (u32 i = 0; i < sys->max_count; i++) { pxl8_particle* p = &sys->particles[i]; diff --git a/src/pxl8_vfx.h b/src/pxl8_vfx.h index 05aaa39..ab870a4 100644 --- a/src/pxl8_vfx.h +++ b/src/pxl8_vfx.h @@ -3,16 +3,6 @@ #include "pxl8_types.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 { f32 x, y, z; f32 vx, vy, vz; @@ -46,15 +36,19 @@ typedef struct pxl8_particle_system { void* userdata; } pxl8_particle_system; -void pxl8_vfx_copper_bars(pxl8_gfx_ctx* ctx, pxl8_copper_bar* bars, u32 bar_count, f32 time); -void pxl8_vfx_plasma(pxl8_gfx_ctx* ctx, f32 time, f32 scale1, f32 scale2, u8 palette_offset); -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); +typedef struct pxl8_raster_bar { + f32 base_y; + f32 amplitude; + i32 height; + 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_destroy(pxl8_particle_system* sys); 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_render(pxl8_particle_system* sys, pxl8_gfx_ctx* ctx); 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_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_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);