initial commit

This commit is contained in:
asrael 2025-08-13 15:04:49 -05:00
commit c18896def0
No known key found for this signature in database
GPG key ID: 2786557804DFAE24
30 changed files with 4183 additions and 0 deletions

469
pxl8.sh Executable file
View file

@ -0,0 +1,469 @@
#!/bin/bash
set -e
CC="${CC:-gcc}"
CFLAGS="-std=c23 -Wall -Wextra"
LIBS="-lm"
MODE="debug"
BUILDDIR=".build"
BINDIR="bin"
if command -v mold >/dev/null 2>&1; then
LINKER_FLAGS="-fuse-ld=mold"
else
LINKER_FLAGS=""
fi
case "$(uname)" in
Linux)
LINKER_FLAGS="$LINKER_FLAGS -rdynamic"
;;
Darwin)
;;
MINGW*|MSYS*|CYGWIN*)
LINKER_FLAGS="$LINKER_FLAGS -Wl,--export-all-symbols"
;;
*)
LINKER_FLAGS="$LINKER_FLAGS -rdynamic"
;;
esac
RED='\033[0;31m'
GREEN='\033[0;32m'
BLUE='\033[0;34m'
BOLD='\033[1m'
NC='\033[0m'
if [[ "$(uname)" == "Linux" ]]; then
CFLAGS="$CFLAGS -D_GNU_SOURCE"
fi
print_info() {
echo -e "${BLUE}${BOLD}info:${NC} $1"
}
print_success() {
echo -e "${GREEN}${BOLD}${NC} $1"
}
print_error() {
echo -e "${RED}${BOLD}error:${NC} $1" >&2
}
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
simd_flags="-mavx2 -msse2"
elif $CC -msse2 -c -x c /dev/null -o /dev/null 2>/dev/null; then
simd_flags="-msse2"
fi
;;
arm64|aarch64)
if $CC -march=armv8-a+simd -c -x c /dev/null -o /dev/null 2>/dev/null; then
simd_flags="-march=armv8-a+simd"
fi
;;
esac
echo "$simd_flags"
}
print_usage() {
echo -e "${BOLD}pxl8${NC} - framework build tool"
echo
echo -e "${BOLD}USAGE:${NC}"
echo " ./pxl8.sh <command> [options]"
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 " update Download/update all dependencies"
echo " vendor Build specific dependencies from source"
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
echo -e "${BOLD}VENDOR OPTIONS:${NC}"
echo " --sdl Build SDL3 from source"
echo " --all Build all vendorable dependencies"
}
COMMAND="$1"
shift || true
for arg in "$@"; do
case $arg in
--release)
MODE="release"
;;
esac
done
SIMD_FLAGS=$(detect_simd)
if [ "$MODE" = "release" ]; then
CFLAGS="$CFLAGS -O3 -march=native -mtune=native -ffast-math -funroll-loops -fno-unwind-tables -fno-asynchronous-unwind-tables $SIMD_FLAGS"
BUILDDIR="$BUILDDIR/release"
BINDIR="$BINDIR/release"
else
CFLAGS="$CFLAGS -g -O1 -DDEBUG $SIMD_FLAGS"
BUILDDIR="$BUILDDIR/debug"
BINDIR="$BINDIR/debug"
fi
setup_sdl3() {
if [[ -d "lib/SDL/build" ]]; then
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
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"
;;
Linux)
SDL3_CFLAGS="-I/usr/include/SDL3"
SDL3_LIBS="-lSDL3"
;;
MINGW*|MSYS*|CYGWIN*)
SDL3_CFLAGS="-I/mingw64/include/SDL3"
SDL3_LIBS="-lSDL3"
;;
esac
fi
print_info "Using system SDL3"
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})"
else
print_error "Downloaded file is empty or missing"
return 1
fi
else
print_error "Failed to download Fennel"
return 1
fi
}
update_luajit() {
print_info "Fetching LuaJIT"
local version="2.1"
local branch="v${version}"
if [[ -d "lib/luajit/.git" ]]; then
cd lib/luajit && git pull --quiet origin ${branch}
cd - > /dev/null
else
rm -rf lib/luajit
git clone --quiet --branch ${branch} https://github.com/LuaJIT/LuaJIT.git lib/luajit
fi
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
print_success "Updated microui"
else
print_error "Failed to download microui"
return 1
fi
}
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
unzip -qjo /tmp/miniz.zip miniz.c miniz.h -d lib/miniz/ 2>/dev/null
rm -f /tmp/miniz.zip
if [[ -f "lib/miniz/miniz.c" ]] && [[ -f "lib/miniz/miniz.h" ]]; then
print_success "Updated miniz (${version})"
else
print_error "Failed to extract miniz files"
return 1
fi
else
print_error "Failed to download miniz"
return 1
fi
}
vendor_sdl() {
print_info "Fetching SDL3"
if [[ -d "lib/SDL/.git" ]]; then
cd lib/SDL && git pull --quiet origin main
cd - > /dev/null
else
rm -rf lib/SDL
git clone --quiet https://github.com/libsdl-org/SDL.git lib/SDL
fi
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"
mkdir -p "$BINDIR"
if [[ ! -f "lib/microui/src/microui.c" ]] || \
[[ ! -d "lib/luajit" ]] || \
[[ ! -f "lib/linenoise/linenoise.c" ]] || \
[[ ! -f "lib/miniz/miniz.c" ]] || \
[[ ! -f "lib/fennel/fennel.lua" ]]; then
print_info "Missing dependencies, fetching..."
update_linenoise
update_fennel
update_luajit
update_microui
update_miniz
fi
if [[ ! -f "bin/.gitignore" ]]; then
echo "*" > "bin/.gitignore"
fi
if [[ ! -f ".build/.gitignore" ]]; then
echo "*" > ".build/.gitignore"
fi
if [[ ! -f "lib/.gitignore" ]]; then
echo "*" > "lib/.gitignore"
fi
if [[ -d "lib/luajit" ]]; then
build_luajit
fi
if [[ -d "lib/SDL" ]]; then
build_sdl
fi
setup_sdl3
print_info "Building pxl8 ($MODE mode)"
if [[ -n "$SIMD_FLAGS" ]]; then
case "$(uname -m)" in
x86_64|amd64)
if [[ "$SIMD_FLAGS" == *"mavx2"* ]]; then
print_info "SIMD: AVX2 + SSE2 enabled"
elif [[ "$SIMD_FLAGS" == *"msse2"* ]]; then
print_info "SIMD: SSE2 enabled"
fi
;;
arm64|aarch64)
print_info "SIMD: ARM NEON enabled"
;;
esac
else
print_info "SIMD: Scalar fallback"
fi
INCLUDES="-Isrc -Ilib -Ilib/microui/src -Ilib/luajit/src -Ilib/linenoise -Ilib/miniz"
COMPILE_FLAGS="$CFLAGS $INCLUDES"
EXECUTABLE="$BINDIR/pxl8"
LIB_SOURCE_FILES="lib/linenoise/linenoise.c lib/miniz/miniz.c"
SRC_SOURCE_FILES="src/pxl8.c src/pxl8_gfx.c src/pxl8_ase.c src/pxl8_font.c src/pxl8_io.c src/pxl8_lua.c src/pxl8_vfx.c src/pxl8_blit.c"
LUAJIT_LIB="lib/luajit/src/libluajit.a"
OBJECT_DIR="$BUILDDIR/obj"
mkdir -p "$OBJECT_DIR"
OBJECTS=""
NEED_LINK=false
SOURCES_COMPILED=""
for src_file in $LIB_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" ]]; 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
SOURCES_COMPILED="yes"
fi
done
for src_file in $SRC_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
SOURCES_COMPILED="yes"
fi
done
if [[ "$LUAJIT_LIB" -nt "$EXECUTABLE" ]] || [[ "$NEED_LINK" == true ]]; then
print_info "Linking executable"
if ! $CC $LINKER_FLAGS $OBJECTS $LUAJIT_LIB $LIBS -o "$EXECUTABLE"; then
print_error "Linking failed"
exit 1
fi
elif [[ -z "$SOURCES_COMPILED" ]]; then
print_info "All files are up to date, skipping build"
fi
print_success "Build complete"
print_info "Binary: $EXECUTABLE"
;;
run)
"$0" build "$@" || exit 1
SCRIPT=""
for arg in "$@"; do
if [[ "$arg" != "--release" ]]; then
SCRIPT="$arg"
break
fi
done
if [[ -z "$SCRIPT" ]]; then
SCRIPT="src/fnl/demo.fnl"
fi
"$BINDIR/pxl8" "$SCRIPT"
;;
clean)
if [[ "$1" == "--all" ]] || [[ "$1" == "--deps" ]]; then
print_info "Removing all build artifacts and dependencies"
rm -rf "$BUILDDIR" "$BINDIR" lib
else
print_info "Removing build artifacts"
rm -rf "$BUILDDIR" "$BINDIR"
fi
print_success "Cleaned"
;;
update)
update_linenoise
update_fennel
update_luajit
update_microui
update_miniz
print_success "All dependencies updated"
;;
vendor)
for arg in "$@"; do
case $arg in
--sdl)
vendor_sdl
;;
--all)
vendor_sdl
;;
*)
;;
esac
done
if [[ -z "$1" ]]; then
vendor_sdl
fi
;;
help|--help|-h|"")
print_usage
;;
*)
print_error "Unknown command: $COMMAND"
print_usage
exit 1
;;
esac