refactor separate framework from game code, add demo3d
This commit is contained in:
parent
19ae869769
commit
40f5cdcaa5
92 changed files with 2665 additions and 6547 deletions
193
Makefile
193
Makefile
|
|
@ -1,21 +1,21 @@
|
||||||
# pxl8 - Makefile
|
# pxl8 - Makefile
|
||||||
#
|
#
|
||||||
# Usage:
|
# Usage:
|
||||||
# make Build everything (debug)
|
# make Build everything (debug)
|
||||||
# make release Build everything (release)
|
# make release Build everything (release)
|
||||||
# make run Build and run (CART=script.fnl)
|
# make run Build and run (CART=script.fnl)
|
||||||
# make server Build pxl8d only
|
# make demo3d-server Build demo3d server only
|
||||||
# make client Build pxl8 only
|
# make client Build pxl8 only
|
||||||
# make install Install to ~/.local/bin (release)
|
# make install Install to ~/.local/bin (release)
|
||||||
# make profile Profile with perf + flamegraph (Linux)
|
# make profile Profile with perf + flamegraph (Linux)
|
||||||
# make ase Aseprite tools (ASE_CMD=package|clean)
|
# make ase Aseprite tools (ASE_CMD=package|clean)
|
||||||
# make clean Remove build artifacts
|
# make clean Remove build artifacts
|
||||||
# make clean-all Remove build artifacts and dependencies
|
# make clean-all Remove build artifacts and dependencies
|
||||||
# make clean-deps Remove only dependencies
|
# make clean-deps Remove only dependencies
|
||||||
# make clean-cache Clear ccache
|
# make clean-cache Clear ccache
|
||||||
# make update Fetch/update all dependencies
|
# make update Fetch/update all dependencies
|
||||||
# make vendor-sdl Vendor SDL3 from source
|
# make vendor-sdl Vendor SDL3 from source
|
||||||
# make help Show available targets
|
# make help Show available targets
|
||||||
#
|
#
|
||||||
# Variables:
|
# Variables:
|
||||||
# MODE=release Build in release mode (default: debug)
|
# MODE=release Build in release mode (default: debug)
|
||||||
|
|
@ -173,11 +173,17 @@ endif
|
||||||
# -- Include paths ------------------------------------------------------------
|
# -- Include paths ------------------------------------------------------------
|
||||||
|
|
||||||
INCLUDES = \
|
INCLUDES = \
|
||||||
-Isrc/asset -Isrc/bsp -Isrc/core -Isrc/gfx -Isrc/gui -Isrc/hal \
|
-Isrc/asset -Isrc/core -Isrc/gfx -Isrc/gui -Isrc/platform \
|
||||||
-Isrc/math -Isrc/net -Isrc/procgen -Isrc/script -Isrc/shader \
|
-Isrc/math -Isrc/net -Isrc/procgen -Isrc/script -Isrc/shader \
|
||||||
-Isrc/sfx -Isrc/sim -Isrc/world \
|
-Isrc/sfx \
|
||||||
-I$(LINENOISE_DIR) -Ilib/luajit/src -Ilib/miniz -I.build/shaders/c
|
-I$(LINENOISE_DIR) -Ilib/luajit/src -Ilib/miniz -I.build/shaders/c
|
||||||
|
|
||||||
|
DEMO3D_INCLUDES = \
|
||||||
|
-Idemo3d/client/bsp \
|
||||||
|
-Idemo3d/client/world \
|
||||||
|
-Idemo3d/client/sim \
|
||||||
|
-Idemo3d/client/net
|
||||||
|
|
||||||
# -- Source files -------------------------------------------------------------
|
# -- Source files -------------------------------------------------------------
|
||||||
|
|
||||||
LIB_SRCS = $(LINENOISE_SRCS) lib/miniz/miniz.c
|
LIB_SRCS = $(LINENOISE_SRCS) lib/miniz/miniz.c
|
||||||
|
|
@ -186,21 +192,19 @@ PXL8_SRCS = \
|
||||||
src/asset/pxl8_ase.c \
|
src/asset/pxl8_ase.c \
|
||||||
src/asset/pxl8_cart.c \
|
src/asset/pxl8_cart.c \
|
||||||
src/asset/pxl8_save.c \
|
src/asset/pxl8_save.c \
|
||||||
src/bsp/pxl8_bsp.c \
|
|
||||||
src/bsp/pxl8_bsp_render.c \
|
|
||||||
src/core/pxl8.c \
|
src/core/pxl8.c \
|
||||||
src/core/pxl8_bytes.c \
|
src/core/pxl8_bytes.c \
|
||||||
src/core/pxl8_io.c \
|
src/core/pxl8_io.c \
|
||||||
src/core/pxl8_log.c \
|
src/core/pxl8_log.c \
|
||||||
src/core/pxl8_replay.c \
|
src/core/pxl8_replay.c \
|
||||||
src/core/pxl8_rng.c \
|
src/core/pxl8_rng.c \
|
||||||
src/gfx/pxl8_3d_camera.c \
|
src/gfx/pxl8_camera3d.c \
|
||||||
src/gfx/pxl8_anim.c \
|
src/gfx/pxl8_anim.c \
|
||||||
src/gfx/pxl8_atlas.c \
|
src/gfx/pxl8_atlas.c \
|
||||||
src/gfx/pxl8_blit.c \
|
src/gfx/pxl8_blit.c \
|
||||||
src/gfx/pxl8_colormap.c \
|
src/gfx/pxl8_colormap.c \
|
||||||
src/gfx/pxl8_dither.c \
|
src/gfx/pxl8_dither.c \
|
||||||
src/gfx/pxl8_render.c \
|
src/gfx/pxl8_blit3d.c \
|
||||||
src/gfx/pxl8_shader_registry.c \
|
src/gfx/pxl8_shader_registry.c \
|
||||||
src/gfx/pxl8_shader_runtime.c \
|
src/gfx/pxl8_shader_runtime.c \
|
||||||
src/gfx/pxl8_font.c \
|
src/gfx/pxl8_font.c \
|
||||||
|
|
@ -215,33 +219,40 @@ PXL8_SRCS = \
|
||||||
src/gfx/pxl8_tilesheet.c \
|
src/gfx/pxl8_tilesheet.c \
|
||||||
src/gfx/pxl8_transition.c \
|
src/gfx/pxl8_transition.c \
|
||||||
src/gui/pxl8_gui.c \
|
src/gui/pxl8_gui.c \
|
||||||
src/hal/pxl8_hal_sdl3.c \
|
src/platform/pxl8_platform_sdl3.c \
|
||||||
src/hal/pxl8_thread_sdl3.c \
|
src/platform/pxl8_thread_sdl3.c \
|
||||||
src/math/pxl8_math.c \
|
src/math/pxl8_math.c \
|
||||||
src/math/pxl8_noise.c \
|
src/math/pxl8_noise.c \
|
||||||
src/net/pxl8_net.c \
|
src/net/pxl8_net.c \
|
||||||
src/net/pxl8_protocol.c \
|
|
||||||
src/procgen/pxl8_graph.c \
|
src/procgen/pxl8_graph.c \
|
||||||
src/script/pxl8_repl.c \
|
src/script/pxl8_repl.c \
|
||||||
src/script/pxl8_script.c \
|
src/script/pxl8_script.c \
|
||||||
src/sfx/pxl8_sfx.c \
|
src/sfx/pxl8_sfx.c
|
||||||
src/sim/pxl8_sim.c \
|
|
||||||
src/world/pxl8_entity.c \
|
DEMO3D_SRCS = \
|
||||||
src/world/pxl8_world.c \
|
demo3d/client/bsp/demo3d_bsp.c \
|
||||||
src/world/pxl8_world_chunk.c \
|
demo3d/client/bsp/demo3d_bsp_render.c \
|
||||||
src/world/pxl8_world_chunk_cache.c
|
demo3d/client/world/demo3d_world.c \
|
||||||
|
demo3d/client/world/demo3d_chunk.c \
|
||||||
|
demo3d/client/world/demo3d_chunk_cache.c \
|
||||||
|
demo3d/client/world/demo3d_entity.c \
|
||||||
|
demo3d/client/sim/demo3d_sim.c \
|
||||||
|
demo3d/client/net/demo3d_protocol.c \
|
||||||
|
demo3d/client/net/demo3d_net.c \
|
||||||
|
demo3d/client/demo3d.c
|
||||||
|
|
||||||
ifeq ($(HAS_SDL3),1)
|
ifeq ($(HAS_SDL3),1)
|
||||||
PXL8_SRCS += src/hal/pxl8_io_sdl3.c src/hal/pxl8_mem_sdl3.c
|
PXL8_SRCS += src/platform/pxl8_io_sdl3.c src/platform/pxl8_mem_sdl3.c
|
||||||
else
|
else
|
||||||
PXL8_SRCS += src/hal/pxl8_mem.c
|
PXL8_SRCS += src/platform/pxl8_mem.c
|
||||||
endif
|
endif
|
||||||
|
|
||||||
# -- Object files -------------------------------------------------------------
|
# -- Object files -------------------------------------------------------------
|
||||||
|
|
||||||
LIB_OBJS = $(patsubst %.c,$(OBJDIR)/%.o,$(notdir $(LIB_SRCS)))
|
LIB_OBJS = $(patsubst %.c,$(OBJDIR)/%.o,$(notdir $(LIB_SRCS)))
|
||||||
PXL8_OBJS = $(patsubst %.c,$(OBJDIR)/%.o,$(notdir $(PXL8_SRCS)))
|
PXL8_OBJS = $(patsubst %.c,$(OBJDIR)/%.o,$(notdir $(PXL8_SRCS)))
|
||||||
ALL_OBJS = $(LIB_OBJS) $(PXL8_OBJS)
|
DEMO3D_OBJS = $(patsubst %.c,$(OBJDIR)/demo3d_%.o,$(notdir $(DEMO3D_SRCS)))
|
||||||
|
ALL_OBJS = $(LIB_OBJS) $(PXL8_OBJS)
|
||||||
|
|
||||||
# -- Shader objects -----------------------------------------------------------
|
# -- Shader objects -----------------------------------------------------------
|
||||||
|
|
||||||
|
|
@ -252,16 +263,18 @@ SHADER_INCLUDES = -Isrc/core -Isrc/gfx -Isrc/math
|
||||||
# -- Targets ------------------------------------------------------------------
|
# -- Targets ------------------------------------------------------------------
|
||||||
|
|
||||||
CLIENT = $(BINDIR)/pxl8$(EXE_EXT)
|
CLIENT = $(BINDIR)/pxl8$(EXE_EXT)
|
||||||
SERVER = $(BINDIR)/pxl8d$(EXE_EXT)
|
SERVER = $(BINDIR)/demo3d-server$(EXE_EXT)
|
||||||
|
DEMO3D = $(BINDIR)/demo3d$(EXE_EXT)
|
||||||
|
|
||||||
CART ?= demo
|
CART ?= demo
|
||||||
PROFILE_DURATION ?= 30
|
PROFILE_DURATION ?= 30
|
||||||
ASE_CMD ?=
|
ASE_CMD ?=
|
||||||
|
|
||||||
.PHONY: all release client server run clean clean-all clean-deps clean-cache \
|
.PHONY: all release client server demo3d demo3d-server run run-demo3d \
|
||||||
|
clean clean-all clean-deps clean-cache \
|
||||||
update vendor-sdl deps luajit install ase profile help
|
update vendor-sdl deps luajit install ase profile help
|
||||||
|
|
||||||
all: client server
|
all: client demo3d demo3d-server
|
||||||
|
|
||||||
release:
|
release:
|
||||||
$(MAKE) MODE=release all
|
$(MAKE) MODE=release all
|
||||||
|
|
@ -326,19 +339,21 @@ $(LUAJIT_LIB): lib/luajit/src/luajit.c
|
||||||
|
|
||||||
# -- Server (Rust) ------------------------------------------------------------
|
# -- Server (Rust) ------------------------------------------------------------
|
||||||
|
|
||||||
server: $(SERVER)
|
server: demo3d-server
|
||||||
|
|
||||||
$(SERVER): $(wildcard pxl8d/src/*.rs pxl8d/Cargo.toml)
|
demo3d-server: $(SERVER)
|
||||||
|
|
||||||
|
$(SERVER): $(wildcard demo3d/server/src/*.rs demo3d/server/Cargo.toml)
|
||||||
@mkdir -p $(BINDIR)
|
@mkdir -p $(BINDIR)
|
||||||
$(INFO) "Building pxl8d ($(MODE) mode)"
|
$(INFO) "Building demo3d-server ($(MODE) mode)"
|
||||||
ifeq ($(MODE),release)
|
ifeq ($(MODE),release)
|
||||||
@cd pxl8d && PATH="$$(echo $$PATH | tr ':' '\n' | grep -v '/usr/bin' | tr '\n' ':')" cargo build --release --quiet
|
@cd demo3d/server && PATH="$$(echo $$PATH | tr ':' '\n' | grep -v '/usr/bin' | tr '\n' ':')" cargo build --release --quiet
|
||||||
@cp pxl8d/target/release/pxl8d$(EXE_EXT) $(SERVER)
|
@cp demo3d/server/target/release/demo3d-server$(EXE_EXT) $(SERVER)
|
||||||
else
|
else
|
||||||
@cd pxl8d && PATH="$$(echo $$PATH | tr ':' '\n' | grep -v '/usr/bin' | tr '\n' ':')" cargo build --quiet
|
@cd demo3d/server && PATH="$$(echo $$PATH | tr ':' '\n' | grep -v '/usr/bin' | tr '\n' ':')" cargo build --quiet
|
||||||
@cp pxl8d/target/debug/pxl8d$(EXE_EXT) $(SERVER)
|
@cp demo3d/server/target/debug/demo3d-server$(EXE_EXT) $(SERVER)
|
||||||
endif
|
endif
|
||||||
$(INFO) "Built pxl8d"
|
$(INFO) "Built demo3d-server"
|
||||||
|
|
||||||
# -- Client (C23) -------------------------------------------------------------
|
# -- Client (C23) -------------------------------------------------------------
|
||||||
|
|
||||||
|
|
@ -359,6 +374,31 @@ ifeq ($(STRIP),true)
|
||||||
endif
|
endif
|
||||||
$(INFO) "Built pxl8 -> $@"
|
$(INFO) "Built pxl8 -> $@"
|
||||||
|
|
||||||
|
# -- Demo3D (game client) ----------------------------------------------------
|
||||||
|
|
||||||
|
demo3d: deps $(DEMO3D)
|
||||||
|
|
||||||
|
$(DEMO3D): $(ALL_OBJS) $(DEMO3D_OBJS) $(SHADER_OBJS) $(LUAJIT_LIB)
|
||||||
|
@mkdir -p $(BINDIR)
|
||||||
|
$(INFO) "Linking demo3d"
|
||||||
|
ifeq ($(PLATFORM),windows)
|
||||||
|
@(echo EXPORTS && llvm-nm --defined-only $(ALL_OBJS) $(DEMO3D_OBJS) $(SHADER_OBJS) | grep ' T pxl8_\| T demo3d_\| T SDL' | awk '{print $$3}') > $(BUILDDIR)/demo3d.def
|
||||||
|
@MSYS_NO_PATHCONV=1 $(CC) $(LDFLAGS) $(ALL_OBJS) $(DEMO3D_OBJS) $(SHADER_OBJS) $(LUAJIT_LIB) $(LIBS) -Wl,/DEF:$(BUILDDIR)/demo3d.def -o $@
|
||||||
|
@cp -u $(SDL3_BUILD_DIR)/SDL3.dll $(BINDIR)/
|
||||||
|
else
|
||||||
|
@$(CC) $(LDFLAGS) $(ALL_OBJS) $(DEMO3D_OBJS) $(SHADER_OBJS) $(LUAJIT_LIB) $(LIBS) -o $@
|
||||||
|
endif
|
||||||
|
ifeq ($(STRIP),true)
|
||||||
|
@llvm-strip $@
|
||||||
|
endif
|
||||||
|
$(INFO) "Built demo3d -> $@"
|
||||||
|
|
||||||
|
run-demo3d: demo3d demo3d-server
|
||||||
|
@$(BINDIR)/demo3d-server$(EXE_EXT) & SERVER_PID=$$!; \
|
||||||
|
sleep 0.5; \
|
||||||
|
$(BINDIR)/demo3d$(EXE_EXT) demo3d $(EXTRA_ARGS) || true; \
|
||||||
|
kill $$SERVER_PID 2>/dev/null; wait $$SERVER_PID 2>/dev/null || true
|
||||||
|
|
||||||
# -- Compile rules ------------------------------------------------------------
|
# -- Compile rules ------------------------------------------------------------
|
||||||
|
|
||||||
# Lib sources (dep flags, no warnings)
|
# Lib sources (dep flags, no warnings)
|
||||||
|
|
@ -385,7 +425,15 @@ $(OBJDIR)/%.o: $(1)/%.c | $(OBJDIR)
|
||||||
@$$(CC) -c $$(CFLAGS) $$(INCLUDES) $$< -o $$@
|
@$$(CC) -c $$(CFLAGS) $$(INCLUDES) $$< -o $$@
|
||||||
endef
|
endef
|
||||||
|
|
||||||
$(foreach dir,src/asset src/bsp src/core src/gfx src/gui src/hal src/math src/net src/procgen src/script src/shader src/sfx src/sim src/world,$(eval $(call PXL8_COMPILE_RULE,$(dir))))
|
$(foreach dir,src/asset src/core src/gfx src/gui src/platform src/math src/net src/procgen src/script src/shader src/sfx,$(eval $(call PXL8_COMPILE_RULE,$(dir))))
|
||||||
|
|
||||||
|
define DEMO3D_COMPILE_RULE
|
||||||
|
$(OBJDIR)/demo3d_%.o: $(1)/%.c | $(OBJDIR)
|
||||||
|
@printf '$(CYAN)[%s CC]$(NC) %s\n' "$$$$(date +%H:%M:%S)" "$$<"
|
||||||
|
@$$(CC) -c $$(CFLAGS) $$(INCLUDES) $$(DEMO3D_INCLUDES) $$< -o $$@
|
||||||
|
endef
|
||||||
|
|
||||||
|
$(foreach dir,demo3d/client demo3d/client/bsp demo3d/client/world demo3d/client/sim demo3d/client/net,$(eval $(call DEMO3D_COMPILE_RULE,$(dir))))
|
||||||
|
|
||||||
# pxl8_script.o depends on embedded Lua/Fennel sources
|
# pxl8_script.o depends on embedded Lua/Fennel sources
|
||||||
LUA_SRCS = $(wildcard src/lua/*.lua src/lua/pxl8/*.lua) lib/fennel/fennel.lua
|
LUA_SRCS = $(wildcard src/lua/*.lua src/lua/pxl8/*.lua) lib/fennel/fennel.lua
|
||||||
|
|
@ -410,17 +458,14 @@ $(shell [ -f lib/.gitignore ] || echo '*' > lib/.gitignore)
|
||||||
|
|
||||||
# -- Run ----------------------------------------------------------------------
|
# -- Run ----------------------------------------------------------------------
|
||||||
|
|
||||||
run: all
|
run: client
|
||||||
@$(BINDIR)/pxl8d$(EXE_EXT) & SERVER_PID=$$!; \
|
@$(BINDIR)/pxl8$(EXE_EXT) $(CART) $(EXTRA_ARGS)
|
||||||
sleep 0.5; \
|
|
||||||
$(BINDIR)/pxl8$(EXE_EXT) $(CART) || true; \
|
|
||||||
kill $$SERVER_PID 2>/dev/null; wait $$SERVER_PID 2>/dev/null || true
|
|
||||||
|
|
||||||
# -- Clean --------------------------------------------------------------------
|
# -- Clean --------------------------------------------------------------------
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
rm -rf .build/debug .build/release bin/debug bin/release .build/shaders
|
rm -rf .build/debug .build/release bin/debug bin/release .build/shaders
|
||||||
@if [ -d pxl8d ]; then cd pxl8d && cargo clean 2>/dev/null; fi || true
|
@if [ -d demo3d/server ]; then cd demo3d/server && cargo clean 2>/dev/null; fi || true
|
||||||
|
|
||||||
clean-all: clean
|
clean-all: clean
|
||||||
rm -rf lib
|
rm -rf lib
|
||||||
|
|
@ -458,7 +503,7 @@ profile: client
|
||||||
TIMESTAMP=$$(date +%Y%m%d_%H%M%S); \
|
TIMESTAMP=$$(date +%Y%m%d_%H%M%S); \
|
||||||
PDIR=.build/$(MODE)/profile; \
|
PDIR=.build/$(MODE)/profile; \
|
||||||
echo "[INFO] Starting server..."; \
|
echo "[INFO] Starting server..."; \
|
||||||
$(BINDIR)/pxl8d$(EXE_EXT) & SERVER_PID=$$!; \
|
$(BINDIR)/demo3d-server$(EXE_EXT) & SERVER_PID=$$!; \
|
||||||
sleep 0.5; \
|
sleep 0.5; \
|
||||||
echo "[INFO] Profiling for $(PROFILE_DURATION)s (Ctrl+C to stop early)..."; \
|
echo "[INFO] Profiling for $(PROFILE_DURATION)s (Ctrl+C to stop early)..."; \
|
||||||
perf record -F 99 -g --call-graph dwarf -o $$PDIR/perf_$$TIMESTAMP.data -- \
|
perf record -F 99 -g --call-graph dwarf -o $$PDIR/perf_$$TIMESTAMP.data -- \
|
||||||
|
|
@ -479,24 +524,25 @@ help:
|
||||||
@echo "pxl8 - framework build system"
|
@echo "pxl8 - framework build system"
|
||||||
@echo ""
|
@echo ""
|
||||||
@echo "TARGETS:"
|
@echo "TARGETS:"
|
||||||
@echo " make Build everything (debug)"
|
@echo " make Build everything (debug)"
|
||||||
@echo " make release Build everything (release)"
|
@echo " make release Build everything (release)"
|
||||||
@echo " make run Build and run (CART=\"demo --repl\")"
|
@echo " make run Build and run (CART=\"demo --repl\")"
|
||||||
@echo " make client Build pxl8 only"
|
@echo " make client Build pxl8 only"
|
||||||
@echo " make server Build pxl8d only"
|
@echo " make demo3d-server Build demo3d client"
|
||||||
@echo " make install Install to ~/.local/bin (release)"
|
@echo " make server Build demo3d-server"
|
||||||
@echo " make profile Profile with perf (PROFILE_DURATION=30, Linux only)"
|
@echo " make install Install to ~/.local/bin (release)"
|
||||||
@echo " make ase Aseprite tools (ASE_CMD=package|clean)"
|
@echo " make profile Profile with perf (PROFILE_DURATION=30, Linux only)"
|
||||||
@echo " make clean Remove build artifacts"
|
@echo " make ase Aseprite tools (ASE_CMD=package|clean)"
|
||||||
@echo " make clean-all Remove artifacts + dependencies"
|
@echo " make clean Remove build artifacts"
|
||||||
@echo " make clean-deps Remove only dependencies"
|
@echo " make clean-all Remove artifacts + dependencies"
|
||||||
@echo " make clean-cache Clear ccache"
|
@echo " make clean-deps Remove only dependencies"
|
||||||
@echo " make update Fetch/update all dependencies"
|
@echo " make clean-cache Clear ccache"
|
||||||
@echo " make vendor-sdl Vendor SDL3 from source"
|
@echo " make update Fetch/update all dependencies"
|
||||||
|
@echo " make vendor-sdl Vendor SDL3 from source"
|
||||||
@echo ""
|
@echo ""
|
||||||
@echo "VARIABLES:"
|
@echo "VARIABLES:"
|
||||||
@echo " MODE=release Build mode (default: debug)"
|
@echo " MODE=release Build mode (default: debug)"
|
||||||
@echo " CART=demo Cart or script to run"
|
@echo " CART=demo Cart or script to run"
|
||||||
|
|
||||||
# -- Auto-generated header dependencies --------------------------------------
|
# -- Auto-generated header dependencies --------------------------------------
|
||||||
|
|
||||||
|
|
@ -505,7 +551,7 @@ help:
|
||||||
|
|
||||||
# -- compile_commands.json ----------------------------------------------------
|
# -- compile_commands.json ----------------------------------------------------
|
||||||
|
|
||||||
compile_commands.json: $(LIB_SRCS) $(PXL8_SRCS)
|
compile_commands.json: $(LIB_SRCS) $(PXL8_SRCS) $(DEMO3D_SRCS)
|
||||||
$(INFO) "Generating compile_commands.json"
|
$(INFO) "Generating compile_commands.json"
|
||||||
@echo '[' > $@.tmp
|
@echo '[' > $@.tmp
|
||||||
@first=true; \
|
@first=true; \
|
||||||
|
|
@ -518,6 +564,11 @@ compile_commands.json: $(LIB_SRCS) $(PXL8_SRCS)
|
||||||
if $$first; then first=false; else printf ',\n' >> $@.tmp; fi; \
|
if $$first; then first=false; else printf ',\n' >> $@.tmp; fi; \
|
||||||
printf ' {"directory":"%s","command":"clang -c %s %s","file":"%s"}' \
|
printf ' {"directory":"%s","command":"clang -c %s %s","file":"%s"}' \
|
||||||
"$(CURDIR)" "$(CFLAGS) $(INCLUDES)" "$$f" "$$f" >> $@.tmp; \
|
"$(CURDIR)" "$(CFLAGS) $(INCLUDES)" "$$f" "$$f" >> $@.tmp; \
|
||||||
|
done; \
|
||||||
|
for f in $(DEMO3D_SRCS); do \
|
||||||
|
if $$first; then first=false; else printf ',\n' >> $@.tmp; fi; \
|
||||||
|
printf ' {"directory":"%s","command":"clang -c %s %s %s","file":"%s"}' \
|
||||||
|
"$(CURDIR)" "$(CFLAGS) $(INCLUDES)" "$(DEMO3D_INCLUDES)" "$$f" "$$f" >> $@.tmp; \
|
||||||
done
|
done
|
||||||
@printf '\n]\n' >> $@.tmp
|
@printf '\n]\n' >> $@.tmp
|
||||||
@mv $@.tmp $@
|
@mv $@.tmp $@
|
||||||
|
|
|
||||||
|
|
@ -1,110 +1,51 @@
|
||||||
(local pxl8 (require :pxl8))
|
(local pxl8 (require :pxl8))
|
||||||
(local menu (require :mod.menu))
|
(local menu (require :mod.menu))
|
||||||
(local music (require :mod.music))
|
(local music (require :mod.music))
|
||||||
(local first_person3d (require :mod.first_person3d))
|
|
||||||
|
|
||||||
(var time 0)
|
(var time 0)
|
||||||
(var in-world false)
|
|
||||||
(var first_person3d-init? false)
|
|
||||||
|
|
||||||
(var logo-x 256)
|
(var logo-x 256)
|
||||||
(var logo-y 148)
|
(var logo-y 148)
|
||||||
(var logo-dx 100)
|
(var logo-dx 100)
|
||||||
(var logo-dy 80)
|
(var logo-dy 80)
|
||||||
(var logo-sprite nil)
|
(var logo-sprite nil)
|
||||||
(var transition nil)
|
|
||||||
(var transition-to-world false)
|
|
||||||
|
|
||||||
(fn start-transition []
|
|
||||||
(when (not transition)
|
|
||||||
(set transition-to-world true)
|
|
||||||
(set transition (pxl8.create_transition :pixelate 0.5))
|
|
||||||
(transition:set_color 0xFF000000)
|
|
||||||
(transition:start)))
|
|
||||||
|
|
||||||
(fn enter-world []
|
|
||||||
(when (first_person3d.is-ready)
|
|
||||||
(start-transition)))
|
|
||||||
|
|
||||||
(global init (fn []
|
(global init (fn []
|
||||||
(pxl8.load_palette "res/sprites/pxl8_logo.ase")
|
(pxl8.load_palette "res/sprites/pxl8_logo.ase")
|
||||||
(set logo-sprite (pxl8.load_sprite "res/sprites/pxl8_logo.ase"))
|
(set logo-sprite (pxl8.load_sprite "res/sprites/pxl8_logo.ase"))
|
||||||
(music.init)
|
(music.init)
|
||||||
(menu.init)
|
(menu.init)))
|
||||||
(first_person3d.preload)))
|
|
||||||
|
|
||||||
(global update (fn [dt]
|
(global update (fn [dt]
|
||||||
(when (pxl8.key_pressed "escape")
|
(when (pxl8.key_pressed "escape")
|
||||||
(if (menu.is-paused)
|
(menu.toggle))
|
||||||
(do
|
|
||||||
(menu.hide)
|
|
||||||
(when in-world
|
|
||||||
(pxl8.set_relative_mouse_mode true)))
|
|
||||||
(if in-world
|
|
||||||
(do
|
|
||||||
(menu.show)
|
|
||||||
(pxl8.set_relative_mouse_mode false))
|
|
||||||
(menu.toggle))))
|
|
||||||
|
|
||||||
(when (not (menu.is-paused))
|
(when (not (menu.is-paused))
|
||||||
(set time (+ time dt))
|
(set time (+ time dt))
|
||||||
(music.update dt)
|
(music.update dt)
|
||||||
|
|
||||||
(when transition
|
(set logo-x (+ logo-x (* logo-dx dt)))
|
||||||
(transition:update dt)
|
(set logo-y (+ logo-y (* logo-dy dt)))
|
||||||
(when (transition:is_complete)
|
(when (< logo-x 0)
|
||||||
(when transition-to-world
|
(set logo-x 0)
|
||||||
(set in-world true)
|
(set logo-dx (math.abs logo-dx)))
|
||||||
(set transition-to-world false)
|
(when (> logo-x 512)
|
||||||
(pxl8.set_relative_mouse_mode true))
|
(set logo-x 512)
|
||||||
(transition:destroy)
|
(set logo-dx (- (math.abs logo-dx))))
|
||||||
(set transition nil)))
|
(when (< logo-y 0)
|
||||||
|
(set logo-y 0)
|
||||||
(if in-world
|
(set logo-dy (math.abs logo-dy)))
|
||||||
(do
|
(when (> logo-y 296)
|
||||||
(when (not first_person3d-init?)
|
(set logo-y 296)
|
||||||
(first_person3d.init)
|
(set logo-dy (- (math.abs logo-dy)))))
|
||||||
(set first_person3d-init? true))
|
|
||||||
(first_person3d.update dt))
|
|
||||||
(do
|
|
||||||
(when (and (not (menu.is-paused))
|
|
||||||
(first_person3d.is-ready)
|
|
||||||
(or (pxl8.key_pressed "return") (pxl8.key_pressed "space")))
|
|
||||||
(enter-world))
|
|
||||||
(set logo-x (+ logo-x (* logo-dx dt)))
|
|
||||||
(set logo-y (+ logo-y (* logo-dy dt)))
|
|
||||||
(when (< logo-x 0)
|
|
||||||
(set logo-x 0)
|
|
||||||
(set logo-dx (math.abs logo-dx)))
|
|
||||||
(when (> logo-x 512)
|
|
||||||
(set logo-x 512)
|
|
||||||
(set logo-dx (- (math.abs logo-dx))))
|
|
||||||
(when (< logo-y 0)
|
|
||||||
(set logo-y 0)
|
|
||||||
(set logo-dy (math.abs logo-dy)))
|
|
||||||
(when (> logo-y 296)
|
|
||||||
(set logo-y 296)
|
|
||||||
(set logo-dy (- (math.abs logo-dy)))))))
|
|
||||||
|
|
||||||
(when (menu.is-paused)
|
(when (menu.is-paused)
|
||||||
(menu.update))))
|
(menu.update))))
|
||||||
|
|
||||||
(global frame (fn []
|
(global frame (fn []
|
||||||
(if in-world
|
(pxl8.clear 0)
|
||||||
(first_person3d.frame)
|
(when logo-sprite
|
||||||
(do
|
(pxl8.sprite logo-sprite logo-x logo-y 128 64 (< logo-dx 0) (< logo-dy 0)))
|
||||||
(pxl8.clear 0)
|
|
||||||
(when logo-sprite
|
|
||||||
(pxl8.sprite logo-sprite logo-x logo-y 128 64 (< logo-dx 0) (< logo-dy 0)))
|
|
||||||
(when (not (menu.is-paused))
|
|
||||||
(if (first_person3d.is-ready)
|
|
||||||
(pxl8.text "Press ENTER to start" 240 320 1)
|
|
||||||
(if (first_person3d.is-connected)
|
|
||||||
(pxl8.text "Loading world..." 260 320 1)
|
|
||||||
(pxl8.text "Connecting..." 275 320 1))))))
|
|
||||||
|
|
||||||
(when transition
|
|
||||||
(transition:render))
|
|
||||||
|
|
||||||
(when (menu.is-paused)
|
(when (menu.is-paused)
|
||||||
(pxl8.push_target)
|
(pxl8.push_target)
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load diff
|
|
@ -1,75 +0,0 @@
|
||||||
(local vfx {})
|
|
||||||
|
|
||||||
(fn vfx.explosion [ps x y ?opts]
|
|
||||||
(let [opts (or ?opts {})
|
|
||||||
color (or opts.color 208)
|
|
||||||
force (or opts.force 200)]
|
|
||||||
(ps:set_position x y)
|
|
||||||
(ps:set_colors color (+ color 15))
|
|
||||||
(ps:set_velocity (- force) force (- force) force)
|
|
||||||
(ps:set_gravity 0 100)
|
|
||||||
(ps:set_life 0.3 0.8)
|
|
||||||
(ps:set_size 1 3)
|
|
||||||
(ps:set_drag 0.98)
|
|
||||||
(ps:set_spawn_rate 0)
|
|
||||||
(ps:emit (or opts.count 50))))
|
|
||||||
|
|
||||||
(fn vfx.fire [ps x y ?opts]
|
|
||||||
(let [opts (or ?opts {})
|
|
||||||
width (or opts.width 50)
|
|
||||||
color (or opts.color 208)]
|
|
||||||
(ps:set_position x y)
|
|
||||||
(ps:set_spread width 5)
|
|
||||||
(ps:set_colors color (+ color 15))
|
|
||||||
(ps:set_velocity -20 20 -80 -40)
|
|
||||||
(ps:set_gravity 0 -30)
|
|
||||||
(ps:set_life 0.5 1.5)
|
|
||||||
(ps:set_size 1 2)
|
|
||||||
(ps:set_turbulence 30)
|
|
||||||
(ps:set_drag 0.95)
|
|
||||||
(ps:set_spawn_rate (or opts.rate 50))))
|
|
||||||
|
|
||||||
(fn vfx.rain [ps width ?opts]
|
|
||||||
(let [opts (or ?opts {})
|
|
||||||
wind (or opts.wind 0)
|
|
||||||
color (or opts.color 153)]
|
|
||||||
(ps:set_position (/ width 2) -10)
|
|
||||||
(ps:set_spread width 0)
|
|
||||||
(ps:set_colors color (+ color 3))
|
|
||||||
(ps:set_velocity (- wind 10) (+ wind 10) 300 400)
|
|
||||||
(ps:set_gravity 0 200)
|
|
||||||
(ps:set_life 1 2)
|
|
||||||
(ps:set_size 1 1)
|
|
||||||
(ps:set_drag 1)
|
|
||||||
(ps:set_spawn_rate (or opts.rate 100))))
|
|
||||||
|
|
||||||
(fn vfx.smoke [ps x y ?opts]
|
|
||||||
(let [opts (or ?opts {})
|
|
||||||
color (or opts.color 248)]
|
|
||||||
(ps:set_position x y)
|
|
||||||
(ps:set_spread 10 5)
|
|
||||||
(ps:set_colors color (+ color 7))
|
|
||||||
(ps:set_velocity -15 15 -30 -10)
|
|
||||||
(ps:set_gravity 0 -20)
|
|
||||||
(ps:set_life 1 3)
|
|
||||||
(ps:set_size 2 4)
|
|
||||||
(ps:set_turbulence 20)
|
|
||||||
(ps:set_drag 0.98)
|
|
||||||
(ps:set_spawn_rate (or opts.rate 20))))
|
|
||||||
|
|
||||||
(fn vfx.snow [ps width ?opts]
|
|
||||||
(let [opts (or ?opts {})
|
|
||||||
wind (or opts.wind 10)
|
|
||||||
color (or opts.color 15)]
|
|
||||||
(ps:set_position (/ width 2) -10)
|
|
||||||
(ps:set_spread width 0)
|
|
||||||
(ps:set_colors color color)
|
|
||||||
(ps:set_velocity (- wind 20) (+ wind 20) 30 60)
|
|
||||||
(ps:set_gravity 0 10)
|
|
||||||
(ps:set_life 3 6)
|
|
||||||
(ps:set_size 1 2)
|
|
||||||
(ps:set_turbulence 15)
|
|
||||||
(ps:set_drag 0.99)
|
|
||||||
(ps:set_spawn_rate (or opts.rate 30))))
|
|
||||||
|
|
||||||
vfx
|
|
||||||
|
|
@ -1,5 +0,0 @@
|
||||||
(local first_person3d (require :mod.first_person3d))
|
|
||||||
|
|
||||||
(global init first_person3d.init)
|
|
||||||
(global update first_person3d.update)
|
|
||||||
(global frame first_person3d.frame)
|
|
||||||
3
demo3d/cart.fnl
Normal file
3
demo3d/cart.fnl
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
{:title "pxl8 3d demo"
|
||||||
|
:resolution "640x360"
|
||||||
|
:window-size [1280 720]}
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
#include "pxl8_bsp.h"
|
#include "demo3d_bsp.h"
|
||||||
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
|
|
@ -26,17 +26,17 @@ typedef enum {
|
||||||
CHUNK_SURFEDGES = 13,
|
CHUNK_SURFEDGES = 13,
|
||||||
CHUNK_MODELS = 14,
|
CHUNK_MODELS = 14,
|
||||||
CHUNK_COUNT = 15
|
CHUNK_COUNT = 15
|
||||||
} pxl8_bsp_chunk_type;
|
} demo3d_bsp_chunk_type;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
u32 offset;
|
u32 offset;
|
||||||
u32 size;
|
u32 size;
|
||||||
} pxl8_bsp_chunk;
|
} demo3d_bsp_chunk;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
u32 version;
|
u32 version;
|
||||||
pxl8_bsp_chunk chunks[CHUNK_COUNT];
|
demo3d_bsp_chunk chunks[CHUNK_COUNT];
|
||||||
} pxl8_bsp_header;
|
} demo3d_bsp_header;
|
||||||
|
|
||||||
static inline pxl8_vec3 read_vec3(pxl8_stream* stream) {
|
static inline pxl8_vec3 read_vec3(pxl8_stream* stream) {
|
||||||
f32 x = pxl8_read_f32(stream);
|
f32 x = pxl8_read_f32(stream);
|
||||||
|
|
@ -45,7 +45,7 @@ static inline pxl8_vec3 read_vec3(pxl8_stream* stream) {
|
||||||
return (pxl8_vec3){x, z, y};
|
return (pxl8_vec3){x, z, y};
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool validate_chunk(const pxl8_bsp_chunk* chunk, u32 element_size, usize file_size) {
|
static bool validate_chunk(const demo3d_bsp_chunk* chunk, u32 element_size, usize file_size) {
|
||||||
if (chunk->size == 0) return true;
|
if (chunk->size == 0) return true;
|
||||||
if (chunk->offset >= file_size) return false;
|
if (chunk->offset >= file_size) return false;
|
||||||
if (chunk->offset + chunk->size > file_size) return false;
|
if (chunk->offset + chunk->size > file_size) return false;
|
||||||
|
|
@ -53,7 +53,7 @@ static bool validate_chunk(const pxl8_bsp_chunk* chunk, u32 element_size, usize
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline bool pxl8_bsp_get_edge_vertex(const pxl8_bsp* bsp, i32 surfedge_idx, u32* out_vert_idx) {
|
static inline bool demo3d_bsp_get_edge_vertex(const demo3d_bsp* bsp, i32 surfedge_idx, u32* out_vert_idx) {
|
||||||
if (surfedge_idx >= (i32)bsp->num_surfedges) return false;
|
if (surfedge_idx >= (i32)bsp->num_surfedges) return false;
|
||||||
|
|
||||||
i32 edge_idx = bsp->surfedges[surfedge_idx];
|
i32 edge_idx = bsp->surfedges[surfedge_idx];
|
||||||
|
|
@ -72,7 +72,7 @@ static inline bool pxl8_bsp_get_edge_vertex(const pxl8_bsp* bsp, i32 surfedge_id
|
||||||
return *out_vert_idx < bsp->num_vertices;
|
return *out_vert_idx < bsp->num_vertices;
|
||||||
}
|
}
|
||||||
|
|
||||||
pxl8_result pxl8_bsp_load(const char* path, pxl8_bsp* bsp) {
|
pxl8_result demo3d_bsp_load(const char* path, demo3d_bsp* bsp) {
|
||||||
if (!path || !bsp) return PXL8_ERROR_INVALID_ARGUMENT;
|
if (!path || !bsp) return PXL8_ERROR_INVALID_ARGUMENT;
|
||||||
|
|
||||||
memset(bsp, 0, sizeof(*bsp));
|
memset(bsp, 0, sizeof(*bsp));
|
||||||
|
|
@ -85,7 +85,7 @@ pxl8_result pxl8_bsp_load(const char* path, pxl8_bsp* bsp) {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (file_size < sizeof(pxl8_bsp_header)) {
|
if (file_size < sizeof(demo3d_bsp_header)) {
|
||||||
pxl8_error("BSP file too small: %s", path);
|
pxl8_error("BSP file too small: %s", path);
|
||||||
pxl8_free(file_data);
|
pxl8_free(file_data);
|
||||||
return PXL8_ERROR_INVALID_FORMAT;
|
return PXL8_ERROR_INVALID_FORMAT;
|
||||||
|
|
@ -93,7 +93,7 @@ pxl8_result pxl8_bsp_load(const char* path, pxl8_bsp* bsp) {
|
||||||
|
|
||||||
pxl8_stream stream = pxl8_stream_create(file_data, (u32)file_size);
|
pxl8_stream stream = pxl8_stream_create(file_data, (u32)file_size);
|
||||||
|
|
||||||
pxl8_bsp_header header;
|
demo3d_bsp_header header;
|
||||||
header.version = pxl8_read_u32(&stream);
|
header.version = pxl8_read_u32(&stream);
|
||||||
|
|
||||||
if (header.version != BSP_VERSION) {
|
if (header.version != BSP_VERSION) {
|
||||||
|
|
@ -107,11 +107,11 @@ pxl8_result pxl8_bsp_load(const char* path, pxl8_bsp* bsp) {
|
||||||
header.chunks[i].size = pxl8_read_u32(&stream);
|
header.chunks[i].size = pxl8_read_u32(&stream);
|
||||||
}
|
}
|
||||||
|
|
||||||
pxl8_bsp_chunk* chunk = &header.chunks[CHUNK_VERTICES];
|
demo3d_bsp_chunk* chunk = &header.chunks[CHUNK_VERTICES];
|
||||||
if (!validate_chunk(chunk, 12, file_size)) goto error_cleanup;
|
if (!validate_chunk(chunk, 12, file_size)) goto error_cleanup;
|
||||||
bsp->num_vertices = chunk->size / 12;
|
bsp->num_vertices = chunk->size / 12;
|
||||||
if (bsp->num_vertices > 0) {
|
if (bsp->num_vertices > 0) {
|
||||||
bsp->vertices = pxl8_calloc(bsp->num_vertices, sizeof(pxl8_bsp_vertex));
|
bsp->vertices = pxl8_calloc(bsp->num_vertices, sizeof(demo3d_bsp_vertex));
|
||||||
if (!bsp->vertices) goto error_cleanup;
|
if (!bsp->vertices) goto error_cleanup;
|
||||||
pxl8_stream_seek(&stream, chunk->offset);
|
pxl8_stream_seek(&stream, chunk->offset);
|
||||||
for (u32 i = 0; i < bsp->num_vertices; i++) {
|
for (u32 i = 0; i < bsp->num_vertices; i++) {
|
||||||
|
|
@ -123,7 +123,7 @@ pxl8_result pxl8_bsp_load(const char* path, pxl8_bsp* bsp) {
|
||||||
if (!validate_chunk(chunk, 4, file_size)) goto error_cleanup;
|
if (!validate_chunk(chunk, 4, file_size)) goto error_cleanup;
|
||||||
bsp->num_edges = chunk->size / 4;
|
bsp->num_edges = chunk->size / 4;
|
||||||
if (bsp->num_edges > 0) {
|
if (bsp->num_edges > 0) {
|
||||||
bsp->edges = pxl8_calloc(bsp->num_edges, sizeof(pxl8_bsp_edge));
|
bsp->edges = pxl8_calloc(bsp->num_edges, sizeof(demo3d_bsp_edge));
|
||||||
pxl8_stream_seek(&stream, chunk->offset);
|
pxl8_stream_seek(&stream, chunk->offset);
|
||||||
for (u32 i = 0; i < bsp->num_edges; i++) {
|
for (u32 i = 0; i < bsp->num_edges; i++) {
|
||||||
bsp->edges[i].vertex[0] = pxl8_read_u16(&stream);
|
bsp->edges[i].vertex[0] = pxl8_read_u16(&stream);
|
||||||
|
|
@ -146,7 +146,7 @@ pxl8_result pxl8_bsp_load(const char* path, pxl8_bsp* bsp) {
|
||||||
if (!validate_chunk(chunk, 20, file_size)) goto error_cleanup;
|
if (!validate_chunk(chunk, 20, file_size)) goto error_cleanup;
|
||||||
bsp->num_planes = chunk->size / 20;
|
bsp->num_planes = chunk->size / 20;
|
||||||
if (bsp->num_planes > 0) {
|
if (bsp->num_planes > 0) {
|
||||||
bsp->planes = pxl8_calloc(bsp->num_planes, sizeof(pxl8_bsp_plane));
|
bsp->planes = pxl8_calloc(bsp->num_planes, sizeof(demo3d_bsp_plane));
|
||||||
pxl8_stream_seek(&stream, chunk->offset);
|
pxl8_stream_seek(&stream, chunk->offset);
|
||||||
for (u32 i = 0; i < bsp->num_planes; i++) {
|
for (u32 i = 0; i < bsp->num_planes; i++) {
|
||||||
bsp->planes[i].normal = read_vec3(&stream);
|
bsp->planes[i].normal = read_vec3(&stream);
|
||||||
|
|
@ -159,7 +159,7 @@ pxl8_result pxl8_bsp_load(const char* path, pxl8_bsp* bsp) {
|
||||||
if (!validate_chunk(chunk, 20, file_size)) goto error_cleanup;
|
if (!validate_chunk(chunk, 20, file_size)) goto error_cleanup;
|
||||||
bsp->num_faces = chunk->size / 20;
|
bsp->num_faces = chunk->size / 20;
|
||||||
if (bsp->num_faces > 0) {
|
if (bsp->num_faces > 0) {
|
||||||
bsp->faces = pxl8_calloc(bsp->num_faces, sizeof(pxl8_bsp_face));
|
bsp->faces = pxl8_calloc(bsp->num_faces, sizeof(demo3d_bsp_face));
|
||||||
pxl8_stream_seek(&stream, chunk->offset);
|
pxl8_stream_seek(&stream, chunk->offset);
|
||||||
for (u32 i = 0; i < bsp->num_faces; i++) {
|
for (u32 i = 0; i < bsp->num_faces; i++) {
|
||||||
bsp->faces[i].plane_id = pxl8_read_u16(&stream);
|
bsp->faces[i].plane_id = pxl8_read_u16(&stream);
|
||||||
|
|
@ -182,7 +182,7 @@ pxl8_result pxl8_bsp_load(const char* path, pxl8_bsp* bsp) {
|
||||||
if (!validate_chunk(chunk, 24, file_size)) goto error_cleanup;
|
if (!validate_chunk(chunk, 24, file_size)) goto error_cleanup;
|
||||||
bsp->num_nodes = chunk->size / 24;
|
bsp->num_nodes = chunk->size / 24;
|
||||||
if (bsp->num_nodes > 0) {
|
if (bsp->num_nodes > 0) {
|
||||||
bsp->nodes = pxl8_calloc(bsp->num_nodes, sizeof(pxl8_bsp_node));
|
bsp->nodes = pxl8_calloc(bsp->num_nodes, sizeof(demo3d_bsp_node));
|
||||||
pxl8_stream_seek(&stream, chunk->offset);
|
pxl8_stream_seek(&stream, chunk->offset);
|
||||||
for (u32 i = 0; i < bsp->num_nodes; i++) {
|
for (u32 i = 0; i < bsp->num_nodes; i++) {
|
||||||
bsp->nodes[i].plane_id = pxl8_read_u32(&stream);
|
bsp->nodes[i].plane_id = pxl8_read_u32(&stream);
|
||||||
|
|
@ -209,7 +209,7 @@ pxl8_result pxl8_bsp_load(const char* path, pxl8_bsp* bsp) {
|
||||||
if (!validate_chunk(chunk, 28, file_size)) goto error_cleanup;
|
if (!validate_chunk(chunk, 28, file_size)) goto error_cleanup;
|
||||||
bsp->num_leafs = chunk->size / 28;
|
bsp->num_leafs = chunk->size / 28;
|
||||||
if (bsp->num_leafs > 0) {
|
if (bsp->num_leafs > 0) {
|
||||||
bsp->leafs = pxl8_calloc(bsp->num_leafs, sizeof(pxl8_bsp_leaf));
|
bsp->leafs = pxl8_calloc(bsp->num_leafs, sizeof(demo3d_bsp_leaf));
|
||||||
pxl8_stream_seek(&stream, chunk->offset);
|
pxl8_stream_seek(&stream, chunk->offset);
|
||||||
for (u32 i = 0; i < bsp->num_leafs; i++) {
|
for (u32 i = 0; i < bsp->num_leafs; i++) {
|
||||||
bsp->leafs[i].contents = pxl8_read_i32(&stream);
|
bsp->leafs[i].contents = pxl8_read_i32(&stream);
|
||||||
|
|
@ -247,7 +247,7 @@ pxl8_result pxl8_bsp_load(const char* path, pxl8_bsp* bsp) {
|
||||||
if (!validate_chunk(chunk, 64, file_size)) goto error_cleanup;
|
if (!validate_chunk(chunk, 64, file_size)) goto error_cleanup;
|
||||||
bsp->num_models = chunk->size / 64;
|
bsp->num_models = chunk->size / 64;
|
||||||
if (bsp->num_models > 0) {
|
if (bsp->num_models > 0) {
|
||||||
bsp->models = pxl8_calloc(bsp->num_models, sizeof(pxl8_bsp_model));
|
bsp->models = pxl8_calloc(bsp->num_models, sizeof(demo3d_bsp_model));
|
||||||
pxl8_stream_seek(&stream, chunk->offset);
|
pxl8_stream_seek(&stream, chunk->offset);
|
||||||
for (u32 i = 0; i < bsp->num_models; i++) {
|
for (u32 i = 0; i < bsp->num_models; i++) {
|
||||||
f32 minx = pxl8_read_f32(&stream);
|
f32 minx = pxl8_read_f32(&stream);
|
||||||
|
|
@ -289,7 +289,7 @@ pxl8_result pxl8_bsp_load(const char* path, pxl8_bsp* bsp) {
|
||||||
pxl8_free(file_data);
|
pxl8_free(file_data);
|
||||||
|
|
||||||
for (u32 i = 0; i < bsp->num_faces; i++) {
|
for (u32 i = 0; i < bsp->num_faces; i++) {
|
||||||
pxl8_bsp_face* face = &bsp->faces[i];
|
demo3d_bsp_face* face = &bsp->faces[i];
|
||||||
f32 min_x = 1e30f, min_y = 1e30f, min_z = 1e30f;
|
f32 min_x = 1e30f, min_y = 1e30f, min_z = 1e30f;
|
||||||
f32 max_x = -1e30f, max_y = -1e30f, max_z = -1e30f;
|
f32 max_x = -1e30f, max_y = -1e30f, max_z = -1e30f;
|
||||||
|
|
||||||
|
|
@ -297,7 +297,7 @@ pxl8_result pxl8_bsp_load(const char* path, pxl8_bsp* bsp) {
|
||||||
i32 surfedge_idx = face->first_edge + j;
|
i32 surfedge_idx = face->first_edge + j;
|
||||||
u32 vert_idx;
|
u32 vert_idx;
|
||||||
|
|
||||||
if (!pxl8_bsp_get_edge_vertex(bsp, surfedge_idx, &vert_idx)) continue;
|
if (!demo3d_bsp_get_edge_vertex(bsp, surfedge_idx, &vert_idx)) continue;
|
||||||
|
|
||||||
pxl8_vec3 v = bsp->vertices[vert_idx].position;
|
pxl8_vec3 v = bsp->vertices[vert_idx].position;
|
||||||
|
|
||||||
|
|
@ -321,11 +321,11 @@ pxl8_result pxl8_bsp_load(const char* path, pxl8_bsp* bsp) {
|
||||||
error_cleanup:
|
error_cleanup:
|
||||||
pxl8_error("BSP chunk validation failed: %s", path);
|
pxl8_error("BSP chunk validation failed: %s", path);
|
||||||
pxl8_free(file_data);
|
pxl8_free(file_data);
|
||||||
pxl8_bsp_destroy(bsp);
|
demo3d_bsp_destroy(bsp);
|
||||||
return PXL8_ERROR_INVALID_FORMAT;
|
return PXL8_ERROR_INVALID_FORMAT;
|
||||||
}
|
}
|
||||||
|
|
||||||
void pxl8_bsp_destroy(pxl8_bsp* bsp) {
|
void demo3d_bsp_destroy(demo3d_bsp* bsp) {
|
||||||
if (!bsp) return;
|
if (!bsp) return;
|
||||||
|
|
||||||
pxl8_free(bsp->cell_portals);
|
pxl8_free(bsp->cell_portals);
|
||||||
|
|
@ -347,14 +347,14 @@ void pxl8_bsp_destroy(pxl8_bsp* bsp) {
|
||||||
memset(bsp, 0, sizeof(*bsp));
|
memset(bsp, 0, sizeof(*bsp));
|
||||||
}
|
}
|
||||||
|
|
||||||
i32 pxl8_bsp_find_leaf(const pxl8_bsp* bsp, pxl8_vec3 pos) {
|
i32 demo3d_bsp_find_leaf(const demo3d_bsp* bsp, pxl8_vec3 pos) {
|
||||||
if (!bsp || bsp->num_nodes == 0) return -1;
|
if (!bsp || bsp->num_nodes == 0) return -1;
|
||||||
|
|
||||||
i32 node_id = 0;
|
i32 node_id = 0;
|
||||||
|
|
||||||
while (node_id >= 0) {
|
while (node_id >= 0) {
|
||||||
const pxl8_bsp_node* node = &bsp->nodes[node_id];
|
const demo3d_bsp_node* node = &bsp->nodes[node_id];
|
||||||
const pxl8_bsp_plane* plane = &bsp->planes[node->plane_id];
|
const demo3d_bsp_plane* plane = &bsp->planes[node->plane_id];
|
||||||
|
|
||||||
f32 dist = pxl8_vec3_dot(pos, plane->normal) - plane->dist;
|
f32 dist = pxl8_vec3_dot(pos, plane->normal) - plane->dist;
|
||||||
node_id = node->children[dist < 0 ? 1 : 0];
|
node_id = node->children[dist < 0 ? 1 : 0];
|
||||||
|
|
@ -364,7 +364,7 @@ i32 pxl8_bsp_find_leaf(const pxl8_bsp* bsp, pxl8_vec3 pos) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool pxl8_bsp_is_leaf_visible(const pxl8_bsp* bsp, i32 leaf_from, i32 leaf_to) {
|
bool demo3d_bsp_is_leaf_visible(const demo3d_bsp* bsp, i32 leaf_from, i32 leaf_to) {
|
||||||
if (!bsp || !bsp->visdata || bsp->visdata_size == 0) return true;
|
if (!bsp || !bsp->visdata || bsp->visdata_size == 0) return true;
|
||||||
if (leaf_from < 0 || leaf_to < 0) return true;
|
if (leaf_from < 0 || leaf_to < 0) return true;
|
||||||
if ((u32)leaf_from >= bsp->num_leafs || (u32)leaf_to >= bsp->num_leafs) return true;
|
if ((u32)leaf_from >= bsp->num_leafs || (u32)leaf_to >= bsp->num_leafs) return true;
|
||||||
|
|
@ -401,8 +401,8 @@ bool pxl8_bsp_is_leaf_visible(const pxl8_bsp* bsp, i32 leaf_from, i32 leaf_to) {
|
||||||
return out > byte_idx ? false : true;
|
return out > byte_idx ? false : true;
|
||||||
}
|
}
|
||||||
|
|
||||||
pxl8_bsp_pvs pxl8_bsp_decompress_pvs(const pxl8_bsp* bsp, i32 leaf) {
|
demo3d_bsp_pvs demo3d_bsp_decompress_pvs(const demo3d_bsp* bsp, i32 leaf) {
|
||||||
pxl8_bsp_pvs pvs = {0};
|
demo3d_bsp_pvs pvs = {0};
|
||||||
|
|
||||||
u32 row = (bsp->num_leafs + 7) >> 3;
|
u32 row = (bsp->num_leafs + 7) >> 3;
|
||||||
pvs.data = pxl8_malloc(row);
|
pvs.data = pxl8_malloc(row);
|
||||||
|
|
@ -441,7 +441,7 @@ pxl8_bsp_pvs pxl8_bsp_decompress_pvs(const pxl8_bsp* bsp, i32 leaf) {
|
||||||
return pvs;
|
return pvs;
|
||||||
}
|
}
|
||||||
|
|
||||||
void pxl8_bsp_pvs_destroy(pxl8_bsp_pvs* pvs) {
|
void demo3d_bsp_pvs_destroy(demo3d_bsp_pvs* pvs) {
|
||||||
if (pvs) {
|
if (pvs) {
|
||||||
pxl8_free(pvs->data);
|
pxl8_free(pvs->data);
|
||||||
pvs->data = NULL;
|
pvs->data = NULL;
|
||||||
|
|
@ -449,7 +449,7 @@ void pxl8_bsp_pvs_destroy(pxl8_bsp_pvs* pvs) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool pxl8_bsp_pvs_is_visible(const pxl8_bsp_pvs* pvs, i32 leaf) {
|
bool demo3d_bsp_pvs_is_visible(const demo3d_bsp_pvs* pvs, i32 leaf) {
|
||||||
if (!pvs || !pvs->data || leaf < 0) return true;
|
if (!pvs || !pvs->data || leaf < 0) return true;
|
||||||
u32 byte_idx = (u32)leaf >> 3;
|
u32 byte_idx = (u32)leaf >> 3;
|
||||||
u32 bit_idx = (u32)leaf & 7;
|
u32 bit_idx = (u32)leaf & 7;
|
||||||
|
|
@ -457,8 +457,8 @@ bool pxl8_bsp_pvs_is_visible(const pxl8_bsp_pvs* pvs, i32 leaf) {
|
||||||
return (pvs->data[byte_idx] & (1 << bit_idx)) != 0;
|
return (pvs->data[byte_idx] & (1 << bit_idx)) != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
pxl8_bsp_lightmap pxl8_bsp_lightmap_uniform(u8 r, u8 g, u8 b) {
|
demo3d_bsp_lightmap demo3d_bsp_lightmap_uniform(u8 r, u8 g, u8 b) {
|
||||||
return (pxl8_bsp_lightmap){
|
return (demo3d_bsp_lightmap){
|
||||||
.color = {r, g, b},
|
.color = {r, g, b},
|
||||||
.height = 0,
|
.height = 0,
|
||||||
.offset = 0,
|
.offset = 0,
|
||||||
|
|
@ -466,8 +466,8 @@ pxl8_bsp_lightmap pxl8_bsp_lightmap_uniform(u8 r, u8 g, u8 b) {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
pxl8_bsp_lightmap pxl8_bsp_lightmap_mapped(u8 width, u8 height, u32 offset) {
|
demo3d_bsp_lightmap demo3d_bsp_lightmap_mapped(u8 width, u8 height, u32 offset) {
|
||||||
return (pxl8_bsp_lightmap){
|
return (demo3d_bsp_lightmap){
|
||||||
.color = {0, 0, 0},
|
.color = {0, 0, 0},
|
||||||
.height = height,
|
.height = height,
|
||||||
.offset = offset,
|
.offset = offset,
|
||||||
|
|
@ -475,7 +475,7 @@ pxl8_bsp_lightmap pxl8_bsp_lightmap_mapped(u8 width, u8 height, u32 offset) {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
u8 pxl8_bsp_light_at(const pxl8_bsp* bsp, f32 x, f32 y, f32 z, u8 ambient) {
|
u8 demo3d_bsp_light_at(const demo3d_bsp* bsp, f32 x, f32 y, f32 z, u8 ambient) {
|
||||||
if (!bsp || !bsp->vertices || !bsp->vertex_lights) return 255;
|
if (!bsp || !bsp->vertices || !bsp->vertex_lights) return 255;
|
||||||
|
|
||||||
f32 best_dist = FLT_MAX;
|
f32 best_dist = FLT_MAX;
|
||||||
|
|
@ -501,17 +501,17 @@ u8 pxl8_bsp_light_at(const pxl8_bsp* bsp, f32 x, f32 y, f32 z, u8 ambient) {
|
||||||
return (u8)(combined > 255.0f ? 255.0f : combined);
|
return (u8)(combined > 255.0f ? 255.0f : combined);
|
||||||
}
|
}
|
||||||
|
|
||||||
pxl8_bsp_lightmap_sample pxl8_bsp_sample_lightmap(const pxl8_bsp* bsp, u32 face_idx, f32 u, f32 v) {
|
demo3d_bsp_lightmap_sample demo3d_bsp_sample_lightmap(const demo3d_bsp* bsp, u32 face_idx, f32 u, f32 v) {
|
||||||
pxl8_bsp_lightmap_sample white = {255, 255, 255};
|
demo3d_bsp_lightmap_sample white = {255, 255, 255};
|
||||||
|
|
||||||
if (!bsp || !bsp->lightmaps || face_idx >= bsp->num_lightmaps) {
|
if (!bsp || !bsp->lightmaps || face_idx >= bsp->num_lightmaps) {
|
||||||
return white;
|
return white;
|
||||||
}
|
}
|
||||||
|
|
||||||
const pxl8_bsp_lightmap* lm = &bsp->lightmaps[face_idx];
|
const demo3d_bsp_lightmap* lm = &bsp->lightmaps[face_idx];
|
||||||
|
|
||||||
if (lm->width == 0) {
|
if (lm->width == 0) {
|
||||||
return (pxl8_bsp_lightmap_sample){lm->color[2], lm->color[1], lm->color[0]};
|
return (demo3d_bsp_lightmap_sample){lm->color[2], lm->color[1], lm->color[0]};
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!bsp->lightdata || bsp->lightdata_size == 0) {
|
if (!bsp->lightdata || bsp->lightdata_size == 0) {
|
||||||
|
|
@ -564,19 +564,19 @@ pxl8_bsp_lightmap_sample pxl8_bsp_sample_lightmap(const pxl8_bsp* bsp, u32 face_
|
||||||
u8 g = (u8)(g00 * inv_x * inv_y + g10 * frac_x * inv_y + g01 * inv_x * frac_y + g11 * frac_x * frac_y);
|
u8 g = (u8)(g00 * inv_x * inv_y + g10 * frac_x * inv_y + g01 * inv_x * frac_y + g11 * frac_x * frac_y);
|
||||||
u8 b = (u8)(b00 * inv_x * inv_y + b10 * frac_x * inv_y + b01 * inv_x * frac_y + b11 * frac_x * frac_y);
|
u8 b = (u8)(b00 * inv_x * inv_y + b10 * frac_x * inv_y + b01 * inv_x * frac_y + b11 * frac_x * frac_y);
|
||||||
|
|
||||||
return (pxl8_bsp_lightmap_sample){b, g, r};
|
return (demo3d_bsp_lightmap_sample){b, g, r};
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 pxl8_bsp_face_count(const pxl8_bsp* bsp) {
|
u32 demo3d_bsp_face_count(const demo3d_bsp* bsp) {
|
||||||
if (!bsp) return 0;
|
if (!bsp) return 0;
|
||||||
return bsp->num_faces;
|
return bsp->num_faces;
|
||||||
}
|
}
|
||||||
|
|
||||||
pxl8_vec3 pxl8_bsp_face_normal(const pxl8_bsp* bsp, u32 face_id) {
|
pxl8_vec3 demo3d_bsp_face_normal(const demo3d_bsp* bsp, u32 face_id) {
|
||||||
pxl8_vec3 up = {0, 1, 0};
|
pxl8_vec3 up = {0, 1, 0};
|
||||||
if (!bsp || face_id >= bsp->num_faces) return up;
|
if (!bsp || face_id >= bsp->num_faces) return up;
|
||||||
|
|
||||||
const pxl8_bsp_face* face = &bsp->faces[face_id];
|
const demo3d_bsp_face* face = &bsp->faces[face_id];
|
||||||
if (face->plane_id >= bsp->num_planes) return up;
|
if (face->plane_id >= bsp->num_planes) return up;
|
||||||
|
|
||||||
pxl8_vec3 normal = bsp->planes[face->plane_id].normal;
|
pxl8_vec3 normal = bsp->planes[face->plane_id].normal;
|
||||||
|
|
@ -588,7 +588,7 @@ pxl8_vec3 pxl8_bsp_face_normal(const pxl8_bsp* bsp, u32 face_id) {
|
||||||
return normal;
|
return normal;
|
||||||
}
|
}
|
||||||
|
|
||||||
void pxl8_bsp_face_set_material(pxl8_bsp* bsp, u32 face_id, u16 material_id) {
|
void demo3d_bsp_face_set_material(demo3d_bsp* bsp, u32 face_id, u16 material_id) {
|
||||||
if (!bsp || face_id >= bsp->num_faces) return;
|
if (!bsp || face_id >= bsp->num_faces) return;
|
||||||
bsp->faces[face_id].material_id = material_id;
|
bsp->faces[face_id].material_id = material_id;
|
||||||
}
|
}
|
||||||
162
demo3d/client/bsp/demo3d_bsp.h
Normal file
162
demo3d/client/bsp/demo3d_bsp.h
Normal file
|
|
@ -0,0 +1,162 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "pxl8_math.h"
|
||||||
|
#include "pxl8_types.h"
|
||||||
|
|
||||||
|
typedef struct demo3d_bsp_edge {
|
||||||
|
u16 vertex[2];
|
||||||
|
} demo3d_bsp_edge;
|
||||||
|
|
||||||
|
typedef struct demo3d_bsp_face {
|
||||||
|
u32 first_edge;
|
||||||
|
u32 lightmap_offset;
|
||||||
|
u16 num_edges;
|
||||||
|
u16 plane_id;
|
||||||
|
u16 side;
|
||||||
|
|
||||||
|
u8 styles[4];
|
||||||
|
u16 material_id;
|
||||||
|
|
||||||
|
pxl8_vec3 aabb_min;
|
||||||
|
pxl8_vec3 aabb_max;
|
||||||
|
} demo3d_bsp_face;
|
||||||
|
|
||||||
|
typedef struct demo3d_bsp_leaf {
|
||||||
|
u8 ambient_level[4];
|
||||||
|
i32 contents;
|
||||||
|
|
||||||
|
u16 first_marksurface;
|
||||||
|
i16 maxs[3];
|
||||||
|
i16 mins[3];
|
||||||
|
u16 num_marksurfaces;
|
||||||
|
|
||||||
|
i32 visofs;
|
||||||
|
} demo3d_bsp_leaf;
|
||||||
|
|
||||||
|
typedef struct demo3d_bsp_model {
|
||||||
|
i32 first_face;
|
||||||
|
i32 headnode[4];
|
||||||
|
f32 maxs[3];
|
||||||
|
f32 mins[3];
|
||||||
|
i32 num_faces;
|
||||||
|
|
||||||
|
pxl8_vec3 origin;
|
||||||
|
i32 visleafs;
|
||||||
|
} demo3d_bsp_model;
|
||||||
|
|
||||||
|
typedef struct demo3d_bsp_node {
|
||||||
|
i32 children[2];
|
||||||
|
|
||||||
|
u16 first_face;
|
||||||
|
i16 maxs[3];
|
||||||
|
i16 mins[3];
|
||||||
|
u16 num_faces;
|
||||||
|
|
||||||
|
u32 plane_id;
|
||||||
|
} demo3d_bsp_node;
|
||||||
|
|
||||||
|
typedef struct demo3d_bsp_plane {
|
||||||
|
f32 dist;
|
||||||
|
pxl8_vec3 normal;
|
||||||
|
i32 type;
|
||||||
|
} demo3d_bsp_plane;
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct demo3d_bsp_vertex {
|
||||||
|
pxl8_vec3 position;
|
||||||
|
} demo3d_bsp_vertex;
|
||||||
|
|
||||||
|
typedef struct demo3d_bsp_lightmap {
|
||||||
|
u8 color[3];
|
||||||
|
u8 height;
|
||||||
|
u32 offset;
|
||||||
|
u8 width;
|
||||||
|
} demo3d_bsp_lightmap;
|
||||||
|
|
||||||
|
typedef struct demo3d_bsp_lightmap_sample {
|
||||||
|
u8 b;
|
||||||
|
u8 g;
|
||||||
|
u8 r;
|
||||||
|
} demo3d_bsp_lightmap_sample;
|
||||||
|
|
||||||
|
typedef struct demo3d_bsp_pvs {
|
||||||
|
u8* data;
|
||||||
|
u32 size;
|
||||||
|
} demo3d_bsp_pvs;
|
||||||
|
|
||||||
|
typedef struct demo3d_bsp_portal {
|
||||||
|
f32 x0, z0;
|
||||||
|
f32 x1, z1;
|
||||||
|
u32 target_leaf;
|
||||||
|
} demo3d_bsp_portal;
|
||||||
|
|
||||||
|
typedef struct demo3d_bsp_cell_portals {
|
||||||
|
demo3d_bsp_portal portals[4];
|
||||||
|
u8 num_portals;
|
||||||
|
} demo3d_bsp_cell_portals;
|
||||||
|
|
||||||
|
typedef struct demo3d_bsp {
|
||||||
|
demo3d_bsp_cell_portals* cell_portals;
|
||||||
|
demo3d_bsp_edge* edges;
|
||||||
|
demo3d_bsp_face* faces;
|
||||||
|
demo3d_bsp_leaf* leafs;
|
||||||
|
u8* lightdata;
|
||||||
|
demo3d_bsp_lightmap* lightmaps;
|
||||||
|
u16* marksurfaces;
|
||||||
|
demo3d_bsp_model* models;
|
||||||
|
demo3d_bsp_node* nodes;
|
||||||
|
demo3d_bsp_plane* planes;
|
||||||
|
i32* surfedges;
|
||||||
|
u32* vertex_lights;
|
||||||
|
demo3d_bsp_vertex* vertices;
|
||||||
|
u8* visdata;
|
||||||
|
f32* heightfield;
|
||||||
|
|
||||||
|
u32 lightdata_size;
|
||||||
|
u32 num_cell_portals;
|
||||||
|
u32 num_edges;
|
||||||
|
u32 num_faces;
|
||||||
|
u32 num_leafs;
|
||||||
|
u32 num_lightmaps;
|
||||||
|
u32 num_marksurfaces;
|
||||||
|
u32 num_models;
|
||||||
|
u32 num_nodes;
|
||||||
|
u32 num_planes;
|
||||||
|
u32 num_surfedges;
|
||||||
|
u32 num_vertex_lights;
|
||||||
|
u32 num_vertices;
|
||||||
|
u32 num_heightfield;
|
||||||
|
f32 heightfield_ox;
|
||||||
|
f32 heightfield_oz;
|
||||||
|
f32 heightfield_cell_size;
|
||||||
|
u16 heightfield_w;
|
||||||
|
u16 heightfield_h;
|
||||||
|
u32 visdata_size;
|
||||||
|
f32 bounds_min_x;
|
||||||
|
f32 bounds_min_z;
|
||||||
|
f32 bounds_max_x;
|
||||||
|
f32 bounds_max_z;
|
||||||
|
} demo3d_bsp;
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
demo3d_bsp_pvs demo3d_bsp_decompress_pvs(const demo3d_bsp* bsp, i32 leaf);
|
||||||
|
void demo3d_bsp_destroy(demo3d_bsp* bsp);
|
||||||
|
u32 demo3d_bsp_face_count(const demo3d_bsp* bsp);
|
||||||
|
pxl8_vec3 demo3d_bsp_face_normal(const demo3d_bsp* bsp, u32 face_id);
|
||||||
|
void demo3d_bsp_face_set_material(demo3d_bsp* bsp, u32 face_id, u16 material_id);
|
||||||
|
i32 demo3d_bsp_find_leaf(const demo3d_bsp* bsp, pxl8_vec3 pos);
|
||||||
|
bool demo3d_bsp_is_leaf_visible(const demo3d_bsp* bsp, i32 leaf_from, i32 leaf_to);
|
||||||
|
demo3d_bsp_lightmap demo3d_bsp_lightmap_mapped(u8 width, u8 height, u32 offset);
|
||||||
|
demo3d_bsp_lightmap demo3d_bsp_lightmap_uniform(u8 r, u8 g, u8 b);
|
||||||
|
pxl8_result demo3d_bsp_load(const char* path, demo3d_bsp* bsp);
|
||||||
|
void demo3d_bsp_pvs_destroy(demo3d_bsp_pvs* pvs);
|
||||||
|
bool demo3d_bsp_pvs_is_visible(const demo3d_bsp_pvs* pvs, i32 leaf);
|
||||||
|
u8 demo3d_bsp_light_at(const demo3d_bsp* bsp, f32 x, f32 y, f32 z, u8 ambient);
|
||||||
|
demo3d_bsp_lightmap_sample demo3d_bsp_sample_lightmap(const demo3d_bsp* bsp, u32 face_idx, f32 u, f32 v);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
#include "pxl8_bsp_render.h"
|
#include "demo3d_bsp_render.h"
|
||||||
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
|
|
@ -7,7 +7,7 @@
|
||||||
#include "pxl8_mem.h"
|
#include "pxl8_mem.h"
|
||||||
#include "pxl8_mesh.h"
|
#include "pxl8_mesh.h"
|
||||||
|
|
||||||
static inline bool pxl8_bsp_get_edge_vertex(const pxl8_bsp* bsp, i32 surfedge_idx, u32* out_vert_idx) {
|
static inline bool demo3d_bsp_get_edge_vertex(const demo3d_bsp* bsp, i32 surfedge_idx, u32* out_vert_idx) {
|
||||||
if (surfedge_idx >= (i32)bsp->num_surfedges) return false;
|
if (surfedge_idx >= (i32)bsp->num_surfedges) return false;
|
||||||
|
|
||||||
i32 edge_idx = bsp->surfedges[surfedge_idx];
|
i32 edge_idx = bsp->surfedges[surfedge_idx];
|
||||||
|
|
@ -26,14 +26,14 @@ static inline bool pxl8_bsp_get_edge_vertex(const pxl8_bsp* bsp, i32 surfedge_id
|
||||||
return *out_vert_idx < bsp->num_vertices;
|
return *out_vert_idx < bsp->num_vertices;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline bool face_in_frustum(const pxl8_bsp* bsp, u32 face_id, const pxl8_frustum* frustum) {
|
static inline bool face_in_frustum(const demo3d_bsp* bsp, u32 face_id, const pxl8_frustum* frustum) {
|
||||||
const pxl8_bsp_face* face = &bsp->faces[face_id];
|
const demo3d_bsp_face* face = &bsp->faces[face_id];
|
||||||
return pxl8_frustum_test_aabb(frustum, face->aabb_min, face->aabb_max);
|
return pxl8_frustum_test_aabb(frustum, face->aabb_min, face->aabb_max);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void collect_face_to_mesh(const pxl8_bsp* bsp, const pxl8_bsp_render_state* state,
|
static void collect_face_to_mesh(const demo3d_bsp* bsp, const demo3d_bsp_render_state* state,
|
||||||
u32 face_id, pxl8_mesh* mesh, u8 ambient) {
|
u32 face_id, pxl8_mesh* mesh, u8 ambient) {
|
||||||
const pxl8_bsp_face* face = &bsp->faces[face_id];
|
const demo3d_bsp_face* face = &bsp->faces[face_id];
|
||||||
if (face->num_edges < 3) return;
|
if (face->num_edges < 3) return;
|
||||||
|
|
||||||
pxl8_vec3 normal = {0, 1, 0};
|
pxl8_vec3 normal = {0, 1, 0};
|
||||||
|
|
@ -82,7 +82,7 @@ static void collect_face_to_mesh(const pxl8_bsp* bsp, const pxl8_bsp_render_stat
|
||||||
i32 surfedge_idx = face->first_edge + edge_i;
|
i32 surfedge_idx = face->first_edge + edge_i;
|
||||||
u32 vert_idx;
|
u32 vert_idx;
|
||||||
|
|
||||||
if (!pxl8_bsp_get_edge_vertex(bsp, surfedge_idx, &vert_idx)) {
|
if (!demo3d_bsp_get_edge_vertex(bsp, surfedge_idx, &vert_idx)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -119,8 +119,8 @@ static void collect_face_to_mesh(const pxl8_bsp* bsp, const pxl8_bsp_render_stat
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pxl8_bsp_render_state* pxl8_bsp_render_state_create(u32 num_faces) {
|
demo3d_bsp_render_state* demo3d_bsp_render_state_create(u32 num_faces) {
|
||||||
pxl8_bsp_render_state* state = pxl8_calloc(1, sizeof(pxl8_bsp_render_state));
|
demo3d_bsp_render_state* state = pxl8_calloc(1, sizeof(demo3d_bsp_render_state));
|
||||||
if (!state) return NULL;
|
if (!state) return NULL;
|
||||||
|
|
||||||
state->num_faces = num_faces;
|
state->num_faces = num_faces;
|
||||||
|
|
@ -135,15 +135,15 @@ pxl8_bsp_render_state* pxl8_bsp_render_state_create(u32 num_faces) {
|
||||||
return state;
|
return state;
|
||||||
}
|
}
|
||||||
|
|
||||||
void pxl8_bsp_render_state_destroy(pxl8_bsp_render_state* state) {
|
void demo3d_bsp_render_state_destroy(demo3d_bsp_render_state* state) {
|
||||||
if (!state) return;
|
if (!state) return;
|
||||||
pxl8_free(state->materials);
|
pxl8_free(state->materials);
|
||||||
pxl8_free(state->render_face_flags);
|
pxl8_free(state->render_face_flags);
|
||||||
pxl8_free(state);
|
pxl8_free(state);
|
||||||
}
|
}
|
||||||
|
|
||||||
void pxl8_bsp_render(pxl8_gfx* gfx, const pxl8_bsp* bsp,
|
void demo3d_bsp_render(pxl8_gfx* gfx, const demo3d_bsp* bsp,
|
||||||
pxl8_bsp_render_state* state,
|
demo3d_bsp_render_state* state,
|
||||||
const pxl8_gfx_draw_opts* opts) {
|
const pxl8_gfx_draw_opts* opts) {
|
||||||
if (!gfx || !bsp || !state || bsp->num_faces == 0) return;
|
if (!gfx || !bsp || !state || bsp->num_faces == 0) return;
|
||||||
if (!state->materials || state->num_materials == 0) return;
|
if (!state->materials || state->num_materials == 0) return;
|
||||||
|
|
@ -161,7 +161,7 @@ void pxl8_bsp_render(pxl8_gfx* gfx, const pxl8_bsp* bsp,
|
||||||
for (u32 mat = 0; mat < state->num_materials; mat++) {
|
for (u32 mat = 0; mat < state->num_materials; mat++) {
|
||||||
for (u32 face_id = 0; face_id < bsp->num_faces; face_id++) {
|
for (u32 face_id = 0; face_id < bsp->num_faces; face_id++) {
|
||||||
if (!state->render_face_flags[face_id]) continue;
|
if (!state->render_face_flags[face_id]) continue;
|
||||||
const pxl8_bsp_face* face = &bsp->faces[face_id];
|
const demo3d_bsp_face* face = &bsp->faces[face_id];
|
||||||
if (face->material_id != mat) continue;
|
if (face->material_id != mat) continue;
|
||||||
if (!face_in_frustum(bsp, face_id, frustum)) continue;
|
if (!face_in_frustum(bsp, face_id, frustum)) continue;
|
||||||
collect_face_to_mesh(bsp, state, face_id, mesh, ambient);
|
collect_face_to_mesh(bsp, state, face_id, mesh, ambient);
|
||||||
|
|
@ -177,7 +177,7 @@ void pxl8_bsp_render(pxl8_gfx* gfx, const pxl8_bsp* bsp,
|
||||||
pxl8_mesh_destroy(mesh);
|
pxl8_mesh_destroy(mesh);
|
||||||
}
|
}
|
||||||
|
|
||||||
void pxl8_bsp_set_material(pxl8_bsp_render_state* state, u16 material_id, const pxl8_gfx_material* material) {
|
void demo3d_bsp_set_material(demo3d_bsp_render_state* state, u16 material_id, const pxl8_gfx_material* material) {
|
||||||
if (!state || !material) return;
|
if (!state || !material) return;
|
||||||
|
|
||||||
if (material_id >= state->num_materials) {
|
if (material_id >= state->num_materials) {
|
||||||
29
demo3d/client/bsp/demo3d_bsp_render.h
Normal file
29
demo3d/client/bsp/demo3d_bsp_render.h
Normal file
|
|
@ -0,0 +1,29 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "demo3d_bsp.h"
|
||||||
|
#include "pxl8_gfx.h"
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
typedef struct demo3d_bsp_render_state {
|
||||||
|
pxl8_gfx_material* materials;
|
||||||
|
u8* render_face_flags;
|
||||||
|
u32 num_materials;
|
||||||
|
u32 num_faces;
|
||||||
|
bool exterior;
|
||||||
|
} demo3d_bsp_render_state;
|
||||||
|
|
||||||
|
demo3d_bsp_render_state* demo3d_bsp_render_state_create(u32 num_faces);
|
||||||
|
void demo3d_bsp_render_state_destroy(demo3d_bsp_render_state* state);
|
||||||
|
|
||||||
|
void demo3d_bsp_render(pxl8_gfx* gfx, const demo3d_bsp* bsp,
|
||||||
|
demo3d_bsp_render_state* state,
|
||||||
|
const pxl8_gfx_draw_opts* opts);
|
||||||
|
void demo3d_bsp_set_material(demo3d_bsp_render_state* state, u16 material_id,
|
||||||
|
const pxl8_gfx_material* material);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
218
demo3d/client/demo3d.c
Normal file
218
demo3d/client/demo3d.c
Normal file
|
|
@ -0,0 +1,218 @@
|
||||||
|
#include "pxl8_sys.h"
|
||||||
|
#include "pxl8_log.h"
|
||||||
|
#include "pxl8_mem.h"
|
||||||
|
#include "pxl8_script.h"
|
||||||
|
|
||||||
|
#include "demo3d_net.h"
|
||||||
|
#include "demo3d_world.h"
|
||||||
|
|
||||||
|
static const char* demo3d_ffi_cdefs =
|
||||||
|
"typedef struct demo3d_bsp demo3d_bsp;\n"
|
||||||
|
"\n"
|
||||||
|
"u32 demo3d_bsp_face_count(const demo3d_bsp* bsp);\n"
|
||||||
|
"pxl8_vec3 demo3d_bsp_face_normal(const demo3d_bsp* bsp, u32 face_id);\n"
|
||||||
|
"void demo3d_bsp_face_set_material(demo3d_bsp* bsp, u32 face_id, u16 material_id);\n"
|
||||||
|
"u8 demo3d_bsp_light_at(const demo3d_bsp* bsp, f32 x, f32 y, f32 z, u8 ambient);\n"
|
||||||
|
"\n"
|
||||||
|
"typedef struct demo3d_chunk {\n"
|
||||||
|
" u32 id;\n"
|
||||||
|
" u32 version;\n"
|
||||||
|
" demo3d_bsp* bsp;\n"
|
||||||
|
"} demo3d_chunk;\n"
|
||||||
|
"\n"
|
||||||
|
"typedef struct demo3d_world demo3d_world;\n"
|
||||||
|
"\n"
|
||||||
|
"typedef struct pxl8_ray {\n"
|
||||||
|
" pxl8_vec3 normal;\n"
|
||||||
|
" pxl8_vec3 point;\n"
|
||||||
|
" float fraction;\n"
|
||||||
|
" bool hit;\n"
|
||||||
|
"} pxl8_ray;\n"
|
||||||
|
"\n"
|
||||||
|
"demo3d_world* demo3d_get_world(pxl8* sys);\n"
|
||||||
|
"demo3d_chunk* demo3d_world_active_chunk(demo3d_world* world);\n"
|
||||||
|
"bool demo3d_world_point_solid(const demo3d_world* world, float x, float y, float z);\n"
|
||||||
|
"pxl8_ray demo3d_world_ray(const demo3d_world* world, pxl8_vec3 from, pxl8_vec3 to);\n"
|
||||||
|
"pxl8_ray demo3d_world_sweep(const demo3d_world* world, pxl8_vec3 from, pxl8_vec3 to, float radius);\n"
|
||||||
|
"void demo3d_world_render(demo3d_world* world, pxl8_gfx* gfx, pxl8_vec3 camera_pos);\n"
|
||||||
|
"void demo3d_world_set_bsp_material(demo3d_world* world, u16 material_id, const pxl8_gfx_material* material);\n"
|
||||||
|
"\n"
|
||||||
|
"typedef struct demo3d_sim_entity {\n"
|
||||||
|
" pxl8_vec3 pos;\n"
|
||||||
|
" pxl8_vec3 vel;\n"
|
||||||
|
" f32 yaw;\n"
|
||||||
|
" f32 pitch;\n"
|
||||||
|
" u32 flags;\n"
|
||||||
|
" u16 kind;\n"
|
||||||
|
" u16 _pad;\n"
|
||||||
|
"} demo3d_sim_entity;\n"
|
||||||
|
"\n"
|
||||||
|
"void demo3d_world_init_local_player(demo3d_world* world, f32 x, f32 y, f32 z);\n"
|
||||||
|
"void demo3d_world_set_look(demo3d_world* world, f32 yaw, f32 pitch);\n"
|
||||||
|
"demo3d_sim_entity* demo3d_world_local_player(demo3d_world* world);\n"
|
||||||
|
"\n"
|
||||||
|
"typedef struct demo3d_input_msg {\n"
|
||||||
|
" u32 buttons;\n"
|
||||||
|
" f32 look_dx;\n"
|
||||||
|
" f32 look_dy;\n"
|
||||||
|
" f32 move_x;\n"
|
||||||
|
" f32 move_y;\n"
|
||||||
|
" f32 yaw;\n"
|
||||||
|
" u64 tick;\n"
|
||||||
|
" u64 timestamp;\n"
|
||||||
|
"} demo3d_input_msg;\n"
|
||||||
|
"\n"
|
||||||
|
"typedef struct demo3d_sim_config {\n"
|
||||||
|
" f32 move_speed;\n"
|
||||||
|
" f32 ground_accel;\n"
|
||||||
|
" f32 air_accel;\n"
|
||||||
|
" f32 stop_speed;\n"
|
||||||
|
" f32 friction;\n"
|
||||||
|
" f32 gravity;\n"
|
||||||
|
" f32 jump_velocity;\n"
|
||||||
|
" f32 player_radius;\n"
|
||||||
|
" f32 player_height;\n"
|
||||||
|
" f32 max_pitch;\n"
|
||||||
|
"} demo3d_sim_config;\n"
|
||||||
|
"\n"
|
||||||
|
"typedef struct demo3d_sim_world {\n"
|
||||||
|
" const demo3d_bsp* chunks[9];\n"
|
||||||
|
" i32 center_cx;\n"
|
||||||
|
" i32 center_cz;\n"
|
||||||
|
" f32 chunk_size;\n"
|
||||||
|
"} demo3d_sim_world;\n"
|
||||||
|
"\n"
|
||||||
|
"void demo3d_sim_move_player(demo3d_sim_entity* ent, const demo3d_input_msg* input, const demo3d_sim_world* world, const demo3d_sim_config* cfg, f32 dt);\n"
|
||||||
|
"void demo3d_sim_integrate(demo3d_sim_entity* ent, const demo3d_sim_world* world, const demo3d_sim_config* cfg, f32 dt);\n"
|
||||||
|
"pxl8_vec3 demo3d_sim_trace(const demo3d_sim_world* world, pxl8_vec3 from, pxl8_vec3 to, f32 radius, f32 height);\n"
|
||||||
|
"bool demo3d_sim_check_ground(const demo3d_sim_world* world, pxl8_vec3 pos, f32 radius);\n"
|
||||||
|
"\n"
|
||||||
|
"demo3d_sim_world demo3d_world_sim_world(const demo3d_world* world, pxl8_vec3 pos);\n"
|
||||||
|
"void demo3d_world_set_sim_config(demo3d_world* world, const demo3d_sim_config* config);\n"
|
||||||
|
"void demo3d_world_push_input(demo3d_world* world, const demo3d_input_msg* input);\n"
|
||||||
|
"\n"
|
||||||
|
"typedef struct demo3d_net demo3d_net;\n"
|
||||||
|
"\n"
|
||||||
|
"typedef struct demo3d_entity_state {\n"
|
||||||
|
" u64 entity_id;\n"
|
||||||
|
" u8 userdata[56];\n"
|
||||||
|
"} demo3d_entity_state;\n"
|
||||||
|
"\n"
|
||||||
|
"typedef struct demo3d_snapshot_header {\n"
|
||||||
|
" u16 entity_count;\n"
|
||||||
|
" u16 event_count;\n"
|
||||||
|
" u64 player_id;\n"
|
||||||
|
" u64 tick;\n"
|
||||||
|
" f32 time;\n"
|
||||||
|
"} demo3d_snapshot_header;\n"
|
||||||
|
"\n"
|
||||||
|
"demo3d_net* demo3d_get_net(pxl8* sys);\n"
|
||||||
|
"bool demo3d_net_connected(const demo3d_net* ng);\n"
|
||||||
|
"i32 demo3d_net_spawn(demo3d_net* ng, f32 x, f32 y, f32 z, f32 yaw, f32 pitch);\n"
|
||||||
|
"bool demo3d_net_has_chunk(const demo3d_net* ng);\n"
|
||||||
|
"i32 demo3d_net_chunk_cx(const demo3d_net* ng);\n"
|
||||||
|
"i32 demo3d_net_chunk_cz(const demo3d_net* ng);\n"
|
||||||
|
"const demo3d_entity_state* demo3d_net_entities(const demo3d_net* ng);\n"
|
||||||
|
"u64 demo3d_net_player_id(const demo3d_net* ng);\n"
|
||||||
|
"const u8* demo3d_net_entity_userdata(const demo3d_net* ng, u64 entity_id);\n"
|
||||||
|
"const u8* demo3d_net_entity_prev_userdata(const demo3d_net* ng, u64 entity_id);\n"
|
||||||
|
"f32 demo3d_net_lerp_alpha(const demo3d_net* ng);\n"
|
||||||
|
"const demo3d_snapshot_header* demo3d_net_snapshot(const demo3d_net* ng);\n"
|
||||||
|
;
|
||||||
|
|
||||||
|
typedef struct demo3d_state {
|
||||||
|
demo3d_net* net;
|
||||||
|
demo3d_world* world;
|
||||||
|
} demo3d_state;
|
||||||
|
|
||||||
|
static pxl8_result demo3d_init(pxl8_game* game, void* userdata) {
|
||||||
|
(void)userdata;
|
||||||
|
demo3d_state* state = pxl8_calloc(1, sizeof(demo3d_state));
|
||||||
|
if (!state) return PXL8_ERROR_INITIALIZATION_FAILED;
|
||||||
|
game->userdata = state;
|
||||||
|
|
||||||
|
pxl8_script_add_ffi(game->script, demo3d_ffi_cdefs);
|
||||||
|
|
||||||
|
state->world = demo3d_world_create();
|
||||||
|
if (!state->world) {
|
||||||
|
pxl8_error("failed to create world");
|
||||||
|
return PXL8_ERROR_INITIALIZATION_FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
pxl8_net_config net_cfg = { .address = "127.0.0.1", .port = 7777 };
|
||||||
|
state->net = demo3d_net_create(&net_cfg);
|
||||||
|
if (state->net) {
|
||||||
|
demo3d_net_set_chunk_cache(state->net, demo3d_world_get_chunk_cache(state->world));
|
||||||
|
demo3d_net_set_world(state->net, state->world);
|
||||||
|
demo3d_net_connect(state->net);
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef PXL8_ASYNC_THREADS
|
||||||
|
if (state->net) {
|
||||||
|
demo3d_net_start_thread(state->net);
|
||||||
|
}
|
||||||
|
if (state->world) {
|
||||||
|
demo3d_world_start_sim_thread(state->world, state->net);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return PXL8_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void demo3d_update(pxl8_game* game, f32 dt, void* userdata) {
|
||||||
|
(void)userdata;
|
||||||
|
demo3d_state* state = (demo3d_state*)game->userdata;
|
||||||
|
|
||||||
|
#ifdef PXL8_ASYNC_THREADS
|
||||||
|
demo3d_net_update(state->net, dt);
|
||||||
|
#else
|
||||||
|
if (state->net) {
|
||||||
|
while (demo3d_net_poll(state->net)) {}
|
||||||
|
demo3d_net_update(state->net, dt);
|
||||||
|
demo3d_world_sync(state->world, state->net);
|
||||||
|
}
|
||||||
|
demo3d_world_update(state->world, dt);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
static void demo3d_quit(pxl8_game* game, void* userdata) {
|
||||||
|
(void)userdata;
|
||||||
|
demo3d_state* state = (demo3d_state*)game->userdata;
|
||||||
|
if (!state) return;
|
||||||
|
|
||||||
|
#ifdef PXL8_ASYNC_THREADS
|
||||||
|
if (state->world) {
|
||||||
|
demo3d_world_stop_sim_thread(state->world);
|
||||||
|
}
|
||||||
|
if (state->net) {
|
||||||
|
demo3d_net_stop_thread(state->net);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (state->net) demo3d_net_destroy(state->net);
|
||||||
|
if (state->world) demo3d_world_destroy(state->world);
|
||||||
|
|
||||||
|
pxl8_free(state);
|
||||||
|
game->userdata = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
demo3d_net* demo3d_get_net(pxl8* sys) {
|
||||||
|
pxl8_game* game = pxl8_get_game(sys);
|
||||||
|
if (!game || !game->userdata) return NULL;
|
||||||
|
return ((demo3d_state*)game->userdata)->net;
|
||||||
|
}
|
||||||
|
|
||||||
|
demo3d_world* demo3d_get_world(pxl8* sys) {
|
||||||
|
pxl8_game* game = pxl8_get_game(sys);
|
||||||
|
if (!game || !game->userdata) return NULL;
|
||||||
|
return ((demo3d_state*)game->userdata)->world;
|
||||||
|
}
|
||||||
|
|
||||||
|
void pxl8_register_game(pxl8* sys) {
|
||||||
|
pxl8_game_hooks hooks = {
|
||||||
|
.init = demo3d_init,
|
||||||
|
.update = demo3d_update,
|
||||||
|
.quit = demo3d_quit,
|
||||||
|
};
|
||||||
|
pxl8_set_game_hooks(sys, hooks);
|
||||||
|
}
|
||||||
297
demo3d/client/net/demo3d_net.c
Normal file
297
demo3d/client/net/demo3d_net.c
Normal file
|
|
@ -0,0 +1,297 @@
|
||||||
|
#include "pxl8_platform.h"
|
||||||
|
#include "demo3d_net.h"
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "pxl8_bytes.h"
|
||||||
|
#include "pxl8_log.h"
|
||||||
|
#include "pxl8_mem.h"
|
||||||
|
#include "demo3d_world.h"
|
||||||
|
#include "demo3d_chunk_cache.h"
|
||||||
|
|
||||||
|
static const demo3d_entity_state* find_entity(const demo3d_entity_state* entities, u16 count, u64 id) {
|
||||||
|
for (u16 i = 0; i < count; i++) {
|
||||||
|
if (entities[i].entity_id == id) return &entities[i];
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool dispatch_message(demo3d_net* ng, const u8* data, usize len) {
|
||||||
|
if (len < sizeof(demo3d_msg_header)) return false;
|
||||||
|
|
||||||
|
demo3d_msg_header hdr;
|
||||||
|
usize offset = demo3d_protocol_deserialize_header(data, len, &hdr);
|
||||||
|
|
||||||
|
if (hdr.type == DEMO3D_MSG_CHUNK) {
|
||||||
|
if (!ng->chunk_cache) return false;
|
||||||
|
demo3d_chunk_msg_header chunk_hdr;
|
||||||
|
offset += demo3d_protocol_deserialize_chunk_msg_header(data + offset, len - offset, &chunk_hdr);
|
||||||
|
const u8* payload = data + offset;
|
||||||
|
usize payload_len = chunk_hdr.payload_size;
|
||||||
|
if (payload_len > len - offset) payload_len = len - offset;
|
||||||
|
demo3d_chunk_cache_receive(ng->chunk_cache, &chunk_hdr, payload, payload_len);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hdr.type == DEMO3D_MSG_CHUNK_ENTER) {
|
||||||
|
demo3d_chunk_enter_msg chunk_msg;
|
||||||
|
demo3d_protocol_deserialize_chunk_enter(data + offset, len - offset, &chunk_msg);
|
||||||
|
ng->chunk_cx = chunk_msg.cx;
|
||||||
|
ng->chunk_cz = chunk_msg.cz;
|
||||||
|
ng->has_chunk = true;
|
||||||
|
pxl8_debug("Received CHUNK_ENTER cx=%d cz=%d", chunk_msg.cx, chunk_msg.cz);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hdr.type == DEMO3D_MSG_CHUNK_EXIT) {
|
||||||
|
ng->has_chunk = false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hdr.type != DEMO3D_MSG_SNAPSHOT) return false;
|
||||||
|
|
||||||
|
demo3d_snapshot_header snap;
|
||||||
|
offset += demo3d_protocol_deserialize_snapshot_header(data + offset, len - offset, &snap);
|
||||||
|
if (snap.tick <= ng->highest_tick) return false;
|
||||||
|
|
||||||
|
memcpy(ng->prev_entities, ng->entities, sizeof(ng->entities));
|
||||||
|
ng->prev_snapshot = ng->snapshot;
|
||||||
|
ng->highest_tick = snap.tick;
|
||||||
|
ng->snapshot = snap;
|
||||||
|
ng->interp_time = 0.0f;
|
||||||
|
|
||||||
|
u16 count = snap.entity_count;
|
||||||
|
if (count > DEMO3D_MAX_SNAPSHOT_ENTITIES) count = DEMO3D_MAX_SNAPSHOT_ENTITIES;
|
||||||
|
|
||||||
|
for (u16 i = 0; i < count; i++) {
|
||||||
|
offset += demo3d_protocol_deserialize_entity_state(data + offset, len - offset, &ng->entities[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
demo3d_net* demo3d_net_create(const pxl8_net_config* config) {
|
||||||
|
demo3d_net* ng = pxl8_calloc(1, sizeof(demo3d_net));
|
||||||
|
if (!ng) return NULL;
|
||||||
|
ng->transport = pxl8_net_create(config);
|
||||||
|
if (!ng->transport) {
|
||||||
|
pxl8_free(ng);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
return ng;
|
||||||
|
}
|
||||||
|
|
||||||
|
void demo3d_net_destroy(demo3d_net* ng) {
|
||||||
|
if (!ng) return;
|
||||||
|
pxl8_net_destroy(ng->transport);
|
||||||
|
pxl8_free(ng);
|
||||||
|
}
|
||||||
|
|
||||||
|
pxl8_result demo3d_net_connect(demo3d_net* ng) {
|
||||||
|
if (!ng) return PXL8_ERROR_INVALID_ARGUMENT;
|
||||||
|
return pxl8_net_connect(ng->transport);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool demo3d_net_connected(const demo3d_net* ng) {
|
||||||
|
return ng && pxl8_net_connected(ng->transport);
|
||||||
|
}
|
||||||
|
|
||||||
|
void demo3d_net_disconnect(demo3d_net* ng) {
|
||||||
|
if (!ng) return;
|
||||||
|
pxl8_net_disconnect(ng->transport);
|
||||||
|
}
|
||||||
|
|
||||||
|
const demo3d_entity_state* demo3d_net_entities(const demo3d_net* ng) {
|
||||||
|
if (!ng) return NULL;
|
||||||
|
return ng->entities;
|
||||||
|
}
|
||||||
|
|
||||||
|
const u8* demo3d_net_entity_prev_userdata(const demo3d_net* ng, u64 entity_id) {
|
||||||
|
if (!ng) return NULL;
|
||||||
|
const demo3d_entity_state* e = find_entity(ng->prev_entities, ng->prev_snapshot.entity_count, entity_id);
|
||||||
|
return e ? e->userdata : NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
const u8* demo3d_net_entity_userdata(const demo3d_net* ng, u64 entity_id) {
|
||||||
|
if (!ng) return NULL;
|
||||||
|
const demo3d_entity_state* e = find_entity(ng->entities, ng->snapshot.entity_count, entity_id);
|
||||||
|
return e ? e->userdata : NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
const demo3d_input_msg* demo3d_net_input_at(const demo3d_net* ng, u64 tick) {
|
||||||
|
if (!ng) return NULL;
|
||||||
|
if (tick < ng->input_oldest_tick) return NULL;
|
||||||
|
u64 age = tick - ng->input_oldest_tick;
|
||||||
|
if (age >= DEMO3D_NET_INPUT_HISTORY_SIZE) return NULL;
|
||||||
|
u64 idx = tick % DEMO3D_NET_INPUT_HISTORY_SIZE;
|
||||||
|
const demo3d_input_msg* msg = &ng->input_history[idx];
|
||||||
|
if (msg->tick != tick) return NULL;
|
||||||
|
return msg;
|
||||||
|
}
|
||||||
|
|
||||||
|
u64 demo3d_net_input_oldest_tick(const demo3d_net* ng) {
|
||||||
|
if (!ng) return 0;
|
||||||
|
return ng->input_oldest_tick;
|
||||||
|
}
|
||||||
|
|
||||||
|
void demo3d_net_input_push(demo3d_net* ng, const demo3d_input_msg* input) {
|
||||||
|
if (!ng || !input) return;
|
||||||
|
u64 idx = input->tick % DEMO3D_NET_INPUT_HISTORY_SIZE;
|
||||||
|
ng->input_history[idx] = *input;
|
||||||
|
ng->input_head = input->tick;
|
||||||
|
if (input->tick >= DEMO3D_NET_INPUT_HISTORY_SIZE) {
|
||||||
|
ng->input_oldest_tick = input->tick - DEMO3D_NET_INPUT_HISTORY_SIZE + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
f32 demo3d_net_lerp_alpha(const demo3d_net* ng) {
|
||||||
|
if (!ng) return 1.0f;
|
||||||
|
return ng->interp_time / (1.0f / DEMO3D_NET_TICK_RATE);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool demo3d_net_needs_correction(const demo3d_net* ng) {
|
||||||
|
if (!ng) return false;
|
||||||
|
if (ng->snapshot.tick == 0) return false;
|
||||||
|
if (ng->predicted_tick == 0) return false;
|
||||||
|
|
||||||
|
u64 player_id = ng->snapshot.player_id;
|
||||||
|
const demo3d_entity_state* server = find_entity(ng->entities, ng->snapshot.entity_count, player_id);
|
||||||
|
if (!server) return false;
|
||||||
|
|
||||||
|
return memcmp(server->userdata, ng->predicted_state, DEMO3D_NET_USERDATA_SIZE) != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
u64 demo3d_net_player_id(const demo3d_net* ng) {
|
||||||
|
if (!ng) return 0;
|
||||||
|
return ng->snapshot.player_id;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool demo3d_net_poll(demo3d_net* ng) {
|
||||||
|
if (!ng || !pxl8_net_connected(ng->transport)) return false;
|
||||||
|
|
||||||
|
u8 recv_buf[4096];
|
||||||
|
usize len = pxl8_net_recv(ng->transport, recv_buf, sizeof(recv_buf));
|
||||||
|
u64 prev_tick = ng->highest_tick;
|
||||||
|
if (!dispatch_message(ng, recv_buf, len)) return false;
|
||||||
|
|
||||||
|
if (ng->highest_tick > prev_tick && ng->world) {
|
||||||
|
demo3d_world_reconcile(ng->world, ng, 1.0f / 30.0f);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
u8* demo3d_net_predicted_state(demo3d_net* ng) {
|
||||||
|
if (!ng) return NULL;
|
||||||
|
return ng->predicted_state;
|
||||||
|
}
|
||||||
|
|
||||||
|
void demo3d_net_predicted_tick_set(demo3d_net* ng, u64 tick) {
|
||||||
|
if (!ng) return;
|
||||||
|
ng->predicted_tick = tick;
|
||||||
|
}
|
||||||
|
|
||||||
|
pxl8_result demo3d_net_send_command(demo3d_net* ng, const demo3d_command_msg* cmd) {
|
||||||
|
if (!ng || !cmd) return PXL8_ERROR_INVALID_ARGUMENT;
|
||||||
|
if (!pxl8_net_connected(ng->transport)) return PXL8_ERROR_INVALID_ARGUMENT;
|
||||||
|
|
||||||
|
u8 buf[512];
|
||||||
|
demo3d_msg_header hdr = {.type = DEMO3D_MSG_COMMAND, .version = DEMO3D_PROTOCOL_VERSION};
|
||||||
|
usize offset = demo3d_protocol_serialize_header(&hdr, buf, sizeof(buf));
|
||||||
|
offset += demo3d_protocol_serialize_command(cmd, buf + offset, sizeof(buf) - offset);
|
||||||
|
|
||||||
|
return pxl8_net_send(ng->transport, buf, offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
pxl8_result demo3d_net_send_input(demo3d_net* ng, const demo3d_input_msg* input) {
|
||||||
|
if (!ng || !input) return PXL8_ERROR_INVALID_ARGUMENT;
|
||||||
|
if (!pxl8_net_connected(ng->transport)) return PXL8_ERROR_INVALID_ARGUMENT;
|
||||||
|
|
||||||
|
demo3d_net_input_push(ng, input);
|
||||||
|
|
||||||
|
u8 buf[512];
|
||||||
|
demo3d_msg_header hdr = {.type = DEMO3D_MSG_INPUT, .version = DEMO3D_PROTOCOL_VERSION};
|
||||||
|
usize offset = demo3d_protocol_serialize_header(&hdr, buf, sizeof(buf));
|
||||||
|
offset += demo3d_protocol_serialize_input(input, buf + offset, sizeof(buf) - offset);
|
||||||
|
|
||||||
|
return pxl8_net_send(ng->transport, buf, offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
const demo3d_snapshot_header* demo3d_net_snapshot(const demo3d_net* ng) {
|
||||||
|
if (!ng) return NULL;
|
||||||
|
return &ng->snapshot;
|
||||||
|
}
|
||||||
|
|
||||||
|
u64 demo3d_net_tick(const demo3d_net* ng) {
|
||||||
|
if (!ng) return 0;
|
||||||
|
return ng->snapshot.tick;
|
||||||
|
}
|
||||||
|
|
||||||
|
void demo3d_net_update(demo3d_net* ng, f32 dt) {
|
||||||
|
if (!ng) return;
|
||||||
|
ng->interp_time += dt;
|
||||||
|
}
|
||||||
|
|
||||||
|
void demo3d_net_set_chunk_cache(demo3d_net* ng, demo3d_chunk_cache* cache) {
|
||||||
|
if (!ng) return;
|
||||||
|
ng->chunk_cache = cache;
|
||||||
|
}
|
||||||
|
|
||||||
|
demo3d_chunk_cache* demo3d_net_chunk_cache(demo3d_net* ng) {
|
||||||
|
if (!ng) return NULL;
|
||||||
|
return ng->chunk_cache;
|
||||||
|
}
|
||||||
|
|
||||||
|
void demo3d_net_set_world(demo3d_net* ng, demo3d_world* world) {
|
||||||
|
if (!ng) return;
|
||||||
|
ng->world = world;
|
||||||
|
}
|
||||||
|
|
||||||
|
i32 demo3d_net_chunk_cx(const demo3d_net* ng) {
|
||||||
|
if (!ng) return 0;
|
||||||
|
return ng->chunk_cx;
|
||||||
|
}
|
||||||
|
|
||||||
|
i32 demo3d_net_chunk_cz(const demo3d_net* ng) {
|
||||||
|
if (!ng) return 0;
|
||||||
|
return ng->chunk_cz;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool demo3d_net_has_chunk(const demo3d_net* ng) {
|
||||||
|
if (!ng) return false;
|
||||||
|
return ng->has_chunk;
|
||||||
|
}
|
||||||
|
|
||||||
|
pxl8_result demo3d_net_spawn(demo3d_net* ng, f32 x, f32 y, f32 z, f32 yaw, f32 pitch) {
|
||||||
|
if (!ng) return PXL8_ERROR_INVALID_ARGUMENT;
|
||||||
|
|
||||||
|
demo3d_command_msg cmd = {0};
|
||||||
|
cmd.cmd_type = DEMO3D_CMD_SPAWN_ENTITY;
|
||||||
|
|
||||||
|
u8* p = cmd.payload;
|
||||||
|
memcpy(p, &x, 4); p += 4;
|
||||||
|
memcpy(p, &y, 4); p += 4;
|
||||||
|
memcpy(p, &z, 4); p += 4;
|
||||||
|
memcpy(p, &yaw, 4); p += 4;
|
||||||
|
memcpy(p, &pitch, 4);
|
||||||
|
cmd.payload_size = 20;
|
||||||
|
|
||||||
|
return demo3d_net_send_command(ng, &cmd);
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef PXL8_ASYNC_THREADS
|
||||||
|
void demo3d_net_start_thread(demo3d_net* ng) {
|
||||||
|
if (!ng) return;
|
||||||
|
pxl8_net_start_thread(ng->transport);
|
||||||
|
}
|
||||||
|
|
||||||
|
void demo3d_net_stop_thread(demo3d_net* ng) {
|
||||||
|
if (!ng) return;
|
||||||
|
pxl8_net_stop_thread(ng->transport);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool demo3d_net_dispatch_packet(demo3d_net* ng, const pxl8_packet* pkt) {
|
||||||
|
if (!ng || !pkt) return false;
|
||||||
|
return dispatch_message(ng, pkt->data, pkt->len);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
74
demo3d/client/net/demo3d_net.h
Normal file
74
demo3d/client/net/demo3d_net.h
Normal file
|
|
@ -0,0 +1,74 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "pxl8_net.h"
|
||||||
|
#include "demo3d_protocol.h"
|
||||||
|
#include "pxl8_types.h"
|
||||||
|
|
||||||
|
#define DEMO3D_NET_INPUT_HISTORY_SIZE 64
|
||||||
|
#define DEMO3D_NET_USERDATA_SIZE 56
|
||||||
|
#define DEMO3D_NET_TICK_RATE 30.0f
|
||||||
|
|
||||||
|
typedef struct demo3d_world demo3d_world;
|
||||||
|
typedef struct demo3d_chunk_cache demo3d_chunk_cache;
|
||||||
|
|
||||||
|
typedef struct demo3d_net {
|
||||||
|
pxl8_net* transport;
|
||||||
|
|
||||||
|
demo3d_chunk_cache* chunk_cache;
|
||||||
|
i32 chunk_cx;
|
||||||
|
i32 chunk_cz;
|
||||||
|
bool has_chunk;
|
||||||
|
demo3d_world* world;
|
||||||
|
|
||||||
|
u64 highest_tick;
|
||||||
|
f32 interp_time;
|
||||||
|
|
||||||
|
demo3d_entity_state entities[DEMO3D_MAX_SNAPSHOT_ENTITIES];
|
||||||
|
demo3d_entity_state prev_entities[DEMO3D_MAX_SNAPSHOT_ENTITIES];
|
||||||
|
demo3d_snapshot_header prev_snapshot;
|
||||||
|
demo3d_snapshot_header snapshot;
|
||||||
|
|
||||||
|
u64 input_head;
|
||||||
|
demo3d_input_msg input_history[DEMO3D_NET_INPUT_HISTORY_SIZE];
|
||||||
|
u64 input_oldest_tick;
|
||||||
|
|
||||||
|
u8 predicted_state[DEMO3D_NET_USERDATA_SIZE];
|
||||||
|
u64 predicted_tick;
|
||||||
|
} demo3d_net;
|
||||||
|
|
||||||
|
demo3d_net* demo3d_net_create(const pxl8_net_config* config);
|
||||||
|
void demo3d_net_destroy(demo3d_net* ng);
|
||||||
|
pxl8_result demo3d_net_connect(demo3d_net* ng);
|
||||||
|
bool demo3d_net_connected(const demo3d_net* ng);
|
||||||
|
void demo3d_net_disconnect(demo3d_net* ng);
|
||||||
|
|
||||||
|
const demo3d_entity_state* demo3d_net_entities(const demo3d_net* ng);
|
||||||
|
const u8* demo3d_net_entity_prev_userdata(const demo3d_net* ng, u64 entity_id);
|
||||||
|
const u8* demo3d_net_entity_userdata(const demo3d_net* ng, u64 entity_id);
|
||||||
|
const demo3d_input_msg* demo3d_net_input_at(const demo3d_net* ng, u64 tick);
|
||||||
|
u64 demo3d_net_input_oldest_tick(const demo3d_net* ng);
|
||||||
|
void demo3d_net_input_push(demo3d_net* ng, const demo3d_input_msg* input);
|
||||||
|
f32 demo3d_net_lerp_alpha(const demo3d_net* ng);
|
||||||
|
bool demo3d_net_needs_correction(const demo3d_net* ng);
|
||||||
|
u64 demo3d_net_player_id(const demo3d_net* ng);
|
||||||
|
bool demo3d_net_poll(demo3d_net* ng);
|
||||||
|
u8* demo3d_net_predicted_state(demo3d_net* ng);
|
||||||
|
void demo3d_net_predicted_tick_set(demo3d_net* ng, u64 tick);
|
||||||
|
pxl8_result demo3d_net_send_command(demo3d_net* ng, const demo3d_command_msg* cmd);
|
||||||
|
pxl8_result demo3d_net_send_input(demo3d_net* ng, const demo3d_input_msg* input);
|
||||||
|
const demo3d_snapshot_header* demo3d_net_snapshot(const demo3d_net* ng);
|
||||||
|
u64 demo3d_net_tick(const demo3d_net* ng);
|
||||||
|
void demo3d_net_update(demo3d_net* ng, f32 dt);
|
||||||
|
void demo3d_net_set_chunk_cache(demo3d_net* ng, demo3d_chunk_cache* cache);
|
||||||
|
demo3d_chunk_cache* demo3d_net_chunk_cache(demo3d_net* ng);
|
||||||
|
void demo3d_net_set_world(demo3d_net* ng, demo3d_world* world);
|
||||||
|
i32 demo3d_net_chunk_cx(const demo3d_net* ng);
|
||||||
|
i32 demo3d_net_chunk_cz(const demo3d_net* ng);
|
||||||
|
bool demo3d_net_has_chunk(const demo3d_net* ng);
|
||||||
|
pxl8_result demo3d_net_spawn(demo3d_net* ng, f32 x, f32 y, f32 z, f32 yaw, f32 pitch);
|
||||||
|
|
||||||
|
#ifdef PXL8_ASYNC_THREADS
|
||||||
|
void demo3d_net_start_thread(demo3d_net* ng);
|
||||||
|
void demo3d_net_stop_thread(demo3d_net* ng);
|
||||||
|
bool demo3d_net_dispatch_packet(demo3d_net* ng, const pxl8_packet* pkt);
|
||||||
|
#endif
|
||||||
|
|
@ -1,8 +1,8 @@
|
||||||
#include "pxl8_protocol.h"
|
#include "demo3d_protocol.h"
|
||||||
#include "pxl8_bytes.h"
|
#include "pxl8_bytes.h"
|
||||||
|
|
||||||
usize pxl8_protocol_serialize_header(const pxl8_msg_header* msg, u8* buf, usize len) {
|
usize demo3d_protocol_serialize_header(const demo3d_msg_header* msg, u8* buf, usize len) {
|
||||||
if (len < sizeof(pxl8_msg_header)) return 0;
|
if (len < sizeof(demo3d_msg_header)) return 0;
|
||||||
pxl8_write_stream s = pxl8_write_stream_create(buf, (u32)len);
|
pxl8_write_stream s = pxl8_write_stream_create(buf, (u32)len);
|
||||||
pxl8_write_u32_be(&s, msg->sequence);
|
pxl8_write_u32_be(&s, msg->sequence);
|
||||||
pxl8_write_u16_be(&s, msg->size);
|
pxl8_write_u16_be(&s, msg->size);
|
||||||
|
|
@ -11,8 +11,8 @@ usize pxl8_protocol_serialize_header(const pxl8_msg_header* msg, u8* buf, usize
|
||||||
return s.offset;
|
return s.offset;
|
||||||
}
|
}
|
||||||
|
|
||||||
usize pxl8_protocol_deserialize_header(const u8* buf, usize len, pxl8_msg_header* msg) {
|
usize demo3d_protocol_deserialize_header(const u8* buf, usize len, demo3d_msg_header* msg) {
|
||||||
if (len < sizeof(pxl8_msg_header)) return 0;
|
if (len < sizeof(demo3d_msg_header)) return 0;
|
||||||
pxl8_stream s = pxl8_stream_create(buf, (u32)len);
|
pxl8_stream s = pxl8_stream_create(buf, (u32)len);
|
||||||
msg->sequence = pxl8_read_u32_be(&s);
|
msg->sequence = pxl8_read_u32_be(&s);
|
||||||
msg->size = pxl8_read_u16_be(&s);
|
msg->size = pxl8_read_u16_be(&s);
|
||||||
|
|
@ -21,8 +21,8 @@ usize pxl8_protocol_deserialize_header(const u8* buf, usize len, pxl8_msg_header
|
||||||
return s.offset;
|
return s.offset;
|
||||||
}
|
}
|
||||||
|
|
||||||
usize pxl8_protocol_serialize_input(const pxl8_input_msg* msg, u8* buf, usize len) {
|
usize demo3d_protocol_serialize_input(const demo3d_input_msg* msg, u8* buf, usize len) {
|
||||||
if (len < sizeof(pxl8_input_msg)) return 0;
|
if (len < sizeof(demo3d_input_msg)) return 0;
|
||||||
pxl8_write_stream s = pxl8_write_stream_create(buf, (u32)len);
|
pxl8_write_stream s = pxl8_write_stream_create(buf, (u32)len);
|
||||||
pxl8_write_u32_be(&s, msg->buttons);
|
pxl8_write_u32_be(&s, msg->buttons);
|
||||||
pxl8_write_f32_be(&s, msg->look_dx);
|
pxl8_write_f32_be(&s, msg->look_dx);
|
||||||
|
|
@ -35,8 +35,8 @@ usize pxl8_protocol_serialize_input(const pxl8_input_msg* msg, u8* buf, usize le
|
||||||
return s.offset;
|
return s.offset;
|
||||||
}
|
}
|
||||||
|
|
||||||
usize pxl8_protocol_deserialize_input(const u8* buf, usize len, pxl8_input_msg* msg) {
|
usize demo3d_protocol_deserialize_input(const u8* buf, usize len, demo3d_input_msg* msg) {
|
||||||
if (len < sizeof(pxl8_input_msg)) return 0;
|
if (len < sizeof(demo3d_input_msg)) return 0;
|
||||||
pxl8_stream s = pxl8_stream_create(buf, (u32)len);
|
pxl8_stream s = pxl8_stream_create(buf, (u32)len);
|
||||||
msg->buttons = pxl8_read_u32_be(&s);
|
msg->buttons = pxl8_read_u32_be(&s);
|
||||||
msg->look_dx = pxl8_read_f32_be(&s);
|
msg->look_dx = pxl8_read_f32_be(&s);
|
||||||
|
|
@ -49,60 +49,60 @@ usize pxl8_protocol_deserialize_input(const u8* buf, usize len, pxl8_input_msg*
|
||||||
return s.offset;
|
return s.offset;
|
||||||
}
|
}
|
||||||
|
|
||||||
usize pxl8_protocol_serialize_command(const pxl8_command_msg* msg, u8* buf, usize len) {
|
usize demo3d_protocol_serialize_command(const demo3d_command_msg* msg, u8* buf, usize len) {
|
||||||
if (len < sizeof(pxl8_command_msg)) return 0;
|
if (len < sizeof(demo3d_command_msg)) return 0;
|
||||||
pxl8_write_stream s = pxl8_write_stream_create(buf, (u32)len);
|
pxl8_write_stream s = pxl8_write_stream_create(buf, (u32)len);
|
||||||
pxl8_write_u16_be(&s, msg->cmd_type);
|
pxl8_write_u16_be(&s, msg->cmd_type);
|
||||||
pxl8_write_bytes(&s, msg->payload, PXL8_COMMAND_PAYLOAD_SIZE);
|
pxl8_write_bytes(&s, msg->payload, DEMO3D_COMMAND_PAYLOAD_SIZE);
|
||||||
pxl8_write_u16_be(&s, msg->payload_size);
|
pxl8_write_u16_be(&s, msg->payload_size);
|
||||||
pxl8_write_u64_be(&s, msg->tick);
|
pxl8_write_u64_be(&s, msg->tick);
|
||||||
return s.offset;
|
return s.offset;
|
||||||
}
|
}
|
||||||
|
|
||||||
usize pxl8_protocol_deserialize_command(const u8* buf, usize len, pxl8_command_msg* msg) {
|
usize demo3d_protocol_deserialize_command(const u8* buf, usize len, demo3d_command_msg* msg) {
|
||||||
if (len < sizeof(pxl8_command_msg)) return 0;
|
if (len < sizeof(demo3d_command_msg)) return 0;
|
||||||
pxl8_stream s = pxl8_stream_create(buf, (u32)len);
|
pxl8_stream s = pxl8_stream_create(buf, (u32)len);
|
||||||
msg->cmd_type = pxl8_read_u16_be(&s);
|
msg->cmd_type = pxl8_read_u16_be(&s);
|
||||||
pxl8_read_bytes(&s, msg->payload, PXL8_COMMAND_PAYLOAD_SIZE);
|
pxl8_read_bytes(&s, msg->payload, DEMO3D_COMMAND_PAYLOAD_SIZE);
|
||||||
msg->payload_size = pxl8_read_u16_be(&s);
|
msg->payload_size = pxl8_read_u16_be(&s);
|
||||||
msg->tick = pxl8_read_u64_be(&s);
|
msg->tick = pxl8_read_u64_be(&s);
|
||||||
return s.offset;
|
return s.offset;
|
||||||
}
|
}
|
||||||
|
|
||||||
usize pxl8_protocol_serialize_entity_state(const pxl8_entity_state* state, u8* buf, usize len) {
|
usize demo3d_protocol_serialize_entity_state(const demo3d_entity_state* state, u8* buf, usize len) {
|
||||||
if (len < sizeof(pxl8_entity_state)) return 0;
|
if (len < sizeof(demo3d_entity_state)) return 0;
|
||||||
pxl8_write_stream s = pxl8_write_stream_create(buf, (u32)len);
|
pxl8_write_stream s = pxl8_write_stream_create(buf, (u32)len);
|
||||||
pxl8_write_u64_be(&s, state->entity_id);
|
pxl8_write_u64_be(&s, state->entity_id);
|
||||||
pxl8_write_bytes(&s, state->userdata, 56);
|
pxl8_write_bytes(&s, state->userdata, 56);
|
||||||
return s.offset;
|
return s.offset;
|
||||||
}
|
}
|
||||||
|
|
||||||
usize pxl8_protocol_deserialize_entity_state(const u8* buf, usize len, pxl8_entity_state* state) {
|
usize demo3d_protocol_deserialize_entity_state(const u8* buf, usize len, demo3d_entity_state* state) {
|
||||||
if (len < sizeof(pxl8_entity_state)) return 0;
|
if (len < sizeof(demo3d_entity_state)) return 0;
|
||||||
pxl8_stream s = pxl8_stream_create(buf, (u32)len);
|
pxl8_stream s = pxl8_stream_create(buf, (u32)len);
|
||||||
state->entity_id = pxl8_read_u64_be(&s);
|
state->entity_id = pxl8_read_u64_be(&s);
|
||||||
pxl8_read_bytes(&s, state->userdata, 56);
|
pxl8_read_bytes(&s, state->userdata, 56);
|
||||||
return s.offset;
|
return s.offset;
|
||||||
}
|
}
|
||||||
|
|
||||||
usize pxl8_protocol_serialize_event(const pxl8_event_msg* msg, u8* buf, usize len) {
|
usize demo3d_protocol_serialize_event(const demo3d_event_msg* msg, u8* buf, usize len) {
|
||||||
if (len < sizeof(pxl8_event_msg)) return 0;
|
if (len < sizeof(demo3d_event_msg)) return 0;
|
||||||
pxl8_write_stream s = pxl8_write_stream_create(buf, (u32)len);
|
pxl8_write_stream s = pxl8_write_stream_create(buf, (u32)len);
|
||||||
pxl8_write_u8(&s, msg->event_type);
|
pxl8_write_u8(&s, msg->event_type);
|
||||||
pxl8_write_bytes(&s, msg->payload, PXL8_EVENT_PAYLOAD_SIZE);
|
pxl8_write_bytes(&s, msg->payload, DEMO3D_EVENT_PAYLOAD_SIZE);
|
||||||
return s.offset;
|
return s.offset;
|
||||||
}
|
}
|
||||||
|
|
||||||
usize pxl8_protocol_deserialize_event(const u8* buf, usize len, pxl8_event_msg* msg) {
|
usize demo3d_protocol_deserialize_event(const u8* buf, usize len, demo3d_event_msg* msg) {
|
||||||
if (len < sizeof(pxl8_event_msg)) return 0;
|
if (len < sizeof(demo3d_event_msg)) return 0;
|
||||||
pxl8_stream s = pxl8_stream_create(buf, (u32)len);
|
pxl8_stream s = pxl8_stream_create(buf, (u32)len);
|
||||||
msg->event_type = pxl8_read_u8(&s);
|
msg->event_type = pxl8_read_u8(&s);
|
||||||
pxl8_read_bytes(&s, msg->payload, PXL8_EVENT_PAYLOAD_SIZE);
|
pxl8_read_bytes(&s, msg->payload, DEMO3D_EVENT_PAYLOAD_SIZE);
|
||||||
return s.offset;
|
return s.offset;
|
||||||
}
|
}
|
||||||
|
|
||||||
usize pxl8_protocol_serialize_snapshot_header(const pxl8_snapshot_header* hdr, u8* buf, usize len) {
|
usize demo3d_protocol_serialize_snapshot_header(const demo3d_snapshot_header* hdr, u8* buf, usize len) {
|
||||||
if (len < sizeof(pxl8_snapshot_header)) return 0;
|
if (len < sizeof(demo3d_snapshot_header)) return 0;
|
||||||
pxl8_write_stream s = pxl8_write_stream_create(buf, (u32)len);
|
pxl8_write_stream s = pxl8_write_stream_create(buf, (u32)len);
|
||||||
pxl8_write_u16_be(&s, hdr->entity_count);
|
pxl8_write_u16_be(&s, hdr->entity_count);
|
||||||
pxl8_write_u16_be(&s, hdr->event_count);
|
pxl8_write_u16_be(&s, hdr->event_count);
|
||||||
|
|
@ -112,8 +112,8 @@ usize pxl8_protocol_serialize_snapshot_header(const pxl8_snapshot_header* hdr, u
|
||||||
return s.offset;
|
return s.offset;
|
||||||
}
|
}
|
||||||
|
|
||||||
usize pxl8_protocol_deserialize_snapshot_header(const u8* buf, usize len, pxl8_snapshot_header* hdr) {
|
usize demo3d_protocol_deserialize_snapshot_header(const u8* buf, usize len, demo3d_snapshot_header* hdr) {
|
||||||
if (len < sizeof(pxl8_snapshot_header)) return 0;
|
if (len < sizeof(demo3d_snapshot_header)) return 0;
|
||||||
pxl8_stream s = pxl8_stream_create(buf, (u32)len);
|
pxl8_stream s = pxl8_stream_create(buf, (u32)len);
|
||||||
hdr->entity_count = pxl8_read_u16_be(&s);
|
hdr->entity_count = pxl8_read_u16_be(&s);
|
||||||
hdr->event_count = pxl8_read_u16_be(&s);
|
hdr->event_count = pxl8_read_u16_be(&s);
|
||||||
|
|
@ -123,7 +123,7 @@ usize pxl8_protocol_deserialize_snapshot_header(const u8* buf, usize len, pxl8_s
|
||||||
return s.offset;
|
return s.offset;
|
||||||
}
|
}
|
||||||
|
|
||||||
usize pxl8_protocol_serialize_chunk_msg_header(const pxl8_chunk_msg_header* hdr, u8* buf, usize len) {
|
usize demo3d_protocol_serialize_chunk_msg_header(const demo3d_chunk_msg_header* hdr, u8* buf, usize len) {
|
||||||
if (len < 24) return 0;
|
if (len < 24) return 0;
|
||||||
pxl8_write_stream s = pxl8_write_stream_create(buf, (u32)len);
|
pxl8_write_stream s = pxl8_write_stream_create(buf, (u32)len);
|
||||||
pxl8_write_u8(&s, hdr->chunk_type);
|
pxl8_write_u8(&s, hdr->chunk_type);
|
||||||
|
|
@ -140,7 +140,7 @@ usize pxl8_protocol_serialize_chunk_msg_header(const pxl8_chunk_msg_header* hdr,
|
||||||
return s.offset;
|
return s.offset;
|
||||||
}
|
}
|
||||||
|
|
||||||
usize pxl8_protocol_deserialize_chunk_msg_header(const u8* buf, usize len, pxl8_chunk_msg_header* hdr) {
|
usize demo3d_protocol_deserialize_chunk_msg_header(const u8* buf, usize len, demo3d_chunk_msg_header* hdr) {
|
||||||
if (len < 24) return 0;
|
if (len < 24) return 0;
|
||||||
pxl8_stream s = pxl8_stream_create(buf, (u32)len);
|
pxl8_stream s = pxl8_stream_create(buf, (u32)len);
|
||||||
hdr->chunk_type = pxl8_read_u8(&s);
|
hdr->chunk_type = pxl8_read_u8(&s);
|
||||||
|
|
@ -157,7 +157,7 @@ usize pxl8_protocol_deserialize_chunk_msg_header(const u8* buf, usize len, pxl8_
|
||||||
return s.offset;
|
return s.offset;
|
||||||
}
|
}
|
||||||
|
|
||||||
usize pxl8_protocol_deserialize_bsp_wire_header(const u8* buf, usize len, pxl8_bsp_wire_header* hdr) {
|
usize demo3d_protocol_deserialize_bsp_wire_header(const u8* buf, usize len, demo3d_bsp_wire_header* hdr) {
|
||||||
if (len < 48) return 0;
|
if (len < 48) return 0;
|
||||||
pxl8_stream s = pxl8_stream_create(buf, (u32)len);
|
pxl8_stream s = pxl8_stream_create(buf, (u32)len);
|
||||||
hdr->num_vertices = pxl8_read_u32_be(&s);
|
hdr->num_vertices = pxl8_read_u32_be(&s);
|
||||||
|
|
@ -175,7 +175,7 @@ usize pxl8_protocol_deserialize_bsp_wire_header(const u8* buf, usize len, pxl8_b
|
||||||
return s.offset;
|
return s.offset;
|
||||||
}
|
}
|
||||||
|
|
||||||
usize pxl8_protocol_serialize_chunk_enter(const pxl8_chunk_enter_msg* msg, u8* buf, usize len) {
|
usize demo3d_protocol_serialize_chunk_enter(const demo3d_chunk_enter_msg* msg, u8* buf, usize len) {
|
||||||
if (len < 8) return 0;
|
if (len < 8) return 0;
|
||||||
pxl8_write_stream s = pxl8_write_stream_create(buf, (u32)len);
|
pxl8_write_stream s = pxl8_write_stream_create(buf, (u32)len);
|
||||||
pxl8_write_u32_be(&s, (u32)msg->cx);
|
pxl8_write_u32_be(&s, (u32)msg->cx);
|
||||||
|
|
@ -183,7 +183,7 @@ usize pxl8_protocol_serialize_chunk_enter(const pxl8_chunk_enter_msg* msg, u8* b
|
||||||
return s.offset;
|
return s.offset;
|
||||||
}
|
}
|
||||||
|
|
||||||
usize pxl8_protocol_deserialize_chunk_enter(const u8* buf, usize len, pxl8_chunk_enter_msg* msg) {
|
usize demo3d_protocol_deserialize_chunk_enter(const u8* buf, usize len, demo3d_chunk_enter_msg* msg) {
|
||||||
if (len < 8) return 0;
|
if (len < 8) return 0;
|
||||||
pxl8_stream s = pxl8_stream_create(buf, (u32)len);
|
pxl8_stream s = pxl8_stream_create(buf, (u32)len);
|
||||||
msg->cx = (i32)pxl8_read_u32_be(&s);
|
msg->cx = (i32)pxl8_read_u32_be(&s);
|
||||||
|
|
@ -191,7 +191,7 @@ usize pxl8_protocol_deserialize_chunk_enter(const u8* buf, usize len, pxl8_chunk
|
||||||
return s.offset;
|
return s.offset;
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 pxl8_chunk_hash(i32 cx, i32 cz) {
|
u32 demo3d_chunk_hash(i32 cx, i32 cz) {
|
||||||
u32 h = (u32)cx * 374761393u + (u32)cz * 668265263u;
|
u32 h = (u32)cx * 374761393u + (u32)cz * 668265263u;
|
||||||
return h ^ (h >> 16);
|
return h ^ (h >> 16);
|
||||||
}
|
}
|
||||||
143
demo3d/client/net/demo3d_protocol.h
Normal file
143
demo3d/client/net/demo3d_protocol.h
Normal file
|
|
@ -0,0 +1,143 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "pxl8_types.h"
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define DEMO3D_PROTOCOL_VERSION 1
|
||||||
|
#define DEMO3D_MAX_SNAPSHOT_ENTITIES 256
|
||||||
|
#define DEMO3D_MAX_SNAPSHOT_EVENTS 32
|
||||||
|
#define DEMO3D_COMMAND_PAYLOAD_SIZE 64
|
||||||
|
#define DEMO3D_EVENT_PAYLOAD_SIZE 15
|
||||||
|
|
||||||
|
typedef enum demo3d_msg_type {
|
||||||
|
DEMO3D_MSG_NONE = 0,
|
||||||
|
DEMO3D_MSG_CHUNK,
|
||||||
|
DEMO3D_MSG_CHUNK_ENTER,
|
||||||
|
DEMO3D_MSG_CHUNK_EXIT,
|
||||||
|
DEMO3D_MSG_COMMAND,
|
||||||
|
DEMO3D_MSG_CONNECT,
|
||||||
|
DEMO3D_MSG_DISCONNECT,
|
||||||
|
DEMO3D_MSG_EVENT,
|
||||||
|
DEMO3D_MSG_INPUT,
|
||||||
|
DEMO3D_MSG_SNAPSHOT
|
||||||
|
} demo3d_msg_type;
|
||||||
|
|
||||||
|
typedef struct demo3d_msg_header {
|
||||||
|
u32 sequence;
|
||||||
|
u16 size;
|
||||||
|
u8 type;
|
||||||
|
u8 version;
|
||||||
|
} demo3d_msg_header;
|
||||||
|
|
||||||
|
typedef enum demo3d_cmd_type {
|
||||||
|
DEMO3D_CMD_NONE = 0,
|
||||||
|
DEMO3D_CMD_SPAWN_ENTITY,
|
||||||
|
} demo3d_cmd_type;
|
||||||
|
|
||||||
|
typedef struct demo3d_input_msg {
|
||||||
|
u32 buttons;
|
||||||
|
f32 look_dx;
|
||||||
|
f32 look_dy;
|
||||||
|
f32 move_x;
|
||||||
|
f32 move_y;
|
||||||
|
f32 yaw;
|
||||||
|
u64 tick;
|
||||||
|
u64 timestamp;
|
||||||
|
} demo3d_input_msg;
|
||||||
|
|
||||||
|
typedef struct demo3d_command_msg {
|
||||||
|
u16 cmd_type;
|
||||||
|
u8 payload[DEMO3D_COMMAND_PAYLOAD_SIZE];
|
||||||
|
u16 payload_size;
|
||||||
|
u64 tick;
|
||||||
|
} demo3d_command_msg;
|
||||||
|
|
||||||
|
typedef struct demo3d_entity_state {
|
||||||
|
u64 entity_id;
|
||||||
|
u8 userdata[56];
|
||||||
|
} demo3d_entity_state;
|
||||||
|
|
||||||
|
typedef struct demo3d_event_msg {
|
||||||
|
u8 event_type;
|
||||||
|
u8 payload[DEMO3D_EVENT_PAYLOAD_SIZE];
|
||||||
|
} demo3d_event_msg;
|
||||||
|
|
||||||
|
typedef struct demo3d_snapshot_header {
|
||||||
|
u16 entity_count;
|
||||||
|
u16 event_count;
|
||||||
|
u64 player_id;
|
||||||
|
u64 tick;
|
||||||
|
f32 time;
|
||||||
|
} demo3d_snapshot_header;
|
||||||
|
|
||||||
|
#define DEMO3D_CHUNK_TYPE_BSP 1
|
||||||
|
|
||||||
|
#define DEMO3D_CHUNK_FLAG_FINAL 0x04
|
||||||
|
#define DEMO3D_CHUNK_MAX_PAYLOAD 1400
|
||||||
|
|
||||||
|
typedef struct demo3d_chunk_msg_header {
|
||||||
|
u8 chunk_type;
|
||||||
|
u8 flags;
|
||||||
|
u8 fragment_idx;
|
||||||
|
u8 fragment_count;
|
||||||
|
u32 id;
|
||||||
|
i32 cx, cy, cz;
|
||||||
|
u32 version;
|
||||||
|
u16 payload_size;
|
||||||
|
u16 reserved;
|
||||||
|
} demo3d_chunk_msg_header;
|
||||||
|
|
||||||
|
typedef struct demo3d_bsp_wire_header {
|
||||||
|
u32 num_vertices;
|
||||||
|
u32 num_edges;
|
||||||
|
u32 num_faces;
|
||||||
|
u32 num_planes;
|
||||||
|
u32 num_nodes;
|
||||||
|
u32 num_leafs;
|
||||||
|
u32 num_surfedges;
|
||||||
|
u32 num_marksurfaces;
|
||||||
|
u32 num_cell_portals;
|
||||||
|
u32 visdata_size;
|
||||||
|
u32 num_vertex_lights;
|
||||||
|
u32 num_heightfield;
|
||||||
|
} demo3d_bsp_wire_header;
|
||||||
|
|
||||||
|
usize demo3d_protocol_serialize_header(const demo3d_msg_header* msg, u8* buf, usize len);
|
||||||
|
usize demo3d_protocol_deserialize_header(const u8* buf, usize len, demo3d_msg_header* msg);
|
||||||
|
|
||||||
|
usize demo3d_protocol_serialize_input(const demo3d_input_msg* msg, u8* buf, usize len);
|
||||||
|
usize demo3d_protocol_deserialize_input(const u8* buf, usize len, demo3d_input_msg* msg);
|
||||||
|
|
||||||
|
usize demo3d_protocol_serialize_command(const demo3d_command_msg* msg, u8* buf, usize len);
|
||||||
|
usize demo3d_protocol_deserialize_command(const u8* buf, usize len, demo3d_command_msg* msg);
|
||||||
|
|
||||||
|
usize demo3d_protocol_serialize_entity_state(const demo3d_entity_state* state, u8* buf, usize len);
|
||||||
|
usize demo3d_protocol_deserialize_entity_state(const u8* buf, usize len, demo3d_entity_state* state);
|
||||||
|
|
||||||
|
usize demo3d_protocol_serialize_event(const demo3d_event_msg* msg, u8* buf, usize len);
|
||||||
|
usize demo3d_protocol_deserialize_event(const u8* buf, usize len, demo3d_event_msg* msg);
|
||||||
|
|
||||||
|
usize demo3d_protocol_serialize_snapshot_header(const demo3d_snapshot_header* hdr, u8* buf, usize len);
|
||||||
|
usize demo3d_protocol_deserialize_snapshot_header(const u8* buf, usize len, demo3d_snapshot_header* hdr);
|
||||||
|
|
||||||
|
usize demo3d_protocol_serialize_chunk_msg_header(const demo3d_chunk_msg_header* hdr, u8* buf, usize len);
|
||||||
|
usize demo3d_protocol_deserialize_chunk_msg_header(const u8* buf, usize len, demo3d_chunk_msg_header* hdr);
|
||||||
|
|
||||||
|
usize demo3d_protocol_deserialize_bsp_wire_header(const u8* buf, usize len, demo3d_bsp_wire_header* hdr);
|
||||||
|
|
||||||
|
typedef struct demo3d_chunk_enter_msg {
|
||||||
|
i32 cx;
|
||||||
|
i32 cz;
|
||||||
|
} demo3d_chunk_enter_msg;
|
||||||
|
|
||||||
|
usize demo3d_protocol_serialize_chunk_enter(const demo3d_chunk_enter_msg* msg, u8* buf, usize len);
|
||||||
|
usize demo3d_protocol_deserialize_chunk_enter(const u8* buf, usize len, demo3d_chunk_enter_msg* msg);
|
||||||
|
|
||||||
|
u32 demo3d_chunk_hash(i32 cx, i32 cz);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
#include "pxl8_sim.h"
|
#include "demo3d_sim.h"
|
||||||
|
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
|
|
||||||
|
|
@ -11,13 +11,13 @@ typedef struct {
|
||||||
bool start_solid;
|
bool start_solid;
|
||||||
} trace_result;
|
} trace_result;
|
||||||
|
|
||||||
static i32 bsp_find_leaf(const pxl8_bsp* bsp, pxl8_vec3 pos) {
|
static i32 bsp_find_leaf(const demo3d_bsp* bsp, pxl8_vec3 pos) {
|
||||||
if (!bsp || bsp->num_nodes == 0) return -1;
|
if (!bsp || bsp->num_nodes == 0) return -1;
|
||||||
|
|
||||||
i32 node_id = 0;
|
i32 node_id = 0;
|
||||||
while (node_id >= 0) {
|
while (node_id >= 0) {
|
||||||
const pxl8_bsp_node* node = &bsp->nodes[node_id];
|
const demo3d_bsp_node* node = &bsp->nodes[node_id];
|
||||||
const pxl8_bsp_plane* plane = &bsp->planes[node->plane_id];
|
const demo3d_bsp_plane* plane = &bsp->planes[node->plane_id];
|
||||||
f32 dist = pxl8_vec3_dot(pos, plane->normal) - plane->dist;
|
f32 dist = pxl8_vec3_dot(pos, plane->normal) - plane->dist;
|
||||||
node_id = node->children[dist < 0 ? 1 : 0];
|
node_id = node->children[dist < 0 ? 1 : 0];
|
||||||
}
|
}
|
||||||
|
|
@ -25,10 +25,10 @@ static i32 bsp_find_leaf(const pxl8_bsp* bsp, pxl8_vec3 pos) {
|
||||||
return -(node_id + 1);
|
return -(node_id + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
static i32 bsp_contents_from(const pxl8_bsp* bsp, i32 node_id, pxl8_vec3 pos) {
|
static i32 bsp_contents_from(const demo3d_bsp* bsp, i32 node_id, pxl8_vec3 pos) {
|
||||||
while (node_id >= 0) {
|
while (node_id >= 0) {
|
||||||
const pxl8_bsp_node* node = &bsp->nodes[node_id];
|
const demo3d_bsp_node* node = &bsp->nodes[node_id];
|
||||||
const pxl8_bsp_plane* plane = &bsp->planes[node->plane_id];
|
const demo3d_bsp_plane* plane = &bsp->planes[node->plane_id];
|
||||||
f32 d = pxl8_vec3_dot(pos, plane->normal) - plane->dist;
|
f32 d = pxl8_vec3_dot(pos, plane->normal) - plane->dist;
|
||||||
node_id = node->children[d < 0 ? 1 : 0];
|
node_id = node->children[d < 0 ? 1 : 0];
|
||||||
}
|
}
|
||||||
|
|
@ -37,7 +37,7 @@ static i32 bsp_contents_from(const pxl8_bsp* bsp, i32 node_id, pxl8_vec3 pos) {
|
||||||
return bsp->leafs[leaf_idx].contents;
|
return bsp->leafs[leaf_idx].contents;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool bsp_recursive_trace(const pxl8_bsp* bsp, i32 node_id,
|
static bool bsp_recursive_trace(const demo3d_bsp* bsp, i32 node_id,
|
||||||
f32 p1f, f32 p2f,
|
f32 p1f, f32 p2f,
|
||||||
pxl8_vec3 p1, pxl8_vec3 p2,
|
pxl8_vec3 p1, pxl8_vec3 p2,
|
||||||
trace_result* tr) {
|
trace_result* tr) {
|
||||||
|
|
@ -52,8 +52,8 @@ static bool bsp_recursive_trace(const pxl8_bsp* bsp, i32 node_id,
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
const pxl8_bsp_node* node = &bsp->nodes[node_id];
|
const demo3d_bsp_node* node = &bsp->nodes[node_id];
|
||||||
const pxl8_bsp_plane* plane = &bsp->planes[node->plane_id];
|
const demo3d_bsp_plane* plane = &bsp->planes[node->plane_id];
|
||||||
|
|
||||||
f32 t1 = pxl8_vec3_dot(p1, plane->normal) - plane->dist;
|
f32 t1 = pxl8_vec3_dot(p1, plane->normal) - plane->dist;
|
||||||
f32 t2 = pxl8_vec3_dot(p2, plane->normal) - plane->dist;
|
f32 t2 = pxl8_vec3_dot(p2, plane->normal) - plane->dist;
|
||||||
|
|
@ -104,7 +104,7 @@ static bool bsp_recursive_trace(const pxl8_bsp* bsp, i32 node_id,
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
static trace_result bsp_trace_line(const pxl8_bsp* bsp, pxl8_vec3 from, pxl8_vec3 to) {
|
static trace_result bsp_trace_line(const demo3d_bsp* bsp, pxl8_vec3 from, pxl8_vec3 to) {
|
||||||
trace_result tr = { .fraction = 1.0f, .all_solid = true };
|
trace_result tr = { .fraction = 1.0f, .all_solid = true };
|
||||||
if (!bsp || bsp->num_nodes == 0) {
|
if (!bsp || bsp->num_nodes == 0) {
|
||||||
tr.all_solid = false;
|
tr.all_solid = false;
|
||||||
|
|
@ -118,7 +118,7 @@ static trace_result bsp_trace_line(const pxl8_bsp* bsp, pxl8_vec3 from, pxl8_vec
|
||||||
return tr;
|
return tr;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool pxl8_bsp_point_solid(const pxl8_bsp* bsp, pxl8_vec3 pos) {
|
bool demo3d_bsp_point_solid(const demo3d_bsp* bsp, pxl8_vec3 pos) {
|
||||||
if (!bsp) return false;
|
if (!bsp) return false;
|
||||||
if (bsp->bounds_max_x > bsp->bounds_min_x &&
|
if (bsp->bounds_max_x > bsp->bounds_min_x &&
|
||||||
(pos.x < bsp->bounds_min_x || pos.x >= bsp->bounds_max_x ||
|
(pos.x < bsp->bounds_min_x || pos.x >= bsp->bounds_max_x ||
|
||||||
|
|
@ -129,7 +129,7 @@ bool pxl8_bsp_point_solid(const pxl8_bsp* bsp, pxl8_vec3 pos) {
|
||||||
return bsp->leafs[leaf].contents == -1;
|
return bsp->leafs[leaf].contents == -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void trace_offsets(const pxl8_bsp* bsp, pxl8_vec3 from, pxl8_vec3 to,
|
static void trace_offsets(const demo3d_bsp* bsp, pxl8_vec3 from, pxl8_vec3 to,
|
||||||
f32 radius, f32* out_frac, pxl8_vec3* out_normal) {
|
f32 radius, f32* out_frac, pxl8_vec3* out_normal) {
|
||||||
f32 d = radius * 0.7071f;
|
f32 d = radius * 0.7071f;
|
||||||
pxl8_vec3 offsets[9] = {
|
pxl8_vec3 offsets[9] = {
|
||||||
|
|
@ -154,7 +154,7 @@ static void trace_offsets(const pxl8_bsp* bsp, pxl8_vec3 from, pxl8_vec3 to,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pxl8_vec3 pxl8_bsp_trace(const pxl8_bsp* bsp, pxl8_vec3 from, pxl8_vec3 to, f32 radius) {
|
pxl8_vec3 demo3d_bsp_trace(const demo3d_bsp* bsp, pxl8_vec3 from, pxl8_vec3 to, f32 radius) {
|
||||||
if (!bsp || bsp->num_nodes == 0) return to;
|
if (!bsp || bsp->num_nodes == 0) return to;
|
||||||
|
|
||||||
f32 frac;
|
f32 frac;
|
||||||
|
|
@ -196,7 +196,7 @@ pxl8_vec3 pxl8_bsp_trace(const pxl8_bsp* bsp, pxl8_vec3 from, pxl8_vec3 to, f32
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
static const pxl8_bsp* sim_bsp_at(const pxl8_sim_world* world, f32 x, f32 z) {
|
static const demo3d_bsp* sim_bsp_at(const demo3d_sim_world* world, f32 x, f32 z) {
|
||||||
i32 cx = (i32)floorf(x / world->chunk_size);
|
i32 cx = (i32)floorf(x / world->chunk_size);
|
||||||
i32 cz = (i32)floorf(z / world->chunk_size);
|
i32 cz = (i32)floorf(z / world->chunk_size);
|
||||||
i32 dx = cx - world->center_cx + 1;
|
i32 dx = cx - world->center_cx + 1;
|
||||||
|
|
@ -205,7 +205,7 @@ static const pxl8_bsp* sim_bsp_at(const pxl8_sim_world* world, f32 x, f32 z) {
|
||||||
return world->chunks[dz * 3 + dx];
|
return world->chunks[dz * 3 + dx];
|
||||||
}
|
}
|
||||||
|
|
||||||
static f32 bsp_terrain_height(const pxl8_bsp* bsp, f32 x, f32 z) {
|
static f32 bsp_terrain_height(const demo3d_bsp* bsp, f32 x, f32 z) {
|
||||||
if (!bsp || !bsp->heightfield || bsp->heightfield_cell_size <= 0) return -1e9f;
|
if (!bsp || !bsp->heightfield || bsp->heightfield_cell_size <= 0) return -1e9f;
|
||||||
f32 lx = (x - bsp->heightfield_ox) / bsp->heightfield_cell_size;
|
f32 lx = (x - bsp->heightfield_ox) / bsp->heightfield_cell_size;
|
||||||
f32 lz = (z - bsp->heightfield_oz) / bsp->heightfield_cell_size;
|
f32 lz = (z - bsp->heightfield_oz) / bsp->heightfield_cell_size;
|
||||||
|
|
@ -224,12 +224,12 @@ static f32 bsp_terrain_height(const pxl8_bsp* bsp, f32 x, f32 z) {
|
||||||
return h0 + (h1 - h0) * fz;
|
return h0 + (h1 - h0) * fz;
|
||||||
}
|
}
|
||||||
|
|
||||||
static f32 sim_terrain_height(const pxl8_sim_world* world, f32 x, f32 z) {
|
static f32 sim_terrain_height(const demo3d_sim_world* world, f32 x, f32 z) {
|
||||||
const pxl8_bsp* bsp = sim_bsp_at(world, x, z);
|
const demo3d_bsp* bsp = sim_bsp_at(world, x, z);
|
||||||
return bsp_terrain_height(bsp, x, z);
|
return bsp_terrain_height(bsp, x, z);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void sim_trace_offsets(const pxl8_sim_world* world, pxl8_vec3 from, pxl8_vec3 to,
|
static void sim_trace_offsets(const demo3d_sim_world* world, pxl8_vec3 from, pxl8_vec3 to,
|
||||||
f32 radius, f32* out_frac, pxl8_vec3* out_normal) {
|
f32 radius, f32* out_frac, pxl8_vec3* out_normal) {
|
||||||
f32 d = radius * 0.7071f;
|
f32 d = radius * 0.7071f;
|
||||||
pxl8_vec3 offsets[9] = {
|
pxl8_vec3 offsets[9] = {
|
||||||
|
|
@ -246,8 +246,8 @@ static void sim_trace_offsets(const pxl8_sim_world* world, pxl8_vec3 from, pxl8_
|
||||||
for (i32 i = 0; i < 9; i++) {
|
for (i32 i = 0; i < 9; i++) {
|
||||||
pxl8_vec3 s = { from.x + offsets[i].x, from.y + offsets[i].y, from.z + offsets[i].z };
|
pxl8_vec3 s = { from.x + offsets[i].x, from.y + offsets[i].y, from.z + offsets[i].z };
|
||||||
pxl8_vec3 e = { to.x + offsets[i].x, to.y + offsets[i].y, to.z + offsets[i].z };
|
pxl8_vec3 e = { to.x + offsets[i].x, to.y + offsets[i].y, to.z + offsets[i].z };
|
||||||
const pxl8_bsp* bsp_s = sim_bsp_at(world, s.x, s.z);
|
const demo3d_bsp* bsp_s = sim_bsp_at(world, s.x, s.z);
|
||||||
const pxl8_bsp* bsp_e = sim_bsp_at(world, e.x, e.z);
|
const demo3d_bsp* bsp_e = sim_bsp_at(world, e.x, e.z);
|
||||||
if (bsp_s) {
|
if (bsp_s) {
|
||||||
trace_result tr = bsp_trace_line(bsp_s, s, e);
|
trace_result tr = bsp_trace_line(bsp_s, s, e);
|
||||||
if (tr.fraction < *out_frac && !tr.start_solid) {
|
if (tr.fraction < *out_frac && !tr.start_solid) {
|
||||||
|
|
@ -270,7 +270,7 @@ static void sim_trace_offsets(const pxl8_sim_world* world, pxl8_vec3 from, pxl8_
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pxl8_vec3 pxl8_sim_trace(const pxl8_sim_world* world, pxl8_vec3 from, pxl8_vec3 to, f32 radius, f32 height) {
|
pxl8_vec3 demo3d_sim_trace(const demo3d_sim_world* world, pxl8_vec3 from, pxl8_vec3 to, f32 radius, f32 height) {
|
||||||
(void)height;
|
(void)height;
|
||||||
if (!world || world->chunk_size <= 0) return to;
|
if (!world || world->chunk_size <= 0) return to;
|
||||||
|
|
||||||
|
|
@ -313,22 +313,22 @@ pxl8_vec3 pxl8_sim_trace(const pxl8_sim_world* world, pxl8_vec3 from, pxl8_vec3
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
bool pxl8_sim_check_ground(const pxl8_sim_world* world, pxl8_vec3 pos, f32 radius) {
|
bool demo3d_sim_check_ground(const demo3d_sim_world* world, pxl8_vec3 pos, f32 radius) {
|
||||||
if (!world || world->chunk_size <= 0) return true;
|
if (!world || world->chunk_size <= 0) return true;
|
||||||
|
|
||||||
f32 th = sim_terrain_height(world, pos.x, pos.z);
|
f32 th = sim_terrain_height(world, pos.x, pos.z);
|
||||||
if (th > -1e8f && pos.y - th < 2.0f) return true;
|
if (th > -1e8f && pos.y - th < 2.0f) return true;
|
||||||
|
|
||||||
pxl8_vec3 down = {pos.x, pos.y - 2.0f, pos.z};
|
pxl8_vec3 down = {pos.x, pos.y - 2.0f, pos.z};
|
||||||
pxl8_vec3 result = pxl8_sim_trace(world, pos, down, radius, 0.0f);
|
pxl8_vec3 result = demo3d_sim_trace(world, pos, down, radius, 0.0f);
|
||||||
|
|
||||||
return result.y > down.y;
|
return result.y > down.y;
|
||||||
}
|
}
|
||||||
|
|
||||||
void pxl8_sim_move_player(pxl8_sim_entity* ent, const pxl8_input_msg* input,
|
void demo3d_sim_move_player(demo3d_sim_entity* ent, const demo3d_input_msg* input,
|
||||||
const pxl8_sim_world* world, const pxl8_sim_config* cfg, f32 dt) {
|
const demo3d_sim_world* world, const demo3d_sim_config* cfg, f32 dt) {
|
||||||
if (!ent || !input || !cfg) return;
|
if (!ent || !input || !cfg) return;
|
||||||
if (!(ent->flags & PXL8_SIM_FLAG_ALIVE)) return;
|
if (!(ent->flags & DEMO3D_SIM_FLAG_ALIVE)) return;
|
||||||
|
|
||||||
ent->yaw -= input->look_dx * 0.008f;
|
ent->yaw -= input->look_dx * 0.008f;
|
||||||
f32 new_pitch = ent->pitch - input->look_dy * 0.008f;
|
f32 new_pitch = ent->pitch - input->look_dy * 0.008f;
|
||||||
|
|
@ -355,11 +355,11 @@ void pxl8_sim_move_player(pxl8_sim_entity* ent, const pxl8_input_msg* input,
|
||||||
ent->vel.x = move_dir.x * target_speed;
|
ent->vel.x = move_dir.x * target_speed;
|
||||||
ent->vel.z = move_dir.z * target_speed;
|
ent->vel.z = move_dir.z * target_speed;
|
||||||
|
|
||||||
bool grounded = (ent->flags & PXL8_SIM_FLAG_GROUNDED) != 0;
|
bool grounded = (ent->flags & DEMO3D_SIM_FLAG_GROUNDED) != 0;
|
||||||
|
|
||||||
if (grounded && (input->buttons & 1)) {
|
if (grounded && (input->buttons & 1)) {
|
||||||
ent->vel.y = cfg->jump_velocity;
|
ent->vel.y = cfg->jump_velocity;
|
||||||
ent->flags &= ~PXL8_SIM_FLAG_GROUNDED;
|
ent->flags &= ~DEMO3D_SIM_FLAG_GROUNDED;
|
||||||
grounded = false;
|
grounded = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -378,7 +378,7 @@ void pxl8_sim_move_player(pxl8_sim_entity* ent, const pxl8_input_msg* input,
|
||||||
if (th_dest > -1e8f) target.y = th_dest;
|
if (th_dest > -1e8f) target.y = th_dest;
|
||||||
}
|
}
|
||||||
|
|
||||||
pxl8_vec3 new_pos = pxl8_sim_trace(world, ent->pos, target, cfg->player_radius, cfg->player_height);
|
pxl8_vec3 new_pos = demo3d_sim_trace(world, ent->pos, target, cfg->player_radius, cfg->player_height);
|
||||||
|
|
||||||
f32 th = sim_terrain_height(world, new_pos.x, new_pos.z);
|
f32 th = sim_terrain_height(world, new_pos.x, new_pos.z);
|
||||||
if (th > -1e8f && new_pos.y < th) {
|
if (th > -1e8f && new_pos.y < th) {
|
||||||
|
|
@ -388,21 +388,21 @@ void pxl8_sim_move_player(pxl8_sim_entity* ent, const pxl8_input_msg* input,
|
||||||
|
|
||||||
ent->pos = new_pos;
|
ent->pos = new_pos;
|
||||||
|
|
||||||
if (pxl8_sim_check_ground(world, ent->pos, cfg->player_radius)) {
|
if (demo3d_sim_check_ground(world, ent->pos, cfg->player_radius)) {
|
||||||
ent->flags |= PXL8_SIM_FLAG_GROUNDED;
|
ent->flags |= DEMO3D_SIM_FLAG_GROUNDED;
|
||||||
if (ent->vel.y < 0) ent->vel.y = 0;
|
if (ent->vel.y < 0) ent->vel.y = 0;
|
||||||
} else {
|
} else {
|
||||||
ent->flags &= ~PXL8_SIM_FLAG_GROUNDED;
|
ent->flags &= ~DEMO3D_SIM_FLAG_GROUNDED;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void pxl8_sim_integrate(pxl8_sim_entity* ent, const pxl8_sim_world* world,
|
void demo3d_sim_integrate(demo3d_sim_entity* ent, const demo3d_sim_world* world,
|
||||||
const pxl8_sim_config* cfg, f32 dt) {
|
const demo3d_sim_config* cfg, f32 dt) {
|
||||||
if (!ent || !cfg) return;
|
if (!ent || !cfg) return;
|
||||||
if (!(ent->flags & PXL8_SIM_FLAG_ALIVE)) return;
|
if (!(ent->flags & DEMO3D_SIM_FLAG_ALIVE)) return;
|
||||||
if (ent->flags & PXL8_SIM_FLAG_PLAYER) return;
|
if (ent->flags & DEMO3D_SIM_FLAG_PLAYER) return;
|
||||||
|
|
||||||
bool grounded = (ent->flags & PXL8_SIM_FLAG_GROUNDED) != 0;
|
bool grounded = (ent->flags & DEMO3D_SIM_FLAG_GROUNDED) != 0;
|
||||||
|
|
||||||
ent->vel.y -= cfg->gravity * dt;
|
ent->vel.y -= cfg->gravity * dt;
|
||||||
|
|
||||||
|
|
@ -429,7 +429,7 @@ void pxl8_sim_integrate(pxl8_sim_entity* ent, const pxl8_sim_world* world,
|
||||||
if (th_dest > -1e8f) target.y = th_dest;
|
if (th_dest > -1e8f) target.y = th_dest;
|
||||||
}
|
}
|
||||||
|
|
||||||
pxl8_vec3 new_pos = pxl8_sim_trace(world, ent->pos, target, cfg->player_radius, cfg->player_height);
|
pxl8_vec3 new_pos = demo3d_sim_trace(world, ent->pos, target, cfg->player_radius, cfg->player_height);
|
||||||
|
|
||||||
f32 th2 = sim_terrain_height(world, new_pos.x, new_pos.z);
|
f32 th2 = sim_terrain_height(world, new_pos.x, new_pos.z);
|
||||||
if (th2 > -1e8f && new_pos.y < th2) {
|
if (th2 > -1e8f && new_pos.y < th2) {
|
||||||
|
|
@ -439,10 +439,10 @@ void pxl8_sim_integrate(pxl8_sim_entity* ent, const pxl8_sim_world* world,
|
||||||
|
|
||||||
ent->pos = new_pos;
|
ent->pos = new_pos;
|
||||||
|
|
||||||
if (pxl8_sim_check_ground(world, ent->pos, cfg->player_radius)) {
|
if (demo3d_sim_check_ground(world, ent->pos, cfg->player_radius)) {
|
||||||
ent->flags |= PXL8_SIM_FLAG_GROUNDED;
|
ent->flags |= DEMO3D_SIM_FLAG_GROUNDED;
|
||||||
if (ent->vel.y < 0.0f) ent->vel.y = 0.0f;
|
if (ent->vel.y < 0.0f) ent->vel.y = 0.0f;
|
||||||
} else {
|
} else {
|
||||||
ent->flags &= ~PXL8_SIM_FLAG_GROUNDED;
|
ent->flags &= ~DEMO3D_SIM_FLAG_GROUNDED;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
56
demo3d/client/sim/demo3d_sim.h
Normal file
56
demo3d/client/sim/demo3d_sim.h
Normal file
|
|
@ -0,0 +1,56 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "demo3d_bsp.h"
|
||||||
|
#include "pxl8_math.h"
|
||||||
|
#include "demo3d_protocol.h"
|
||||||
|
#include "pxl8_types.h"
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define DEMO3D_SIM_FLAG_ALIVE (1 << 0)
|
||||||
|
#define DEMO3D_SIM_FLAG_PLAYER (1 << 1)
|
||||||
|
#define DEMO3D_SIM_FLAG_GROUNDED (1 << 2)
|
||||||
|
|
||||||
|
typedef struct demo3d_sim_config {
|
||||||
|
f32 move_speed;
|
||||||
|
f32 ground_accel;
|
||||||
|
f32 air_accel;
|
||||||
|
f32 stop_speed;
|
||||||
|
f32 friction;
|
||||||
|
f32 gravity;
|
||||||
|
f32 jump_velocity;
|
||||||
|
f32 player_radius;
|
||||||
|
f32 player_height;
|
||||||
|
f32 max_pitch;
|
||||||
|
} demo3d_sim_config;
|
||||||
|
|
||||||
|
typedef struct demo3d_sim_entity {
|
||||||
|
pxl8_vec3 pos;
|
||||||
|
pxl8_vec3 vel;
|
||||||
|
f32 yaw;
|
||||||
|
f32 pitch;
|
||||||
|
u32 flags;
|
||||||
|
u16 kind;
|
||||||
|
u16 _pad;
|
||||||
|
} demo3d_sim_entity;
|
||||||
|
|
||||||
|
typedef struct demo3d_sim_world {
|
||||||
|
const demo3d_bsp* chunks[9];
|
||||||
|
i32 center_cx;
|
||||||
|
i32 center_cz;
|
||||||
|
f32 chunk_size;
|
||||||
|
} demo3d_sim_world;
|
||||||
|
|
||||||
|
bool demo3d_bsp_point_solid(const demo3d_bsp* bsp, pxl8_vec3 pos);
|
||||||
|
pxl8_vec3 demo3d_bsp_trace(const demo3d_bsp* bsp, pxl8_vec3 from, pxl8_vec3 to, f32 radius);
|
||||||
|
|
||||||
|
pxl8_vec3 demo3d_sim_trace(const demo3d_sim_world* world, pxl8_vec3 from, pxl8_vec3 to, f32 radius, f32 height);
|
||||||
|
bool demo3d_sim_check_ground(const demo3d_sim_world* world, pxl8_vec3 pos, f32 radius);
|
||||||
|
void demo3d_sim_move_player(demo3d_sim_entity* ent, const demo3d_input_msg* input, const demo3d_sim_world* world, const demo3d_sim_config* cfg, f32 dt);
|
||||||
|
void demo3d_sim_integrate(demo3d_sim_entity* ent, const demo3d_sim_world* world, const demo3d_sim_config* cfg, f32 dt);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
17
demo3d/client/world/demo3d_chunk.c
Normal file
17
demo3d/client/world/demo3d_chunk.c
Normal file
|
|
@ -0,0 +1,17 @@
|
||||||
|
#include "demo3d_chunk.h"
|
||||||
|
|
||||||
|
#include "demo3d_bsp.h"
|
||||||
|
#include "pxl8_mem.h"
|
||||||
|
|
||||||
|
demo3d_chunk* demo3d_chunk_create_bsp(u32 id) {
|
||||||
|
demo3d_chunk* chunk = pxl8_calloc(1, sizeof(demo3d_chunk));
|
||||||
|
if (!chunk) return NULL;
|
||||||
|
chunk->id = id;
|
||||||
|
return chunk;
|
||||||
|
}
|
||||||
|
|
||||||
|
void demo3d_chunk_destroy(demo3d_chunk* chunk) {
|
||||||
|
if (!chunk) return;
|
||||||
|
if (chunk->bsp) demo3d_bsp_destroy(chunk->bsp);
|
||||||
|
pxl8_free(chunk);
|
||||||
|
}
|
||||||
21
demo3d/client/world/demo3d_chunk.h
Normal file
21
demo3d/client/world/demo3d_chunk.h
Normal file
|
|
@ -0,0 +1,21 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "demo3d_bsp.h"
|
||||||
|
#include "pxl8_types.h"
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
typedef struct demo3d_chunk {
|
||||||
|
u32 id;
|
||||||
|
u32 version;
|
||||||
|
demo3d_bsp* bsp;
|
||||||
|
} demo3d_chunk;
|
||||||
|
|
||||||
|
demo3d_chunk* demo3d_chunk_create_bsp(u32 id);
|
||||||
|
void demo3d_chunk_destroy(demo3d_chunk* chunk);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
#include "pxl8_world_chunk_cache.h"
|
#include "demo3d_chunk_cache.h"
|
||||||
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
@ -7,9 +7,9 @@
|
||||||
#include "pxl8_log.h"
|
#include "pxl8_log.h"
|
||||||
#include "pxl8_mem.h"
|
#include "pxl8_mem.h"
|
||||||
|
|
||||||
static pxl8_world_chunk_cache_entry* find_entry_bsp(pxl8_world_chunk_cache* cache, u32 id) {
|
static demo3d_chunk_cache_entry* find_entry_bsp(demo3d_chunk_cache* cache, u32 id) {
|
||||||
for (u32 i = 0; i < cache->entry_count; i++) {
|
for (u32 i = 0; i < cache->entry_count; i++) {
|
||||||
pxl8_world_chunk_cache_entry* e = &cache->entries[i];
|
demo3d_chunk_cache_entry* e = &cache->entries[i];
|
||||||
if (e->valid && e->chunk && e->chunk->id == id) {
|
if (e->valid && e->chunk && e->chunk->id == id) {
|
||||||
return e;
|
return e;
|
||||||
}
|
}
|
||||||
|
|
@ -17,16 +17,16 @@ static pxl8_world_chunk_cache_entry* find_entry_bsp(pxl8_world_chunk_cache* cach
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static pxl8_world_chunk_cache_entry* alloc_entry(pxl8_world_chunk_cache* cache) {
|
static demo3d_chunk_cache_entry* alloc_entry(demo3d_chunk_cache* cache) {
|
||||||
if (cache->entry_count < PXL8_WORLD_CHUNK_CACHE_SIZE) {
|
if (cache->entry_count < DEMO3D_CHUNK_CACHE_SIZE) {
|
||||||
pxl8_world_chunk_cache_entry* e = &cache->entries[cache->entry_count++];
|
demo3d_chunk_cache_entry* e = &cache->entries[cache->entry_count++];
|
||||||
memset(e, 0, sizeof(*e));
|
memset(e, 0, sizeof(*e));
|
||||||
return e;
|
return e;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (u32 i = 0; i < PXL8_WORLD_CHUNK_CACHE_SIZE; i++) {
|
for (u32 i = 0; i < DEMO3D_CHUNK_CACHE_SIZE; i++) {
|
||||||
if (!cache->entries[i].valid) {
|
if (!cache->entries[i].valid) {
|
||||||
pxl8_world_chunk_cache_entry* e = &cache->entries[i];
|
demo3d_chunk_cache_entry* e = &cache->entries[i];
|
||||||
memset(e, 0, sizeof(*e));
|
memset(e, 0, sizeof(*e));
|
||||||
return e;
|
return e;
|
||||||
}
|
}
|
||||||
|
|
@ -34,22 +34,22 @@ static pxl8_world_chunk_cache_entry* alloc_entry(pxl8_world_chunk_cache* cache)
|
||||||
|
|
||||||
u64 oldest = cache->entries[0].last_used;
|
u64 oldest = cache->entries[0].last_used;
|
||||||
u32 slot = 0;
|
u32 slot = 0;
|
||||||
for (u32 i = 1; i < PXL8_WORLD_CHUNK_CACHE_SIZE; i++) {
|
for (u32 i = 1; i < DEMO3D_CHUNK_CACHE_SIZE; i++) {
|
||||||
if (cache->entries[i].last_used < oldest) {
|
if (cache->entries[i].last_used < oldest) {
|
||||||
oldest = cache->entries[i].last_used;
|
oldest = cache->entries[i].last_used;
|
||||||
slot = i;
|
slot = i;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pxl8_world_chunk_cache_entry* e = &cache->entries[slot];
|
demo3d_chunk_cache_entry* e = &cache->entries[slot];
|
||||||
if (e->chunk) {
|
if (e->chunk) {
|
||||||
pxl8_world_chunk_destroy(e->chunk);
|
demo3d_chunk_destroy(e->chunk);
|
||||||
}
|
}
|
||||||
memset(e, 0, sizeof(*e));
|
memset(e, 0, sizeof(*e));
|
||||||
return e;
|
return e;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void assembly_reset(pxl8_world_chunk_assembly* a) {
|
static void assembly_reset(demo3d_chunk_assembly* a) {
|
||||||
a->id = 0;
|
a->id = 0;
|
||||||
a->cx = 0;
|
a->cx = 0;
|
||||||
a->cy = 0;
|
a->cy = 0;
|
||||||
|
|
@ -62,7 +62,7 @@ static void assembly_reset(pxl8_world_chunk_assembly* a) {
|
||||||
a->complete = false;
|
a->complete = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void assembly_init(pxl8_world_chunk_assembly* a, const pxl8_chunk_msg_header* hdr) {
|
static void assembly_init(demo3d_chunk_assembly* a, const demo3d_chunk_msg_header* hdr) {
|
||||||
assembly_reset(a);
|
assembly_reset(a);
|
||||||
a->id = hdr->id;
|
a->id = hdr->id;
|
||||||
a->cx = hdr->cx;
|
a->cx = hdr->cx;
|
||||||
|
|
@ -72,27 +72,27 @@ static void assembly_init(pxl8_world_chunk_assembly* a, const pxl8_chunk_msg_hea
|
||||||
a->fragment_count = hdr->fragment_count;
|
a->fragment_count = hdr->fragment_count;
|
||||||
a->active = true;
|
a->active = true;
|
||||||
|
|
||||||
u32 needed = PXL8_CHUNK_MAX_PAYLOAD * hdr->fragment_count;
|
u32 needed = DEMO3D_CHUNK_MAX_PAYLOAD * hdr->fragment_count;
|
||||||
if (a->data_capacity < needed) {
|
if (a->data_capacity < needed) {
|
||||||
a->data_capacity = needed;
|
a->data_capacity = needed;
|
||||||
a->data = pxl8_realloc(a->data, a->data_capacity);
|
a->data = pxl8_realloc(a->data, a->data_capacity);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static pxl8_result deserialize_vertex(pxl8_stream* s, pxl8_bsp_vertex* v) {
|
static pxl8_result deserialize_vertex(pxl8_stream* s, demo3d_bsp_vertex* v) {
|
||||||
v->position.x = pxl8_read_f32_be(s);
|
v->position.x = pxl8_read_f32_be(s);
|
||||||
v->position.y = pxl8_read_f32_be(s);
|
v->position.y = pxl8_read_f32_be(s);
|
||||||
v->position.z = pxl8_read_f32_be(s);
|
v->position.z = pxl8_read_f32_be(s);
|
||||||
return PXL8_OK;
|
return PXL8_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
static pxl8_result deserialize_edge(pxl8_stream* s, pxl8_bsp_edge* e) {
|
static pxl8_result deserialize_edge(pxl8_stream* s, demo3d_bsp_edge* e) {
|
||||||
e->vertex[0] = pxl8_read_u16_be(s);
|
e->vertex[0] = pxl8_read_u16_be(s);
|
||||||
e->vertex[1] = pxl8_read_u16_be(s);
|
e->vertex[1] = pxl8_read_u16_be(s);
|
||||||
return PXL8_OK;
|
return PXL8_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
static pxl8_result deserialize_plane(pxl8_stream* s, pxl8_bsp_plane* p) {
|
static pxl8_result deserialize_plane(pxl8_stream* s, demo3d_bsp_plane* p) {
|
||||||
p->normal.x = pxl8_read_f32_be(s);
|
p->normal.x = pxl8_read_f32_be(s);
|
||||||
p->normal.y = pxl8_read_f32_be(s);
|
p->normal.y = pxl8_read_f32_be(s);
|
||||||
p->normal.z = pxl8_read_f32_be(s);
|
p->normal.z = pxl8_read_f32_be(s);
|
||||||
|
|
@ -101,7 +101,7 @@ static pxl8_result deserialize_plane(pxl8_stream* s, pxl8_bsp_plane* p) {
|
||||||
return PXL8_OK;
|
return PXL8_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
static pxl8_result deserialize_face(pxl8_stream* s, pxl8_bsp_face* f) {
|
static pxl8_result deserialize_face(pxl8_stream* s, demo3d_bsp_face* f) {
|
||||||
f->first_edge = pxl8_read_u32_be(s);
|
f->first_edge = pxl8_read_u32_be(s);
|
||||||
f->lightmap_offset = pxl8_read_u32_be(s);
|
f->lightmap_offset = pxl8_read_u32_be(s);
|
||||||
f->num_edges = pxl8_read_u16_be(s);
|
f->num_edges = pxl8_read_u16_be(s);
|
||||||
|
|
@ -118,7 +118,7 @@ static pxl8_result deserialize_face(pxl8_stream* s, pxl8_bsp_face* f) {
|
||||||
return PXL8_OK;
|
return PXL8_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
static pxl8_result deserialize_node(pxl8_stream* s, pxl8_bsp_node* n) {
|
static pxl8_result deserialize_node(pxl8_stream* s, demo3d_bsp_node* n) {
|
||||||
n->children[0] = (i32)pxl8_read_u32_be(s);
|
n->children[0] = (i32)pxl8_read_u32_be(s);
|
||||||
n->children[1] = (i32)pxl8_read_u32_be(s);
|
n->children[1] = (i32)pxl8_read_u32_be(s);
|
||||||
n->first_face = pxl8_read_u16_be(s);
|
n->first_face = pxl8_read_u16_be(s);
|
||||||
|
|
@ -133,7 +133,7 @@ static pxl8_result deserialize_node(pxl8_stream* s, pxl8_bsp_node* n) {
|
||||||
return PXL8_OK;
|
return PXL8_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
static pxl8_result deserialize_leaf(pxl8_stream* s, pxl8_bsp_leaf* l) {
|
static pxl8_result deserialize_leaf(pxl8_stream* s, demo3d_bsp_leaf* l) {
|
||||||
pxl8_read_bytes(s, l->ambient_level, 4);
|
pxl8_read_bytes(s, l->ambient_level, 4);
|
||||||
l->contents = (i32)pxl8_read_u32_be(s);
|
l->contents = (i32)pxl8_read_u32_be(s);
|
||||||
l->first_marksurface = pxl8_read_u16_be(s);
|
l->first_marksurface = pxl8_read_u16_be(s);
|
||||||
|
|
@ -148,7 +148,7 @@ static pxl8_result deserialize_leaf(pxl8_stream* s, pxl8_bsp_leaf* l) {
|
||||||
return PXL8_OK;
|
return PXL8_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
static pxl8_result deserialize_portal(pxl8_stream* s, pxl8_bsp_portal* p) {
|
static pxl8_result deserialize_portal(pxl8_stream* s, demo3d_bsp_portal* p) {
|
||||||
p->x0 = pxl8_read_f32_be(s);
|
p->x0 = pxl8_read_f32_be(s);
|
||||||
p->z0 = pxl8_read_f32_be(s);
|
p->z0 = pxl8_read_f32_be(s);
|
||||||
p->x1 = pxl8_read_f32_be(s);
|
p->x1 = pxl8_read_f32_be(s);
|
||||||
|
|
@ -157,7 +157,7 @@ static pxl8_result deserialize_portal(pxl8_stream* s, pxl8_bsp_portal* p) {
|
||||||
return PXL8_OK;
|
return PXL8_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
static pxl8_result deserialize_cell_portals(pxl8_stream* s, pxl8_bsp_cell_portals* cp) {
|
static pxl8_result deserialize_cell_portals(pxl8_stream* s, demo3d_bsp_cell_portals* cp) {
|
||||||
cp->num_portals = pxl8_read_u8(s);
|
cp->num_portals = pxl8_read_u8(s);
|
||||||
pxl8_read_u8(s);
|
pxl8_read_u8(s);
|
||||||
pxl8_read_u8(s);
|
pxl8_read_u8(s);
|
||||||
|
|
@ -168,22 +168,22 @@ static pxl8_result deserialize_cell_portals(pxl8_stream* s, pxl8_bsp_cell_portal
|
||||||
return PXL8_OK;
|
return PXL8_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
static pxl8_bsp* assembly_to_bsp(pxl8_world_chunk_assembly* a) {
|
static demo3d_bsp* assembly_to_bsp(demo3d_chunk_assembly* a) {
|
||||||
if (!a->complete || a->data_size < 48) {
|
if (!a->complete || a->data_size < 48) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
pxl8_bsp* bsp = pxl8_calloc(1, sizeof(pxl8_bsp));
|
demo3d_bsp* bsp = pxl8_calloc(1, sizeof(demo3d_bsp));
|
||||||
if (!bsp) return NULL;
|
if (!bsp) return NULL;
|
||||||
|
|
||||||
pxl8_stream s = pxl8_stream_create(a->data, (u32)a->data_size);
|
pxl8_stream s = pxl8_stream_create(a->data, (u32)a->data_size);
|
||||||
|
|
||||||
pxl8_bsp_wire_header wire_hdr;
|
demo3d_bsp_wire_header wire_hdr;
|
||||||
pxl8_protocol_deserialize_bsp_wire_header(a->data, 48, &wire_hdr);
|
demo3d_protocol_deserialize_bsp_wire_header(a->data, 48, &wire_hdr);
|
||||||
s.offset = 48;
|
s.offset = 48;
|
||||||
|
|
||||||
if (wire_hdr.num_vertices > 0) {
|
if (wire_hdr.num_vertices > 0) {
|
||||||
bsp->vertices = pxl8_calloc(wire_hdr.num_vertices, sizeof(pxl8_bsp_vertex));
|
bsp->vertices = pxl8_calloc(wire_hdr.num_vertices, sizeof(demo3d_bsp_vertex));
|
||||||
bsp->num_vertices = wire_hdr.num_vertices;
|
bsp->num_vertices = wire_hdr.num_vertices;
|
||||||
for (u32 i = 0; i < wire_hdr.num_vertices; i++) {
|
for (u32 i = 0; i < wire_hdr.num_vertices; i++) {
|
||||||
deserialize_vertex(&s, &bsp->vertices[i]);
|
deserialize_vertex(&s, &bsp->vertices[i]);
|
||||||
|
|
@ -191,7 +191,7 @@ static pxl8_bsp* assembly_to_bsp(pxl8_world_chunk_assembly* a) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (wire_hdr.num_edges > 0) {
|
if (wire_hdr.num_edges > 0) {
|
||||||
bsp->edges = pxl8_calloc(wire_hdr.num_edges, sizeof(pxl8_bsp_edge));
|
bsp->edges = pxl8_calloc(wire_hdr.num_edges, sizeof(demo3d_bsp_edge));
|
||||||
bsp->num_edges = wire_hdr.num_edges;
|
bsp->num_edges = wire_hdr.num_edges;
|
||||||
for (u32 i = 0; i < wire_hdr.num_edges; i++) {
|
for (u32 i = 0; i < wire_hdr.num_edges; i++) {
|
||||||
deserialize_edge(&s, &bsp->edges[i]);
|
deserialize_edge(&s, &bsp->edges[i]);
|
||||||
|
|
@ -207,7 +207,7 @@ static pxl8_bsp* assembly_to_bsp(pxl8_world_chunk_assembly* a) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (wire_hdr.num_planes > 0) {
|
if (wire_hdr.num_planes > 0) {
|
||||||
bsp->planes = pxl8_calloc(wire_hdr.num_planes, sizeof(pxl8_bsp_plane));
|
bsp->planes = pxl8_calloc(wire_hdr.num_planes, sizeof(demo3d_bsp_plane));
|
||||||
bsp->num_planes = wire_hdr.num_planes;
|
bsp->num_planes = wire_hdr.num_planes;
|
||||||
for (u32 i = 0; i < wire_hdr.num_planes; i++) {
|
for (u32 i = 0; i < wire_hdr.num_planes; i++) {
|
||||||
deserialize_plane(&s, &bsp->planes[i]);
|
deserialize_plane(&s, &bsp->planes[i]);
|
||||||
|
|
@ -215,7 +215,7 @@ static pxl8_bsp* assembly_to_bsp(pxl8_world_chunk_assembly* a) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (wire_hdr.num_faces > 0) {
|
if (wire_hdr.num_faces > 0) {
|
||||||
bsp->faces = pxl8_calloc(wire_hdr.num_faces, sizeof(pxl8_bsp_face));
|
bsp->faces = pxl8_calloc(wire_hdr.num_faces, sizeof(demo3d_bsp_face));
|
||||||
bsp->num_faces = wire_hdr.num_faces;
|
bsp->num_faces = wire_hdr.num_faces;
|
||||||
for (u32 i = 0; i < wire_hdr.num_faces; i++) {
|
for (u32 i = 0; i < wire_hdr.num_faces; i++) {
|
||||||
deserialize_face(&s, &bsp->faces[i]);
|
deserialize_face(&s, &bsp->faces[i]);
|
||||||
|
|
@ -223,7 +223,7 @@ static pxl8_bsp* assembly_to_bsp(pxl8_world_chunk_assembly* a) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (wire_hdr.num_nodes > 0) {
|
if (wire_hdr.num_nodes > 0) {
|
||||||
bsp->nodes = pxl8_calloc(wire_hdr.num_nodes, sizeof(pxl8_bsp_node));
|
bsp->nodes = pxl8_calloc(wire_hdr.num_nodes, sizeof(demo3d_bsp_node));
|
||||||
bsp->num_nodes = wire_hdr.num_nodes;
|
bsp->num_nodes = wire_hdr.num_nodes;
|
||||||
for (u32 i = 0; i < wire_hdr.num_nodes; i++) {
|
for (u32 i = 0; i < wire_hdr.num_nodes; i++) {
|
||||||
deserialize_node(&s, &bsp->nodes[i]);
|
deserialize_node(&s, &bsp->nodes[i]);
|
||||||
|
|
@ -231,7 +231,7 @@ static pxl8_bsp* assembly_to_bsp(pxl8_world_chunk_assembly* a) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (wire_hdr.num_leafs > 0) {
|
if (wire_hdr.num_leafs > 0) {
|
||||||
bsp->leafs = pxl8_calloc(wire_hdr.num_leafs, sizeof(pxl8_bsp_leaf));
|
bsp->leafs = pxl8_calloc(wire_hdr.num_leafs, sizeof(demo3d_bsp_leaf));
|
||||||
bsp->num_leafs = wire_hdr.num_leafs;
|
bsp->num_leafs = wire_hdr.num_leafs;
|
||||||
for (u32 i = 0; i < wire_hdr.num_leafs; i++) {
|
for (u32 i = 0; i < wire_hdr.num_leafs; i++) {
|
||||||
deserialize_leaf(&s, &bsp->leafs[i]);
|
deserialize_leaf(&s, &bsp->leafs[i]);
|
||||||
|
|
@ -247,7 +247,7 @@ static pxl8_bsp* assembly_to_bsp(pxl8_world_chunk_assembly* a) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (wire_hdr.num_cell_portals > 0) {
|
if (wire_hdr.num_cell_portals > 0) {
|
||||||
bsp->cell_portals = pxl8_calloc(wire_hdr.num_cell_portals, sizeof(pxl8_bsp_cell_portals));
|
bsp->cell_portals = pxl8_calloc(wire_hdr.num_cell_portals, sizeof(demo3d_bsp_cell_portals));
|
||||||
bsp->num_cell_portals = wire_hdr.num_cell_portals;
|
bsp->num_cell_portals = wire_hdr.num_cell_portals;
|
||||||
for (u32 i = 0; i < wire_hdr.num_cell_portals; i++) {
|
for (u32 i = 0; i < wire_hdr.num_cell_portals; i++) {
|
||||||
deserialize_cell_portals(&s, &bsp->cell_portals[i]);
|
deserialize_cell_portals(&s, &bsp->cell_portals[i]);
|
||||||
|
|
@ -298,21 +298,21 @@ static pxl8_bsp* assembly_to_bsp(pxl8_world_chunk_assembly* a) {
|
||||||
return bsp;
|
return bsp;
|
||||||
}
|
}
|
||||||
|
|
||||||
static pxl8_result assemble_bsp(pxl8_world_chunk_cache* cache, pxl8_world_chunk_assembly* a) {
|
static pxl8_result assemble_bsp(demo3d_chunk_cache* cache, demo3d_chunk_assembly* a) {
|
||||||
pxl8_bsp* bsp = assembly_to_bsp(a);
|
demo3d_bsp* bsp = assembly_to_bsp(a);
|
||||||
if (!bsp) {
|
if (!bsp) {
|
||||||
assembly_reset(a);
|
assembly_reset(a);
|
||||||
return PXL8_ERROR_INVALID_ARGUMENT;
|
return PXL8_ERROR_INVALID_ARGUMENT;
|
||||||
}
|
}
|
||||||
|
|
||||||
pxl8_world_chunk_cache_entry* entry = find_entry_bsp(cache, a->id);
|
demo3d_chunk_cache_entry* entry = find_entry_bsp(cache, a->id);
|
||||||
if (entry) {
|
if (entry) {
|
||||||
if (entry->chunk && entry->chunk->bsp) {
|
if (entry->chunk && entry->chunk->bsp) {
|
||||||
pxl8_bsp_destroy(entry->chunk->bsp);
|
demo3d_bsp_destroy(entry->chunk->bsp);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
entry = alloc_entry(cache);
|
entry = alloc_entry(cache);
|
||||||
entry->chunk = pxl8_world_chunk_create_bsp(a->id);
|
entry->chunk = demo3d_chunk_create_bsp(a->id);
|
||||||
entry->valid = true;
|
entry->valid = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -324,31 +324,31 @@ static pxl8_result assemble_bsp(pxl8_world_chunk_cache* cache, pxl8_world_chunk_
|
||||||
return PXL8_OK;
|
return PXL8_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
pxl8_world_chunk_cache* pxl8_world_chunk_cache_create(void) {
|
demo3d_chunk_cache* demo3d_chunk_cache_create(void) {
|
||||||
pxl8_world_chunk_cache* cache = pxl8_calloc(1, sizeof(pxl8_world_chunk_cache));
|
demo3d_chunk_cache* cache = pxl8_calloc(1, sizeof(demo3d_chunk_cache));
|
||||||
if (!cache) return NULL;
|
if (!cache) return NULL;
|
||||||
assembly_reset(&cache->assembly);
|
assembly_reset(&cache->assembly);
|
||||||
return cache;
|
return cache;
|
||||||
}
|
}
|
||||||
|
|
||||||
void pxl8_world_chunk_cache_destroy(pxl8_world_chunk_cache* cache) {
|
void demo3d_chunk_cache_destroy(demo3d_chunk_cache* cache) {
|
||||||
if (!cache) return;
|
if (!cache) return;
|
||||||
|
|
||||||
for (u32 i = 0; i < cache->entry_count; i++) {
|
for (u32 i = 0; i < cache->entry_count; i++) {
|
||||||
pxl8_world_chunk_cache_entry* e = &cache->entries[i];
|
demo3d_chunk_cache_entry* e = &cache->entries[i];
|
||||||
if (e->chunk) pxl8_world_chunk_destroy(e->chunk);
|
if (e->chunk) demo3d_chunk_destroy(e->chunk);
|
||||||
}
|
}
|
||||||
|
|
||||||
pxl8_free(cache->assembly.data);
|
pxl8_free(cache->assembly.data);
|
||||||
pxl8_free(cache);
|
pxl8_free(cache);
|
||||||
}
|
}
|
||||||
|
|
||||||
pxl8_result pxl8_world_chunk_cache_receive(pxl8_world_chunk_cache* cache,
|
pxl8_result demo3d_chunk_cache_receive(demo3d_chunk_cache* cache,
|
||||||
const pxl8_chunk_msg_header* hdr,
|
const demo3d_chunk_msg_header* hdr,
|
||||||
const u8* payload, usize len) {
|
const u8* payload, usize len) {
|
||||||
if (!cache || !hdr || !payload) return PXL8_ERROR_INVALID_ARGUMENT;
|
if (!cache || !hdr || !payload) return PXL8_ERROR_INVALID_ARGUMENT;
|
||||||
|
|
||||||
pxl8_world_chunk_assembly* a = &cache->assembly;
|
demo3d_chunk_assembly* a = &cache->assembly;
|
||||||
|
|
||||||
bool new_assembly = !a->active ||
|
bool new_assembly = !a->active ||
|
||||||
a->id != hdr->id ||
|
a->id != hdr->id ||
|
||||||
|
|
@ -358,11 +358,11 @@ pxl8_result pxl8_world_chunk_cache_receive(pxl8_world_chunk_cache* cache,
|
||||||
assembly_init(a, hdr);
|
assembly_init(a, hdr);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (hdr->fragment_idx >= PXL8_WORLD_CHUNK_MAX_FRAGMENTS) {
|
if (hdr->fragment_idx >= DEMO3D_CHUNK_MAX_FRAGMENTS) {
|
||||||
return PXL8_ERROR_INVALID_ARGUMENT;
|
return PXL8_ERROR_INVALID_ARGUMENT;
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 offset = (u32)hdr->fragment_idx * PXL8_CHUNK_MAX_PAYLOAD;
|
u32 offset = (u32)hdr->fragment_idx * DEMO3D_CHUNK_MAX_PAYLOAD;
|
||||||
u32 required = offset + (u32)len;
|
u32 required = offset + (u32)len;
|
||||||
|
|
||||||
if (required > a->data_capacity) {
|
if (required > a->data_capacity) {
|
||||||
|
|
@ -377,7 +377,7 @@ pxl8_result pxl8_world_chunk_cache_receive(pxl8_world_chunk_cache* cache,
|
||||||
|
|
||||||
a->fragments_received++;
|
a->fragments_received++;
|
||||||
|
|
||||||
if (hdr->flags & PXL8_CHUNK_FLAG_FINAL) {
|
if (hdr->flags & DEMO3D_CHUNK_FLAG_FINAL) {
|
||||||
a->complete = true;
|
a->complete = true;
|
||||||
return assemble_bsp(cache, a);
|
return assemble_bsp(cache, a);
|
||||||
}
|
}
|
||||||
|
|
@ -385,9 +385,9 @@ pxl8_result pxl8_world_chunk_cache_receive(pxl8_world_chunk_cache* cache,
|
||||||
return PXL8_OK;
|
return PXL8_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
pxl8_world_chunk* pxl8_world_chunk_cache_get_bsp(pxl8_world_chunk_cache* cache, u32 id) {
|
demo3d_chunk* demo3d_chunk_cache_get_bsp(demo3d_chunk_cache* cache, u32 id) {
|
||||||
if (!cache) return NULL;
|
if (!cache) return NULL;
|
||||||
pxl8_world_chunk_cache_entry* e = find_entry_bsp(cache, id);
|
demo3d_chunk_cache_entry* e = find_entry_bsp(cache, id);
|
||||||
if (e) {
|
if (e) {
|
||||||
e->last_used = cache->frame_counter;
|
e->last_used = cache->frame_counter;
|
||||||
return e->chunk;
|
return e->chunk;
|
||||||
|
|
@ -395,7 +395,7 @@ pxl8_world_chunk* pxl8_world_chunk_cache_get_bsp(pxl8_world_chunk_cache* cache,
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
void pxl8_world_chunk_cache_tick(pxl8_world_chunk_cache* cache) {
|
void demo3d_chunk_cache_tick(demo3d_chunk_cache* cache) {
|
||||||
if (!cache) return;
|
if (!cache) return;
|
||||||
cache->frame_counter++;
|
cache->frame_counter++;
|
||||||
}
|
}
|
||||||
55
demo3d/client/world/demo3d_chunk_cache.h
Normal file
55
demo3d/client/world/demo3d_chunk_cache.h
Normal file
|
|
@ -0,0 +1,55 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "pxl8_mesh.h"
|
||||||
|
#include "demo3d_protocol.h"
|
||||||
|
#include "pxl8_types.h"
|
||||||
|
#include "demo3d_chunk.h"
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define DEMO3D_CHUNK_CACHE_SIZE 512
|
||||||
|
#define DEMO3D_CHUNK_MAX_FRAGMENTS 255
|
||||||
|
#define DEMO3D_CHUNK_MAX_DATA_SIZE 131072
|
||||||
|
|
||||||
|
typedef struct demo3d_chunk_cache_entry {
|
||||||
|
demo3d_chunk* chunk;
|
||||||
|
u64 last_used;
|
||||||
|
bool valid;
|
||||||
|
} demo3d_chunk_cache_entry;
|
||||||
|
|
||||||
|
typedef struct demo3d_chunk_assembly {
|
||||||
|
u32 id;
|
||||||
|
i32 cx, cy, cz;
|
||||||
|
u32 version;
|
||||||
|
u8 fragment_count;
|
||||||
|
u8 fragments_received;
|
||||||
|
u8* data;
|
||||||
|
u32 data_size;
|
||||||
|
u32 data_capacity;
|
||||||
|
bool active;
|
||||||
|
bool complete;
|
||||||
|
} demo3d_chunk_assembly;
|
||||||
|
|
||||||
|
typedef struct demo3d_chunk_cache {
|
||||||
|
demo3d_chunk_cache_entry entries[DEMO3D_CHUNK_CACHE_SIZE];
|
||||||
|
demo3d_chunk_assembly assembly;
|
||||||
|
u32 entry_count;
|
||||||
|
u64 frame_counter;
|
||||||
|
} demo3d_chunk_cache;
|
||||||
|
|
||||||
|
demo3d_chunk_cache* demo3d_chunk_cache_create(void);
|
||||||
|
void demo3d_chunk_cache_destroy(demo3d_chunk_cache* cache);
|
||||||
|
|
||||||
|
pxl8_result demo3d_chunk_cache_receive(demo3d_chunk_cache* cache,
|
||||||
|
const demo3d_chunk_msg_header* hdr,
|
||||||
|
const u8* payload, usize len);
|
||||||
|
|
||||||
|
demo3d_chunk* demo3d_chunk_cache_get_bsp(demo3d_chunk_cache* cache, u32 id);
|
||||||
|
|
||||||
|
void demo3d_chunk_cache_tick(demo3d_chunk_cache* cache);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
@ -1,61 +1,61 @@
|
||||||
#include "pxl8_entity.h"
|
#include "demo3d_entity.h"
|
||||||
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
#include "pxl8_mem.h"
|
#include "pxl8_mem.h"
|
||||||
|
|
||||||
#define PXL8_ENTITY_COMPONENT_NAME_MAX 32
|
#define DEMO3D_ENTITY_COMPONENT_NAME_MAX 32
|
||||||
#define PXL8_ENTITY_RELATIONSHIP_NAME_MAX 32
|
#define DEMO3D_ENTITY_RELATIONSHIP_NAME_MAX 32
|
||||||
|
|
||||||
typedef struct pxl8_component_type {
|
typedef struct demo3d_component_type {
|
||||||
char name[PXL8_ENTITY_COMPONENT_NAME_MAX];
|
char name[DEMO3D_ENTITY_COMPONENT_NAME_MAX];
|
||||||
u32 size;
|
u32 size;
|
||||||
} pxl8_component_type;
|
} demo3d_component_type;
|
||||||
|
|
||||||
typedef struct pxl8_component_storage {
|
typedef struct demo3d_component_storage {
|
||||||
u32* sparse;
|
u32* sparse;
|
||||||
void* dense_data;
|
void* dense_data;
|
||||||
pxl8_entity* dense_entities;
|
demo3d_entity* dense_entities;
|
||||||
u32 count;
|
u32 count;
|
||||||
} pxl8_component_storage;
|
} demo3d_component_storage;
|
||||||
|
|
||||||
typedef struct pxl8_relationship_type {
|
typedef struct demo3d_relationship_type {
|
||||||
char name[PXL8_ENTITY_RELATIONSHIP_NAME_MAX];
|
char name[DEMO3D_ENTITY_RELATIONSHIP_NAME_MAX];
|
||||||
} pxl8_relationship_type;
|
} demo3d_relationship_type;
|
||||||
|
|
||||||
typedef struct pxl8_relationship_entry {
|
typedef struct demo3d_relationship_entry {
|
||||||
pxl8_entity subject;
|
demo3d_entity subject;
|
||||||
pxl8_entity object;
|
demo3d_entity object;
|
||||||
pxl8_entity_relationship rel;
|
demo3d_entity_relationship rel;
|
||||||
u32 next_by_subject;
|
u32 next_by_subject;
|
||||||
u32 next_by_object;
|
u32 next_by_object;
|
||||||
} pxl8_relationship_entry;
|
} demo3d_relationship_entry;
|
||||||
|
|
||||||
struct pxl8_entity_pool {
|
struct demo3d_entity_pool {
|
||||||
u32* generations;
|
u32* generations;
|
||||||
u32* free_list;
|
u32* free_list;
|
||||||
u32 free_count;
|
u32 free_count;
|
||||||
u32 capacity;
|
u32 capacity;
|
||||||
u32 alive_count;
|
u32 alive_count;
|
||||||
|
|
||||||
pxl8_component_type* component_types;
|
demo3d_component_type* component_types;
|
||||||
pxl8_component_storage* component_storage;
|
demo3d_component_storage* component_storage;
|
||||||
u32 component_type_count;
|
u32 component_type_count;
|
||||||
u32 component_type_capacity;
|
u32 component_type_capacity;
|
||||||
|
|
||||||
pxl8_relationship_type* relationship_types;
|
demo3d_relationship_type* relationship_types;
|
||||||
u32 relationship_type_count;
|
u32 relationship_type_count;
|
||||||
u32 relationship_type_capacity;
|
u32 relationship_type_capacity;
|
||||||
|
|
||||||
pxl8_relationship_entry* relationships;
|
demo3d_relationship_entry* relationships;
|
||||||
u32* rel_by_subject;
|
u32* rel_by_subject;
|
||||||
u32* rel_by_object;
|
u32* rel_by_object;
|
||||||
u32 relationship_count;
|
u32 relationship_count;
|
||||||
u32 relationship_capacity;
|
u32 relationship_capacity;
|
||||||
};
|
};
|
||||||
|
|
||||||
pxl8_entity_pool* pxl8_entity_pool_create(u32 capacity) {
|
demo3d_entity_pool* demo3d_entity_pool_create(u32 capacity) {
|
||||||
pxl8_entity_pool* pool = pxl8_calloc(1, sizeof(pxl8_entity_pool));
|
demo3d_entity_pool* pool = pxl8_calloc(1, sizeof(demo3d_entity_pool));
|
||||||
if (!pool) return NULL;
|
if (!pool) return NULL;
|
||||||
|
|
||||||
pool->capacity = capacity;
|
pool->capacity = capacity;
|
||||||
|
|
@ -63,7 +63,7 @@ pxl8_entity_pool* pxl8_entity_pool_create(u32 capacity) {
|
||||||
pool->free_list = pxl8_malloc(capacity * sizeof(u32));
|
pool->free_list = pxl8_malloc(capacity * sizeof(u32));
|
||||||
|
|
||||||
if (!pool->generations || !pool->free_list) {
|
if (!pool->generations || !pool->free_list) {
|
||||||
pxl8_entity_pool_destroy(pool);
|
demo3d_entity_pool_destroy(pool);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -73,14 +73,14 @@ pxl8_entity_pool* pxl8_entity_pool_create(u32 capacity) {
|
||||||
pool->free_count = capacity;
|
pool->free_count = capacity;
|
||||||
|
|
||||||
pool->component_type_capacity = 16;
|
pool->component_type_capacity = 16;
|
||||||
pool->component_types = pxl8_calloc(pool->component_type_capacity, sizeof(pxl8_component_type));
|
pool->component_types = pxl8_calloc(pool->component_type_capacity, sizeof(demo3d_component_type));
|
||||||
pool->component_storage = pxl8_calloc(pool->component_type_capacity, sizeof(pxl8_component_storage));
|
pool->component_storage = pxl8_calloc(pool->component_type_capacity, sizeof(demo3d_component_storage));
|
||||||
|
|
||||||
pool->relationship_type_capacity = 16;
|
pool->relationship_type_capacity = 16;
|
||||||
pool->relationship_types = pxl8_calloc(pool->relationship_type_capacity, sizeof(pxl8_relationship_type));
|
pool->relationship_types = pxl8_calloc(pool->relationship_type_capacity, sizeof(demo3d_relationship_type));
|
||||||
|
|
||||||
pool->relationship_capacity = 256;
|
pool->relationship_capacity = 256;
|
||||||
pool->relationships = pxl8_malloc(pool->relationship_capacity * sizeof(pxl8_relationship_entry));
|
pool->relationships = pxl8_malloc(pool->relationship_capacity * sizeof(demo3d_relationship_entry));
|
||||||
pool->rel_by_subject = pxl8_malloc(capacity * sizeof(u32));
|
pool->rel_by_subject = pxl8_malloc(capacity * sizeof(u32));
|
||||||
pool->rel_by_object = pxl8_malloc(capacity * sizeof(u32));
|
pool->rel_by_object = pxl8_malloc(capacity * sizeof(u32));
|
||||||
|
|
||||||
|
|
@ -92,7 +92,7 @@ pxl8_entity_pool* pxl8_entity_pool_create(u32 capacity) {
|
||||||
return pool;
|
return pool;
|
||||||
}
|
}
|
||||||
|
|
||||||
void pxl8_entity_pool_clear(pxl8_entity_pool* pool) {
|
void demo3d_entity_pool_clear(demo3d_entity_pool* pool) {
|
||||||
if (!pool) return;
|
if (!pool) return;
|
||||||
|
|
||||||
for (u32 i = 0; i < pool->capacity; i++) {
|
for (u32 i = 0; i < pool->capacity; i++) {
|
||||||
|
|
@ -111,7 +111,7 @@ void pxl8_entity_pool_clear(pxl8_entity_pool* pool) {
|
||||||
pool->relationship_count = 0;
|
pool->relationship_count = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void pxl8_entity_pool_destroy(pxl8_entity_pool* pool) {
|
void demo3d_entity_pool_destroy(demo3d_entity_pool* pool) {
|
||||||
if (!pool) return;
|
if (!pool) return;
|
||||||
|
|
||||||
for (u32 i = 0; i < pool->component_type_count; i++) {
|
for (u32 i = 0; i < pool->component_type_count; i++) {
|
||||||
|
|
@ -131,21 +131,21 @@ void pxl8_entity_pool_destroy(pxl8_entity_pool* pool) {
|
||||||
pxl8_free(pool);
|
pxl8_free(pool);
|
||||||
}
|
}
|
||||||
|
|
||||||
pxl8_entity pxl8_entity_spawn(pxl8_entity_pool* pool) {
|
demo3d_entity demo3d_entity_spawn(demo3d_entity_pool* pool) {
|
||||||
if (!pool || pool->free_count == 0) return PXL8_ENTITY_INVALID;
|
if (!pool || pool->free_count == 0) return DEMO3D_ENTITY_INVALID;
|
||||||
|
|
||||||
u32 idx = pool->free_list[--pool->free_count];
|
u32 idx = pool->free_list[--pool->free_count];
|
||||||
pool->generations[idx]++;
|
pool->generations[idx]++;
|
||||||
pool->alive_count++;
|
pool->alive_count++;
|
||||||
|
|
||||||
return (pxl8_entity){ .idx = idx, .gen = pool->generations[idx] };
|
return (demo3d_entity){ .idx = idx, .gen = pool->generations[idx] };
|
||||||
}
|
}
|
||||||
|
|
||||||
void pxl8_entity_despawn(pxl8_entity_pool* pool, pxl8_entity e) {
|
void demo3d_entity_despawn(demo3d_entity_pool* pool, demo3d_entity e) {
|
||||||
if (!pool || !pxl8_entity_alive(pool, e)) return;
|
if (!pool || !demo3d_entity_alive(pool, e)) return;
|
||||||
|
|
||||||
for (u32 i = 0; i < pool->component_type_count; i++) {
|
for (u32 i = 0; i < pool->component_type_count; i++) {
|
||||||
pxl8_entity_component_remove(pool, e, i + 1);
|
demo3d_entity_component_remove(pool, e, i + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
pool->free_list[pool->free_count++] = e.idx;
|
pool->free_list[pool->free_count++] = e.idx;
|
||||||
|
|
@ -153,42 +153,42 @@ void pxl8_entity_despawn(pxl8_entity_pool* pool, pxl8_entity e) {
|
||||||
pool->alive_count--;
|
pool->alive_count--;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool pxl8_entity_alive(const pxl8_entity_pool* pool, pxl8_entity e) {
|
bool demo3d_entity_alive(const demo3d_entity_pool* pool, demo3d_entity e) {
|
||||||
if (!pool || e.idx >= pool->capacity) return false;
|
if (!pool || e.idx >= pool->capacity) return false;
|
||||||
return pool->generations[e.idx] == e.gen && e.gen != 0;
|
return pool->generations[e.idx] == e.gen && e.gen != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 pxl8_entity_count(const pxl8_entity_pool* pool) {
|
u32 demo3d_entity_count(const demo3d_entity_pool* pool) {
|
||||||
return pool ? pool->alive_count : 0;
|
return pool ? pool->alive_count : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
pxl8_entity_component pxl8_entity_component_register(pxl8_entity_pool* pool, const char* name, u32 size) {
|
demo3d_entity_component demo3d_entity_component_register(demo3d_entity_pool* pool, const char* name, u32 size) {
|
||||||
if (!pool || !name || size == 0) return PXL8_ENTITY_COMPONENT_INVALID;
|
if (!pool || !name || size == 0) return DEMO3D_ENTITY_COMPONENT_INVALID;
|
||||||
|
|
||||||
pxl8_entity_component existing = pxl8_entity_component_find(pool, name);
|
demo3d_entity_component existing = demo3d_entity_component_find(pool, name);
|
||||||
if (existing != PXL8_ENTITY_COMPONENT_INVALID) return existing;
|
if (existing != DEMO3D_ENTITY_COMPONENT_INVALID) return existing;
|
||||||
|
|
||||||
if (pool->component_type_count >= pool->component_type_capacity) {
|
if (pool->component_type_count >= pool->component_type_capacity) {
|
||||||
u32 new_capacity = pool->component_type_capacity * 2;
|
u32 new_capacity = pool->component_type_capacity * 2;
|
||||||
pxl8_component_type* new_types = pxl8_realloc(pool->component_types, new_capacity * sizeof(pxl8_component_type));
|
demo3d_component_type* new_types = pxl8_realloc(pool->component_types, new_capacity * sizeof(demo3d_component_type));
|
||||||
pxl8_component_storage* new_storage = pxl8_realloc(pool->component_storage, new_capacity * sizeof(pxl8_component_storage));
|
demo3d_component_storage* new_storage = pxl8_realloc(pool->component_storage, new_capacity * sizeof(demo3d_component_storage));
|
||||||
if (!new_types || !new_storage) return PXL8_ENTITY_COMPONENT_INVALID;
|
if (!new_types || !new_storage) return DEMO3D_ENTITY_COMPONENT_INVALID;
|
||||||
|
|
||||||
pool->component_types = new_types;
|
pool->component_types = new_types;
|
||||||
pool->component_storage = new_storage;
|
pool->component_storage = new_storage;
|
||||||
memset(&pool->component_types[pool->component_type_capacity], 0, (new_capacity - pool->component_type_capacity) * sizeof(pxl8_component_type));
|
memset(&pool->component_types[pool->component_type_capacity], 0, (new_capacity - pool->component_type_capacity) * sizeof(demo3d_component_type));
|
||||||
memset(&pool->component_storage[pool->component_type_capacity], 0, (new_capacity - pool->component_type_capacity) * sizeof(pxl8_component_storage));
|
memset(&pool->component_storage[pool->component_type_capacity], 0, (new_capacity - pool->component_type_capacity) * sizeof(demo3d_component_storage));
|
||||||
pool->component_type_capacity = new_capacity;
|
pool->component_type_capacity = new_capacity;
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 type_idx = pool->component_type_count++;
|
u32 type_idx = pool->component_type_count++;
|
||||||
strncpy(pool->component_types[type_idx].name, name, PXL8_ENTITY_COMPONENT_NAME_MAX - 1);
|
strncpy(pool->component_types[type_idx].name, name, DEMO3D_ENTITY_COMPONENT_NAME_MAX - 1);
|
||||||
pool->component_types[type_idx].size = size;
|
pool->component_types[type_idx].size = size;
|
||||||
|
|
||||||
pxl8_component_storage* storage = &pool->component_storage[type_idx];
|
demo3d_component_storage* storage = &pool->component_storage[type_idx];
|
||||||
storage->sparse = pxl8_malloc(pool->capacity * sizeof(u32));
|
storage->sparse = pxl8_malloc(pool->capacity * sizeof(u32));
|
||||||
storage->dense_data = pxl8_malloc(pool->capacity * size);
|
storage->dense_data = pxl8_malloc(pool->capacity * size);
|
||||||
storage->dense_entities = pxl8_malloc(pool->capacity * sizeof(pxl8_entity));
|
storage->dense_entities = pxl8_malloc(pool->capacity * sizeof(demo3d_entity));
|
||||||
storage->count = 0;
|
storage->count = 0;
|
||||||
|
|
||||||
for (u32 i = 0; i < pool->capacity; i++) {
|
for (u32 i = 0; i < pool->capacity; i++) {
|
||||||
|
|
@ -198,28 +198,28 @@ pxl8_entity_component pxl8_entity_component_register(pxl8_entity_pool* pool, con
|
||||||
return type_idx + 1;
|
return type_idx + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
pxl8_entity_component pxl8_entity_component_find(const pxl8_entity_pool* pool, const char* name) {
|
demo3d_entity_component demo3d_entity_component_find(const demo3d_entity_pool* pool, const char* name) {
|
||||||
if (!pool || !name) return PXL8_ENTITY_COMPONENT_INVALID;
|
if (!pool || !name) return DEMO3D_ENTITY_COMPONENT_INVALID;
|
||||||
|
|
||||||
for (u32 i = 0; i < pool->component_type_count; i++) {
|
for (u32 i = 0; i < pool->component_type_count; i++) {
|
||||||
if (strcmp(pool->component_types[i].name, name) == 0) {
|
if (strcmp(pool->component_types[i].name, name) == 0) {
|
||||||
return i + 1;
|
return i + 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return PXL8_ENTITY_COMPONENT_INVALID;
|
return DEMO3D_ENTITY_COMPONENT_INVALID;
|
||||||
}
|
}
|
||||||
|
|
||||||
const char* pxl8_entity_component_name(const pxl8_entity_pool* pool, pxl8_entity_component comp) {
|
const char* demo3d_entity_component_name(const demo3d_entity_pool* pool, demo3d_entity_component comp) {
|
||||||
if (!pool || comp == 0 || comp > pool->component_type_count) return NULL;
|
if (!pool || comp == 0 || comp > pool->component_type_count) return NULL;
|
||||||
return pool->component_types[comp - 1].name;
|
return pool->component_types[comp - 1].name;
|
||||||
}
|
}
|
||||||
|
|
||||||
void* pxl8_entity_component_add(pxl8_entity_pool* pool, pxl8_entity e, pxl8_entity_component comp) {
|
void* demo3d_entity_component_add(demo3d_entity_pool* pool, demo3d_entity e, demo3d_entity_component comp) {
|
||||||
if (!pool || !pxl8_entity_alive(pool, e)) return NULL;
|
if (!pool || !demo3d_entity_alive(pool, e)) return NULL;
|
||||||
if (comp == 0 || comp > pool->component_type_count) return NULL;
|
if (comp == 0 || comp > pool->component_type_count) return NULL;
|
||||||
|
|
||||||
u32 type_idx = comp - 1;
|
u32 type_idx = comp - 1;
|
||||||
pxl8_component_storage* storage = &pool->component_storage[type_idx];
|
demo3d_component_storage* storage = &pool->component_storage[type_idx];
|
||||||
u32 size = pool->component_types[type_idx].size;
|
u32 size = pool->component_types[type_idx].size;
|
||||||
|
|
||||||
if (storage->sparse[e.idx] != UINT32_MAX) {
|
if (storage->sparse[e.idx] != UINT32_MAX) {
|
||||||
|
|
@ -235,12 +235,12 @@ void* pxl8_entity_component_add(pxl8_entity_pool* pool, pxl8_entity e, pxl8_enti
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
void* pxl8_entity_component_get(const pxl8_entity_pool* pool, pxl8_entity e, pxl8_entity_component comp) {
|
void* demo3d_entity_component_get(const demo3d_entity_pool* pool, demo3d_entity e, demo3d_entity_component comp) {
|
||||||
if (!pool || !pxl8_entity_alive(pool, e)) return NULL;
|
if (!pool || !demo3d_entity_alive(pool, e)) return NULL;
|
||||||
if (comp == 0 || comp > pool->component_type_count) return NULL;
|
if (comp == 0 || comp > pool->component_type_count) return NULL;
|
||||||
|
|
||||||
u32 type_idx = comp - 1;
|
u32 type_idx = comp - 1;
|
||||||
const pxl8_component_storage* storage = &pool->component_storage[type_idx];
|
const demo3d_component_storage* storage = &pool->component_storage[type_idx];
|
||||||
|
|
||||||
if (storage->sparse[e.idx] == UINT32_MAX) return NULL;
|
if (storage->sparse[e.idx] == UINT32_MAX) return NULL;
|
||||||
|
|
||||||
|
|
@ -248,12 +248,12 @@ void* pxl8_entity_component_get(const pxl8_entity_pool* pool, pxl8_entity e, pxl
|
||||||
return (u8*)storage->dense_data + storage->sparse[e.idx] * size;
|
return (u8*)storage->dense_data + storage->sparse[e.idx] * size;
|
||||||
}
|
}
|
||||||
|
|
||||||
void pxl8_entity_component_remove(pxl8_entity_pool* pool, pxl8_entity e, pxl8_entity_component comp) {
|
void demo3d_entity_component_remove(demo3d_entity_pool* pool, demo3d_entity e, demo3d_entity_component comp) {
|
||||||
if (!pool || !pxl8_entity_alive(pool, e)) return;
|
if (!pool || !demo3d_entity_alive(pool, e)) return;
|
||||||
if (comp == 0 || comp > pool->component_type_count) return;
|
if (comp == 0 || comp > pool->component_type_count) return;
|
||||||
|
|
||||||
u32 type_idx = comp - 1;
|
u32 type_idx = comp - 1;
|
||||||
pxl8_component_storage* storage = &pool->component_storage[type_idx];
|
demo3d_component_storage* storage = &pool->component_storage[type_idx];
|
||||||
u32 size = pool->component_types[type_idx].size;
|
u32 size = pool->component_types[type_idx].size;
|
||||||
|
|
||||||
u32 dense_idx = storage->sparse[e.idx];
|
u32 dense_idx = storage->sparse[e.idx];
|
||||||
|
|
@ -261,7 +261,7 @@ void pxl8_entity_component_remove(pxl8_entity_pool* pool, pxl8_entity e, pxl8_en
|
||||||
|
|
||||||
u32 last_idx = storage->count - 1;
|
u32 last_idx = storage->count - 1;
|
||||||
if (dense_idx != last_idx) {
|
if (dense_idx != last_idx) {
|
||||||
pxl8_entity last_entity = storage->dense_entities[last_idx];
|
demo3d_entity last_entity = storage->dense_entities[last_idx];
|
||||||
memcpy((u8*)storage->dense_data + dense_idx * size,
|
memcpy((u8*)storage->dense_data + dense_idx * size,
|
||||||
(u8*)storage->dense_data + last_idx * size, size);
|
(u8*)storage->dense_data + last_idx * size, size);
|
||||||
storage->dense_entities[dense_idx] = last_entity;
|
storage->dense_entities[dense_idx] = last_entity;
|
||||||
|
|
@ -272,67 +272,67 @@ void pxl8_entity_component_remove(pxl8_entity_pool* pool, pxl8_entity e, pxl8_en
|
||||||
storage->count--;
|
storage->count--;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool pxl8_entity_component_has(const pxl8_entity_pool* pool, pxl8_entity e, pxl8_entity_component comp) {
|
bool demo3d_entity_component_has(const demo3d_entity_pool* pool, demo3d_entity e, demo3d_entity_component comp) {
|
||||||
if (!pool || !pxl8_entity_alive(pool, e)) return false;
|
if (!pool || !demo3d_entity_alive(pool, e)) return false;
|
||||||
if (comp == 0 || comp > pool->component_type_count) return false;
|
if (comp == 0 || comp > pool->component_type_count) return false;
|
||||||
|
|
||||||
return pool->component_storage[comp - 1].sparse[e.idx] != UINT32_MAX;
|
return pool->component_storage[comp - 1].sparse[e.idx] != UINT32_MAX;
|
||||||
}
|
}
|
||||||
|
|
||||||
pxl8_entity_relationship pxl8_entity_relationship_register(pxl8_entity_pool* pool, const char* name) {
|
demo3d_entity_relationship demo3d_entity_relationship_register(demo3d_entity_pool* pool, const char* name) {
|
||||||
if (!pool || !name) return PXL8_ENTITY_RELATIONSHIP_INVALID;
|
if (!pool || !name) return DEMO3D_ENTITY_RELATIONSHIP_INVALID;
|
||||||
|
|
||||||
pxl8_entity_relationship existing = pxl8_entity_relationship_find(pool, name);
|
demo3d_entity_relationship existing = demo3d_entity_relationship_find(pool, name);
|
||||||
if (existing != PXL8_ENTITY_RELATIONSHIP_INVALID) return existing;
|
if (existing != DEMO3D_ENTITY_RELATIONSHIP_INVALID) return existing;
|
||||||
|
|
||||||
if (pool->relationship_type_count >= pool->relationship_type_capacity) {
|
if (pool->relationship_type_count >= pool->relationship_type_capacity) {
|
||||||
u32 new_capacity = pool->relationship_type_capacity * 2;
|
u32 new_capacity = pool->relationship_type_capacity * 2;
|
||||||
pxl8_relationship_type* new_types = pxl8_realloc(pool->relationship_types, new_capacity * sizeof(pxl8_relationship_type));
|
demo3d_relationship_type* new_types = pxl8_realloc(pool->relationship_types, new_capacity * sizeof(demo3d_relationship_type));
|
||||||
if (!new_types) return PXL8_ENTITY_RELATIONSHIP_INVALID;
|
if (!new_types) return DEMO3D_ENTITY_RELATIONSHIP_INVALID;
|
||||||
|
|
||||||
pool->relationship_types = new_types;
|
pool->relationship_types = new_types;
|
||||||
memset(&pool->relationship_types[pool->relationship_type_capacity], 0, (new_capacity - pool->relationship_type_capacity) * sizeof(pxl8_relationship_type));
|
memset(&pool->relationship_types[pool->relationship_type_capacity], 0, (new_capacity - pool->relationship_type_capacity) * sizeof(demo3d_relationship_type));
|
||||||
pool->relationship_type_capacity = new_capacity;
|
pool->relationship_type_capacity = new_capacity;
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 type_idx = pool->relationship_type_count++;
|
u32 type_idx = pool->relationship_type_count++;
|
||||||
strncpy(pool->relationship_types[type_idx].name, name, PXL8_ENTITY_RELATIONSHIP_NAME_MAX - 1);
|
strncpy(pool->relationship_types[type_idx].name, name, DEMO3D_ENTITY_RELATIONSHIP_NAME_MAX - 1);
|
||||||
|
|
||||||
return type_idx + 1;
|
return type_idx + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
pxl8_entity_relationship pxl8_entity_relationship_find(const pxl8_entity_pool* pool, const char* name) {
|
demo3d_entity_relationship demo3d_entity_relationship_find(const demo3d_entity_pool* pool, const char* name) {
|
||||||
if (!pool || !name) return PXL8_ENTITY_RELATIONSHIP_INVALID;
|
if (!pool || !name) return DEMO3D_ENTITY_RELATIONSHIP_INVALID;
|
||||||
|
|
||||||
for (u32 i = 0; i < pool->relationship_type_count; i++) {
|
for (u32 i = 0; i < pool->relationship_type_count; i++) {
|
||||||
if (strcmp(pool->relationship_types[i].name, name) == 0) {
|
if (strcmp(pool->relationship_types[i].name, name) == 0) {
|
||||||
return i + 1;
|
return i + 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return PXL8_ENTITY_RELATIONSHIP_INVALID;
|
return DEMO3D_ENTITY_RELATIONSHIP_INVALID;
|
||||||
}
|
}
|
||||||
|
|
||||||
const char* pxl8_entity_relationship_name(const pxl8_entity_pool* pool, pxl8_entity_relationship rel) {
|
const char* demo3d_entity_relationship_name(const demo3d_entity_pool* pool, demo3d_entity_relationship rel) {
|
||||||
if (!pool || rel == 0 || rel > pool->relationship_type_count) return NULL;
|
if (!pool || rel == 0 || rel > pool->relationship_type_count) return NULL;
|
||||||
return pool->relationship_types[rel - 1].name;
|
return pool->relationship_types[rel - 1].name;
|
||||||
}
|
}
|
||||||
|
|
||||||
void pxl8_entity_relationship_add(pxl8_entity_pool* pool, pxl8_entity subject, pxl8_entity_relationship rel, pxl8_entity object) {
|
void demo3d_entity_relationship_add(demo3d_entity_pool* pool, demo3d_entity subject, demo3d_entity_relationship rel, demo3d_entity object) {
|
||||||
if (!pool) return;
|
if (!pool) return;
|
||||||
if (!pxl8_entity_alive(pool, subject) || !pxl8_entity_alive(pool, object)) return;
|
if (!demo3d_entity_alive(pool, subject) || !demo3d_entity_alive(pool, object)) return;
|
||||||
if (rel == 0 || rel > pool->relationship_type_count) return;
|
if (rel == 0 || rel > pool->relationship_type_count) return;
|
||||||
if (pxl8_entity_relationship_has(pool, subject, rel, object)) return;
|
if (demo3d_entity_relationship_has(pool, subject, rel, object)) return;
|
||||||
|
|
||||||
if (pool->relationship_count >= pool->relationship_capacity) {
|
if (pool->relationship_count >= pool->relationship_capacity) {
|
||||||
u32 new_capacity = pool->relationship_capacity * 2;
|
u32 new_capacity = pool->relationship_capacity * 2;
|
||||||
pxl8_relationship_entry* new_rels = pxl8_realloc(pool->relationships, new_capacity * sizeof(pxl8_relationship_entry));
|
demo3d_relationship_entry* new_rels = pxl8_realloc(pool->relationships, new_capacity * sizeof(demo3d_relationship_entry));
|
||||||
if (!new_rels) return;
|
if (!new_rels) return;
|
||||||
pool->relationships = new_rels;
|
pool->relationships = new_rels;
|
||||||
pool->relationship_capacity = new_capacity;
|
pool->relationship_capacity = new_capacity;
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 entry_idx = pool->relationship_count++;
|
u32 entry_idx = pool->relationship_count++;
|
||||||
pxl8_relationship_entry* entry = &pool->relationships[entry_idx];
|
demo3d_relationship_entry* entry = &pool->relationships[entry_idx];
|
||||||
entry->subject = subject;
|
entry->subject = subject;
|
||||||
entry->object = object;
|
entry->object = object;
|
||||||
entry->rel = rel;
|
entry->rel = rel;
|
||||||
|
|
@ -344,7 +344,7 @@ void pxl8_entity_relationship_add(pxl8_entity_pool* pool, pxl8_entity subject, p
|
||||||
pool->rel_by_object[object.idx] = entry_idx;
|
pool->rel_by_object[object.idx] = entry_idx;
|
||||||
}
|
}
|
||||||
|
|
||||||
void pxl8_entity_relationship_remove(pxl8_entity_pool* pool, pxl8_entity subject, pxl8_entity_relationship rel, pxl8_entity object) {
|
void demo3d_entity_relationship_remove(demo3d_entity_pool* pool, demo3d_entity subject, demo3d_entity_relationship rel, demo3d_entity object) {
|
||||||
if (!pool) return;
|
if (!pool) return;
|
||||||
if (rel == 0 || rel > pool->relationship_type_count) return;
|
if (rel == 0 || rel > pool->relationship_type_count) return;
|
||||||
|
|
||||||
|
|
@ -352,9 +352,9 @@ void pxl8_entity_relationship_remove(pxl8_entity_pool* pool, pxl8_entity subject
|
||||||
u32 idx = *prev_ptr;
|
u32 idx = *prev_ptr;
|
||||||
|
|
||||||
while (idx != UINT32_MAX) {
|
while (idx != UINT32_MAX) {
|
||||||
pxl8_relationship_entry* entry = &pool->relationships[idx];
|
demo3d_relationship_entry* entry = &pool->relationships[idx];
|
||||||
if (pxl8_entity_eq(entry->subject, subject) &&
|
if (demo3d_entity_eq(entry->subject, subject) &&
|
||||||
pxl8_entity_eq(entry->object, object) &&
|
demo3d_entity_eq(entry->object, object) &&
|
||||||
entry->rel == rel) {
|
entry->rel == rel) {
|
||||||
|
|
||||||
*prev_ptr = entry->next_by_subject;
|
*prev_ptr = entry->next_by_subject;
|
||||||
|
|
@ -370,7 +370,7 @@ void pxl8_entity_relationship_remove(pxl8_entity_pool* pool, pxl8_entity subject
|
||||||
|
|
||||||
if (idx != pool->relationship_count - 1) {
|
if (idx != pool->relationship_count - 1) {
|
||||||
u32 last_idx = pool->relationship_count - 1;
|
u32 last_idx = pool->relationship_count - 1;
|
||||||
pxl8_relationship_entry* last = &pool->relationships[last_idx];
|
demo3d_relationship_entry* last = &pool->relationships[last_idx];
|
||||||
|
|
||||||
u32* last_subj_prev = &pool->rel_by_subject[last->subject.idx];
|
u32* last_subj_prev = &pool->rel_by_subject[last->subject.idx];
|
||||||
while (*last_subj_prev != UINT32_MAX) {
|
while (*last_subj_prev != UINT32_MAX) {
|
||||||
|
|
@ -400,15 +400,15 @@ void pxl8_entity_relationship_remove(pxl8_entity_pool* pool, pxl8_entity subject
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool pxl8_entity_relationship_has(const pxl8_entity_pool* pool, pxl8_entity subject, pxl8_entity_relationship rel, pxl8_entity object) {
|
bool demo3d_entity_relationship_has(const demo3d_entity_pool* pool, demo3d_entity subject, demo3d_entity_relationship rel, demo3d_entity object) {
|
||||||
if (!pool) return false;
|
if (!pool) return false;
|
||||||
if (rel == 0 || rel > pool->relationship_type_count) return false;
|
if (rel == 0 || rel > pool->relationship_type_count) return false;
|
||||||
|
|
||||||
u32 idx = pool->rel_by_subject[subject.idx];
|
u32 idx = pool->rel_by_subject[subject.idx];
|
||||||
while (idx != UINT32_MAX) {
|
while (idx != UINT32_MAX) {
|
||||||
const pxl8_relationship_entry* entry = &pool->relationships[idx];
|
const demo3d_relationship_entry* entry = &pool->relationships[idx];
|
||||||
if (pxl8_entity_eq(entry->subject, subject) &&
|
if (demo3d_entity_eq(entry->subject, subject) &&
|
||||||
pxl8_entity_eq(entry->object, object) &&
|
demo3d_entity_eq(entry->object, object) &&
|
||||||
entry->rel == rel) {
|
entry->rel == rel) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
@ -417,15 +417,15 @@ bool pxl8_entity_relationship_has(const pxl8_entity_pool* pool, pxl8_entity subj
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 pxl8_entity_relationship_subjects(const pxl8_entity_pool* pool, pxl8_entity object, pxl8_entity_relationship rel, pxl8_entity* out, u32 max) {
|
u32 demo3d_entity_relationship_subjects(const demo3d_entity_pool* pool, demo3d_entity object, demo3d_entity_relationship rel, demo3d_entity* out, u32 max) {
|
||||||
if (!pool || !out || max == 0) return 0;
|
if (!pool || !out || max == 0) return 0;
|
||||||
if (rel == 0 || rel > pool->relationship_type_count) return 0;
|
if (rel == 0 || rel > pool->relationship_type_count) return 0;
|
||||||
|
|
||||||
u32 count = 0;
|
u32 count = 0;
|
||||||
u32 idx = pool->rel_by_object[object.idx];
|
u32 idx = pool->rel_by_object[object.idx];
|
||||||
while (idx != UINT32_MAX && count < max) {
|
while (idx != UINT32_MAX && count < max) {
|
||||||
const pxl8_relationship_entry* entry = &pool->relationships[idx];
|
const demo3d_relationship_entry* entry = &pool->relationships[idx];
|
||||||
if (pxl8_entity_eq(entry->object, object) && entry->rel == rel) {
|
if (demo3d_entity_eq(entry->object, object) && entry->rel == rel) {
|
||||||
out[count++] = entry->subject;
|
out[count++] = entry->subject;
|
||||||
}
|
}
|
||||||
idx = entry->next_by_object;
|
idx = entry->next_by_object;
|
||||||
|
|
@ -433,15 +433,15 @@ u32 pxl8_entity_relationship_subjects(const pxl8_entity_pool* pool, pxl8_entity
|
||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 pxl8_entity_relationship_objects(const pxl8_entity_pool* pool, pxl8_entity subject, pxl8_entity_relationship rel, pxl8_entity* out, u32 max) {
|
u32 demo3d_entity_relationship_objects(const demo3d_entity_pool* pool, demo3d_entity subject, demo3d_entity_relationship rel, demo3d_entity* out, u32 max) {
|
||||||
if (!pool || !out || max == 0) return 0;
|
if (!pool || !out || max == 0) return 0;
|
||||||
if (rel == 0 || rel > pool->relationship_type_count) return 0;
|
if (rel == 0 || rel > pool->relationship_type_count) return 0;
|
||||||
|
|
||||||
u32 count = 0;
|
u32 count = 0;
|
||||||
u32 idx = pool->rel_by_subject[subject.idx];
|
u32 idx = pool->rel_by_subject[subject.idx];
|
||||||
while (idx != UINT32_MAX && count < max) {
|
while (idx != UINT32_MAX && count < max) {
|
||||||
const pxl8_relationship_entry* entry = &pool->relationships[idx];
|
const demo3d_relationship_entry* entry = &pool->relationships[idx];
|
||||||
if (pxl8_entity_eq(entry->subject, subject) && entry->rel == rel) {
|
if (demo3d_entity_eq(entry->subject, subject) && entry->rel == rel) {
|
||||||
out[count++] = entry->object;
|
out[count++] = entry->object;
|
||||||
}
|
}
|
||||||
idx = entry->next_by_subject;
|
idx = entry->next_by_subject;
|
||||||
|
|
@ -449,20 +449,20 @@ u32 pxl8_entity_relationship_objects(const pxl8_entity_pool* pool, pxl8_entity s
|
||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
|
|
||||||
void pxl8_entity_each(pxl8_entity_pool* pool, pxl8_entity_component comp, pxl8_entity_each_fn fn, void* ctx) {
|
void demo3d_entity_each(demo3d_entity_pool* pool, demo3d_entity_component comp, demo3d_entity_each_fn fn, void* ctx) {
|
||||||
if (!pool || !fn) return;
|
if (!pool || !fn) return;
|
||||||
if (comp == 0 || comp > pool->component_type_count) return;
|
if (comp == 0 || comp > pool->component_type_count) return;
|
||||||
|
|
||||||
pxl8_component_storage* storage = &pool->component_storage[comp - 1];
|
demo3d_component_storage* storage = &pool->component_storage[comp - 1];
|
||||||
for (u32 i = 0; i < storage->count; i++) {
|
for (u32 i = 0; i < storage->count; i++) {
|
||||||
pxl8_entity e = storage->dense_entities[i];
|
demo3d_entity e = storage->dense_entities[i];
|
||||||
if (pxl8_entity_alive(pool, e)) {
|
if (demo3d_entity_alive(pool, e)) {
|
||||||
fn(pool, e, ctx);
|
fn(pool, e, ctx);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void pxl8_entity_each_with(pxl8_entity_pool* pool, const pxl8_entity_component* comps, u32 count, pxl8_entity_each_fn fn, void* ctx) {
|
void demo3d_entity_each_with(demo3d_entity_pool* pool, const demo3d_entity_component* comps, u32 count, demo3d_entity_each_fn fn, void* ctx) {
|
||||||
if (!pool || !comps || !fn || count == 0) return;
|
if (!pool || !comps || !fn || count == 0) return;
|
||||||
|
|
||||||
u32 smallest_idx = 0;
|
u32 smallest_idx = 0;
|
||||||
|
|
@ -477,15 +477,15 @@ void pxl8_entity_each_with(pxl8_entity_pool* pool, const pxl8_entity_component*
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pxl8_component_storage* storage = &pool->component_storage[comps[smallest_idx] - 1];
|
demo3d_component_storage* storage = &pool->component_storage[comps[smallest_idx] - 1];
|
||||||
for (u32 i = 0; i < storage->count; i++) {
|
for (u32 i = 0; i < storage->count; i++) {
|
||||||
pxl8_entity e = storage->dense_entities[i];
|
demo3d_entity e = storage->dense_entities[i];
|
||||||
if (!pxl8_entity_alive(pool, e)) continue;
|
if (!demo3d_entity_alive(pool, e)) continue;
|
||||||
|
|
||||||
bool has_all = true;
|
bool has_all = true;
|
||||||
for (u32 j = 0; j < count && has_all; j++) {
|
for (u32 j = 0; j < count && has_all; j++) {
|
||||||
if (j != smallest_idx) {
|
if (j != smallest_idx) {
|
||||||
has_all = pxl8_entity_component_has(pool, e, comps[j]);
|
has_all = demo3d_entity_component_has(pool, e, comps[j]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
67
demo3d/client/world/demo3d_entity.h
Normal file
67
demo3d/client/world/demo3d_entity.h
Normal file
|
|
@ -0,0 +1,67 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "pxl8_types.h"
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
typedef struct demo3d_entity_pool demo3d_entity_pool;
|
||||||
|
|
||||||
|
typedef struct demo3d_entity {
|
||||||
|
u32 idx;
|
||||||
|
u32 gen;
|
||||||
|
} demo3d_entity;
|
||||||
|
|
||||||
|
#define DEMO3D_ENTITY_INVALID ((demo3d_entity){0, 0})
|
||||||
|
|
||||||
|
typedef u32 demo3d_entity_component;
|
||||||
|
typedef u32 demo3d_entity_relationship;
|
||||||
|
|
||||||
|
#define DEMO3D_ENTITY_COMPONENT_INVALID 0
|
||||||
|
#define DEMO3D_ENTITY_RELATIONSHIP_INVALID 0
|
||||||
|
|
||||||
|
demo3d_entity_pool* demo3d_entity_pool_create(u32 capacity);
|
||||||
|
void demo3d_entity_pool_clear(demo3d_entity_pool* pool);
|
||||||
|
void demo3d_entity_pool_destroy(demo3d_entity_pool* pool);
|
||||||
|
|
||||||
|
demo3d_entity demo3d_entity_spawn(demo3d_entity_pool* pool);
|
||||||
|
void demo3d_entity_despawn(demo3d_entity_pool* pool, demo3d_entity e);
|
||||||
|
bool demo3d_entity_alive(const demo3d_entity_pool* pool, demo3d_entity e);
|
||||||
|
u32 demo3d_entity_count(const demo3d_entity_pool* pool);
|
||||||
|
|
||||||
|
demo3d_entity_component demo3d_entity_component_register(demo3d_entity_pool* pool, const char* name, u32 size);
|
||||||
|
demo3d_entity_component demo3d_entity_component_find(const demo3d_entity_pool* pool, const char* name);
|
||||||
|
const char* demo3d_entity_component_name(const demo3d_entity_pool* pool, demo3d_entity_component comp);
|
||||||
|
|
||||||
|
void* demo3d_entity_component_add(demo3d_entity_pool* pool, demo3d_entity e, demo3d_entity_component comp);
|
||||||
|
void* demo3d_entity_component_get(const demo3d_entity_pool* pool, demo3d_entity e, demo3d_entity_component comp);
|
||||||
|
void demo3d_entity_component_remove(demo3d_entity_pool* pool, demo3d_entity e, demo3d_entity_component comp);
|
||||||
|
bool demo3d_entity_component_has(const demo3d_entity_pool* pool, demo3d_entity e, demo3d_entity_component comp);
|
||||||
|
|
||||||
|
demo3d_entity_relationship demo3d_entity_relationship_register(demo3d_entity_pool* pool, const char* name);
|
||||||
|
demo3d_entity_relationship demo3d_entity_relationship_find(const demo3d_entity_pool* pool, const char* name);
|
||||||
|
const char* demo3d_entity_relationship_name(const demo3d_entity_pool* pool, demo3d_entity_relationship rel);
|
||||||
|
|
||||||
|
void demo3d_entity_relationship_add(demo3d_entity_pool* pool, demo3d_entity subject, demo3d_entity_relationship rel, demo3d_entity object);
|
||||||
|
void demo3d_entity_relationship_remove(demo3d_entity_pool* pool, demo3d_entity subject, demo3d_entity_relationship rel, demo3d_entity object);
|
||||||
|
bool demo3d_entity_relationship_has(const demo3d_entity_pool* pool, demo3d_entity subject, demo3d_entity_relationship rel, demo3d_entity object);
|
||||||
|
|
||||||
|
u32 demo3d_entity_relationship_subjects(const demo3d_entity_pool* pool, demo3d_entity object, demo3d_entity_relationship rel, demo3d_entity* out, u32 max);
|
||||||
|
u32 demo3d_entity_relationship_objects(const demo3d_entity_pool* pool, demo3d_entity subject, demo3d_entity_relationship rel, demo3d_entity* out, u32 max);
|
||||||
|
|
||||||
|
typedef void (*demo3d_entity_each_fn)(demo3d_entity_pool* pool, demo3d_entity e, void* ctx);
|
||||||
|
void demo3d_entity_each(demo3d_entity_pool* pool, demo3d_entity_component comp, demo3d_entity_each_fn fn, void* ctx);
|
||||||
|
void demo3d_entity_each_with(demo3d_entity_pool* pool, const demo3d_entity_component* comps, u32 count, demo3d_entity_each_fn fn, void* ctx);
|
||||||
|
|
||||||
|
static inline bool demo3d_entity_valid(demo3d_entity e) {
|
||||||
|
return e.idx != 0 || e.gen != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline bool demo3d_entity_eq(demo3d_entity a, demo3d_entity b) {
|
||||||
|
return a.idx == b.idx && a.gen == b.gen;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
@ -1,26 +1,26 @@
|
||||||
#include "pxl8_world.h"
|
#include "demo3d_world.h"
|
||||||
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
#include "pxl8_hal.h"
|
#include "pxl8_platform.h"
|
||||||
|
|
||||||
#ifdef PXL8_ASYNC_THREADS
|
#ifdef PXL8_ASYNC_THREADS
|
||||||
#include <stdatomic.h>
|
#include <stdatomic.h>
|
||||||
#include "pxl8_queue.h"
|
#include "pxl8_queue.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "pxl8_bsp_render.h"
|
#include "demo3d_bsp_render.h"
|
||||||
#include "pxl8_io.h"
|
#include "pxl8_io.h"
|
||||||
#include "pxl8_gfx3d.h"
|
#include "pxl8_gfx3d.h"
|
||||||
#include "pxl8_log.h"
|
#include "pxl8_log.h"
|
||||||
#include "pxl8_mem.h"
|
#include "pxl8_mem.h"
|
||||||
#include "pxl8_protocol.h"
|
#include "demo3d_protocol.h"
|
||||||
#include "pxl8_sim.h"
|
#include "demo3d_sim.h"
|
||||||
|
|
||||||
#define PXL8_VIS_MAX_NODES (PXL8_WORLD_MAX_LOADED_CHUNKS * 512)
|
#define DEMO3D_VIS_MAX_NODES (DEMO3D_WORLD_MAX_LOADED_CHUNKS * 512)
|
||||||
#define PXL8_VIS_MAX_QUEUE (PXL8_VIS_MAX_NODES * 4)
|
#define DEMO3D_VIS_MAX_QUEUE (DEMO3D_VIS_MAX_NODES * 4)
|
||||||
#define PXL8_VIS_BYTES ((PXL8_VIS_MAX_NODES + 7) / 8)
|
#define DEMO3D_VIS_BYTES ((DEMO3D_VIS_MAX_NODES + 7) / 8)
|
||||||
#define PXL8_WORLD_ENTITY_CAPACITY 256
|
#define DEMO3D_WORLD_ENTITY_CAPACITY 256
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
u16 chunk_idx;
|
u16 chunk_idx;
|
||||||
|
|
@ -28,49 +28,49 @@ typedef struct {
|
||||||
pxl8_rect window;
|
pxl8_rect window;
|
||||||
} world_vis_node;
|
} world_vis_node;
|
||||||
|
|
||||||
struct pxl8_world {
|
struct demo3d_world {
|
||||||
pxl8_loaded_chunk loaded[PXL8_WORLD_MAX_LOADED_CHUNKS];
|
demo3d_loaded_chunk loaded[DEMO3D_WORLD_MAX_LOADED_CHUNKS];
|
||||||
u32 loaded_count;
|
u32 loaded_count;
|
||||||
pxl8_world_chunk* active_chunk;
|
demo3d_chunk* active_chunk;
|
||||||
pxl8_bsp_render_state* active_render_state;
|
demo3d_bsp_render_state* active_render_state;
|
||||||
|
|
||||||
pxl8_gfx_material shared_materials[16];
|
pxl8_gfx_material shared_materials[16];
|
||||||
bool shared_material_set[16];
|
bool shared_material_set[16];
|
||||||
|
|
||||||
pxl8_world_chunk_cache* chunk_cache;
|
demo3d_chunk_cache* chunk_cache;
|
||||||
pxl8_entity_pool* entities;
|
demo3d_entity_pool* entities;
|
||||||
|
|
||||||
pxl8_sim_entity local_player;
|
demo3d_sim_entity local_player;
|
||||||
u64 client_tick;
|
u64 client_tick;
|
||||||
|
|
||||||
pxl8_vec2 pointer_motion;
|
pxl8_vec2 pointer_motion;
|
||||||
pxl8_sim_config sim_config;
|
demo3d_sim_config sim_config;
|
||||||
|
|
||||||
u8 vis_bits[PXL8_VIS_BYTES];
|
u8 vis_bits[DEMO3D_VIS_BYTES];
|
||||||
u8* vis_ptrs[PXL8_WORLD_MAX_LOADED_CHUNKS];
|
u8* vis_ptrs[DEMO3D_WORLD_MAX_LOADED_CHUNKS];
|
||||||
pxl8_rect vis_windows[PXL8_VIS_MAX_NODES];
|
pxl8_rect vis_windows[DEMO3D_VIS_MAX_NODES];
|
||||||
pxl8_rect* vis_win_ptrs[PXL8_WORLD_MAX_LOADED_CHUNKS];
|
pxl8_rect* vis_win_ptrs[DEMO3D_WORLD_MAX_LOADED_CHUNKS];
|
||||||
world_vis_node vis_queue[PXL8_VIS_MAX_QUEUE];
|
world_vis_node vis_queue[DEMO3D_VIS_MAX_QUEUE];
|
||||||
|
|
||||||
#ifdef PXL8_ASYNC_THREADS
|
#ifdef PXL8_ASYNC_THREADS
|
||||||
pxl8_sim_entity render_state[2];
|
demo3d_sim_entity render_state[2];
|
||||||
atomic_uint active_buffer;
|
atomic_uint active_buffer;
|
||||||
pxl8_thread* sim_thread;
|
pxl8_thread* sim_thread;
|
||||||
atomic_bool sim_running;
|
atomic_bool sim_running;
|
||||||
atomic_bool sim_paused;
|
atomic_bool sim_paused;
|
||||||
pxl8_net* net;
|
demo3d_net* net;
|
||||||
pxl8_queue input_queue;
|
pxl8_queue input_queue;
|
||||||
f32 sim_accumulator;
|
f32 sim_accumulator;
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
pxl8_world* pxl8_world_create(void) {
|
demo3d_world* demo3d_world_create(void) {
|
||||||
pxl8_world* world = pxl8_calloc(1, sizeof(pxl8_world));
|
demo3d_world* world = pxl8_calloc(1, sizeof(demo3d_world));
|
||||||
if (!world) return NULL;
|
if (!world) return NULL;
|
||||||
|
|
||||||
world->chunk_cache = pxl8_world_chunk_cache_create();
|
world->chunk_cache = demo3d_chunk_cache_create();
|
||||||
world->entities = pxl8_entity_pool_create(PXL8_WORLD_ENTITY_CAPACITY);
|
world->entities = demo3d_entity_pool_create(DEMO3D_WORLD_ENTITY_CAPACITY);
|
||||||
world->sim_config = (pxl8_sim_config){
|
world->sim_config = (demo3d_sim_config){
|
||||||
.move_speed = 180.0f,
|
.move_speed = 180.0f,
|
||||||
.ground_accel = 10.0f,
|
.ground_accel = 10.0f,
|
||||||
.air_accel = 1.0f,
|
.air_accel = 1.0f,
|
||||||
|
|
@ -84,36 +84,36 @@ pxl8_world* pxl8_world_create(void) {
|
||||||
};
|
};
|
||||||
|
|
||||||
if (!world->chunk_cache || !world->entities) {
|
if (!world->chunk_cache || !world->entities) {
|
||||||
pxl8_world_destroy(world);
|
demo3d_world_destroy(world);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
return world;
|
return world;
|
||||||
}
|
}
|
||||||
|
|
||||||
void pxl8_world_destroy(pxl8_world* world) {
|
void demo3d_world_destroy(demo3d_world* world) {
|
||||||
if (!world) return;
|
if (!world) return;
|
||||||
|
|
||||||
for (u32 i = 0; i < world->loaded_count; i++) {
|
for (u32 i = 0; i < world->loaded_count; i++) {
|
||||||
pxl8_bsp_render_state_destroy(world->loaded[i].render_state);
|
demo3d_bsp_render_state_destroy(world->loaded[i].render_state);
|
||||||
}
|
}
|
||||||
pxl8_world_chunk_cache_destroy(world->chunk_cache);
|
demo3d_chunk_cache_destroy(world->chunk_cache);
|
||||||
pxl8_entity_pool_destroy(world->entities);
|
demo3d_entity_pool_destroy(world->entities);
|
||||||
pxl8_free(world);
|
pxl8_free(world);
|
||||||
}
|
}
|
||||||
|
|
||||||
pxl8_world_chunk_cache* pxl8_world_get_chunk_cache(pxl8_world* world) {
|
demo3d_chunk_cache* demo3d_world_get_chunk_cache(demo3d_world* world) {
|
||||||
if (!world) return NULL;
|
if (!world) return NULL;
|
||||||
return world->chunk_cache;
|
return world->chunk_cache;
|
||||||
}
|
}
|
||||||
|
|
||||||
pxl8_world_chunk* pxl8_world_active_chunk(pxl8_world* world) {
|
demo3d_chunk* demo3d_world_active_chunk(demo3d_world* world) {
|
||||||
if (!world) return NULL;
|
if (!world) return NULL;
|
||||||
return world->active_chunk;
|
return world->active_chunk;
|
||||||
}
|
}
|
||||||
|
|
||||||
pxl8_sim_world pxl8_world_sim_world(const pxl8_world* world, pxl8_vec3 pos) {
|
demo3d_sim_world demo3d_world_sim_world(const demo3d_world* world, pxl8_vec3 pos) {
|
||||||
pxl8_sim_world sim = {0};
|
demo3d_sim_world sim = {0};
|
||||||
const f32 chunk_size = 16.0f * 64.0f;
|
const f32 chunk_size = 16.0f * 64.0f;
|
||||||
sim.chunk_size = chunk_size;
|
sim.chunk_size = chunk_size;
|
||||||
|
|
||||||
|
|
@ -123,7 +123,7 @@ pxl8_sim_world pxl8_world_sim_world(const pxl8_world* world, pxl8_vec3 pos) {
|
||||||
sim.center_cz = pcz;
|
sim.center_cz = pcz;
|
||||||
|
|
||||||
for (u32 i = 0; i < world->loaded_count; i++) {
|
for (u32 i = 0; i < world->loaded_count; i++) {
|
||||||
const pxl8_loaded_chunk* lc = &world->loaded[i];
|
const demo3d_loaded_chunk* lc = &world->loaded[i];
|
||||||
if (!lc->chunk || !lc->chunk->bsp) continue;
|
if (!lc->chunk || !lc->chunk->bsp) continue;
|
||||||
i32 dx = lc->cx - pcx + 1;
|
i32 dx = lc->cx - pcx + 1;
|
||||||
i32 dz = lc->cz - pcz + 1;
|
i32 dz = lc->cz - pcz + 1;
|
||||||
|
|
@ -135,7 +135,7 @@ pxl8_sim_world pxl8_world_sim_world(const pxl8_world* world, pxl8_vec3 pos) {
|
||||||
return sim;
|
return sim;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void entity_to_userdata(const pxl8_sim_entity* ent, u8* userdata) {
|
static void entity_to_userdata(const demo3d_sim_entity* ent, u8* userdata) {
|
||||||
u8* p = userdata;
|
u8* p = userdata;
|
||||||
memcpy(p, &ent->pos.x, 4); p += 4;
|
memcpy(p, &ent->pos.x, 4); p += 4;
|
||||||
memcpy(p, &ent->pos.y, 4); p += 4;
|
memcpy(p, &ent->pos.y, 4); p += 4;
|
||||||
|
|
@ -149,7 +149,7 @@ static void entity_to_userdata(const pxl8_sim_entity* ent, u8* userdata) {
|
||||||
memcpy(p, &ent->kind, 2);
|
memcpy(p, &ent->kind, 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void userdata_to_entity(const u8* userdata, pxl8_sim_entity* ent) {
|
static void userdata_to_entity(const u8* userdata, demo3d_sim_entity* ent) {
|
||||||
const u8* p = userdata;
|
const u8* p = userdata;
|
||||||
memcpy(&ent->pos.x, p, 4); p += 4;
|
memcpy(&ent->pos.x, p, 4); p += 4;
|
||||||
memcpy(&ent->pos.y, p, 4); p += 4;
|
memcpy(&ent->pos.y, p, 4); p += 4;
|
||||||
|
|
@ -163,17 +163,17 @@ static void userdata_to_entity(const u8* userdata, pxl8_sim_entity* ent) {
|
||||||
memcpy(&ent->kind, p, 2);
|
memcpy(&ent->kind, p, 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool pxl8_world_point_solid(const pxl8_world* world, f32 x, f32 y, f32 z) {
|
bool demo3d_world_point_solid(const demo3d_world* world, f32 x, f32 y, f32 z) {
|
||||||
if (!world) return false;
|
if (!world) return false;
|
||||||
|
|
||||||
if (world->active_chunk && world->active_chunk->bsp) {
|
if (world->active_chunk && world->active_chunk->bsp) {
|
||||||
return pxl8_bsp_point_solid(world->active_chunk->bsp, (pxl8_vec3){x, y, z});
|
return demo3d_bsp_point_solid(world->active_chunk->bsp, (pxl8_vec3){x, y, z});
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
pxl8_ray pxl8_world_ray(const pxl8_world* world, pxl8_vec3 from, pxl8_vec3 to) {
|
pxl8_ray demo3d_world_ray(const demo3d_world* world, pxl8_vec3 from, pxl8_vec3 to) {
|
||||||
pxl8_ray result = {0};
|
pxl8_ray result = {0};
|
||||||
|
|
||||||
if (!world) return result;
|
if (!world) return result;
|
||||||
|
|
@ -193,18 +193,18 @@ pxl8_ray pxl8_world_ray(const pxl8_world* world, pxl8_vec3 from, pxl8_vec3 to) {
|
||||||
from.z + dir.z * t
|
from.z + dir.z * t
|
||||||
};
|
};
|
||||||
|
|
||||||
if (pxl8_world_point_solid(world, pos.x, pos.y, pos.z)) {
|
if (demo3d_world_point_solid(world, pos.x, pos.y, pos.z)) {
|
||||||
result.hit = true;
|
result.hit = true;
|
||||||
result.fraction = t;
|
result.fraction = t;
|
||||||
result.point = pos;
|
result.point = pos;
|
||||||
|
|
||||||
f32 eps = 0.1f;
|
f32 eps = 0.1f;
|
||||||
bool sx_neg = pxl8_world_point_solid(world, pos.x - eps, pos.y, pos.z);
|
bool sx_neg = demo3d_world_point_solid(world, pos.x - eps, pos.y, pos.z);
|
||||||
bool sx_pos = pxl8_world_point_solid(world, pos.x + eps, pos.y, pos.z);
|
bool sx_pos = demo3d_world_point_solid(world, pos.x + eps, pos.y, pos.z);
|
||||||
bool sy_neg = pxl8_world_point_solid(world, pos.x, pos.y - eps, pos.z);
|
bool sy_neg = demo3d_world_point_solid(world, pos.x, pos.y - eps, pos.z);
|
||||||
bool sy_pos = pxl8_world_point_solid(world, pos.x, pos.y + eps, pos.z);
|
bool sy_pos = demo3d_world_point_solid(world, pos.x, pos.y + eps, pos.z);
|
||||||
bool sz_neg = pxl8_world_point_solid(world, pos.x, pos.y, pos.z - eps);
|
bool sz_neg = demo3d_world_point_solid(world, pos.x, pos.y, pos.z - eps);
|
||||||
bool sz_pos = pxl8_world_point_solid(world, pos.x, pos.y, pos.z + eps);
|
bool sz_pos = demo3d_world_point_solid(world, pos.x, pos.y, pos.z + eps);
|
||||||
|
|
||||||
result.normal = (pxl8_vec3){
|
result.normal = (pxl8_vec3){
|
||||||
(sx_neg && !sx_pos) ? 1.0f : (!sx_neg && sx_pos) ? -1.0f : 0.0f,
|
(sx_neg && !sx_pos) ? 1.0f : (!sx_neg && sx_pos) ? -1.0f : 0.0f,
|
||||||
|
|
@ -228,22 +228,22 @@ pxl8_ray pxl8_world_ray(const pxl8_world* world, pxl8_vec3 from, pxl8_vec3 to) {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
pxl8_ray pxl8_world_sweep(const pxl8_world* world, pxl8_vec3 from, pxl8_vec3 to, f32 radius) {
|
pxl8_ray demo3d_world_sweep(const demo3d_world* world, pxl8_vec3 from, pxl8_vec3 to, f32 radius) {
|
||||||
pxl8_ray result = {0};
|
pxl8_ray result = {0};
|
||||||
|
|
||||||
if (!world) return result;
|
if (!world) return result;
|
||||||
|
|
||||||
f32 diag = radius * 0.707f;
|
f32 diag = radius * 0.707f;
|
||||||
|
|
||||||
bool dest_blocked = pxl8_world_point_solid(world, to.x, to.y, to.z) ||
|
bool dest_blocked = demo3d_world_point_solid(world, to.x, to.y, to.z) ||
|
||||||
pxl8_world_point_solid(world, to.x + radius, to.y, to.z) ||
|
demo3d_world_point_solid(world, to.x + radius, to.y, to.z) ||
|
||||||
pxl8_world_point_solid(world, to.x - radius, to.y, to.z) ||
|
demo3d_world_point_solid(world, to.x - radius, to.y, to.z) ||
|
||||||
pxl8_world_point_solid(world, to.x, to.y, to.z + radius) ||
|
demo3d_world_point_solid(world, to.x, to.y, to.z + radius) ||
|
||||||
pxl8_world_point_solid(world, to.x, to.y, to.z - radius) ||
|
demo3d_world_point_solid(world, to.x, to.y, to.z - radius) ||
|
||||||
pxl8_world_point_solid(world, to.x + diag, to.y, to.z + diag) ||
|
demo3d_world_point_solid(world, to.x + diag, to.y, to.z + diag) ||
|
||||||
pxl8_world_point_solid(world, to.x + diag, to.y, to.z - diag) ||
|
demo3d_world_point_solid(world, to.x + diag, to.y, to.z - diag) ||
|
||||||
pxl8_world_point_solid(world, to.x - diag, to.y, to.z + diag) ||
|
demo3d_world_point_solid(world, to.x - diag, to.y, to.z + diag) ||
|
||||||
pxl8_world_point_solid(world, to.x - diag, to.y, to.z - diag);
|
demo3d_world_point_solid(world, to.x - diag, to.y, to.z - diag);
|
||||||
|
|
||||||
if (dest_blocked) {
|
if (dest_blocked) {
|
||||||
result.hit = true;
|
result.hit = true;
|
||||||
|
|
@ -261,10 +261,10 @@ pxl8_ray pxl8_world_sweep(const pxl8_world* world, pxl8_vec3 from, pxl8_vec3 to,
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
void pxl8_world_update(pxl8_world* world, f32 dt) {
|
void demo3d_world_update(demo3d_world* world, f32 dt) {
|
||||||
(void)dt;
|
(void)dt;
|
||||||
if (!world) return;
|
if (!world) return;
|
||||||
pxl8_world_chunk_cache_tick(world->chunk_cache);
|
demo3d_chunk_cache_tick(world->chunk_cache);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline bool vr_valid(pxl8_rect r) {
|
static inline bool vr_valid(pxl8_rect r) {
|
||||||
|
|
@ -319,9 +319,9 @@ static pxl8_rect project_portal(f32 px0, f32 pz0, f32 px1, f32 pz1,
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void compute_edge_leafs(pxl8_loaded_chunk* lc) {
|
static void compute_edge_leafs(demo3d_loaded_chunk* lc) {
|
||||||
const f32 CHUNK_SIZE = 16.0f * 64.0f;
|
const f32 CHUNK_SIZE = 16.0f * 64.0f;
|
||||||
const pxl8_bsp* bsp = lc->chunk->bsp;
|
const demo3d_bsp* bsp = lc->chunk->bsp;
|
||||||
f32 cx0 = lc->cx * CHUNK_SIZE;
|
f32 cx0 = lc->cx * CHUNK_SIZE;
|
||||||
f32 cz0 = lc->cz * CHUNK_SIZE;
|
f32 cz0 = lc->cz * CHUNK_SIZE;
|
||||||
f32 cx1 = cx0 + CHUNK_SIZE;
|
f32 cx1 = cx0 + CHUNK_SIZE;
|
||||||
|
|
@ -330,7 +330,7 @@ static void compute_edge_leafs(pxl8_loaded_chunk* lc) {
|
||||||
memset(lc->edges, 0, sizeof(lc->edges));
|
memset(lc->edges, 0, sizeof(lc->edges));
|
||||||
|
|
||||||
for (u32 i = 0; i < bsp->num_leafs; i++) {
|
for (u32 i = 0; i < bsp->num_leafs; i++) {
|
||||||
const pxl8_bsp_leaf* leaf = &bsp->leafs[i];
|
const demo3d_bsp_leaf* leaf = &bsp->leafs[i];
|
||||||
if (bsp->leafs[i].contents == -1) continue;
|
if (bsp->leafs[i].contents == -1) continue;
|
||||||
|
|
||||||
if ((f32)leaf->mins[2] <= (f32)((i16)cz0) + 1.0f && lc->edges[0].count < 16)
|
if ((f32)leaf->mins[2] <= (f32)((i16)cz0) + 1.0f && lc->edges[0].count < 16)
|
||||||
|
|
@ -344,7 +344,7 @@ static void compute_edge_leafs(pxl8_loaded_chunk* lc) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static i32 world_find_chunk(const pxl8_world* world, i32 cx, i32 cz) {
|
static i32 world_find_chunk(const demo3d_world* world, i32 cx, i32 cz) {
|
||||||
for (u32 i = 0; i < world->loaded_count; i++) {
|
for (u32 i = 0; i < world->loaded_count; i++) {
|
||||||
if (world->loaded[i].cx == cx && world->loaded[i].cz == cz &&
|
if (world->loaded[i].cx == cx && world->loaded[i].cz == cz &&
|
||||||
world->loaded[i].chunk && world->loaded[i].chunk->bsp)
|
world->loaded[i].chunk && world->loaded[i].chunk->bsp)
|
||||||
|
|
@ -353,8 +353,8 @@ static i32 world_find_chunk(const pxl8_world* world, i32 cx, i32 cz) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void world_mark_leaf_faces(const pxl8_bsp* bsp, pxl8_bsp_render_state* rs, u32 leaf_idx) {
|
static void world_mark_leaf_faces(const demo3d_bsp* bsp, demo3d_bsp_render_state* rs, u32 leaf_idx) {
|
||||||
const pxl8_bsp_leaf* leaf = &bsp->leafs[leaf_idx];
|
const demo3d_bsp_leaf* leaf = &bsp->leafs[leaf_idx];
|
||||||
for (u32 i = 0; i < leaf->num_marksurfaces; i++) {
|
for (u32 i = 0; i < leaf->num_marksurfaces; i++) {
|
||||||
u32 si = leaf->first_marksurface + i;
|
u32 si = leaf->first_marksurface + i;
|
||||||
if (si < bsp->num_marksurfaces) {
|
if (si < bsp->num_marksurfaces) {
|
||||||
|
|
@ -392,7 +392,7 @@ static bool vis_try_enqueue(u8** vis, pxl8_rect** windows, world_vis_node* queue
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void world_compute_visibility(pxl8_world* world, pxl8_gfx* gfx, pxl8_vec3 camera_pos) {
|
static void world_compute_visibility(demo3d_world* world, pxl8_gfx* gfx, pxl8_vec3 camera_pos) {
|
||||||
const f32 CHUNK_SIZE = 16.0f * 64.0f;
|
const f32 CHUNK_SIZE = 16.0f * 64.0f;
|
||||||
const f32 PORTAL_Y_HI = 192.0f;
|
const f32 PORTAL_Y_HI = 192.0f;
|
||||||
|
|
||||||
|
|
@ -400,9 +400,9 @@ static void world_compute_visibility(pxl8_world* world, pxl8_gfx* gfx, pxl8_vec3
|
||||||
|
|
||||||
i32 cam_ci = -1, cam_li = -1;
|
i32 cam_ci = -1, cam_li = -1;
|
||||||
for (u32 i = 0; i < world->loaded_count; i++) {
|
for (u32 i = 0; i < world->loaded_count; i++) {
|
||||||
pxl8_loaded_chunk* lc = &world->loaded[i];
|
demo3d_loaded_chunk* lc = &world->loaded[i];
|
||||||
if (!lc->chunk || !lc->chunk->bsp) continue;
|
if (!lc->chunk || !lc->chunk->bsp) continue;
|
||||||
const pxl8_bsp* bsp = lc->chunk->bsp;
|
const demo3d_bsp* bsp = lc->chunk->bsp;
|
||||||
f32 cx0 = lc->cx * CHUNK_SIZE;
|
f32 cx0 = lc->cx * CHUNK_SIZE;
|
||||||
f32 cz0 = lc->cz * CHUNK_SIZE;
|
f32 cz0 = lc->cz * CHUNK_SIZE;
|
||||||
if (camera_pos.x < cx0 || camera_pos.x >= cx0 + CHUNK_SIZE ||
|
if (camera_pos.x < cx0 || camera_pos.x >= cx0 + CHUNK_SIZE ||
|
||||||
|
|
@ -411,28 +411,9 @@ static void world_compute_visibility(pxl8_world* world, pxl8_gfx* gfx, pxl8_vec3
|
||||||
(camera_pos.x < bsp->bounds_min_x || camera_pos.x >= bsp->bounds_max_x ||
|
(camera_pos.x < bsp->bounds_min_x || camera_pos.x >= bsp->bounds_max_x ||
|
||||||
camera_pos.z < bsp->bounds_min_z || camera_pos.z >= bsp->bounds_max_z))
|
camera_pos.z < bsp->bounds_min_z || camera_pos.z >= bsp->bounds_max_z))
|
||||||
continue;
|
continue;
|
||||||
i32 leaf = pxl8_bsp_find_leaf(bsp, camera_pos);
|
i32 leaf = demo3d_bsp_find_leaf(bsp, camera_pos);
|
||||||
if (leaf >= 0 && (u32)leaf < bsp->num_leafs &&
|
if (leaf >= 0 && (u32)leaf < bsp->num_leafs &&
|
||||||
bsp->leafs[leaf].contents != -1 &&
|
bsp->leafs[leaf].contents == -2) {
|
||||||
(!(bsp->bounds_max_x > bsp->bounds_min_x) || bsp->leafs[leaf].contents == -2)) {
|
|
||||||
cam_ci = (i32)i;
|
|
||||||
cam_li = leaf;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (cam_ci < 0) {
|
|
||||||
for (u32 i = 0; i < world->loaded_count; i++) {
|
|
||||||
pxl8_loaded_chunk* lc = &world->loaded[i];
|
|
||||||
if (!lc->chunk || !lc->chunk->bsp) continue;
|
|
||||||
const pxl8_bsp* bsp = lc->chunk->bsp;
|
|
||||||
if (bsp->bounds_max_x > bsp->bounds_min_x) continue;
|
|
||||||
i32 leaf = pxl8_bsp_find_leaf(bsp, camera_pos);
|
|
||||||
if (leaf < 0 || (u32)leaf >= bsp->num_leafs) continue;
|
|
||||||
const pxl8_bsp_leaf* l = &bsp->leafs[leaf];
|
|
||||||
if (l->contents == -1) continue;
|
|
||||||
if (camera_pos.x < (f32)l->mins[0] || camera_pos.x > (f32)l->maxs[0] ||
|
|
||||||
camera_pos.z < (f32)l->mins[2] || camera_pos.z > (f32)l->maxs[2]) continue;
|
|
||||||
cam_ci = (i32)i;
|
cam_ci = (i32)i;
|
||||||
cam_li = leaf;
|
cam_li = leaf;
|
||||||
break;
|
break;
|
||||||
|
|
@ -441,7 +422,7 @@ static void world_compute_visibility(pxl8_world* world, pxl8_gfx* gfx, pxl8_vec3
|
||||||
|
|
||||||
if (cam_ci < 0 || !vp) {
|
if (cam_ci < 0 || !vp) {
|
||||||
for (u32 i = 0; i < world->loaded_count; i++) {
|
for (u32 i = 0; i < world->loaded_count; i++) {
|
||||||
pxl8_bsp_render_state* rs = world->loaded[i].render_state;
|
demo3d_bsp_render_state* rs = world->loaded[i].render_state;
|
||||||
if (!rs) continue;
|
if (!rs) continue;
|
||||||
if (rs->render_face_flags)
|
if (rs->render_face_flags)
|
||||||
memset(rs->render_face_flags, 1, rs->num_faces);
|
memset(rs->render_face_flags, 1, rs->num_faces);
|
||||||
|
|
@ -459,7 +440,7 @@ static void world_compute_visibility(pxl8_world* world, pxl8_gfx* gfx, pxl8_vec3
|
||||||
if (world->loaded[i].chunk && world->loaded[i].chunk->bsp) {
|
if (world->loaded[i].chunk && world->loaded[i].chunk->bsp) {
|
||||||
u32 nl = world->loaded[i].chunk->bsp->num_leafs;
|
u32 nl = world->loaded[i].chunk->bsp->num_leafs;
|
||||||
u32 vbytes = (nl + 7) / 8;
|
u32 vbytes = (nl + 7) / 8;
|
||||||
if (voff + vbytes > PXL8_VIS_BYTES || woff + nl > PXL8_VIS_MAX_NODES)
|
if (voff + vbytes > DEMO3D_VIS_BYTES || woff + nl > DEMO3D_VIS_MAX_NODES)
|
||||||
continue;
|
continue;
|
||||||
world->vis_ptrs[i] = world->vis_bits + voff;
|
world->vis_ptrs[i] = world->vis_bits + voff;
|
||||||
voff += vbytes;
|
voff += vbytes;
|
||||||
|
|
@ -471,7 +452,7 @@ static void world_compute_visibility(pxl8_world* world, pxl8_gfx* gfx, pxl8_vec3
|
||||||
if (!world->vis_ptrs[cam_ci] || !world->vis_win_ptrs[cam_ci]) return;
|
if (!world->vis_ptrs[cam_ci] || !world->vis_win_ptrs[cam_ci]) return;
|
||||||
|
|
||||||
for (u32 i = 0; i < world->loaded_count; i++) {
|
for (u32 i = 0; i < world->loaded_count; i++) {
|
||||||
pxl8_bsp_render_state* rs = world->loaded[i].render_state;
|
demo3d_bsp_render_state* rs = world->loaded[i].render_state;
|
||||||
if (!rs) continue;
|
if (!rs) continue;
|
||||||
if (rs->render_face_flags)
|
if (rs->render_face_flags)
|
||||||
memset(rs->render_face_flags, 0, rs->num_faces);
|
memset(rs->render_face_flags, 0, rs->num_faces);
|
||||||
|
|
@ -481,7 +462,7 @@ static void world_compute_visibility(pxl8_world* world, pxl8_gfx* gfx, pxl8_vec3
|
||||||
u32 head = 0, tail = 0;
|
u32 head = 0, tail = 0;
|
||||||
|
|
||||||
pxl8_rect full_screen = {-1.0f, -1.0f, 1.0f, 1.0f};
|
pxl8_rect full_screen = {-1.0f, -1.0f, 1.0f, 1.0f};
|
||||||
const pxl8_bsp* cam_bsp = world->loaded[cam_ci].chunk->bsp;
|
const demo3d_bsp* cam_bsp = world->loaded[cam_ci].chunk->bsp;
|
||||||
bool cam_exterior = cam_bsp->leafs[cam_li].contents == 0 &&
|
bool cam_exterior = cam_bsp->leafs[cam_li].contents == 0 &&
|
||||||
!(cam_bsp->bounds_max_x > cam_bsp->bounds_min_x);
|
!(cam_bsp->bounds_max_x > cam_bsp->bounds_min_x);
|
||||||
|
|
||||||
|
|
@ -491,25 +472,25 @@ static void world_compute_visibility(pxl8_world* world, pxl8_gfx* gfx, pxl8_vec3
|
||||||
|
|
||||||
while (head < tail) {
|
while (head < tail) {
|
||||||
world_vis_node cur = world->vis_queue[head++];
|
world_vis_node cur = world->vis_queue[head++];
|
||||||
pxl8_loaded_chunk* lc = &world->loaded[cur.chunk_idx];
|
demo3d_loaded_chunk* lc = &world->loaded[cur.chunk_idx];
|
||||||
const pxl8_bsp* bsp = lc->chunk->bsp;
|
const demo3d_bsp* bsp = lc->chunk->bsp;
|
||||||
|
|
||||||
world_mark_leaf_faces(bsp, lc->render_state, cur.leaf_idx);
|
world_mark_leaf_faces(bsp, lc->render_state, cur.leaf_idx);
|
||||||
|
|
||||||
if (bsp->cell_portals && cur.leaf_idx < bsp->num_cell_portals) {
|
if (bsp->cell_portals && cur.leaf_idx < bsp->num_cell_portals) {
|
||||||
bool is_cam_leaf = (cur.chunk_idx == (u16)cam_ci && cur.leaf_idx == (u16)cam_li);
|
bool is_cam_leaf = (cur.chunk_idx == (u16)cam_ci && cur.leaf_idx == (u16)cam_li);
|
||||||
bool is_cam_chunk = (cur.chunk_idx == (u16)cam_ci);
|
bool is_cam_chunk = (cur.chunk_idx == (u16)cam_ci);
|
||||||
const pxl8_bsp_cell_portals* cp = &bsp->cell_portals[cur.leaf_idx];
|
const demo3d_bsp_cell_portals* cp = &bsp->cell_portals[cur.leaf_idx];
|
||||||
for (u8 pi = 0; pi < cp->num_portals; pi++) {
|
for (u8 pi = 0; pi < cp->num_portals; pi++) {
|
||||||
const pxl8_bsp_portal* p = &cp->portals[pi];
|
const demo3d_bsp_portal* p = &cp->portals[pi];
|
||||||
u32 target = p->target_leaf;
|
u32 target = p->target_leaf;
|
||||||
if (target >= bsp->num_leafs) continue;
|
if (target >= bsp->num_leafs) continue;
|
||||||
if (bsp->leafs[target].contents == -1) continue;
|
if (bsp->leafs[target].contents == -1) continue;
|
||||||
if (is_cam_chunk && !pxl8_bsp_is_leaf_visible(bsp, cam_li, (i32)target)) continue;
|
if (is_cam_chunk && !demo3d_bsp_is_leaf_visible(bsp, cam_li, (i32)target)) continue;
|
||||||
|
|
||||||
if (is_cam_leaf || cam_exterior) {
|
if (is_cam_leaf || cam_exterior) {
|
||||||
vis_try_enqueue(world->vis_ptrs, world->vis_win_ptrs,
|
vis_try_enqueue(world->vis_ptrs, world->vis_win_ptrs,
|
||||||
world->vis_queue, &tail, PXL8_VIS_MAX_QUEUE,
|
world->vis_queue, &tail, DEMO3D_VIS_MAX_QUEUE,
|
||||||
cur.chunk_idx, (u16)target, full_screen);
|
cur.chunk_idx, (u16)target, full_screen);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
@ -521,12 +502,12 @@ static void world_compute_visibility(pxl8_world* world, pxl8_gfx* gfx, pxl8_vec3
|
||||||
if (!vr_valid(nw)) continue;
|
if (!vr_valid(nw)) continue;
|
||||||
|
|
||||||
vis_try_enqueue(world->vis_ptrs, world->vis_win_ptrs,
|
vis_try_enqueue(world->vis_ptrs, world->vis_win_ptrs,
|
||||||
world->vis_queue, &tail, PXL8_VIS_MAX_QUEUE,
|
world->vis_queue, &tail, DEMO3D_VIS_MAX_QUEUE,
|
||||||
cur.chunk_idx, (u16)target, nw);
|
cur.chunk_idx, (u16)target, nw);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const pxl8_bsp_leaf* leaf = &bsp->leafs[cur.leaf_idx];
|
const demo3d_bsp_leaf* leaf = &bsp->leafs[cur.leaf_idx];
|
||||||
f32 chunk_x0 = lc->cx * CHUNK_SIZE;
|
f32 chunk_x0 = lc->cx * CHUNK_SIZE;
|
||||||
f32 chunk_z0 = lc->cz * CHUNK_SIZE;
|
f32 chunk_z0 = lc->cz * CHUNK_SIZE;
|
||||||
f32 chunk_x1 = chunk_x0 + CHUNK_SIZE;
|
f32 chunk_x1 = chunk_x0 + CHUNK_SIZE;
|
||||||
|
|
@ -546,12 +527,12 @@ static void world_compute_visibility(pxl8_world* world, pxl8_gfx* gfx, pxl8_vec3
|
||||||
i32 nci = world_find_chunk(world, lc->cx + dirs[d].dx, lc->cz + dirs[d].dz);
|
i32 nci = world_find_chunk(world, lc->cx + dirs[d].dx, lc->cz + dirs[d].dz);
|
||||||
if (nci < 0) continue;
|
if (nci < 0) continue;
|
||||||
|
|
||||||
const pxl8_bsp* nbsp = world->loaded[nci].chunk->bsp;
|
const demo3d_bsp* nbsp = world->loaded[nci].chunk->bsp;
|
||||||
const pxl8_edge_leafs* nedge = &world->loaded[nci].edges[opposite_edge[d]];
|
const demo3d_edge_leafs* nedge = &world->loaded[nci].edges[opposite_edge[d]];
|
||||||
|
|
||||||
for (u8 k = 0; k < nedge->count; k++) {
|
for (u8 k = 0; k < nedge->count; k++) {
|
||||||
u16 nl = nedge->leafs[k];
|
u16 nl = nedge->leafs[k];
|
||||||
const pxl8_bsp_leaf* nleaf =  ->leafs[nl];
|
const demo3d_bsp_leaf* nleaf =  ->leafs[nl];
|
||||||
|
|
||||||
bool overlaps = false;
|
bool overlaps = false;
|
||||||
if (dirs[d].dx != 0) {
|
if (dirs[d].dx != 0) {
|
||||||
|
|
@ -576,7 +557,7 @@ static void world_compute_visibility(pxl8_world* world, pxl8_gfx* gfx, pxl8_vec3
|
||||||
|
|
||||||
if (cam_exterior) {
|
if (cam_exterior) {
|
||||||
vis_try_enqueue(world->vis_ptrs, world->vis_win_ptrs,
|
vis_try_enqueue(world->vis_ptrs, world->vis_win_ptrs,
|
||||||
world->vis_queue, &tail, PXL8_VIS_MAX_QUEUE,
|
world->vis_queue, &tail, DEMO3D_VIS_MAX_QUEUE,
|
||||||
(u16)nci, (u16)nl, full_screen);
|
(u16)nci, (u16)nl, full_screen);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
@ -588,7 +569,7 @@ static void world_compute_visibility(pxl8_world* world, pxl8_gfx* gfx, pxl8_vec3
|
||||||
if (!vr_valid(nw)) continue;
|
if (!vr_valid(nw)) continue;
|
||||||
|
|
||||||
vis_try_enqueue(world->vis_ptrs, world->vis_win_ptrs,
|
vis_try_enqueue(world->vis_ptrs, world->vis_win_ptrs,
|
||||||
world->vis_queue, &tail, PXL8_VIS_MAX_QUEUE,
|
world->vis_queue, &tail, DEMO3D_VIS_MAX_QUEUE,
|
||||||
(u16)nci, (u16)nl, nw);
|
(u16)nci, (u16)nl, nw);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -596,67 +577,76 @@ static void world_compute_visibility(pxl8_world* world, pxl8_gfx* gfx, pxl8_vec3
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void pxl8_world_render(pxl8_world* world, pxl8_gfx* gfx, pxl8_vec3 camera_pos) {
|
void demo3d_world_render(demo3d_world* world, pxl8_gfx* gfx, pxl8_vec3 camera_pos) {
|
||||||
if (!world || !gfx) return;
|
if (!world || !gfx) return;
|
||||||
|
|
||||||
if (world->active_chunk && world->active_chunk->bsp)
|
|
||||||
pxl8_3d_set_bsp(gfx, world->active_chunk->bsp);
|
|
||||||
else
|
|
||||||
pxl8_3d_set_bsp(gfx, NULL);
|
|
||||||
|
|
||||||
world_compute_visibility(world, gfx, camera_pos);
|
world_compute_visibility(world, gfx, camera_pos);
|
||||||
|
|
||||||
for (u32 i = 0; i < world->loaded_count; i++) {
|
for (u32 i = 0; i < world->loaded_count; i++) {
|
||||||
pxl8_loaded_chunk* lc = &world->loaded[i];
|
demo3d_loaded_chunk* lc = &world->loaded[i];
|
||||||
if (!lc->chunk || !lc->chunk->bsp || !lc->render_state) continue;
|
if (!lc->chunk || !lc->chunk->bsp || !lc->render_state) continue;
|
||||||
pxl8_bsp_render(gfx, lc->chunk->bsp, lc->render_state, NULL);
|
demo3d_bsp_render(gfx, lc->chunk->bsp, lc->render_state, NULL);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void apply_shared_materials(pxl8_world* world, pxl8_bsp_render_state* rs) {
|
static void apply_shared_materials(demo3d_world* world, demo3d_bsp_render_state* rs) {
|
||||||
for (u16 i = 0; i < 16; i++) {
|
for (u16 i = 0; i < 16; i++) {
|
||||||
if (world->shared_material_set[i]) {
|
if (world->shared_material_set[i]) {
|
||||||
pxl8_bsp_set_material(rs, i, &world->shared_materials[i]);
|
demo3d_bsp_set_material(rs, i, &world->shared_materials[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void pxl8_world_sync(pxl8_world* world, pxl8_net* net) {
|
void demo3d_world_sync(demo3d_world* world, demo3d_net* net) {
|
||||||
if (!world || !net) return;
|
if (!world || !net) return;
|
||||||
|
|
||||||
if (!pxl8_net_has_chunk(net)) {
|
if (!demo3d_net_has_chunk(net)) {
|
||||||
u32 old_count = world->loaded_count;
|
u32 old_count = world->loaded_count;
|
||||||
world->loaded_count = 0;
|
world->loaded_count = 0;
|
||||||
world->active_chunk = NULL;
|
world->active_chunk = NULL;
|
||||||
world->active_render_state = NULL;
|
world->active_render_state = NULL;
|
||||||
for (u32 i = 0; i < old_count; i++) {
|
for (u32 i = 0; i < old_count; i++) {
|
||||||
pxl8_bsp_render_state_destroy(world->loaded[i].render_state);
|
demo3d_bsp_render_state_destroy(world->loaded[i].render_state);
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
i32 center_cx = pxl8_net_chunk_cx(net);
|
i32 center_cx = demo3d_net_chunk_cx(net);
|
||||||
i32 center_cz = pxl8_net_chunk_cz(net);
|
i32 center_cz = demo3d_net_chunk_cz(net);
|
||||||
|
|
||||||
pxl8_loaded_chunk old_loaded[PXL8_WORLD_MAX_LOADED_CHUNKS];
|
demo3d_loaded_chunk old_loaded[DEMO3D_WORLD_MAX_LOADED_CHUNKS];
|
||||||
u32 old_count = world->loaded_count;
|
u32 old_count = world->loaded_count;
|
||||||
memcpy(old_loaded, world->loaded, sizeof(old_loaded));
|
memcpy(old_loaded, world->loaded, sizeof(old_loaded));
|
||||||
|
|
||||||
pxl8_loaded_chunk new_loaded[PXL8_WORLD_MAX_LOADED_CHUNKS];
|
demo3d_loaded_chunk new_loaded[DEMO3D_WORLD_MAX_LOADED_CHUNKS];
|
||||||
u32 new_count = 0;
|
u32 new_count = 0;
|
||||||
pxl8_world_chunk* new_active_chunk = NULL;
|
demo3d_chunk* new_active_chunk = NULL;
|
||||||
pxl8_bsp_render_state* new_active_rs = NULL;
|
demo3d_bsp_render_state* new_active_rs = NULL;
|
||||||
|
|
||||||
for (i32 dz = -2; dz <= 2; dz++) {
|
for (i32 dz = -2; dz <= 2; dz++) {
|
||||||
for (i32 dx = -2; dx <= 2; dx++) {
|
for (i32 dx = -2; dx <= 2; dx++) {
|
||||||
i32 cx = center_cx + dx;
|
i32 cx = center_cx + dx;
|
||||||
i32 cz = center_cz + dz;
|
i32 cz = center_cz + dz;
|
||||||
u32 id = pxl8_chunk_hash(cx, cz);
|
u32 id = demo3d_chunk_hash(cx, cz);
|
||||||
|
|
||||||
pxl8_world_chunk* chunk = pxl8_world_chunk_cache_get_bsp(world->chunk_cache, id);
|
demo3d_chunk* chunk = demo3d_chunk_cache_get_bsp(world->chunk_cache, id);
|
||||||
if (!chunk || !chunk->bsp) continue;
|
if (!chunk || !chunk->bsp) {
|
||||||
|
for (u32 j = 0; j < old_count; j++) {
|
||||||
|
if (old_loaded[j].active && old_loaded[j].cx == cx && old_loaded[j].cz == cz) {
|
||||||
|
u32 idx = new_count++;
|
||||||
|
new_loaded[idx] = old_loaded[j];
|
||||||
|
old_loaded[j].active = false;
|
||||||
|
if (dx == 0 && dz == 0) {
|
||||||
|
new_active_chunk = new_loaded[idx].chunk;
|
||||||
|
new_active_rs = new_loaded[idx].render_state;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
pxl8_bsp_render_state* rs = NULL;
|
demo3d_bsp_render_state* rs = NULL;
|
||||||
for (u32 j = 0; j < old_count; j++) {
|
for (u32 j = 0; j < old_count; j++) {
|
||||||
if (old_loaded[j].active && old_loaded[j].cx == cx && old_loaded[j].cz == cz &&
|
if (old_loaded[j].active && old_loaded[j].cx == cx && old_loaded[j].cz == cz &&
|
||||||
old_loaded[j].chunk == chunk) {
|
old_loaded[j].chunk == chunk) {
|
||||||
|
|
@ -667,14 +657,14 @@ void pxl8_world_sync(pxl8_world* world, pxl8_net* net) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!rs) {
|
if (!rs) {
|
||||||
rs = pxl8_bsp_render_state_create(chunk->bsp->num_faces);
|
rs = demo3d_bsp_render_state_create(chunk->bsp->num_faces);
|
||||||
if (rs && rs->render_face_flags)
|
if (rs && rs->render_face_flags)
|
||||||
memset(rs->render_face_flags, 1, rs->num_faces);
|
memset(rs->render_face_flags, 1, rs->num_faces);
|
||||||
apply_shared_materials(world, rs);
|
apply_shared_materials(world, rs);
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 idx = new_count++;
|
u32 idx = new_count++;
|
||||||
new_loaded[idx] = (pxl8_loaded_chunk){
|
new_loaded[idx] = (demo3d_loaded_chunk){
|
||||||
.chunk = chunk,
|
.chunk = chunk,
|
||||||
.render_state = rs,
|
.render_state = rs,
|
||||||
.cx = cx,
|
.cx = cx,
|
||||||
|
|
@ -690,19 +680,24 @@ void pxl8_world_sync(pxl8_world* world, pxl8_net* net) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (u32 j = 0; j < old_count; j++) {
|
||||||
|
if (!old_loaded[j].active) continue;
|
||||||
|
if (new_count < DEMO3D_WORLD_MAX_LOADED_CHUNKS &&
|
||||||
|
old_loaded[j].chunk && old_loaded[j].chunk->bsp &&
|
||||||
|
demo3d_chunk_cache_get_bsp(world->chunk_cache, old_loaded[j].chunk->id)) {
|
||||||
|
new_loaded[new_count++] = old_loaded[j];
|
||||||
|
} else {
|
||||||
|
demo3d_bsp_render_state_destroy(old_loaded[j].render_state);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
memcpy(world->loaded, new_loaded, sizeof(new_loaded));
|
memcpy(world->loaded, new_loaded, sizeof(new_loaded));
|
||||||
world->active_chunk = new_active_chunk;
|
world->active_chunk = new_active_chunk;
|
||||||
world->active_render_state = new_active_rs;
|
world->active_render_state = new_active_rs;
|
||||||
world->loaded_count = new_count;
|
world->loaded_count = new_count;
|
||||||
|
|
||||||
for (u32 j = 0; j < old_count; j++) {
|
|
||||||
if (old_loaded[j].active) {
|
|
||||||
pxl8_bsp_render_state_destroy(old_loaded[j].render_state);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void pxl8_world_set_bsp_material(pxl8_world* world, u16 material_id, const pxl8_gfx_material* material) {
|
void demo3d_world_set_bsp_material(demo3d_world* world, u16 material_id, const pxl8_gfx_material* material) {
|
||||||
if (!world || !material || material_id >= 16) return;
|
if (!world || !material || material_id >= 16) return;
|
||||||
|
|
||||||
world->shared_materials[material_id] = *material;
|
world->shared_materials[material_id] = *material;
|
||||||
|
|
@ -710,23 +705,23 @@ void pxl8_world_set_bsp_material(pxl8_world* world, u16 material_id, const pxl8_
|
||||||
|
|
||||||
for (u32 i = 0; i < world->loaded_count; i++) {
|
for (u32 i = 0; i < world->loaded_count; i++) {
|
||||||
if (world->loaded[i].render_state) {
|
if (world->loaded[i].render_state) {
|
||||||
pxl8_bsp_set_material(world->loaded[i].render_state, material_id, material);
|
demo3d_bsp_set_material(world->loaded[i].render_state, material_id, material);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void pxl8_world_set_sim_config(pxl8_world* world, const pxl8_sim_config* config) {
|
void demo3d_world_set_sim_config(demo3d_world* world, const demo3d_sim_config* config) {
|
||||||
if (!world || !config) return;
|
if (!world || !config) return;
|
||||||
world->sim_config = *config;
|
world->sim_config = *config;
|
||||||
}
|
}
|
||||||
|
|
||||||
void pxl8_world_init_local_player(pxl8_world* world, f32 x, f32 y, f32 z) {
|
void demo3d_world_init_local_player(demo3d_world* world, f32 x, f32 y, f32 z) {
|
||||||
if (!world) return;
|
if (!world) return;
|
||||||
world->local_player.pos = (pxl8_vec3){x, y, z};
|
world->local_player.pos = (pxl8_vec3){x, y, z};
|
||||||
world->local_player.vel = (pxl8_vec3){0, 0, 0};
|
world->local_player.vel = (pxl8_vec3){0, 0, 0};
|
||||||
world->local_player.yaw = 0;
|
world->local_player.yaw = 0;
|
||||||
world->local_player.pitch = 0;
|
world->local_player.pitch = 0;
|
||||||
world->local_player.flags = PXL8_SIM_FLAG_ALIVE | PXL8_SIM_FLAG_PLAYER | PXL8_SIM_FLAG_GROUNDED;
|
world->local_player.flags = DEMO3D_SIM_FLAG_ALIVE | DEMO3D_SIM_FLAG_PLAYER | DEMO3D_SIM_FLAG_GROUNDED;
|
||||||
world->local_player.kind = 0;
|
world->local_player.kind = 0;
|
||||||
world->client_tick = 0;
|
world->client_tick = 0;
|
||||||
world->pointer_motion = (pxl8_vec2){0};
|
world->pointer_motion = (pxl8_vec2){0};
|
||||||
|
|
@ -737,7 +732,7 @@ void pxl8_world_init_local_player(pxl8_world* world, f32 x, f32 y, f32 z) {
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void pxl8_world_set_look(pxl8_world* world, f32 yaw, f32 pitch) {
|
void demo3d_world_set_look(demo3d_world* world, f32 yaw, f32 pitch) {
|
||||||
if (!world) return;
|
if (!world) return;
|
||||||
world->local_player.yaw = yaw;
|
world->local_player.yaw = yaw;
|
||||||
world->local_player.pitch = pitch;
|
world->local_player.pitch = pitch;
|
||||||
|
|
@ -751,72 +746,72 @@ void pxl8_world_set_look(pxl8_world* world, f32 yaw, f32 pitch) {
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
pxl8_sim_entity* pxl8_world_local_player(pxl8_world* world) {
|
demo3d_sim_entity* demo3d_world_local_player(demo3d_world* world) {
|
||||||
if (!world) return NULL;
|
if (!world) return NULL;
|
||||||
#ifdef PXL8_ASYNC_THREADS
|
#ifdef PXL8_ASYNC_THREADS
|
||||||
const pxl8_sim_entity* state = pxl8_world_get_render_state(world);
|
const demo3d_sim_entity* state = demo3d_world_get_render_state(world);
|
||||||
if (!state) return NULL;
|
if (!state) return NULL;
|
||||||
if (!(state->flags & PXL8_SIM_FLAG_ALIVE)) return NULL;
|
if (!(state->flags & DEMO3D_SIM_FLAG_ALIVE)) return NULL;
|
||||||
return (pxl8_sim_entity*)state;
|
return (demo3d_sim_entity*)state;
|
||||||
#else
|
#else
|
||||||
if (!(world->local_player.flags & PXL8_SIM_FLAG_ALIVE)) return NULL;
|
if (!(world->local_player.flags & DEMO3D_SIM_FLAG_ALIVE)) return NULL;
|
||||||
return &world->local_player;
|
return &world->local_player;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void pxl8_world_predict(pxl8_world* world, pxl8_net* net, const pxl8_input_msg* input, f32 dt) {
|
void demo3d_world_predict(demo3d_world* world, demo3d_net* net, const demo3d_input_msg* input, f32 dt) {
|
||||||
if (!world || !net || !input) return;
|
if (!world || !net || !input) return;
|
||||||
if (!(world->local_player.flags & PXL8_SIM_FLAG_ALIVE)) return;
|
if (!(world->local_player.flags & DEMO3D_SIM_FLAG_ALIVE)) return;
|
||||||
|
|
||||||
pxl8_sim_world sim = pxl8_world_sim_world(world, world->local_player.pos);
|
demo3d_sim_world sim = demo3d_world_sim_world(world, world->local_player.pos);
|
||||||
pxl8_sim_move_player(&world->local_player, input, &sim, &world->sim_config, dt);
|
demo3d_sim_move_player(&world->local_player, input, &sim, &world->sim_config, dt);
|
||||||
|
|
||||||
world->client_tick++;
|
world->client_tick++;
|
||||||
|
|
||||||
entity_to_userdata(&world->local_player, pxl8_net_predicted_state(net));
|
entity_to_userdata(&world->local_player, demo3d_net_predicted_state(net));
|
||||||
pxl8_net_predicted_tick_set(net, world->client_tick);
|
demo3d_net_predicted_tick_set(net, world->client_tick);
|
||||||
}
|
}
|
||||||
|
|
||||||
void pxl8_world_reconcile(pxl8_world* world, pxl8_net* net, f32 dt) {
|
void demo3d_world_reconcile(demo3d_world* world, demo3d_net* net, f32 dt) {
|
||||||
if (!world || !net) return;
|
if (!world || !net) return;
|
||||||
if (!(world->local_player.flags & PXL8_SIM_FLAG_ALIVE)) return;
|
if (!(world->local_player.flags & DEMO3D_SIM_FLAG_ALIVE)) return;
|
||||||
if (!pxl8_net_needs_correction(net)) return;
|
if (!demo3d_net_needs_correction(net)) return;
|
||||||
|
|
||||||
u64 player_id = pxl8_net_player_id(net);
|
u64 player_id = demo3d_net_player_id(net);
|
||||||
const u8* server_state = pxl8_net_entity_userdata(net, player_id);
|
const u8* server_state = demo3d_net_entity_userdata(net, player_id);
|
||||||
if (!server_state) return;
|
if (!server_state) return;
|
||||||
|
|
||||||
pxl8_sim_entity server_player = {0};
|
demo3d_sim_entity server_player = {0};
|
||||||
userdata_to_entity(server_state, &server_player);
|
userdata_to_entity(server_state, &server_player);
|
||||||
|
|
||||||
if (!(server_player.flags & PXL8_SIM_FLAG_ALIVE)) {
|
if (!(server_player.flags & DEMO3D_SIM_FLAG_ALIVE)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
world->local_player = server_player;
|
world->local_player = server_player;
|
||||||
|
|
||||||
const pxl8_snapshot_header* snap = pxl8_net_snapshot(net);
|
const demo3d_snapshot_header* snap = demo3d_net_snapshot(net);
|
||||||
u64 server_tick = snap ? snap->tick : 0;
|
u64 server_tick = snap ? snap->tick : 0;
|
||||||
|
|
||||||
for (u64 tick = server_tick + 1; tick <= world->client_tick; tick++) {
|
for (u64 tick = server_tick + 1; tick <= world->client_tick; tick++) {
|
||||||
const pxl8_input_msg* input = pxl8_net_input_at(net, tick);
|
const demo3d_input_msg* input = demo3d_net_input_at(net, tick);
|
||||||
if (!input) continue;
|
if (!input) continue;
|
||||||
|
|
||||||
pxl8_sim_world sim = pxl8_world_sim_world(world, world->local_player.pos);
|
demo3d_sim_world sim = demo3d_world_sim_world(world, world->local_player.pos);
|
||||||
pxl8_sim_move_player(&world->local_player, input, &sim, &world->sim_config, dt);
|
demo3d_sim_move_player(&world->local_player, input, &sim, &world->sim_config, dt);
|
||||||
}
|
}
|
||||||
|
|
||||||
entity_to_userdata(&world->local_player, pxl8_net_predicted_state(net));
|
entity_to_userdata(&world->local_player, demo3d_net_predicted_state(net));
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef PXL8_ASYNC_THREADS
|
#ifdef PXL8_ASYNC_THREADS
|
||||||
|
|
||||||
#define SIM_TIMESTEP (1.0f / 60.0f)
|
#define SIM_TIMESTEP (1.0f / 60.0f)
|
||||||
|
|
||||||
static void pxl8_world_sim_tick(pxl8_world* world, f32 dt) {
|
static void demo3d_world_sim_tick(demo3d_world* world, f32 dt) {
|
||||||
bool alive = (world->local_player.flags & PXL8_SIM_FLAG_ALIVE) != 0;
|
bool alive = (world->local_player.flags & DEMO3D_SIM_FLAG_ALIVE) != 0;
|
||||||
pxl8_input_msg merged = {0};
|
demo3d_input_msg merged = {0};
|
||||||
pxl8_input_msg* input = NULL;
|
demo3d_input_msg* input = NULL;
|
||||||
|
|
||||||
while ((input = pxl8_queue_pop(&world->input_queue))) {
|
while ((input = pxl8_queue_pop(&world->input_queue))) {
|
||||||
merged.look_dx += input->look_dx;
|
merged.look_dx += input->look_dx;
|
||||||
|
|
@ -841,7 +836,7 @@ static void pxl8_world_sim_tick(pxl8_world* world, f32 dt) {
|
||||||
merged.timestamp = pxl8_get_ticks_ns();
|
merged.timestamp = pxl8_get_ticks_ns();
|
||||||
merged.yaw = world->pointer_motion.yaw;
|
merged.yaw = world->pointer_motion.yaw;
|
||||||
if (world->net) {
|
if (world->net) {
|
||||||
pxl8_net_send_input(world->net, &merged);
|
demo3d_net_send_input(world->net, &merged);
|
||||||
}
|
}
|
||||||
|
|
||||||
world->local_player.yaw = world->pointer_motion.yaw;
|
world->local_player.yaw = world->pointer_motion.yaw;
|
||||||
|
|
@ -849,25 +844,25 @@ static void pxl8_world_sim_tick(pxl8_world* world, f32 dt) {
|
||||||
merged.look_dx = 0;
|
merged.look_dx = 0;
|
||||||
merged.look_dy = 0;
|
merged.look_dy = 0;
|
||||||
|
|
||||||
pxl8_sim_world sim = pxl8_world_sim_world(world, world->local_player.pos);
|
demo3d_sim_world sim = demo3d_world_sim_world(world, world->local_player.pos);
|
||||||
pxl8_sim_move_player(&world->local_player, &merged, &sim, &world->sim_config, dt);
|
demo3d_sim_move_player(&world->local_player, &merged, &sim, &world->sim_config, dt);
|
||||||
|
|
||||||
if (world->net) {
|
if (world->net) {
|
||||||
entity_to_userdata(&world->local_player, pxl8_net_predicted_state(world->net));
|
entity_to_userdata(&world->local_player, demo3d_net_predicted_state(world->net));
|
||||||
pxl8_net_predicted_tick_set(world->net, world->client_tick);
|
demo3d_net_predicted_tick_set(world->net, world->client_tick);
|
||||||
}
|
}
|
||||||
|
|
||||||
world->client_tick++;
|
world->client_tick++;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void pxl8_world_swap_buffers(pxl8_world* world) {
|
static void demo3d_world_swap_buffers(demo3d_world* world) {
|
||||||
u32 back = atomic_load(&world->active_buffer) ^ 1;
|
u32 back = atomic_load(&world->active_buffer) ^ 1;
|
||||||
world->render_state[back] = world->local_player;
|
world->render_state[back] = world->local_player;
|
||||||
atomic_store(&world->active_buffer, back);
|
atomic_store(&world->active_buffer, back);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int pxl8_world_sim_thread(void* data) {
|
static int demo3d_world_sim_thread(void* data) {
|
||||||
pxl8_world* world = (pxl8_world*)data;
|
demo3d_world* world = (demo3d_world*)data;
|
||||||
u64 last_time = pxl8_get_ticks_ns();
|
u64 last_time = pxl8_get_ticks_ns();
|
||||||
|
|
||||||
while (atomic_load(&world->sim_running)) {
|
while (atomic_load(&world->sim_running)) {
|
||||||
|
|
@ -887,31 +882,31 @@ static int pxl8_world_sim_thread(void* data) {
|
||||||
world->sim_accumulator += dt;
|
world->sim_accumulator += dt;
|
||||||
|
|
||||||
while (world->sim_accumulator >= SIM_TIMESTEP) {
|
while (world->sim_accumulator >= SIM_TIMESTEP) {
|
||||||
pxl8_world_chunk_cache_tick(world->chunk_cache);
|
demo3d_chunk_cache_tick(world->chunk_cache);
|
||||||
|
|
||||||
if (world->net) {
|
if (world->net) {
|
||||||
pxl8_packet* pkt;
|
pxl8_packet* pkt;
|
||||||
while ((pkt = pxl8_net_pop_packet(world->net))) {
|
while ((pkt = pxl8_net_pop_packet(world->net->transport))) {
|
||||||
pxl8_net_process_packet(world->net, pkt);
|
demo3d_net_dispatch_packet(world->net, pkt);
|
||||||
pxl8_net_packet_free(pkt);
|
pxl8_net_packet_free(pkt);
|
||||||
}
|
}
|
||||||
|
|
||||||
pxl8_world_sync(world, world->net);
|
demo3d_world_sync(world, world->net);
|
||||||
pxl8_world_reconcile(world, world->net, SIM_TIMESTEP);
|
demo3d_world_reconcile(world, world->net, SIM_TIMESTEP);
|
||||||
}
|
}
|
||||||
|
|
||||||
pxl8_world_sim_tick(world, SIM_TIMESTEP);
|
demo3d_world_sim_tick(world, SIM_TIMESTEP);
|
||||||
world->sim_accumulator -= SIM_TIMESTEP;
|
world->sim_accumulator -= SIM_TIMESTEP;
|
||||||
}
|
}
|
||||||
|
|
||||||
pxl8_world_swap_buffers(world);
|
demo3d_world_swap_buffers(world);
|
||||||
pxl8_sleep_ms(1);
|
pxl8_sleep_ms(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void pxl8_world_start_sim_thread(pxl8_world* world, pxl8_net* net) {
|
void demo3d_world_start_sim_thread(demo3d_world* world, demo3d_net* net) {
|
||||||
if (!world || world->sim_thread) return;
|
if (!world || world->sim_thread) return;
|
||||||
|
|
||||||
world->net = net;
|
world->net = net;
|
||||||
|
|
@ -923,29 +918,29 @@ void pxl8_world_start_sim_thread(pxl8_world* world, pxl8_net* net) {
|
||||||
world->render_state[0] = world->local_player;
|
world->render_state[0] = world->local_player;
|
||||||
world->render_state[1] = world->local_player;
|
world->render_state[1] = world->local_player;
|
||||||
|
|
||||||
world->sim_thread = pxl8_thread_create(pxl8_world_sim_thread, "pxl8_sim", world);
|
world->sim_thread = pxl8_thread_create(demo3d_world_sim_thread, "pxl8_sim", world);
|
||||||
}
|
}
|
||||||
|
|
||||||
void pxl8_world_stop_sim_thread(pxl8_world* world) {
|
void demo3d_world_stop_sim_thread(demo3d_world* world) {
|
||||||
if (!world || !world->sim_thread) return;
|
if (!world || !world->sim_thread) return;
|
||||||
|
|
||||||
atomic_store(&world->sim_running, false);
|
atomic_store(&world->sim_running, false);
|
||||||
pxl8_thread_wait(world->sim_thread, NULL);
|
pxl8_thread_wait(world->sim_thread, NULL);
|
||||||
world->sim_thread = NULL;
|
world->sim_thread = NULL;
|
||||||
|
|
||||||
pxl8_input_msg* input;
|
demo3d_input_msg* input;
|
||||||
while ((input = pxl8_queue_pop(&world->input_queue))) {
|
while ((input = pxl8_queue_pop(&world->input_queue))) {
|
||||||
pxl8_free(input);
|
pxl8_free(input);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void pxl8_world_pause_sim(pxl8_world* world, bool paused) {
|
void demo3d_world_pause_sim(demo3d_world* world, bool paused) {
|
||||||
if (!world) return;
|
if (!world) return;
|
||||||
|
|
||||||
if (paused) {
|
if (paused) {
|
||||||
atomic_store(&world->sim_paused, true);
|
atomic_store(&world->sim_paused, true);
|
||||||
} else {
|
} else {
|
||||||
pxl8_input_msg* input;
|
demo3d_input_msg* input;
|
||||||
while ((input = pxl8_queue_pop(&world->input_queue))) {
|
while ((input = pxl8_queue_pop(&world->input_queue))) {
|
||||||
pxl8_free(input);
|
pxl8_free(input);
|
||||||
}
|
}
|
||||||
|
|
@ -954,7 +949,7 @@ void pxl8_world_pause_sim(pxl8_world* world, bool paused) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void pxl8_world_push_input(pxl8_world* world, const pxl8_input_msg* input) {
|
void demo3d_world_push_input(demo3d_world* world, const demo3d_input_msg* input) {
|
||||||
if (!world || !input) return;
|
if (!world || !input) return;
|
||||||
|
|
||||||
world->pointer_motion.yaw -= input->look_dx * 0.008f;
|
world->pointer_motion.yaw -= input->look_dx * 0.008f;
|
||||||
|
|
@ -963,7 +958,7 @@ void pxl8_world_push_input(pxl8_world* world, const pxl8_input_msg* input) {
|
||||||
if (pitch < -world->sim_config.max_pitch) pitch = -world->sim_config.max_pitch;
|
if (pitch < -world->sim_config.max_pitch) pitch = -world->sim_config.max_pitch;
|
||||||
world->pointer_motion.pitch = pitch;
|
world->pointer_motion.pitch = pitch;
|
||||||
|
|
||||||
pxl8_input_msg* copy = pxl8_malloc(sizeof(pxl8_input_msg));
|
demo3d_input_msg* copy = pxl8_malloc(sizeof(demo3d_input_msg));
|
||||||
if (copy) {
|
if (copy) {
|
||||||
*copy = *input;
|
*copy = *input;
|
||||||
if (!pxl8_queue_push(&world->input_queue, copy)) {
|
if (!pxl8_queue_push(&world->input_queue, copy)) {
|
||||||
|
|
@ -972,13 +967,13 @@ void pxl8_world_push_input(pxl8_world* world, const pxl8_input_msg* input) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const pxl8_sim_entity* pxl8_world_get_render_state(const pxl8_world* world) {
|
const demo3d_sim_entity* demo3d_world_get_render_state(const demo3d_world* world) {
|
||||||
if (!world) return NULL;
|
if (!world) return NULL;
|
||||||
u32 front = atomic_load(&((pxl8_world*)world)->active_buffer);
|
u32 front = atomic_load(&((demo3d_world*)world)->active_buffer);
|
||||||
return &world->render_state[front];
|
return &world->render_state[front];
|
||||||
}
|
}
|
||||||
|
|
||||||
f32 pxl8_world_get_interp_alpha(const pxl8_world* world) {
|
f32 demo3d_world_get_interp_alpha(const demo3d_world* world) {
|
||||||
if (!world) return 1.0f;
|
if (!world) return 1.0f;
|
||||||
return world->sim_accumulator / SIM_TIMESTEP;
|
return world->sim_accumulator / SIM_TIMESTEP;
|
||||||
}
|
}
|
||||||
71
demo3d/client/world/demo3d_world.h
Normal file
71
demo3d/client/world/demo3d_world.h
Normal file
|
|
@ -0,0 +1,71 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "demo3d_entity.h"
|
||||||
|
#include "pxl8_gfx.h"
|
||||||
|
#include "pxl8_gfx3d.h"
|
||||||
|
#include "pxl8_math.h"
|
||||||
|
#include "demo3d_net.h"
|
||||||
|
#include "demo3d_sim.h"
|
||||||
|
#include "pxl8_types.h"
|
||||||
|
#include "demo3d_chunk.h"
|
||||||
|
#include "demo3d_chunk_cache.h"
|
||||||
|
#include "demo3d_bsp_render.h"
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define DEMO3D_WORLD_MAX_LOADED_CHUNKS 64
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
u16 leafs[16];
|
||||||
|
u8 count;
|
||||||
|
} demo3d_edge_leafs;
|
||||||
|
|
||||||
|
typedef struct demo3d_loaded_chunk {
|
||||||
|
demo3d_chunk* chunk;
|
||||||
|
demo3d_bsp_render_state* render_state;
|
||||||
|
demo3d_edge_leafs edges[4];
|
||||||
|
i32 cx;
|
||||||
|
i32 cz;
|
||||||
|
bool active;
|
||||||
|
} demo3d_loaded_chunk;
|
||||||
|
|
||||||
|
typedef struct demo3d_world demo3d_world;
|
||||||
|
|
||||||
|
demo3d_world* demo3d_world_create(void);
|
||||||
|
void demo3d_world_destroy(demo3d_world* world);
|
||||||
|
|
||||||
|
demo3d_chunk_cache* demo3d_world_get_chunk_cache(demo3d_world* world);
|
||||||
|
demo3d_chunk* demo3d_world_active_chunk(demo3d_world* world);
|
||||||
|
|
||||||
|
bool demo3d_world_point_solid(const demo3d_world* world, f32 x, f32 y, f32 z);
|
||||||
|
pxl8_ray demo3d_world_ray(const demo3d_world* world, pxl8_vec3 from, pxl8_vec3 to);
|
||||||
|
pxl8_ray demo3d_world_sweep(const demo3d_world* world, pxl8_vec3 from, pxl8_vec3 to, f32 radius);
|
||||||
|
|
||||||
|
void demo3d_world_update(demo3d_world* world, f32 dt);
|
||||||
|
void demo3d_world_render(demo3d_world* world, pxl8_gfx* gfx, pxl8_vec3 camera_pos);
|
||||||
|
void demo3d_world_sync(demo3d_world* world, demo3d_net* net);
|
||||||
|
|
||||||
|
void demo3d_world_set_bsp_material(demo3d_world* world, u16 material_id, const pxl8_gfx_material* material);
|
||||||
|
|
||||||
|
void demo3d_world_set_sim_config(demo3d_world* world, const demo3d_sim_config* config);
|
||||||
|
void demo3d_world_init_local_player(demo3d_world* world, f32 x, f32 y, f32 z);
|
||||||
|
void demo3d_world_set_look(demo3d_world* world, f32 yaw, f32 pitch);
|
||||||
|
demo3d_sim_entity* demo3d_world_local_player(demo3d_world* world);
|
||||||
|
demo3d_sim_world demo3d_world_sim_world(const demo3d_world* world, pxl8_vec3 pos);
|
||||||
|
void demo3d_world_predict(demo3d_world* world, demo3d_net* net, const demo3d_input_msg* input, f32 dt);
|
||||||
|
void demo3d_world_reconcile(demo3d_world* world, demo3d_net* net, f32 dt);
|
||||||
|
|
||||||
|
#ifdef PXL8_ASYNC_THREADS
|
||||||
|
void demo3d_world_start_sim_thread(demo3d_world* world, demo3d_net* net);
|
||||||
|
void demo3d_world_stop_sim_thread(demo3d_world* world);
|
||||||
|
void demo3d_world_pause_sim(demo3d_world* world, bool paused);
|
||||||
|
void demo3d_world_push_input(demo3d_world* world, const demo3d_input_msg* input);
|
||||||
|
const demo3d_sim_entity* demo3d_world_get_render_state(const demo3d_world* world);
|
||||||
|
f32 demo3d_world_get_interp_alpha(const demo3d_world* world);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
@ -1,7 +1,10 @@
|
||||||
(local pxl8 (require :pxl8))
|
(local pxl8 (require :pxl8))
|
||||||
(local bit (require :bit))
|
(local bit (require :bit))
|
||||||
|
(local ffi (require :ffi))
|
||||||
|
(local C ffi.C)
|
||||||
|
(local core (require :pxl8.core))
|
||||||
(local effects (require :pxl8.effects))
|
(local effects (require :pxl8.effects))
|
||||||
(local net (require :pxl8.net))
|
(local game-world (require :mod.world))
|
||||||
|
|
||||||
(local entities (require :mod.entities))
|
(local entities (require :mod.entities))
|
||||||
(local menu (require :mod.menu))
|
(local menu (require :mod.menu))
|
||||||
|
|
@ -18,7 +21,7 @@
|
||||||
|
|
||||||
(local SIM_FLAG_GROUNDED 4)
|
(local SIM_FLAG_GROUNDED 4)
|
||||||
|
|
||||||
(local sim-cfg (pxl8.sim_config {:move_speed 150
|
(local sim-cfg (game-world.sim_config {:move_speed 150
|
||||||
:gravity 600
|
:gravity 600
|
||||||
:jump_velocity 180
|
:jump_velocity 180
|
||||||
:player_radius 12
|
:player_radius 12
|
||||||
|
|
@ -64,24 +67,22 @@
|
||||||
|
|
||||||
(fn preload []
|
(fn preload []
|
||||||
(when (not network)
|
(when (not network)
|
||||||
(set network (net.get))
|
(let [net (C.demo3d_get_net core.sys)]
|
||||||
(when network
|
(when (and (not= net nil) (C.demo3d_net_connected net))
|
||||||
(network:spawn cam-x cam-y cam-z cam-yaw cam-pitch)))
|
(set network net)
|
||||||
|
(C.demo3d_net_spawn net cam-x cam-y cam-z cam-yaw cam-pitch))))
|
||||||
(when (not world)
|
(when (not world)
|
||||||
(set world (pxl8.get_world))
|
(set world (game-world.World.get))
|
||||||
(when world
|
(when world
|
||||||
(world:set_sim_config sim-cfg))))
|
(world:set_sim_config sim-cfg))))
|
||||||
|
|
||||||
(fn is-connected []
|
|
||||||
(and network (network:connected)))
|
|
||||||
|
|
||||||
(fn is-ready []
|
(fn is-ready []
|
||||||
(if (not world)
|
(if (not world)
|
||||||
false
|
false
|
||||||
(let [chunk (world:active_chunk)]
|
(let [chunk (world:active_chunk)]
|
||||||
(and chunk (chunk:ready)))))
|
(and chunk (chunk:ready)))))
|
||||||
|
|
||||||
(fn init []
|
(fn game-init []
|
||||||
(pxl8.set_relative_mouse_mode true)
|
(pxl8.set_relative_mouse_mode true)
|
||||||
(pxl8.load_palette "res/palettes/palette.ase")
|
(pxl8.load_palette "res/palettes/palette.ase")
|
||||||
(for [i 0 7]
|
(for [i 0 7]
|
||||||
|
|
@ -102,6 +103,7 @@
|
||||||
(when (not lights)
|
(when (not lights)
|
||||||
(set lights (pxl8.create_lights)))
|
(set lights (pxl8.create_lights)))
|
||||||
|
|
||||||
|
(menu.init)
|
||||||
(entities.init textures)
|
(entities.init textures)
|
||||||
(sky.generate-stars)
|
(sky.generate-stars)
|
||||||
(preload)
|
(preload)
|
||||||
|
|
@ -113,9 +115,7 @@
|
||||||
|
|
||||||
(fn setup-materials []
|
(fn setup-materials []
|
||||||
(when (not world) (lua "return"))
|
(when (not world) (lua "return"))
|
||||||
(when (not network) (lua "return"))
|
|
||||||
(when materials-set? (lua "return"))
|
(when materials-set? (lua "return"))
|
||||||
(when (not (network:has_chunk)) (lua "return"))
|
|
||||||
(let [chunk (world:active_chunk)]
|
(let [chunk (world:active_chunk)]
|
||||||
(when (not chunk) (lua "return"))
|
(when (not chunk) (lua "return"))
|
||||||
(when (not (chunk:ready)) (lua "return"))
|
(when (not (chunk:ready)) (lua "return"))
|
||||||
|
|
@ -154,7 +154,7 @@
|
||||||
(when (and auto-run-cancel-key (not (pxl8.key_down auto-run-cancel-key)))
|
(when (and auto-run-cancel-key (not (pxl8.key_down auto-run-cancel-key)))
|
||||||
(set auto-run-cancel-key nil))
|
(set auto-run-cancel-key nil))
|
||||||
|
|
||||||
(pxl8.make_input_msg
|
(game-world.make_input_msg
|
||||||
{:move_x (+ (if (pxl8.key_down "d") 1 0) (if (pxl8.key_down "a") -1 0))
|
{:move_x (+ (if (pxl8.key_down "d") 1 0) (if (pxl8.key_down "a") -1 0))
|
||||||
:move_y (+ (if (or (pxl8.key_down "w") auto-run?) 1 0)
|
:move_y (+ (if (or (pxl8.key_down "w") auto-run?) 1 0)
|
||||||
(if (and (pxl8.key_down "s") (not= auto-run-cancel-key "s")) -1 0))
|
(if (and (pxl8.key_down "s") (not= auto-run-cancel-key "s")) -1 0))
|
||||||
|
|
@ -162,8 +162,16 @@
|
||||||
:look_dy (pxl8.mouse_dy)
|
:look_dy (pxl8.mouse_dy)
|
||||||
:buttons (if (pxl8.key_down "space") 1 0)}))
|
:buttons (if (pxl8.key_down "space") 1 0)}))
|
||||||
|
|
||||||
(fn update [dt]
|
(global update (fn [dt]
|
||||||
(set last-dt dt)
|
(set last-dt dt)
|
||||||
|
|
||||||
|
(when (pxl8.key_pressed "escape")
|
||||||
|
(menu.toggle))
|
||||||
|
|
||||||
|
(when (menu.is-paused)
|
||||||
|
(menu.update)
|
||||||
|
(lua "return"))
|
||||||
|
|
||||||
(setup-materials)
|
(setup-materials)
|
||||||
|
|
||||||
(when world
|
(when world
|
||||||
|
|
@ -198,85 +206,88 @@
|
||||||
|
|
||||||
(set day-time (% (+ day-time (/ dt day-length)) 1))
|
(set day-time (% (+ day-time (/ dt day-length)) 1))
|
||||||
(set light-time (+ light-time (* dt 0.5)))
|
(set light-time (+ light-time (* dt 0.5)))
|
||||||
(set real-time (+ real-time dt)))))
|
(set real-time (+ real-time dt))))))
|
||||||
|
|
||||||
(fn frame []
|
(global frame (fn []
|
||||||
(pxl8.clear 1)
|
(pxl8.clear 1)
|
||||||
|
(preload)
|
||||||
|
|
||||||
(when (or (not camera) (not world))
|
(when (or (not camera) (not world))
|
||||||
|
(pxl8.text "Loading..." 280 180 1)
|
||||||
(lua "return"))
|
(lua "return"))
|
||||||
|
|
||||||
(let [chunk (when world (world:active_chunk))
|
(let [chunk (when world (world:active_chunk))
|
||||||
ready (and chunk (chunk:ready))]
|
ready (and chunk (chunk:ready))]
|
||||||
|
(when ready
|
||||||
|
(let [bob-offset (* (math.sin bob-time) bob-amount)
|
||||||
|
eye-y (+ cam-y player-eye-height bob-offset land-squash)
|
||||||
|
forward-x (- (math.sin cam-yaw))
|
||||||
|
forward-z (- (math.cos cam-yaw))
|
||||||
|
target-x (+ smooth-cam-x forward-x)
|
||||||
|
target-y (+ eye-y (math.sin cam-pitch))
|
||||||
|
target-z (+ smooth-cam-z forward-z)
|
||||||
|
aspect (/ (pxl8.get_width) (pxl8.get_height))]
|
||||||
|
|
||||||
(when ready
|
(camera:lookat [smooth-cam-x eye-y smooth-cam-z]
|
||||||
(let [bob-offset (* (math.sin bob-time) bob-amount)
|
[target-x target-y target-z]
|
||||||
eye-y (+ cam-y player-eye-height bob-offset land-squash)
|
[0 1 0])
|
||||||
forward-x (- (math.sin cam-yaw))
|
(camera:set_perspective 1.047 aspect 1.0 4096.0)
|
||||||
forward-z (- (math.cos cam-yaw))
|
|
||||||
target-x (+ smooth-cam-x forward-x)
|
|
||||||
target-y (+ eye-y (math.sin cam-pitch))
|
|
||||||
target-z (+ smooth-cam-z forward-z)
|
|
||||||
aspect (/ (pxl8.get_width) (pxl8.get_height))]
|
|
||||||
|
|
||||||
(camera:lookat [smooth-cam-x eye-y smooth-cam-z]
|
(let [light-x (+ 384 (* 50 (math.cos light-time)))
|
||||||
[target-x target-y target-z]
|
light-z (+ 324 (* 50 (math.sin light-time)))
|
||||||
[0 1 0])
|
light-y 80
|
||||||
(camera:set_perspective 1.047 aspect 1.0 4096.0)
|
phase (+ (* light-x 0.01) 1.7)
|
||||||
|
f1 (* 0.08 (math.sin (+ (* real-time 2.5) phase)))
|
||||||
|
f2 (* 0.05 (math.sin (+ (* real-time 4.1) (* phase 0.7))))
|
||||||
|
f3 (* 0.03 (math.sin (+ (* real-time 7.3) (* phase 1.2))))
|
||||||
|
flicker (+ 0.92 f1 f2 f3)
|
||||||
|
light-intensity (math.floor (math.max 0 (math.min 255 (* 255 flicker))))
|
||||||
|
r1 (* 0.06 (math.sin (+ (* real-time 1.8) (* phase 0.5))))
|
||||||
|
r2 (* 0.04 (math.sin (+ (* real-time 3.2) phase)))
|
||||||
|
light-radius (* 150 (+ 0.95 r1 r2))]
|
||||||
|
(lights:clear)
|
||||||
|
(lights:add light-x light-y light-z 2 light-intensity light-radius)
|
||||||
|
|
||||||
(let [light-x (+ 384 (* 50 (math.cos light-time)))
|
(pxl8.push_target)
|
||||||
light-z (+ 324 (* 50 (math.sin light-time)))
|
(pxl8.begin_frame_3d camera lights {
|
||||||
light-y 80
|
:ambient 2
|
||||||
phase (+ (* light-x 0.01) 1.7)
|
:dither true
|
||||||
f1 (* 0.08 (math.sin (+ (* real-time 2.5) phase)))
|
:fog_density 0.002
|
||||||
f2 (* 0.05 (math.sin (+ (* real-time 4.1) (* phase 0.7))))
|
:celestial_dir [0.5 -0.8 0.3]
|
||||||
f3 (* 0.03 (math.sin (+ (* real-time 7.3) (* phase 1.2))))
|
:celestial_intensity 0.3})
|
||||||
flicker (+ 0.92 f1 f2 f3)
|
|
||||||
light-intensity (math.floor (math.max 0 (math.min 255 (* 255 flicker))))
|
(when (not (menu.is-wireframe))
|
||||||
r1 (* 0.06 (math.sin (+ (* real-time 1.8) (* phase 0.5))))
|
(sky.update-gradient 1 2 6 6 10 18))
|
||||||
r2 (* 0.04 (math.sin (+ (* real-time 3.2) phase)))
|
(sky.render smooth-cam-x eye-y smooth-cam-z (menu.is-wireframe))
|
||||||
light-radius (* 150 (+ 0.95 r1 r2))]
|
(pxl8.clear_depth)
|
||||||
(lights:clear)
|
|
||||||
(lights:add light-x light-y light-z 2 light-intensity light-radius)
|
(pxl8.set_wireframe (menu.is-wireframe))
|
||||||
|
(world:render [smooth-cam-x eye-y smooth-cam-z])
|
||||||
|
|
||||||
|
(when chunk
|
||||||
|
(entities.render-fireball light-x light-y light-z))
|
||||||
|
|
||||||
|
(pxl8.end_frame_3d)
|
||||||
|
|
||||||
|
(when (not (menu.is-wireframe))
|
||||||
|
(sky.render-stars smooth-cam-x eye-y smooth-cam-z day-time 0 last-dt))
|
||||||
|
|
||||||
|
(pxl8.pop_target))
|
||||||
|
|
||||||
(pxl8.push_target)
|
(pxl8.push_target)
|
||||||
(pxl8.begin_frame_3d camera lights {
|
(let [cx (/ (pxl8.get_width) 2)
|
||||||
:ambient 2
|
cy (/ (pxl8.get_height) 2)
|
||||||
:dither true
|
crosshair-size 4
|
||||||
:fog_density 0.002
|
crosshair-color 240]
|
||||||
:celestial_dir [0.5 -0.8 0.3]
|
(pxl8.line (- cx crosshair-size) cy (+ cx crosshair-size) cy crosshair-color)
|
||||||
:celestial_intensity 0.3})
|
(pxl8.line cx (- cy crosshair-size) cx (+ cy crosshair-size) crosshair-color))
|
||||||
|
(pxl8.pop_target))))
|
||||||
|
|
||||||
(when (not (menu.is-wireframe))
|
(when (menu.is-paused)
|
||||||
(sky.update-gradient 1 2 6 6 10 18))
|
(pxl8.push_target)
|
||||||
(sky.render smooth-cam-x eye-y smooth-cam-z (menu.is-wireframe))
|
(menu.draw)
|
||||||
(pxl8.clear_depth)
|
(pxl8.pop_target))))
|
||||||
|
|
||||||
(pxl8.set_wireframe (menu.is-wireframe))
|
(global init (fn []
|
||||||
(world:render [smooth-cam-x eye-y smooth-cam-z])
|
(preload)
|
||||||
|
(game-init)))
|
||||||
(when chunk
|
|
||||||
(entities.render-fireball light-x light-y light-z))
|
|
||||||
|
|
||||||
(pxl8.end_frame_3d)
|
|
||||||
|
|
||||||
(when (not (menu.is-wireframe))
|
|
||||||
(sky.render-stars smooth-cam-x eye-y smooth-cam-z day-time 0 last-dt))
|
|
||||||
|
|
||||||
(pxl8.pop_target))
|
|
||||||
|
|
||||||
(pxl8.push_target)
|
|
||||||
(let [cx (/ (pxl8.get_width) 2)
|
|
||||||
cy (/ (pxl8.get_height) 2)
|
|
||||||
crosshair-size 4
|
|
||||||
crosshair-color 240]
|
|
||||||
(pxl8.line (- cx crosshair-size) cy (+ cx crosshair-size) cy crosshair-color)
|
|
||||||
(pxl8.line cx (- cy crosshair-size) cx (+ cy crosshair-size) crosshair-color))
|
|
||||||
(pxl8.pop_target)))))
|
|
||||||
|
|
||||||
{:preload preload
|
|
||||||
:is-connected is-connected
|
|
||||||
:is-ready is-ready
|
|
||||||
:init init
|
|
||||||
:update update
|
|
||||||
:frame frame}
|
|
||||||
172
demo3d/mod/menu.fnl
Normal file
172
demo3d/mod/menu.fnl
Normal file
|
|
@ -0,0 +1,172 @@
|
||||||
|
(local pxl8 (require :pxl8))
|
||||||
|
|
||||||
|
(var paused false)
|
||||||
|
(var gui nil)
|
||||||
|
(var current-panel :main)
|
||||||
|
(var selected-item nil)
|
||||||
|
(var current-items [])
|
||||||
|
(var pending-action nil)
|
||||||
|
|
||||||
|
(var baked-lighting true)
|
||||||
|
(var dynamic-lighting true)
|
||||||
|
(var textures true)
|
||||||
|
(var wireframe false)
|
||||||
|
|
||||||
|
(fn init []
|
||||||
|
(set gui (pxl8.create_gui)))
|
||||||
|
|
||||||
|
(fn show []
|
||||||
|
(set paused true)
|
||||||
|
(set current-panel :main)
|
||||||
|
(pxl8.set_relative_mouse_mode false)
|
||||||
|
(pxl8.center_cursor))
|
||||||
|
|
||||||
|
(fn hide []
|
||||||
|
(set paused false)
|
||||||
|
(pxl8.set_relative_mouse_mode true))
|
||||||
|
|
||||||
|
(fn toggle []
|
||||||
|
(when (not gui) (init))
|
||||||
|
(if paused
|
||||||
|
(hide)
|
||||||
|
(show)))
|
||||||
|
|
||||||
|
(fn select-next []
|
||||||
|
(when (> (length current-items) 0)
|
||||||
|
(var found-idx nil)
|
||||||
|
(for [i 1 (length current-items)]
|
||||||
|
(when (= (. current-items i) selected-item)
|
||||||
|
(set found-idx i)))
|
||||||
|
(if found-idx
|
||||||
|
(let [next-idx (+ found-idx 1)]
|
||||||
|
(if (<= next-idx (length current-items))
|
||||||
|
(set selected-item (. current-items next-idx))
|
||||||
|
(set selected-item (. current-items 1))))
|
||||||
|
(set selected-item (. current-items 1)))))
|
||||||
|
|
||||||
|
(fn select-prev []
|
||||||
|
(when (> (length current-items) 0)
|
||||||
|
(var found-idx nil)
|
||||||
|
(for [i 1 (length current-items)]
|
||||||
|
(when (= (. current-items i) selected-item)
|
||||||
|
(set found-idx i)))
|
||||||
|
(if found-idx
|
||||||
|
(let [prev-idx (- found-idx 1)]
|
||||||
|
(if (>= prev-idx 1)
|
||||||
|
(set selected-item (. current-items prev-idx))
|
||||||
|
(set selected-item (. current-items (length current-items)))))
|
||||||
|
(set selected-item (. current-items (length current-items))))))
|
||||||
|
|
||||||
|
(fn update []
|
||||||
|
(set pending-action nil)
|
||||||
|
|
||||||
|
(when gui
|
||||||
|
(let [(mx my) (pxl8.get_mouse_pos)]
|
||||||
|
(gui:cursor_move mx my))
|
||||||
|
|
||||||
|
(when (pxl8.mouse_pressed 1)
|
||||||
|
(gui:cursor_down))
|
||||||
|
|
||||||
|
(when (pxl8.mouse_released 1)
|
||||||
|
(gui:cursor_up))
|
||||||
|
|
||||||
|
(when (or (pxl8.key_pressed "down")
|
||||||
|
(and (pxl8.key_pressed "tab") (not (pxl8.key_down "lshift")) (not (pxl8.key_down "rshift"))))
|
||||||
|
(select-next))
|
||||||
|
|
||||||
|
(when (or (pxl8.key_pressed "up")
|
||||||
|
(and (pxl8.key_pressed "tab") (or (pxl8.key_down "lshift") (pxl8.key_down "rshift"))))
|
||||||
|
(select-prev))
|
||||||
|
|
||||||
|
(when (or (pxl8.key_pressed "return") (pxl8.key_pressed "space"))
|
||||||
|
(when selected-item
|
||||||
|
(set pending-action selected-item)))))
|
||||||
|
|
||||||
|
(fn menu-button [id x y w h label]
|
||||||
|
(table.insert current-items label)
|
||||||
|
(when (= selected-item nil)
|
||||||
|
(set selected-item label))
|
||||||
|
(let [is-selected (= selected-item label)]
|
||||||
|
(when is-selected
|
||||||
|
(pxl8.rect (- x 3) (- y 3) (+ w 6) (+ h 6) (pxl8.gui_color 4)))
|
||||||
|
(let [clicked (gui:button id x y w h label)]
|
||||||
|
(when clicked
|
||||||
|
(set selected-item label))
|
||||||
|
(or clicked (and is-selected (= pending-action label))))))
|
||||||
|
|
||||||
|
(fn draw-main-menu []
|
||||||
|
(pxl8.gui_window 200 80 240 200 "pxl8 demo")
|
||||||
|
|
||||||
|
(when (menu-button 1 215 127 210 30 "Resume")
|
||||||
|
(hide))
|
||||||
|
|
||||||
|
(when (menu-button 5 215 162 210 30 "GFX")
|
||||||
|
(set current-panel :gfx)
|
||||||
|
(set selected-item nil))
|
||||||
|
|
||||||
|
(when (menu-button 6 215 197 210 30 "SFX")
|
||||||
|
(set current-panel :sfx)
|
||||||
|
(set selected-item nil))
|
||||||
|
|
||||||
|
(when (menu-button 2 215 232 210 30 "Quit")
|
||||||
|
(pxl8.quit)))
|
||||||
|
|
||||||
|
(fn draw-sfx-panel []
|
||||||
|
(pxl8.gui_window 200 100 240 145 "SFX")
|
||||||
|
|
||||||
|
(pxl8.gui_label 215 147 "Volume/Devices: TODO" (pxl8.gui_color 4))
|
||||||
|
|
||||||
|
(when (menu-button 20 215 180 210 30 "Back")
|
||||||
|
(set current-panel :main)
|
||||||
|
(set selected-item nil)))
|
||||||
|
|
||||||
|
(fn draw-gfx-panel []
|
||||||
|
(pxl8.gui_window 200 60 240 195 "GFX")
|
||||||
|
|
||||||
|
(let [baked-label (if baked-lighting "Baked Lighting: On" "Baked Lighting: Off")]
|
||||||
|
(when (menu-button 40 215 107 210 24 baked-label)
|
||||||
|
(set baked-lighting (not baked-lighting))))
|
||||||
|
|
||||||
|
(let [dynamic-label (if dynamic-lighting "Dynamic Lighting: On" "Dynamic Lighting: Off")]
|
||||||
|
(when (menu-button 41 215 134 210 24 dynamic-label)
|
||||||
|
(set dynamic-lighting (not dynamic-lighting))))
|
||||||
|
|
||||||
|
(let [tex-label (if textures "Textures: On" "Textures: Off")]
|
||||||
|
(when (menu-button 42 215 161 210 24 tex-label)
|
||||||
|
(set textures (not textures))))
|
||||||
|
|
||||||
|
(let [wire-label (if wireframe "Wireframe: On" "Wireframe: Off")]
|
||||||
|
(when (menu-button 43 215 188 210 24 wire-label)
|
||||||
|
(set wireframe (not wireframe))))
|
||||||
|
|
||||||
|
(when (menu-button 32 215 218 210 24 "Back")
|
||||||
|
(set current-panel :main)
|
||||||
|
(set selected-item nil)))
|
||||||
|
|
||||||
|
(fn draw []
|
||||||
|
(set current-items [])
|
||||||
|
(when gui
|
||||||
|
(gui:begin_frame)
|
||||||
|
|
||||||
|
(case current-panel
|
||||||
|
:main (draw-main-menu)
|
||||||
|
:sfx (draw-sfx-panel)
|
||||||
|
:gfx (draw-gfx-panel))
|
||||||
|
|
||||||
|
(if (gui:is_hovering)
|
||||||
|
(pxl8.set_cursor :hand)
|
||||||
|
(pxl8.set_cursor :arrow))
|
||||||
|
|
||||||
|
(gui:end_frame)))
|
||||||
|
|
||||||
|
{:init init
|
||||||
|
:is-paused (fn [] paused)
|
||||||
|
:is-baked-lighting (fn [] baked-lighting)
|
||||||
|
:is-dynamic-lighting (fn [] dynamic-lighting)
|
||||||
|
:is-textures (fn [] textures)
|
||||||
|
:is-wireframe (fn [] wireframe)
|
||||||
|
:toggle toggle
|
||||||
|
:show show
|
||||||
|
:hide hide
|
||||||
|
:update update
|
||||||
|
:draw draw}
|
||||||
|
|
@ -8,19 +8,19 @@ local Bsp = {}
|
||||||
Bsp.__index = Bsp
|
Bsp.__index = Bsp
|
||||||
|
|
||||||
function Bsp:face_count()
|
function Bsp:face_count()
|
||||||
return C.pxl8_bsp_face_count(self._ptr)
|
return C.demo3d_bsp_face_count(self._ptr)
|
||||||
end
|
end
|
||||||
|
|
||||||
function Bsp:face_normal(face_id)
|
function Bsp:face_normal(face_id)
|
||||||
return C.pxl8_bsp_face_normal(self._ptr, face_id)
|
return C.demo3d_bsp_face_normal(self._ptr, face_id)
|
||||||
end
|
end
|
||||||
|
|
||||||
function Bsp:light_at(x, y, z, ambient)
|
function Bsp:light_at(x, y, z, ambient)
|
||||||
return C.pxl8_bsp_light_at(self._ptr, x, y, z, ambient or 0)
|
return C.demo3d_bsp_light_at(self._ptr, x, y, z, ambient or 0)
|
||||||
end
|
end
|
||||||
|
|
||||||
function Bsp:face_set_material(face_id, material_id)
|
function Bsp:face_set_material(face_id, material_id)
|
||||||
C.pxl8_bsp_face_set_material(self._ptr, face_id, material_id)
|
C.demo3d_bsp_face_set_material(self._ptr, face_id, material_id)
|
||||||
end
|
end
|
||||||
|
|
||||||
world.Bsp = Bsp
|
world.Bsp = Bsp
|
||||||
|
|
@ -49,69 +49,69 @@ local World = {}
|
||||||
World.__index = World
|
World.__index = World
|
||||||
|
|
||||||
function World.get()
|
function World.get()
|
||||||
local w = C.pxl8_get_world(core.sys)
|
local w = C.demo3d_get_world(core.sys)
|
||||||
if w == nil then return nil end
|
if w == nil then return nil end
|
||||||
return setmetatable({ _ptr = w }, World)
|
return setmetatable({ _ptr = w }, World)
|
||||||
end
|
end
|
||||||
|
|
||||||
function World:active_chunk()
|
function World:active_chunk()
|
||||||
local ptr = C.pxl8_world_active_chunk(self._ptr)
|
local ptr = C.demo3d_world_active_chunk(self._ptr)
|
||||||
if ptr == nil then return nil end
|
if ptr == nil then return nil end
|
||||||
return setmetatable({ _ptr = ptr }, Chunk)
|
return setmetatable({ _ptr = ptr }, Chunk)
|
||||||
end
|
end
|
||||||
|
|
||||||
function World:init_local_player(x, y, z)
|
function World:init_local_player(x, y, z)
|
||||||
C.pxl8_world_init_local_player(self._ptr, x, y, z)
|
C.demo3d_world_init_local_player(self._ptr, x, y, z)
|
||||||
end
|
end
|
||||||
|
|
||||||
function World:set_look(yaw, pitch)
|
function World:set_look(yaw, pitch)
|
||||||
C.pxl8_world_set_look(self._ptr, yaw, pitch or 0)
|
C.demo3d_world_set_look(self._ptr, yaw, pitch or 0)
|
||||||
end
|
end
|
||||||
|
|
||||||
function World:local_player()
|
function World:local_player()
|
||||||
local ptr = C.pxl8_world_local_player(self._ptr)
|
local ptr = C.demo3d_world_local_player(self._ptr)
|
||||||
if ptr == nil then return nil end
|
if ptr == nil then return nil end
|
||||||
return ptr
|
return ptr
|
||||||
end
|
end
|
||||||
|
|
||||||
function World:point_solid(x, y, z)
|
function World:point_solid(x, y, z)
|
||||||
return C.pxl8_world_point_solid(self._ptr, x, y, z)
|
return C.demo3d_world_point_solid(self._ptr, x, y, z)
|
||||||
end
|
end
|
||||||
|
|
||||||
function World:ray(from_x, from_y, from_z, to_x, to_y, to_z)
|
function World:ray(from_x, from_y, from_z, to_x, to_y, to_z)
|
||||||
local from = ffi.new("pxl8_vec3", {x = from_x, y = from_y, z = from_z})
|
local from = ffi.new("pxl8_vec3", {x = from_x, y = from_y, z = from_z})
|
||||||
local to = ffi.new("pxl8_vec3", {x = to_x, y = to_y, z = to_z})
|
local to = ffi.new("pxl8_vec3", {x = to_x, y = to_y, z = to_z})
|
||||||
return C.pxl8_world_ray(self._ptr, from, to)
|
return C.demo3d_world_ray(self._ptr, from, to)
|
||||||
end
|
end
|
||||||
|
|
||||||
function World:render(camera_pos)
|
function World:render(camera_pos)
|
||||||
local vec = ffi.new("pxl8_vec3", {x = camera_pos[1], y = camera_pos[2], z = camera_pos[3]})
|
local vec = ffi.new("pxl8_vec3", {x = camera_pos[1], y = camera_pos[2], z = camera_pos[3]})
|
||||||
C.pxl8_world_render(self._ptr, core.gfx, vec)
|
C.demo3d_world_render(self._ptr, core.gfx, vec)
|
||||||
end
|
end
|
||||||
|
|
||||||
function World:set_bsp_material(material_id, material)
|
function World:set_bsp_material(material_id, material)
|
||||||
C.pxl8_world_set_bsp_material(self._ptr, material_id, material._ptr)
|
C.demo3d_world_set_bsp_material(self._ptr, material_id, material._ptr)
|
||||||
end
|
end
|
||||||
|
|
||||||
function World:sweep(from_x, from_y, from_z, to_x, to_y, to_z, radius)
|
function World:sweep(from_x, from_y, from_z, to_x, to_y, to_z, radius)
|
||||||
local from = ffi.new("pxl8_vec3", {x = from_x, y = from_y, z = from_z})
|
local from = ffi.new("pxl8_vec3", {x = from_x, y = from_y, z = from_z})
|
||||||
local to = ffi.new("pxl8_vec3", {x = to_x, y = to_y, z = to_z})
|
local to = ffi.new("pxl8_vec3", {x = to_x, y = to_y, z = to_z})
|
||||||
return C.pxl8_world_sweep(self._ptr, from, to, radius)
|
return C.demo3d_world_sweep(self._ptr, from, to, radius)
|
||||||
end
|
end
|
||||||
|
|
||||||
function World:set_sim_config(config)
|
function World:set_sim_config(config)
|
||||||
C.pxl8_world_set_sim_config(self._ptr, config)
|
C.demo3d_world_set_sim_config(self._ptr, config)
|
||||||
end
|
end
|
||||||
|
|
||||||
function World:push_input(input_msg)
|
function World:push_input(input_msg)
|
||||||
C.pxl8_world_push_input(self._ptr, input_msg)
|
C.demo3d_world_push_input(self._ptr, input_msg)
|
||||||
end
|
end
|
||||||
|
|
||||||
world.World = World
|
world.World = World
|
||||||
|
|
||||||
function world.sim_config(opts)
|
function world.sim_config(opts)
|
||||||
opts = opts or {}
|
opts = opts or {}
|
||||||
return ffi.new("pxl8_sim_config", {
|
return ffi.new("demo3d_sim_config", {
|
||||||
move_speed = opts.move_speed or 180.0,
|
move_speed = opts.move_speed or 180.0,
|
||||||
ground_accel = opts.ground_accel or 10.0,
|
ground_accel = opts.ground_accel or 10.0,
|
||||||
air_accel = opts.air_accel or 1.0,
|
air_accel = opts.air_accel or 1.0,
|
||||||
|
|
@ -126,28 +126,28 @@ function world.sim_config(opts)
|
||||||
end
|
end
|
||||||
|
|
||||||
function world.sim_move_player(entity, input_msg, sim_world, config, dt)
|
function world.sim_move_player(entity, input_msg, sim_world, config, dt)
|
||||||
C.pxl8_sim_move_player(entity, input_msg, sim_world, config, dt)
|
C.demo3d_sim_move_player(entity, input_msg, sim_world, config, dt)
|
||||||
end
|
end
|
||||||
|
|
||||||
function world.sim_trace(sim_world, from_x, from_y, from_z, to_x, to_y, to_z, radius, height)
|
function world.sim_trace(sim_world, from_x, from_y, from_z, to_x, to_y, to_z, radius, height)
|
||||||
local from = ffi.new("pxl8_vec3", {x = from_x, y = from_y, z = from_z})
|
local from = ffi.new("pxl8_vec3", {x = from_x, y = from_y, z = from_z})
|
||||||
local to = ffi.new("pxl8_vec3", {x = to_x, y = to_y, z = to_z})
|
local to = ffi.new("pxl8_vec3", {x = to_x, y = to_y, z = to_z})
|
||||||
return C.pxl8_sim_trace(sim_world, from, to, radius, height)
|
return C.demo3d_sim_trace(sim_world, from, to, radius, height)
|
||||||
end
|
end
|
||||||
|
|
||||||
function world.sim_check_ground(sim_world, x, y, z, radius)
|
function world.sim_check_ground(sim_world, x, y, z, radius)
|
||||||
local pos = ffi.new("pxl8_vec3", {x = x, y = y, z = z})
|
local pos = ffi.new("pxl8_vec3", {x = x, y = y, z = z})
|
||||||
return C.pxl8_sim_check_ground(sim_world, pos, radius)
|
return C.demo3d_sim_check_ground(sim_world, pos, radius)
|
||||||
end
|
end
|
||||||
|
|
||||||
function World:sim_world(x, y, z)
|
function World:sim_world(x, y, z)
|
||||||
local pos = ffi.new("pxl8_vec3", {x = x, y = y, z = z})
|
local pos = ffi.new("pxl8_vec3", {x = x, y = y, z = z})
|
||||||
return C.pxl8_world_sim_world(self._ptr, pos)
|
return C.demo3d_world_sim_world(self._ptr, pos)
|
||||||
end
|
end
|
||||||
|
|
||||||
function world.make_input_msg(opts)
|
function world.make_input_msg(opts)
|
||||||
opts = opts or {}
|
opts = opts or {}
|
||||||
return ffi.new("pxl8_input_msg", {
|
return ffi.new("demo3d_input_msg", {
|
||||||
move_x = opts.move_x or 0,
|
move_x = opts.move_x or 0,
|
||||||
move_y = opts.move_y or 0,
|
move_y = opts.move_y or 0,
|
||||||
look_dx = opts.look_dx or 0,
|
look_dx = opts.look_dx or 0,
|
||||||
BIN
demo3d/res/palettes/palette.ase
Normal file
BIN
demo3d/res/palettes/palette.ase
Normal file
Binary file not shown.
BIN
demo3d/res/textures/door.ase
Normal file
BIN
demo3d/res/textures/door.ase
Normal file
Binary file not shown.
0
pxl8d/.gitignore → demo3d/server/.gitignore
vendored
0
pxl8d/.gitignore → demo3d/server/.gitignore
vendored
22
pxl8d/Cargo.lock → demo3d/server/Cargo.lock
generated
22
pxl8d/Cargo.lock → demo3d/server/Cargo.lock
generated
|
|
@ -73,6 +73,17 @@ dependencies = [
|
||||||
"libloading",
|
"libloading",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "demo3d-server"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"bindgen",
|
||||||
|
"cc",
|
||||||
|
"libc",
|
||||||
|
"libm",
|
||||||
|
"windows-sys",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "either"
|
name = "either"
|
||||||
version = "1.15.0"
|
version = "1.15.0"
|
||||||
|
|
@ -169,17 +180,6 @@ dependencies = [
|
||||||
"unicode-ident",
|
"unicode-ident",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "pxl8d"
|
|
||||||
version = "0.1.0"
|
|
||||||
dependencies = [
|
|
||||||
"bindgen",
|
|
||||||
"cc",
|
|
||||||
"libc",
|
|
||||||
"libm",
|
|
||||||
"windows-sys",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "quote"
|
name = "quote"
|
||||||
version = "1.0.43"
|
version = "1.0.43"
|
||||||
|
|
@ -1,10 +1,10 @@
|
||||||
[package]
|
[package]
|
||||||
name = "pxl8d"
|
name = "demo3d-server"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
edition = "2024"
|
edition = "2024"
|
||||||
|
|
||||||
[lib]
|
[lib]
|
||||||
name = "pxl8d"
|
name = "demo3d_server"
|
||||||
|
|
||||||
[build-dependencies]
|
[build-dependencies]
|
||||||
bindgen = "0.72"
|
bindgen = "0.72"
|
||||||
|
|
@ -23,7 +23,7 @@ windows-sys = { version = "0.61", default-features = false, features = [
|
||||||
] }
|
] }
|
||||||
|
|
||||||
[[bin]]
|
[[bin]]
|
||||||
name = "pxl8d"
|
name = "demo3d-server"
|
||||||
path = "src/main.rs"
|
path = "src/main.rs"
|
||||||
|
|
||||||
[profile.dev]
|
[profile.dev]
|
||||||
68
demo3d/server/build.rs
Normal file
68
demo3d/server/build.rs
Normal file
|
|
@ -0,0 +1,68 @@
|
||||||
|
use std::env;
|
||||||
|
use std::path::PathBuf;
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let manifest_dir = env::var("CARGO_MANIFEST_DIR").unwrap();
|
||||||
|
let root = PathBuf::from(&manifest_dir).join("../..");
|
||||||
|
let framework_src = root.join("src");
|
||||||
|
let game_client = root.join("demo3d/client");
|
||||||
|
|
||||||
|
println!("cargo:rerun-if-changed=../client/bsp/demo3d_bsp.h");
|
||||||
|
println!("cargo:rerun-if-changed=../client/protocol/demo3d_protocol.c");
|
||||||
|
println!("cargo:rerun-if-changed=../client/protocol/demo3d_protocol.h");
|
||||||
|
println!("cargo:rerun-if-changed=../client/sim/demo3d_sim.c");
|
||||||
|
println!("cargo:rerun-if-changed=../client/sim/demo3d_sim.h");
|
||||||
|
println!("cargo:rerun-if-changed=../../src/core/pxl8_log.c");
|
||||||
|
println!("cargo:rerun-if-changed=../../src/core/pxl8_log.h");
|
||||||
|
println!("cargo:rerun-if-changed=../../src/core/pxl8_types.h");
|
||||||
|
println!("cargo:rerun-if-changed=../../src/math/pxl8_math.c");
|
||||||
|
println!("cargo:rerun-if-changed=../../src/math/pxl8_math.h");
|
||||||
|
|
||||||
|
cc::Build::new()
|
||||||
|
.file(framework_src.join("core/pxl8_log.c"))
|
||||||
|
.file(framework_src.join("platform/pxl8_mem.c"))
|
||||||
|
.file(framework_src.join("math/pxl8_math.c"))
|
||||||
|
.file(framework_src.join("math/pxl8_noise.c"))
|
||||||
|
.file(game_client.join("sim/demo3d_sim.c"))
|
||||||
|
.include(framework_src.join("core"))
|
||||||
|
.include(framework_src.join("math"))
|
||||||
|
.include(framework_src.join("platform"))
|
||||||
|
.include(game_client.join("bsp"))
|
||||||
|
.include(game_client.join("net"))
|
||||||
|
.include(game_client.join("sim"))
|
||||||
|
.compile("pxl8");
|
||||||
|
|
||||||
|
let bindings = bindgen::Builder::default()
|
||||||
|
.header(framework_src.join("core/pxl8_log.h").to_str().unwrap())
|
||||||
|
.header(framework_src.join("math/pxl8_noise.h").to_str().unwrap())
|
||||||
|
.header(game_client.join("sim/demo3d_sim.h").to_str().unwrap())
|
||||||
|
.clang_arg(format!("-I{}", framework_src.join("core").display()))
|
||||||
|
.clang_arg(format!("-I{}", framework_src.join("math").display()))
|
||||||
|
.clang_arg(format!("-I{}", framework_src.join("platform").display()))
|
||||||
|
.clang_arg(format!("-I{}", game_client.join("bsp").display()))
|
||||||
|
.clang_arg(format!("-I{}", game_client.join("net").display()))
|
||||||
|
.clang_arg(format!("-I{}", game_client.join("sim").display()))
|
||||||
|
.blocklist_item("FP_NAN")
|
||||||
|
.blocklist_item("FP_INFINITE")
|
||||||
|
.blocklist_item("FP_ZERO")
|
||||||
|
.blocklist_item("FP_SUBNORMAL")
|
||||||
|
.blocklist_item("FP_NORMAL")
|
||||||
|
.blocklist_type("pxl8_vec2")
|
||||||
|
.blocklist_type("pxl8_vec3")
|
||||||
|
.blocklist_type("pxl8_vec4")
|
||||||
|
.blocklist_type("pxl8_mat4")
|
||||||
|
.blocklist_item(".*_simd.*")
|
||||||
|
.blocklist_item("PXL8_SIMD.*")
|
||||||
|
.blocklist_type("__m128.*")
|
||||||
|
.blocklist_type(".*32x4_t|.*16x8_t")
|
||||||
|
.raw_line("pub use crate::math::{pxl8_vec2, pxl8_vec3, pxl8_vec4, pxl8_mat4};")
|
||||||
|
.use_core()
|
||||||
|
.rustified_enum(".*")
|
||||||
|
.generate()
|
||||||
|
.expect("Unable to generate bindings");
|
||||||
|
|
||||||
|
let out_path = PathBuf::from(env::var("OUT_DIR").unwrap());
|
||||||
|
bindings
|
||||||
|
.write_to_file(out_path.join("bindings.rs"))
|
||||||
|
.expect("Couldn't write bindings");
|
||||||
|
}
|
||||||
|
|
@ -2,16 +2,16 @@ use alloc::boxed::Box;
|
||||||
use alloc::vec::Vec;
|
use alloc::vec::Vec;
|
||||||
|
|
||||||
use crate::math::Vec3;
|
use crate::math::Vec3;
|
||||||
use crate::pxl8::*;
|
use crate::bindings::*;
|
||||||
|
|
||||||
pub type Vertex = pxl8_bsp_vertex;
|
pub type Vertex = demo3d_bsp_vertex;
|
||||||
pub type Edge = pxl8_bsp_edge;
|
pub type Edge = demo3d_bsp_edge;
|
||||||
pub type Face = pxl8_bsp_face;
|
pub type Face = demo3d_bsp_face;
|
||||||
pub type Plane = pxl8_bsp_plane;
|
pub type Plane = demo3d_bsp_plane;
|
||||||
pub type Node = pxl8_bsp_node;
|
pub type Node = demo3d_bsp_node;
|
||||||
pub type Leaf = pxl8_bsp_leaf;
|
pub type Leaf = demo3d_bsp_leaf;
|
||||||
pub type Portal = pxl8_bsp_portal;
|
pub type Portal = demo3d_bsp_portal;
|
||||||
pub type CellPortals = pxl8_bsp_cell_portals;
|
pub type CellPortals = demo3d_bsp_cell_portals;
|
||||||
|
|
||||||
impl Default for Edge {
|
impl Default for Edge {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
|
|
@ -132,7 +132,7 @@ impl Clone for Vertex {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Bsp {
|
pub struct Bsp {
|
||||||
inner: pxl8_bsp,
|
inner: demo3d_bsp,
|
||||||
pub cell_portals: Box<[CellPortals]>,
|
pub cell_portals: Box<[CellPortals]>,
|
||||||
pub edges: Box<[Edge]>,
|
pub edges: Box<[Edge]>,
|
||||||
pub faces: Box<[Face]>,
|
pub faces: Box<[Face]>,
|
||||||
|
|
@ -193,7 +193,7 @@ impl From<BspBuilder> for Bsp {
|
||||||
let visdata = b.visdata.into_boxed_slice();
|
let visdata = b.visdata.into_boxed_slice();
|
||||||
let heightfield = b.heightfield.into_boxed_slice();
|
let heightfield = b.heightfield.into_boxed_slice();
|
||||||
|
|
||||||
let inner = pxl8_bsp {
|
let inner = demo3d_bsp {
|
||||||
cell_portals: if cell_portals.is_empty() { core::ptr::null_mut() } else { cell_portals.as_ptr() as *mut _ },
|
cell_portals: if cell_portals.is_empty() { core::ptr::null_mut() } else { cell_portals.as_ptr() as *mut _ },
|
||||||
edges: if edges.is_empty() { core::ptr::null_mut() } else { edges.as_ptr() as *mut _ },
|
edges: if edges.is_empty() { core::ptr::null_mut() } else { edges.as_ptr() as *mut _ },
|
||||||
faces: if faces.is_empty() { core::ptr::null_mut() } else { faces.as_ptr() as *mut _ },
|
faces: if faces.is_empty() { core::ptr::null_mut() } else { faces.as_ptr() as *mut _ },
|
||||||
|
|
@ -254,12 +254,12 @@ impl From<BspBuilder> for Bsp {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Bsp {
|
impl Bsp {
|
||||||
pub fn as_c_bsp(&self) -> &pxl8_bsp {
|
pub fn as_c_bsp(&self) -> &demo3d_bsp {
|
||||||
&self.inner
|
&self.inner
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn trace(&self, from: Vec3, to: Vec3, radius: f32) -> Vec3 {
|
pub fn trace(&self, from: Vec3, to: Vec3, radius: f32) -> Vec3 {
|
||||||
unsafe { pxl8_bsp_trace(&self.inner, from, to, radius) }
|
unsafe { demo3d_bsp_trace(&self.inner, from, to, radius) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -23,8 +23,8 @@ fn panic(_info: &PanicInfo) -> ! {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(dead_code, non_camel_case_types, non_snake_case, non_upper_case_globals)]
|
#[allow(dead_code, non_camel_case_types, non_snake_case, non_upper_case_globals)]
|
||||||
pub mod pxl8 {
|
pub mod bindings {
|
||||||
include!(concat!(env!("OUT_DIR"), "/pxl8.rs"));
|
include!(concat!(env!("OUT_DIR"), "/bindings.rs"));
|
||||||
}
|
}
|
||||||
|
|
||||||
pub use bsp::*;
|
pub use bsp::*;
|
||||||
|
|
@ -32,7 +32,7 @@ pub use chunk::*;
|
||||||
pub use chunk::stream::*;
|
pub use chunk::stream::*;
|
||||||
pub use math::*;
|
pub use math::*;
|
||||||
pub use procgen::generate_chunk;
|
pub use procgen::generate_chunk;
|
||||||
pub use pxl8::*;
|
pub use bindings::*;
|
||||||
pub use sim::*;
|
pub use sim::*;
|
||||||
pub use transport::*;
|
pub use transport::*;
|
||||||
pub use world::*;
|
pub use world::*;
|
||||||
|
|
@ -1,9 +1,9 @@
|
||||||
use crate::pxl8::{pxl8_log, pxl8_log_init};
|
use crate::bindings::{pxl8_log, pxl8_log_init};
|
||||||
use core::ffi::c_char;
|
use core::ffi::c_char;
|
||||||
|
|
||||||
static mut G_LOG: pxl8_log = pxl8_log {
|
static mut G_LOG: pxl8_log = pxl8_log {
|
||||||
handler: None,
|
handler: None,
|
||||||
level: crate::pxl8::pxl8_log_level::PXL8_LOG_LEVEL_DEBUG,
|
level: crate::bindings::pxl8_log_level::PXL8_LOG_LEVEL_DEBUG,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub fn init() {
|
pub fn init() {
|
||||||
|
|
@ -20,7 +20,7 @@ macro_rules! pxl8_debug {
|
||||||
let _ = ::core::write!(&mut buf, $($arg)*);
|
let _ = ::core::write!(&mut buf, $($arg)*);
|
||||||
buf.push(0);
|
buf.push(0);
|
||||||
unsafe {
|
unsafe {
|
||||||
$crate::pxl8::pxl8_log_write_debug(
|
$crate::bindings::pxl8_log_write_debug(
|
||||||
concat!(file!(), "\0").as_ptr() as *const ::core::ffi::c_char,
|
concat!(file!(), "\0").as_ptr() as *const ::core::ffi::c_char,
|
||||||
line!() as ::core::ffi::c_int,
|
line!() as ::core::ffi::c_int,
|
||||||
c"%s".as_ptr() as *const ::core::ffi::c_char,
|
c"%s".as_ptr() as *const ::core::ffi::c_char,
|
||||||
|
|
@ -38,7 +38,7 @@ macro_rules! pxl8_error {
|
||||||
let _ = ::core::write!(&mut buf, $($arg)*);
|
let _ = ::core::write!(&mut buf, $($arg)*);
|
||||||
buf.push(0);
|
buf.push(0);
|
||||||
unsafe {
|
unsafe {
|
||||||
$crate::pxl8::pxl8_log_write_error(
|
$crate::bindings::pxl8_log_write_error(
|
||||||
concat!(file!(), "\0").as_ptr() as *const ::core::ffi::c_char,
|
concat!(file!(), "\0").as_ptr() as *const ::core::ffi::c_char,
|
||||||
line!() as ::core::ffi::c_int,
|
line!() as ::core::ffi::c_int,
|
||||||
c"%s".as_ptr() as *const ::core::ffi::c_char,
|
c"%s".as_ptr() as *const ::core::ffi::c_char,
|
||||||
|
|
@ -56,7 +56,7 @@ macro_rules! pxl8_info {
|
||||||
let _ = ::core::write!(&mut buf, $($arg)*);
|
let _ = ::core::write!(&mut buf, $($arg)*);
|
||||||
buf.push(0);
|
buf.push(0);
|
||||||
unsafe {
|
unsafe {
|
||||||
$crate::pxl8::pxl8_log_write_info(
|
$crate::bindings::pxl8_log_write_info(
|
||||||
c"%s".as_ptr() as *const ::core::ffi::c_char,
|
c"%s".as_ptr() as *const ::core::ffi::c_char,
|
||||||
buf.as_ptr(),
|
buf.as_ptr(),
|
||||||
);
|
);
|
||||||
|
|
@ -72,7 +72,7 @@ macro_rules! pxl8_trace {
|
||||||
let _ = ::core::write!(&mut buf, $($arg)*);
|
let _ = ::core::write!(&mut buf, $($arg)*);
|
||||||
buf.push(0);
|
buf.push(0);
|
||||||
unsafe {
|
unsafe {
|
||||||
$crate::pxl8::pxl8_log_write_trace(
|
$crate::bindings::pxl8_log_write_trace(
|
||||||
concat!(file!(), "\0").as_ptr() as *const ::core::ffi::c_char,
|
concat!(file!(), "\0").as_ptr() as *const ::core::ffi::c_char,
|
||||||
line!() as ::core::ffi::c_int,
|
line!() as ::core::ffi::c_int,
|
||||||
c"%s".as_ptr() as *const ::core::ffi::c_char,
|
c"%s".as_ptr() as *const ::core::ffi::c_char,
|
||||||
|
|
@ -90,7 +90,7 @@ macro_rules! pxl8_warn {
|
||||||
let _ = ::core::write!(&mut buf, $($arg)*);
|
let _ = ::core::write!(&mut buf, $($arg)*);
|
||||||
buf.push(0);
|
buf.push(0);
|
||||||
unsafe {
|
unsafe {
|
||||||
$crate::pxl8::pxl8_log_write_warn(
|
$crate::bindings::pxl8_log_write_warn(
|
||||||
concat!(file!(), "\0").as_ptr() as *const ::core::ffi::c_char,
|
concat!(file!(), "\0").as_ptr() as *const ::core::ffi::c_char,
|
||||||
line!() as ::core::ffi::c_int,
|
line!() as ::core::ffi::c_int,
|
||||||
c"%s".as_ptr() as *const ::core::ffi::c_char,
|
c"%s".as_ptr() as *const ::core::ffi::c_char,
|
||||||
|
|
@ -4,11 +4,11 @@
|
||||||
extern crate alloc;
|
extern crate alloc;
|
||||||
|
|
||||||
use alloc::vec::Vec;
|
use alloc::vec::Vec;
|
||||||
use pxl8d::*;
|
use demo3d_server::*;
|
||||||
use pxl8d::chunk::ChunkId;
|
use demo3d_server::chunk::ChunkId;
|
||||||
use pxl8d::chunk::stream::ClientChunkState;
|
use demo3d_server::chunk::stream::ClientChunkState;
|
||||||
use pxl8d::pxl8::pxl8_cmd_type::*;
|
use demo3d_server::bindings::demo3d_cmd_type::*;
|
||||||
use pxl8d::pxl8::pxl8_msg_type::*;
|
use demo3d_server::bindings::demo3d_msg_type::*;
|
||||||
|
|
||||||
const TICK_RATE: u64 = 30;
|
const TICK_RATE: u64 = 30;
|
||||||
const TICK_NS: u64 = 1_000_000_000 / TICK_RATE;
|
const TICK_NS: u64 = 1_000_000_000 / TICK_RATE;
|
||||||
|
|
@ -82,11 +82,11 @@ pub extern "C" fn main(_argc: i32, _argv: *const *const u8) -> i32 {
|
||||||
|
|
||||||
let mut sequence: u32 = 0;
|
let mut sequence: u32 = 0;
|
||||||
let mut last_tick = get_time_ns();
|
let mut last_tick = get_time_ns();
|
||||||
let mut entities_buf = [pxl8d::pxl8_entity_state {
|
let mut entities_buf = [demo3d_server::demo3d_entity_state {
|
||||||
entity_id: 0,
|
entity_id: 0,
|
||||||
userdata: [0u8; 56],
|
userdata: [0u8; 56],
|
||||||
}; 64];
|
}; 64];
|
||||||
let mut inputs_buf: [pxl8d::pxl8_input_msg; 16] = unsafe { core::mem::zeroed() };
|
let mut inputs_buf: [demo3d_server::demo3d_input_msg; 16] = unsafe { core::mem::zeroed() };
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
let now = get_time_ns();
|
let now = get_time_ns();
|
||||||
|
|
@ -96,15 +96,15 @@ pub extern "C" fn main(_argc: i32, _argv: *const *const u8) -> i32 {
|
||||||
last_tick = now;
|
last_tick = now;
|
||||||
let dt = (elapsed as f32) / 1_000_000_000.0;
|
let dt = (elapsed as f32) / 1_000_000_000.0;
|
||||||
|
|
||||||
let mut latest_input: Option<pxl8d::pxl8_input_msg> = None;
|
let mut latest_input: Option<demo3d_server::demo3d_input_msg> = None;
|
||||||
while let Some(msg_type) = transport.recv() {
|
while let Some(msg_type) = transport.recv() {
|
||||||
match msg_type {
|
match msg_type {
|
||||||
x if x == PXL8_MSG_INPUT as u8 => {
|
x if x == DEMO3D_MSG_INPUT as u8 => {
|
||||||
latest_input = Some(transport.get_input());
|
latest_input = Some(transport.get_input());
|
||||||
}
|
}
|
||||||
x if x == PXL8_MSG_COMMAND as u8 => {
|
x if x == DEMO3D_MSG_COMMAND as u8 => {
|
||||||
let cmd = transport.get_command();
|
let cmd = transport.get_command();
|
||||||
if cmd.cmd_type == PXL8_CMD_SPAWN_ENTITY as u16 {
|
if cmd.cmd_type == DEMO3D_CMD_SPAWN_ENTITY as u16 {
|
||||||
let (x, y, z, _yaw, _pitch) = extract_spawn_position(&cmd.payload);
|
let (x, y, z, _yaw, _pitch) = extract_spawn_position(&cmd.payload);
|
||||||
player_id = Some(sim.spawn_player(x, y, z) as u64);
|
player_id = Some(sim.spawn_player(x, y, z) as u64);
|
||||||
}
|
}
|
||||||
|
|
@ -129,7 +129,7 @@ pub extern "C" fn main(_argc: i32, _argv: *const *const u8) -> i32 {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
let header = pxl8d::pxl8_snapshot_header {
|
let header = demo3d_server::demo3d_snapshot_header {
|
||||||
entity_count: count as u16,
|
entity_count: count as u16,
|
||||||
event_count: 0,
|
event_count: 0,
|
||||||
player_id: player_id.unwrap_or(0),
|
player_id: player_id.unwrap_or(0),
|
||||||
|
|
@ -1401,7 +1401,7 @@ fn grid_to_bsp_exterior(bsp: &mut BspBuilder, grid: &RoomGrid, origin_x: f32, or
|
||||||
let wx = origin_x + vx as f32 * CELL_SIZE;
|
let wx = origin_x + vx as f32 * CELL_SIZE;
|
||||||
let wz = origin_z + vz as f32 * CELL_SIZE;
|
let wz = origin_z + vz as f32 * CELL_SIZE;
|
||||||
let h = unsafe {
|
let h = unsafe {
|
||||||
crate::pxl8::pxl8_fbm(wx * 0.002, wz * 0.002, world_seed + 5000, 4)
|
crate::bindings::pxl8_fbm(wx * 0.002, wz * 0.002, world_seed + 5000, 4)
|
||||||
};
|
};
|
||||||
let blend = edge_blend(wx, wz, world_seed);
|
let blend = edge_blend(wx, wz, world_seed);
|
||||||
corner_heights[vz as usize * vw + vx as usize] = h * 128.0 * blend;
|
corner_heights[vz as usize * vw + vx as usize] = h * 128.0 * blend;
|
||||||
|
|
@ -1878,7 +1878,7 @@ pub fn generate_rooms(params: &ProcgenParams, doorways: &[Doorway], entries: &[C
|
||||||
for vx in 0..vw as i32 {
|
for vx in 0..vw as i32 {
|
||||||
let wx = params.origin_x + vx as f32 * CELL_SIZE;
|
let wx = params.origin_x + vx as f32 * CELL_SIZE;
|
||||||
let wz = params.origin_z + vz as f32 * CELL_SIZE;
|
let wz = params.origin_z + vz as f32 * CELL_SIZE;
|
||||||
let h = unsafe { crate::pxl8::pxl8_fbm(wx * 0.002, wz * 0.002, world_seed + 5000, 4) };
|
let h = unsafe { crate::bindings::pxl8_fbm(wx * 0.002, wz * 0.002, world_seed + 5000, 4) };
|
||||||
let blend = edge_blend(wx, wz, world_seed);
|
let blend = edge_blend(wx, wz, world_seed);
|
||||||
bsp.heightfield[vz as usize * vw + vx as usize] = h * 128.0 * blend;
|
bsp.heightfield[vz as usize * vw + vx as usize] = h * 128.0 * blend;
|
||||||
}
|
}
|
||||||
|
|
@ -2046,7 +2046,7 @@ pub fn generate_courtyard(params: &ProcgenParams, entries: &[ChunkEntry], world_
|
||||||
for vx in 0..vw as i32 {
|
for vx in 0..vw as i32 {
|
||||||
let wx = params.origin_x + vx as f32 * CELL_SIZE;
|
let wx = params.origin_x + vx as f32 * CELL_SIZE;
|
||||||
let wz = params.origin_z + vz as f32 * CELL_SIZE;
|
let wz = params.origin_z + vz as f32 * CELL_SIZE;
|
||||||
let h = unsafe { crate::pxl8::pxl8_fbm(wx * 0.002, wz * 0.002, world_seed + 5000, 4) };
|
let h = unsafe { crate::bindings::pxl8_fbm(wx * 0.002, wz * 0.002, world_seed + 5000, 4) };
|
||||||
let blend = edge_blend(wx, wz, world_seed);
|
let blend = edge_blend(wx, wz, world_seed);
|
||||||
bsp.heightfield[vz as usize * vw + vx as usize] = h * 128.0 * blend;
|
bsp.heightfield[vz as usize * vw + vx as usize] = h * 128.0 * blend;
|
||||||
}
|
}
|
||||||
|
|
@ -2087,7 +2087,7 @@ pub fn select_biome(cx: i32, cz: i32, seed: u64) -> Biome {
|
||||||
if cx == 0 && cz == 0 { return Biome::Dungeon; }
|
if cx == 0 && cz == 0 { return Biome::Dungeon; }
|
||||||
if cx == 1 && cz == 0 { return Biome::Courtyard; }
|
if cx == 1 && cz == 0 { return Biome::Courtyard; }
|
||||||
|
|
||||||
let n = unsafe { crate::pxl8::pxl8_fbm(cx as f32 * 0.1, cz as f32 * 0.1, seed, 3) };
|
let n = unsafe { crate::bindings::pxl8_fbm(cx as f32 * 0.1, cz as f32 * 0.1, seed, 3) };
|
||||||
if n < 0.4 {
|
if n < 0.4 {
|
||||||
Biome::Dungeon
|
Biome::Dungeon
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -2,13 +2,13 @@ use alloc::vec::Vec;
|
||||||
|
|
||||||
use crate::chunk::ChunkId;
|
use crate::chunk::ChunkId;
|
||||||
use crate::math::Vec3;
|
use crate::math::Vec3;
|
||||||
use crate::pxl8::*;
|
use crate::bindings::*;
|
||||||
use crate::world::World;
|
use crate::world::World;
|
||||||
|
|
||||||
pub type Entity = pxl8_sim_entity;
|
pub type Entity = demo3d_sim_entity;
|
||||||
|
|
||||||
const ALIVE: u32 = PXL8_SIM_FLAG_ALIVE;
|
const ALIVE: u32 = DEMO3D_SIM_FLAG_ALIVE;
|
||||||
const PLAYER: u32 = PXL8_SIM_FLAG_PLAYER;
|
const PLAYER: u32 = DEMO3D_SIM_FLAG_PLAYER;
|
||||||
|
|
||||||
const MAX_ENTITIES: usize = 1024;
|
const MAX_ENTITIES: usize = 1024;
|
||||||
|
|
||||||
|
|
@ -95,7 +95,7 @@ impl Simulation {
|
||||||
id
|
id
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn step(&mut self, inputs: &[pxl8_input_msg], dt: f32) {
|
pub fn step(&mut self, inputs: &[demo3d_input_msg], dt: f32) {
|
||||||
self.tick += 1;
|
self.tick += 1;
|
||||||
self.time += dt;
|
self.time += dt;
|
||||||
|
|
||||||
|
|
@ -106,8 +106,8 @@ impl Simulation {
|
||||||
self.integrate(dt);
|
self.integrate(dt);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn sim_config() -> pxl8_sim_config {
|
fn sim_config() -> demo3d_sim_config {
|
||||||
pxl8_sim_config {
|
demo3d_sim_config {
|
||||||
move_speed: 180.0,
|
move_speed: 180.0,
|
||||||
ground_accel: 10.0,
|
ground_accel: 10.0,
|
||||||
air_accel: 1.0,
|
air_accel: 1.0,
|
||||||
|
|
@ -121,12 +121,12 @@ impl Simulation {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn make_sim_world(&self, player_pos: Vec3) -> pxl8_sim_world {
|
fn make_sim_world(&self, player_pos: Vec3) -> demo3d_sim_world {
|
||||||
let chunk_size: f32 = 16.0 * 64.0;
|
let chunk_size: f32 = 16.0 * 64.0;
|
||||||
let center_cx = libm::floorf(player_pos.x / chunk_size) as i32;
|
let center_cx = libm::floorf(player_pos.x / chunk_size) as i32;
|
||||||
let center_cz = libm::floorf(player_pos.z / chunk_size) as i32;
|
let center_cz = libm::floorf(player_pos.z / chunk_size) as i32;
|
||||||
|
|
||||||
let mut sim = pxl8_sim_world {
|
let mut sim = demo3d_sim_world {
|
||||||
chunks: [core::ptr::null(); 9],
|
chunks: [core::ptr::null(); 9],
|
||||||
center_cx,
|
center_cx,
|
||||||
center_cz,
|
center_cz,
|
||||||
|
|
@ -160,12 +160,12 @@ impl Simulation {
|
||||||
let world = self.make_sim_world(ent.pos);
|
let world = self.make_sim_world(ent.pos);
|
||||||
let ent = &mut self.entities[i];
|
let ent = &mut self.entities[i];
|
||||||
unsafe {
|
unsafe {
|
||||||
pxl8_sim_integrate(ent, &world, &cfg, dt);
|
demo3d_sim_integrate(ent, &world, &cfg, dt);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn move_player(&mut self, input: &pxl8_input_msg, dt: f32) {
|
fn move_player(&mut self, input: &demo3d_input_msg, dt: f32) {
|
||||||
let cfg = Self::sim_config();
|
let cfg = Self::sim_config();
|
||||||
let Some(id) = self.player else { return };
|
let Some(id) = self.player else { return };
|
||||||
let ent = &self.entities[id as usize];
|
let ent = &self.entities[id as usize];
|
||||||
|
|
@ -176,20 +176,20 @@ impl Simulation {
|
||||||
let world = self.make_sim_world(ent.pos);
|
let world = self.make_sim_world(ent.pos);
|
||||||
let ent = &mut self.entities[id as usize];
|
let ent = &mut self.entities[id as usize];
|
||||||
unsafe {
|
unsafe {
|
||||||
pxl8_sim_move_player(ent, input, &world, &cfg, dt);
|
demo3d_sim_move_player(ent, input, &world, &cfg, dt);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn generate_snapshot<F>(&self, mut writer: F)
|
pub fn generate_snapshot<F>(&self, mut writer: F)
|
||||||
where
|
where
|
||||||
F: FnMut(&pxl8_entity_state),
|
F: FnMut(&demo3d_entity_state),
|
||||||
{
|
{
|
||||||
for (i, ent) in self.entities.iter().enumerate() {
|
for (i, ent) in self.entities.iter().enumerate() {
|
||||||
if ent.flags & ALIVE == 0 {
|
if ent.flags & ALIVE == 0 {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut state = pxl8_entity_state {
|
let mut state = demo3d_entity_state {
|
||||||
entity_id: i as u64,
|
entity_id: i as u64,
|
||||||
userdata: [0u8; 56],
|
userdata: [0u8; 56],
|
||||||
};
|
};
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
use alloc::vec;
|
use alloc::vec;
|
||||||
use alloc::vec::Vec;
|
use alloc::vec::Vec;
|
||||||
use crate::pxl8::*;
|
use crate::bindings::*;
|
||||||
use crate::pxl8::pxl8_msg_type::*;
|
use crate::bindings::demo3d_msg_type::*;
|
||||||
pub const DEFAULT_PORT: u16 = 7777;
|
pub const DEFAULT_PORT: u16 = 7777;
|
||||||
pub const CHUNK_MAX_PAYLOAD: usize = 1400;
|
pub const CHUNK_MAX_PAYLOAD: usize = 1400;
|
||||||
pub const CHUNK_FLAG_FINAL: u8 = 0x04;
|
pub const CHUNK_FLAG_FINAL: u8 = 0x04;
|
||||||
|
|
@ -308,7 +308,7 @@ impl Transport {
|
||||||
let mut addr: SockAddr = unsafe { core::mem::zeroed() };
|
let mut addr: SockAddr = unsafe { core::mem::zeroed() };
|
||||||
let len = sys::recvfrom(self.socket, &mut self.recv_buf, &mut addr);
|
let len = sys::recvfrom(self.socket, &mut self.recv_buf, &mut addr);
|
||||||
|
|
||||||
if len <= 0 || (len as usize) < size_of::<pxl8_msg_header>() {
|
if len <= 0 || (len as usize) < size_of::<demo3d_msg_header>() {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -319,18 +319,18 @@ impl Transport {
|
||||||
Some(header.type_)
|
Some(header.type_)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_input(&self) -> pxl8_input_msg {
|
pub fn get_input(&self) -> demo3d_input_msg {
|
||||||
self.deserialize_input()
|
self.deserialize_input()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_command(&self) -> pxl8_command_msg {
|
pub fn get_command(&self) -> demo3d_command_msg {
|
||||||
self.deserialize_command()
|
self.deserialize_command()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn send_snapshot(
|
pub fn send_snapshot(
|
||||||
&mut self,
|
&mut self,
|
||||||
header: &pxl8_snapshot_header,
|
header: &demo3d_snapshot_header,
|
||||||
entities: &[pxl8_entity_state],
|
entities: &[demo3d_entity_state],
|
||||||
sequence: u32,
|
sequence: u32,
|
||||||
) {
|
) {
|
||||||
if !self.has_client {
|
if !self.has_client {
|
||||||
|
|
@ -339,11 +339,11 @@ impl Transport {
|
||||||
|
|
||||||
let mut offset = 0;
|
let mut offset = 0;
|
||||||
|
|
||||||
let msg_header = pxl8_msg_header {
|
let msg_header = demo3d_msg_header {
|
||||||
sequence,
|
sequence,
|
||||||
size: 0,
|
size: 0,
|
||||||
type_: PXL8_MSG_SNAPSHOT as u8,
|
type_: DEMO3D_MSG_SNAPSHOT as u8,
|
||||||
version: PXL8_PROTOCOL_VERSION as u8,
|
version: DEMO3D_PROTOCOL_VERSION as u8,
|
||||||
};
|
};
|
||||||
offset += self.serialize_header(&msg_header, offset);
|
offset += self.serialize_header(&msg_header, offset);
|
||||||
offset += self.serialize_snapshot_header(header, offset);
|
offset += self.serialize_snapshot_header(header, offset);
|
||||||
|
|
@ -362,11 +362,11 @@ impl Transport {
|
||||||
|
|
||||||
let mut offset = 0;
|
let mut offset = 0;
|
||||||
|
|
||||||
let msg_header = pxl8_msg_header {
|
let msg_header = demo3d_msg_header {
|
||||||
sequence,
|
sequence,
|
||||||
size: 0,
|
size: 0,
|
||||||
type_: PXL8_MSG_CHUNK as u8,
|
type_: DEMO3D_MSG_CHUNK as u8,
|
||||||
version: PXL8_PROTOCOL_VERSION as u8,
|
version: DEMO3D_PROTOCOL_VERSION as u8,
|
||||||
};
|
};
|
||||||
offset += self.serialize_header(&msg_header, offset);
|
offset += self.serialize_header(&msg_header, offset);
|
||||||
offset += self.serialize_chunk_msg_header(msg, offset);
|
offset += self.serialize_chunk_msg_header(msg, offset);
|
||||||
|
|
@ -385,11 +385,11 @@ impl Transport {
|
||||||
|
|
||||||
let mut offset = 0;
|
let mut offset = 0;
|
||||||
|
|
||||||
let msg_header = pxl8_msg_header {
|
let msg_header = demo3d_msg_header {
|
||||||
sequence,
|
sequence,
|
||||||
size: 0,
|
size: 0,
|
||||||
type_: PXL8_MSG_CHUNK_ENTER as u8,
|
type_: DEMO3D_MSG_CHUNK_ENTER as u8,
|
||||||
version: PXL8_PROTOCOL_VERSION as u8,
|
version: DEMO3D_PROTOCOL_VERSION as u8,
|
||||||
};
|
};
|
||||||
offset += self.serialize_header(&msg_header, offset);
|
offset += self.serialize_header(&msg_header, offset);
|
||||||
|
|
||||||
|
|
@ -418,7 +418,7 @@ impl Transport {
|
||||||
28
|
28
|
||||||
}
|
}
|
||||||
|
|
||||||
fn serialize_header(&mut self, h: &pxl8_msg_header, offset: usize) -> usize {
|
fn serialize_header(&mut self, h: &demo3d_msg_header, offset: usize) -> usize {
|
||||||
let buf = &mut self.send_buf[offset..];
|
let buf = &mut self.send_buf[offset..];
|
||||||
buf[0..4].copy_from_slice(&h.sequence.to_be_bytes());
|
buf[0..4].copy_from_slice(&h.sequence.to_be_bytes());
|
||||||
buf[4..6].copy_from_slice(&h.size.to_be_bytes());
|
buf[4..6].copy_from_slice(&h.size.to_be_bytes());
|
||||||
|
|
@ -427,7 +427,7 @@ impl Transport {
|
||||||
8
|
8
|
||||||
}
|
}
|
||||||
|
|
||||||
fn serialize_snapshot_header(&mut self, h: &pxl8_snapshot_header, offset: usize) -> usize {
|
fn serialize_snapshot_header(&mut self, h: &demo3d_snapshot_header, offset: usize) -> usize {
|
||||||
let buf = &mut self.send_buf[offset..];
|
let buf = &mut self.send_buf[offset..];
|
||||||
buf[0..2].copy_from_slice(&h.entity_count.to_be_bytes());
|
buf[0..2].copy_from_slice(&h.entity_count.to_be_bytes());
|
||||||
buf[2..4].copy_from_slice(&h.event_count.to_be_bytes());
|
buf[2..4].copy_from_slice(&h.event_count.to_be_bytes());
|
||||||
|
|
@ -437,16 +437,16 @@ impl Transport {
|
||||||
24
|
24
|
||||||
}
|
}
|
||||||
|
|
||||||
fn serialize_entity_state(&mut self, e: &pxl8_entity_state, offset: usize) -> usize {
|
fn serialize_entity_state(&mut self, e: &demo3d_entity_state, offset: usize) -> usize {
|
||||||
let buf = &mut self.send_buf[offset..];
|
let buf = &mut self.send_buf[offset..];
|
||||||
buf[0..8].copy_from_slice(&e.entity_id.to_be_bytes());
|
buf[0..8].copy_from_slice(&e.entity_id.to_be_bytes());
|
||||||
buf[8..64].copy_from_slice(&e.userdata);
|
buf[8..64].copy_from_slice(&e.userdata);
|
||||||
64
|
64
|
||||||
}
|
}
|
||||||
|
|
||||||
fn deserialize_header(&self) -> pxl8_msg_header {
|
fn deserialize_header(&self) -> demo3d_msg_header {
|
||||||
let buf = &self.recv_buf;
|
let buf = &self.recv_buf;
|
||||||
pxl8_msg_header {
|
demo3d_msg_header {
|
||||||
sequence: u32::from_be_bytes([buf[0], buf[1], buf[2], buf[3]]),
|
sequence: u32::from_be_bytes([buf[0], buf[1], buf[2], buf[3]]),
|
||||||
size: u16::from_be_bytes([buf[4], buf[5]]),
|
size: u16::from_be_bytes([buf[4], buf[5]]),
|
||||||
type_: buf[6],
|
type_: buf[6],
|
||||||
|
|
@ -454,9 +454,9 @@ impl Transport {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn deserialize_input(&self) -> pxl8_input_msg {
|
fn deserialize_input(&self) -> demo3d_input_msg {
|
||||||
let buf = &self.recv_buf[8..];
|
let buf = &self.recv_buf[8..];
|
||||||
pxl8_input_msg {
|
demo3d_input_msg {
|
||||||
buttons: u32::from_be_bytes([buf[0], buf[1], buf[2], buf[3]]),
|
buttons: u32::from_be_bytes([buf[0], buf[1], buf[2], buf[3]]),
|
||||||
look_dx: f32::from_be_bytes([buf[4], buf[5], buf[6], buf[7]]),
|
look_dx: f32::from_be_bytes([buf[4], buf[5], buf[6], buf[7]]),
|
||||||
look_dy: f32::from_be_bytes([buf[8], buf[9], buf[10], buf[11]]),
|
look_dy: f32::from_be_bytes([buf[8], buf[9], buf[10], buf[11]]),
|
||||||
|
|
@ -468,9 +468,9 @@ impl Transport {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn deserialize_command(&self) -> pxl8_command_msg {
|
fn deserialize_command(&self) -> demo3d_command_msg {
|
||||||
let buf = &self.recv_buf[8..];
|
let buf = &self.recv_buf[8..];
|
||||||
let mut cmd = pxl8_command_msg {
|
let mut cmd = demo3d_command_msg {
|
||||||
cmd_type: u16::from_be_bytes([buf[0], buf[1]]),
|
cmd_type: u16::from_be_bytes([buf[0], buf[1]]),
|
||||||
payload: [0u8; 64],
|
payload: [0u8; 64],
|
||||||
payload_size: u16::from_be_bytes([buf[66], buf[67]]),
|
payload_size: u16::from_be_bytes([buf[66], buf[67]]),
|
||||||
|
|
@ -1,64 +0,0 @@
|
||||||
use std::env;
|
|
||||||
use std::path::PathBuf;
|
|
||||||
|
|
||||||
fn main() {
|
|
||||||
let manifest_dir = env::var("CARGO_MANIFEST_DIR").unwrap();
|
|
||||||
let pxl8_src = PathBuf::from(&manifest_dir).join("../src");
|
|
||||||
|
|
||||||
println!("cargo:rerun-if-changed=../src/bsp/pxl8_bsp.h");
|
|
||||||
println!("cargo:rerun-if-changed=../src/core/pxl8_log.c");
|
|
||||||
println!("cargo:rerun-if-changed=../src/core/pxl8_log.h");
|
|
||||||
println!("cargo:rerun-if-changed=../src/core/pxl8_types.h");
|
|
||||||
println!("cargo:rerun-if-changed=../src/math/pxl8_math.c");
|
|
||||||
println!("cargo:rerun-if-changed=../src/math/pxl8_math.h");
|
|
||||||
println!("cargo:rerun-if-changed=../src/net/pxl8_protocol.c");
|
|
||||||
println!("cargo:rerun-if-changed=../src/net/pxl8_protocol.h");
|
|
||||||
println!("cargo:rerun-if-changed=../src/sim/pxl8_sim.c");
|
|
||||||
println!("cargo:rerun-if-changed=../src/sim/pxl8_sim.h");
|
|
||||||
cc::Build::new()
|
|
||||||
.file(pxl8_src.join("core/pxl8_log.c"))
|
|
||||||
.file(pxl8_src.join("hal/pxl8_mem.c"))
|
|
||||||
.file(pxl8_src.join("math/pxl8_math.c"))
|
|
||||||
.file(pxl8_src.join("math/pxl8_noise.c"))
|
|
||||||
.file(pxl8_src.join("sim/pxl8_sim.c"))
|
|
||||||
.include(pxl8_src.join("bsp"))
|
|
||||||
.include(pxl8_src.join("core"))
|
|
||||||
.include(pxl8_src.join("hal"))
|
|
||||||
.include(pxl8_src.join("math"))
|
|
||||||
.include(pxl8_src.join("net"))
|
|
||||||
.include(pxl8_src.join("sim"))
|
|
||||||
.compile("pxl8");
|
|
||||||
|
|
||||||
let bindings = bindgen::Builder::default()
|
|
||||||
.header(pxl8_src.join("core/pxl8_log.h").to_str().unwrap())
|
|
||||||
.header(pxl8_src.join("math/pxl8_noise.h").to_str().unwrap())
|
|
||||||
.header(pxl8_src.join("sim/pxl8_sim.h").to_str().unwrap())
|
|
||||||
.clang_arg(format!("-I{}", pxl8_src.join("bsp").display()))
|
|
||||||
.clang_arg(format!("-I{}", pxl8_src.join("core").display()))
|
|
||||||
.clang_arg(format!("-I{}", pxl8_src.join("math").display()))
|
|
||||||
.clang_arg(format!("-I{}", pxl8_src.join("net").display()))
|
|
||||||
.clang_arg(format!("-I{}", pxl8_src.join("sim").display()))
|
|
||||||
.blocklist_item("FP_NAN")
|
|
||||||
.blocklist_item("FP_INFINITE")
|
|
||||||
.blocklist_item("FP_ZERO")
|
|
||||||
.blocklist_item("FP_SUBNORMAL")
|
|
||||||
.blocklist_item("FP_NORMAL")
|
|
||||||
.blocklist_type("pxl8_vec2")
|
|
||||||
.blocklist_type("pxl8_vec3")
|
|
||||||
.blocklist_type("pxl8_vec4")
|
|
||||||
.blocklist_type("pxl8_mat4")
|
|
||||||
.blocklist_item(".*_simd.*")
|
|
||||||
.blocklist_item("PXL8_SIMD.*")
|
|
||||||
.blocklist_type("__m128.*")
|
|
||||||
.blocklist_type(".*32x4_t|.*16x8_t")
|
|
||||||
.raw_line("pub use crate::math::{pxl8_vec2, pxl8_vec3, pxl8_vec4, pxl8_mat4};")
|
|
||||||
.use_core()
|
|
||||||
.rustified_enum(".*")
|
|
||||||
.generate()
|
|
||||||
.expect("Unable to generate bindings");
|
|
||||||
|
|
||||||
let out_path = PathBuf::from(env::var("OUT_DIR").unwrap());
|
|
||||||
bindings
|
|
||||||
.write_to_file(out_path.join("pxl8.rs"))
|
|
||||||
.expect("Couldn't write bindings");
|
|
||||||
}
|
|
||||||
|
|
@ -67,10 +67,6 @@ static const char embed_pxl8_transition[] = {
|
||||||
#embed "src/lua/pxl8/transition.lua"
|
#embed "src/lua/pxl8/transition.lua"
|
||||||
, 0 };
|
, 0 };
|
||||||
|
|
||||||
static const char embed_pxl8_world[] = {
|
|
||||||
#embed "src/lua/pxl8/world.lua"
|
|
||||||
, 0 };
|
|
||||||
|
|
||||||
#define PXL8_EMBED_ENTRY(var, name) {name, var, sizeof(var) - 1}
|
#define PXL8_EMBED_ENTRY(var, name) {name, var, sizeof(var) - 1}
|
||||||
|
|
||||||
typedef struct { const char* name; const char* data; u32 size; } pxl8_embed;
|
typedef struct { const char* name; const char* data; u32 size; } pxl8_embed;
|
||||||
|
|
@ -92,7 +88,6 @@ static const pxl8_embed pxl8_embeds[] = {
|
||||||
PXL8_EMBED_ENTRY(embed_pxl8_sfx, "pxl8.sfx"),
|
PXL8_EMBED_ENTRY(embed_pxl8_sfx, "pxl8.sfx"),
|
||||||
PXL8_EMBED_ENTRY(embed_pxl8_tilemap, "pxl8.tilemap"),
|
PXL8_EMBED_ENTRY(embed_pxl8_tilemap, "pxl8.tilemap"),
|
||||||
PXL8_EMBED_ENTRY(embed_pxl8_transition, "pxl8.transition"),
|
PXL8_EMBED_ENTRY(embed_pxl8_transition, "pxl8.transition"),
|
||||||
PXL8_EMBED_ENTRY(embed_pxl8_world, "pxl8.world"),
|
|
||||||
{0}
|
{0}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,162 +0,0 @@
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include "pxl8_math.h"
|
|
||||||
#include "pxl8_types.h"
|
|
||||||
|
|
||||||
typedef struct pxl8_bsp_edge {
|
|
||||||
u16 vertex[2];
|
|
||||||
} pxl8_bsp_edge;
|
|
||||||
|
|
||||||
typedef struct pxl8_bsp_face {
|
|
||||||
u32 first_edge;
|
|
||||||
u32 lightmap_offset;
|
|
||||||
u16 num_edges;
|
|
||||||
u16 plane_id;
|
|
||||||
u16 side;
|
|
||||||
|
|
||||||
u8 styles[4];
|
|
||||||
u16 material_id;
|
|
||||||
|
|
||||||
pxl8_vec3 aabb_min;
|
|
||||||
pxl8_vec3 aabb_max;
|
|
||||||
} pxl8_bsp_face;
|
|
||||||
|
|
||||||
typedef struct pxl8_bsp_leaf {
|
|
||||||
u8 ambient_level[4];
|
|
||||||
i32 contents;
|
|
||||||
|
|
||||||
u16 first_marksurface;
|
|
||||||
i16 maxs[3];
|
|
||||||
i16 mins[3];
|
|
||||||
u16 num_marksurfaces;
|
|
||||||
|
|
||||||
i32 visofs;
|
|
||||||
} pxl8_bsp_leaf;
|
|
||||||
|
|
||||||
typedef struct pxl8_bsp_model {
|
|
||||||
i32 first_face;
|
|
||||||
i32 headnode[4];
|
|
||||||
f32 maxs[3];
|
|
||||||
f32 mins[3];
|
|
||||||
i32 num_faces;
|
|
||||||
|
|
||||||
pxl8_vec3 origin;
|
|
||||||
i32 visleafs;
|
|
||||||
} pxl8_bsp_model;
|
|
||||||
|
|
||||||
typedef struct pxl8_bsp_node {
|
|
||||||
i32 children[2];
|
|
||||||
|
|
||||||
u16 first_face;
|
|
||||||
i16 maxs[3];
|
|
||||||
i16 mins[3];
|
|
||||||
u16 num_faces;
|
|
||||||
|
|
||||||
u32 plane_id;
|
|
||||||
} pxl8_bsp_node;
|
|
||||||
|
|
||||||
typedef struct pxl8_bsp_plane {
|
|
||||||
f32 dist;
|
|
||||||
pxl8_vec3 normal;
|
|
||||||
i32 type;
|
|
||||||
} pxl8_bsp_plane;
|
|
||||||
|
|
||||||
|
|
||||||
typedef struct pxl8_bsp_vertex {
|
|
||||||
pxl8_vec3 position;
|
|
||||||
} pxl8_bsp_vertex;
|
|
||||||
|
|
||||||
typedef struct pxl8_bsp_lightmap {
|
|
||||||
u8 color[3];
|
|
||||||
u8 height;
|
|
||||||
u32 offset;
|
|
||||||
u8 width;
|
|
||||||
} pxl8_bsp_lightmap;
|
|
||||||
|
|
||||||
typedef struct pxl8_bsp_lightmap_sample {
|
|
||||||
u8 b;
|
|
||||||
u8 g;
|
|
||||||
u8 r;
|
|
||||||
} pxl8_bsp_lightmap_sample;
|
|
||||||
|
|
||||||
typedef struct pxl8_bsp_pvs {
|
|
||||||
u8* data;
|
|
||||||
u32 size;
|
|
||||||
} pxl8_bsp_pvs;
|
|
||||||
|
|
||||||
typedef struct pxl8_bsp_portal {
|
|
||||||
f32 x0, z0;
|
|
||||||
f32 x1, z1;
|
|
||||||
u32 target_leaf;
|
|
||||||
} pxl8_bsp_portal;
|
|
||||||
|
|
||||||
typedef struct pxl8_bsp_cell_portals {
|
|
||||||
pxl8_bsp_portal portals[4];
|
|
||||||
u8 num_portals;
|
|
||||||
} pxl8_bsp_cell_portals;
|
|
||||||
|
|
||||||
typedef struct pxl8_bsp {
|
|
||||||
pxl8_bsp_cell_portals* cell_portals;
|
|
||||||
pxl8_bsp_edge* edges;
|
|
||||||
pxl8_bsp_face* faces;
|
|
||||||
pxl8_bsp_leaf* leafs;
|
|
||||||
u8* lightdata;
|
|
||||||
pxl8_bsp_lightmap* lightmaps;
|
|
||||||
u16* marksurfaces;
|
|
||||||
pxl8_bsp_model* models;
|
|
||||||
pxl8_bsp_node* nodes;
|
|
||||||
pxl8_bsp_plane* planes;
|
|
||||||
i32* surfedges;
|
|
||||||
u32* vertex_lights;
|
|
||||||
pxl8_bsp_vertex* vertices;
|
|
||||||
u8* visdata;
|
|
||||||
f32* heightfield;
|
|
||||||
|
|
||||||
u32 lightdata_size;
|
|
||||||
u32 num_cell_portals;
|
|
||||||
u32 num_edges;
|
|
||||||
u32 num_faces;
|
|
||||||
u32 num_leafs;
|
|
||||||
u32 num_lightmaps;
|
|
||||||
u32 num_marksurfaces;
|
|
||||||
u32 num_models;
|
|
||||||
u32 num_nodes;
|
|
||||||
u32 num_planes;
|
|
||||||
u32 num_surfedges;
|
|
||||||
u32 num_vertex_lights;
|
|
||||||
u32 num_vertices;
|
|
||||||
u32 num_heightfield;
|
|
||||||
f32 heightfield_ox;
|
|
||||||
f32 heightfield_oz;
|
|
||||||
f32 heightfield_cell_size;
|
|
||||||
u16 heightfield_w;
|
|
||||||
u16 heightfield_h;
|
|
||||||
u32 visdata_size;
|
|
||||||
f32 bounds_min_x;
|
|
||||||
f32 bounds_min_z;
|
|
||||||
f32 bounds_max_x;
|
|
||||||
f32 bounds_max_z;
|
|
||||||
} pxl8_bsp;
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
extern "C" {
|
|
||||||
#endif
|
|
||||||
|
|
||||||
pxl8_bsp_pvs pxl8_bsp_decompress_pvs(const pxl8_bsp* bsp, i32 leaf);
|
|
||||||
void pxl8_bsp_destroy(pxl8_bsp* bsp);
|
|
||||||
u32 pxl8_bsp_face_count(const pxl8_bsp* bsp);
|
|
||||||
pxl8_vec3 pxl8_bsp_face_normal(const pxl8_bsp* bsp, u32 face_id);
|
|
||||||
void pxl8_bsp_face_set_material(pxl8_bsp* bsp, u32 face_id, u16 material_id);
|
|
||||||
i32 pxl8_bsp_find_leaf(const pxl8_bsp* bsp, pxl8_vec3 pos);
|
|
||||||
bool pxl8_bsp_is_leaf_visible(const pxl8_bsp* bsp, i32 leaf_from, i32 leaf_to);
|
|
||||||
pxl8_bsp_lightmap pxl8_bsp_lightmap_mapped(u8 width, u8 height, u32 offset);
|
|
||||||
pxl8_bsp_lightmap pxl8_bsp_lightmap_uniform(u8 r, u8 g, u8 b);
|
|
||||||
pxl8_result pxl8_bsp_load(const char* path, pxl8_bsp* bsp);
|
|
||||||
void pxl8_bsp_pvs_destroy(pxl8_bsp_pvs* pvs);
|
|
||||||
bool pxl8_bsp_pvs_is_visible(const pxl8_bsp_pvs* pvs, i32 leaf);
|
|
||||||
u8 pxl8_bsp_light_at(const pxl8_bsp* bsp, f32 x, f32 y, f32 z, u8 ambient);
|
|
||||||
pxl8_bsp_lightmap_sample pxl8_bsp_sample_lightmap(const pxl8_bsp* bsp, u32 face_idx, f32 u, f32 v);
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
@ -1,29 +0,0 @@
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include "pxl8_bsp.h"
|
|
||||||
#include "pxl8_gfx.h"
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
extern "C" {
|
|
||||||
#endif
|
|
||||||
|
|
||||||
typedef struct pxl8_bsp_render_state {
|
|
||||||
pxl8_gfx_material* materials;
|
|
||||||
u8* render_face_flags;
|
|
||||||
u32 num_materials;
|
|
||||||
u32 num_faces;
|
|
||||||
bool exterior;
|
|
||||||
} pxl8_bsp_render_state;
|
|
||||||
|
|
||||||
pxl8_bsp_render_state* pxl8_bsp_render_state_create(u32 num_faces);
|
|
||||||
void pxl8_bsp_render_state_destroy(pxl8_bsp_render_state* state);
|
|
||||||
|
|
||||||
void pxl8_bsp_render(pxl8_gfx* gfx, const pxl8_bsp* bsp,
|
|
||||||
pxl8_bsp_render_state* state,
|
|
||||||
const pxl8_gfx_draw_opts* opts);
|
|
||||||
void pxl8_bsp_set_material(pxl8_bsp_render_state* state, u16 material_id,
|
|
||||||
const pxl8_gfx_material* material);
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
136
src/core/pxl8.c
136
src/core/pxl8.c
|
|
@ -7,7 +7,7 @@
|
||||||
|
|
||||||
#include "pxl8_ase.h"
|
#include "pxl8_ase.h"
|
||||||
#include "pxl8_game.h"
|
#include "pxl8_game.h"
|
||||||
#include "pxl8_hal.h"
|
#include "pxl8_platform.h"
|
||||||
#include "pxl8_log.h"
|
#include "pxl8_log.h"
|
||||||
#include "pxl8_macros.h"
|
#include "pxl8_macros.h"
|
||||||
#include "pxl8_mem.h"
|
#include "pxl8_mem.h"
|
||||||
|
|
@ -16,14 +16,13 @@
|
||||||
#include "pxl8_script.h"
|
#include "pxl8_script.h"
|
||||||
#include "pxl8_sfx.h"
|
#include "pxl8_sfx.h"
|
||||||
#include "pxl8_sys.h"
|
#include "pxl8_sys.h"
|
||||||
#include "pxl8_world.h"
|
|
||||||
|
|
||||||
struct pxl8 {
|
struct pxl8 {
|
||||||
pxl8_cart* cart;
|
pxl8_cart* cart;
|
||||||
pxl8_game* game;
|
pxl8_game* game;
|
||||||
pxl8_repl* repl;
|
pxl8_repl* repl;
|
||||||
pxl8_log log;
|
pxl8_log log;
|
||||||
const pxl8_hal* hal;
|
const pxl8_platform* platform;
|
||||||
void* platform_data;
|
void* platform_data;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -36,19 +35,19 @@ static void pxl8_audio_event_callback(u8 event_type, u8 context_id, u8 note, f32
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
pxl8* pxl8_create(const pxl8_hal* hal) {
|
pxl8* pxl8_create(const pxl8_platform* platform) {
|
||||||
pxl8* sys = (pxl8*)pxl8_calloc(1, sizeof(pxl8));
|
pxl8* sys = (pxl8*)pxl8_calloc(1, sizeof(pxl8));
|
||||||
if (!sys) return NULL;
|
if (!sys) return NULL;
|
||||||
|
|
||||||
pxl8_log_init(&sys->log);
|
pxl8_log_init(&sys->log);
|
||||||
|
|
||||||
if (!hal) {
|
if (!platform) {
|
||||||
pxl8_error("hal cannot be null");
|
pxl8_error("platform cannot be null");
|
||||||
pxl8_free(sys);
|
pxl8_free(sys);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
sys->hal = hal;
|
sys->platform = platform;
|
||||||
|
|
||||||
sys->game = (pxl8_game*)pxl8_calloc(1, sizeof(pxl8_game));
|
sys->game = (pxl8_game*)pxl8_calloc(1, sizeof(pxl8_game));
|
||||||
if (!sys->game) {
|
if (!sys->game) {
|
||||||
|
|
@ -65,7 +64,7 @@ void pxl8_destroy(pxl8* sys) {
|
||||||
|
|
||||||
if (sys->game) pxl8_free(sys->game);
|
if (sys->game) pxl8_free(sys->game);
|
||||||
if (sys->cart) pxl8_cart_destroy(sys->cart);
|
if (sys->cart) pxl8_cart_destroy(sys->cart);
|
||||||
if (sys->hal && sys->platform_data) sys->hal->destroy(sys->platform_data);
|
if (sys->platform && sys->platform_data) sys->platform->destroy(sys->platform_data);
|
||||||
|
|
||||||
pxl8_free(sys);
|
pxl8_free(sys);
|
||||||
}
|
}
|
||||||
|
|
@ -227,42 +226,35 @@ pxl8_result pxl8_init(pxl8* sys, i32 argc, char* argv[]) {
|
||||||
pxl8_size window_size = pxl8_cart_get_window_size(sys->cart);
|
pxl8_size window_size = pxl8_cart_get_window_size(sys->cart);
|
||||||
pxl8_size render_size = pxl8_get_resolution_dimensions(resolution);
|
pxl8_size render_size = pxl8_get_resolution_dimensions(resolution);
|
||||||
|
|
||||||
sys->platform_data = sys->hal->create(render_size.w, render_size.h, window_title, window_size.w, window_size.h);
|
sys->platform_data = sys->platform->create(render_size.w, render_size.h, window_title, window_size.w, window_size.h);
|
||||||
if (!sys->platform_data) {
|
if (!sys->platform_data) {
|
||||||
pxl8_error("failed to create platform context");
|
pxl8_error("failed to create platform context");
|
||||||
return PXL8_ERROR_INITIALIZATION_FAILED;
|
return PXL8_ERROR_INITIALIZATION_FAILED;
|
||||||
}
|
}
|
||||||
|
|
||||||
game->gfx = pxl8_gfx_create(sys->hal, sys->platform_data, resolution);
|
game->gfx = pxl8_gfx_create(sys->platform, sys->platform_data, resolution);
|
||||||
if (!game->gfx) {
|
if (!game->gfx) {
|
||||||
pxl8_error("failed to create graphics context");
|
pxl8_error("failed to create graphics context");
|
||||||
return PXL8_ERROR_INITIALIZATION_FAILED;
|
return PXL8_ERROR_INITIALIZATION_FAILED;
|
||||||
}
|
}
|
||||||
|
|
||||||
game->mixer = pxl8_sfx_mixer_create(sys->hal);
|
game->mixer = pxl8_sfx_mixer_create(sys->platform);
|
||||||
if (!game->mixer) {
|
if (!game->mixer) {
|
||||||
pxl8_error("failed to create audio mixer");
|
pxl8_error("failed to create audio mixer");
|
||||||
return PXL8_ERROR_INITIALIZATION_FAILED;
|
return PXL8_ERROR_INITIALIZATION_FAILED;
|
||||||
}
|
}
|
||||||
|
|
||||||
pxl8_rng_seed(&game->rng, (u32)sys->hal->get_ticks());
|
pxl8_rng_seed(&game->rng, (u32)sys->platform->get_ticks());
|
||||||
|
|
||||||
game->world = pxl8_world_create();
|
if (game->hooks.init) {
|
||||||
if (!game->world) {
|
pxl8_result hook_result = game->hooks.init(game, game->hooks.userdata);
|
||||||
pxl8_error("failed to create world");
|
if (hook_result != PXL8_OK) {
|
||||||
return PXL8_ERROR_INITIALIZATION_FAILED;
|
return hook_result;
|
||||||
}
|
}
|
||||||
|
|
||||||
pxl8_net_config net_cfg = { .address = "127.0.0.1", .port = 7777 };
|
|
||||||
game->net = pxl8_net_create(&net_cfg);
|
|
||||||
if (game->net) {
|
|
||||||
pxl8_net_set_chunk_cache(game->net, pxl8_world_get_chunk_cache(game->world));
|
|
||||||
pxl8_net_set_world(game->net, game->world);
|
|
||||||
pxl8_net_connect(game->net);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef NDEBUG
|
#ifndef NDEBUG
|
||||||
game->debug_stats = true;
|
game->debug_stats = false;
|
||||||
game->debug_replay = pxl8_replay_create_buffer(60, 60);
|
game->debug_replay = pxl8_replay_create_buffer(60, 60);
|
||||||
pxl8_sfx_mixer_set_event_callback(game->mixer, pxl8_audio_event_callback, game);
|
pxl8_sfx_mixer_set_event_callback(game->mixer, pxl8_audio_event_callback, game);
|
||||||
#endif
|
#endif
|
||||||
|
|
@ -289,18 +281,9 @@ pxl8_result pxl8_init(pxl8* sys, i32 argc, char* argv[]) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
game->last_time = sys->hal->get_ticks();
|
game->last_time = sys->platform->get_ticks();
|
||||||
game->running = true;
|
game->running = true;
|
||||||
|
|
||||||
#ifdef PXL8_ASYNC_THREADS
|
|
||||||
if (game->net) {
|
|
||||||
pxl8_net_start_thread(game->net);
|
|
||||||
}
|
|
||||||
if (game->world) {
|
|
||||||
pxl8_world_start_sim_thread(game->world, game->net);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return PXL8_OK;
|
return PXL8_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -310,7 +293,7 @@ pxl8_result pxl8_update(pxl8* sys) {
|
||||||
}
|
}
|
||||||
|
|
||||||
pxl8_game* game = sys->game;
|
pxl8_game* game = sys->game;
|
||||||
u64 current_time = sys->hal->get_ticks();
|
u64 current_time = sys->platform->get_ticks();
|
||||||
f32 dt = (f32)(current_time - game->last_time) / 1000000000.0f;
|
f32 dt = (f32)(current_time - game->last_time) / 1000000000.0f;
|
||||||
|
|
||||||
game->last_time = current_time;
|
game->last_time = current_time;
|
||||||
|
|
@ -364,16 +347,9 @@ pxl8_result pxl8_update(pxl8* sys) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef PXL8_ASYNC_THREADS
|
if (game->hooks.update) {
|
||||||
pxl8_net_update(game->net, dt);
|
game->hooks.update(game, dt, game->hooks.userdata);
|
||||||
#else
|
|
||||||
if (game->net) {
|
|
||||||
while (pxl8_net_poll(game->net)) {}
|
|
||||||
pxl8_net_update(game->net, dt);
|
|
||||||
pxl8_world_sync(game->world, game->net);
|
|
||||||
}
|
}
|
||||||
pxl8_world_update(game->world, dt);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
pxl8_gfx_update(game->gfx, dt);
|
pxl8_gfx_update(game->gfx, dt);
|
||||||
pxl8_sfx_mixer_process(game->mixer);
|
pxl8_sfx_mixer_process(game->mixer);
|
||||||
|
|
@ -412,30 +388,10 @@ pxl8_result pxl8_frame(pxl8* sys) {
|
||||||
|
|
||||||
if (game->debug_stats) {
|
if (game->debug_stats) {
|
||||||
const pxl8_gfx_stats* stats = pxl8_gfx_get_stats(game->gfx);
|
const pxl8_gfx_stats* stats = pxl8_gfx_get_stats(game->gfx);
|
||||||
char buf[64];
|
|
||||||
i32 y = 4;
|
|
||||||
|
|
||||||
if (stats) {
|
if (stats) {
|
||||||
|
char buf[32];
|
||||||
snprintf(buf, sizeof(buf), "FPS: %.0f", stats->fps);
|
snprintf(buf, sizeof(buf), "FPS: %.0f", stats->fps);
|
||||||
pxl8_2d_text(game->gfx, buf, 4, y, 15);
|
pxl8_2d_text(game->gfx, buf, 4, 4, 15);
|
||||||
y += 10;
|
|
||||||
|
|
||||||
pxl8_sim_entity* player = pxl8_world_local_player(game->world);
|
|
||||||
if (player) {
|
|
||||||
snprintf(buf, sizeof(buf), "Pos: %.0f,%.0f,%.0f",
|
|
||||||
player->pos.x, player->pos.y, player->pos.z);
|
|
||||||
pxl8_2d_text(game->gfx, buf, 4, y, 15);
|
|
||||||
y += 10;
|
|
||||||
}
|
|
||||||
|
|
||||||
snprintf(buf, sizeof(buf), "Draw: %llu Tri: %llu",
|
|
||||||
(unsigned long long)stats->draw_calls,
|
|
||||||
(unsigned long long)stats->triangles);
|
|
||||||
pxl8_2d_text(game->gfx, buf, 4, y, 15);
|
|
||||||
y += 10;
|
|
||||||
|
|
||||||
snprintf(buf, sizeof(buf), "Raster: %.2fms", stats->raster_ms);
|
|
||||||
pxl8_2d_text(game->gfx, buf, 4, y, 15);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -478,14 +434,9 @@ void pxl8_quit(pxl8* sys) {
|
||||||
|
|
||||||
pxl8_info("Shutting down");
|
pxl8_info("Shutting down");
|
||||||
|
|
||||||
#ifdef PXL8_ASYNC_THREADS
|
if (game->hooks.quit) {
|
||||||
if (game->world) {
|
game->hooks.quit(game, game->hooks.userdata);
|
||||||
pxl8_world_stop_sim_thread(game->world);
|
|
||||||
}
|
}
|
||||||
if (game->net) {
|
|
||||||
pxl8_net_stop_thread(game->net);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (sys->cart) {
|
if (sys->cart) {
|
||||||
pxl8_cart_unmount(sys->cart);
|
pxl8_cart_unmount(sys->cart);
|
||||||
|
|
@ -495,9 +446,6 @@ void pxl8_quit(pxl8* sys) {
|
||||||
pxl8_replay_destroy(game->debug_replay);
|
pxl8_replay_destroy(game->debug_replay);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (game->net) pxl8_net_destroy(game->net);
|
|
||||||
if (game->world) pxl8_world_destroy(game->world);
|
|
||||||
|
|
||||||
pxl8_sfx_mixer_destroy(game->mixer);
|
pxl8_sfx_mixer_destroy(game->mixer);
|
||||||
pxl8_gfx_destroy(game->gfx);
|
pxl8_gfx_destroy(game->gfx);
|
||||||
pxl8_script_destroy(game->script);
|
pxl8_script_destroy(game->script);
|
||||||
|
|
@ -517,16 +465,16 @@ void pxl8_set_running(pxl8* sys, bool running) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pxl8_world* pxl8_get_world(pxl8* sys) {
|
|
||||||
return (sys && sys->game) ? sys->game->world : NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
f32 pxl8_get_fps(const pxl8* sys) {
|
f32 pxl8_get_fps(const pxl8* sys) {
|
||||||
if (!sys || !sys->game) return 0.0f;
|
if (!sys || !sys->game) return 0.0f;
|
||||||
const pxl8_gfx_stats* stats = pxl8_gfx_get_stats(sys->game->gfx);
|
const pxl8_gfx_stats* stats = pxl8_gfx_get_stats(sys->game->gfx);
|
||||||
return stats ? stats->fps : 0.0f;
|
return stats ? stats->fps : 0.0f;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pxl8_game* pxl8_get_game(pxl8* sys) {
|
||||||
|
return sys ? sys->game : NULL;
|
||||||
|
}
|
||||||
|
|
||||||
pxl8_gfx* pxl8_get_gfx(const pxl8* sys) {
|
pxl8_gfx* pxl8_get_gfx(const pxl8* sys) {
|
||||||
return (sys && sys->game) ? sys->game->gfx : NULL;
|
return (sys && sys->game) ? sys->game->gfx : NULL;
|
||||||
}
|
}
|
||||||
|
|
@ -535,27 +483,23 @@ pxl8_input_state* pxl8_get_input(const pxl8* sys) {
|
||||||
return (sys && sys->game) ? &sys->game->input : NULL;
|
return (sys && sys->game) ? &sys->game->input : NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
pxl8_net* pxl8_get_net(const pxl8* sys) {
|
|
||||||
return (sys && sys->game) ? sys->game->net : NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
pxl8_sfx_mixer* pxl8_get_sfx_mixer(const pxl8* sys) {
|
pxl8_sfx_mixer* pxl8_get_sfx_mixer(const pxl8* sys) {
|
||||||
return (sys && sys->game) ? sys->game->mixer : NULL;
|
return (sys && sys->game) ? sys->game->mixer : NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
void pxl8_center_cursor(pxl8* sys) {
|
void pxl8_center_cursor(pxl8* sys) {
|
||||||
if (!sys || !sys->hal || !sys->hal->center_cursor) return;
|
if (!sys || !sys->platform || !sys->platform->center_cursor) return;
|
||||||
sys->hal->center_cursor(sys->platform_data);
|
sys->platform->center_cursor(sys->platform_data);
|
||||||
}
|
}
|
||||||
|
|
||||||
void pxl8_set_cursor(pxl8* sys, pxl8_cursor cursor) {
|
void pxl8_set_cursor(pxl8* sys, pxl8_cursor cursor) {
|
||||||
if (!sys || !sys->hal || !sys->hal->set_cursor) return;
|
if (!sys || !sys->platform || !sys->platform->set_cursor) return;
|
||||||
sys->hal->set_cursor(sys->platform_data, cursor);
|
sys->platform->set_cursor(sys->platform_data, cursor);
|
||||||
}
|
}
|
||||||
|
|
||||||
void pxl8_set_relative_mouse_mode(pxl8* sys, bool enabled) {
|
void pxl8_set_relative_mouse_mode(pxl8* sys, bool enabled) {
|
||||||
if (!sys || !sys->hal || !sys->hal->set_relative_mouse_mode) return;
|
if (!sys || !sys->platform || !sys->platform->set_relative_mouse_mode) return;
|
||||||
sys->hal->set_relative_mouse_mode(sys->platform_data, enabled);
|
sys->platform->set_relative_mouse_mode(sys->platform_data, enabled);
|
||||||
if (sys->game) {
|
if (sys->game) {
|
||||||
sys->game->input.mouse_relative_mode = enabled;
|
sys->game->input.mouse_relative_mode = enabled;
|
||||||
}
|
}
|
||||||
|
|
@ -573,3 +517,13 @@ pxl8_size pxl8_get_resolution_dimensions(pxl8_resolution resolution) {
|
||||||
default: return (pxl8_size){640, 360};
|
default: return (pxl8_size){640, 360};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
__attribute__((weak)) void pxl8_register_game(pxl8* sys) {
|
||||||
|
(void)sys;
|
||||||
|
}
|
||||||
|
|
||||||
|
void pxl8_set_game_hooks(pxl8* sys, pxl8_game_hooks hooks) {
|
||||||
|
if (sys && sys->game) {
|
||||||
|
sys->game->hooks = hooks;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,15 +1,22 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "pxl8_gfx.h"
|
#include "pxl8_gfx.h"
|
||||||
#include "pxl8_net.h"
|
|
||||||
#include "pxl8_rng.h"
|
#include "pxl8_rng.h"
|
||||||
#include "pxl8_script.h"
|
#include "pxl8_script.h"
|
||||||
#include "pxl8_sfx.h"
|
#include "pxl8_sfx.h"
|
||||||
#include "pxl8_types.h"
|
#include "pxl8_types.h"
|
||||||
#include "pxl8_world.h"
|
|
||||||
|
|
||||||
typedef struct pxl8_replay pxl8_replay;
|
typedef struct pxl8_replay pxl8_replay;
|
||||||
|
|
||||||
|
typedef struct pxl8_game pxl8_game;
|
||||||
|
|
||||||
|
typedef struct pxl8_game_hooks {
|
||||||
|
pxl8_result (*init)(pxl8_game* game, void* userdata);
|
||||||
|
void (*update)(pxl8_game* game, f32 dt, void* userdata);
|
||||||
|
void (*quit)(pxl8_game* game, void* userdata);
|
||||||
|
void* userdata;
|
||||||
|
} pxl8_game_hooks;
|
||||||
|
|
||||||
typedef struct pxl8_game {
|
typedef struct pxl8_game {
|
||||||
#ifndef NDEBUG
|
#ifndef NDEBUG
|
||||||
pxl8_replay* debug_replay;
|
pxl8_replay* debug_replay;
|
||||||
|
|
@ -19,10 +26,10 @@ typedef struct pxl8_game {
|
||||||
f32 dt;
|
f32 dt;
|
||||||
i32 frame_count;
|
i32 frame_count;
|
||||||
pxl8_gfx* gfx;
|
pxl8_gfx* gfx;
|
||||||
|
pxl8_game_hooks hooks;
|
||||||
pxl8_input_state input;
|
pxl8_input_state input;
|
||||||
u64 last_time;
|
u64 last_time;
|
||||||
pxl8_sfx_mixer* mixer;
|
pxl8_sfx_mixer* mixer;
|
||||||
pxl8_net* net;
|
|
||||||
pxl8_input_state prev_input;
|
pxl8_input_state prev_input;
|
||||||
bool repl_mode;
|
bool repl_mode;
|
||||||
bool repl_started;
|
bool repl_started;
|
||||||
|
|
@ -32,5 +39,5 @@ typedef struct pxl8_game {
|
||||||
bool script_loaded;
|
bool script_loaded;
|
||||||
char script_path[256];
|
char script_path[256];
|
||||||
f32 time;
|
f32 time;
|
||||||
pxl8_world* world;
|
void* userdata;
|
||||||
} pxl8_game;
|
} pxl8_game;
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,9 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include "pxl8_game.h"
|
||||||
#include "pxl8_gfx.h"
|
#include "pxl8_gfx.h"
|
||||||
#include "pxl8_hal.h"
|
#include "pxl8_platform.h"
|
||||||
#include "pxl8_io.h"
|
#include "pxl8_io.h"
|
||||||
#include "pxl8_net.h"
|
|
||||||
#include "pxl8_sfx.h"
|
#include "pxl8_sfx.h"
|
||||||
#include "pxl8_types.h"
|
#include "pxl8_types.h"
|
||||||
|
|
||||||
|
|
@ -13,7 +13,7 @@ typedef struct pxl8 pxl8;
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
pxl8* pxl8_create(const pxl8_hal* hal);
|
pxl8* pxl8_create(const pxl8_platform* platform);
|
||||||
void pxl8_destroy(pxl8* sys);
|
void pxl8_destroy(pxl8* sys);
|
||||||
|
|
||||||
pxl8_result pxl8_init(pxl8* sys, i32 argc, char* argv[]);
|
pxl8_result pxl8_init(pxl8* sys, i32 argc, char* argv[]);
|
||||||
|
|
@ -22,15 +22,18 @@ pxl8_result pxl8_frame(pxl8* sys);
|
||||||
void pxl8_quit(pxl8* sys);
|
void pxl8_quit(pxl8* sys);
|
||||||
|
|
||||||
f32 pxl8_get_fps(const pxl8* sys);
|
f32 pxl8_get_fps(const pxl8* sys);
|
||||||
|
pxl8_game* pxl8_get_game(pxl8* sys);
|
||||||
pxl8_gfx* pxl8_get_gfx(const pxl8* sys);
|
pxl8_gfx* pxl8_get_gfx(const pxl8* sys);
|
||||||
pxl8_input_state* pxl8_get_input(const pxl8* sys);
|
pxl8_input_state* pxl8_get_input(const pxl8* sys);
|
||||||
pxl8_net* pxl8_get_net(const pxl8* sys);
|
|
||||||
pxl8_size pxl8_get_resolution_dimensions(pxl8_resolution resolution);
|
pxl8_size pxl8_get_resolution_dimensions(pxl8_resolution resolution);
|
||||||
pxl8_sfx_mixer* pxl8_get_sfx_mixer(const pxl8* sys);
|
pxl8_sfx_mixer* pxl8_get_sfx_mixer(const pxl8* sys);
|
||||||
bool pxl8_is_running(const pxl8* sys);
|
bool pxl8_is_running(const pxl8* sys);
|
||||||
|
|
||||||
|
void pxl8_register_game(pxl8* sys);
|
||||||
|
|
||||||
void pxl8_center_cursor(pxl8* sys);
|
void pxl8_center_cursor(pxl8* sys);
|
||||||
void pxl8_set_cursor(pxl8* sys, pxl8_cursor cursor);
|
void pxl8_set_cursor(pxl8* sys, pxl8_cursor cursor);
|
||||||
|
void pxl8_set_game_hooks(pxl8* sys, pxl8_game_hooks hooks);
|
||||||
void pxl8_set_relative_mouse_mode(pxl8* sys, bool enabled);
|
void pxl8_set_relative_mouse_mode(pxl8* sys, bool enabled);
|
||||||
void pxl8_set_running(pxl8* sys, bool running);
|
void pxl8_set_running(pxl8* sys, bool running);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,41 +0,0 @@
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include "pxl8_math.h"
|
|
||||||
#include "pxl8_types.h"
|
|
||||||
|
|
||||||
typedef enum pxl8_3d_camera_mode {
|
|
||||||
PXL8_3D_CAMERA_ORTHO,
|
|
||||||
PXL8_3D_CAMERA_PERSPECTIVE
|
|
||||||
} pxl8_3d_camera_mode;
|
|
||||||
|
|
||||||
typedef struct pxl8_3d_camera pxl8_3d_camera;
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
extern "C" {
|
|
||||||
#endif
|
|
||||||
|
|
||||||
pxl8_3d_camera* pxl8_3d_camera_create(void);
|
|
||||||
void pxl8_3d_camera_destroy(pxl8_3d_camera* cam);
|
|
||||||
|
|
||||||
void pxl8_3d_camera_lookat(pxl8_3d_camera* cam, pxl8_vec3 eye, pxl8_vec3 target, pxl8_vec3 up);
|
|
||||||
void pxl8_3d_camera_set_ortho(pxl8_3d_camera* cam, f32 left, f32 right, f32 bottom, f32 top, f32 near, f32 far);
|
|
||||||
void pxl8_3d_camera_set_perspective(pxl8_3d_camera* cam, f32 fov, f32 aspect, f32 near, f32 far);
|
|
||||||
void pxl8_3d_camera_set_position(pxl8_3d_camera* cam, pxl8_vec3 pos);
|
|
||||||
void pxl8_3d_camera_set_rotation(pxl8_3d_camera* cam, f32 pitch, f32 yaw, f32 roll);
|
|
||||||
|
|
||||||
pxl8_vec3 pxl8_3d_camera_get_forward(const pxl8_3d_camera* cam);
|
|
||||||
pxl8_vec3 pxl8_3d_camera_get_position(const pxl8_3d_camera* cam);
|
|
||||||
pxl8_mat4 pxl8_3d_camera_get_projection(const pxl8_3d_camera* cam);
|
|
||||||
pxl8_vec3 pxl8_3d_camera_get_right(const pxl8_3d_camera* cam);
|
|
||||||
pxl8_vec3 pxl8_3d_camera_get_up(const pxl8_3d_camera* cam);
|
|
||||||
pxl8_mat4 pxl8_3d_camera_get_view(const pxl8_3d_camera* cam);
|
|
||||||
|
|
||||||
void pxl8_3d_camera_blend(pxl8_3d_camera* dest, const pxl8_3d_camera* a, const pxl8_3d_camera* b, f32 t);
|
|
||||||
void pxl8_3d_camera_follow(pxl8_3d_camera* cam, pxl8_vec3 target, pxl8_vec3 offset, f32 smoothing, f32 dt);
|
|
||||||
pxl8_projected_point pxl8_3d_camera_world_to_screen(const pxl8_3d_camera* cam, pxl8_vec3 world_pos, u32 screen_width, u32 screen_height);
|
|
||||||
void pxl8_3d_camera_shake(pxl8_3d_camera* cam, f32 intensity, f32 duration);
|
|
||||||
void pxl8_3d_camera_update(pxl8_3d_camera* cam, f32 dt);
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
@ -1,8 +1,8 @@
|
||||||
#include "pxl8_render.h"
|
#include "pxl8_blit3d.h"
|
||||||
#include "pxl8_atlas.h"
|
#include "pxl8_atlas.h"
|
||||||
#include "pxl8_colormap.h"
|
#include "pxl8_colormap.h"
|
||||||
#include "pxl8_dither.h"
|
#include "pxl8_dither.h"
|
||||||
#include "pxl8_hal.h"
|
#include "pxl8_platform.h"
|
||||||
#include "pxl8_log.h"
|
#include "pxl8_log.h"
|
||||||
#include "pxl8_mem.h"
|
#include "pxl8_mem.h"
|
||||||
#include "pxl8_mesh.h"
|
#include "pxl8_mesh.h"
|
||||||
|
|
@ -794,7 +794,7 @@ typedef struct {
|
||||||
bool active;
|
bool active;
|
||||||
} texture_slot;
|
} texture_slot;
|
||||||
|
|
||||||
struct pxl8_renderer {
|
struct pxl8_blit3d {
|
||||||
u32 width;
|
u32 width;
|
||||||
u32 height;
|
u32 height;
|
||||||
u8* stencil;
|
u8* stencil;
|
||||||
|
|
@ -828,8 +828,8 @@ struct pxl8_gfx_cmdbuf {
|
||||||
u32 count;
|
u32 count;
|
||||||
};
|
};
|
||||||
|
|
||||||
pxl8_renderer* pxl8_renderer_create(u32 width, u32 height) {
|
pxl8_blit3d* pxl8_blit3d_create(u32 width, u32 height) {
|
||||||
pxl8_renderer* r = pxl8_calloc(1, sizeof(pxl8_renderer));
|
pxl8_blit3d* r = pxl8_calloc(1, sizeof(pxl8_blit3d));
|
||||||
r->width = width;
|
r->width = width;
|
||||||
r->height = height;
|
r->height = height;
|
||||||
r->stencil = pxl8_calloc(width * height, 1);
|
r->stencil = pxl8_calloc(width * height, 1);
|
||||||
|
|
@ -840,7 +840,7 @@ pxl8_renderer* pxl8_renderer_create(u32 width, u32 height) {
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
void pxl8_renderer_destroy(pxl8_renderer* r) {
|
void pxl8_blit3d_destroy(pxl8_blit3d* r) {
|
||||||
if (!r) return;
|
if (!r) return;
|
||||||
for (u32 i = 0; i < PXL8_GFX_MAX_TEXTURES; i++) {
|
for (u32 i = 0; i < PXL8_GFX_MAX_TEXTURES; i++) {
|
||||||
if (r->textures[i].data) pxl8_free(r->textures[i].data);
|
if (r->textures[i].data) pxl8_free(r->textures[i].data);
|
||||||
|
|
@ -852,7 +852,7 @@ void pxl8_renderer_destroy(pxl8_renderer* r) {
|
||||||
pxl8_free(r);
|
pxl8_free(r);
|
||||||
}
|
}
|
||||||
|
|
||||||
void pxl8_renderer_update_stats(pxl8_renderer* r, f32 dt) {
|
void pxl8_blit3d_update_stats(pxl8_blit3d* r, f32 dt) {
|
||||||
if (!r) return;
|
if (!r) return;
|
||||||
|
|
||||||
r->stats.dt_accumulator += dt;
|
r->stats.dt_accumulator += dt;
|
||||||
|
|
@ -870,7 +870,7 @@ void pxl8_renderer_update_stats(pxl8_renderer* r, f32 dt) {
|
||||||
r->stats.triangles = 0;
|
r->stats.triangles = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
pxl8_gfx_stats* pxl8_renderer_get_stats(pxl8_renderer* r) {
|
pxl8_gfx_stats* pxl8_blit3d_get_stats(pxl8_blit3d* r) {
|
||||||
return r ? &r->stats : NULL;
|
return r ? &r->stats : NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -882,7 +882,7 @@ static u32 texture_byte_size(pxl8_gfx_texture_format fmt, u32 w, u32 h) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
pxl8_gfx_texture pxl8_create_texture(pxl8_renderer* r, const pxl8_gfx_texture_desc* desc) {
|
pxl8_gfx_texture pxl8_create_texture(pxl8_blit3d* r, const pxl8_gfx_texture_desc* desc) {
|
||||||
for (u32 i = 0; i < PXL8_GFX_MAX_TEXTURES; i++) {
|
for (u32 i = 0; i < PXL8_GFX_MAX_TEXTURES; i++) {
|
||||||
if (!r->textures[i].active) {
|
if (!r->textures[i].active) {
|
||||||
texture_slot* s = &r->textures[i];
|
texture_slot* s = &r->textures[i];
|
||||||
|
|
@ -906,7 +906,7 @@ pxl8_gfx_texture pxl8_create_texture(pxl8_renderer* r, const pxl8_gfx_texture_de
|
||||||
return (pxl8_gfx_texture){ PXL8_GFX_INVALID_ID };
|
return (pxl8_gfx_texture){ PXL8_GFX_INVALID_ID };
|
||||||
}
|
}
|
||||||
|
|
||||||
pxl8_gfx_buffer pxl8_create_buffer(pxl8_renderer* r, const pxl8_gfx_buffer_desc* desc) {
|
pxl8_gfx_buffer pxl8_create_buffer(pxl8_blit3d* r, const pxl8_gfx_buffer_desc* desc) {
|
||||||
for (u32 i = 0; i < PXL8_GFX_MAX_BUFFERS; i++) {
|
for (u32 i = 0; i < PXL8_GFX_MAX_BUFFERS; i++) {
|
||||||
if (!r->buffers[i].active) {
|
if (!r->buffers[i].active) {
|
||||||
buffer_slot* s = &r->buffers[i];
|
buffer_slot* s = &r->buffers[i];
|
||||||
|
|
@ -933,7 +933,7 @@ pxl8_gfx_buffer pxl8_create_buffer(pxl8_renderer* r, const pxl8_gfx_buffer_desc*
|
||||||
return (pxl8_gfx_buffer){ PXL8_GFX_INVALID_ID };
|
return (pxl8_gfx_buffer){ PXL8_GFX_INVALID_ID };
|
||||||
}
|
}
|
||||||
|
|
||||||
pxl8_gfx_pipeline pxl8_create_pipeline(pxl8_renderer* r, const pxl8_gfx_pipeline_desc* desc) {
|
pxl8_gfx_pipeline pxl8_create_pipeline(pxl8_blit3d* r, const pxl8_gfx_pipeline_desc* desc) {
|
||||||
u32 hash = pipeline_desc_hash(desc);
|
u32 hash = pipeline_desc_hash(desc);
|
||||||
u32 bucket = hash & (PXL8_PIPELINE_CACHE_SIZE - 1);
|
u32 bucket = hash & (PXL8_PIPELINE_CACHE_SIZE - 1);
|
||||||
pipeline_cache_entry* ce = &r->pipeline_cache[bucket];
|
pipeline_cache_entry* ce = &r->pipeline_cache[bucket];
|
||||||
|
|
@ -974,7 +974,7 @@ pxl8_gfx_pipeline pxl8_create_pipeline(pxl8_renderer* r, const pxl8_gfx_pipeline
|
||||||
return (pxl8_gfx_pipeline){ PXL8_GFX_INVALID_ID };
|
return (pxl8_gfx_pipeline){ PXL8_GFX_INVALID_ID };
|
||||||
}
|
}
|
||||||
|
|
||||||
pxl8_gfx_bindings pxl8_create_bindings(pxl8_renderer* r, const pxl8_gfx_bindings_desc* desc) {
|
pxl8_gfx_bindings pxl8_create_bindings(pxl8_blit3d* r, const pxl8_gfx_bindings_desc* desc) {
|
||||||
for (u32 i = 0; i < PXL8_GFX_MAX_BINDINGS; i++) {
|
for (u32 i = 0; i < PXL8_GFX_MAX_BINDINGS; i++) {
|
||||||
if (!r->bindings[i].active) {
|
if (!r->bindings[i].active) {
|
||||||
bindings_slot* s = &r->bindings[i];
|
bindings_slot* s = &r->bindings[i];
|
||||||
|
|
@ -988,7 +988,7 @@ pxl8_gfx_bindings pxl8_create_bindings(pxl8_renderer* r, const pxl8_gfx_bindings
|
||||||
return (pxl8_gfx_bindings){ PXL8_GFX_INVALID_ID };
|
return (pxl8_gfx_bindings){ PXL8_GFX_INVALID_ID };
|
||||||
}
|
}
|
||||||
|
|
||||||
pxl8_gfx_pass pxl8_create_pass(pxl8_renderer* r, const pxl8_gfx_pass_desc* desc) {
|
pxl8_gfx_pass pxl8_create_pass(pxl8_blit3d* r, const pxl8_gfx_pass_desc* desc) {
|
||||||
for (u32 i = 0; i < PXL8_GFX_MAX_PASSES; i++) {
|
for (u32 i = 0; i < PXL8_GFX_MAX_PASSES; i++) {
|
||||||
if (!r->passes[i].active) {
|
if (!r->passes[i].active) {
|
||||||
pass_slot* s = &r->passes[i];
|
pass_slot* s = &r->passes[i];
|
||||||
|
|
@ -1022,7 +1022,7 @@ pxl8_gfx_pass pxl8_create_pass(pxl8_renderer* r, const pxl8_gfx_pass_desc* desc)
|
||||||
r->bindings[SLOT_INDEX((h).id)].active && \
|
r->bindings[SLOT_INDEX((h).id)].active && \
|
||||||
r->bindings[SLOT_INDEX((h).id)].generation == SLOT_GEN((h).id))
|
r->bindings[SLOT_INDEX((h).id)].generation == SLOT_GEN((h).id))
|
||||||
|
|
||||||
void pxl8_destroy_texture(pxl8_renderer* r, pxl8_gfx_texture tex) {
|
void pxl8_destroy_texture(pxl8_blit3d* r, pxl8_gfx_texture tex) {
|
||||||
if (!VALID_TEX(r, tex)) return;
|
if (!VALID_TEX(r, tex)) return;
|
||||||
texture_slot* s = &r->textures[SLOT_INDEX(tex.id)];
|
texture_slot* s = &r->textures[SLOT_INDEX(tex.id)];
|
||||||
pxl8_free(s->data);
|
pxl8_free(s->data);
|
||||||
|
|
@ -1030,7 +1030,7 @@ void pxl8_destroy_texture(pxl8_renderer* r, pxl8_gfx_texture tex) {
|
||||||
s->active = false;
|
s->active = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void pxl8_destroy_buffer(pxl8_renderer* r, pxl8_gfx_buffer buf) {
|
void pxl8_destroy_buffer(pxl8_blit3d* r, pxl8_gfx_buffer buf) {
|
||||||
if (!VALID_BUF(r, buf)) return;
|
if (!VALID_BUF(r, buf)) return;
|
||||||
buffer_slot* s = &r->buffers[SLOT_INDEX(buf.id)];
|
buffer_slot* s = &r->buffers[SLOT_INDEX(buf.id)];
|
||||||
pxl8_free(s->data);
|
pxl8_free(s->data);
|
||||||
|
|
@ -1038,7 +1038,7 @@ void pxl8_destroy_buffer(pxl8_renderer* r, pxl8_gfx_buffer buf) {
|
||||||
s->active = false;
|
s->active = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void pxl8_destroy_pipeline(pxl8_renderer* r, pxl8_gfx_pipeline pip) {
|
void pxl8_destroy_pipeline(pxl8_blit3d* r, pxl8_gfx_pipeline pip) {
|
||||||
u32 idx = SLOT_INDEX(pip.id);
|
u32 idx = SLOT_INDEX(pip.id);
|
||||||
if (idx < PXL8_GFX_MAX_PIPELINES && r->pipelines[idx].generation == SLOT_GEN(pip.id)) {
|
if (idx < PXL8_GFX_MAX_PIPELINES && r->pipelines[idx].generation == SLOT_GEN(pip.id)) {
|
||||||
if (!r->pipelines[idx].cached)
|
if (!r->pipelines[idx].cached)
|
||||||
|
|
@ -1046,28 +1046,28 @@ void pxl8_destroy_pipeline(pxl8_renderer* r, pxl8_gfx_pipeline pip) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void pxl8_destroy_bindings(pxl8_renderer* r, pxl8_gfx_bindings bnd) {
|
void pxl8_destroy_bindings(pxl8_blit3d* r, pxl8_gfx_bindings bnd) {
|
||||||
u32 idx = SLOT_INDEX(bnd.id);
|
u32 idx = SLOT_INDEX(bnd.id);
|
||||||
if (idx < PXL8_GFX_MAX_BINDINGS && r->bindings[idx].generation == SLOT_GEN(bnd.id)) {
|
if (idx < PXL8_GFX_MAX_BINDINGS && r->bindings[idx].generation == SLOT_GEN(bnd.id)) {
|
||||||
r->bindings[idx].active = false;
|
r->bindings[idx].active = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void pxl8_destroy_pass(pxl8_renderer* r, pxl8_gfx_pass pass) {
|
void pxl8_destroy_pass(pxl8_blit3d* r, pxl8_gfx_pass pass) {
|
||||||
u32 idx = SLOT_INDEX(pass.id);
|
u32 idx = SLOT_INDEX(pass.id);
|
||||||
if (idx < PXL8_GFX_MAX_PASSES && r->passes[idx].generation == SLOT_GEN(pass.id)) {
|
if (idx < PXL8_GFX_MAX_PASSES && r->passes[idx].generation == SLOT_GEN(pass.id)) {
|
||||||
r->passes[idx].active = false;
|
r->passes[idx].active = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void pxl8_update_buffer(pxl8_renderer* r, pxl8_gfx_buffer buf, const pxl8_gfx_range* data) {
|
void pxl8_update_buffer(pxl8_blit3d* r, pxl8_gfx_buffer buf, const pxl8_gfx_range* data) {
|
||||||
if (!VALID_BUF(r, buf)) return;
|
if (!VALID_BUF(r, buf)) return;
|
||||||
buffer_slot* s = &r->buffers[SLOT_INDEX(buf.id)];
|
buffer_slot* s = &r->buffers[SLOT_INDEX(buf.id)];
|
||||||
u32 copy_size = data->size < s->size ? data->size : s->size;
|
u32 copy_size = data->size < s->size ? data->size : s->size;
|
||||||
memcpy(s->data, data->ptr, copy_size);
|
memcpy(s->data, data->ptr, copy_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
i32 pxl8_append_buffer(pxl8_renderer* r, pxl8_gfx_buffer buf, const pxl8_gfx_range* data) {
|
i32 pxl8_append_buffer(pxl8_blit3d* r, pxl8_gfx_buffer buf, const pxl8_gfx_range* data) {
|
||||||
if (!VALID_BUF(r, buf)) return -1;
|
if (!VALID_BUF(r, buf)) return -1;
|
||||||
buffer_slot* s = &r->buffers[SLOT_INDEX(buf.id)];
|
buffer_slot* s = &r->buffers[SLOT_INDEX(buf.id)];
|
||||||
if (s->append_pos + data->size > s->size) return -1;
|
if (s->append_pos + data->size > s->size) return -1;
|
||||||
|
|
@ -1077,7 +1077,7 @@ i32 pxl8_append_buffer(pxl8_renderer* r, pxl8_gfx_buffer buf, const pxl8_gfx_ran
|
||||||
return offset;
|
return offset;
|
||||||
}
|
}
|
||||||
|
|
||||||
void pxl8_update_texture(pxl8_renderer* r, pxl8_gfx_texture tex, const pxl8_gfx_range* data, u32 x, u32 y, u32 w, u32 h) {
|
void pxl8_update_texture(pxl8_blit3d* r, pxl8_gfx_texture tex, const pxl8_gfx_range* data, u32 x, u32 y, u32 w, u32 h) {
|
||||||
if (!VALID_TEX(r, tex)) return;
|
if (!VALID_TEX(r, tex)) return;
|
||||||
texture_slot* s = &r->textures[SLOT_INDEX(tex.id)];
|
texture_slot* s = &r->textures[SLOT_INDEX(tex.id)];
|
||||||
u32 bpp = (s->format == PXL8_GFX_FORMAT_INDEXED8) ? 1 :
|
u32 bpp = (s->format == PXL8_GFX_FORMAT_INDEXED8) ? 1 :
|
||||||
|
|
@ -1091,17 +1091,17 @@ void pxl8_update_texture(pxl8_renderer* r, pxl8_gfx_texture tex, const pxl8_gfx_
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void* pxl8_texture_get_data(pxl8_renderer* r, pxl8_gfx_texture tex) {
|
void* pxl8_texture_get_data(pxl8_blit3d* r, pxl8_gfx_texture tex) {
|
||||||
if (!VALID_TEX(r, tex)) return NULL;
|
if (!VALID_TEX(r, tex)) return NULL;
|
||||||
return r->textures[SLOT_INDEX(tex.id)].data;
|
return r->textures[SLOT_INDEX(tex.id)].data;
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 pxl8_texture_get_width(pxl8_renderer* r, pxl8_gfx_texture tex) {
|
u32 pxl8_texture_get_width(pxl8_blit3d* r, pxl8_gfx_texture tex) {
|
||||||
if (!VALID_TEX(r, tex)) return 0;
|
if (!VALID_TEX(r, tex)) return 0;
|
||||||
return r->textures[SLOT_INDEX(tex.id)].width;
|
return r->textures[SLOT_INDEX(tex.id)].width;
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 pxl8_texture_get_height(pxl8_renderer* r, pxl8_gfx_texture tex) {
|
u32 pxl8_texture_get_height(pxl8_blit3d* r, pxl8_gfx_texture tex) {
|
||||||
if (!VALID_TEX(r, tex)) return 0;
|
if (!VALID_TEX(r, tex)) return 0;
|
||||||
return r->textures[SLOT_INDEX(tex.id)].height;
|
return r->textures[SLOT_INDEX(tex.id)].height;
|
||||||
}
|
}
|
||||||
|
|
@ -1198,7 +1198,7 @@ void pxl8_draw(pxl8_gfx_cmdbuf* cb, pxl8_gfx_buffer vb, pxl8_gfx_buffer ib, u32
|
||||||
}
|
}
|
||||||
|
|
||||||
static void execute_draw(
|
static void execute_draw(
|
||||||
pxl8_renderer* r,
|
pxl8_blit3d* r,
|
||||||
const pxl8_gfx_cmd_draw* cmd
|
const pxl8_gfx_cmd_draw* cmd
|
||||||
) {
|
) {
|
||||||
r->stats.draw_calls++;
|
r->stats.draw_calls++;
|
||||||
|
|
@ -1416,7 +1416,7 @@ static void execute_draw(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void pxl8_gfx_submit(pxl8_renderer* r, pxl8_gfx_cmdbuf* cb) {
|
void pxl8_gfx_submit(pxl8_blit3d* r, pxl8_gfx_cmdbuf* cb) {
|
||||||
for (u32 i = 0; i < cb->count; i++) {
|
for (u32 i = 0; i < cb->count; i++) {
|
||||||
pxl8_gfx_cmd* cmd = &cb->commands[i];
|
pxl8_gfx_cmd* cmd = &cb->commands[i];
|
||||||
switch (cmd->type) {
|
switch (cmd->type) {
|
||||||
|
|
@ -1475,7 +1475,7 @@ void pxl8_gfx_submit(pxl8_renderer* r, pxl8_gfx_cmdbuf* cb) {
|
||||||
r->frame_counter++;
|
r->frame_counter++;
|
||||||
}
|
}
|
||||||
|
|
||||||
void pxl8_clear(pxl8_renderer* r, pxl8_gfx_texture target, u8 color) {
|
void pxl8_clear(pxl8_blit3d* r, pxl8_gfx_texture target, u8 color) {
|
||||||
if (!VALID_TEX(r, target)) return;
|
if (!VALID_TEX(r, target)) return;
|
||||||
texture_slot* s = &r->textures[SLOT_INDEX(target.id)];
|
texture_slot* s = &r->textures[SLOT_INDEX(target.id)];
|
||||||
if (s->format == PXL8_GFX_FORMAT_INDEXED8) {
|
if (s->format == PXL8_GFX_FORMAT_INDEXED8) {
|
||||||
|
|
@ -1483,7 +1483,7 @@ void pxl8_clear(pxl8_renderer* r, pxl8_gfx_texture target, u8 color) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void pxl8_clear_depth(pxl8_renderer* r, pxl8_gfx_texture target) {
|
void pxl8_clear_depth(pxl8_blit3d* r, pxl8_gfx_texture target) {
|
||||||
if (!VALID_TEX(r, target)) return;
|
if (!VALID_TEX(r, target)) return;
|
||||||
texture_slot* s = &r->textures[SLOT_INDEX(target.id)];
|
texture_slot* s = &r->textures[SLOT_INDEX(target.id)];
|
||||||
if (s->format == PXL8_GFX_FORMAT_DEPTH16) {
|
if (s->format == PXL8_GFX_FORMAT_DEPTH16) {
|
||||||
|
|
@ -1491,13 +1491,13 @@ void pxl8_clear_depth(pxl8_renderer* r, pxl8_gfx_texture target) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void pxl8_clear_stencil(pxl8_renderer* r, u8 value) {
|
void pxl8_clear_stencil(pxl8_blit3d* r, u8 value) {
|
||||||
if (!r || !r->stencil) return;
|
if (!r || !r->stencil) return;
|
||||||
memset(r->stencil, value, r->width * r->height);
|
memset(r->stencil, value, r->width * r->height);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void pxl8_draw_pixel(pxl8_renderer* r, pxl8_gfx_texture target, i32 x, i32 y, u8 color) {
|
void pxl8_draw_pixel(pxl8_blit3d* r, pxl8_gfx_texture target, i32 x, i32 y, u8 color) {
|
||||||
if (!VALID_TEX(r, target)) return;
|
if (!VALID_TEX(r, target)) return;
|
||||||
texture_slot* s = &r->textures[SLOT_INDEX(target.id)];
|
texture_slot* s = &r->textures[SLOT_INDEX(target.id)];
|
||||||
if (x < 0 || y < 0 || (u32)x >= s->width || (u32)y >= s->height) return;
|
if (x < 0 || y < 0 || (u32)x >= s->width || (u32)y >= s->height) return;
|
||||||
|
|
@ -1506,7 +1506,7 @@ void pxl8_draw_pixel(pxl8_renderer* r, pxl8_gfx_texture target, i32 x, i32 y, u8
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
u8 pxl8_get_pixel(pxl8_renderer* r, pxl8_gfx_texture target, i32 x, i32 y) {
|
u8 pxl8_get_pixel(pxl8_blit3d* r, pxl8_gfx_texture target, i32 x, i32 y) {
|
||||||
if (!VALID_TEX(r, target)) return 0;
|
if (!VALID_TEX(r, target)) return 0;
|
||||||
texture_slot* s = &r->textures[SLOT_INDEX(target.id)];
|
texture_slot* s = &r->textures[SLOT_INDEX(target.id)];
|
||||||
if (x < 0 || y < 0 || (u32)x >= s->width || (u32)y >= s->height) return 0;
|
if (x < 0 || y < 0 || (u32)x >= s->width || (u32)y >= s->height) return 0;
|
||||||
|
|
@ -1516,7 +1516,7 @@ u8 pxl8_get_pixel(pxl8_renderer* r, pxl8_gfx_texture target, i32 x, i32 y) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void pxl8_draw_line(pxl8_renderer* r, pxl8_gfx_texture target, i32 x0, i32 y0, i32 x1, i32 y1, u8 color) {
|
void pxl8_draw_line(pxl8_blit3d* r, pxl8_gfx_texture target, i32 x0, i32 y0, i32 x1, i32 y1, u8 color) {
|
||||||
if (!VALID_TEX(r, target)) return;
|
if (!VALID_TEX(r, target)) return;
|
||||||
texture_slot* s = &r->textures[SLOT_INDEX(target.id)];
|
texture_slot* s = &r->textures[SLOT_INDEX(target.id)];
|
||||||
if (s->format != PXL8_GFX_FORMAT_INDEXED8) return;
|
if (s->format != PXL8_GFX_FORMAT_INDEXED8) return;
|
||||||
|
|
@ -1542,14 +1542,14 @@ void pxl8_draw_line(pxl8_renderer* r, pxl8_gfx_texture target, i32 x0, i32 y0, i
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void pxl8_draw_rect(pxl8_renderer* r, pxl8_gfx_texture target, i32 x, i32 y, i32 w, i32 h, u8 color) {
|
void pxl8_draw_rect(pxl8_blit3d* r, pxl8_gfx_texture target, i32 x, i32 y, i32 w, i32 h, u8 color) {
|
||||||
pxl8_draw_line(r, target, x, y, x + w - 1, y, color);
|
pxl8_draw_line(r, target, x, y, x + w - 1, y, color);
|
||||||
pxl8_draw_line(r, target, x + w - 1, y, x + w - 1, y + h - 1, color);
|
pxl8_draw_line(r, target, x + w - 1, y, x + w - 1, y + h - 1, color);
|
||||||
pxl8_draw_line(r, target, x + w - 1, y + h - 1, x, y + h - 1, color);
|
pxl8_draw_line(r, target, x + w - 1, y + h - 1, x, y + h - 1, color);
|
||||||
pxl8_draw_line(r, target, x, y + h - 1, x, y, color);
|
pxl8_draw_line(r, target, x, y + h - 1, x, y, color);
|
||||||
}
|
}
|
||||||
|
|
||||||
void pxl8_draw_rect_fill(pxl8_renderer* r, pxl8_gfx_texture target, i32 x, i32 y, i32 w, i32 h, u8 color) {
|
void pxl8_draw_rect_fill(pxl8_blit3d* r, pxl8_gfx_texture target, i32 x, i32 y, i32 w, i32 h, u8 color) {
|
||||||
if (!VALID_TEX(r, target)) return;
|
if (!VALID_TEX(r, target)) return;
|
||||||
texture_slot* s = &r->textures[SLOT_INDEX(target.id)];
|
texture_slot* s = &r->textures[SLOT_INDEX(target.id)];
|
||||||
if (s->format != PXL8_GFX_FORMAT_INDEXED8) return;
|
if (s->format != PXL8_GFX_FORMAT_INDEXED8) return;
|
||||||
|
|
@ -1568,7 +1568,7 @@ void pxl8_draw_rect_fill(pxl8_renderer* r, pxl8_gfx_texture target, i32 x, i32 y
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void pxl8_draw_circle(pxl8_renderer* r, pxl8_gfx_texture target, i32 cx, i32 cy, i32 radius, u8 color) {
|
void pxl8_draw_circle(pxl8_blit3d* r, pxl8_gfx_texture target, i32 cx, i32 cy, i32 radius, u8 color) {
|
||||||
if (!VALID_TEX(r, target)) return;
|
if (!VALID_TEX(r, target)) return;
|
||||||
texture_slot* s = &r->textures[SLOT_INDEX(target.id)];
|
texture_slot* s = &r->textures[SLOT_INDEX(target.id)];
|
||||||
if (s->format != PXL8_GFX_FORMAT_INDEXED8) return;
|
if (s->format != PXL8_GFX_FORMAT_INDEXED8) return;
|
||||||
|
|
@ -1594,7 +1594,7 @@ void pxl8_draw_circle(pxl8_renderer* r, pxl8_gfx_texture target, i32 cx, i32 cy,
|
||||||
#undef PLOT
|
#undef PLOT
|
||||||
}
|
}
|
||||||
|
|
||||||
void pxl8_draw_circle_fill(pxl8_renderer* r, pxl8_gfx_texture target, i32 cx, i32 cy, i32 radius, u8 color) {
|
void pxl8_draw_circle_fill(pxl8_blit3d* r, pxl8_gfx_texture target, i32 cx, i32 cy, i32 radius, u8 color) {
|
||||||
if (!VALID_TEX(r, target)) return;
|
if (!VALID_TEX(r, target)) return;
|
||||||
texture_slot* s = &r->textures[SLOT_INDEX(target.id)];
|
texture_slot* s = &r->textures[SLOT_INDEX(target.id)];
|
||||||
if (s->format != PXL8_GFX_FORMAT_INDEXED8) return;
|
if (s->format != PXL8_GFX_FORMAT_INDEXED8) return;
|
||||||
|
|
@ -1618,7 +1618,7 @@ void pxl8_draw_circle_fill(pxl8_renderer* r, pxl8_gfx_texture target, i32 cx, i3
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void pxl8_resolve_to_rgba(pxl8_renderer* r, pxl8_gfx_texture color, const u32* palette, u32* output) {
|
void pxl8_resolve_to_rgba(pxl8_blit3d* r, pxl8_gfx_texture color, const u32* palette, u32* output) {
|
||||||
if (!VALID_TEX(r, color)) return;
|
if (!VALID_TEX(r, color)) return;
|
||||||
texture_slot* cs = &r->textures[SLOT_INDEX(color.id)];
|
texture_slot* cs = &r->textures[SLOT_INDEX(color.id)];
|
||||||
|
|
||||||
70
src/gfx/pxl8_blit3d.h
Normal file
70
src/gfx/pxl8_blit3d.h
Normal file
|
|
@ -0,0 +1,70 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "pxl8_colormap.h"
|
||||||
|
#include "pxl8_gfx.h"
|
||||||
|
#include "pxl8_blit3d_types.h"
|
||||||
|
#include "pxl8_shader.h"
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
typedef struct pxl8_blit3d pxl8_blit3d;
|
||||||
|
typedef struct pxl8_gfx_cmdbuf pxl8_gfx_cmdbuf;
|
||||||
|
|
||||||
|
pxl8_blit3d* pxl8_blit3d_create(u32 width, u32 height);
|
||||||
|
void pxl8_blit3d_destroy(pxl8_blit3d* r);
|
||||||
|
|
||||||
|
pxl8_gfx_bindings pxl8_create_bindings(pxl8_blit3d* r, const pxl8_gfx_bindings_desc* desc);
|
||||||
|
pxl8_gfx_buffer pxl8_create_buffer(pxl8_blit3d* r, const pxl8_gfx_buffer_desc* desc);
|
||||||
|
pxl8_gfx_pass pxl8_create_pass(pxl8_blit3d* r, const pxl8_gfx_pass_desc* desc);
|
||||||
|
pxl8_gfx_pipeline pxl8_create_pipeline(pxl8_blit3d* r, const pxl8_gfx_pipeline_desc* desc);
|
||||||
|
pxl8_gfx_texture pxl8_create_texture(pxl8_blit3d* r, const pxl8_gfx_texture_desc* desc);
|
||||||
|
|
||||||
|
void pxl8_destroy_bindings(pxl8_blit3d* r, pxl8_gfx_bindings bnd);
|
||||||
|
void pxl8_destroy_buffer(pxl8_blit3d* r, pxl8_gfx_buffer buf);
|
||||||
|
void pxl8_destroy_pass(pxl8_blit3d* r, pxl8_gfx_pass pass);
|
||||||
|
void pxl8_destroy_pipeline(pxl8_blit3d* r, pxl8_gfx_pipeline pip);
|
||||||
|
void pxl8_destroy_texture(pxl8_blit3d* r, pxl8_gfx_texture tex);
|
||||||
|
|
||||||
|
void pxl8_update_buffer(pxl8_blit3d* r, pxl8_gfx_buffer buf, const pxl8_gfx_range* data);
|
||||||
|
i32 pxl8_append_buffer(pxl8_blit3d* r, pxl8_gfx_buffer buf, const pxl8_gfx_range* data);
|
||||||
|
void pxl8_update_texture(pxl8_blit3d* r, pxl8_gfx_texture tex, const pxl8_gfx_range* data, u32 x, u32 y, u32 w, u32 h);
|
||||||
|
|
||||||
|
void* pxl8_texture_get_data(pxl8_blit3d* r, pxl8_gfx_texture tex);
|
||||||
|
u32 pxl8_texture_get_width(pxl8_blit3d* r, pxl8_gfx_texture tex);
|
||||||
|
u32 pxl8_texture_get_height(pxl8_blit3d* r, pxl8_gfx_texture tex);
|
||||||
|
|
||||||
|
pxl8_gfx_cmdbuf* pxl8_cmdbuf_create(u32 capacity);
|
||||||
|
void pxl8_cmdbuf_destroy(pxl8_gfx_cmdbuf* cb);
|
||||||
|
void pxl8_cmdbuf_reset(pxl8_gfx_cmdbuf* cb);
|
||||||
|
|
||||||
|
void pxl8_begin_pass(pxl8_gfx_cmdbuf* cb, pxl8_gfx_pass pass);
|
||||||
|
void pxl8_cmdbuf_clear_depth(pxl8_gfx_cmdbuf* cb, pxl8_gfx_texture texture);
|
||||||
|
void pxl8_end_pass(pxl8_gfx_cmdbuf* cb);
|
||||||
|
void pxl8_set_bindings(pxl8_gfx_cmdbuf* cb, pxl8_gfx_bindings bindings);
|
||||||
|
void pxl8_set_draw_params(pxl8_gfx_cmdbuf* cb, const pxl8_gfx_cmd_draw_params* p);
|
||||||
|
void pxl8_set_pipeline(pxl8_gfx_cmdbuf* cb, pxl8_gfx_pipeline pipeline);
|
||||||
|
void pxl8_set_scissor(pxl8_gfx_cmdbuf* cb, i32 x, i32 y, u32 w, u32 h);
|
||||||
|
void pxl8_set_viewport(pxl8_gfx_cmdbuf* cb, i32 x, i32 y, u32 w, u32 h);
|
||||||
|
void pxl8_draw(pxl8_gfx_cmdbuf* cb, pxl8_gfx_buffer vb, pxl8_gfx_buffer ib, u32 first, u32 count, u32 base_vertex);
|
||||||
|
|
||||||
|
void pxl8_gfx_submit(pxl8_blit3d* r, pxl8_gfx_cmdbuf* cb);
|
||||||
|
|
||||||
|
void pxl8_clear(pxl8_blit3d* r, pxl8_gfx_texture target, u8 color);
|
||||||
|
void pxl8_clear_depth(pxl8_blit3d* r, pxl8_gfx_texture target);
|
||||||
|
void pxl8_clear_stencil(pxl8_blit3d* r, u8 value);
|
||||||
|
|
||||||
|
void pxl8_draw_pixel(pxl8_blit3d* r, pxl8_gfx_texture target, i32 x, i32 y, u8 color);
|
||||||
|
u8 pxl8_get_pixel(pxl8_blit3d* r, pxl8_gfx_texture target, i32 x, i32 y);
|
||||||
|
void pxl8_draw_line(pxl8_blit3d* r, pxl8_gfx_texture target, i32 x0, i32 y0, i32 x1, i32 y1, u8 color);
|
||||||
|
void pxl8_draw_rect(pxl8_blit3d* r, pxl8_gfx_texture target, i32 x, i32 y, i32 w, i32 h, u8 color);
|
||||||
|
void pxl8_draw_rect_fill(pxl8_blit3d* r, pxl8_gfx_texture target, i32 x, i32 y, i32 w, i32 h, u8 color);
|
||||||
|
void pxl8_draw_circle(pxl8_blit3d* r, pxl8_gfx_texture target, i32 cx, i32 cy, i32 radius, u8 color);
|
||||||
|
void pxl8_draw_circle_fill(pxl8_blit3d* r, pxl8_gfx_texture target, i32 cx, i32 cy, i32 radius, u8 color);
|
||||||
|
|
||||||
|
void pxl8_resolve_to_rgba(pxl8_blit3d* r, pxl8_gfx_texture color, const u32* palette, u32* output);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
@ -1,16 +1,16 @@
|
||||||
#include "pxl8_3d_camera.h"
|
#include "pxl8_camera3d.h"
|
||||||
#include "pxl8_mem.h"
|
#include "pxl8_mem.h"
|
||||||
|
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
|
||||||
struct pxl8_3d_camera {
|
struct pxl8_camera3d {
|
||||||
pxl8_vec3 position;
|
pxl8_vec3 position;
|
||||||
f32 pitch;
|
f32 pitch;
|
||||||
f32 roll;
|
f32 roll;
|
||||||
f32 yaw;
|
f32 yaw;
|
||||||
|
|
||||||
pxl8_3d_camera_mode mode;
|
pxl8_camera3d_mode mode;
|
||||||
|
|
||||||
f32 aspect;
|
f32 aspect;
|
||||||
f32 far;
|
f32 far;
|
||||||
|
|
@ -28,8 +28,8 @@ struct pxl8_3d_camera {
|
||||||
f32 shake_timer;
|
f32 shake_timer;
|
||||||
};
|
};
|
||||||
|
|
||||||
pxl8_3d_camera* pxl8_3d_camera_create(void) {
|
pxl8_camera3d* pxl8_camera3d_create(void) {
|
||||||
pxl8_3d_camera* cam = pxl8_calloc(1, sizeof(pxl8_3d_camera));
|
pxl8_camera3d* cam = pxl8_calloc(1, sizeof(pxl8_camera3d));
|
||||||
if (!cam) return NULL;
|
if (!cam) return NULL;
|
||||||
|
|
||||||
cam->position = (pxl8_vec3){0, 0, 0};
|
cam->position = (pxl8_vec3){0, 0, 0};
|
||||||
|
|
@ -37,7 +37,7 @@ pxl8_3d_camera* pxl8_3d_camera_create(void) {
|
||||||
cam->yaw = 0;
|
cam->yaw = 0;
|
||||||
cam->roll = 0;
|
cam->roll = 0;
|
||||||
|
|
||||||
cam->mode = PXL8_3D_CAMERA_PERSPECTIVE;
|
cam->mode = PXL8_CAMERA3D_PERSPECTIVE;
|
||||||
cam->fov = 1.0f;
|
cam->fov = 1.0f;
|
||||||
cam->aspect = 16.0f / 9.0f;
|
cam->aspect = 16.0f / 9.0f;
|
||||||
cam->near = 1.0f;
|
cam->near = 1.0f;
|
||||||
|
|
@ -46,11 +46,11 @@ pxl8_3d_camera* pxl8_3d_camera_create(void) {
|
||||||
return cam;
|
return cam;
|
||||||
}
|
}
|
||||||
|
|
||||||
void pxl8_3d_camera_destroy(pxl8_3d_camera* cam) {
|
void pxl8_camera3d_destroy(pxl8_camera3d* cam) {
|
||||||
pxl8_free(cam);
|
pxl8_free(cam);
|
||||||
}
|
}
|
||||||
|
|
||||||
void pxl8_3d_camera_lookat(pxl8_3d_camera* cam, pxl8_vec3 eye, pxl8_vec3 target, pxl8_vec3 up) {
|
void pxl8_camera3d_lookat(pxl8_camera3d* cam, pxl8_vec3 eye, pxl8_vec3 target, pxl8_vec3 up) {
|
||||||
if (!cam) return;
|
if (!cam) return;
|
||||||
|
|
||||||
cam->position = eye;
|
cam->position = eye;
|
||||||
|
|
@ -64,9 +64,9 @@ void pxl8_3d_camera_lookat(pxl8_3d_camera* cam, pxl8_vec3 eye, pxl8_vec3 target,
|
||||||
(void)up;
|
(void)up;
|
||||||
}
|
}
|
||||||
|
|
||||||
void pxl8_3d_camera_set_ortho(pxl8_3d_camera* cam, f32 left, f32 right, f32 bottom, f32 top, f32 near, f32 far) {
|
void pxl8_camera3d_set_ortho(pxl8_camera3d* cam, f32 left, f32 right, f32 bottom, f32 top, f32 near, f32 far) {
|
||||||
if (!cam) return;
|
if (!cam) return;
|
||||||
cam->mode = PXL8_3D_CAMERA_ORTHO;
|
cam->mode = PXL8_CAMERA3D_ORTHO;
|
||||||
cam->ortho_left = left;
|
cam->ortho_left = left;
|
||||||
cam->ortho_right = right;
|
cam->ortho_right = right;
|
||||||
cam->ortho_bottom = bottom;
|
cam->ortho_bottom = bottom;
|
||||||
|
|
@ -75,28 +75,28 @@ void pxl8_3d_camera_set_ortho(pxl8_3d_camera* cam, f32 left, f32 right, f32 bott
|
||||||
cam->far = far;
|
cam->far = far;
|
||||||
}
|
}
|
||||||
|
|
||||||
void pxl8_3d_camera_set_perspective(pxl8_3d_camera* cam, f32 fov, f32 aspect, f32 near, f32 far) {
|
void pxl8_camera3d_set_perspective(pxl8_camera3d* cam, f32 fov, f32 aspect, f32 near, f32 far) {
|
||||||
if (!cam) return;
|
if (!cam) return;
|
||||||
cam->mode = PXL8_3D_CAMERA_PERSPECTIVE;
|
cam->mode = PXL8_CAMERA3D_PERSPECTIVE;
|
||||||
cam->fov = fov;
|
cam->fov = fov;
|
||||||
cam->aspect = aspect;
|
cam->aspect = aspect;
|
||||||
cam->near = near;
|
cam->near = near;
|
||||||
cam->far = far;
|
cam->far = far;
|
||||||
}
|
}
|
||||||
|
|
||||||
void pxl8_3d_camera_set_position(pxl8_3d_camera* cam, pxl8_vec3 pos) {
|
void pxl8_camera3d_set_position(pxl8_camera3d* cam, pxl8_vec3 pos) {
|
||||||
if (!cam) return;
|
if (!cam) return;
|
||||||
cam->position = pos;
|
cam->position = pos;
|
||||||
}
|
}
|
||||||
|
|
||||||
void pxl8_3d_camera_set_rotation(pxl8_3d_camera* cam, f32 pitch, f32 yaw, f32 roll) {
|
void pxl8_camera3d_set_rotation(pxl8_camera3d* cam, f32 pitch, f32 yaw, f32 roll) {
|
||||||
if (!cam) return;
|
if (!cam) return;
|
||||||
cam->pitch = pitch;
|
cam->pitch = pitch;
|
||||||
cam->yaw = yaw;
|
cam->yaw = yaw;
|
||||||
cam->roll = roll;
|
cam->roll = roll;
|
||||||
}
|
}
|
||||||
|
|
||||||
pxl8_vec3 pxl8_3d_camera_get_forward(const pxl8_3d_camera* cam) {
|
pxl8_vec3 pxl8_camera3d_get_forward(const pxl8_camera3d* cam) {
|
||||||
if (!cam) return (pxl8_vec3){0, 0, -1};
|
if (!cam) return (pxl8_vec3){0, 0, -1};
|
||||||
|
|
||||||
f32 cp = cosf(cam->pitch);
|
f32 cp = cosf(cam->pitch);
|
||||||
|
|
@ -111,15 +111,15 @@ pxl8_vec3 pxl8_3d_camera_get_forward(const pxl8_3d_camera* cam) {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
pxl8_vec3 pxl8_3d_camera_get_position(const pxl8_3d_camera* cam) {
|
pxl8_vec3 pxl8_camera3d_get_position(const pxl8_camera3d* cam) {
|
||||||
if (!cam) return (pxl8_vec3){0, 0, 0};
|
if (!cam) return (pxl8_vec3){0, 0, 0};
|
||||||
return pxl8_vec3_add(cam->position, cam->shake_offset);
|
return pxl8_vec3_add(cam->position, cam->shake_offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
pxl8_mat4 pxl8_3d_camera_get_projection(const pxl8_3d_camera* cam) {
|
pxl8_mat4 pxl8_camera3d_get_projection(const pxl8_camera3d* cam) {
|
||||||
if (!cam) return pxl8_mat4_identity();
|
if (!cam) return pxl8_mat4_identity();
|
||||||
|
|
||||||
if (cam->mode == PXL8_3D_CAMERA_PERSPECTIVE) {
|
if (cam->mode == PXL8_CAMERA3D_PERSPECTIVE) {
|
||||||
return pxl8_mat4_perspective(cam->fov, cam->aspect, cam->near, cam->far);
|
return pxl8_mat4_perspective(cam->fov, cam->aspect, cam->near, cam->far);
|
||||||
} else {
|
} else {
|
||||||
return pxl8_mat4_orthographic(
|
return pxl8_mat4_orthographic(
|
||||||
|
|
@ -130,7 +130,7 @@ pxl8_mat4 pxl8_3d_camera_get_projection(const pxl8_3d_camera* cam) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pxl8_vec3 pxl8_3d_camera_get_right(const pxl8_3d_camera* cam) {
|
pxl8_vec3 pxl8_camera3d_get_right(const pxl8_camera3d* cam) {
|
||||||
if (!cam) return (pxl8_vec3){1, 0, 0};
|
if (!cam) return (pxl8_vec3){1, 0, 0};
|
||||||
|
|
||||||
f32 cy = cosf(cam->yaw);
|
f32 cy = cosf(cam->yaw);
|
||||||
|
|
@ -139,27 +139,27 @@ pxl8_vec3 pxl8_3d_camera_get_right(const pxl8_3d_camera* cam) {
|
||||||
return (pxl8_vec3){cy, 0, -sy};
|
return (pxl8_vec3){cy, 0, -sy};
|
||||||
}
|
}
|
||||||
|
|
||||||
pxl8_vec3 pxl8_3d_camera_get_up(const pxl8_3d_camera* cam) {
|
pxl8_vec3 pxl8_camera3d_get_up(const pxl8_camera3d* cam) {
|
||||||
if (!cam) return (pxl8_vec3){0, 1, 0};
|
if (!cam) return (pxl8_vec3){0, 1, 0};
|
||||||
|
|
||||||
pxl8_vec3 forward = pxl8_3d_camera_get_forward(cam);
|
pxl8_vec3 forward = pxl8_camera3d_get_forward(cam);
|
||||||
pxl8_vec3 right = pxl8_3d_camera_get_right(cam);
|
pxl8_vec3 right = pxl8_camera3d_get_right(cam);
|
||||||
|
|
||||||
return pxl8_vec3_cross(forward, right);
|
return pxl8_vec3_cross(forward, right);
|
||||||
}
|
}
|
||||||
|
|
||||||
pxl8_mat4 pxl8_3d_camera_get_view(const pxl8_3d_camera* cam) {
|
pxl8_mat4 pxl8_camera3d_get_view(const pxl8_camera3d* cam) {
|
||||||
if (!cam) return pxl8_mat4_identity();
|
if (!cam) return pxl8_mat4_identity();
|
||||||
|
|
||||||
pxl8_vec3 pos = pxl8_3d_camera_get_position(cam);
|
pxl8_vec3 pos = pxl8_camera3d_get_position(cam);
|
||||||
pxl8_vec3 forward = pxl8_3d_camera_get_forward(cam);
|
pxl8_vec3 forward = pxl8_camera3d_get_forward(cam);
|
||||||
pxl8_vec3 target = pxl8_vec3_add(pos, forward);
|
pxl8_vec3 target = pxl8_vec3_add(pos, forward);
|
||||||
pxl8_vec3 up = (pxl8_vec3){0, 1, 0};
|
pxl8_vec3 up = (pxl8_vec3){0, 1, 0};
|
||||||
|
|
||||||
return pxl8_mat4_lookat(pos, target, up);
|
return pxl8_mat4_lookat(pos, target, up);
|
||||||
}
|
}
|
||||||
|
|
||||||
void pxl8_3d_camera_blend(pxl8_3d_camera* dest, const pxl8_3d_camera* a, const pxl8_3d_camera* b, f32 t) {
|
void pxl8_camera3d_blend(pxl8_camera3d* dest, const pxl8_camera3d* a, const pxl8_camera3d* b, f32 t) {
|
||||||
if (!dest || !a || !b) return;
|
if (!dest || !a || !b) return;
|
||||||
|
|
||||||
dest->position = pxl8_vec3_lerp(a->position, b->position, t);
|
dest->position = pxl8_vec3_lerp(a->position, b->position, t);
|
||||||
|
|
@ -175,7 +175,7 @@ void pxl8_3d_camera_blend(pxl8_3d_camera* dest, const pxl8_3d_camera* a, const p
|
||||||
dest->mode = (t < 0.5f) ? a->mode : b->mode;
|
dest->mode = (t < 0.5f) ? a->mode : b->mode;
|
||||||
}
|
}
|
||||||
|
|
||||||
void pxl8_3d_camera_follow(pxl8_3d_camera* cam, pxl8_vec3 target, pxl8_vec3 offset, f32 smoothing, f32 dt) {
|
void pxl8_camera3d_follow(pxl8_camera3d* cam, pxl8_vec3 target, pxl8_vec3 offset, f32 smoothing, f32 dt) {
|
||||||
if (!cam) return;
|
if (!cam) return;
|
||||||
|
|
||||||
pxl8_vec3 desired = pxl8_vec3_add(target, offset);
|
pxl8_vec3 desired = pxl8_vec3_add(target, offset);
|
||||||
|
|
@ -188,14 +188,14 @@ void pxl8_3d_camera_follow(pxl8_3d_camera* cam, pxl8_vec3 target, pxl8_vec3 offs
|
||||||
cam->yaw = atan2f(-forward.x, -forward.z);
|
cam->yaw = atan2f(-forward.x, -forward.z);
|
||||||
}
|
}
|
||||||
|
|
||||||
void pxl8_3d_camera_shake(pxl8_3d_camera* cam, f32 intensity, f32 duration) {
|
void pxl8_camera3d_shake(pxl8_camera3d* cam, f32 intensity, f32 duration) {
|
||||||
if (!cam) return;
|
if (!cam) return;
|
||||||
cam->shake_intensity = intensity;
|
cam->shake_intensity = intensity;
|
||||||
cam->shake_duration = duration;
|
cam->shake_duration = duration;
|
||||||
cam->shake_timer = duration;
|
cam->shake_timer = duration;
|
||||||
}
|
}
|
||||||
|
|
||||||
void pxl8_3d_camera_update(pxl8_3d_camera* cam, f32 dt) {
|
void pxl8_camera3d_update(pxl8_camera3d* cam, f32 dt) {
|
||||||
if (!cam) return;
|
if (!cam) return;
|
||||||
|
|
||||||
if (cam->shake_timer > 0) {
|
if (cam->shake_timer > 0) {
|
||||||
|
|
@ -214,12 +214,12 @@ void pxl8_3d_camera_update(pxl8_3d_camera* cam, f32 dt) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pxl8_projected_point pxl8_3d_camera_world_to_screen(const pxl8_3d_camera* cam, pxl8_vec3 world_pos, u32 screen_width, u32 screen_height) {
|
pxl8_projected_point pxl8_camera3d_world_to_screen(const pxl8_camera3d* cam, pxl8_vec3 world_pos, u32 screen_width, u32 screen_height) {
|
||||||
pxl8_projected_point result = {0, 0, 0.0f, false};
|
pxl8_projected_point result = {0, 0, 0.0f, false};
|
||||||
if (!cam) return result;
|
if (!cam) return result;
|
||||||
|
|
||||||
pxl8_mat4 view = pxl8_3d_camera_get_view(cam);
|
pxl8_mat4 view = pxl8_camera3d_get_view(cam);
|
||||||
pxl8_mat4 proj = pxl8_3d_camera_get_projection(cam);
|
pxl8_mat4 proj = pxl8_camera3d_get_projection(cam);
|
||||||
pxl8_mat4 vp = pxl8_mat4_multiply(proj, view);
|
pxl8_mat4 vp = pxl8_mat4_multiply(proj, view);
|
||||||
|
|
||||||
pxl8_vec4 clip = pxl8_mat4_multiply_vec4(vp, (pxl8_vec4){world_pos.x, world_pos.y, world_pos.z, 1.0f});
|
pxl8_vec4 clip = pxl8_mat4_multiply_vec4(vp, (pxl8_vec4){world_pos.x, world_pos.y, world_pos.z, 1.0f});
|
||||||
41
src/gfx/pxl8_camera3d.h
Normal file
41
src/gfx/pxl8_camera3d.h
Normal file
|
|
@ -0,0 +1,41 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "pxl8_math.h"
|
||||||
|
#include "pxl8_types.h"
|
||||||
|
|
||||||
|
typedef enum pxl8_camera3d_mode {
|
||||||
|
PXL8_CAMERA3D_ORTHO,
|
||||||
|
PXL8_CAMERA3D_PERSPECTIVE
|
||||||
|
} pxl8_camera3d_mode;
|
||||||
|
|
||||||
|
typedef struct pxl8_camera3d pxl8_camera3d;
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
pxl8_camera3d* pxl8_camera3d_create(void);
|
||||||
|
void pxl8_camera3d_destroy(pxl8_camera3d* cam);
|
||||||
|
|
||||||
|
void pxl8_camera3d_lookat(pxl8_camera3d* cam, pxl8_vec3 eye, pxl8_vec3 target, pxl8_vec3 up);
|
||||||
|
void pxl8_camera3d_set_ortho(pxl8_camera3d* cam, f32 left, f32 right, f32 bottom, f32 top, f32 near, f32 far);
|
||||||
|
void pxl8_camera3d_set_perspective(pxl8_camera3d* cam, f32 fov, f32 aspect, f32 near, f32 far);
|
||||||
|
void pxl8_camera3d_set_position(pxl8_camera3d* cam, pxl8_vec3 pos);
|
||||||
|
void pxl8_camera3d_set_rotation(pxl8_camera3d* cam, f32 pitch, f32 yaw, f32 roll);
|
||||||
|
|
||||||
|
pxl8_vec3 pxl8_camera3d_get_forward(const pxl8_camera3d* cam);
|
||||||
|
pxl8_vec3 pxl8_camera3d_get_position(const pxl8_camera3d* cam);
|
||||||
|
pxl8_mat4 pxl8_camera3d_get_projection(const pxl8_camera3d* cam);
|
||||||
|
pxl8_vec3 pxl8_camera3d_get_right(const pxl8_camera3d* cam);
|
||||||
|
pxl8_vec3 pxl8_camera3d_get_up(const pxl8_camera3d* cam);
|
||||||
|
pxl8_mat4 pxl8_camera3d_get_view(const pxl8_camera3d* cam);
|
||||||
|
|
||||||
|
void pxl8_camera3d_blend(pxl8_camera3d* dest, const pxl8_camera3d* a, const pxl8_camera3d* b, f32 t);
|
||||||
|
void pxl8_camera3d_follow(pxl8_camera3d* cam, pxl8_vec3 target, pxl8_vec3 offset, f32 smoothing, f32 dt);
|
||||||
|
pxl8_projected_point pxl8_camera3d_world_to_screen(const pxl8_camera3d* cam, pxl8_vec3 world_pos, u32 screen_width, u32 screen_height);
|
||||||
|
void pxl8_camera3d_shake(pxl8_camera3d* cam, f32 intensity, f32 duration);
|
||||||
|
void pxl8_camera3d_update(pxl8_camera3d* cam, f32 dt);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
@ -9,18 +9,18 @@
|
||||||
#include "pxl8_colormap.h"
|
#include "pxl8_colormap.h"
|
||||||
#include "pxl8_font.h"
|
#include "pxl8_font.h"
|
||||||
#include "pxl8_glows.h"
|
#include "pxl8_glows.h"
|
||||||
#include "pxl8_hal.h"
|
#include "pxl8_platform.h"
|
||||||
#include "pxl8_log.h"
|
#include "pxl8_log.h"
|
||||||
#include "pxl8_macros.h"
|
#include "pxl8_macros.h"
|
||||||
#include "pxl8_math.h"
|
#include "pxl8_math.h"
|
||||||
#include "pxl8_mem.h"
|
#include "pxl8_mem.h"
|
||||||
#include "pxl8_render.h"
|
#include "pxl8_blit3d.h"
|
||||||
#include "pxl8_shader_registry.h"
|
#include "pxl8_shader_registry.h"
|
||||||
#include "pxl8_sys.h"
|
#include "pxl8_sys.h"
|
||||||
#include "pxl8_types.h"
|
#include "pxl8_types.h"
|
||||||
|
|
||||||
void pxl8_renderer_update_stats(pxl8_renderer* r, f32 dt);
|
void pxl8_blit3d_update_stats(pxl8_blit3d* r, f32 dt);
|
||||||
pxl8_gfx_stats* pxl8_renderer_get_stats(pxl8_renderer* r);
|
pxl8_gfx_stats* pxl8_blit3d_get_stats(pxl8_blit3d* r);
|
||||||
|
|
||||||
#define PXL8_MAX_TARGET_STACK 8
|
#define PXL8_MAX_TARGET_STACK 8
|
||||||
|
|
||||||
|
|
@ -53,18 +53,17 @@ typedef struct pxl8_frame_resources {
|
||||||
|
|
||||||
struct pxl8_gfx {
|
struct pxl8_gfx {
|
||||||
pxl8_atlas* atlas;
|
pxl8_atlas* atlas;
|
||||||
pxl8_renderer* renderer;
|
pxl8_blit3d* renderer;
|
||||||
pxl8_gfx_texture color_target;
|
pxl8_gfx_texture color_target;
|
||||||
pxl8_gfx_texture depth_target;
|
pxl8_gfx_texture depth_target;
|
||||||
pxl8_gfx_cmdbuf* cmdbuf;
|
pxl8_gfx_cmdbuf* cmdbuf;
|
||||||
pxl8_target_entry target_stack[PXL8_MAX_TARGET_STACK];
|
pxl8_target_entry target_stack[PXL8_MAX_TARGET_STACK];
|
||||||
u32 target_stack_depth;
|
u32 target_stack_depth;
|
||||||
const pxl8_bsp* bsp;
|
|
||||||
pxl8_colormap* colormap;
|
pxl8_colormap* colormap;
|
||||||
i32 framebuffer_height;
|
i32 framebuffer_height;
|
||||||
i32 framebuffer_width;
|
i32 framebuffer_width;
|
||||||
pxl8_frustum frustum;
|
pxl8_frustum frustum;
|
||||||
const pxl8_hal* hal;
|
const pxl8_platform* platform;
|
||||||
bool initialized;
|
bool initialized;
|
||||||
u32* output;
|
u32* output;
|
||||||
pxl8_palette* palette;
|
pxl8_palette* palette;
|
||||||
|
|
@ -170,7 +169,7 @@ i32 pxl8_gfx_load_palette(pxl8_gfx* gfx, const char* filepath) {
|
||||||
}
|
}
|
||||||
|
|
||||||
pxl8_gfx* pxl8_gfx_create(
|
pxl8_gfx* pxl8_gfx_create(
|
||||||
const pxl8_hal* hal,
|
const pxl8_platform* platform,
|
||||||
void* platform_data,
|
void* platform_data,
|
||||||
pxl8_resolution resolution
|
pxl8_resolution resolution
|
||||||
) {
|
) {
|
||||||
|
|
@ -182,7 +181,7 @@ pxl8_gfx* pxl8_gfx_create(
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
gfx->hal = hal;
|
gfx->platform = platform;
|
||||||
gfx->platform_data = platform_data;
|
gfx->platform_data = platform_data;
|
||||||
|
|
||||||
pxl8_size size = pxl8_get_resolution_dimensions(resolution);
|
pxl8_size size = pxl8_get_resolution_dimensions(resolution);
|
||||||
|
|
@ -197,7 +196,7 @@ pxl8_gfx* pxl8_gfx_create(
|
||||||
|
|
||||||
gfx->palette = pxl8_palette_create();
|
gfx->palette = pxl8_palette_create();
|
||||||
|
|
||||||
gfx->renderer = pxl8_renderer_create(gfx->framebuffer_width, gfx->framebuffer_height);
|
gfx->renderer = pxl8_blit3d_create(gfx->framebuffer_width, gfx->framebuffer_height);
|
||||||
if (!gfx->renderer) {
|
if (!gfx->renderer) {
|
||||||
pxl8_error("Failed to create renderer");
|
pxl8_error("Failed to create renderer");
|
||||||
pxl8_gfx_destroy(gfx);
|
pxl8_gfx_destroy(gfx);
|
||||||
|
|
@ -281,7 +280,7 @@ void pxl8_gfx_destroy(pxl8_gfx* gfx) {
|
||||||
pxl8_palette_cube_destroy(gfx->palette_cube);
|
pxl8_palette_cube_destroy(gfx->palette_cube);
|
||||||
pxl8_palette_destroy(gfx->palette);
|
pxl8_palette_destroy(gfx->palette);
|
||||||
pxl8_free(gfx->sprite_cache);
|
pxl8_free(gfx->sprite_cache);
|
||||||
pxl8_renderer_destroy(gfx->renderer);
|
pxl8_blit3d_destroy(gfx->renderer);
|
||||||
|
|
||||||
pxl8_free(gfx);
|
pxl8_free(gfx);
|
||||||
}
|
}
|
||||||
|
|
@ -393,10 +392,10 @@ pxl8_atlas* pxl8_gfx_get_atlas(pxl8_gfx* gfx) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void pxl8_gfx_upload_framebuffer(pxl8_gfx* gfx) {
|
void pxl8_gfx_upload_framebuffer(pxl8_gfx* gfx) {
|
||||||
if (!gfx || !gfx->initialized || !gfx->hal) return;
|
if (!gfx || !gfx->initialized || !gfx->platform) return;
|
||||||
|
|
||||||
pxl8_gfx_resolve(gfx);
|
pxl8_gfx_resolve(gfx);
|
||||||
gfx->hal->upload_texture(
|
gfx->platform->upload_texture(
|
||||||
gfx->platform_data,
|
gfx->platform_data,
|
||||||
gfx->output,
|
gfx->output,
|
||||||
gfx->framebuffer_width,
|
gfx->framebuffer_width,
|
||||||
|
|
@ -407,9 +406,9 @@ void pxl8_gfx_upload_framebuffer(pxl8_gfx* gfx) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void pxl8_gfx_present(pxl8_gfx* gfx) {
|
void pxl8_gfx_present(pxl8_gfx* gfx) {
|
||||||
if (!gfx || !gfx->initialized || !gfx->hal) return;
|
if (!gfx || !gfx->initialized || !gfx->platform) return;
|
||||||
|
|
||||||
gfx->hal->present(gfx->platform_data);
|
gfx->platform->present(gfx->platform_data);
|
||||||
}
|
}
|
||||||
|
|
||||||
pxl8_viewport pxl8_gfx_viewport(pxl8_bounds bounds, i32 width, i32 height) {
|
pxl8_viewport pxl8_gfx_viewport(pxl8_bounds bounds, i32 width, i32 height) {
|
||||||
|
|
@ -618,14 +617,14 @@ void pxl8_gfx_update(pxl8_gfx* gfx, f32 dt) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static pxl8_3d_frame pxl8_3d_frame_from_camera(const pxl8_3d_camera* camera, const pxl8_shader_uniforms* uniforms) {
|
static pxl8_3d_frame pxl8_3d_frame_from_camera(const pxl8_camera3d* camera, const pxl8_shader_uniforms* uniforms) {
|
||||||
pxl8_3d_frame frame = {0};
|
pxl8_3d_frame frame = {0};
|
||||||
if (!camera) return frame;
|
if (!camera) return frame;
|
||||||
|
|
||||||
frame.view = pxl8_3d_camera_get_view(camera);
|
frame.view = pxl8_camera3d_get_view(camera);
|
||||||
frame.projection = pxl8_3d_camera_get_projection(camera);
|
frame.projection = pxl8_camera3d_get_projection(camera);
|
||||||
frame.camera_pos = pxl8_3d_camera_get_position(camera);
|
frame.camera_pos = pxl8_camera3d_get_position(camera);
|
||||||
frame.camera_dir = pxl8_3d_camera_get_forward(camera);
|
frame.camera_dir = pxl8_camera3d_get_forward(camera);
|
||||||
frame.near_clip = 1.0f;
|
frame.near_clip = 1.0f;
|
||||||
frame.far_clip = 4096.0f;
|
frame.far_clip = 4096.0f;
|
||||||
|
|
||||||
|
|
@ -636,16 +635,10 @@ static pxl8_3d_frame pxl8_3d_frame_from_camera(const pxl8_3d_camera* camera, con
|
||||||
return frame;
|
return frame;
|
||||||
}
|
}
|
||||||
|
|
||||||
void pxl8_3d_set_bsp(pxl8_gfx* gfx, const pxl8_bsp* bsp) {
|
void pxl8_3d_begin_frame(pxl8_gfx* gfx, const pxl8_camera3d* camera, const pxl8_lights* lights, const pxl8_shader_uniforms* uniforms) {
|
||||||
if (!gfx) return;
|
|
||||||
gfx->bsp = bsp;
|
|
||||||
}
|
|
||||||
|
|
||||||
void pxl8_3d_begin_frame(pxl8_gfx* gfx, const pxl8_3d_camera* camera, const pxl8_lights* lights, const pxl8_shader_uniforms* uniforms) {
|
|
||||||
if (!gfx || !camera) return;
|
if (!gfx || !camera) return;
|
||||||
|
|
||||||
pxl8_3d_frame frame = pxl8_3d_frame_from_camera(camera, uniforms);
|
pxl8_3d_frame frame = pxl8_3d_frame_from_camera(camera, uniforms);
|
||||||
frame.bsp = gfx->bsp;
|
|
||||||
frame.uniforms.camera_pos = frame.camera_pos;
|
frame.uniforms.camera_pos = frame.camera_pos;
|
||||||
frame.uniforms.lights = lights ? pxl8_lights_data(lights) : NULL;
|
frame.uniforms.lights = lights ? pxl8_lights_data(lights) : NULL;
|
||||||
frame.uniforms.lights_count = lights ? pxl8_lights_count(lights) : 0;
|
frame.uniforms.lights_count = lights ? pxl8_lights_count(lights) : 0;
|
||||||
|
|
@ -1102,9 +1095,9 @@ u8 pxl8_gfx_get_ambient(const pxl8_gfx* gfx) {
|
||||||
}
|
}
|
||||||
|
|
||||||
const pxl8_gfx_stats* pxl8_gfx_get_stats(const pxl8_gfx* gfx) {
|
const pxl8_gfx_stats* pxl8_gfx_get_stats(const pxl8_gfx* gfx) {
|
||||||
return gfx ? pxl8_renderer_get_stats(gfx->renderer) : NULL;
|
return gfx ? pxl8_blit3d_get_stats(gfx->renderer) : NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
void pxl8_gfx_update_stats(pxl8_gfx* gfx, f32 dt) {
|
void pxl8_gfx_update_stats(pxl8_gfx* gfx, f32 dt) {
|
||||||
if (gfx) pxl8_renderer_update_stats(gfx->renderer, dt);
|
if (gfx) pxl8_blit3d_update_stats(gfx->renderer, dt);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@
|
||||||
#include "pxl8_gfx2d.h"
|
#include "pxl8_gfx2d.h"
|
||||||
#include "pxl8_gfx3d.h"
|
#include "pxl8_gfx3d.h"
|
||||||
#include "pxl8_glows.h"
|
#include "pxl8_glows.h"
|
||||||
#include "pxl8_hal.h"
|
#include "pxl8_platform.h"
|
||||||
#include "pxl8_colormap.h"
|
#include "pxl8_colormap.h"
|
||||||
#include "pxl8_palette.h"
|
#include "pxl8_palette.h"
|
||||||
#include "pxl8_types.h"
|
#include "pxl8_types.h"
|
||||||
|
|
@ -36,7 +36,7 @@ typedef enum pxl8_gfx_effect {
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
pxl8_gfx* pxl8_gfx_create(const pxl8_hal* hal, void* platform_data, pxl8_resolution resolution);
|
pxl8_gfx* pxl8_gfx_create(const pxl8_platform* platform, void* platform_data, pxl8_resolution resolution);
|
||||||
void pxl8_gfx_destroy(pxl8_gfx* gfx);
|
void pxl8_gfx_destroy(pxl8_gfx* gfx);
|
||||||
|
|
||||||
void pxl8_gfx_present(pxl8_gfx* gfx);
|
void pxl8_gfx_present(pxl8_gfx* gfx);
|
||||||
|
|
|
||||||
|
|
@ -1,18 +1,16 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "pxl8_3d_camera.h"
|
#include "pxl8_camera3d.h"
|
||||||
#include "pxl8_lights.h"
|
#include "pxl8_lights.h"
|
||||||
#include "pxl8_math.h"
|
#include "pxl8_math.h"
|
||||||
#include "pxl8_mesh.h"
|
#include "pxl8_mesh.h"
|
||||||
#include "pxl8_render_types.h"
|
#include "pxl8_blit3d_types.h"
|
||||||
#include "pxl8_shader.h"
|
#include "pxl8_shader.h"
|
||||||
#include "pxl8_types.h"
|
#include "pxl8_types.h"
|
||||||
|
|
||||||
typedef struct pxl8_bsp pxl8_bsp;
|
|
||||||
typedef struct pxl8_gfx pxl8_gfx;
|
typedef struct pxl8_gfx pxl8_gfx;
|
||||||
|
|
||||||
typedef struct pxl8_3d_frame {
|
typedef struct pxl8_3d_frame {
|
||||||
const pxl8_bsp* bsp;
|
|
||||||
pxl8_vec3 camera_dir;
|
pxl8_vec3 camera_dir;
|
||||||
pxl8_vec3 camera_pos;
|
pxl8_vec3 camera_pos;
|
||||||
f32 far_clip;
|
f32 far_clip;
|
||||||
|
|
@ -26,8 +24,7 @@ typedef struct pxl8_3d_frame {
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
void pxl8_3d_set_bsp(pxl8_gfx* gfx, const pxl8_bsp* bsp);
|
void pxl8_3d_begin_frame(pxl8_gfx* gfx, const pxl8_camera3d* camera, const pxl8_lights* lights, const pxl8_shader_uniforms* uniforms);
|
||||||
void pxl8_3d_begin_frame(pxl8_gfx* gfx, const pxl8_3d_camera* camera, const pxl8_lights* lights, const pxl8_shader_uniforms* uniforms);
|
|
||||||
void pxl8_3d_clear(pxl8_gfx* gfx, u8 color);
|
void pxl8_3d_clear(pxl8_gfx* gfx, u8 color);
|
||||||
void pxl8_3d_clear_depth(pxl8_gfx* gfx);
|
void pxl8_3d_clear_depth(pxl8_gfx* gfx);
|
||||||
void pxl8_3d_clear_stencil(pxl8_gfx* gfx, u8 value);
|
void pxl8_3d_clear_stencil(pxl8_gfx* gfx, u8 value);
|
||||||
|
|
|
||||||
|
|
@ -1,70 +0,0 @@
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include "pxl8_colormap.h"
|
|
||||||
#include "pxl8_gfx.h"
|
|
||||||
#include "pxl8_render_types.h"
|
|
||||||
#include "pxl8_shader.h"
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
extern "C" {
|
|
||||||
#endif
|
|
||||||
|
|
||||||
typedef struct pxl8_renderer pxl8_renderer;
|
|
||||||
typedef struct pxl8_gfx_cmdbuf pxl8_gfx_cmdbuf;
|
|
||||||
|
|
||||||
pxl8_renderer* pxl8_renderer_create(u32 width, u32 height);
|
|
||||||
void pxl8_renderer_destroy(pxl8_renderer* r);
|
|
||||||
|
|
||||||
pxl8_gfx_bindings pxl8_create_bindings(pxl8_renderer* r, const pxl8_gfx_bindings_desc* desc);
|
|
||||||
pxl8_gfx_buffer pxl8_create_buffer(pxl8_renderer* r, const pxl8_gfx_buffer_desc* desc);
|
|
||||||
pxl8_gfx_pass pxl8_create_pass(pxl8_renderer* r, const pxl8_gfx_pass_desc* desc);
|
|
||||||
pxl8_gfx_pipeline pxl8_create_pipeline(pxl8_renderer* r, const pxl8_gfx_pipeline_desc* desc);
|
|
||||||
pxl8_gfx_texture pxl8_create_texture(pxl8_renderer* r, const pxl8_gfx_texture_desc* desc);
|
|
||||||
|
|
||||||
void pxl8_destroy_bindings(pxl8_renderer* r, pxl8_gfx_bindings bnd);
|
|
||||||
void pxl8_destroy_buffer(pxl8_renderer* r, pxl8_gfx_buffer buf);
|
|
||||||
void pxl8_destroy_pass(pxl8_renderer* r, pxl8_gfx_pass pass);
|
|
||||||
void pxl8_destroy_pipeline(pxl8_renderer* r, pxl8_gfx_pipeline pip);
|
|
||||||
void pxl8_destroy_texture(pxl8_renderer* r, pxl8_gfx_texture tex);
|
|
||||||
|
|
||||||
void pxl8_update_buffer(pxl8_renderer* r, pxl8_gfx_buffer buf, const pxl8_gfx_range* data);
|
|
||||||
i32 pxl8_append_buffer(pxl8_renderer* r, pxl8_gfx_buffer buf, const pxl8_gfx_range* data);
|
|
||||||
void pxl8_update_texture(pxl8_renderer* r, pxl8_gfx_texture tex, const pxl8_gfx_range* data, u32 x, u32 y, u32 w, u32 h);
|
|
||||||
|
|
||||||
void* pxl8_texture_get_data(pxl8_renderer* r, pxl8_gfx_texture tex);
|
|
||||||
u32 pxl8_texture_get_width(pxl8_renderer* r, pxl8_gfx_texture tex);
|
|
||||||
u32 pxl8_texture_get_height(pxl8_renderer* r, pxl8_gfx_texture tex);
|
|
||||||
|
|
||||||
pxl8_gfx_cmdbuf* pxl8_cmdbuf_create(u32 capacity);
|
|
||||||
void pxl8_cmdbuf_destroy(pxl8_gfx_cmdbuf* cb);
|
|
||||||
void pxl8_cmdbuf_reset(pxl8_gfx_cmdbuf* cb);
|
|
||||||
|
|
||||||
void pxl8_begin_pass(pxl8_gfx_cmdbuf* cb, pxl8_gfx_pass pass);
|
|
||||||
void pxl8_cmdbuf_clear_depth(pxl8_gfx_cmdbuf* cb, pxl8_gfx_texture texture);
|
|
||||||
void pxl8_end_pass(pxl8_gfx_cmdbuf* cb);
|
|
||||||
void pxl8_set_bindings(pxl8_gfx_cmdbuf* cb, pxl8_gfx_bindings bindings);
|
|
||||||
void pxl8_set_draw_params(pxl8_gfx_cmdbuf* cb, const pxl8_gfx_cmd_draw_params* p);
|
|
||||||
void pxl8_set_pipeline(pxl8_gfx_cmdbuf* cb, pxl8_gfx_pipeline pipeline);
|
|
||||||
void pxl8_set_scissor(pxl8_gfx_cmdbuf* cb, i32 x, i32 y, u32 w, u32 h);
|
|
||||||
void pxl8_set_viewport(pxl8_gfx_cmdbuf* cb, i32 x, i32 y, u32 w, u32 h);
|
|
||||||
void pxl8_draw(pxl8_gfx_cmdbuf* cb, pxl8_gfx_buffer vb, pxl8_gfx_buffer ib, u32 first, u32 count, u32 base_vertex);
|
|
||||||
|
|
||||||
void pxl8_gfx_submit(pxl8_renderer* r, pxl8_gfx_cmdbuf* cb);
|
|
||||||
|
|
||||||
void pxl8_clear(pxl8_renderer* r, pxl8_gfx_texture target, u8 color);
|
|
||||||
void pxl8_clear_depth(pxl8_renderer* r, pxl8_gfx_texture target);
|
|
||||||
void pxl8_clear_stencil(pxl8_renderer* r, u8 value);
|
|
||||||
|
|
||||||
void pxl8_draw_pixel(pxl8_renderer* r, pxl8_gfx_texture target, i32 x, i32 y, u8 color);
|
|
||||||
u8 pxl8_get_pixel(pxl8_renderer* r, pxl8_gfx_texture target, i32 x, i32 y);
|
|
||||||
void pxl8_draw_line(pxl8_renderer* r, pxl8_gfx_texture target, i32 x0, i32 y0, i32 x1, i32 y1, u8 color);
|
|
||||||
void pxl8_draw_rect(pxl8_renderer* r, pxl8_gfx_texture target, i32 x, i32 y, i32 w, i32 h, u8 color);
|
|
||||||
void pxl8_draw_rect_fill(pxl8_renderer* r, pxl8_gfx_texture target, i32 x, i32 y, i32 w, i32 h, u8 color);
|
|
||||||
void pxl8_draw_circle(pxl8_renderer* r, pxl8_gfx_texture target, i32 cx, i32 cy, i32 radius, u8 color);
|
|
||||||
void pxl8_draw_circle_fill(pxl8_renderer* r, pxl8_gfx_texture target, i32 cx, i32 cy, i32 radius, u8 color);
|
|
||||||
|
|
||||||
void pxl8_resolve_to_rgba(pxl8_renderer* r, pxl8_gfx_texture color, const u32* palette, u32* output);
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
@ -12,7 +12,6 @@ local procgen = require("pxl8.procgen")
|
||||||
local sfx = require("pxl8.sfx")
|
local sfx = require("pxl8.sfx")
|
||||||
local tilemap = require("pxl8.tilemap")
|
local tilemap = require("pxl8.tilemap")
|
||||||
local transition = require("pxl8.transition")
|
local transition = require("pxl8.transition")
|
||||||
local world = require("pxl8.world")
|
|
||||||
local pxl8 = {}
|
local pxl8 = {}
|
||||||
|
|
||||||
core.init(pxl8_gfx, pxl8_input, pxl8_rng, pxl8_sfx, pxl8_sys)
|
core.init(pxl8_gfx, pxl8_input, pxl8_rng, pxl8_sfx, pxl8_sys)
|
||||||
|
|
@ -149,7 +148,7 @@ pxl8.mat4_rotate_z = math.mat4_rotate_z
|
||||||
pxl8.mat4_scale = math.mat4_scale
|
pxl8.mat4_scale = math.mat4_scale
|
||||||
pxl8.mat4_translate = math.mat4_translate
|
pxl8.mat4_translate = math.mat4_translate
|
||||||
|
|
||||||
pxl8.get_net = net.get
|
pxl8.net = net
|
||||||
|
|
||||||
pxl8.pack_f32_be = bytes.pack_f32_be
|
pxl8.pack_f32_be = bytes.pack_f32_be
|
||||||
pxl8.pack_f32_le = bytes.pack_f32_le
|
pxl8.pack_f32_le = bytes.pack_f32_le
|
||||||
|
|
@ -251,14 +250,4 @@ pxl8.STENCIL_NOTEQUAL = 5
|
||||||
pxl8.STENCIL_GEQUAL = 6
|
pxl8.STENCIL_GEQUAL = 6
|
||||||
pxl8.STENCIL_ALWAYS = 7
|
pxl8.STENCIL_ALWAYS = 7
|
||||||
|
|
||||||
pxl8.Bsp = world.Bsp
|
|
||||||
pxl8.Chunk = world.Chunk
|
|
||||||
pxl8.World = world.World
|
|
||||||
pxl8.get_world = world.World.get
|
|
||||||
pxl8.sim_config = world.sim_config
|
|
||||||
pxl8.sim_move_player = world.sim_move_player
|
|
||||||
pxl8.sim_trace = world.sim_trace
|
|
||||||
pxl8.sim_check_ground = world.sim_check_ground
|
|
||||||
pxl8.make_input_msg = world.make_input_msg
|
|
||||||
|
|
||||||
return pxl8
|
return pxl8
|
||||||
|
|
|
||||||
|
|
@ -109,7 +109,7 @@ local Camera3D = {}
|
||||||
Camera3D.__index = Camera3D
|
Camera3D.__index = Camera3D
|
||||||
|
|
||||||
function Camera3D.new()
|
function Camera3D.new()
|
||||||
local cam = C.pxl8_3d_camera_create()
|
local cam = C.pxl8_camera3d_create()
|
||||||
if cam == nil then
|
if cam == nil then
|
||||||
return nil
|
return nil
|
||||||
end
|
end
|
||||||
|
|
@ -118,37 +118,37 @@ end
|
||||||
|
|
||||||
function Camera3D:destroy()
|
function Camera3D:destroy()
|
||||||
if self._ptr then
|
if self._ptr then
|
||||||
C.pxl8_3d_camera_destroy(self._ptr)
|
C.pxl8_camera3d_destroy(self._ptr)
|
||||||
self._ptr = nil
|
self._ptr = nil
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
function Camera3D:get_forward()
|
function Camera3D:get_forward()
|
||||||
local v = C.pxl8_3d_camera_get_forward(self._ptr)
|
local v = C.pxl8_camera3d_get_forward(self._ptr)
|
||||||
return {v.x, v.y, v.z}
|
return {v.x, v.y, v.z}
|
||||||
end
|
end
|
||||||
|
|
||||||
function Camera3D:get_position()
|
function Camera3D:get_position()
|
||||||
local v = C.pxl8_3d_camera_get_position(self._ptr)
|
local v = C.pxl8_camera3d_get_position(self._ptr)
|
||||||
return {v.x, v.y, v.z}
|
return {v.x, v.y, v.z}
|
||||||
end
|
end
|
||||||
|
|
||||||
function Camera3D:get_right()
|
function Camera3D:get_right()
|
||||||
local v = C.pxl8_3d_camera_get_right(self._ptr)
|
local v = C.pxl8_camera3d_get_right(self._ptr)
|
||||||
return {v.x, v.y, v.z}
|
return {v.x, v.y, v.z}
|
||||||
end
|
end
|
||||||
|
|
||||||
function Camera3D:get_up()
|
function Camera3D:get_up()
|
||||||
local v = C.pxl8_3d_camera_get_up(self._ptr)
|
local v = C.pxl8_camera3d_get_up(self._ptr)
|
||||||
return {v.x, v.y, v.z}
|
return {v.x, v.y, v.z}
|
||||||
end
|
end
|
||||||
|
|
||||||
function Camera3D:get_view()
|
function Camera3D:get_view()
|
||||||
return C.pxl8_3d_camera_get_view(self._ptr)
|
return C.pxl8_camera3d_get_view(self._ptr)
|
||||||
end
|
end
|
||||||
|
|
||||||
function Camera3D:get_projection()
|
function Camera3D:get_projection()
|
||||||
return C.pxl8_3d_camera_get_projection(self._ptr)
|
return C.pxl8_camera3d_get_projection(self._ptr)
|
||||||
end
|
end
|
||||||
|
|
||||||
function Camera3D:lookat(eye, target, up)
|
function Camera3D:lookat(eye, target, up)
|
||||||
|
|
@ -156,29 +156,29 @@ function Camera3D:lookat(eye, target, up)
|
||||||
local eye_vec = ffi.new("pxl8_vec3", {x = eye[1], y = eye[2], z = eye[3]})
|
local eye_vec = ffi.new("pxl8_vec3", {x = eye[1], y = eye[2], z = eye[3]})
|
||||||
local target_vec = ffi.new("pxl8_vec3", {x = target[1], y = target[2], z = target[3]})
|
local target_vec = ffi.new("pxl8_vec3", {x = target[1], y = target[2], z = target[3]})
|
||||||
local up_vec = ffi.new("pxl8_vec3", {x = up[1], y = up[2], z = up[3]})
|
local up_vec = ffi.new("pxl8_vec3", {x = up[1], y = up[2], z = up[3]})
|
||||||
C.pxl8_3d_camera_lookat(self._ptr, eye_vec, target_vec, up_vec)
|
C.pxl8_camera3d_lookat(self._ptr, eye_vec, target_vec, up_vec)
|
||||||
end
|
end
|
||||||
|
|
||||||
function Camera3D:set_perspective(fov, aspect, near, far)
|
function Camera3D:set_perspective(fov, aspect, near, far)
|
||||||
C.pxl8_3d_camera_set_perspective(self._ptr, fov, aspect, near, far)
|
C.pxl8_camera3d_set_perspective(self._ptr, fov, aspect, near, far)
|
||||||
end
|
end
|
||||||
|
|
||||||
function Camera3D:set_position(x, y, z)
|
function Camera3D:set_position(x, y, z)
|
||||||
local pos = ffi.new("pxl8_vec3", {x = x, y = y, z = z})
|
local pos = ffi.new("pxl8_vec3", {x = x, y = y, z = z})
|
||||||
C.pxl8_3d_camera_set_position(self._ptr, pos)
|
C.pxl8_camera3d_set_position(self._ptr, pos)
|
||||||
end
|
end
|
||||||
|
|
||||||
function Camera3D:set_rotation(pitch, yaw, roll)
|
function Camera3D:set_rotation(pitch, yaw, roll)
|
||||||
C.pxl8_3d_camera_set_rotation(self._ptr, pitch, yaw or 0, roll or 0)
|
C.pxl8_camera3d_set_rotation(self._ptr, pitch, yaw or 0, roll or 0)
|
||||||
end
|
end
|
||||||
|
|
||||||
function Camera3D:update(dt)
|
function Camera3D:update(dt)
|
||||||
C.pxl8_3d_camera_update(self._ptr, dt)
|
C.pxl8_camera3d_update(self._ptr, dt)
|
||||||
end
|
end
|
||||||
|
|
||||||
function Camera3D:world_to_screen(x, y, z, width, height)
|
function Camera3D:world_to_screen(x, y, z, width, height)
|
||||||
local pos = ffi.new("pxl8_vec3", {x = x, y = y, z = z})
|
local pos = ffi.new("pxl8_vec3", {x = x, y = y, z = z})
|
||||||
local result = C.pxl8_3d_camera_world_to_screen(self._ptr, pos, width, height)
|
local result = C.pxl8_camera3d_world_to_screen(self._ptr, pos, width, height)
|
||||||
if result.visible then
|
if result.visible then
|
||||||
return {x = result.x, y = result.y, depth = result.depth}
|
return {x = result.x, y = result.y, depth = result.depth}
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -1,51 +1,41 @@
|
||||||
local ffi = require("ffi")
|
local ffi = require("ffi")
|
||||||
local C = ffi.C
|
local C = ffi.C
|
||||||
local core = require("pxl8.core")
|
|
||||||
|
|
||||||
local net = {}
|
local net = {}
|
||||||
|
|
||||||
local Net = {}
|
local Net = {}
|
||||||
Net.__index = Net
|
Net.__index = Net
|
||||||
|
|
||||||
function net.get()
|
function net.create(config)
|
||||||
local ptr = C.pxl8_get_net(core.sys)
|
local cfg = ffi.new("pxl8_net_config")
|
||||||
|
cfg.address = config.address or "127.0.0.1"
|
||||||
|
cfg.port = config.port or 7777
|
||||||
|
local ptr = C.pxl8_net_create(cfg)
|
||||||
if ptr == nil then
|
if ptr == nil then
|
||||||
return nil
|
return nil
|
||||||
end
|
end
|
||||||
return setmetatable({ _ptr = ptr }, Net)
|
return setmetatable({ _ptr = ptr }, Net)
|
||||||
end
|
end
|
||||||
|
|
||||||
function Net:chunk_cx()
|
function Net:destroy()
|
||||||
return C.pxl8_net_chunk_cx(self._ptr)
|
C.pxl8_net_destroy(self._ptr)
|
||||||
|
self._ptr = nil
|
||||||
end
|
end
|
||||||
|
|
||||||
function Net:chunk_cz()
|
function Net:connect()
|
||||||
return C.pxl8_net_chunk_cz(self._ptr)
|
return C.pxl8_net_connect(self._ptr) == 0
|
||||||
end
|
|
||||||
|
|
||||||
function Net:has_chunk()
|
|
||||||
return C.pxl8_net_has_chunk(self._ptr)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
function Net:connected()
|
function Net:connected()
|
||||||
return C.pxl8_net_connected(self._ptr)
|
return C.pxl8_net_connected(self._ptr)
|
||||||
end
|
end
|
||||||
|
|
||||||
function Net:send_input(input)
|
function Net:disconnect()
|
||||||
local msg = ffi.new("pxl8_input_msg")
|
C.pxl8_net_disconnect(self._ptr)
|
||||||
msg.buttons = input.buttons or 0
|
|
||||||
msg.look_dx = input.look_dx or 0
|
|
||||||
msg.look_dy = input.look_dy or 0
|
|
||||||
msg.move_x = input.move_x or 0
|
|
||||||
msg.move_y = input.move_y or 0
|
|
||||||
msg.yaw = input.yaw or 0
|
|
||||||
msg.tick = input.tick or 0
|
|
||||||
msg.timestamp = input.timestamp or 0
|
|
||||||
return C.pxl8_net_send_input(self._ptr, msg) == 0
|
|
||||||
end
|
end
|
||||||
|
|
||||||
function Net:spawn(x, y, z, yaw, pitch)
|
function Net:poll()
|
||||||
return C.pxl8_net_spawn(self._ptr, x or 0, y or 0, z or 0, yaw or 0, pitch or 0) == 0
|
return C.pxl8_net_poll(self._ptr)
|
||||||
end
|
end
|
||||||
|
|
||||||
return net
|
return net
|
||||||
|
|
|
||||||
|
|
@ -3,18 +3,15 @@
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
#include "pxl8_hal.h"
|
#include "pxl8_platform.h"
|
||||||
|
|
||||||
#ifdef PXL8_ASYNC_THREADS
|
#ifdef PXL8_ASYNC_THREADS
|
||||||
#include <stdatomic.h>
|
#include <stdatomic.h>
|
||||||
#include "pxl8_queue.h"
|
#include "pxl8_queue.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "pxl8_bytes.h"
|
|
||||||
#include "pxl8_log.h"
|
#include "pxl8_log.h"
|
||||||
#include "pxl8_mem.h"
|
#include "pxl8_mem.h"
|
||||||
#include "pxl8_world.h"
|
|
||||||
#include "pxl8_world_chunk_cache.h"
|
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
#define WIN32_LEAN_AND_MEAN
|
#define WIN32_LEAN_AND_MEAN
|
||||||
|
|
@ -37,7 +34,6 @@
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define PXL8_NET_DEFAULT_PORT 7777
|
#define PXL8_NET_DEFAULT_PORT 7777
|
||||||
#define PXL8_NET_TICK_RATE 30.0f
|
|
||||||
|
|
||||||
struct pxl8_net {
|
struct pxl8_net {
|
||||||
char address[256];
|
char address[256];
|
||||||
|
|
@ -46,27 +42,6 @@ struct pxl8_net {
|
||||||
struct sockaddr_in server_addr;
|
struct sockaddr_in server_addr;
|
||||||
socket_t sock;
|
socket_t sock;
|
||||||
|
|
||||||
pxl8_world_chunk_cache* chunk_cache;
|
|
||||||
i32 chunk_cx;
|
|
||||||
i32 chunk_cz;
|
|
||||||
bool has_chunk;
|
|
||||||
pxl8_world* world;
|
|
||||||
|
|
||||||
u64 highest_tick;
|
|
||||||
f32 interp_time;
|
|
||||||
|
|
||||||
pxl8_entity_state entities[PXL8_MAX_SNAPSHOT_ENTITIES];
|
|
||||||
pxl8_entity_state prev_entities[PXL8_MAX_SNAPSHOT_ENTITIES];
|
|
||||||
pxl8_snapshot_header prev_snapshot;
|
|
||||||
pxl8_snapshot_header snapshot;
|
|
||||||
|
|
||||||
u64 input_head;
|
|
||||||
pxl8_input_msg input_history[PXL8_NET_INPUT_HISTORY_SIZE];
|
|
||||||
u64 input_oldest_tick;
|
|
||||||
|
|
||||||
u8 predicted_state[PXL8_NET_USERDATA_SIZE];
|
|
||||||
u64 predicted_tick;
|
|
||||||
|
|
||||||
u8 recv_buf[4096];
|
u8 recv_buf[4096];
|
||||||
u8 send_buf[4096];
|
u8 send_buf[4096];
|
||||||
|
|
||||||
|
|
@ -77,13 +52,6 @@ struct pxl8_net {
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
static const pxl8_entity_state* find_entity(const pxl8_entity_state* entities, u16 count, u64 id) {
|
|
||||||
for (u16 i = 0; i < count; i++) {
|
|
||||||
if (entities[i].entity_id == id) return &entities[i];
|
|
||||||
}
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
pxl8_result pxl8_net_connect(pxl8_net* net) {
|
pxl8_result pxl8_net_connect(pxl8_net* net) {
|
||||||
if (!net) return PXL8_ERROR_INVALID_ARGUMENT;
|
if (!net) return PXL8_ERROR_INVALID_ARGUMENT;
|
||||||
if (net->connected) return PXL8_OK;
|
if (net->connected) return PXL8_OK;
|
||||||
|
|
@ -161,154 +129,11 @@ void pxl8_net_disconnect(pxl8_net* net) {
|
||||||
net->connected = false;
|
net->connected = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
const pxl8_entity_state* pxl8_net_entities(const pxl8_net* net) {
|
|
||||||
if (!net) return NULL;
|
|
||||||
return net->entities;
|
|
||||||
}
|
|
||||||
|
|
||||||
const u8* pxl8_net_entity_prev_userdata(const pxl8_net* net, u64 entity_id) {
|
|
||||||
if (!net) return NULL;
|
|
||||||
const pxl8_entity_state* e = find_entity(net->prev_entities, net->prev_snapshot.entity_count, entity_id);
|
|
||||||
return e ? e->userdata : NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
const u8* pxl8_net_entity_userdata(const pxl8_net* net, u64 entity_id) {
|
|
||||||
if (!net) return NULL;
|
|
||||||
const pxl8_entity_state* e = find_entity(net->entities, net->snapshot.entity_count, entity_id);
|
|
||||||
return e ? e->userdata : NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
const pxl8_input_msg* pxl8_net_input_at(const pxl8_net* net, u64 tick) {
|
|
||||||
if (!net) return NULL;
|
|
||||||
for (u64 i = 0; i < PXL8_NET_INPUT_HISTORY_SIZE; i++) {
|
|
||||||
if (net->input_history[i].tick == tick) {
|
|
||||||
return &net->input_history[i];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
u64 pxl8_net_input_oldest_tick(const pxl8_net* net) {
|
|
||||||
if (!net) return 0;
|
|
||||||
return net->input_oldest_tick;
|
|
||||||
}
|
|
||||||
|
|
||||||
void pxl8_net_input_push(pxl8_net* net, const pxl8_input_msg* input) {
|
|
||||||
if (!net || !input) return;
|
|
||||||
u64 idx = net->input_head % PXL8_NET_INPUT_HISTORY_SIZE;
|
|
||||||
net->input_history[idx] = *input;
|
|
||||||
net->input_head++;
|
|
||||||
if (net->input_oldest_tick == 0 || input->tick < net->input_oldest_tick) {
|
|
||||||
net->input_oldest_tick = input->tick;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
f32 pxl8_net_lerp_alpha(const pxl8_net* net) {
|
|
||||||
if (!net) return 1.0f;
|
|
||||||
f32 tick_duration = 1.0f / PXL8_NET_TICK_RATE;
|
|
||||||
f32 alpha = net->interp_time / tick_duration;
|
|
||||||
return alpha > 1.0f ? 1.0f : alpha;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool pxl8_net_needs_correction(const pxl8_net* net) {
|
|
||||||
if (!net) return false;
|
|
||||||
if (net->snapshot.tick == 0) return false;
|
|
||||||
if (net->predicted_tick == 0) return false;
|
|
||||||
if (net->snapshot.tick > net->predicted_tick) return true;
|
|
||||||
const u8* server = pxl8_net_entity_userdata(net, net->snapshot.player_id);
|
|
||||||
if (!server) return false;
|
|
||||||
return memcmp(server, net->predicted_state, PXL8_NET_USERDATA_SIZE) != 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
u64 pxl8_net_player_id(const pxl8_net* net) {
|
|
||||||
if (!net) return 0;
|
|
||||||
return net->snapshot.player_id;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool dispatch_message(pxl8_net* net, const u8* data, usize len) {
|
|
||||||
if (len < sizeof(pxl8_msg_header)) return false;
|
|
||||||
|
|
||||||
pxl8_msg_header hdr;
|
|
||||||
usize offset = pxl8_protocol_deserialize_header(data, len, &hdr);
|
|
||||||
|
|
||||||
if (hdr.type == PXL8_MSG_CHUNK) {
|
|
||||||
if (!net->chunk_cache) return false;
|
|
||||||
|
|
||||||
pxl8_chunk_msg_header chunk_hdr;
|
|
||||||
offset += pxl8_protocol_deserialize_chunk_msg_header(data + offset, len - offset, &chunk_hdr);
|
|
||||||
|
|
||||||
const u8* payload = data + offset;
|
|
||||||
usize payload_len = chunk_hdr.payload_size;
|
|
||||||
if (payload_len > len - offset) {
|
|
||||||
payload_len = len - offset;
|
|
||||||
}
|
|
||||||
|
|
||||||
pxl8_world_chunk_cache_receive(net->chunk_cache, &chunk_hdr, payload, payload_len);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (hdr.type == PXL8_MSG_CHUNK_ENTER) {
|
|
||||||
pxl8_chunk_enter_msg chunk_msg;
|
|
||||||
pxl8_protocol_deserialize_chunk_enter(data + offset, len - offset, &chunk_msg);
|
|
||||||
net->chunk_cx = chunk_msg.cx;
|
|
||||||
net->chunk_cz = chunk_msg.cz;
|
|
||||||
net->has_chunk = true;
|
|
||||||
pxl8_debug("[CLIENT] Received CHUNK_ENTER cx=%d cz=%d", chunk_msg.cx, chunk_msg.cz);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (hdr.type == PXL8_MSG_CHUNK_EXIT) {
|
|
||||||
net->has_chunk = false;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (hdr.type != PXL8_MSG_SNAPSHOT) return false;
|
|
||||||
|
|
||||||
pxl8_snapshot_header snap;
|
|
||||||
offset += pxl8_protocol_deserialize_snapshot_header(data + offset, len - offset, &snap);
|
|
||||||
|
|
||||||
if (snap.tick <= net->highest_tick) return false;
|
|
||||||
|
|
||||||
memcpy(net->prev_entities, net->entities, sizeof(net->entities));
|
|
||||||
net->prev_snapshot = net->snapshot;
|
|
||||||
|
|
||||||
net->highest_tick = snap.tick;
|
|
||||||
net->snapshot = snap;
|
|
||||||
net->interp_time = 0.0f;
|
|
||||||
|
|
||||||
u16 count = snap.entity_count;
|
|
||||||
if (count > PXL8_MAX_SNAPSHOT_ENTITIES) count = PXL8_MAX_SNAPSHOT_ENTITIES;
|
|
||||||
|
|
||||||
for (u16 i = 0; i < count; i++) {
|
|
||||||
offset += pxl8_protocol_deserialize_entity_state(
|
|
||||||
data + offset, len - offset, &net->entities[i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool pxl8_net_poll(pxl8_net* net) {
|
bool pxl8_net_poll(pxl8_net* net) {
|
||||||
if (!net || !net->connected) return false;
|
if (!net || !net->connected) return false;
|
||||||
|
|
||||||
usize len = pxl8_net_recv(net, net->recv_buf, sizeof(net->recv_buf));
|
usize len = pxl8_net_recv(net, net->recv_buf, sizeof(net->recv_buf));
|
||||||
u64 prev_tick = net->highest_tick;
|
return len > 0;
|
||||||
if (!dispatch_message(net, net->recv_buf, len)) return false;
|
|
||||||
|
|
||||||
if (net->highest_tick > prev_tick && net->world) {
|
|
||||||
pxl8_world_reconcile(net->world, net, 1.0f / 30.0f);
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
u8* pxl8_net_predicted_state(pxl8_net* net) {
|
|
||||||
if (!net) return NULL;
|
|
||||||
return net->predicted_state;
|
|
||||||
}
|
|
||||||
|
|
||||||
void pxl8_net_predicted_tick_set(pxl8_net* net, u64 tick) {
|
|
||||||
if (!net) return;
|
|
||||||
net->predicted_tick = tick;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
usize pxl8_net_recv(pxl8_net* net, u8* buf, usize len) {
|
usize pxl8_net_recv(pxl8_net* net, u8* buf, usize len) {
|
||||||
|
|
@ -330,103 +155,6 @@ pxl8_result pxl8_net_send(pxl8_net* net, const u8* data, usize len) {
|
||||||
return (sent > 0) ? PXL8_OK : PXL8_ERROR_SYSTEM_FAILURE;
|
return (sent > 0) ? PXL8_OK : PXL8_ERROR_SYSTEM_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
pxl8_result pxl8_net_send_command(pxl8_net* net, const pxl8_command_msg* cmd) {
|
|
||||||
if (!net || !net->connected) return PXL8_ERROR_INVALID_ARGUMENT;
|
|
||||||
|
|
||||||
u8 buf[sizeof(pxl8_msg_header) + sizeof(pxl8_command_msg)];
|
|
||||||
pxl8_msg_header hdr = {
|
|
||||||
.type = PXL8_MSG_COMMAND,
|
|
||||||
.version = PXL8_PROTOCOL_VERSION,
|
|
||||||
.size = sizeof(pxl8_command_msg),
|
|
||||||
.sequence = 0
|
|
||||||
};
|
|
||||||
|
|
||||||
usize offset = pxl8_protocol_serialize_header(&hdr, buf, sizeof(buf));
|
|
||||||
offset += pxl8_protocol_serialize_command(cmd, buf + offset, sizeof(buf) - offset);
|
|
||||||
|
|
||||||
return pxl8_net_send(net, buf, offset);
|
|
||||||
}
|
|
||||||
|
|
||||||
pxl8_result pxl8_net_send_input(pxl8_net* net, const pxl8_input_msg* input) {
|
|
||||||
if (!net || !net->connected) return PXL8_ERROR_INVALID_ARGUMENT;
|
|
||||||
|
|
||||||
pxl8_net_input_push(net, input);
|
|
||||||
|
|
||||||
u8 buf[sizeof(pxl8_msg_header) + sizeof(pxl8_input_msg)];
|
|
||||||
pxl8_msg_header hdr = {
|
|
||||||
.type = PXL8_MSG_INPUT,
|
|
||||||
.version = PXL8_PROTOCOL_VERSION,
|
|
||||||
.size = sizeof(pxl8_input_msg),
|
|
||||||
.sequence = 0
|
|
||||||
};
|
|
||||||
|
|
||||||
usize offset = pxl8_protocol_serialize_header(&hdr, buf, sizeof(buf));
|
|
||||||
offset += pxl8_protocol_serialize_input(input, buf + offset, sizeof(buf) - offset);
|
|
||||||
|
|
||||||
return pxl8_net_send(net, buf, offset);
|
|
||||||
}
|
|
||||||
|
|
||||||
const pxl8_snapshot_header* pxl8_net_snapshot(const pxl8_net* net) {
|
|
||||||
if (!net) return NULL;
|
|
||||||
return &net->snapshot;
|
|
||||||
}
|
|
||||||
|
|
||||||
u64 pxl8_net_tick(const pxl8_net* net) {
|
|
||||||
if (!net) return 0;
|
|
||||||
return net->snapshot.tick;
|
|
||||||
}
|
|
||||||
|
|
||||||
void pxl8_net_update(pxl8_net* net, f32 dt) {
|
|
||||||
if (!net) return;
|
|
||||||
net->interp_time += dt;
|
|
||||||
}
|
|
||||||
|
|
||||||
void pxl8_net_set_chunk_cache(pxl8_net* net, pxl8_world_chunk_cache* cache) {
|
|
||||||
if (!net) return;
|
|
||||||
net->chunk_cache = cache;
|
|
||||||
}
|
|
||||||
|
|
||||||
pxl8_world_chunk_cache* pxl8_net_chunk_cache(pxl8_net* net) {
|
|
||||||
if (!net) return NULL;
|
|
||||||
return net->chunk_cache;
|
|
||||||
}
|
|
||||||
|
|
||||||
void pxl8_net_set_world(pxl8_net* net, pxl8_world* world) {
|
|
||||||
if (!net) return;
|
|
||||||
net->world = world;
|
|
||||||
}
|
|
||||||
|
|
||||||
i32 pxl8_net_chunk_cx(const pxl8_net* net) {
|
|
||||||
if (!net) return 0;
|
|
||||||
return net->chunk_cx;
|
|
||||||
}
|
|
||||||
|
|
||||||
i32 pxl8_net_chunk_cz(const pxl8_net* net) {
|
|
||||||
if (!net) return 0;
|
|
||||||
return net->chunk_cz;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool pxl8_net_has_chunk(const pxl8_net* net) {
|
|
||||||
if (!net) return false;
|
|
||||||
return net->has_chunk;
|
|
||||||
}
|
|
||||||
|
|
||||||
pxl8_result pxl8_net_spawn(pxl8_net* net, f32 x, f32 y, f32 z, f32 yaw, f32 pitch) {
|
|
||||||
if (!net) return PXL8_ERROR_NULL_POINTER;
|
|
||||||
if (!net->connected) return PXL8_ERROR_NOT_CONNECTED;
|
|
||||||
|
|
||||||
pxl8_command_msg cmd = {0};
|
|
||||||
cmd.cmd_type = PXL8_CMD_SPAWN_ENTITY;
|
|
||||||
pxl8_pack_f32_be(cmd.payload, 0, x);
|
|
||||||
pxl8_pack_f32_be(cmd.payload, 4, y);
|
|
||||||
pxl8_pack_f32_be(cmd.payload, 8, z);
|
|
||||||
pxl8_pack_f32_be(cmd.payload, 12, yaw);
|
|
||||||
pxl8_pack_f32_be(cmd.payload, 16, pitch);
|
|
||||||
cmd.payload_size = 20;
|
|
||||||
|
|
||||||
return pxl8_net_send_command(net, &cmd);
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef PXL8_ASYNC_THREADS
|
#ifdef PXL8_ASYNC_THREADS
|
||||||
|
|
||||||
static int pxl8_net_recv_thread(void* data) {
|
static int pxl8_net_recv_thread(void* data) {
|
||||||
|
|
@ -494,7 +222,9 @@ void pxl8_net_packet_free(pxl8_packet* pkt) {
|
||||||
|
|
||||||
bool pxl8_net_process_packet(pxl8_net* net, const pxl8_packet* pkt) {
|
bool pxl8_net_process_packet(pxl8_net* net, const pxl8_packet* pkt) {
|
||||||
if (!net || !pkt) return false;
|
if (!net || !pkt) return false;
|
||||||
return dispatch_message(net, pkt->data, pkt->len);
|
(void)net;
|
||||||
|
(void)pkt;
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -1,19 +1,14 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "pxl8_protocol.h"
|
|
||||||
#include "pxl8_types.h"
|
#include "pxl8_types.h"
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define PXL8_NET_INPUT_HISTORY_SIZE 64
|
|
||||||
#define PXL8_NET_USERDATA_SIZE 56
|
|
||||||
#define PXL8_NET_PACKET_MAX_SIZE 2048
|
#define PXL8_NET_PACKET_MAX_SIZE 2048
|
||||||
|
|
||||||
typedef struct pxl8_net pxl8_net;
|
typedef struct pxl8_net pxl8_net;
|
||||||
typedef struct pxl8_world pxl8_world;
|
|
||||||
typedef struct pxl8_world_chunk_cache pxl8_world_chunk_cache;
|
|
||||||
|
|
||||||
typedef struct pxl8_packet {
|
typedef struct pxl8_packet {
|
||||||
u8 data[PXL8_NET_PACKET_MAX_SIZE];
|
u8 data[PXL8_NET_PACKET_MAX_SIZE];
|
||||||
|
|
@ -30,34 +25,9 @@ bool pxl8_net_connected(const pxl8_net* net);
|
||||||
pxl8_net* pxl8_net_create(const pxl8_net_config* config);
|
pxl8_net* pxl8_net_create(const pxl8_net_config* config);
|
||||||
void pxl8_net_destroy(pxl8_net* net);
|
void pxl8_net_destroy(pxl8_net* net);
|
||||||
void pxl8_net_disconnect(pxl8_net* net);
|
void pxl8_net_disconnect(pxl8_net* net);
|
||||||
const pxl8_entity_state* pxl8_net_entities(const pxl8_net* net);
|
|
||||||
const u8* pxl8_net_entity_prev_userdata(const pxl8_net* net, u64 entity_id);
|
|
||||||
const u8* pxl8_net_entity_userdata(const pxl8_net* net, u64 entity_id);
|
|
||||||
const pxl8_input_msg* pxl8_net_input_at(const pxl8_net* net, u64 tick);
|
|
||||||
u64 pxl8_net_input_oldest_tick(const pxl8_net* net);
|
|
||||||
void pxl8_net_input_push(pxl8_net* net, const pxl8_input_msg* input);
|
|
||||||
f32 pxl8_net_lerp_alpha(const pxl8_net* net);
|
|
||||||
bool pxl8_net_needs_correction(const pxl8_net* net);
|
|
||||||
u64 pxl8_net_player_id(const pxl8_net* net);
|
|
||||||
bool pxl8_net_poll(pxl8_net* net);
|
bool pxl8_net_poll(pxl8_net* net);
|
||||||
u8* pxl8_net_predicted_state(pxl8_net* net);
|
|
||||||
void pxl8_net_predicted_tick_set(pxl8_net* net, u64 tick);
|
|
||||||
usize pxl8_net_recv(pxl8_net* net, u8* buf, usize len);
|
usize pxl8_net_recv(pxl8_net* net, u8* buf, usize len);
|
||||||
pxl8_result pxl8_net_send(pxl8_net* net, const u8* data, usize len);
|
pxl8_result pxl8_net_send(pxl8_net* net, const u8* data, usize len);
|
||||||
pxl8_result pxl8_net_send_command(pxl8_net* net, const pxl8_command_msg* cmd);
|
|
||||||
pxl8_result pxl8_net_send_input(pxl8_net* net, const pxl8_input_msg* input);
|
|
||||||
const pxl8_snapshot_header* pxl8_net_snapshot(const pxl8_net* net);
|
|
||||||
u64 pxl8_net_tick(const pxl8_net* net);
|
|
||||||
void pxl8_net_update(pxl8_net* net, f32 dt);
|
|
||||||
void pxl8_net_set_chunk_cache(pxl8_net* net, pxl8_world_chunk_cache* cache);
|
|
||||||
pxl8_world_chunk_cache* pxl8_net_chunk_cache(pxl8_net* net);
|
|
||||||
void pxl8_net_set_world(pxl8_net* net, pxl8_world* world);
|
|
||||||
|
|
||||||
i32 pxl8_net_chunk_cx(const pxl8_net* net);
|
|
||||||
i32 pxl8_net_chunk_cz(const pxl8_net* net);
|
|
||||||
bool pxl8_net_has_chunk(const pxl8_net* net);
|
|
||||||
|
|
||||||
pxl8_result pxl8_net_spawn(pxl8_net* net, f32 x, f32 y, f32 z, f32 yaw, f32 pitch);
|
|
||||||
|
|
||||||
#ifdef PXL8_ASYNC_THREADS
|
#ifdef PXL8_ASYNC_THREADS
|
||||||
void pxl8_net_start_thread(pxl8_net* net);
|
void pxl8_net_start_thread(pxl8_net* net);
|
||||||
|
|
|
||||||
|
|
@ -1,143 +0,0 @@
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include "pxl8_types.h"
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
extern "C" {
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define PXL8_PROTOCOL_VERSION 1
|
|
||||||
#define PXL8_MAX_SNAPSHOT_ENTITIES 256
|
|
||||||
#define PXL8_MAX_SNAPSHOT_EVENTS 32
|
|
||||||
#define PXL8_COMMAND_PAYLOAD_SIZE 64
|
|
||||||
#define PXL8_EVENT_PAYLOAD_SIZE 15
|
|
||||||
|
|
||||||
typedef enum pxl8_msg_type {
|
|
||||||
PXL8_MSG_NONE = 0,
|
|
||||||
PXL8_MSG_CHUNK,
|
|
||||||
PXL8_MSG_CHUNK_ENTER,
|
|
||||||
PXL8_MSG_CHUNK_EXIT,
|
|
||||||
PXL8_MSG_COMMAND,
|
|
||||||
PXL8_MSG_CONNECT,
|
|
||||||
PXL8_MSG_DISCONNECT,
|
|
||||||
PXL8_MSG_EVENT,
|
|
||||||
PXL8_MSG_INPUT,
|
|
||||||
PXL8_MSG_SNAPSHOT
|
|
||||||
} pxl8_msg_type;
|
|
||||||
|
|
||||||
typedef struct pxl8_msg_header {
|
|
||||||
u32 sequence;
|
|
||||||
u16 size;
|
|
||||||
u8 type;
|
|
||||||
u8 version;
|
|
||||||
} pxl8_msg_header;
|
|
||||||
|
|
||||||
typedef enum pxl8_cmd_type {
|
|
||||||
PXL8_CMD_NONE = 0,
|
|
||||||
PXL8_CMD_SPAWN_ENTITY,
|
|
||||||
} pxl8_cmd_type;
|
|
||||||
|
|
||||||
typedef struct pxl8_input_msg {
|
|
||||||
u32 buttons;
|
|
||||||
f32 look_dx;
|
|
||||||
f32 look_dy;
|
|
||||||
f32 move_x;
|
|
||||||
f32 move_y;
|
|
||||||
f32 yaw;
|
|
||||||
u64 tick;
|
|
||||||
u64 timestamp;
|
|
||||||
} pxl8_input_msg;
|
|
||||||
|
|
||||||
typedef struct pxl8_command_msg {
|
|
||||||
u16 cmd_type;
|
|
||||||
u8 payload[PXL8_COMMAND_PAYLOAD_SIZE];
|
|
||||||
u16 payload_size;
|
|
||||||
u64 tick;
|
|
||||||
} pxl8_command_msg;
|
|
||||||
|
|
||||||
typedef struct pxl8_entity_state {
|
|
||||||
u64 entity_id;
|
|
||||||
u8 userdata[56];
|
|
||||||
} pxl8_entity_state;
|
|
||||||
|
|
||||||
typedef struct pxl8_event_msg {
|
|
||||||
u8 event_type;
|
|
||||||
u8 payload[PXL8_EVENT_PAYLOAD_SIZE];
|
|
||||||
} pxl8_event_msg;
|
|
||||||
|
|
||||||
typedef struct pxl8_snapshot_header {
|
|
||||||
u16 entity_count;
|
|
||||||
u16 event_count;
|
|
||||||
u64 player_id;
|
|
||||||
u64 tick;
|
|
||||||
f32 time;
|
|
||||||
} pxl8_snapshot_header;
|
|
||||||
|
|
||||||
#define PXL8_CHUNK_TYPE_BSP 1
|
|
||||||
|
|
||||||
#define PXL8_CHUNK_FLAG_FINAL 0x04
|
|
||||||
#define PXL8_CHUNK_MAX_PAYLOAD 1400
|
|
||||||
|
|
||||||
typedef struct pxl8_chunk_msg_header {
|
|
||||||
u8 chunk_type;
|
|
||||||
u8 flags;
|
|
||||||
u8 fragment_idx;
|
|
||||||
u8 fragment_count;
|
|
||||||
u32 id;
|
|
||||||
i32 cx, cy, cz;
|
|
||||||
u32 version;
|
|
||||||
u16 payload_size;
|
|
||||||
u16 reserved;
|
|
||||||
} pxl8_chunk_msg_header;
|
|
||||||
|
|
||||||
typedef struct pxl8_bsp_wire_header {
|
|
||||||
u32 num_vertices;
|
|
||||||
u32 num_edges;
|
|
||||||
u32 num_faces;
|
|
||||||
u32 num_planes;
|
|
||||||
u32 num_nodes;
|
|
||||||
u32 num_leafs;
|
|
||||||
u32 num_surfedges;
|
|
||||||
u32 num_marksurfaces;
|
|
||||||
u32 num_cell_portals;
|
|
||||||
u32 visdata_size;
|
|
||||||
u32 num_vertex_lights;
|
|
||||||
u32 num_heightfield;
|
|
||||||
} pxl8_bsp_wire_header;
|
|
||||||
|
|
||||||
usize pxl8_protocol_serialize_header(const pxl8_msg_header* msg, u8* buf, usize len);
|
|
||||||
usize pxl8_protocol_deserialize_header(const u8* buf, usize len, pxl8_msg_header* msg);
|
|
||||||
|
|
||||||
usize pxl8_protocol_serialize_input(const pxl8_input_msg* msg, u8* buf, usize len);
|
|
||||||
usize pxl8_protocol_deserialize_input(const u8* buf, usize len, pxl8_input_msg* msg);
|
|
||||||
|
|
||||||
usize pxl8_protocol_serialize_command(const pxl8_command_msg* msg, u8* buf, usize len);
|
|
||||||
usize pxl8_protocol_deserialize_command(const u8* buf, usize len, pxl8_command_msg* msg);
|
|
||||||
|
|
||||||
usize pxl8_protocol_serialize_entity_state(const pxl8_entity_state* state, u8* buf, usize len);
|
|
||||||
usize pxl8_protocol_deserialize_entity_state(const u8* buf, usize len, pxl8_entity_state* state);
|
|
||||||
|
|
||||||
usize pxl8_protocol_serialize_event(const pxl8_event_msg* msg, u8* buf, usize len);
|
|
||||||
usize pxl8_protocol_deserialize_event(const u8* buf, usize len, pxl8_event_msg* msg);
|
|
||||||
|
|
||||||
usize pxl8_protocol_serialize_snapshot_header(const pxl8_snapshot_header* hdr, u8* buf, usize len);
|
|
||||||
usize pxl8_protocol_deserialize_snapshot_header(const u8* buf, usize len, pxl8_snapshot_header* hdr);
|
|
||||||
|
|
||||||
usize pxl8_protocol_serialize_chunk_msg_header(const pxl8_chunk_msg_header* hdr, u8* buf, usize len);
|
|
||||||
usize pxl8_protocol_deserialize_chunk_msg_header(const u8* buf, usize len, pxl8_chunk_msg_header* hdr);
|
|
||||||
|
|
||||||
usize pxl8_protocol_deserialize_bsp_wire_header(const u8* buf, usize len, pxl8_bsp_wire_header* hdr);
|
|
||||||
|
|
||||||
typedef struct pxl8_chunk_enter_msg {
|
|
||||||
i32 cx;
|
|
||||||
i32 cz;
|
|
||||||
} pxl8_chunk_enter_msg;
|
|
||||||
|
|
||||||
usize pxl8_protocol_serialize_chunk_enter(const pxl8_chunk_enter_msg* msg, u8* buf, usize len);
|
|
||||||
usize pxl8_protocol_deserialize_chunk_enter(const u8* buf, usize len, pxl8_chunk_enter_msg* msg);
|
|
||||||
|
|
||||||
u32 pxl8_chunk_hash(i32 cx, i32 cz);
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
@ -30,7 +30,7 @@ void pxl8_cond_wait(pxl8_cond* cond, pxl8_mutex* mutex);
|
||||||
u64 pxl8_get_ticks_ns(void);
|
u64 pxl8_get_ticks_ns(void);
|
||||||
void pxl8_sleep_ms(u32 ms);
|
void pxl8_sleep_ms(u32 ms);
|
||||||
|
|
||||||
typedef struct pxl8_hal {
|
typedef struct pxl8_platform {
|
||||||
void* (*create)(i32 render_w, i32 render_h,
|
void* (*create)(i32 render_w, i32 render_h,
|
||||||
const char* title, i32 win_w, i32 win_h);
|
const char* title, i32 win_w, i32 win_h);
|
||||||
void (*destroy)(void* platform_data);
|
void (*destroy)(void* platform_data);
|
||||||
|
|
@ -48,4 +48,4 @@ typedef struct pxl8_hal {
|
||||||
void (*audio_stop)(void* audio_handle);
|
void (*audio_stop)(void* audio_handle);
|
||||||
bool (*upload_audio)(void* audio_handle, const f32* stereo_samples, i32 sample_count);
|
bool (*upload_audio)(void* audio_handle, const f32* stereo_samples, i32 sample_count);
|
||||||
i32 (*audio_queued)(void* audio_handle);
|
i32 (*audio_queued)(void* audio_handle);
|
||||||
} pxl8_hal;
|
} pxl8_platform;
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
#include "pxl8_hal.h"
|
#include "pxl8_platform.h"
|
||||||
|
|
||||||
#define SDL_MAIN_USE_CALLBACKS
|
#define SDL_MAIN_USE_CALLBACKS
|
||||||
#include <SDL3/SDL.h>
|
#include <SDL3/SDL.h>
|
||||||
|
|
@ -8,7 +8,7 @@
|
||||||
#include "pxl8_log.h"
|
#include "pxl8_log.h"
|
||||||
#include "pxl8_sys.h"
|
#include "pxl8_sys.h"
|
||||||
|
|
||||||
extern const pxl8_hal pxl8_hal_sdl3;
|
extern const pxl8_platform pxl8_platform_sdl3;
|
||||||
|
|
||||||
typedef struct pxl8_sdl3_context {
|
typedef struct pxl8_sdl3_context {
|
||||||
SDL_Texture* framebuffer;
|
SDL_Texture* framebuffer;
|
||||||
|
|
@ -139,13 +139,15 @@ SDL_AppResult SDL_AppInit(void** appstate, int argc, char* argv[]) {
|
||||||
return SDL_APP_FAILURE;
|
return SDL_APP_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
pxl8* sys = pxl8_create(&pxl8_hal_sdl3);
|
pxl8* sys = pxl8_create(&pxl8_platform_sdl3);
|
||||||
if (!sys) {
|
if (!sys) {
|
||||||
pxl8_error("Failed to create pxl8 system");
|
pxl8_error("Failed to create pxl8 system");
|
||||||
SDL_Quit();
|
SDL_Quit();
|
||||||
return SDL_APP_FAILURE;
|
return SDL_APP_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pxl8_register_game(sys);
|
||||||
|
|
||||||
pxl8_result result = pxl8_init(sys, argc, argv);
|
pxl8_result result = pxl8_init(sys, argc, argv);
|
||||||
if (result != PXL8_OK) {
|
if (result != PXL8_OK) {
|
||||||
pxl8_destroy(sys);
|
pxl8_destroy(sys);
|
||||||
|
|
@ -395,7 +397,7 @@ static i32 sdl3_audio_queued(void* audio_handle) {
|
||||||
return bytes / (audio->channels * sizeof(f32));
|
return bytes / (audio->channels * sizeof(f32));
|
||||||
}
|
}
|
||||||
|
|
||||||
const pxl8_hal pxl8_hal_sdl3 = {
|
const pxl8_platform pxl8_platform_sdl3 = {
|
||||||
.create = sdl3_create,
|
.create = sdl3_create,
|
||||||
.destroy = sdl3_destroy,
|
.destroy = sdl3_destroy,
|
||||||
.get_ticks = sdl3_get_ticks,
|
.get_ticks = sdl3_get_ticks,
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
#include "pxl8_hal.h"
|
#include "pxl8_platform.h"
|
||||||
|
|
||||||
#include <SDL3/SDL.h>
|
#include <SDL3/SDL.h>
|
||||||
|
|
||||||
|
|
@ -21,6 +21,8 @@
|
||||||
#include "pxl8_mem.h"
|
#include "pxl8_mem.h"
|
||||||
#include "pxl8_script_ffi.h"
|
#include "pxl8_script_ffi.h"
|
||||||
|
|
||||||
|
#define PXL8_SCRIPT_MAX_FFI_EXTENSIONS 8
|
||||||
|
|
||||||
struct pxl8_script {
|
struct pxl8_script {
|
||||||
lua_State* L;
|
lua_State* L;
|
||||||
pxl8_gfx* gfx;
|
pxl8_gfx* gfx;
|
||||||
|
|
@ -32,6 +34,8 @@ struct pxl8_script {
|
||||||
f64 latest_mod_time;
|
f64 latest_mod_time;
|
||||||
int repl_env_ref;
|
int repl_env_ref;
|
||||||
bool repl_mode;
|
bool repl_mode;
|
||||||
|
const char* ffi_extensions[PXL8_SCRIPT_MAX_FFI_EXTENSIONS];
|
||||||
|
u32 ffi_extension_count;
|
||||||
};
|
};
|
||||||
|
|
||||||
#define PXL8_MAX_REPL_COMMAND_SIZE 4096
|
#define PXL8_MAX_REPL_COMMAND_SIZE 4096
|
||||||
|
|
@ -354,6 +358,33 @@ void pxl8_script_destroy(pxl8_script* script) {
|
||||||
pxl8_free(script);
|
pxl8_free(script);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void pxl8_script_add_ffi(pxl8_script* script, const char* cdefs) {
|
||||||
|
if (!script || !cdefs) return;
|
||||||
|
if (script->ffi_extension_count >= PXL8_SCRIPT_MAX_FFI_EXTENSIONS) return;
|
||||||
|
|
||||||
|
script->ffi_extensions[script->ffi_extension_count++] = cdefs;
|
||||||
|
|
||||||
|
if (script->L) {
|
||||||
|
lua_getglobal(script->L, "require");
|
||||||
|
lua_pushstring(script->L, "ffi");
|
||||||
|
if (lua_pcall(script->L, 1, 1, 0) != 0) {
|
||||||
|
pxl8_error("FFI require failed: %s", lua_tostring(script->L, -1));
|
||||||
|
lua_pop(script->L, 1);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
lua_getfield(script->L, -1, "cdef");
|
||||||
|
lua_pushstring(script->L, cdefs);
|
||||||
|
if (lua_pcall(script->L, 1, 0, 0) != 0) {
|
||||||
|
pxl8_error("FFI extension cdef failed: %s", lua_tostring(script->L, -1));
|
||||||
|
lua_pop(script->L, 1);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
lua_pop(script->L, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void pxl8_script_set_gfx(pxl8_script* script, pxl8_gfx* gfx) {
|
void pxl8_script_set_gfx(pxl8_script* script, pxl8_gfx* gfx) {
|
||||||
if (!script) return;
|
if (!script) return;
|
||||||
script->gfx = gfx;
|
script->gfx = gfx;
|
||||||
|
|
|
||||||
|
|
@ -13,6 +13,7 @@ extern "C" {
|
||||||
|
|
||||||
pxl8_script* pxl8_script_create(bool repl_mode);
|
pxl8_script* pxl8_script_create(bool repl_mode);
|
||||||
void pxl8_script_destroy(pxl8_script* script);
|
void pxl8_script_destroy(pxl8_script* script);
|
||||||
|
void pxl8_script_add_ffi(pxl8_script* script, const char* cdefs);
|
||||||
|
|
||||||
const char* pxl8_script_get_last_error(pxl8_script* script);
|
const char* pxl8_script_get_last_error(pxl8_script* script);
|
||||||
bool pxl8_script_is_incomplete_input(pxl8_script* script);
|
bool pxl8_script_is_incomplete_input(pxl8_script* script);
|
||||||
|
|
|
||||||
|
|
@ -238,27 +238,27 @@ static const char* pxl8_ffi_cdefs =
|
||||||
" f32 time;\n"
|
" f32 time;\n"
|
||||||
"} pxl8_3d_uniforms;\n"
|
"} pxl8_3d_uniforms;\n"
|
||||||
"\n"
|
"\n"
|
||||||
"typedef struct pxl8_3d_camera pxl8_3d_camera;\n"
|
"typedef struct pxl8_camera3d pxl8_camera3d;\n"
|
||||||
"pxl8_3d_camera* pxl8_3d_camera_create(void);\n"
|
"pxl8_camera3d* pxl8_camera3d_create(void);\n"
|
||||||
"void pxl8_3d_camera_destroy(pxl8_3d_camera* cam);\n"
|
"void pxl8_camera3d_destroy(pxl8_camera3d* cam);\n"
|
||||||
"void pxl8_3d_camera_set_perspective(pxl8_3d_camera* cam, f32 fov, f32 aspect, f32 near, f32 far);\n"
|
"void pxl8_camera3d_set_perspective(pxl8_camera3d* cam, f32 fov, f32 aspect, f32 near, f32 far);\n"
|
||||||
"void pxl8_3d_camera_set_position(pxl8_3d_camera* cam, pxl8_vec3 pos);\n"
|
"void pxl8_camera3d_set_position(pxl8_camera3d* cam, pxl8_vec3 pos);\n"
|
||||||
"void pxl8_3d_camera_set_rotation(pxl8_3d_camera* cam, f32 pitch, f32 yaw, f32 roll);\n"
|
"void pxl8_camera3d_set_rotation(pxl8_camera3d* cam, f32 pitch, f32 yaw, f32 roll);\n"
|
||||||
"void pxl8_3d_camera_lookat(pxl8_3d_camera* cam, pxl8_vec3 eye, pxl8_vec3 target, pxl8_vec3 up);\n"
|
"void pxl8_camera3d_lookat(pxl8_camera3d* cam, pxl8_vec3 eye, pxl8_vec3 target, pxl8_vec3 up);\n"
|
||||||
"pxl8_vec3 pxl8_3d_camera_get_forward(const pxl8_3d_camera* cam);\n"
|
"pxl8_vec3 pxl8_camera3d_get_forward(const pxl8_camera3d* cam);\n"
|
||||||
"pxl8_vec3 pxl8_3d_camera_get_position(const pxl8_3d_camera* cam);\n"
|
"pxl8_vec3 pxl8_camera3d_get_position(const pxl8_camera3d* cam);\n"
|
||||||
"pxl8_vec3 pxl8_3d_camera_get_right(const pxl8_3d_camera* cam);\n"
|
"pxl8_vec3 pxl8_camera3d_get_right(const pxl8_camera3d* cam);\n"
|
||||||
"pxl8_vec3 pxl8_3d_camera_get_up(const pxl8_3d_camera* cam);\n"
|
"pxl8_vec3 pxl8_camera3d_get_up(const pxl8_camera3d* cam);\n"
|
||||||
"pxl8_mat4 pxl8_3d_camera_get_view(const pxl8_3d_camera* cam);\n"
|
"pxl8_mat4 pxl8_camera3d_get_view(const pxl8_camera3d* cam);\n"
|
||||||
"pxl8_mat4 pxl8_3d_camera_get_projection(const pxl8_3d_camera* cam);\n"
|
"pxl8_mat4 pxl8_camera3d_get_projection(const pxl8_camera3d* cam);\n"
|
||||||
"void pxl8_3d_camera_update(pxl8_3d_camera* cam, f32 dt);\n"
|
"void pxl8_camera3d_update(pxl8_camera3d* cam, f32 dt);\n"
|
||||||
"typedef struct pxl8_projected_point { i32 x; i32 y; f32 depth; bool visible; } pxl8_projected_point;\n"
|
"typedef struct pxl8_projected_point { i32 x; i32 y; f32 depth; bool visible; } pxl8_projected_point;\n"
|
||||||
"pxl8_projected_point pxl8_3d_camera_world_to_screen(const pxl8_3d_camera* cam, pxl8_vec3 world_pos, u32 screen_width, u32 screen_height);\n"
|
"pxl8_projected_point pxl8_camera3d_world_to_screen(const pxl8_camera3d* cam, pxl8_vec3 world_pos, u32 screen_width, u32 screen_height);\n"
|
||||||
"\n"
|
"\n"
|
||||||
"void pxl8_gfx_blend_tables_update(pxl8_gfx* gfx);\n"
|
"void pxl8_gfx_blend_tables_update(pxl8_gfx* gfx);\n"
|
||||||
"void pxl8_gfx_colormap_update(pxl8_gfx* gfx);\n"
|
"void pxl8_gfx_colormap_update(pxl8_gfx* gfx);\n"
|
||||||
"\n"
|
"\n"
|
||||||
"void pxl8_3d_begin_frame(pxl8_gfx* gfx, const pxl8_3d_camera* camera, const pxl8_lights* lights, const pxl8_3d_uniforms* uniforms);\n"
|
"void pxl8_3d_begin_frame(pxl8_gfx* gfx, const pxl8_camera3d* camera, const pxl8_lights* lights, const pxl8_3d_uniforms* uniforms);\n"
|
||||||
"void pxl8_3d_clear(pxl8_gfx* gfx, u8 color);\n"
|
"void pxl8_3d_clear(pxl8_gfx* gfx, u8 color);\n"
|
||||||
"void pxl8_3d_clear_depth(pxl8_gfx* gfx);\n"
|
"void pxl8_3d_clear_depth(pxl8_gfx* gfx);\n"
|
||||||
"void pxl8_3d_clear_stencil(pxl8_gfx* gfx, uint8_t value);\n"
|
"void pxl8_3d_clear_stencil(pxl8_gfx* gfx, uint8_t value);\n"
|
||||||
|
|
@ -408,50 +408,6 @@ static const char* pxl8_ffi_cdefs =
|
||||||
"void pxl8_graph_set_seed(pxl8_graph* graph, u32 seed);\n"
|
"void pxl8_graph_set_seed(pxl8_graph* graph, u32 seed);\n"
|
||||||
"void pxl8_graph_eval_texture(const pxl8_graph* graph, u8* buffer, i32 width, i32 height);\n"
|
"void pxl8_graph_eval_texture(const pxl8_graph* graph, u8* buffer, i32 width, i32 height);\n"
|
||||||
"\n"
|
"\n"
|
||||||
"typedef struct pxl8_bsp pxl8_bsp;\n"
|
|
||||||
"\n"
|
|
||||||
"u32 pxl8_bsp_face_count(const pxl8_bsp* bsp);\n"
|
|
||||||
"pxl8_vec3 pxl8_bsp_face_normal(const pxl8_bsp* bsp, u32 face_id);\n"
|
|
||||||
"void pxl8_bsp_face_set_material(pxl8_bsp* bsp, u32 face_id, u16 material_id);\n"
|
|
||||||
"u8 pxl8_bsp_light_at(const pxl8_bsp* bsp, f32 x, f32 y, f32 z, u8 ambient);\n"
|
|
||||||
"\n"
|
|
||||||
"typedef struct pxl8_world_chunk {\n"
|
|
||||||
" u32 id;\n"
|
|
||||||
" u32 version;\n"
|
|
||||||
" pxl8_bsp* bsp;\n"
|
|
||||||
"} pxl8_world_chunk;\n"
|
|
||||||
"\n"
|
|
||||||
"typedef struct pxl8_world pxl8_world;\n"
|
|
||||||
"\n"
|
|
||||||
"typedef struct pxl8_ray {\n"
|
|
||||||
" pxl8_vec3 normal;\n"
|
|
||||||
" pxl8_vec3 point;\n"
|
|
||||||
" float fraction;\n"
|
|
||||||
" bool hit;\n"
|
|
||||||
"} pxl8_ray;\n"
|
|
||||||
"\n"
|
|
||||||
"pxl8_world* pxl8_get_world(pxl8* sys);\n"
|
|
||||||
"pxl8_world_chunk* pxl8_world_active_chunk(pxl8_world* world);\n"
|
|
||||||
"bool pxl8_world_point_solid(const pxl8_world* world, float x, float y, float z);\n"
|
|
||||||
"pxl8_ray pxl8_world_ray(const pxl8_world* world, pxl8_vec3 from, pxl8_vec3 to);\n"
|
|
||||||
"pxl8_ray pxl8_world_sweep(const pxl8_world* world, pxl8_vec3 from, pxl8_vec3 to, float radius);\n"
|
|
||||||
"void pxl8_world_render(pxl8_world* world, pxl8_gfx* gfx, pxl8_vec3 camera_pos);\n"
|
|
||||||
"void pxl8_world_set_bsp_material(pxl8_world* world, u16 material_id, const pxl8_gfx_material* material);\n"
|
|
||||||
"\n"
|
|
||||||
"typedef struct pxl8_sim_entity {\n"
|
|
||||||
" pxl8_vec3 pos;\n"
|
|
||||||
" pxl8_vec3 vel;\n"
|
|
||||||
" f32 yaw;\n"
|
|
||||||
" f32 pitch;\n"
|
|
||||||
" u32 flags;\n"
|
|
||||||
" u16 kind;\n"
|
|
||||||
" u16 _pad;\n"
|
|
||||||
"} pxl8_sim_entity;\n"
|
|
||||||
"\n"
|
|
||||||
"void pxl8_world_init_local_player(pxl8_world* world, f32 x, f32 y, f32 z);\n"
|
|
||||||
"void pxl8_world_set_look(pxl8_world* world, f32 yaw, f32 pitch);\n"
|
|
||||||
"pxl8_sim_entity* pxl8_world_local_player(pxl8_world* world);\n"
|
|
||||||
"\n"
|
|
||||||
"typedef struct { i32 cursor_x; i32 cursor_y; bool cursor_down; bool cursor_clicked; u32 hot_id; u32 active_id; } pxl8_gui_state;\n"
|
"typedef struct { i32 cursor_x; i32 cursor_y; bool cursor_down; bool cursor_clicked; u32 hot_id; u32 active_id; } pxl8_gui_state;\n"
|
||||||
"pxl8_gui_state* pxl8_gui_state_create(void);\n"
|
"pxl8_gui_state* pxl8_gui_state_create(void);\n"
|
||||||
"void pxl8_gui_state_destroy(pxl8_gui_state* state);\n"
|
"void pxl8_gui_state_destroy(pxl8_gui_state* state);\n"
|
||||||
|
|
@ -533,95 +489,12 @@ static const char* pxl8_ffi_cdefs =
|
||||||
"\n"
|
"\n"
|
||||||
"typedef struct pxl8_net pxl8_net;\n"
|
"typedef struct pxl8_net pxl8_net;\n"
|
||||||
"typedef struct pxl8_net_config { const char* address; u16 port; } pxl8_net_config;\n"
|
"typedef struct pxl8_net_config { const char* address; u16 port; } pxl8_net_config;\n"
|
||||||
"typedef enum pxl8_cmd_type { PXL8_CMD_NONE = 0, PXL8_CMD_SPAWN_ENTITY } pxl8_cmd_type;\n"
|
|
||||||
"\n"
|
|
||||||
"typedef struct pxl8_command_msg {\n"
|
|
||||||
" u16 cmd_type;\n"
|
|
||||||
" u8 payload[64];\n"
|
|
||||||
" u16 payload_size;\n"
|
|
||||||
" u64 tick;\n"
|
|
||||||
"} pxl8_command_msg;\n"
|
|
||||||
"\n"
|
|
||||||
"typedef struct pxl8_input_msg {\n"
|
|
||||||
" u32 buttons;\n"
|
|
||||||
" f32 look_dx;\n"
|
|
||||||
" f32 look_dy;\n"
|
|
||||||
" f32 move_x;\n"
|
|
||||||
" f32 move_y;\n"
|
|
||||||
" f32 yaw;\n"
|
|
||||||
" u64 tick;\n"
|
|
||||||
" u64 timestamp;\n"
|
|
||||||
"} pxl8_input_msg;\n"
|
|
||||||
"\n"
|
|
||||||
"typedef struct pxl8_sim_config {\n"
|
|
||||||
" f32 move_speed;\n"
|
|
||||||
" f32 ground_accel;\n"
|
|
||||||
" f32 air_accel;\n"
|
|
||||||
" f32 stop_speed;\n"
|
|
||||||
" f32 friction;\n"
|
|
||||||
" f32 gravity;\n"
|
|
||||||
" f32 jump_velocity;\n"
|
|
||||||
" f32 player_radius;\n"
|
|
||||||
" f32 player_height;\n"
|
|
||||||
" f32 max_pitch;\n"
|
|
||||||
"} pxl8_sim_config;\n"
|
|
||||||
"\n"
|
|
||||||
"typedef struct pxl8_sim_world {\n"
|
|
||||||
" const pxl8_bsp* chunks[9];\n"
|
|
||||||
" i32 center_cx;\n"
|
|
||||||
" i32 center_cz;\n"
|
|
||||||
" f32 chunk_size;\n"
|
|
||||||
"} pxl8_sim_world;\n"
|
|
||||||
"\n"
|
|
||||||
"void pxl8_sim_move_player(pxl8_sim_entity* ent, const pxl8_input_msg* input, const pxl8_sim_world* world, const pxl8_sim_config* cfg, f32 dt);\n"
|
|
||||||
"void pxl8_sim_integrate(pxl8_sim_entity* ent, const pxl8_sim_world* world, const pxl8_sim_config* cfg, f32 dt);\n"
|
|
||||||
"pxl8_vec3 pxl8_sim_trace(const pxl8_sim_world* world, pxl8_vec3 from, pxl8_vec3 to, f32 radius, f32 height);\n"
|
|
||||||
"bool pxl8_sim_check_ground(const pxl8_sim_world* world, pxl8_vec3 pos, f32 radius);\n"
|
|
||||||
"\n"
|
|
||||||
"pxl8_sim_world pxl8_world_sim_world(const pxl8_world* world, pxl8_vec3 pos);\n"
|
|
||||||
"void pxl8_world_set_sim_config(pxl8_world* world, const pxl8_sim_config* config);\n"
|
|
||||||
"void pxl8_world_push_input(pxl8_world* world, const pxl8_input_msg* input);\n"
|
|
||||||
"\n"
|
|
||||||
"typedef struct pxl8_entity_state {\n"
|
|
||||||
" u64 entity_id;\n"
|
|
||||||
" u8 userdata[56];\n"
|
|
||||||
"} pxl8_entity_state;\n"
|
|
||||||
"\n"
|
|
||||||
"typedef struct pxl8_snapshot_header {\n"
|
|
||||||
" u16 entity_count;\n"
|
|
||||||
" u16 event_count;\n"
|
|
||||||
" u64 player_id;\n"
|
|
||||||
" u64 tick;\n"
|
|
||||||
" f32 time;\n"
|
|
||||||
"} pxl8_snapshot_header;\n"
|
|
||||||
"\n"
|
|
||||||
"i32 pxl8_net_connect(pxl8_net* net);\n"
|
"i32 pxl8_net_connect(pxl8_net* net);\n"
|
||||||
"bool pxl8_net_connected(const pxl8_net* net);\n"
|
"bool pxl8_net_connected(const pxl8_net* net);\n"
|
||||||
"pxl8_net* pxl8_net_create(const pxl8_net_config* config);\n"
|
"pxl8_net* pxl8_net_create(const pxl8_net_config* config);\n"
|
||||||
"void pxl8_net_destroy(pxl8_net* net);\n"
|
"void pxl8_net_destroy(pxl8_net* net);\n"
|
||||||
"void pxl8_net_disconnect(pxl8_net* net);\n"
|
"void pxl8_net_disconnect(pxl8_net* net);\n"
|
||||||
"const pxl8_entity_state* pxl8_net_entities(const pxl8_net* net);\n"
|
|
||||||
"const u8* pxl8_net_entity_prev_userdata(const pxl8_net* net, u64 entity_id);\n"
|
|
||||||
"const u8* pxl8_net_entity_userdata(const pxl8_net* net, u64 entity_id);\n"
|
|
||||||
"const pxl8_input_msg* pxl8_net_input_at(const pxl8_net* net, u64 tick);\n"
|
|
||||||
"u64 pxl8_net_input_oldest_tick(const pxl8_net* net);\n"
|
|
||||||
"void pxl8_net_input_push(pxl8_net* net, const pxl8_input_msg* input);\n"
|
|
||||||
"f32 pxl8_net_lerp_alpha(const pxl8_net* net);\n"
|
|
||||||
"bool pxl8_net_needs_correction(const pxl8_net* net);\n"
|
|
||||||
"u64 pxl8_net_player_id(const pxl8_net* net);\n"
|
|
||||||
"i32 pxl8_net_chunk_cx(const pxl8_net* net);\n"
|
|
||||||
"i32 pxl8_net_chunk_cz(const pxl8_net* net);\n"
|
|
||||||
"bool pxl8_net_has_chunk(const pxl8_net* net);\n"
|
|
||||||
"bool pxl8_net_poll(pxl8_net* net);\n"
|
"bool pxl8_net_poll(pxl8_net* net);\n"
|
||||||
"u8* pxl8_net_predicted_state(pxl8_net* net);\n"
|
|
||||||
"void pxl8_net_predicted_tick_set(pxl8_net* net, u64 tick);\n"
|
|
||||||
"i32 pxl8_net_send_command(pxl8_net* net, const pxl8_command_msg* cmd);\n"
|
|
||||||
"i32 pxl8_net_send_input(pxl8_net* net, const pxl8_input_msg* input);\n"
|
|
||||||
"i32 pxl8_net_spawn(pxl8_net* net, f32 x, f32 y, f32 z, f32 yaw, f32 pitch);\n"
|
|
||||||
"const pxl8_snapshot_header* pxl8_net_snapshot(const pxl8_net* net);\n"
|
|
||||||
"u64 pxl8_net_tick(const pxl8_net* net);\n"
|
|
||||||
"void pxl8_net_update(pxl8_net* net, f32 dt);\n"
|
|
||||||
"pxl8_net* pxl8_get_net(const pxl8* sys);\n"
|
|
||||||
"\n"
|
"\n"
|
||||||
"void pxl8_bit_clear(u32* val, u8 bit);\n"
|
"void pxl8_bit_clear(u32* val, u8 bit);\n"
|
||||||
"u32 pxl8_bit_count(u32 val);\n"
|
"u32 pxl8_bit_count(u32 val);\n"
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
#include "pxl8_hal.h"
|
#include "pxl8_platform.h"
|
||||||
#include "pxl8_log.h"
|
#include "pxl8_log.h"
|
||||||
#include "pxl8_math.h"
|
#include "pxl8_math.h"
|
||||||
#include "pxl8_mem.h"
|
#include "pxl8_mem.h"
|
||||||
|
|
@ -140,7 +140,7 @@ struct pxl8_sfx_context {
|
||||||
};
|
};
|
||||||
|
|
||||||
struct pxl8_sfx_mixer {
|
struct pxl8_sfx_mixer {
|
||||||
const pxl8_hal* hal;
|
const pxl8_platform* platform;
|
||||||
void* audio_handle;
|
void* audio_handle;
|
||||||
pxl8_sfx_context* contexts[PXL8_SFX_MAX_CONTEXTS];
|
pxl8_sfx_context* contexts[PXL8_SFX_MAX_CONTEXTS];
|
||||||
f32 master_volume;
|
f32 master_volume;
|
||||||
|
|
@ -652,8 +652,8 @@ static void context_process_sample(pxl8_sfx_context* ctx, f32* out_left, f32* ou
|
||||||
*out_right = right;
|
*out_right = right;
|
||||||
}
|
}
|
||||||
|
|
||||||
pxl8_sfx_mixer* pxl8_sfx_mixer_create(const pxl8_hal* hal) {
|
pxl8_sfx_mixer* pxl8_sfx_mixer_create(const pxl8_platform* platform) {
|
||||||
if (!hal || !hal->audio_create) return NULL;
|
if (!platform || !platform->audio_create) return NULL;
|
||||||
|
|
||||||
pxl8_sfx_mixer* mixer = (pxl8_sfx_mixer*)pxl8_calloc(1, sizeof(pxl8_sfx_mixer));
|
pxl8_sfx_mixer* mixer = (pxl8_sfx_mixer*)pxl8_calloc(1, sizeof(pxl8_sfx_mixer));
|
||||||
if (!mixer) return NULL;
|
if (!mixer) return NULL;
|
||||||
|
|
@ -664,17 +664,17 @@ pxl8_sfx_mixer* pxl8_sfx_mixer_create(const pxl8_hal* hal) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
mixer->hal = hal;
|
mixer->platform = platform;
|
||||||
mixer->master_volume = 0.8f;
|
mixer->master_volume = 0.8f;
|
||||||
|
|
||||||
mixer->audio_handle = hal->audio_create(PXL8_SFX_SAMPLE_RATE, 2);
|
mixer->audio_handle = platform->audio_create(PXL8_SFX_SAMPLE_RATE, 2);
|
||||||
if (!mixer->audio_handle) {
|
if (!mixer->audio_handle) {
|
||||||
pxl8_free(mixer->output_buffer);
|
pxl8_free(mixer->output_buffer);
|
||||||
pxl8_free(mixer);
|
pxl8_free(mixer);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
hal->audio_start(mixer->audio_handle);
|
platform->audio_start(mixer->audio_handle);
|
||||||
pxl8_info("Audio mixer initialized: %d Hz, stereo, %d context slots", PXL8_SFX_SAMPLE_RATE, PXL8_SFX_MAX_CONTEXTS);
|
pxl8_info("Audio mixer initialized: %d Hz, stereo, %d context slots", PXL8_SFX_SAMPLE_RATE, PXL8_SFX_MAX_CONTEXTS);
|
||||||
|
|
||||||
return mixer;
|
return mixer;
|
||||||
|
|
@ -683,8 +683,8 @@ pxl8_sfx_mixer* pxl8_sfx_mixer_create(const pxl8_hal* hal) {
|
||||||
void pxl8_sfx_mixer_destroy(pxl8_sfx_mixer* mixer) {
|
void pxl8_sfx_mixer_destroy(pxl8_sfx_mixer* mixer) {
|
||||||
if (!mixer) return;
|
if (!mixer) return;
|
||||||
|
|
||||||
if (mixer->hal && mixer->audio_handle) {
|
if (mixer->platform && mixer->audio_handle) {
|
||||||
mixer->hal->audio_destroy(mixer->audio_handle);
|
mixer->platform->audio_destroy(mixer->audio_handle);
|
||||||
}
|
}
|
||||||
|
|
||||||
pxl8_free(mixer->output_buffer);
|
pxl8_free(mixer->output_buffer);
|
||||||
|
|
@ -692,9 +692,9 @@ void pxl8_sfx_mixer_destroy(pxl8_sfx_mixer* mixer) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void pxl8_sfx_mixer_process(pxl8_sfx_mixer* mixer) {
|
void pxl8_sfx_mixer_process(pxl8_sfx_mixer* mixer) {
|
||||||
if (!mixer || !mixer->hal || !mixer->audio_handle || !mixer->output_buffer) return;
|
if (!mixer || !mixer->platform || !mixer->audio_handle || !mixer->output_buffer) return;
|
||||||
|
|
||||||
i32 queued = mixer->hal->audio_queued(mixer->audio_handle);
|
i32 queued = mixer->platform->audio_queued(mixer->audio_handle);
|
||||||
i32 target = PXL8_SFX_SAMPLE_RATE / 10;
|
i32 target = PXL8_SFX_SAMPLE_RATE / 10;
|
||||||
|
|
||||||
while (queued < target) {
|
while (queued < target) {
|
||||||
|
|
@ -729,7 +729,7 @@ void pxl8_sfx_mixer_process(pxl8_sfx_mixer* mixer) {
|
||||||
mixer->output_buffer[i * 2 + 1] = right;
|
mixer->output_buffer[i * 2 + 1] = right;
|
||||||
}
|
}
|
||||||
|
|
||||||
mixer->hal->upload_audio(mixer->audio_handle, mixer->output_buffer, samples_to_generate);
|
mixer->platform->upload_audio(mixer->audio_handle, mixer->output_buffer, samples_to_generate);
|
||||||
queued += samples_to_generate;
|
queued += samples_to_generate;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "pxl8_hal.h"
|
#include "pxl8_platform.h"
|
||||||
#include "pxl8_types.h"
|
#include "pxl8_types.h"
|
||||||
|
|
||||||
#define PXL8_SFX_BUFFER_SIZE 1024
|
#define PXL8_SFX_BUFFER_SIZE 1024
|
||||||
|
|
@ -115,7 +115,7 @@ typedef void (*pxl8_sfx_event_callback)(u8 event_type, u8 context_id, u8 note, f
|
||||||
|
|
||||||
void pxl8_sfx_mixer_attach(pxl8_sfx_mixer* mixer, pxl8_sfx_context* ctx);
|
void pxl8_sfx_mixer_attach(pxl8_sfx_mixer* mixer, pxl8_sfx_context* ctx);
|
||||||
void pxl8_sfx_mixer_clear(pxl8_sfx_mixer* mixer);
|
void pxl8_sfx_mixer_clear(pxl8_sfx_mixer* mixer);
|
||||||
pxl8_sfx_mixer* pxl8_sfx_mixer_create(const pxl8_hal* hal);
|
pxl8_sfx_mixer* pxl8_sfx_mixer_create(const pxl8_platform* platform);
|
||||||
void pxl8_sfx_mixer_destroy(pxl8_sfx_mixer* mixer);
|
void pxl8_sfx_mixer_destroy(pxl8_sfx_mixer* mixer);
|
||||||
void pxl8_sfx_mixer_detach(pxl8_sfx_mixer* mixer, pxl8_sfx_context* ctx);
|
void pxl8_sfx_mixer_detach(pxl8_sfx_mixer* mixer, pxl8_sfx_context* ctx);
|
||||||
f32 pxl8_sfx_mixer_get_master_volume(const pxl8_sfx_mixer* mixer);
|
f32 pxl8_sfx_mixer_get_master_volume(const pxl8_sfx_mixer* mixer);
|
||||||
|
|
|
||||||
|
|
@ -1,56 +0,0 @@
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include "pxl8_bsp.h"
|
|
||||||
#include "pxl8_math.h"
|
|
||||||
#include "pxl8_protocol.h"
|
|
||||||
#include "pxl8_types.h"
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
extern "C" {
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define PXL8_SIM_FLAG_ALIVE (1 << 0)
|
|
||||||
#define PXL8_SIM_FLAG_PLAYER (1 << 1)
|
|
||||||
#define PXL8_SIM_FLAG_GROUNDED (1 << 2)
|
|
||||||
|
|
||||||
typedef struct pxl8_sim_config {
|
|
||||||
f32 move_speed;
|
|
||||||
f32 ground_accel;
|
|
||||||
f32 air_accel;
|
|
||||||
f32 stop_speed;
|
|
||||||
f32 friction;
|
|
||||||
f32 gravity;
|
|
||||||
f32 jump_velocity;
|
|
||||||
f32 player_radius;
|
|
||||||
f32 player_height;
|
|
||||||
f32 max_pitch;
|
|
||||||
} pxl8_sim_config;
|
|
||||||
|
|
||||||
typedef struct pxl8_sim_entity {
|
|
||||||
pxl8_vec3 pos;
|
|
||||||
pxl8_vec3 vel;
|
|
||||||
f32 yaw;
|
|
||||||
f32 pitch;
|
|
||||||
u32 flags;
|
|
||||||
u16 kind;
|
|
||||||
u16 _pad;
|
|
||||||
} pxl8_sim_entity;
|
|
||||||
|
|
||||||
typedef struct pxl8_sim_world {
|
|
||||||
const pxl8_bsp* chunks[9];
|
|
||||||
i32 center_cx;
|
|
||||||
i32 center_cz;
|
|
||||||
f32 chunk_size;
|
|
||||||
} pxl8_sim_world;
|
|
||||||
|
|
||||||
bool pxl8_bsp_point_solid(const pxl8_bsp* bsp, pxl8_vec3 pos);
|
|
||||||
pxl8_vec3 pxl8_bsp_trace(const pxl8_bsp* bsp, pxl8_vec3 from, pxl8_vec3 to, f32 radius);
|
|
||||||
|
|
||||||
pxl8_vec3 pxl8_sim_trace(const pxl8_sim_world* world, pxl8_vec3 from, pxl8_vec3 to, f32 radius, f32 height);
|
|
||||||
bool pxl8_sim_check_ground(const pxl8_sim_world* world, pxl8_vec3 pos, f32 radius);
|
|
||||||
void pxl8_sim_move_player(pxl8_sim_entity* ent, const pxl8_input_msg* input, const pxl8_sim_world* world, const pxl8_sim_config* cfg, f32 dt);
|
|
||||||
void pxl8_sim_integrate(pxl8_sim_entity* ent, const pxl8_sim_world* world, const pxl8_sim_config* cfg, f32 dt);
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
@ -1,67 +0,0 @@
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include "pxl8_types.h"
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
extern "C" {
|
|
||||||
#endif
|
|
||||||
|
|
||||||
typedef struct pxl8_entity_pool pxl8_entity_pool;
|
|
||||||
|
|
||||||
typedef struct pxl8_entity {
|
|
||||||
u32 idx;
|
|
||||||
u32 gen;
|
|
||||||
} pxl8_entity;
|
|
||||||
|
|
||||||
#define PXL8_ENTITY_INVALID ((pxl8_entity){0, 0})
|
|
||||||
|
|
||||||
typedef u32 pxl8_entity_component;
|
|
||||||
typedef u32 pxl8_entity_relationship;
|
|
||||||
|
|
||||||
#define PXL8_ENTITY_COMPONENT_INVALID 0
|
|
||||||
#define PXL8_ENTITY_RELATIONSHIP_INVALID 0
|
|
||||||
|
|
||||||
pxl8_entity_pool* pxl8_entity_pool_create(u32 capacity);
|
|
||||||
void pxl8_entity_pool_clear(pxl8_entity_pool* pool);
|
|
||||||
void pxl8_entity_pool_destroy(pxl8_entity_pool* pool);
|
|
||||||
|
|
||||||
pxl8_entity pxl8_entity_spawn(pxl8_entity_pool* pool);
|
|
||||||
void pxl8_entity_despawn(pxl8_entity_pool* pool, pxl8_entity e);
|
|
||||||
bool pxl8_entity_alive(const pxl8_entity_pool* pool, pxl8_entity e);
|
|
||||||
u32 pxl8_entity_count(const pxl8_entity_pool* pool);
|
|
||||||
|
|
||||||
pxl8_entity_component pxl8_entity_component_register(pxl8_entity_pool* pool, const char* name, u32 size);
|
|
||||||
pxl8_entity_component pxl8_entity_component_find(const pxl8_entity_pool* pool, const char* name);
|
|
||||||
const char* pxl8_entity_component_name(const pxl8_entity_pool* pool, pxl8_entity_component comp);
|
|
||||||
|
|
||||||
void* pxl8_entity_component_add(pxl8_entity_pool* pool, pxl8_entity e, pxl8_entity_component comp);
|
|
||||||
void* pxl8_entity_component_get(const pxl8_entity_pool* pool, pxl8_entity e, pxl8_entity_component comp);
|
|
||||||
void pxl8_entity_component_remove(pxl8_entity_pool* pool, pxl8_entity e, pxl8_entity_component comp);
|
|
||||||
bool pxl8_entity_component_has(const pxl8_entity_pool* pool, pxl8_entity e, pxl8_entity_component comp);
|
|
||||||
|
|
||||||
pxl8_entity_relationship pxl8_entity_relationship_register(pxl8_entity_pool* pool, const char* name);
|
|
||||||
pxl8_entity_relationship pxl8_entity_relationship_find(const pxl8_entity_pool* pool, const char* name);
|
|
||||||
const char* pxl8_entity_relationship_name(const pxl8_entity_pool* pool, pxl8_entity_relationship rel);
|
|
||||||
|
|
||||||
void pxl8_entity_relationship_add(pxl8_entity_pool* pool, pxl8_entity subject, pxl8_entity_relationship rel, pxl8_entity object);
|
|
||||||
void pxl8_entity_relationship_remove(pxl8_entity_pool* pool, pxl8_entity subject, pxl8_entity_relationship rel, pxl8_entity object);
|
|
||||||
bool pxl8_entity_relationship_has(const pxl8_entity_pool* pool, pxl8_entity subject, pxl8_entity_relationship rel, pxl8_entity object);
|
|
||||||
|
|
||||||
u32 pxl8_entity_relationship_subjects(const pxl8_entity_pool* pool, pxl8_entity object, pxl8_entity_relationship rel, pxl8_entity* out, u32 max);
|
|
||||||
u32 pxl8_entity_relationship_objects(const pxl8_entity_pool* pool, pxl8_entity subject, pxl8_entity_relationship rel, pxl8_entity* out, u32 max);
|
|
||||||
|
|
||||||
typedef void (*pxl8_entity_each_fn)(pxl8_entity_pool* pool, pxl8_entity e, void* ctx);
|
|
||||||
void pxl8_entity_each(pxl8_entity_pool* pool, pxl8_entity_component comp, pxl8_entity_each_fn fn, void* ctx);
|
|
||||||
void pxl8_entity_each_with(pxl8_entity_pool* pool, const pxl8_entity_component* comps, u32 count, pxl8_entity_each_fn fn, void* ctx);
|
|
||||||
|
|
||||||
static inline bool pxl8_entity_valid(pxl8_entity e) {
|
|
||||||
return e.idx != 0 || e.gen != 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline bool pxl8_entity_eq(pxl8_entity a, pxl8_entity b) {
|
|
||||||
return a.idx == b.idx && a.gen == b.gen;
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
@ -1,71 +0,0 @@
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include "pxl8_entity.h"
|
|
||||||
#include "pxl8_gfx.h"
|
|
||||||
#include "pxl8_gfx3d.h"
|
|
||||||
#include "pxl8_math.h"
|
|
||||||
#include "pxl8_net.h"
|
|
||||||
#include "pxl8_sim.h"
|
|
||||||
#include "pxl8_types.h"
|
|
||||||
#include "pxl8_world_chunk.h"
|
|
||||||
#include "pxl8_world_chunk_cache.h"
|
|
||||||
#include "pxl8_bsp_render.h"
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
extern "C" {
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define PXL8_WORLD_MAX_LOADED_CHUNKS 25
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
u16 leafs[16];
|
|
||||||
u8 count;
|
|
||||||
} pxl8_edge_leafs;
|
|
||||||
|
|
||||||
typedef struct pxl8_loaded_chunk {
|
|
||||||
pxl8_world_chunk* chunk;
|
|
||||||
pxl8_bsp_render_state* render_state;
|
|
||||||
pxl8_edge_leafs edges[4];
|
|
||||||
i32 cx;
|
|
||||||
i32 cz;
|
|
||||||
bool active;
|
|
||||||
} pxl8_loaded_chunk;
|
|
||||||
|
|
||||||
typedef struct pxl8_world pxl8_world;
|
|
||||||
|
|
||||||
pxl8_world* pxl8_world_create(void);
|
|
||||||
void pxl8_world_destroy(pxl8_world* world);
|
|
||||||
|
|
||||||
pxl8_world_chunk_cache* pxl8_world_get_chunk_cache(pxl8_world* world);
|
|
||||||
pxl8_world_chunk* pxl8_world_active_chunk(pxl8_world* world);
|
|
||||||
|
|
||||||
bool pxl8_world_point_solid(const pxl8_world* world, f32 x, f32 y, f32 z);
|
|
||||||
pxl8_ray pxl8_world_ray(const pxl8_world* world, pxl8_vec3 from, pxl8_vec3 to);
|
|
||||||
pxl8_ray pxl8_world_sweep(const pxl8_world* world, pxl8_vec3 from, pxl8_vec3 to, f32 radius);
|
|
||||||
|
|
||||||
void pxl8_world_update(pxl8_world* world, f32 dt);
|
|
||||||
void pxl8_world_render(pxl8_world* world, pxl8_gfx* gfx, pxl8_vec3 camera_pos);
|
|
||||||
void pxl8_world_sync(pxl8_world* world, pxl8_net* net);
|
|
||||||
|
|
||||||
void pxl8_world_set_bsp_material(pxl8_world* world, u16 material_id, const pxl8_gfx_material* material);
|
|
||||||
|
|
||||||
void pxl8_world_set_sim_config(pxl8_world* world, const pxl8_sim_config* config);
|
|
||||||
void pxl8_world_init_local_player(pxl8_world* world, f32 x, f32 y, f32 z);
|
|
||||||
void pxl8_world_set_look(pxl8_world* world, f32 yaw, f32 pitch);
|
|
||||||
pxl8_sim_entity* pxl8_world_local_player(pxl8_world* world);
|
|
||||||
pxl8_sim_world pxl8_world_sim_world(const pxl8_world* world, pxl8_vec3 pos);
|
|
||||||
void pxl8_world_predict(pxl8_world* world, pxl8_net* net, const pxl8_input_msg* input, f32 dt);
|
|
||||||
void pxl8_world_reconcile(pxl8_world* world, pxl8_net* net, f32 dt);
|
|
||||||
|
|
||||||
#ifdef PXL8_ASYNC_THREADS
|
|
||||||
void pxl8_world_start_sim_thread(pxl8_world* world, pxl8_net* net);
|
|
||||||
void pxl8_world_stop_sim_thread(pxl8_world* world);
|
|
||||||
void pxl8_world_pause_sim(pxl8_world* world, bool paused);
|
|
||||||
void pxl8_world_push_input(pxl8_world* world, const pxl8_input_msg* input);
|
|
||||||
const pxl8_sim_entity* pxl8_world_get_render_state(const pxl8_world* world);
|
|
||||||
f32 pxl8_world_get_interp_alpha(const pxl8_world* world);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
@ -1,17 +0,0 @@
|
||||||
#include "pxl8_world_chunk.h"
|
|
||||||
|
|
||||||
#include "pxl8_bsp.h"
|
|
||||||
#include "pxl8_mem.h"
|
|
||||||
|
|
||||||
pxl8_world_chunk* pxl8_world_chunk_create_bsp(u32 id) {
|
|
||||||
pxl8_world_chunk* chunk = pxl8_calloc(1, sizeof(pxl8_world_chunk));
|
|
||||||
if (!chunk) return NULL;
|
|
||||||
chunk->id = id;
|
|
||||||
return chunk;
|
|
||||||
}
|
|
||||||
|
|
||||||
void pxl8_world_chunk_destroy(pxl8_world_chunk* chunk) {
|
|
||||||
if (!chunk) return;
|
|
||||||
if (chunk->bsp) pxl8_bsp_destroy(chunk->bsp);
|
|
||||||
pxl8_free(chunk);
|
|
||||||
}
|
|
||||||
|
|
@ -1,21 +0,0 @@
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include "pxl8_bsp.h"
|
|
||||||
#include "pxl8_types.h"
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
extern "C" {
|
|
||||||
#endif
|
|
||||||
|
|
||||||
typedef struct pxl8_world_chunk {
|
|
||||||
u32 id;
|
|
||||||
u32 version;
|
|
||||||
pxl8_bsp* bsp;
|
|
||||||
} pxl8_world_chunk;
|
|
||||||
|
|
||||||
pxl8_world_chunk* pxl8_world_chunk_create_bsp(u32 id);
|
|
||||||
void pxl8_world_chunk_destroy(pxl8_world_chunk* chunk);
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
@ -1,55 +0,0 @@
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include "pxl8_mesh.h"
|
|
||||||
#include "pxl8_protocol.h"
|
|
||||||
#include "pxl8_types.h"
|
|
||||||
#include "pxl8_world_chunk.h"
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
extern "C" {
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define PXL8_WORLD_CHUNK_CACHE_SIZE 512
|
|
||||||
#define PXL8_WORLD_CHUNK_MAX_FRAGMENTS 255
|
|
||||||
#define PXL8_WORLD_CHUNK_MAX_DATA_SIZE 131072
|
|
||||||
|
|
||||||
typedef struct pxl8_world_chunk_cache_entry {
|
|
||||||
pxl8_world_chunk* chunk;
|
|
||||||
u64 last_used;
|
|
||||||
bool valid;
|
|
||||||
} pxl8_world_chunk_cache_entry;
|
|
||||||
|
|
||||||
typedef struct pxl8_world_chunk_assembly {
|
|
||||||
u32 id;
|
|
||||||
i32 cx, cy, cz;
|
|
||||||
u32 version;
|
|
||||||
u8 fragment_count;
|
|
||||||
u8 fragments_received;
|
|
||||||
u8* data;
|
|
||||||
u32 data_size;
|
|
||||||
u32 data_capacity;
|
|
||||||
bool active;
|
|
||||||
bool complete;
|
|
||||||
} pxl8_world_chunk_assembly;
|
|
||||||
|
|
||||||
typedef struct pxl8_world_chunk_cache {
|
|
||||||
pxl8_world_chunk_cache_entry entries[PXL8_WORLD_CHUNK_CACHE_SIZE];
|
|
||||||
pxl8_world_chunk_assembly assembly;
|
|
||||||
u32 entry_count;
|
|
||||||
u64 frame_counter;
|
|
||||||
} pxl8_world_chunk_cache;
|
|
||||||
|
|
||||||
pxl8_world_chunk_cache* pxl8_world_chunk_cache_create(void);
|
|
||||||
void pxl8_world_chunk_cache_destroy(pxl8_world_chunk_cache* cache);
|
|
||||||
|
|
||||||
pxl8_result pxl8_world_chunk_cache_receive(pxl8_world_chunk_cache* cache,
|
|
||||||
const pxl8_chunk_msg_header* hdr,
|
|
||||||
const u8* payload, usize len);
|
|
||||||
|
|
||||||
pxl8_world_chunk* pxl8_world_chunk_cache_get_bsp(pxl8_world_chunk_cache* cache, u32 id);
|
|
||||||
|
|
||||||
void pxl8_world_chunk_cache_tick(pxl8_world_chunk_cache* cache);
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue