Compare commits
48 commits
f0876825f1
...
7e04937c8b
Author | SHA1 | Date | |
---|---|---|---|
John Alanbrook | 7e04937c8b | ||
John Alanbrook | c05cb3c6d2 | ||
John Alanbrook | 17ad44e5a5 | ||
John Alanbrook | 0b4231c0b6 | ||
John Alanbrook | 33ac36ae5c | ||
John Alanbrook | 941106ced5 | ||
John Alanbrook | 5051d11005 | ||
John Alanbrook | 53f2addeec | ||
John Alanbrook | 33d450189c | ||
John Alanbrook | 9106ebcc48 | ||
John Alanbrook | 403771d7f8 | ||
John Alanbrook | 32268fc25d | ||
John Alanbrook | ccdcfafdf2 | ||
John Alanbrook | 033b7c5109 | ||
John Alanbrook | 3f73a808d8 | ||
John Alanbrook | 32333c32ad | ||
John Alanbrook | 3b9a932c85 | ||
John Alanbrook | 1195e6c73d | ||
John Alanbrook | 59ad64bbba | ||
John Alanbrook | c27e1a3071 | ||
John Alanbrook | fe3250752d | ||
John Alanbrook | 204aa19c50 | ||
John Alanbrook | c3aa598300 | ||
John Alanbrook | fa5398474b | ||
John Alanbrook | 459ef00330 | ||
John Alanbrook | b17e5d3917 | ||
John Alanbrook | 3023a12184 | ||
John Alanbrook | 79c06098b3 | ||
John Alanbrook | ecb2882e7e | ||
John Alanbrook | 5e3fb73398 | ||
John Alanbrook | 845fc5d4b8 | ||
John Alanbrook | 1540da8392 | ||
John Alanbrook | f5d610cbed | ||
John Alanbrook | 51f3b5abeb | ||
John Alanbrook | 5a52afc2fd | ||
John Alanbrook | d3db5ca61e | ||
John Alanbrook | 23afa7b266 | ||
John Alanbrook | 7e6fc1ffbe | ||
John Alanbrook | 046b7c6f44 | ||
John Alanbrook | 18c07e9f82 | ||
John Alanbrook | 62a34c1e7c | ||
John Alanbrook | 9730f8defb | ||
John Alanbrook | 261b373a75 | ||
John Alanbrook | 088dd4d4fd | ||
John Alanbrook | 32b0cc7377 | ||
bad225b965 | |||
188fe7526c | |||
John Alanbrook | 55ab159a85 |
14
.gitignore
vendored
14
.gitignore
vendored
|
@ -12,13 +12,21 @@ Jenkinsfile
|
|||
*.gz
|
||||
*.tar
|
||||
.nova/
|
||||
packer
|
||||
packer*
|
||||
primum
|
||||
sokol-shdc
|
||||
sokol-shdc*
|
||||
source/shaders/*.h
|
||||
core.cdb
|
||||
primum.exe
|
||||
core.cdb.h
|
||||
jsc
|
||||
.DS_Store
|
||||
primum.html
|
||||
*.html
|
||||
.vscode
|
||||
primum*
|
||||
Prosperon*
|
||||
prosperon*
|
||||
*.icns
|
||||
game.cdb
|
||||
icon.ico
|
||||
steam/
|
16
Info.plist
Normal file
16
Info.plist
Normal file
|
@ -0,0 +1,16 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>Prosperon</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>pockle.world.prosperon</string>
|
||||
<key>CFBundleName</key>
|
||||
<string>Prosperon</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>0.5</string>
|
||||
<key>NSHumanReadableCopyright</key>
|
||||
<string>Copyright © 2024 Pockle World. All rights reserved.</string>
|
||||
</dict>
|
||||
</plist>
|
321
Makefile
321
Makefile
|
@ -1,30 +1,25 @@
|
|||
MAKEFLAGS = --jobs=4
|
||||
MAKEFLAGS = --jobs=8
|
||||
UNAME != uname
|
||||
MAKEDIR != pwd
|
||||
# Options
|
||||
# DBG --- build with debugging symbols and logging
|
||||
# NDEBUG --- build with debugging symbols and logging
|
||||
|
||||
CXX:=$(CC)
|
||||
|
||||
ifeq ($(CXX), tcc)
|
||||
CXX=clang
|
||||
endif
|
||||
|
||||
ifeq ($(CC),cc)
|
||||
CC=clang
|
||||
endif
|
||||
# Temp to strip long emcc paths to just emcc
|
||||
CC := $(notdir $(CC))
|
||||
|
||||
DBG ?= 1
|
||||
OPT ?= 0
|
||||
LEAK ?= 0
|
||||
|
||||
INFO :=
|
||||
LD = $(CC)
|
||||
|
||||
ifeq ($(CC), x86_64-w64-mingw32-gcc)
|
||||
AR = x86_64-w64-mingw32-ar
|
||||
STEAM = steam/sdk
|
||||
STEAMAPI = steam_api
|
||||
|
||||
CCC != $(CC) -v
|
||||
ifneq ($(findstring clangcc , $(CCC)),)
|
||||
LDFLAGS += -Wl,-rpath=./
|
||||
endif
|
||||
|
||||
ifdef NEDITOR
|
||||
|
@ -47,56 +42,49 @@ ifdef NQOA
|
|||
CPPFLAGS += -DNQOA
|
||||
endif
|
||||
|
||||
CPPFLAGS += -ffast-math
|
||||
|
||||
ifeq ($(CC), emcc)
|
||||
LDFLAGS += #--closure 1
|
||||
LDFLAGS += #--closure 1 --emrun
|
||||
CPPFLAGS += -O0
|
||||
OPT = 0
|
||||
DBG = 0
|
||||
NDEBUG = 1
|
||||
AR = emar
|
||||
endif
|
||||
|
||||
ifeq ($(DBG),1)
|
||||
CPPFLAGS += -g
|
||||
INFO += _dbg
|
||||
else
|
||||
ifdef NDEBUG
|
||||
CPPFLAGS += -DNDEBUG
|
||||
LDFLAGS += -s
|
||||
else
|
||||
CPPFLAGS += -g -DDUMP
|
||||
INFO :=$(INFO)_dbg
|
||||
endif
|
||||
|
||||
ifeq ($(LEAK),1)
|
||||
CPPFLAGS += -fsanitize=address
|
||||
ifdef LEAK
|
||||
CPPFLAGS += -fsanitize=address -fsanitize=undefined -fno-omit-frame-pointer -DLEAK
|
||||
endif
|
||||
|
||||
CPPFLAGS += -DLEAK=$(LEAK)
|
||||
|
||||
ifeq ($(OPT),small)
|
||||
CPPFLAGS += -Oz -flto -fno-ident -fno-asynchronous-unwind-tables
|
||||
CPPFLAGS += -Oz -flto -fno-ident -fno-asynchronous-unwind-tables -ffunction-sections -fdata-sections
|
||||
|
||||
LDFLAGS += -flto
|
||||
|
||||
ifeq ($(CC), emcc)
|
||||
LDFLAGS += --closure 1
|
||||
endif
|
||||
|
||||
INFO := $(addsuffix _small,$(INFO))
|
||||
else
|
||||
ifeq ($(OPT), 1)
|
||||
INFO :=$(INFO)_small
|
||||
else ifeq ($(OPT), 1)
|
||||
CPPFLAGS += -O2 -flto
|
||||
INFO := $(addsuffix _opt,$(INFO))
|
||||
INFO :=$(INFO)_opt
|
||||
else
|
||||
CPPFLAGS += -O0
|
||||
endif
|
||||
CPPFLAGS += -O2
|
||||
endif
|
||||
|
||||
CPPFLAGS += -DHAVE_CEIL -DCP_USE_CGTYPES=0 -DCP_USE_DOUBLES=0 -DHAVE_FLOOR -DHAVE_FMOD -DHAVE_LRINT -DHAVE_LRINTF $(includeflag) -MD $(WARNING_FLAGS) -I. -DVER=\"$(VER)\" -DCOM=\"$(COM)\" -DINFO=\"$(INFO)\" #-DENABLE_SINC_MEDIUM_CONVERTER -DENABLE_SINC_FAST_CONVERTER -DCP_COLLISION_TYPE_TYPE=uintptr_t -DCP_BITMASK_TYPE=uintptr_t
|
||||
|
||||
CPPFLAGS += -D_FILE_OFFSET_BITS=64 # for tinycdb
|
||||
CPPFLAGS += -DHAVE_CEIL -DCP_USE_CGTYPES=0 -DCP_USE_DOUBLES=0 -DHAVE_FLOOR -DHAVE_FMOD -DHAVE_LRINT -DHAVE_LRINTF $(includeflag) -MD $(WARNING_FLAGS) -I. -DVER=\"$(SEM)\" -DCOM=\"$(COM)\" -DINFO=\"$(INFO)\" #-DENABLE_SINC_MEDIUM_CONVERTER -DENABLE_SINC_FAST_CONVERTER -DCP_COLLISION_TYPE_TYPE=uintptr_t -DCP_BITMASK_TYPE=uintptr_t
|
||||
CPPFLAGS += -DCONFIG_VERSION=\"2024-02-14\" -DCONFIG_BIGNUM #for quickjs
|
||||
|
||||
# ENABLE_SINC_[BEST|FAST|MEDIUM]_CONVERTER
|
||||
# default, fast and medium available in game at runtime; best available in editor
|
||||
|
||||
PKGCMD = tar --directory $(BIN) --exclude="./*.a" --exclude="./obj" -czf $(DISTDIR)/$(DIST) .
|
||||
PKGCMD = tar --directory --exclude="./*.a" --exclude="./obj" -czf $(DISTDIR)/$(DIST) .
|
||||
ZIP = .tar.gz
|
||||
UNZIP = cp $(DISTDIR)/$(DIST) $(DESTDIR) && tar xzf $(DESTDIR)/$(DIST) -C $(DESTDIR) && rm $(DESTDIR)/$(DIST)
|
||||
|
||||
|
@ -104,30 +92,31 @@ ifeq ($(ARCH),)
|
|||
ARCH != uname -m
|
||||
endif
|
||||
|
||||
STEAMPATH = steam/sdk/redistributable_bin
|
||||
DISCORDPATH = discord/lib
|
||||
INFO :=$(INFO)_$(ARCH)
|
||||
|
||||
ifdef DISCORD
|
||||
LDPATHS += $(DISCORDPATH)/$(ARCH)
|
||||
LDLIBS += discord_game_sdk
|
||||
CPPFLAGS += -DDISCORD
|
||||
endif
|
||||
|
||||
ifdef STEAM
|
||||
LDLIBS += steam_api
|
||||
LDPATHS += $(STEAMPATH)/$(ARCH)
|
||||
endif
|
||||
|
||||
ifeq ($(OS), Windows_NT)
|
||||
ifeq ($(OS), Windows_NT) # then WINDOWS
|
||||
PLATFORM := win64
|
||||
DEPS += resource.o
|
||||
STEAMAPI := steam_api64
|
||||
LDFLAGS += -mwin32 -static
|
||||
CPPFLAGS += -mwin32
|
||||
LDLIBS += mingw32 kernel32 d3d11 user32 shell32 dxgi gdi32 ws2_32 ole32 winmm setupapi m pthread
|
||||
EXT = .exe
|
||||
ARCH := x86_64
|
||||
PKGCMD = cd $(BIN); zip -q -r $(MAKEDIR)/$(DISTDIR)/$(DIST) . -x \*.a ./obj/\*
|
||||
|
||||
PKGCMD = zip -q -r $(MAKEDIR)/$(DISTDIR)/$(DIST) . -x \*.a ./obj/\*
|
||||
ZIP = .zip
|
||||
UNZIP = unzip -o -q $(DISTDIR)/$(DIST) -d $(DESTDIR)
|
||||
else ifeq ($(CC), emcc)
|
||||
INFO :=$(INFO)_win
|
||||
else ifeq ($(OS), IOS)
|
||||
CC = /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/clang
|
||||
SDK = iphoneos
|
||||
SDK_PATH = /Applications/Xcode.app/Contents/Developer/Platforms/$(SDK).platform/Developer/SDKs/$(SDK).sdk
|
||||
CFLAGS += -isysroot $(SDK_PATH) -miphoneos-version-min=13.0
|
||||
LDFLAGS += -isysroot $(SDK_PATH) -miphoneos-version-min=13.0
|
||||
LDFLAGS += -framework Foundation -framework UIKit -framework AudioToolbox -framework Metal -framework MetalKit -framework AVFoundation
|
||||
CXXFLAGS += -std=c++11
|
||||
CFLAGS += -x objective-c
|
||||
INFO :=$(INFO)_ios
|
||||
else ifeq ($(CC), emcc) # Then WEB
|
||||
OS := Web
|
||||
LDFLAGS += -sMIN_WEBGL_VERSION=2 -sMAX_WEBGL_VERSION=2 -pthread -sTOTAL_MEMORY=128MB
|
||||
CPPFLAGS += -pthread
|
||||
|
@ -135,213 +124,165 @@ else ifeq ($(CC), emcc)
|
|||
EXT = .html
|
||||
else
|
||||
UNAME != uname -s
|
||||
ifeq ($(UNAME), Linux)
|
||||
ifeq ($(UNAME), Linux) # then LINUX
|
||||
OS := Linux
|
||||
PLATFORM := linux64
|
||||
LDFLAGS += -pthread -rdynamic
|
||||
LDLIBS += GL pthread c m dl X11 Xi Xcursor EGL asound
|
||||
INFO :=$(INFO)_linux
|
||||
endif
|
||||
|
||||
ifeq ($(UNAME), Darwin)
|
||||
OS := macos
|
||||
PLATFORM := osx
|
||||
CPPFLAGS += -arch $(ARCH)
|
||||
CFLAGS += -x objective-c
|
||||
CXXFLAGS += -std=c++11
|
||||
LDFLAGS += -framework Cocoa -framework QuartzCore -framework AudioToolbox -framework Metal -framework MetalKit
|
||||
INFO :=$(INFO)_macos
|
||||
endif
|
||||
endif
|
||||
|
||||
BIN = bin/$(OS)/$(ARCH)$(INFO)
|
||||
|
||||
ifdef STEAM
|
||||
BIN := $(addsuffix /steam, $(BIN))
|
||||
endif
|
||||
|
||||
OBJDIR = $(BIN)/obj
|
||||
|
||||
# All other sources
|
||||
OBJS != find source/engine -type f -name '*.c' | grep -vE 'test|tool|example|fuzz|main' | grep -vE 'quickjs'
|
||||
CPPOBJS != find source/engine -type f -name '*.cpp' | grep -vE 'test|tool|example|fuzz|main'
|
||||
OBJS != find source -type f -name '*.c' | grep -vE 'test|tool|example|fuzz|main' | grep -vE 'quickjs'
|
||||
CPPOBJS != find source -type f -name '*.cpp' | grep -vE 'test|tool|example|fuzz|main'
|
||||
OBJS += $(CPPOBJS)
|
||||
OBJS += source/engine/yugine.c
|
||||
OBJS += $(shell find source/engine -type f -name '*.m')
|
||||
OBJS := $(patsubst %.cpp, %.o, $(OBJS))
|
||||
OBJS := $(patsubst %.c, %.o,$(OBJS))
|
||||
OBJS := $(patsubst %.m, %.o, $(OBJS))
|
||||
OBJS := $(addprefix $(BIN)/obj/, $(OBJS))
|
||||
QUICKJS := source/engine/thirdparty/quickjs
|
||||
OBJS += $(addprefix $(QUICKJS)/, libregexp.c quickjs.c libunicode.c cutils.c libbf.c)
|
||||
OBJS := $(patsubst %.cpp, %$(INFO).o, $(OBJS))
|
||||
OBJS := $(patsubst %.c, %$(INFO).o,$(OBJS))
|
||||
OBJS := $(patsubst %.m, %$(INFO).o, $(OBJS))
|
||||
|
||||
engineincs != find source/engine -maxdepth 1 -type d
|
||||
includeflag != find source -type d -name include
|
||||
includeflag += $(engineincs) source/engine/thirdparty/tinycdb source/shaders source/engine/thirdparty/sokol source/engine/thirdparty/stb source/engine/thirdparty/cgltf source/engine/thirdparty/TinySoundFont source/engine/thirdparty/dr_libs
|
||||
includeflag += $(engineincs) source/shaders source/engine/thirdparty/sokol source/engine/thirdparty/stb source/engine/thirdparty/cgltf source/engine/thirdparty/TinySoundFont source/engine/thirdparty/dr_libs
|
||||
includeflag += $(STEAM)/public
|
||||
includeflag += source
|
||||
includeflag := $(addprefix -I, $(includeflag))
|
||||
|
||||
# Adding different SDKs
|
||||
ifdef STEAM
|
||||
includeflag += -Isteam/sdk/public
|
||||
CPPFLAGS += -DSTEAM
|
||||
# BIN += /steam
|
||||
endif
|
||||
|
||||
WARNING_FLAGS = -Wno-incompatible-function-pointer-types -Wno-incompatible-pointer-types
|
||||
|
||||
NAME = primum$(EXT)
|
||||
SEM = 0.3.0
|
||||
COM != fossil describe
|
||||
VER = $(SEM)
|
||||
APP = prosperon
|
||||
NAME = $(APP)$(INFO)$(EXT)
|
||||
SEM != git describe --tags --abbrev=0
|
||||
COM != git rev-parse --short HEAD
|
||||
|
||||
LDLIBS += $(STEAMAPI)
|
||||
LDLIBS := $(addprefix -l, $(LDLIBS))
|
||||
LDPATHS := $(STEAM)/redistributable_bin/$(PLATFORM)
|
||||
LDPATHS := $(addprefix -L, $(LDPATHS))
|
||||
|
||||
DEPENDS = $(OBJS:.o=.d)
|
||||
-include $(DEPENDS)
|
||||
|
||||
DIST = yugine-$(OS)$(ARCH)$(INFO)-$(COM)$(ZIP)
|
||||
DISTDIR = ./dist
|
||||
|
||||
.DEFAULT_GOAL := all
|
||||
primum: all
|
||||
all: $(BIN)/$(NAME)
|
||||
cp $(BIN)/$(NAME) .
|
||||
|
||||
DESTDIR ?= ~/.bin
|
||||
|
||||
CDB = source/engine/thirdparty/tinycdb
|
||||
all: $(NAME)
|
||||
cp -f $(NAME) $(APP)$(EXT)
|
||||
|
||||
SHADERS = $(shell ls source/shaders/*.sglsl)
|
||||
SHADERS := $(patsubst %.sglsl, %.sglsl.h, $(SHADERS))
|
||||
|
||||
install: $(BIN)/$(NAME)
|
||||
cp -f $(BIN)/$(NAME) $(DESTDIR)
|
||||
prereqs: $(SHADERS) source/engine/core.cdb.h
|
||||
|
||||
$(BIN)/$(NAME): $(BIN)/libengine.a $(BIN)/libquickjs.a
|
||||
DESTDIR ?= ~/.bin
|
||||
install: $(NAME)
|
||||
@echo Copying to destination
|
||||
cp -f $(NAME) $(DESTDIR)/$(APP)
|
||||
|
||||
$(NAME): $(OBJS) $(DEPS)
|
||||
@echo Linking $(NAME)
|
||||
$(LD) $^ $(CPPFLAGS) $(LDFLAGS) -L$(BIN) $(LDPATHS) $(LDLIBS) -o $@
|
||||
$(LD) $^ $(CPPFLAGS) $(LDFLAGS) -L. $(LDPATHS) $(LDLIBS) -o $@
|
||||
@echo Finished build
|
||||
|
||||
$(DISTDIR)/$(DIST): $(BIN)/$(NAME)
|
||||
@echo Creating distribution $(DIST)
|
||||
@mkdir -p $(DISTDIR)
|
||||
@$(PKGCMD)
|
||||
|
||||
$(BIN)/libengine.a: $(OBJS)
|
||||
@$(AR) rcs $@ $(OBJS)
|
||||
|
||||
CDB_C != find $(CDB) -name *.c
|
||||
CDB_O := $(patsubst %.c, %.o, $(CDB_C))
|
||||
$(CDB)/libcdb.a:
|
||||
rm -f $(CDB)/libcdb.a
|
||||
make -C $(CDB) libcdb.a
|
||||
|
||||
tools/libcdb.a: $(CDB)/libcdb.a
|
||||
cp $(CDB)/libcdb.a tools
|
||||
|
||||
DOCOS = Sound gameobject Game Window physics Profile Time Player Mouse IO Log ColorMap sprite SpriteAnim Render Geometry
|
||||
DOCHTML := $(addsuffix .api.html, $(DOCOS))
|
||||
DOCMD := $(addsuffix .api.md, $(DOCOS))
|
||||
|
||||
api.md: $(DOCMD)
|
||||
@(echo "# API"; cat $^) > $@
|
||||
@rm $^
|
||||
|
||||
INPUT = editor DebugControls component.sprite component.polygon2d component.edge2d component.circle2d
|
||||
|
||||
INPUTMD := $(addsuffix .input.md, $(INPUT))
|
||||
input.md: $(INPUTMD)
|
||||
@(echo "# Input"; cat $^) > $@
|
||||
@rm $^
|
||||
|
||||
%.input.md: primum $(SCRIPTS)
|
||||
@echo Printing controls for $*
|
||||
@./primum -e $* > $@
|
||||
|
||||
%.api.md: primum $(SCRIPTS)
|
||||
@echo Printing api for $*
|
||||
@./primum -d $* > $@
|
||||
|
||||
QUICKJS := source/engine/thirdparty/quickjs
|
||||
$(BIN)/libquickjs.a:
|
||||
make -C $(QUICKJS) clean
|
||||
make -C $(QUICKJS) SYSRT=$(SYSRT) TTARGET=$(TTARGET) ARCH=$(ARCH) DBG=$(DBG) OPT=$(OPT) AR=$(AR) OS=$(OS) libquickjs.a HOST_CC=$(CC) LEAK=$(LEAK)
|
||||
@mkdir -p $(BIN)
|
||||
cp -rf $(QUICKJS)/libquickjs.* $(BIN)
|
||||
|
||||
$(OBJDIR)/%.o: %.c source/engine/core.cdb.h $(SHADERS)
|
||||
@mkdir -p $(@D)
|
||||
%$(INFO).o: %.c
|
||||
@echo Making C object $@
|
||||
@$(CC) $(CPPFLAGS) $(CFLAGS) -c $< -o $@
|
||||
$(CC) $(CPPFLAGS) $(CFLAGS) -c $< -o $@
|
||||
|
||||
$(OBJDIR)/%.o: %.cpp
|
||||
@mkdir -p $(@D)
|
||||
%$(INFO).o: %.cpp
|
||||
@echo Making C++ object $@
|
||||
@$(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $< -o $@
|
||||
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -fpermissive -c $< -o $@
|
||||
|
||||
$(OBJDIR)/%.o: %.m
|
||||
@mkdir -p $(@D)
|
||||
%$(INFO).o: %.m
|
||||
@echo Making Objective-C object $@
|
||||
@$(CC) $(CPPFLAGS) $(CFLAGS) -c $< -o $@
|
||||
$(CC) $(CPPFLAGS) $(CFLAGS) -c $< -o $@
|
||||
|
||||
shaders: $(SHADERS)
|
||||
@echo Making shaders
|
||||
|
||||
%.sglsl.h:%.sglsl
|
||||
@echo Creating shader $^
|
||||
@./sokol-shdc --ifdef -i $^ --slang=glsl330:hlsl5:metal_macos:metal_ios:metal_sim:glsl300es -o $@
|
||||
|
||||
cdb: tools/cdb.c tools/libcdb.a
|
||||
cc $^ -I$(CDB) -o cdb
|
||||
|
||||
source/engine/core.cdb.h: core.cdb
|
||||
xxd -i $< > $@
|
||||
./sokol-shdc --ifdef -i $^ --slang=glsl330:hlsl5:metal_macos:metal_ios:metal_sim:glsl300es -o $@
|
||||
|
||||
SCRIPTS := $(shell ls scripts/*.js*)
|
||||
SCRIPT_O := $(addsuffix o, $(SCRIPTS))
|
||||
CORE != (ls icons/* fonts/*)
|
||||
CORE := $(CORE) $(SCRIPTS)
|
||||
|
||||
core.cdb: packer $(CORE)
|
||||
./packer $(CORE)
|
||||
chmod 644 out.cdb
|
||||
mv out.cdb core.cdb
|
||||
packer$(EXT): tools/packer.c source/engine/miniz.c
|
||||
@echo Making packer
|
||||
$(CC) -O2 $^ -Isource/engine -o packer
|
||||
|
||||
packer: tools/packer.c tools/libcdb.a
|
||||
cc $^ -I$(CDB) -o packer
|
||||
core.cdb: packer$(EXT) $(CORE)
|
||||
@echo Packing core.cdb
|
||||
./packer$(EXT) $@ $(CORE)
|
||||
|
||||
jsc: tools/jso.c tools/libquickjs.a
|
||||
$(CC) $^ -lm -Iquickjs -o $@
|
||||
source/engine/core.cdb.h: core.cdb
|
||||
@echo Making $@
|
||||
xxd -i $< > $@
|
||||
|
||||
tools/libquickjs.a: $(BIN)/libquickjs.a
|
||||
cp -f $(BIN)/libquickjs.a tools
|
||||
ICNSIZE = 16 32 128 256 512 1024
|
||||
ICNNAME := $(addsuffix .png, $(ICNSIZE))
|
||||
ICON = icons/moon.gif
|
||||
icon.ico: $(ICON)
|
||||
for i in $(ICNSIZE); do convert $^ -thumbnail $${i}x$${i} $${i}.png; done
|
||||
convert $(ICNNAME) icon.ico
|
||||
rm $(ICNNAME)
|
||||
|
||||
WINCC = x86_64-w64-mingw32-gcc
|
||||
#WINCC = i686-w64-mingw32-g++
|
||||
.PHONY: crosswin
|
||||
crosswin:
|
||||
make packer
|
||||
make CC=$(WINCC) OS=Windows_NT
|
||||
resource.o: resource.rc resource.manifest icon.ico
|
||||
windres -i $< -o $@
|
||||
|
||||
crossmac:
|
||||
make ARCH=arm64
|
||||
mv primum primum_arm64
|
||||
make ARCH=x86_64
|
||||
mv primum primum_x86_64
|
||||
lipo primum_arm64 primum_x86_64 -create -output primum
|
||||
crossios:
|
||||
make OS=IOS ARCH=arm64 DEBUG=$(DEBUG) OPT=$(OPT)
|
||||
|
||||
Prosperon.icns: $(ICON)
|
||||
mkdir -p Prosperon.iconset
|
||||
for i in $(ICNSIZE); do magick $^ -size $${i}x$${i} Prosperon.iconset/icon_$${i}x$${i}.png; done
|
||||
iconutil -c icns Prosperon.iconset
|
||||
|
||||
crossmac: Prosperon.icns
|
||||
make ARCH=arm64 DEBUG=$(DEBUG) OPT=$(OPT)
|
||||
mv $(APP) mac_arm64
|
||||
make ARCH=x86_64 DEBUG=$(DEBUG) OPT=$(OPT)
|
||||
mv $(APP) mac_x86_64
|
||||
lipo mac_arm64 mac_x86_64 -create -output $(APP)_mac
|
||||
rm mac_arm64 mac_x86_64
|
||||
rm -rf Prosperon.app
|
||||
mkdir Prosperon.app
|
||||
mkdir Prosperon.app/Contents
|
||||
mkdir Prosperon.app/Contents/MacOS
|
||||
mkdir Prosperon.app/Contents/Resources
|
||||
mv $(NAME) Prosperon.app/Contents/MacOS/Prosperon
|
||||
cp Info.plist Prosperon.app/Contents
|
||||
cp Prosperon.icns Prosperon.app/Contents/Resources
|
||||
|
||||
crossweb:
|
||||
make packer
|
||||
make CC=emcc
|
||||
|
||||
playweb:
|
||||
make crossweb
|
||||
emrun $(NAME).html
|
||||
|
||||
clean:
|
||||
@echo Cleaning project
|
||||
rm -rf bin dist
|
||||
rm -f source/shaders/*.h core.cdb jso cdb packer TAGS source/engine/core.cdb.h tools/libcdb.a $(CDB)/libcdb.a
|
||||
rm -f $(CDB)/*.o
|
||||
@make -C $(QUICKJS) clean
|
||||
rm -f source/shaders/*.h core.cdb jso cdb packer TAGS source/engine/core.cdb.h tools/libcdb.a $(APP)* *.icns *.ico
|
||||
find . -type f -name "*.[oad]" -delete
|
||||
rm -rf Prosperon.app
|
||||
|
||||
docs: doc/prosperon.org
|
||||
make -C doc
|
||||
mv doc/html .
|
||||
|
||||
test:
|
||||
@echo No tests yet ...
|
||||
|
||||
TAGINC != find . -name "*.[chj]"
|
||||
tags: $(TAGINC)
|
||||
@echo Making tags.
|
||||
|
|
|
@ -212,7 +212,18 @@ Components only work in the context of an entity. They have no meaning outside o
|
|||
While components can be added via scripting, it is easier to add them via the editor, as we will later see.
|
||||
|
||||
*** Ur system
|
||||
The ur[fn::A German prefix meaning primitive, original, or earliest.] system is a prototypical inheritence system used by the actor files. When actor files are loaded, they are stored as an ur. An *ur* represents a set of instructions to create the (text, config) needed to spawn an actor or entity.
|
||||
The ur[fn::A German prefix meaning primitive, original, or earliest.] system is a prototypical inheritence system used by the actor files. When actor files are loaded, they are stored as an ur. An *ur* holds a list of (text, config) required to create an entity.
|
||||
|
||||
When prosperon starts, it searches for urs by name. Any file ending in ".jso" or ".json" will be interpereted as an ur, with same named jso and json being applied as (text, config) for an ur. A jso or json alone also constitute an ur.
|
||||
|
||||
An ur can also be defined by a json file. If an ur is found, it takes predecent over auto generated urs. The json of an ur looks like this:
|
||||
|
||||
| field | description |
|
||||
|----|----|
|
||||
| text | Path to a script file, or array of script files, to apply to the object |
|
||||
| data | Path to a json file, or array of json files, to apply to the object |
|
||||
|
||||
Any ur file with this sort of json creates an ur which can be created in the game. A file named "box.ur" will be ingested and be available as "ur.box". When saving differences, it creates a json file with the same name as an ur (in this case, "box.json").
|
||||
|
||||
#+begin_scholium
|
||||
Create an ur from the *hello* files above, and then spawn it.
|
||||
|
@ -223,6 +234,14 @@ Primum.spawn(ur.hello);
|
|||
When creating an actor from source files, all of its setup must take place. In this example, the setup happens during *ur.create*, and spawning is simply a matter of prototyping it.
|
||||
#+end_scholium
|
||||
|
||||
This method allows high composability of game objects.
|
||||
|
||||
If an entity is created without an ur, is ur is defined as its given text and data. It cannot be saved. It must be given a new ur name.
|
||||
|
||||
Objects can be composed on the fly by stringing together urs. For example, a "2x.json" might define scale as 2x. Then, you can create a goblin with `ur.goblin`, or a large goblin with `ur.goblin.2x`. This creates a goblin object, and then applies the 2x scripts and jsons onto the object.
|
||||
|
||||
*** Urs in game
|
||||
|
||||
Each ur has the following fields.
|
||||
|
||||
| field | description |
|
||||
|
|
17
resource.manifest
Normal file
17
resource.manifest
Normal file
|
@ -0,0 +1,17 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||
<copyright>Copyright (c) 2024 Pockle World. All Rights Reserved.</copyright>
|
||||
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
|
||||
<assemblyIdentity
|
||||
name="Prosperon"
|
||||
version="0.4"
|
||||
type="win32"
|
||||
/>
|
||||
<description>Prosperon Game Engine</description>
|
||||
<trustInfo xmlns="urn:schemas-microsoft-com:asm.v3">
|
||||
<security>
|
||||
<requestedPrivileges>
|
||||
<requestedExecutionLevel level="asInvoker" uiAccess="false"/>
|
||||
</requestedPrivileges>
|
||||
</security>
|
||||
</trustInfo>
|
||||
</assembly>
|
16
resource.rc
Normal file
16
resource.rc
Normal file
|
@ -0,0 +1,16 @@
|
|||
101 ICON "icon.ico"
|
||||
102 RT_MANIFEST "resource.manifest"
|
||||
103 VERSIONINFO
|
||||
BEGIN
|
||||
BLOCK "StringFileInfo"
|
||||
BEGIN
|
||||
BLOCK "040904b0"
|
||||
BEGIN
|
||||
VALUE "CompanyName", "Pockle World"
|
||||
VALUE "FileDescription", "Prosperon Game Engine"
|
||||
VALUE "FileVersion", "0.4.0"
|
||||
VALUE "LegalCopyright", "Copyright 2024 Pockle World."
|
||||
VALUE "ProductVersion", "0.4.0"
|
||||
END
|
||||
END
|
||||
END
|
|
@ -1,11 +1,10 @@
|
|||
var actor = {};
|
||||
var a_db = {};
|
||||
|
||||
actor.spawn = function(script, config){
|
||||
actor.spawn = function(script, config, callback){
|
||||
if (typeof script !== 'string') return undefined;
|
||||
if (!a_db[script]) a_db[script] = io.slurp(script);
|
||||
console.info(`spawning actor with script ${script}`);
|
||||
var padawan = Object.create(actor);
|
||||
eval_env(a_db[script], padawan, script);
|
||||
use(script, padawan);
|
||||
|
||||
if (typeof config === 'object')
|
||||
Object.merge(padawan,config);
|
||||
|
@ -30,7 +29,7 @@ actor.timers = [];
|
|||
actor.kill = function(){
|
||||
if (this.__dead__) return;
|
||||
this.timers.forEach(t => t());
|
||||
Player.do_uncontrol(this);
|
||||
input.do_uncontrol(this);
|
||||
Event.rm_obj(this);
|
||||
if (this.master) this.master.rm_pawn(this);
|
||||
this.padawans.forEach(p => p.kill());
|
||||
|
@ -42,10 +41,48 @@ actor.kill = function(){
|
|||
|
||||
actor.kill.doc = `Remove this actor and all its padawans from existence.`;
|
||||
|
||||
actor.interval = function(fn, seconds) {
|
||||
var cur;
|
||||
var stop = function() {
|
||||
cur();
|
||||
}
|
||||
|
||||
var f = function() {
|
||||
fn.call(this);
|
||||
cur = this.delay(f,seconds);
|
||||
}
|
||||
|
||||
cur = this.delay(f,seconds);
|
||||
|
||||
return stop;
|
||||
}
|
||||
|
||||
actor.delay = function(fn, seconds) {
|
||||
var t = timer.delay(fn.bind(this), seconds);
|
||||
this.timers.push(t);
|
||||
return t;
|
||||
var timers = this.timers;
|
||||
var stop = function() {
|
||||
timers.remove(stop);
|
||||
rm();
|
||||
}
|
||||
|
||||
function execute() {
|
||||
fn();
|
||||
stop();
|
||||
}
|
||||
|
||||
stop.remain = seconds;
|
||||
stop.seconds = seconds;
|
||||
stop.pct = function() { return 1-(stop.remain / stop.seconds); };
|
||||
|
||||
function update(dt) {
|
||||
stop.remain -= dt;
|
||||
if (stop.remain <= 0)
|
||||
execute();
|
||||
}
|
||||
|
||||
var rm = Register.appupdate.register(update);
|
||||
|
||||
timers.push(stop);
|
||||
return stop;
|
||||
};
|
||||
|
||||
actor.delay.doc = `Call 'fn' after 'seconds' with 'this' set to the actor.`;
|
||||
|
@ -53,10 +90,6 @@ actor.delay.doc = `Call 'fn' after 'seconds' with 'this' set to the actor.`;
|
|||
actor.padawans = [];
|
||||
|
||||
global.app = Object.create(actor);
|
||||
|
||||
app.die = function()
|
||||
{
|
||||
Game.quit();
|
||||
}
|
||||
app.die = function() { os.quit(); }
|
||||
|
||||
return {actor, app};
|
||||
|
|
|
@ -2,26 +2,28 @@ var ai = {
|
|||
race(list) {
|
||||
return function(dt) {
|
||||
var good = false;
|
||||
list.forEach(function(x) { if (x.call(this,dt)) good = true; }, this);
|
||||
for (var i = 0; i < list.length; i++)
|
||||
if (list[i].call(this,dt)) good=true;
|
||||
|
||||
return good;
|
||||
};
|
||||
},
|
||||
|
||||
do(times, list) {
|
||||
|
||||
},
|
||||
|
||||
sequence(list) {
|
||||
var i = 0;
|
||||
return function(dt) {
|
||||
var fn = function(dt) {
|
||||
while (i !== list.length) {
|
||||
if (list[i].call(this,dt))
|
||||
i++;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
if (fn.done) fn.done();
|
||||
return true;
|
||||
};
|
||||
|
||||
fn.restart = function() { i = 0; };
|
||||
return fn;
|
||||
},
|
||||
|
||||
parallel(list) {
|
||||
|
@ -32,30 +34,21 @@ var ai = {
|
|||
};
|
||||
},
|
||||
|
||||
moveto() {
|
||||
return function(dt) {
|
||||
var dir = this.randomloc.sub(this.pos);
|
||||
if (Vector.length(dir) < 10) return true;
|
||||
|
||||
this.velocity = Vector.norm(this.randomloc.sub(this.pos)).scale(20);
|
||||
return False;
|
||||
}
|
||||
dofor(secs, fn) {
|
||||
return ai.race([
|
||||
ai.wait(secs),
|
||||
fn
|
||||
]);
|
||||
},
|
||||
|
||||
move() {
|
||||
return function(dt) {
|
||||
this.velocity = this.left().scale(20);
|
||||
return false;
|
||||
}
|
||||
},
|
||||
|
||||
wait(secs) {
|
||||
secs ??= 1;
|
||||
wait(secs = 1) {
|
||||
var accum = 0;
|
||||
return function(dt) {
|
||||
accum += dt;
|
||||
if (accum >= secs)
|
||||
if (accum >= secs) {
|
||||
accum = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
};
|
||||
|
|
212
scripts/base.js
212
scripts/base.js
|
@ -8,6 +8,7 @@
|
|||
In addition to the removal of a bunch of stuff as seen here.
|
||||
Access prototypes through __proto__ instead of the long-winded Object.getProtoTypeOf.
|
||||
*/
|
||||
|
||||
/*
|
||||
Object.getPrototypeOf = undefined;
|
||||
Object.setPrototypeOf = undefined;
|
||||
|
@ -62,12 +63,12 @@ convert.buf2hex = function(buffer) { // buffer is an ArrayBuffer
|
|||
}
|
||||
|
||||
/* Time values are always expressed in terms of real earth-seconds */
|
||||
var time = {
|
||||
get hour2minute() { return this.hour/this.minute; },
|
||||
get day2hour() { return this.day/this.hour; },
|
||||
get minute2second() { return this.minute/this.second; },
|
||||
get week2day() { return this.week/this.day; },
|
||||
};
|
||||
Object.assign(time, {
|
||||
hour2minute() { return this.hour/this.minute; },
|
||||
day2hour() { return this.day/this.hour; },
|
||||
minute2second() { return this.minute/this.second; },
|
||||
week2day() { return this.week/this.day; },
|
||||
});
|
||||
|
||||
time.strparse = {
|
||||
yyyy: "year",
|
||||
|
@ -106,8 +107,6 @@ time.doc = {
|
|||
text: "Return a text formatted time."
|
||||
};
|
||||
|
||||
|
||||
|
||||
time.second = 1;
|
||||
time.minute = 60;
|
||||
time.hour = 3_600;
|
||||
|
@ -117,9 +116,6 @@ time.weekdays = ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday
|
|||
time.monthstr = ["January", "February", "March", 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'];
|
||||
|
||||
time.epoch = 1970;
|
||||
time.now = function() { return cmd(210);}
|
||||
time.computer_zone = function() { return cmd(211)/this.hour; }
|
||||
time.computer_dst = function() { return cmd(212); }
|
||||
time.isleap = function(year) { return this.yearsize(year) === 366; }
|
||||
time.isleap.doc = "Return true if the given year is a leapyear.";
|
||||
|
||||
|
@ -129,14 +125,20 @@ time.yearsize = function(y) {
|
|||
return 365;
|
||||
}
|
||||
|
||||
time.timecode = function(t, fps = 24)
|
||||
{
|
||||
var s = Math.trunc(t);
|
||||
t -= s;
|
||||
return `${s}:${Math.trunc(fps*s)}`;
|
||||
}
|
||||
|
||||
time.monthdays = [31,28,31,30,31,30,31,31,30,31,30,31];
|
||||
time.zones = {};
|
||||
time.zones['-12'] = 'IDLW';
|
||||
time.record = function(num, zone)
|
||||
time.record = function(num, zone = this.computer_zone())
|
||||
{
|
||||
if (typeof num === 'object') return num;
|
||||
else if (typeof num === 'number') {
|
||||
zone ??= this.computer_zone();
|
||||
var monthdays = this.monthdays.slice();
|
||||
var rec = {
|
||||
second: 0,
|
||||
|
@ -215,9 +217,9 @@ time.number = function(rec)
|
|||
c += this.day*this.yearsize(i);
|
||||
|
||||
c += (this.yearsize(year)-yday-1)*this.day;
|
||||
c += (this.day2hour-hour-1)*this.hour;
|
||||
c += (this.hour2minute-minute-1)*this.minute;
|
||||
c += (this.minute2second-second);
|
||||
c += (this.day2hour()-hour-1)*this.hour;
|
||||
c += (this.hour2minute()-minute-1)*this.minute;
|
||||
c += (this.minute2second()-second);
|
||||
c += zone*this.hour;
|
||||
c *= -1;
|
||||
return c;
|
||||
|
@ -258,9 +260,8 @@ time.number = function(rec)
|
|||
time.fmt = "vB mB d h:nn:ss TZz a y c";
|
||||
|
||||
/* If num is a number, converts to a rec first. */
|
||||
time.text = function(num, fmt, zone)
|
||||
time.text = function(num, fmt = this.fmt, zone)
|
||||
{
|
||||
fmt ??= this.fmt;
|
||||
var rec = num;
|
||||
|
||||
if (typeof rec === 'number')
|
||||
|
@ -312,37 +313,6 @@ time.text = function(num, fmt, zone)
|
|||
return fmt;
|
||||
}
|
||||
|
||||
var json = {};
|
||||
json.encode = function(value, space, replacer, whitelist)
|
||||
{
|
||||
return JSON.stringify(value, space, replacer);
|
||||
}
|
||||
|
||||
json.decode = function(text, reviver)
|
||||
{
|
||||
if (!text) return undefined;
|
||||
return JSON.parse(text,reviver);
|
||||
}
|
||||
|
||||
json.readout = function(obj)
|
||||
{
|
||||
var j = {};
|
||||
for (var k in obj)
|
||||
if (typeof obj[k] === 'function')
|
||||
j[k] = 'function ' + obj[k].toString();
|
||||
else
|
||||
j[k] = obj[k];
|
||||
|
||||
return json.encode(j);
|
||||
}
|
||||
|
||||
json.doc = {
|
||||
doc: "json implementation.",
|
||||
encode: "Encode a value to json.",
|
||||
decode: "Decode a json string to a value.",
|
||||
readout: "Encode an object fully, including function definitions."
|
||||
};
|
||||
|
||||
Object.methods = function(o)
|
||||
{
|
||||
var m = [];
|
||||
|
@ -353,9 +323,8 @@ Object.methods = function(o)
|
|||
}
|
||||
Object.methods.doc = "Retun an array of all functions an object has access to.";
|
||||
|
||||
Object.dig = function(obj, path, def)
|
||||
Object.dig = function(obj, path, def = {})
|
||||
{
|
||||
def ??= {};
|
||||
var pp = path.split('.');
|
||||
for (var i = 0; i < pp.length-1; i++) {
|
||||
obj = obj[pp[i]] = obj[pp[i]] || {};
|
||||
|
@ -364,17 +333,6 @@ Object.dig = function(obj, path, def)
|
|||
return def;
|
||||
}
|
||||
|
||||
Object.samenewkeys = function(a,b)
|
||||
{
|
||||
b ??= a.__proto__;
|
||||
var ret = {};
|
||||
ret.same = [];
|
||||
ret.unique = [];
|
||||
Object.keys(a).forEach(key => (key in b) ? ret.same.push(key) : ret.unique.push(key));
|
||||
return ret;
|
||||
}
|
||||
Object.samenewkeys.doc = "Return an object listing which keys are the same and unique on a compared to b.";
|
||||
|
||||
Object.rkeys = function(o)
|
||||
{
|
||||
var keys = [];
|
||||
|
@ -386,6 +344,20 @@ Object.rkeys = function(o)
|
|||
return keys;
|
||||
}
|
||||
|
||||
Object.readonly = function(o, name, msg)
|
||||
{
|
||||
var tmp = {};
|
||||
var prop = Object.getOwnPropertyDescriptor(o, name);
|
||||
if (!prop) {
|
||||
console.error(`Attempted to make property ${name} readonly, but it doesn't exist on ${o}.`);
|
||||
return;
|
||||
}
|
||||
Object.defineProperty(tmp, name, prop);
|
||||
prop.get = function() { return tmp[name]; }
|
||||
prop.set = function() { console.warn(`Attempted to set readonly property ${name}`); }
|
||||
Object.defineProperty(o, name, prop);
|
||||
}
|
||||
|
||||
Object.extend = function(from)
|
||||
{
|
||||
var n = {};
|
||||
|
@ -587,10 +559,8 @@ Object.defineProperty(Object.prototype, 'obscure', {
|
|||
|
||||
Object.defineProperty(Object.prototype, 'mixin', {
|
||||
value: function(obj) {
|
||||
if (typeof obj === 'string') {
|
||||
var script = io.slurp(obj);
|
||||
obj = eval_env(script, this, obj);
|
||||
}
|
||||
if (typeof obj === 'string')
|
||||
obj = use(obj, this);
|
||||
|
||||
if (obj)
|
||||
Object.mixin(this, obj);
|
||||
|
@ -816,14 +786,6 @@ Object.defineProperty(String.prototype, 'fromlast', {
|
|||
}
|
||||
});
|
||||
|
||||
Object.defineProperty(String.prototype, 'tolast', {
|
||||
value: function(val) {
|
||||
var idx = this.lastIndexOf(val);
|
||||
if (idx === -1) return this.slice();
|
||||
return this.slice(0,idx);
|
||||
}
|
||||
});
|
||||
|
||||
Object.defineProperty(String.prototype, 'tofirst', {
|
||||
value: function(val) {
|
||||
var idx = this.indexOf(val);
|
||||
|
@ -852,13 +814,6 @@ Object.defineProperty(String.prototype, 'base', {
|
|||
value: function() { return this.fromlast('/'); }
|
||||
});
|
||||
|
||||
Object.defineProperty(String.prototype, 'dir', {
|
||||
value: function() {
|
||||
if (!this.includes('/')) return "";
|
||||
return this.tolast('/');
|
||||
}
|
||||
});
|
||||
|
||||
Object.defineProperty(String.prototype, 'splice', {
|
||||
value: function(index, str) {
|
||||
return this.slice(0,index) + str + this.slice(index);
|
||||
|
@ -866,10 +821,7 @@ Object.defineProperty(String.prototype, 'splice', {
|
|||
});
|
||||
|
||||
Object.defineProperty(String.prototype, 'rm', {
|
||||
value: function(index, endidx) {
|
||||
endidx ??= index+1;
|
||||
return this.slice(0,index) + this.slice(endidx);
|
||||
}
|
||||
value: function(index, endidx = index+1) { return this.slice(0,index) + this.slice(endidx); }
|
||||
});
|
||||
|
||||
Object.defineProperty(String.prototype, 'updir', {
|
||||
|
@ -927,6 +879,11 @@ Object.defineProperty(String.prototype, 'uc', { value: function() { return this.
|
|||
Object.defineProperty(String.prototype, 'lc', {value:function() { return this.toLowerCase(); }});
|
||||
|
||||
/* ARRAY DEFS */
|
||||
Object.defineProperty(Array.prototype, 'aspect', {
|
||||
value: function() {
|
||||
return this.x/this.y;
|
||||
}
|
||||
});
|
||||
Object.defineProperty(Array.prototype, 'copy', {
|
||||
value: function() {
|
||||
var c = [];
|
||||
|
@ -941,14 +898,12 @@ Object.defineProperty(Array.prototype, 'copy', {
|
|||
|
||||
Object.defineProperty(Array.prototype, 'dofilter', {
|
||||
value: function(fn) {
|
||||
var j = 0;
|
||||
this.forEach(function(val,i) {
|
||||
if (fn(val)) {
|
||||
if (i !== j) this[j] = val;
|
||||
j++;
|
||||
for (let i = 0; i < this.length; i++) {
|
||||
if (!fn.call(this, this[i], i, this)) {
|
||||
this.splice(i, 1);
|
||||
i--;
|
||||
}
|
||||
}
|
||||
}, this);
|
||||
this.length = j;
|
||||
return this;
|
||||
}
|
||||
});
|
||||
|
@ -1138,13 +1093,19 @@ Object.defineProperty(Array.prototype, 'scale', {
|
|||
return this.map(function(x) { return x*s; });
|
||||
}});
|
||||
|
||||
Object.defineProperty(Array.prototype, 'sorted', {
|
||||
value: function() {
|
||||
return this.toSorted();
|
||||
}
|
||||
});
|
||||
|
||||
Object.defineProperty(Array.prototype, 'equal', {
|
||||
value: function(b) {
|
||||
if (this.length !== b.length) return false;
|
||||
if (b == null) return false;
|
||||
if (this === b) return true;
|
||||
|
||||
return JSON.stringify(this.sort()) === JSON.stringify(b.sort());
|
||||
return JSON.stringify(this.sorted()) === JSON.stringify(b.sorted());
|
||||
|
||||
for (var i = 0; i < this.length; i++) {
|
||||
if (!this[i] === b[i])
|
||||
|
@ -1401,6 +1362,21 @@ Math.randomint = function(max) { return Math.clamp(Math.floor(Math.random() * ma
|
|||
/* BOUNDINGBOXES */
|
||||
var bbox = {};
|
||||
|
||||
bbox.overlap = function(box1, box2) {
|
||||
return (
|
||||
box1.l > box2.l &&
|
||||
box1.r < box2.r &&
|
||||
box1.t < box2.t &&
|
||||
box1.b > box2.b
|
||||
);
|
||||
return (
|
||||
box1.l > box2.r ||
|
||||
box1.r < box2.l ||
|
||||
box1.t > box2.b ||
|
||||
box1.b < box2.t
|
||||
);
|
||||
}
|
||||
|
||||
bbox.fromcwh = function(c, wh) {
|
||||
return {
|
||||
t: c.y+(wh.y/2),
|
||||
|
@ -1499,42 +1475,32 @@ bbox.fromobjs = function(objs)
|
|||
};
|
||||
|
||||
/* VECTORS */
|
||||
var Vector = {
|
||||
length(v) {
|
||||
var Vector = {};
|
||||
Vector.length = function(v) {
|
||||
var sum = v.reduce(function(acc, val) { return acc + val**2; }, 0);
|
||||
return Math.sqrt(sum);
|
||||
},
|
||||
|
||||
norm(v) {
|
||||
}
|
||||
Vector.norm = function(v) {
|
||||
var len = Vector.length(v);
|
||||
if (!len) return [0,0];
|
||||
return [v.x/len, v.y/len];
|
||||
},
|
||||
|
||||
project(a, b) {
|
||||
return cmd(85, a, b);
|
||||
},
|
||||
|
||||
dot(a, b) {
|
||||
return cmd(88,a,b);
|
||||
},
|
||||
|
||||
random() {
|
||||
}
|
||||
Vector.project = function(a, b) { return vector.project(a,b); }
|
||||
Vector.dot = function(a, b) { return vector.dot(a,b); },
|
||||
Vector.random = function() {
|
||||
var vec = [Math.random()-0.5, Math.random()-0.5];
|
||||
return Vector.norm(vec);
|
||||
},
|
||||
}
|
||||
|
||||
angle(v) {
|
||||
return Math.rad2turn(Math.atan2(v.y, v.x));
|
||||
},
|
||||
|
||||
rotate(v,angle) {
|
||||
Vector.angle = function(v) { return Math.rad2turn(Math.atan2(v.y, v.x)); }
|
||||
Vector.rotate = function(v,angle) {
|
||||
var r = Vector.length(v);
|
||||
angle += Vector.angle(v);
|
||||
angle = Math.turn2rad(angle);
|
||||
return [r*Math.cos(angle), r*Math.sin(angle)];
|
||||
},
|
||||
}
|
||||
|
||||
equal(v1, v2, tol) {
|
||||
Vector.equal = function(v1, v2, tol) {
|
||||
if (!tol)
|
||||
return v1.equal(v2);
|
||||
|
||||
|
@ -1548,18 +1514,14 @@ var Vector = {
|
|||
});
|
||||
|
||||
return eql;
|
||||
},
|
||||
}
|
||||
|
||||
reflect(vec, plane) {
|
||||
Vector.reflect = function(vec, plane) {
|
||||
var p = Vector.norm(plane);
|
||||
return vec.sub(p.scale(2*Vector.dot(vec, p)));
|
||||
},
|
||||
}
|
||||
|
||||
reflect_point(vec, point) {
|
||||
return point.add(vec.sub(point).scale(-1));
|
||||
},
|
||||
|
||||
};
|
||||
Vector.reflect_point = function(vec, point) { return point.add(vec.sub(point).scale(-1)); }
|
||||
|
||||
/* POINT ASSISTANCE */
|
||||
|
||||
|
|
|
@ -1,29 +1,44 @@
|
|||
this.phys = physics.kinematic;
|
||||
this.dir_view2world = function(dir) { return dir.scale(this.realzoom()); };
|
||||
this.view2world = function(pos) { return cmd(137,pos); };
|
||||
this.world2view = function(pos) { return cmd(136,pos); };
|
||||
this.realzoom = function() { return cmd(135); };
|
||||
|
||||
this.right = function()
|
||||
{
|
||||
return this.pos.x + (Window.rendersize.x/2);
|
||||
this.dir_view2world = function(dir) { return dir.scale(this.zoom); };
|
||||
this.view2world = function(pos) {
|
||||
var useren = window.rendersize.scale(this.zoom);
|
||||
if (window.mode === window.modetypes.stretch) {
|
||||
pos = pos.scale([window.rendersize.x/window.size.x, window.rendersize.y/window.size.y]);
|
||||
pos = pos.sub(window.rendersize.scale(0.5));
|
||||
pos = pos.scale(this.zoom);
|
||||
pos = pos.add(this.pos);
|
||||
}
|
||||
|
||||
this.left = function()
|
||||
{
|
||||
return this.pos.x - (Window.rendersize.x/2);
|
||||
if (window.mode === window.modetypes.full) {
|
||||
pos = pos.sub(window.size.scale(0.5));
|
||||
pos = pos.scale(this.zoom);
|
||||
pos = pos.add(this.pos);
|
||||
}
|
||||
return pos;
|
||||
};
|
||||
this.world2view = function(pos) {
|
||||
if (window.mode === window.modetypes.stretch) {
|
||||
pos = pos.sub(this.pos);
|
||||
pos = pos.scale(1.0/this.zoom);
|
||||
pos = pos.add(window.rendersize.scale(0.5));
|
||||
}
|
||||
if (window.mode === window.modetypes.full) {
|
||||
pos = pos.sub(this.pos);
|
||||
pos = pos.scale(1/this.zoom);
|
||||
pos = pos.add(window.size.scale(0.5));
|
||||
}
|
||||
return pos;
|
||||
};
|
||||
|
||||
this.mixin({
|
||||
get zoom() {
|
||||
// var z = Game.native.y / Window.dimensions.y;
|
||||
return cmd(135);///z;
|
||||
},
|
||||
this.screenright = function() { return this.view2world(window.size).x; }
|
||||
this.screenleft = function() { return this.view2world([0,0]).x; }
|
||||
|
||||
var zoom = 1;
|
||||
|
||||
Object.mixin(self, {
|
||||
set zoom(x) {
|
||||
x = Math.clamp(x,0.1,10);
|
||||
// var z = Game.native.y / Window.dimensions.y;
|
||||
// z *= x;
|
||||
cmd(62,x);
|
||||
zoom = x;
|
||||
if (zoom <= 0.1) zoom = 0.1;
|
||||
},
|
||||
});
|
||||
get zoom() { return zoom; }
|
||||
}
|
||||
);
|
||||
|
|
|
@ -173,9 +173,8 @@ ColorMap.Viridis = ColorMap.makemap({
|
|||
|
||||
Color.normalize(ColorMap);
|
||||
|
||||
ColorMap.sample = function(t, map)
|
||||
ColorMap.sample = function(t, map = this)
|
||||
{
|
||||
map ??= this;
|
||||
if (t < 0) return map[0];
|
||||
if (t > 1) return map[1];
|
||||
|
||||
|
|
|
@ -22,10 +22,11 @@ var component = {
|
|||
make(go) {
|
||||
var nc = Object.create(this);
|
||||
nc.gameobject = go;
|
||||
Object.mixin(nc, this._enghook(go.body));
|
||||
Object.mixin(nc, this._enghook(go, nc));
|
||||
assign_impl(nc,this.impl);
|
||||
Object.hide(nc, 'gameobject', 'id');
|
||||
nc.post();
|
||||
nc.make = undefined;
|
||||
return nc;
|
||||
},
|
||||
|
||||
|
@ -75,7 +76,8 @@ function json_from_whitelist(whitelist)
|
|||
}
|
||||
}
|
||||
|
||||
Object.mixin(cmd(268,true), {
|
||||
Object.mixin(os.sprite(true), {
|
||||
loop: true,
|
||||
toJSON:json_from_whitelist([
|
||||
"path",
|
||||
"pos",
|
||||
|
@ -88,36 +90,66 @@ Object.mixin(cmd(268,true), {
|
|||
]),
|
||||
anim:{},
|
||||
playing: 0,
|
||||
play(str) {
|
||||
var sp = this;
|
||||
str ??= 0;
|
||||
var playing = this.anim[str];
|
||||
if (!playing) return; //TODO: ERROR
|
||||
play(str = 0) {
|
||||
this.del_anim?.();
|
||||
var self = this;
|
||||
var stop;
|
||||
self.del_anim = function() {
|
||||
self.del_anim = undefined;
|
||||
self = undefined;
|
||||
advance = undefined;
|
||||
stop?.();
|
||||
}
|
||||
var playing = self.anim[str];
|
||||
if (!playing) return;
|
||||
var f = 0;
|
||||
self.path = playing.path;
|
||||
|
||||
function advance() {
|
||||
sp.path = playing.path;
|
||||
sp.frame = playing.frames[f].rect;
|
||||
if (!self) return;
|
||||
if (!self.gameobject) return;
|
||||
//self.path = playing.path;
|
||||
self.frame = playing.frames[f].rect;
|
||||
f = (f+1)%playing.frames.length;
|
||||
if (f === 0)
|
||||
sp.anim_done?.();
|
||||
sp.gameobject?.delay(advance, playing.frames[f].time);
|
||||
if (f === 0) {
|
||||
self.anim_done?.();
|
||||
if (!self.loop) { self.stop(); return; }
|
||||
}
|
||||
stop = self.gameobject.delay(advance, playing.frames[f].time);
|
||||
}
|
||||
this.tex(game.texture(playing.path));
|
||||
advance();
|
||||
},
|
||||
stop() {},
|
||||
stop() {
|
||||
this.del_anim?.();
|
||||
},
|
||||
set path(p) {
|
||||
p = Resources.find_image(p);
|
||||
if (!p) return;
|
||||
if (!p) {
|
||||
console.warn(`Could not find image ${p}.`);
|
||||
return;
|
||||
}
|
||||
if (p === this.path) return;
|
||||
this.tex = cmd(269,p);
|
||||
this._p = p;
|
||||
this.del_anim?.();
|
||||
this.texture = game.texture(p);
|
||||
this.tex(this.texture);
|
||||
|
||||
var anim = SpriteAnim.make(p);
|
||||
if (!anim) return;
|
||||
this.anim = anim;
|
||||
this.play();
|
||||
|
||||
this.pos = this.dimensions().scale(this.anchor);
|
||||
},
|
||||
get path() {
|
||||
return this.tex.path();
|
||||
return this._p;
|
||||
},
|
||||
kill() {
|
||||
this.del_anim?.();
|
||||
this.anim = undefined;
|
||||
this.gameobject = undefined;
|
||||
this.anim_done = undefined;
|
||||
},
|
||||
toString() { return "sprite"; },
|
||||
move(d) { this.pos = this.pos.add(d); },
|
||||
|
@ -125,7 +157,7 @@ Object.mixin(cmd(268,true), {
|
|||
this.scale = this.scale.scale(x);
|
||||
this.pos = this.pos.scale(x);
|
||||
},
|
||||
|
||||
anchor:[0,0],
|
||||
sync() { },
|
||||
pick() { return this; },
|
||||
boundingbox() {
|
||||
|
@ -136,7 +168,7 @@ Object.mixin(cmd(268,true), {
|
|||
},
|
||||
|
||||
dimensions() {
|
||||
var dim = [this.tex.width(), this.tex.height()];
|
||||
var dim = [this.texture.width, this.texture.height];
|
||||
dim.x *= this.frame.w;
|
||||
dim.y *= this.frame.h;
|
||||
return dim;
|
||||
|
@ -145,28 +177,15 @@ Object.mixin(cmd(268,true), {
|
|||
height() { return this.dimensions().y; },
|
||||
});
|
||||
|
||||
cmd(268,true).make = function(go)
|
||||
os.sprite(true).make = function(go)
|
||||
{
|
||||
var sp = cmd(268);
|
||||
sp.go = go.body;
|
||||
var sp = os.sprite();
|
||||
sp.go = go;
|
||||
sp.gameobject = go;
|
||||
return sp;
|
||||
}
|
||||
|
||||
component.sprite = cmd(268,true);
|
||||
|
||||
Object.freeze(sprite);
|
||||
|
||||
component.model = Object.copy(component, {
|
||||
path:"",
|
||||
_enghook: make_model,
|
||||
});
|
||||
|
||||
component.model.impl = {
|
||||
set path(x) { cmd(149, this.id, x); },
|
||||
draw() { cmd(150, this.id); },
|
||||
kill() { cmd(213, this.id); },
|
||||
};
|
||||
component.sprite = os.sprite(true);
|
||||
|
||||
var sprite = component.sprite;
|
||||
|
||||
|
@ -176,16 +195,34 @@ sprite.doc = {
|
|||
pos: "The offset position of the sprite, relative to its entity."
|
||||
};
|
||||
|
||||
sprite.setanchor = function(anch) {
|
||||
var off = [0,0];
|
||||
switch(anch) {
|
||||
case "ll": break;
|
||||
case "lm": off = [-0.5,0]; break;
|
||||
case "lr": off = [-1,0]; break;
|
||||
case "ml": off = [0,-0.5]; break;
|
||||
case "mm": off = [-0.5,-0.5]; break;
|
||||
case "mr": off = [-1,-0.5]; break;
|
||||
case "ul": off = [0,-1]; break;
|
||||
case "um": off = [-0.5,-1]; break;
|
||||
case "ur": off = [-1,-1]; break;
|
||||
}
|
||||
this.anchor = off;
|
||||
this.pos = this.dimensions().scale(off);
|
||||
}
|
||||
|
||||
sprite.inputs = {};
|
||||
sprite.inputs.kp9 = function() { this.pos = this.dimensions().scale([0,0]); };
|
||||
sprite.inputs.kp8 = function() { this.pos = this.dimensions().scale([-0.5, 0]); };
|
||||
sprite.inputs.kp7 = function() { this.pos = this.dimensions().scale([-1,0]); };
|
||||
sprite.inputs.kp6 = function() { this.pos = this.dimensions().scale([0,-0.5]); };
|
||||
sprite.inputs.kp5 = function() { this.pos = this.dimensions().scale([-0.5,-0.5]); };
|
||||
sprite.inputs.kp4 = function() { this.pos = this.dimensions().scale([-1,-0.5]); };
|
||||
sprite.inputs.kp3 = function() { this.pos = this.dimensions().scale([0, -1]); };
|
||||
sprite.inputs.kp2 = function() { this.pos = this.dimensions().scale([-0.5,-1]); };
|
||||
sprite.inputs.kp1 = function() { this.pos = this.dimensions().scale([-1,-1]); };
|
||||
sprite.inputs.kp9 = function() { this.setanchor("ll"); }
|
||||
sprite.inputs.kp8 = function() { this.setanchor("lm"); }
|
||||
sprite.inputs.kp7 = function() { this.setanchor("lr"); }
|
||||
sprite.inputs.kp6 = function() { this.setanchor("ml"); }
|
||||
sprite.inputs.kp5 = function() { this.setanchor("mm"); }
|
||||
sprite.inputs.kp4 = function() { this.setanchor("mr"); }
|
||||
sprite.inputs.kp3 = function() { this.setanchor("ur"); }
|
||||
sprite.inputs.kp2 = function() { this.setanchor("um"); }
|
||||
sprite.inputs.kp1 = function() { this.setanchor("ul"); }
|
||||
|
||||
Object.seal(sprite);
|
||||
|
||||
/* sprite anim returns a data structure for the given file path
|
||||
|
@ -194,20 +231,34 @@ Object.seal(sprite);
|
|||
time: miliseconds to hold the frame for
|
||||
loop: true if it should be looped
|
||||
*/
|
||||
var SpriteAnim = {
|
||||
make(path) {
|
||||
if (path.ext() === 'gif')
|
||||
return SpriteAnim.gif(path);
|
||||
var animcache = {};
|
||||
var SpriteAnim = {};
|
||||
SpriteAnim.make = function(path) {
|
||||
if (path in animcache) return animcache[path];
|
||||
var anim;
|
||||
if (io.exists(path.set_ext(".ase")))
|
||||
anim = SpriteAnim.aseprite(path.set_ext(".ase"));
|
||||
else if (io.exists(path.set_ext(".json")))
|
||||
anim = SpriteAnim.aseprite(path.set_ext(".json"));
|
||||
else if (path.ext() === 'ase')
|
||||
return SpriteAnim.aseprite(path);
|
||||
anim = SpriteAnim.aseprite(path);
|
||||
else if (path.ext() === 'gif')
|
||||
anim = SpriteAnim.gif(path);
|
||||
else
|
||||
return undefined;
|
||||
},
|
||||
gif(path) {
|
||||
anim = undefined;
|
||||
|
||||
animcache[path] = anim;
|
||||
return animcache[path];
|
||||
};
|
||||
SpriteAnim.gif = function(path) {
|
||||
console.info(`making an anim from ${path}`);
|
||||
var anim = {};
|
||||
anim.frames = [];
|
||||
anim.path = path;
|
||||
var frames = Resources.gif.frames(path);
|
||||
var tex = game.texture(path);
|
||||
var frames = tex.frames;
|
||||
console.info(`frames are ${frames}`);
|
||||
if (frames === 1) return undefined;
|
||||
var yslice = 1/frames;
|
||||
for (var f = 0; f < frames; f++) {
|
||||
var frame = {};
|
||||
|
@ -220,17 +271,18 @@ var SpriteAnim = {
|
|||
frame.time = 0.05;
|
||||
anim.frames.push(frame);
|
||||
}
|
||||
var times = cmd(224,path);
|
||||
var times = tex.delays;
|
||||
for (var i = 0; i < frames; i++)
|
||||
anim.frames[i].time = times[i]/1000;
|
||||
anim.loop = true;
|
||||
var dim = Resources.texture.dimensions(path);
|
||||
var dim = [tex.width,tex.height];
|
||||
console.info(`dimensions are ${dim}`);
|
||||
dim.y /= frames;
|
||||
anim.dim = dim;
|
||||
return {0:anim};
|
||||
},
|
||||
};
|
||||
|
||||
strip(path, frames, time=0.05) {
|
||||
SpriteAnim.strip = function(path, frames, time=0.05) {
|
||||
var anim = {};
|
||||
anim.frames = [];
|
||||
anim.path = path;
|
||||
|
@ -244,16 +296,16 @@ var SpriteAnim = {
|
|||
anim.dim = Resources.texture.dimensions(path);
|
||||
anim.dim.x /= frames;
|
||||
return anim;
|
||||
},
|
||||
};
|
||||
|
||||
aseprite(path) {
|
||||
SpriteAnim.aseprite = function(path) {
|
||||
function aseframeset2anim(frameset, meta) {
|
||||
var anim = {};
|
||||
anim.frames = [];
|
||||
anim.path = meta.image;
|
||||
anim.path = path.dir() + "/" + meta.image;
|
||||
var dim = meta.size;
|
||||
|
||||
var ase_make_frame = function(ase_frame,i) {
|
||||
var ase_make_frame = function(ase_frame) {
|
||||
var f = ase_frame.frame;
|
||||
var frame = {};
|
||||
frame.rect = {
|
||||
|
@ -267,38 +319,35 @@ var SpriteAnim = {
|
|||
};
|
||||
|
||||
frameset.forEach(ase_make_frame);
|
||||
anim.dim = [frameset[0].sourceSize.x, frameset[0].sourceSize.y];
|
||||
anim.dim = frameset[0].sourceSize;
|
||||
anim.loop = true;
|
||||
return anim;
|
||||
};
|
||||
|
||||
var json = io.slurp(path);
|
||||
json = JSON.parse(json);
|
||||
var data = json.decode(io.slurp(path));
|
||||
if (!data?.meta?.app.includes("aseprite")) return;
|
||||
var anims = {};
|
||||
var frames = Array.isArray(json.frames) ? json.frames : Object.values(json.frames);
|
||||
var frames = Array.isArray(data.frames) ? data.frames : Object.values(data.frames);
|
||||
var f = 0;
|
||||
for (var tag of json.meta.frameTags) {
|
||||
anims[tag.name] = aseframeset2anim(frames.slice(tag.from, tag.to+1), json.meta);
|
||||
for (var tag of data.meta.frameTags) {
|
||||
anims[tag.name] = aseframeset2anim(frames.slice(tag.from, tag.to+1), data.meta);
|
||||
anims[f] = anims[tag.name];
|
||||
f++;
|
||||
}
|
||||
|
||||
return anims;
|
||||
},
|
||||
};
|
||||
|
||||
validate(anim)
|
||||
{
|
||||
SpriteAnim.validate = function(anim) {
|
||||
if (!Object.isObject(anim)) return false;
|
||||
if (typeof anim.path !== 'string') return false;
|
||||
if (typeof anim.dim !== 'object') return false;
|
||||
return true;
|
||||
},
|
||||
};
|
||||
|
||||
find(path) {
|
||||
SpriteAnim.find = function(path) {
|
||||
if (!io.exists(path + ".asset")) return;
|
||||
var asset = JSON.parse(io.slurp(path + ".asset"));
|
||||
|
||||
},
|
||||
};
|
||||
|
||||
SpriteAnim.doc = 'Functions to create Primum animations from varying sources.';
|
||||
|
@ -309,16 +358,11 @@ SpriteAnim.find.doc = 'Given a path, find the relevant animation for the file.';
|
|||
|
||||
/* For all colliders, "shape" is a pointer to a phys2d_shape, "id" is a pointer to the shape data */
|
||||
var collider2d = Object.copy(component, {
|
||||
name: "collider 2d",
|
||||
sensor: false,
|
||||
|
||||
kill() {}, /* No killing is necessary - it is done through the gameobject's kill */
|
||||
|
||||
impl: {
|
||||
set sensor(x) { cmd(18,this.shape,x); },
|
||||
get sensor() { return cmd(21,this.shape); },
|
||||
set enabled(x) { cmd(22,this.shape,x); },
|
||||
get enabled() { return cmd(23,this.shape); }
|
||||
set sensor(x) { pshape.set_sensor(this.shape,x); },
|
||||
get sensor() { return pshape.get_sensor(this.shape); },
|
||||
set enabled(x) { pshape.set_enabled(this.shape,x); },
|
||||
get enabled() { return pshape.get_enabled(this.shape); }
|
||||
},
|
||||
});
|
||||
|
||||
|
@ -345,7 +389,7 @@ component.polygon2d = Object.copy(collider2d, {
|
|||
},
|
||||
|
||||
hides: ['id', 'shape', 'gameobject'],
|
||||
_enghook: make_poly2d,
|
||||
_enghook: os.make_poly2d,
|
||||
points:[],
|
||||
setpoints(points) {
|
||||
this.points = points;
|
||||
|
@ -376,7 +420,7 @@ component.polygon2d = Object.copy(collider2d, {
|
|||
|
||||
gizmo() {
|
||||
this.spoints().forEach(x => render.point(this.gameobject.this2screen(x), 3, Color.green));
|
||||
this.points.forEach((x,i)=>Debug.numbered_point(this.gameobject.this2screen(x), i));
|
||||
this.points.forEach((x,i)=>render.coordinate(this.gameobject.this2screen(x)));
|
||||
},
|
||||
|
||||
pick(pos) {
|
||||
|
@ -398,8 +442,8 @@ function pointscaler(x) {
|
|||
}
|
||||
|
||||
component.polygon2d.impl = Object.mix(collider2d.impl, {
|
||||
sync() { cmd_poly2d(0, this.id, this.spoints());},
|
||||
query() { return cmd(80, this.shape); },
|
||||
sync() { poly2d.setverts(this.id,this.spoints()); },
|
||||
query() { return physics.shape_query(this.shape); },
|
||||
grow: pointscaler,
|
||||
});
|
||||
|
||||
|
@ -413,14 +457,14 @@ polygon2d.inputs.f10 = function() {
|
|||
polygon2d.inputs.f10.doc = "Sort all points to be CCW order.";
|
||||
|
||||
polygon2d.inputs['C-lm'] = function() {
|
||||
this.points.push(this.gameobject.world2this(Mouse.worldpos()));
|
||||
this.points.push(this.gameobject.world2this(input.mouse.worldpos()));
|
||||
};
|
||||
polygon2d.inputs['C-lm'].doc = "Add a point to location of mouse.";
|
||||
polygon2d.inputs.lm = function(){};
|
||||
polygon2d.inputs.lm.released = function(){};
|
||||
|
||||
polygon2d.inputs['C-M-lm'] = function() {
|
||||
var idx = Math.grab_from_points(Mouse.worldpos(), this.points.map(p => this.gameobject.this2world(p)), 25);
|
||||
var idx = Math.grab_from_points(input.mouse.worldpos(), this.points.map(p => this.gameobject.this2world(p)), 25);
|
||||
if (idx === -1) return;
|
||||
this.points.splice(idx, 1);
|
||||
};
|
||||
|
@ -440,6 +484,7 @@ component.edge2d = Object.copy(collider2d, {
|
|||
'points',
|
||||
'hollow',
|
||||
'hollowt',
|
||||
'angle',
|
||||
]),
|
||||
dimensions:2,
|
||||
thickness:0,
|
||||
|
@ -484,7 +529,7 @@ component.edge2d = Object.copy(collider2d, {
|
|||
}
|
||||
|
||||
if (this.hollow) {
|
||||
var hpoints = inflate_cpv(spoints, spoints.length, this.hollowt);
|
||||
var hpoints = vector.inflate(spoints, this.hollowt);
|
||||
if (hpoints.length === spoints.length) return spoints;
|
||||
var arr1 = hpoints.filter(function(x,i) { return i % 2 === 0; });
|
||||
var arr2 = hpoints.filter(function(x,i) { return i % 2 !== 0; });
|
||||
|
@ -530,20 +575,20 @@ component.edge2d = Object.copy(collider2d, {
|
|||
boundingbox() { return bbox.frompoints(this.points.map(x => x.scale(this.gameobject.scale))); },
|
||||
|
||||
hides: ['gameobject', 'id', 'shape'],
|
||||
_enghook: make_edge2d,
|
||||
_enghook: os.make_edge2d,
|
||||
|
||||
/* EDITOR */
|
||||
gizmo() {
|
||||
if (this.type === Spline.type.catmull || this.type === -1) {
|
||||
this.spoints().forEach(x => render.point(this.gameobject.this2screen(x), 3, Color.teal));
|
||||
this.points.forEach((x,i) => Debug.numbered_point(this.gameobject.this2screen(x), i));
|
||||
this.points.forEach((x,i) => render.coordinate(this.gameobject.this2screen(x)));
|
||||
} else {
|
||||
for (var i = 0; i < this.points.length; i += 3)
|
||||
Debug.numbered_point(this.gameobject.this2screen(this.points[i]), i, Color.teal);
|
||||
render.coordinate(this.gameobject.this2screen(this.points[i]), 1, Color.teal);
|
||||
|
||||
for (var i = 1; i < this.points.length; i+=3) {
|
||||
Debug.numbered_point(this.gameobject.this2screen(this.points[i]), i, Color.green);
|
||||
Debug.numbered_point(this.gameobject.this2screen(this.points[i+1]), i+1, Color.green);
|
||||
render.coordinate(this.gameobject.this2screen(this.points[i]), 1, Color.green);
|
||||
render.coordinate(this.gameobject.this2screen(this.points[i+1]), 1, Color.green);
|
||||
render.line([this.gameobject.this2screen(this.points[i-1]), this.gameobject.this2screen(this.points[i])], Color.yellow);
|
||||
render.line([this.gameobject.this2screen(this.points[i+1]), this.gameobject.this2screen(this.points[i+2])], Color.yellow);
|
||||
}
|
||||
|
@ -607,7 +652,7 @@ component.edge2d = Object.copy(collider2d, {
|
|||
var idx = 0;
|
||||
if (Spline.is_catmull(this.type) || this.type === -1) {
|
||||
if (this.points.length >= 2)
|
||||
idx = cmd(59, pos, this.points, 400);
|
||||
idx = physics.closest_point(pos, this.points, 400);
|
||||
|
||||
if (idx === this.points.length)
|
||||
this.points.push(pos);
|
||||
|
@ -616,7 +661,7 @@ component.edge2d = Object.copy(collider2d, {
|
|||
}
|
||||
|
||||
if (Spline.is_bezier(this.type)) {
|
||||
idx = cmd(59, pos, Spline.bezier_nodes(this.points),400);
|
||||
idx = physics.closest_point(pos, Spline.bezier_nodes(this.points),400);
|
||||
|
||||
if (idx < 0) return;
|
||||
|
||||
|
@ -642,16 +687,14 @@ component.edge2d = Object.copy(collider2d, {
|
|||
});
|
||||
|
||||
component.edge2d.impl = Object.mix(collider2d.impl, {
|
||||
set thickness(x) {
|
||||
cmd_edge2d(1,this.id,x);
|
||||
},
|
||||
get thickness() { return cmd(112,this.id); },
|
||||
set thickness(x) { edge2d.set_thickness(this.id,x); },
|
||||
get thickness() { return edge2d.get_thickness(this.id); },
|
||||
grow: pointscaler,
|
||||
sync() {
|
||||
var sensor = this.sensor;
|
||||
var points = this.sample();
|
||||
if (!points) return;
|
||||
cmd_edge2d(0,this.id,points);
|
||||
edge2d.setverts(this.id,points);
|
||||
this.sensor = sensor;
|
||||
},
|
||||
});
|
||||
|
@ -659,7 +702,6 @@ component.edge2d.impl = Object.mix(collider2d.impl, {
|
|||
var bucket = component.edge2d;
|
||||
bucket.spoints.doc = "Returns the controls points after modifiers are applied, such as it being hollow or mirrored on its axises.";
|
||||
bucket.inputs = {};
|
||||
//bucket.inputs.post = function() { this.sync(); };
|
||||
bucket.inputs.h = function() { this.hollow = !this.hollow; };
|
||||
bucket.inputs.h.doc = "Toggle hollow.";
|
||||
|
||||
|
@ -731,7 +773,7 @@ bucket.inputs['C-o'].doc = "Set spline to linear.";
|
|||
|
||||
bucket.inputs['C-M-lm'] = function() {
|
||||
if (Spline.is_catmull(this.type)) {
|
||||
var idx = Math.grab_from_points(Mouse.worldpos(), this.points.map(p => this.gameobject.this2world(p)), 25);
|
||||
var idx = Math.grab_from_points(input.mouse.worldpos(), this.points.map(p => this.gameobject.this2world(p)), 25);
|
||||
if (idx === -1) return;
|
||||
} else {
|
||||
|
||||
|
@ -741,16 +783,16 @@ bucket.inputs['C-M-lm'] = function() {
|
|||
};
|
||||
bucket.inputs['C-M-lm'].doc = "Select the given point as the '0' of this spline.";
|
||||
|
||||
bucket.inputs['C-lm'] = function() { this.add_node(Mouse.worldpos()); }
|
||||
bucket.inputs['C-lm'] = function() { this.add_node(input.mouse.worldpos()); }
|
||||
bucket.inputs['C-lm'].doc = "Add a point to the spline at the mouse position.";
|
||||
|
||||
bucket.inputs['C-M-lm'] = function() {
|
||||
var idx = -1;
|
||||
if (Spline.is_catmull(this.type))
|
||||
idx = Math.grab_from_points(Mouse.worldpos(), this.points.map(p => this.gameobject.this2world(p)), 25);
|
||||
idx = Math.grab_from_points(input.mouse.worldpos(), this.points.map(p => this.gameobject.this2world(p)), 25);
|
||||
else {
|
||||
var nodes = Spline.bezier_nodes(this.points);
|
||||
idx = Math.grab_from_points(Mouse.worldpos(), nodes.map(p => this.gameobject.this2world(p)), 25);
|
||||
idx = Math.grab_from_points(input.mouse.worldpos(), nodes.map(p => this.gameobject.this2world(p)), 25);
|
||||
idx *= 3;
|
||||
}
|
||||
|
||||
|
@ -791,11 +833,11 @@ component.circle2d = Object.copy(collider2d, {
|
|||
toString() { return "circle2d"; },
|
||||
|
||||
boundingbox() {
|
||||
return bbox.fromcwh(this.offset.scale(this.gameobject.scale), [this.radius,this.radius]);
|
||||
return bbox.fromcwh([0,0], [this.radius,this.radius]);
|
||||
},
|
||||
|
||||
hides: ['gameobject', 'id', 'shape', 'scale'],
|
||||
_enghook: make_circle2d,
|
||||
_enghook: os.make_circle2d,
|
||||
});
|
||||
|
||||
component.circle2d.impl = Object.mix({
|
||||
|
@ -804,17 +846,17 @@ component.circle2d.impl = Object.mix({
|
|||
"radius",
|
||||
]),
|
||||
|
||||
set radius(x) { cmd_circle2d(0,this.id,x); },
|
||||
get radius() { return cmd_circle2d(2,this.id); },
|
||||
set radius(x) { circle2d.set_radius(this.id,x); circle2d.sync(this.id); },
|
||||
get radius() { return circle2d.get_radius(this.id); },
|
||||
|
||||
set scale(x) { this.radius = x; },
|
||||
get scale() { return this.radius; },
|
||||
|
||||
set offset(x) { cmd_circle2d(1,this.id,x); },
|
||||
get offset() { return cmd_circle2d(3,this.id); },
|
||||
set offset(x) { circle2d.set_offset(this.id,x); circle2d.sync(this.id); },
|
||||
get offset() { circle2d.get_offset(this.id); },
|
||||
|
||||
get pos() { return cmd_circle2d(3,this.id); },
|
||||
set pos(x) { cmd_circle2d(1,this.id,x); },
|
||||
get pos() { return this.offset; },
|
||||
set pos(x) { this.offset = x; },
|
||||
|
||||
grow(x) {
|
||||
if (typeof x === 'number') this.scale *= x;
|
||||
|
|
276
scripts/debug.js
276
scripts/debug.js
|
@ -1,95 +1,59 @@
|
|||
var Debug = {
|
||||
fn_break(fn, obj) {
|
||||
debug.fn_break = function(fn,obj = globalThis) {
|
||||
if (typeof fn !== 'function') return;
|
||||
obj ??= globalThis;
|
||||
|
||||
var newfn = function() {
|
||||
console.log("broke");
|
||||
fn();
|
||||
};
|
||||
obj[fn.name] = newfn;
|
||||
},
|
||||
}
|
||||
|
||||
draw_grid(width, span, color) {
|
||||
color = color ? color : Color.green;
|
||||
cmd(47, width, span, color);
|
||||
},
|
||||
debug.draw_phys = false;
|
||||
debug.draw_bb = false;
|
||||
debug.draw_gizmos = false;
|
||||
debug.draw_names = false;
|
||||
debug.draw = function() {
|
||||
if (this.draw_phys) game.all_objects(function(x) { debug.draw_gameobject(x); });
|
||||
|
||||
coordinate(pos, size, color) { GUI.text(JSON.stringify(pos.map(p=>Math.round(p))), pos, size, color); },
|
||||
|
||||
boundingbox(bb, color) {
|
||||
color ??= Color.white;
|
||||
cmd_points(0, bbox.topoints(bb), color);
|
||||
},
|
||||
|
||||
numbered_point(pos, n, color) {
|
||||
color ??= Color.white;
|
||||
render.point(pos, 3, color);
|
||||
GUI.text(n, pos.add([0,4]), 1, color);
|
||||
},
|
||||
|
||||
phys_drawing: false,
|
||||
draw_phys(on) {
|
||||
this.phys_drawing = on;
|
||||
cmd(4, this.phys_drawing);
|
||||
},
|
||||
|
||||
draw_obj_phys(obj) {
|
||||
cmd(82, obj.body);
|
||||
},
|
||||
|
||||
gameobject(go) { cmd(15, go.body); },
|
||||
|
||||
draw_bb: false,
|
||||
draw_gizmos: false,
|
||||
draw_names: false,
|
||||
|
||||
draw() {
|
||||
if (this.draw_bb)
|
||||
Game.all_objects(function(x) { Debug.boundingbox(x.boundingbox(), Color.Debug.boundingbox.alpha(0.05)); });
|
||||
|
||||
if (Game.paused()) GUI.text("PAUSED", [0,0],1);
|
||||
game.all_objects(function(x) { debug.boundingbox(x.boundingbox(), Color.debug.boundingbox.alpha(0.05)); });
|
||||
|
||||
if (this.draw_gizmos)
|
||||
Game.all_objects(function(x) {
|
||||
game.all_objects(function(x) {
|
||||
if (!x.icon) return;
|
||||
GUI.image(x.icon, Window.world2screen(x.pos));
|
||||
gui.image(x.icon, game.camera.world2view(x.pos));
|
||||
});
|
||||
|
||||
if (this.draw_names)
|
||||
Game.all_objects(function(x) {
|
||||
GUI.text(x, Window.world2screen(x.pos).add([0,32]), 1, Color.Debug.names);
|
||||
game.all_objects(function(x) {
|
||||
render.text(x, game.camera.view2screen(x.pos).add([0,32]), 1, Color.debug.names);
|
||||
});
|
||||
|
||||
if (Debug.Options.gif.rec) {
|
||||
GUI.text("REC", [0,40], 1);
|
||||
GUI.text(Time.seconds_to_timecode(Time.time - Debug.Options.gif.start_time, Debug.Options.gif.fps), [0,30], 1);
|
||||
if (debug.gif.rec) {
|
||||
render.text("REC", [0,40], 1);
|
||||
render.text(time.timecode(time.timenow() - debug.gif.start_time, debug.gif.fps), [0,30], 1);
|
||||
}
|
||||
|
||||
GUI.text(Game.playing() ? "PLAYING"
|
||||
: Game.stepping() ?
|
||||
return;
|
||||
|
||||
if (sim.paused()) render.text("PAUSED", [0,0],1);
|
||||
|
||||
render.text(sim.playing() ? "PLAYING"
|
||||
: sim.stepping() ?
|
||||
"STEP" :
|
||||
Game.paused() ?
|
||||
sim.paused() ?
|
||||
"PAUSED; EDITING" :
|
||||
"EDIT", [0, 0], 1);
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
function assert(op, str)
|
||||
function assert(op, str = `assertion failed [value '${op}']`)
|
||||
{
|
||||
str ??= `assertion failed [value '${op}']`;
|
||||
if (!op) {
|
||||
console.error(`Assertion failed: ${str}`);
|
||||
Game.quit();
|
||||
console.error(str);
|
||||
os.quit();
|
||||
}
|
||||
}
|
||||
|
||||
Debug.Options = { };
|
||||
Debug.Options.Color = {
|
||||
set trigger(x) { cmd(17,x); },
|
||||
set debug(x) { cmd(16, x); },
|
||||
};
|
||||
|
||||
var Gizmos = {
|
||||
pick_gameobject_points(worldpos, gameobject, points) {
|
||||
var idx = Math.grab_from_points(worldpos, points.map(gameobject.this2world,gameobject), 25);
|
||||
|
@ -98,83 +62,34 @@ var Gizmos = {
|
|||
},
|
||||
};
|
||||
|
||||
Object.assign(performance, {
|
||||
tick_now() { return cmd(127); },
|
||||
ns(ticks) { return cmd(128, ticks); },
|
||||
us(ticks) { return cmd(129, ticks); },
|
||||
ms(ticks) { return cmd(130, ticks); },
|
||||
best_t(ns) {
|
||||
var e = ns;
|
||||
var qq = 'ns';
|
||||
if (e > 1000) {
|
||||
e /= 1000;
|
||||
qq = 'us';
|
||||
if (e > 1000) {
|
||||
e /= 1000;
|
||||
qq = 'ms';
|
||||
}
|
||||
}
|
||||
return {
|
||||
time: e,
|
||||
unit: qq
|
||||
};
|
||||
},
|
||||
cpu(fn, times, q) {
|
||||
times ??= 1;
|
||||
q ??= "unnamed";
|
||||
var start = performance.tick_now();
|
||||
profile.cpu = function(fn, times = 1, q = "unnamed") {
|
||||
var start = profile.now();
|
||||
for (var i = 0; i < times; i++)
|
||||
fn();
|
||||
|
||||
var elapsed = performance.tick_now() - start;
|
||||
var avgt = performance.best_t(elapsed/times);
|
||||
var totalt = performance.best_t(elapsed);
|
||||
var elapsed = profile.now() - start;
|
||||
var avgt = profile.best_t(elapsed/times);
|
||||
var totalt = profile.best_t(elapsed);
|
||||
|
||||
say(`performance [${q}]: ${avgt.time.toFixed(3)} ${avgt.unit} average [${totalt.time.toFixed(3)} ${totalt.unit} for ${times} loops]`);
|
||||
},
|
||||
say(`profile [${q}]: ${profile.best_t(avgt)} average [${profile.best_t(totalt)} for ${times} loops]`);
|
||||
}
|
||||
|
||||
get fps() { return sys_cmd(8); },
|
||||
|
||||
measure(fn, str) {
|
||||
str ??= 'unnamed';
|
||||
var start = performance.tick_now();
|
||||
fn();
|
||||
var elapsed = performance.tick_now()-start;
|
||||
elapsed = performance.best_t(elapsed);
|
||||
say(`performance [${str}]: ${elapsed.time.toFixed(3)} ${elapsed.unit}`);
|
||||
},
|
||||
});
|
||||
|
||||
performance.now = performance.tick_now;
|
||||
|
||||
performance.test = {
|
||||
barecall() { performance(0); },
|
||||
unpack_num(n) { performance(1,n); },
|
||||
unpack_array(n) { performance(2,n); },
|
||||
pack_num() { performance(3); },
|
||||
pack_string() { performance(6); },
|
||||
unpack_string(s) { performance(4,s); },
|
||||
unpack_32farr(a) { performance(5,a); },
|
||||
call_fn_n(fn1, n) { performance(7,fn1,n,fn2); },
|
||||
};
|
||||
|
||||
performance.test.call_fn_n.doc = "Calls fn1 n times, and then fn2.";
|
||||
|
||||
performance.cpu.doc = `Output the time it takes to do a given function n number of times. Provide 'q' as "ns", "us", or "ms" to output the time taken in the requested resolution.`;
|
||||
profile.ms = function(t) { return t/1000000; }
|
||||
profile.secs = function(t) { return t/1000000000; }
|
||||
|
||||
/* These controls are available during editing, and during play of debug builds */
|
||||
Debug.inputs = {};
|
||||
Debug.inputs.f1 = function () { Debug.draw_phys(!Debug.phys_drawing); };
|
||||
Debug.inputs.f1.doc = "Draw physics debugging aids.";
|
||||
//Debug.inputs.f3 = function() { Debug.draw_bb = !Debug.draw_bb; };
|
||||
//Debug.inputs.f3.doc = "Toggle drawing bounding boxes.";
|
||||
Debug.inputs.f4 = function() {
|
||||
Debug.draw_names = !Debug.draw_names;
|
||||
Debug.draw_gizmos = !Debug.draw_gizmos;
|
||||
debug.inputs = {};
|
||||
debug.inputs.f1 = function () { debug.draw_phys = !debug.draw_phys; };
|
||||
debug.inputs.f1.doc = "Draw physics debugging aids.";
|
||||
debug.inputs.f3 = function() { debug.draw_bb = !debug.draw_bb; };
|
||||
debug.inputs.f3.doc = "Toggle drawing bounding boxes.";
|
||||
debug.inputs.f4 = function() {
|
||||
debug.draw_names = !debug.draw_names;
|
||||
debug.draw_gizmos = !debug.draw_gizmos;
|
||||
};
|
||||
Debug.inputs.f4.doc = "Toggle drawing gizmos and names of objects.";
|
||||
debug.inputs.f4.doc = "Toggle drawing gizmos and names of objects.";
|
||||
|
||||
Debug.Options.gif = {
|
||||
debug.gif = {
|
||||
w: 640, /* Max width */
|
||||
h: 480, /* Max height */
|
||||
stretch: false, /* True if you want to stretch */
|
||||
|
@ -189,7 +104,7 @@ Debug.Options.gif = {
|
|||
var w = this.w;
|
||||
var h = this.h;
|
||||
if (!this.stretch) {
|
||||
var win = Window.height / Window.width;
|
||||
var win = window.height / window.width;
|
||||
var gif = h/w;
|
||||
if (gif > win)
|
||||
h = w * win;
|
||||
|
@ -197,84 +112,43 @@ Debug.Options.gif = {
|
|||
w = h / win;
|
||||
}
|
||||
|
||||
cmd(131, w, h, this.cpf, this.depth);
|
||||
// cmd(131, w, h, this.cpf, this.depth);
|
||||
this.rec = true;
|
||||
this.fps = (1/this.cpf)*100;
|
||||
this.start_time = Time.time;
|
||||
this.start_time = time.now();
|
||||
|
||||
timer.oneshot(this.stop.bind(this), this.secs, this, true);
|
||||
},
|
||||
|
||||
stop() {
|
||||
if (!this.rec) return;
|
||||
cmd(132, this.file);
|
||||
// cmd(132, this.file);
|
||||
this.rec = false;
|
||||
},
|
||||
};
|
||||
|
||||
Debug.inputs.f8 = function() {
|
||||
debug.inputs.f8 = function() {
|
||||
var now = new Date();
|
||||
Debug.Options.gif.file = now.toISOString() + ".gif";
|
||||
Debug.Options.gif.start();
|
||||
debug.gif.file = now.toISOString() + ".gif";
|
||||
debug.gif.start();
|
||||
};
|
||||
Debug.inputs.f9 = function() {
|
||||
Debug.Options.gif.stop();
|
||||
debug.inputs.f9 = function() {
|
||||
debug.gif.stop();
|
||||
}
|
||||
|
||||
Debug.inputs.f10 = function() { Time.timescale = 0.1; };
|
||||
Debug.inputs.f10.doc = "Toggle timescale to 1/10.";
|
||||
Debug.inputs.f10.released = function () { Time.timescale = 1.0; };
|
||||
Debug.inputs.f12 = function() { GUI.defaults.debug = !GUI.defaults.debug; console.warn("GUI toggle debug");};
|
||||
Debug.inputs.f12.doc = "Toggle drawing GUI debugging aids.";
|
||||
debug.inputs.f10 = function() { time.timescale = 0.1; };
|
||||
debug.inputs.f10.doc = "Toggle timescale to 1/10.";
|
||||
debug.inputs.f10.released = function () { time.timescale = 1.0; };
|
||||
debug.inputs.f12 = function() { gui.defaults.debug = !gui.defaults.debug; console.warn("gui toggle debug");};
|
||||
debug.inputs.f12.doc = "Toggle drawing gui debugging aids.";
|
||||
|
||||
Debug.inputs['M-1'] = render.normal;
|
||||
Debug.inputs['M-2'] = render.wireframe;
|
||||
debug.inputs['M-1'] = render.normal;
|
||||
debug.inputs['M-2'] = render.wireframe;
|
||||
debug.inputs['C-M-f'] = function() {};
|
||||
debug.inputs['C-M-f'].doc = "Enter camera fly mode.";
|
||||
|
||||
Debug.inputs['C-M-f'] = function() {};
|
||||
Debug.inputs['C-M-f'].doc = "Enter camera fly mode.";
|
||||
|
||||
var Time = {
|
||||
set timescale(x) { cmd(3, x); },
|
||||
get timescale() { return cmd(121); },
|
||||
set updateMS(x) { cmd(6, x); },
|
||||
set physMS(x) { cmd(7, x); },
|
||||
set renderMS(x) { cmd(5, x); },
|
||||
|
||||
get time() { return cmd(133); },
|
||||
|
||||
seconds_to_timecode(secs, fps)
|
||||
{
|
||||
var s = Math.trunc(secs);
|
||||
secs -= s;
|
||||
var f = Math.trunc(fps * secs);
|
||||
return `${s}:${f}`;
|
||||
},
|
||||
|
||||
pause() {
|
||||
Time.stash = Time.timescale;
|
||||
Time.timescale = 0;
|
||||
},
|
||||
|
||||
play() {
|
||||
if (!Time.stash) {
|
||||
console.warn("Tried to resume time without calling Time.pause first.");
|
||||
return;
|
||||
}
|
||||
Time.timescale = Time.stash;
|
||||
},
|
||||
};
|
||||
|
||||
Time.doc = {};
|
||||
Time.doc.timescale = "Get and set the timescale. 1 is normal time; 0.5 is half speed; etc.";
|
||||
Time.doc.updateMS = "Set the ms per game update.";
|
||||
Time.doc.physMS = "Set the ms per physics update.";
|
||||
Time.doc.renderMS = "Set the ms per render update.";
|
||||
Time.doc.time = "Seconds elapsed since the game started.";
|
||||
Time.doc.pause = "Pause the game by setting the timescale to 0; remembers the current timescale on play.";
|
||||
Time.doc.play = "Resume the game after using Time.pause.";
|
||||
|
||||
Debug.api = {};
|
||||
Debug.api.doc_entry = function(obj, key)
|
||||
debug.api = {};
|
||||
debug.api.doc_entry = function(obj, key)
|
||||
{
|
||||
if (typeof key !== 'string') {
|
||||
console.warn("Cannot print a key that isn't a string.");
|
||||
|
@ -310,7 +184,7 @@ ${doc}
|
|||
`;
|
||||
}
|
||||
|
||||
Debug.api.print_doc = function(name)
|
||||
debug.api.print_doc = function(name)
|
||||
{
|
||||
var obj = name;
|
||||
if (typeof name === 'string') {
|
||||
|
@ -343,16 +217,24 @@ Debug.api.print_doc = function(name)
|
|||
if (key === 'doc') continue;
|
||||
if (key === 'toString') continue;
|
||||
|
||||
mdoc += Debug.api.doc_entry(obj, key) + "\n";
|
||||
mdoc += debug.api.doc_entry(obj, key) + "\n";
|
||||
}
|
||||
|
||||
return mdoc;
|
||||
}
|
||||
|
||||
debug.log = {};
|
||||
|
||||
debug.log.time = function(fn, name, avg=0)
|
||||
{
|
||||
debug.log.time[name] ??= [];
|
||||
var start = profile.now();
|
||||
fn();
|
||||
debug.log.time[name].push(profile.now()-start);
|
||||
}
|
||||
|
||||
return {
|
||||
Debug,
|
||||
Time,
|
||||
debug,
|
||||
Gizmos,
|
||||
performance,
|
||||
assert
|
||||
}
|
||||
|
|
|
@ -47,14 +47,14 @@ function ediff(from,to)
|
|||
return;
|
||||
}
|
||||
|
||||
if (typeof v === 'object') {
|
||||
if (typeof v === 'object' && v !== null) {
|
||||
var diff = ediff(v, to[key]);
|
||||
if (diff && !Object.empty(diff))
|
||||
ret[key] = diff;
|
||||
return;
|
||||
}
|
||||
|
||||
if (typeof v === 'number') {
|
||||
if (typeof v === 'number' || v === null) {
|
||||
if (!isFinite(v)) v = null; // Squash infinity to null
|
||||
if (v !== to[key])
|
||||
ret[key] = v;
|
||||
|
|
|
@ -3,11 +3,13 @@
|
|||
selectable
|
||||
*/
|
||||
|
||||
Window.mode = Window.modetypes.full;
|
||||
Game.loadurs();
|
||||
game.loadurs();
|
||||
|
||||
player[0].control(Debug);
|
||||
Register.gui.register(Debug.draw, Debug);
|
||||
console.info(`window size: ${window.size}, render size: ${window.rendersize}`);
|
||||
|
||||
player[0].control(debug);
|
||||
|
||||
var show_frame = true;
|
||||
|
||||
var editor = {
|
||||
toString() { return "editor"; },
|
||||
|
@ -24,22 +26,19 @@ var editor = {
|
|||
desktop: undefined, /* The editor desktop, where all editing objects live */
|
||||
working_layer: 0,
|
||||
get cursor() {
|
||||
if (this.selectlist.length === 0 ) return Mouse.worldpos();
|
||||
if (this.selectlist.length === 0 ) return input.mouse.worldpos();
|
||||
return physics.com(this.selectlist.map(x => x.pos));
|
||||
},
|
||||
edit_mode: "basic",
|
||||
|
||||
get_this() { return this.edit_level; },
|
||||
|
||||
get_that() { return this.selectlist.length === 1 ? this.selectlist[0] : this.get_this(); },
|
||||
|
||||
try_select() { /* nullify true if it should set selected to null if it doesn't find an object */
|
||||
var go = physics.pos_query(Mouse.worldpos());
|
||||
var go = physics.pos_query(input.mouse.worldpos());
|
||||
return this.do_select(go);
|
||||
},
|
||||
|
||||
/* Tries to select id */
|
||||
do_select(obj) {
|
||||
do_select(obj) { /* select an object, if it is selectable given the current editor state */
|
||||
if (!obj) return;
|
||||
if (!obj._ed.selectable) return undefined;
|
||||
|
||||
|
@ -84,7 +83,7 @@ var editor = {
|
|||
return function(go) { go.pos = go.pos.add(amt)};
|
||||
},
|
||||
|
||||
step_amt() { return Keys.shift() ? 10 : 1; },
|
||||
step_amt() { return input.keyboard.down("shift") ? 10 : 1; },
|
||||
|
||||
on_grid(pos) {
|
||||
return pos.every(function(x) { return x % editor.grid_size === 0; });
|
||||
|
@ -99,7 +98,7 @@ var editor = {
|
|||
|
||||
key_move(dir) {
|
||||
if (!editor.grabselect) return;
|
||||
if (Keys.ctrl())
|
||||
if (input.keyboard.down('ctrl'))
|
||||
this.selectlist.forEach(this.snapper(dir.scale(1.01), editor.grid_size));
|
||||
else
|
||||
this.selectlist.forEach(this.mover(dir.scale(this.step_amt())));
|
||||
|
@ -156,7 +155,7 @@ var editor = {
|
|||
},
|
||||
|
||||
input_num_pressed(num) {
|
||||
if (Keys.ctrl()) {
|
||||
if (input.keyboard.down('ctrl')) {
|
||||
this.camera_recalls[num] = {
|
||||
pos:this.camera.pos,
|
||||
zoom:this.camera.zoom
|
||||
|
@ -171,8 +170,8 @@ var editor = {
|
|||
zoom_to_bb(bb) {
|
||||
var cwh = bbox.tocwh(bb);
|
||||
|
||||
var xscale = cwh.wh.x / Window.width;
|
||||
var yscale = cwh.wh.y / Window.height;
|
||||
var xscale = cwh.wh.x / window.width;
|
||||
var yscale = cwh.wh.y / window.height;
|
||||
|
||||
var zoom = yscale > xscale ? yscale : xscale;
|
||||
|
||||
|
@ -191,7 +190,7 @@ var editor = {
|
|||
this.stash = this.desktop.instance_obj();
|
||||
world.clear();
|
||||
global.mixin("config.js");
|
||||
Game.play();
|
||||
sim.play();
|
||||
player[0].uncontrol(this);
|
||||
player[0].control(limited_editor);
|
||||
editor.cbs.forEach(cb => cb());
|
||||
|
@ -206,7 +205,7 @@ var editor = {
|
|||
start_play() {
|
||||
world.clear();
|
||||
global.mixin("config.js");
|
||||
Game.play();
|
||||
sim.play();
|
||||
player[0].uncontrol(this);
|
||||
player[0].control(limited_editor);
|
||||
editor.cbs.forEach(cb=>cb());
|
||||
|
@ -217,14 +216,14 @@ var editor = {
|
|||
cbs: [],
|
||||
|
||||
enter_editor() {
|
||||
Game.pause();
|
||||
sim.pause();
|
||||
player[0].control(this);
|
||||
player[0].uncontrol(limited_editor);
|
||||
|
||||
editor.cbs.push(Register.gui.register(editor.gui.bind(editor)));
|
||||
editor.cbs.push(Register.draw.register(editor.draw.bind(editor)));
|
||||
editor.cbs.push(Register.debug.register(editor.ed_debug.bind(editor)));
|
||||
editor.cbs.push(Register.update.register(GUI.controls.update, GUI.controls));
|
||||
editor.cbs.push(Register.update.register(gui.controls.update, gui.controls));
|
||||
|
||||
this.desktop = world.spawn();
|
||||
world.rename_obj(this.desktop.toString(), "desktop");
|
||||
|
@ -237,11 +236,7 @@ var editor = {
|
|||
this.selectlist = [];
|
||||
editor.camera = world.spawn("scripts/camera2d.jso");
|
||||
editor.camera._ed.selectable = false;
|
||||
Game.view_camera(editor.camera);
|
||||
},
|
||||
|
||||
end_debug() {
|
||||
|
||||
game.camera = editor.camera;
|
||||
},
|
||||
|
||||
openpanel(panel) {
|
||||
|
@ -342,14 +337,13 @@ var editor = {
|
|||
}
|
||||
},
|
||||
|
||||
draw_objects_names(obj,root,depth){
|
||||
draw_objects_names(obj,root,depth = 0){
|
||||
if (!obj) return;
|
||||
if (!obj.objects) return;
|
||||
depth ??= 0;
|
||||
root = root ? root + "." : root;
|
||||
Object.entries(obj.objects).forEach(function(x) {
|
||||
var p = root + x[0];
|
||||
GUI.text(p, x[1].screenpos(), 1, editor.color_depths[depth]);
|
||||
render.text(p, x[1].screenpos(), 1, editor.color_depths[depth]);
|
||||
editor.draw_objects_names(x[1], p, depth+1);
|
||||
});
|
||||
},
|
||||
|
@ -362,10 +356,8 @@ var editor = {
|
|||
|
||||
this._sel_comp = x;
|
||||
|
||||
if (this._sel_comp) {
|
||||
console.info("sel comp is now " + this._sel_comp);
|
||||
if (this._sel_comp)
|
||||
player[0].control(this._sel_comp);
|
||||
}
|
||||
},
|
||||
|
||||
time: 0,
|
||||
|
@ -377,11 +369,11 @@ var editor = {
|
|||
x.gizmo();
|
||||
});
|
||||
|
||||
render.line(bbox.topoints(bbox.fromcwh([0,0],[Game.width,Game.height])).wrapped(1), Color.green);
|
||||
render.line(bbox.topoints(bbox.fromcwh([0,0],[game.width,game.height])).wrapped(1), Color.green);
|
||||
|
||||
/* Draw selection box */
|
||||
if (this.sel_start) {
|
||||
var endpos = Mouse.worldpos();
|
||||
var endpos = input.mouse.worldpos();
|
||||
var c = [];
|
||||
c[0] = (endpos[0] - this.sel_start[0]) / 2;
|
||||
c[0] += this.sel_start[0];
|
||||
|
@ -391,21 +383,23 @@ var editor = {
|
|||
wh[0] = Math.abs(endpos[0] - this.sel_start[0]);
|
||||
wh[1] = Math.abs(endpos[1] - this.sel_start[1]);
|
||||
var bb = bbox.fromcwh(c,wh);
|
||||
Debug.boundingbox(bb, Color.Editor.select.alpha(0.1));
|
||||
render.boundingbox(bb, Color.Editor.select.alpha(0.1));
|
||||
render.line(bbox.topoints(bb).wrapped(1), Color.white);
|
||||
}
|
||||
},
|
||||
|
||||
gui() {
|
||||
/* Clean out killed objects */
|
||||
this.selectlist = this.selectlist.filter(function(x) { return x.alive; });
|
||||
GUI.text([0,0], Window.world2screen([0,0]));
|
||||
if (show_frame)
|
||||
render.line(shape.box(window.rendersize.x, window.rendersize.y).wrapped(1).map(p => game.camera.world2view(p)), Color.yellow);
|
||||
|
||||
GUI.text("WORKING LAYER: " + this.working_layer, [0,520]);
|
||||
GUI.text("MODE: " + this.edit_mode, [0,500]);
|
||||
render.text([0,0], game.camera.world2view([0,0]));
|
||||
|
||||
render.text("WORKING LAYER: " + this.working_layer, [0,520]);
|
||||
render.text("MODE: " + this.edit_mode, [0,520-render.font.linegap]);
|
||||
|
||||
if (this.comp_info && this.sel_comp)
|
||||
GUI.text(Input.print_pawn_kbm(this.sel_comp,false), [100,700],1);
|
||||
render.text(input.print_pawn_kbm(this.sel_comp,false), [100,700],1);
|
||||
|
||||
render.cross(editor.edit_level.screenpos(),3,Color.blue);
|
||||
|
||||
|
@ -428,9 +422,11 @@ var editor = {
|
|||
var depth = 0;
|
||||
var alldirty = false;
|
||||
for (var lvl of lvlchain) {
|
||||
if (!lvl._ed?.selectable) continue;
|
||||
if (alldirty)
|
||||
lvl._ed.dirty = true;
|
||||
else {
|
||||
if (!lvl._ed) continue;
|
||||
lvl.check_dirty();
|
||||
if (lvl._ed.dirty) alldirty = true;
|
||||
}
|
||||
|
@ -440,43 +436,44 @@ var editor = {
|
|||
depth = i;
|
||||
var lvlstr = x.namestr();
|
||||
if (i === lvlchain.length-1) lvlstr += "[this]";
|
||||
GUI.text(lvlstr, [0, ypos], 1, editor.color_depths[depth]);
|
||||
|
||||
GUI.text("^^^^^^", [0,ypos+=5],1);
|
||||
ypos += 15;
|
||||
render.text(lvlstr, [0, ypos], 1, editor.color_depths[depth]);
|
||||
ypos += render.font.linegap;
|
||||
render.text("^^^^^^", [0,ypos],1);
|
||||
ypos += render.font.linegap;
|
||||
});
|
||||
|
||||
depth++;
|
||||
GUI.text("$$$$$$", [0,ypos],1,editor.color_depths[depth]);
|
||||
render.text("$$$$$$", [0,ypos],1,editor.color_depths[depth]);
|
||||
|
||||
this.selectlist.forEach(function(x) {
|
||||
GUI.text(x.urstr(), x.screenpos().add([0, 32]), 1, Color.editor.ur);
|
||||
GUI.text(x.worldpos().map(function(x) { return Math.round(x); }), x.screenpos(), 1, Color.white);
|
||||
render.text(x.urstr(), x.screenpos().add([0, render.font.linegap*2]), 1, Color.editor.ur);
|
||||
render.text(x.pos.map(function(x) { return Math.round(x); }), x.screenpos());
|
||||
render.cross(x.screenpos(), 10, Color.blue);
|
||||
});
|
||||
|
||||
Object.entries(thiso.objects).forEach(function(x) {
|
||||
var p = x[1].namestr();
|
||||
GUI.text(p, x[1].screenpos().add([0,16]),1,editor.color_depths[depth]);
|
||||
render.circle(x[1].screenpos(),10,Color.blue.alpha(0.3));
|
||||
render.text(p, x[1].screenpos().add([0,render.font.linegap]),1,editor.color_depths[depth]);
|
||||
render.point(x[1].screenpos(),5,Color.blue.alpha(0.3));
|
||||
render.point(x[1].screenpos(), 1, Color.red);
|
||||
});
|
||||
|
||||
var mg = physics.pos_query(Mouse.worldpos(),10);
|
||||
var mg = physics.pos_query(input.mouse.worldpos());
|
||||
|
||||
if (mg) {
|
||||
if (mg && mg._ed?.selectable) {
|
||||
var p = mg.path_from(thiso);
|
||||
GUI.text(p, Mouse.screenpos(),1,Color.teal);
|
||||
render.text(p, input.mouse.screenpos(),1,Color.teal);
|
||||
}
|
||||
|
||||
if (this.rotlist.length === 1)
|
||||
GUI.text(Math.trunc(this.rotlist[0].obj.angle), Mouse.screenpos(), 1, Color.teal);
|
||||
render.text(Math.places(this.rotlist[0].angle, 3), input.mouse.screenpos(), 1, Color.teal);
|
||||
|
||||
if (this.selectlist.length === 1) {
|
||||
var i = 1;
|
||||
for (var key in this.selectlist[0].components) {
|
||||
var selected = this.sel_comp === this.selectlist[0].components[key];
|
||||
var str = (selected ? ">" : " ") + key + " [" + this.selectlist[0].components[key].toString() + "]";
|
||||
GUI.text(str, this.selectlist[0].screenpos().add([0,-16*(i++)]));
|
||||
render.text(str, this.selectlist[0].screenpos().add([0,-render.font.linegap*(i++)]));
|
||||
}
|
||||
|
||||
if (this.sel_comp) {
|
||||
|
@ -486,26 +483,26 @@ var editor = {
|
|||
|
||||
editor.edit_level.objects.forEach(function(obj) {
|
||||
if (!obj._ed.selectable)
|
||||
GUI.text("lock", obj,screenpos());
|
||||
render.text("lock", obj,screenpos());
|
||||
});
|
||||
|
||||
Debug.draw_grid(1, editor.grid_size, Color.Editor.grid.alpha(0.3));
|
||||
var startgrid = Window.screen2world([-20,0]).map(function(x) { return Math.snap(x, editor.grid_size); });
|
||||
var endgrid = Window.screen2world([Window.width, Window.height]);
|
||||
render.grid(1, editor.grid_size, Color.Editor.grid.alpha(0.3));
|
||||
var startgrid = game.camera.view2world([-20,0]).map(function(x) { return Math.snap(x, editor.grid_size); });
|
||||
var endgrid = game.camera.view2world([window.width, window.height]);
|
||||
|
||||
var w_step = Math.round(editor.ruler_mark_px/Window.width * (endgrid.x-startgrid.x)/editor.grid_size)*editor.grid_size;
|
||||
var w_step = Math.round(editor.ruler_mark_px/window.width * (endgrid.x-startgrid.x)/editor.grid_size)*editor.grid_size;
|
||||
if (w_step === 0) w_step = editor.grid_size;
|
||||
|
||||
var h_step = Math.round(editor.ruler_mark_px/Window.height * (endgrid.y-startgrid.y)/editor.grid_size)*editor.grid_size;
|
||||
var h_step = Math.round(editor.ruler_mark_px/window.height * (endgrid.y-startgrid.y)/editor.grid_size)*editor.grid_size;
|
||||
if (h_step === 0) h_step = editor.grid_size;
|
||||
|
||||
while(startgrid[0] <= endgrid[0]) {
|
||||
GUI.text(startgrid[0], [Window.world2screen([startgrid[0], 0])[0],0]);
|
||||
render.text(startgrid[0], [game.camera.world2view([startgrid[0], 0])[0],0]);
|
||||
startgrid[0] += w_step;
|
||||
}
|
||||
|
||||
while(startgrid[1] <= endgrid[1]) {
|
||||
GUI.text(startgrid[1], [0, Window.world2screen([0, startgrid[1]])[1]]);
|
||||
render.text(startgrid[1], [0, game.camera.world2view([0, startgrid[1]])[1]]);
|
||||
startgrid[1] += h_step;
|
||||
}
|
||||
|
||||
|
@ -518,8 +515,8 @@ var editor = {
|
|||
},
|
||||
|
||||
ed_debug() {
|
||||
if (!Debug.phys_drawing)
|
||||
this.selectlist.forEach(function(x) { Debug.draw_obj_phys(x); });
|
||||
if (!debug.phys_drawing)
|
||||
this.selectlist.forEach(function(x) { debug.draw_obj_phys(x); });
|
||||
},
|
||||
|
||||
killring: [],
|
||||
|
@ -528,8 +525,10 @@ var editor = {
|
|||
lvl_history: [],
|
||||
|
||||
load(urstr) {
|
||||
var obj = editor.edit_level.spawn(urstr);
|
||||
obj.set_worldpos(Mouse.worldpos());
|
||||
var mur = ur[urstr];
|
||||
if (!mur) return;
|
||||
var obj = editor.edit_level.spawn(mur);
|
||||
obj.set_pos(input.mouse.worldpos());
|
||||
this.selectlist = [obj];
|
||||
},
|
||||
|
||||
|
@ -567,7 +566,7 @@ var editor = {
|
|||
ur[sub] = {
|
||||
name: sub,
|
||||
data: file,
|
||||
proto: json.decode(json.encode(obj))
|
||||
fresh: json.decode(json.encode(obj))
|
||||
}
|
||||
obj.ur = sub;
|
||||
|
||||
|
@ -610,7 +609,7 @@ var editor = {
|
|||
editor.new_object = function()
|
||||
{
|
||||
var obj = editor.edit_level.spawn();
|
||||
obj.set_worldpos(Mouse.worldpos());
|
||||
obj.set_pos(input.mouse.worldpos());
|
||||
this.selectlist = [obj];
|
||||
return obj;
|
||||
}
|
||||
|
@ -638,7 +637,7 @@ editor.inputs['C-b'] = function() {
|
|||
c.grow(obj.scale);
|
||||
c.sync?.();
|
||||
});
|
||||
obj.scale = [1,1,1];
|
||||
obj.set_scale([1,1,1]);
|
||||
}
|
||||
|
||||
editor.inputs.drop = function(str) {
|
||||
|
@ -656,24 +655,22 @@ editor.inputs.drop = function(str) {
|
|||
return;
|
||||
}
|
||||
|
||||
var mg = physics.pos_query(Mouse.worldpos(),10);
|
||||
var mg = physics.pos_query(input.mouse.worldpos());
|
||||
if (!mg) return;
|
||||
var img = mg.get_comp_by_name('sprite');
|
||||
if (!img) return;
|
||||
img[0].path = str;
|
||||
}
|
||||
|
||||
editor.inputs.f9 = function() {
|
||||
console.warn("CAPTURING");
|
||||
cmd(173, "capture.bmp", 0, 0, 500, 500);
|
||||
}
|
||||
editor.inputs.f9 = function() { os.capture( "capture.bmp", 0, 0, 500, 500); }
|
||||
|
||||
editor.inputs.release_post = function() {
|
||||
editor.snapshot();
|
||||
editor.edit_level.check_dirty();
|
||||
|
||||
editor.selectlist?.forEach(x => x.check_dirty());
|
||||
|
||||
/* snap all objects to be pixel perfect */
|
||||
editor.edit_level.obj_descend(o => o.pos = o.pos.map(x => Math.round(x)));
|
||||
game.all_objects(o => o.pos = o.pos.map(x => Math.round(x)), editor.edit_level);
|
||||
};
|
||||
editor.inputs['C-a'] = function() {
|
||||
if (!Object.empty(editor.selectlist)) { editor.unselect(); return; }
|
||||
|
@ -692,9 +689,9 @@ editor.inputs.n = function() {
|
|||
if (o === editor.selectlist[0]) return;
|
||||
if (o.master !== editor.selectlist[0].master) return;
|
||||
|
||||
var tpos = editor.selectlist[0].pos;
|
||||
var tpos = editor.selectlist[0].get_pos(editor.selectlist[0].master);
|
||||
tpos.x *= -1;
|
||||
o.pos = tpos;
|
||||
o.set_pos(tpos, o.master);
|
||||
};
|
||||
editor.inputs.n.doc = "Set the hovered object's position to mirror the selected object's position on the X axis."
|
||||
editor.inputs['M-n'] = function()
|
||||
|
@ -743,7 +740,6 @@ editor.inputs['C-d'] = function() {
|
|||
};
|
||||
editor.inputs['C-d'].doc = "Duplicate all selected objects.";
|
||||
|
||||
|
||||
editor.inputs['C-m'] = function() {
|
||||
if (editor.sel_comp) {
|
||||
if ('flipy' in editor.sel_comp)
|
||||
|
@ -764,15 +760,15 @@ editor.inputs.m = function() {
|
|||
return;
|
||||
}
|
||||
|
||||
editor.selectlist.forEach(obj => obj.scale = [-obj.scale[0], obj.scale[1]]);
|
||||
editor.selectlist.forEach(obj => obj.grow([-1,1,1]));
|
||||
};
|
||||
editor.inputs.m.doc = "Mirror selected objects on the X axis.";
|
||||
|
||||
|
||||
editor.inputs.q = function() { editor.comp_info = !editor.comp_info; };
|
||||
editor.inputs.q.doc = "Toggle help for the selected component.";
|
||||
|
||||
editor.inputs.f = function() {
|
||||
return;
|
||||
if (editor.selectlist.length === 0) return;
|
||||
var bb = editor.selectlist[0].boundingbox();
|
||||
editor.selectlist.forEach(function(obj) { bb = bbox.expand(bb, obj.boundingbox()); });
|
||||
|
@ -789,38 +785,24 @@ editor.inputs['C-f'] = function() {
|
|||
};
|
||||
editor.inputs['C-f'].doc = "Tunnel into the selected level object to edit it.";
|
||||
|
||||
editor.inputs['C-F'] = function() {
|
||||
editor.inputs['M-f'] = function() {
|
||||
if (editor.edit_level.master === world) return;
|
||||
|
||||
editor.edit_level = editor.edit_level.master;
|
||||
editor.unselect();
|
||||
editor.reset_undos();
|
||||
};
|
||||
editor.inputs['C-F'].doc = "Tunnel out of the level you are editing, saving it in the process.";
|
||||
|
||||
editor.inputs['C-r'] = function() { editor.selectlist.forEach(function(x) { x.angle = -x.angle; }); };
|
||||
editor.inputs['M-f'].doc = "Tunnel out of the level you are editing, saving it in the process.";
|
||||
editor.inputs['C-r'] = function() { editor.selectlist.forEach(function(x) { x.rotate(-x.angle*2); }); }
|
||||
editor.inputs['C-r'].doc = "Negate the selected's angle.";
|
||||
|
||||
editor.inputs.r = function() {
|
||||
if (editor.sel_comp && 'angle' in editor.sel_comp) {
|
||||
var relpos = Mouse.worldpos().sub(editor.sel_comp.gameobject.worldpos());
|
||||
editor.startoffset = Math.atan2(relpos.y, relpos.x);
|
||||
editor.startrot = editor.sel_comp.angle;
|
||||
|
||||
var relpos = input.mouse.worldpos().sub(editor.sel_comp.gameobject.pos);
|
||||
return;
|
||||
}
|
||||
|
||||
editor.rotlist = [];
|
||||
editor.selectlist.forEach(function(x) {
|
||||
var relpos = Mouse.worldpos().sub(editor.cursor);
|
||||
editor.rotlist.push({
|
||||
obj: x,
|
||||
angle: x.angle,
|
||||
pos: x.pos,
|
||||
offset: x.pos.sub(editor.cursor),
|
||||
rotoffset: Math.atan2(relpos.y, relpos.x),
|
||||
});
|
||||
});
|
||||
editor.rotlist = editor.selectlist;
|
||||
};
|
||||
editor.inputs.r.doc = "Rotate selected using the mouse while held down.";
|
||||
editor.inputs.r.released = function() { editor.rotlist = []; }
|
||||
|
@ -832,15 +814,15 @@ editor.inputs.f6 = function() { editor.start_play(); }
|
|||
editor.inputs.f6.doc = "Start game as if the player started it.";
|
||||
|
||||
editor.inputs['M-p'] = function() {
|
||||
if (Game.playing())
|
||||
Game.pause();
|
||||
if (sim.playing())
|
||||
sim.pause();
|
||||
|
||||
Game.step();
|
||||
sim.step();
|
||||
}
|
||||
editor.inputs['M-p'].doc = "Do one time step, pausing if necessary.";
|
||||
|
||||
editor.inputs['C-M-p'] = function() {
|
||||
if (!Game.playing()) {
|
||||
if (!sim.playing()) {
|
||||
editor.start_play_ed();
|
||||
}
|
||||
console.warn(`Starting edited level ...`);
|
||||
|
@ -904,21 +886,20 @@ editor.inputs['C-s'] = function() {
|
|||
if (!tur.data) {
|
||||
io.slurpwrite(tur.text.set_ext(".json"), json.encode(savejs,null,1));
|
||||
tur.data = tur.text.set_ext(".json");
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
var oldjs = json.decode(io.slurp(tur.data));
|
||||
Object.merge(oldjs, savejs);
|
||||
io.slurpwrite(tur.data, json.encode(oldjs,null,1));
|
||||
}
|
||||
|
||||
Object.merge(tur.proto, savejs);
|
||||
Object.merge(tur.fresh, savejs);
|
||||
saveobj.check_dirty();
|
||||
|
||||
// Object.values(saveobj.objects).forEach(function(x) { x.check_dirty(); });
|
||||
|
||||
return;
|
||||
|
||||
Game.all_objects(function(x) {
|
||||
game.all_objects(function(x) {
|
||||
if (typeof x !== 'object') return;
|
||||
if (!('_ed' in x)) return;
|
||||
if (x._ed.dirty) return;
|
||||
|
@ -982,6 +963,10 @@ editor.inputs['C-y'] = function() {
|
|||
};
|
||||
editor.inputs['C-y'].doc = "Open script editor for the level.";
|
||||
|
||||
editor.inputs['C-p'] = function() {
|
||||
os.system("prosperon");
|
||||
}
|
||||
|
||||
editor.inputs['M-y'] = function() { editor.programmode = !editor.programmode; };
|
||||
editor.inputs['M-y'].doc = "Toggle program mode.";
|
||||
|
||||
|
@ -1025,11 +1010,11 @@ editor.inputs.f3 = function() {
|
|||
this.openpanel(componentexplorer);
|
||||
};
|
||||
|
||||
editor.inputs.lm = function() { editor.sel_start = Mouse.worldpos(); };
|
||||
editor.inputs.lm = function() { editor.sel_start = input.mouse.worldpos(); };
|
||||
editor.inputs.lm.doc = "Selection box.";
|
||||
|
||||
editor.inputs.lm.released = function() {
|
||||
Mouse.normal();
|
||||
input.mouse.normal();
|
||||
editor.unselect();
|
||||
|
||||
if (!editor.sel_start) return;
|
||||
|
@ -1042,18 +1027,15 @@ editor.inputs.lm.released = function() {
|
|||
var selects = [];
|
||||
|
||||
/* TODO: selects somehow gets undefined objects in here */
|
||||
if (Vector.equal(Mouse.worldpos(), editor.sel_start, 5)) {
|
||||
if (Vector.equal(input.mouse.worldpos(), editor.sel_start, 5)) {
|
||||
var sel = editor.try_select();
|
||||
if (sel) selects.push(sel);
|
||||
} else {
|
||||
var box = bbox.frompoints([editor.sel_start, Mouse.worldpos()]);
|
||||
var box = bbox.frompoints([editor.sel_start, input.mouse.worldpos()]);
|
||||
|
||||
var hits = physics.box_query(bbox.tocwh(box));
|
||||
|
||||
hits.forEach(function(x, i) {
|
||||
var obj = editor.do_select(x);
|
||||
if (obj)
|
||||
selects.push(obj);
|
||||
physics.box_query(bbox.tocwh(box), function(entity) {
|
||||
var obj = editor.do_select(entity);
|
||||
if (obj) selects.push(obj);
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -1063,7 +1045,7 @@ editor.inputs.lm.released = function() {
|
|||
|
||||
if (Object.empty(selects)) return;
|
||||
|
||||
if (Keys.shift()) {
|
||||
if (input.keyboard.down('shift')) {
|
||||
selects.forEach(function(x) {
|
||||
this.selectlist.push_unique(x);
|
||||
}, this);
|
||||
|
@ -1071,7 +1053,7 @@ editor.inputs.lm.released = function() {
|
|||
return;
|
||||
}
|
||||
|
||||
if (Keys.ctrl()) {
|
||||
if (input.keyboard.down('ctrl')) {
|
||||
selects.forEach(function(x) {
|
||||
delete this.selectlist[x.toString()];
|
||||
}, this);
|
||||
|
@ -1103,7 +1085,7 @@ editor.try_pick = function()
|
|||
editor.grabselect = [];
|
||||
|
||||
if (editor.sel_comp && 'pick' in editor.sel_comp)
|
||||
return editor.sel_comp.pick(Mouse.worldpos());
|
||||
return editor.sel_comp.pick(input.mouse.worldpos());
|
||||
|
||||
return editor.try_select();
|
||||
}
|
||||
|
@ -1111,7 +1093,7 @@ editor.try_pick = function()
|
|||
editor.inputs.mm = function() {
|
||||
if (editor.brush_obj) {
|
||||
editor.selectlist = editor.dup_objects([editor.brush_obj]);
|
||||
editor.selectlist[0].pos = Mouse.worldpos();
|
||||
editor.selectlist[0].pos = input.mouse.worldpos();
|
||||
editor.grabselect = editor.selectlist[0];
|
||||
return;
|
||||
}
|
||||
|
@ -1125,30 +1107,30 @@ editor.inputs['C-mm'] = editor.inputs.mm;
|
|||
|
||||
editor.inputs['C-M-lm'] = function()
|
||||
{
|
||||
var go = physics.pos_query(Mouse.worldpos());
|
||||
var go = physics.pos_query(input.mouse.worldpos());
|
||||
if (!go) return;
|
||||
editor.edit_level = go.master;
|
||||
}
|
||||
|
||||
editor.inputs['C-M-mm'] = function() {
|
||||
editor.mousejoy = Mouse.screenpos();
|
||||
editor.mousejoy = input.mouse.screenpos();
|
||||
editor.joystart = editor.camera.pos;
|
||||
};
|
||||
|
||||
editor.inputs['C-M-rm'] = function() {
|
||||
editor.mousejoy = Mouse.screenpos();
|
||||
editor.mousejoy = input.mouse.screenpos();
|
||||
editor.z_start = editor.camera.zoom;
|
||||
Mouse.disabled();
|
||||
input.mouse.disabled();
|
||||
};
|
||||
|
||||
editor.inputs.rm.released = function() {
|
||||
editor.mousejoy = undefined;
|
||||
editor.z_start = undefined;
|
||||
Mouse.normal();
|
||||
input.mouse.normal();
|
||||
};
|
||||
|
||||
editor.inputs.mm.released = function () {
|
||||
Mouse.normal();
|
||||
input.mouse.normal();
|
||||
this.grabselect = [];
|
||||
editor.mousejoy = undefined;
|
||||
editor.joystart = undefined;
|
||||
|
@ -1160,43 +1142,36 @@ editor.inputs.mouse.move = function(pos, dpos)
|
|||
if (editor.z_start)
|
||||
editor.camera.zoom -= dpos.y/500;
|
||||
else if (editor.joystart)
|
||||
editor.camera.pos = editor.camera.pos.sub(Game.camera.dir_view2world(dpos));
|
||||
editor.camera.pos = editor.camera.pos.sub(game.camera.dir_view2world(dpos));
|
||||
}
|
||||
|
||||
editor.grabselect?.forEach(function(x) {
|
||||
if (!x) return;
|
||||
x.move(Game.camera.dir_view2world(dpos));
|
||||
x.move(game.camera.dir_view2world(dpos));
|
||||
x.sync();
|
||||
});
|
||||
|
||||
var relpos = Mouse.worldpos().sub(editor.cursor);
|
||||
var dist = Vector.length(relpos);
|
||||
var relpos = input.mouse.worldpos().sub(editor.cursor);
|
||||
var lastpos = relpos.sub(dpos);
|
||||
|
||||
editor.scalelist?.forEach(function(x) {
|
||||
var scalediff = dist / x.scaleoffset;
|
||||
if (typeof x.obj.scale === 'number')
|
||||
x.obj.scale = x.scale * scalediff;
|
||||
else {
|
||||
x.obj.scale = x.scale.map(x=> x * scalediff);
|
||||
if (x.offset)
|
||||
x.obj.pos = editor.cursor.add(x.offset.scale(scalediff));
|
||||
}
|
||||
});
|
||||
var dist = Vector.length(relpos.add(dpos)) - Vector.length(relpos);
|
||||
var scalediff = 1+(dist/editor.scaleoffset);
|
||||
|
||||
editor.scalelist?.forEach(function(x) { x.grow(scalediff); });
|
||||
|
||||
var anglediff = Math.atan2(relpos.y, relpos.x) - Math.atan2(lastpos.y, lastpos.x);
|
||||
editor.rotlist?.forEach(function(x) {
|
||||
var anglediff = Math.atan2(relpos.y, relpos.x) - x.rotoffset;
|
||||
x.obj.angle = x.angle + Math.rad2turn(anglediff);
|
||||
if (Keys.shift())
|
||||
x.obj.angle = Math.nearest(x.obj.angle, (1/24));
|
||||
if (x.pos)
|
||||
x.obj.pos = x.pos.sub(x.offset).add(x.offset.rotate(anglediff));
|
||||
x.rotate(anglediff/(2*Math.PI));
|
||||
if (input.keyboard.down('shift')) {
|
||||
var rotate = Math.nearest(x.angle, 1/24) - x.angle;
|
||||
x.rotate(rotate)
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
editor.inputs.mouse.scroll = function(scroll)
|
||||
{
|
||||
scroll.y *= -1;
|
||||
editor.camera.move(Game.camera.dir_view2world(scroll.scale(-3)));
|
||||
editor.camera.move(game.camera.dir_view2world(scroll.scale(-3)));
|
||||
}
|
||||
|
||||
editor.inputs.mouse['C-scroll'] = function(scroll)
|
||||
|
@ -1204,7 +1179,7 @@ editor.inputs.mouse['C-scroll'] = function(scroll)
|
|||
editor.camera.zoom += scroll.y/100;
|
||||
}
|
||||
|
||||
editor.inputs['C-M-S-lm'] = function() { editor.selectlist[0].set_center(Mouse.worldpos()); };
|
||||
editor.inputs['C-M-S-lm'] = function() { editor.selectlist[0].set_center(input.mouse.worldpos()); };
|
||||
editor.inputs['C-M-S-lm'].doc = "Set world center to mouse position.";
|
||||
|
||||
editor.inputs.delete = function() {
|
||||
|
@ -1215,11 +1190,7 @@ editor.inputs.delete.doc = "Delete selected objects.";
|
|||
editor.inputs['S-d'] = editor.inputs.delete;
|
||||
editor.inputs['C-k'] = editor.inputs.delete;
|
||||
|
||||
editor.inputs['C-u'] = function() {
|
||||
this.selectlist.forEach(function(x) {
|
||||
x.revert();
|
||||
});
|
||||
};
|
||||
editor.inputs['C-u'] = function() { this.selectlist.forEach(x => x.revert()); };
|
||||
editor.inputs['C-u'].doc = "Revert selected objects back to their prefab form.";
|
||||
|
||||
editor.inputs['M-u'] = function() {
|
||||
|
@ -1241,7 +1212,7 @@ editor.inputs.g = function() {
|
|||
|
||||
if (editor.sel_comp) {
|
||||
if ('pick' in editor.sel_comp) {
|
||||
editor.grabselect = [editor.sel_comp.pick(Mouse.worldpos())];
|
||||
editor.grabselect = [editor.sel_comp.pick(input.mouse.worldpos())];
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -1258,7 +1229,7 @@ editor.inputs.g = function() {
|
|||
}
|
||||
|
||||
if (editor.sel_comp && 'pick' in editor.sel_comp) {
|
||||
var o = editor.sel_comp.pick(Mouse.worldpos());
|
||||
var o = editor.sel_comp.pick(input.mouse.worldpos());
|
||||
if (o) editor.grabselect = [o];
|
||||
return;
|
||||
}
|
||||
|
@ -1267,7 +1238,7 @@ editor.inputs.g = function() {
|
|||
};
|
||||
|
||||
editor.inputs.g.doc = "Move selected objects.";
|
||||
editor.inputs.g.released = function() { editor.grabselect = []; Mouse.normal(); };
|
||||
editor.inputs.g.released = function() { editor.grabselect = []; input.mouse.normal(); };
|
||||
|
||||
editor.inputs.up = function() { this.key_move([0,1]); };
|
||||
editor.inputs.up.rep = true;
|
||||
|
@ -1314,13 +1285,13 @@ editor.inputs['M-g'] = function()
|
|||
editor.inputs['M-g'].doc = "Move all.";
|
||||
|
||||
editor.inputs['C-lb'] = function() {
|
||||
editor.grid_size -= Keys.shift() ? 10 : 1;
|
||||
editor.grid_size -= input.keyboard.down('shift') ? 10 : 1;
|
||||
if (editor.grid_size <= 0) editor.grid_size = 1;
|
||||
};
|
||||
editor.inputs['C-lb'].doc = "Decrease grid size. Hold shift to decrease it more.";
|
||||
editor.inputs['C-lb'].rep = true;
|
||||
|
||||
editor.inputs['C-rb'] = function() { editor.grid_size += Keys.shift() ? 10 : 1; };
|
||||
editor.inputs['C-rb'] = function() { editor.grid_size += input.keyboard.down('shift') ? 10 : 1; };
|
||||
editor.inputs['C-rb'].doc = "Increase grid size. Hold shift to increase it more.";
|
||||
editor.inputs['C-rb'].rep = true;
|
||||
|
||||
|
@ -1385,27 +1356,16 @@ compmode.inputs['C-x'] = function() {};
|
|||
|
||||
editor.scalelist = [];
|
||||
editor.inputs.s = function() {
|
||||
var scaleoffset = Vector.length(Mouse.worldpos().sub(editor.cursor));
|
||||
editor.scaleoffset = Vector.length(input.mouse.worldpos().sub(editor.cursor));
|
||||
editor.scalelist = [];
|
||||
|
||||
if (editor.sel_comp) {
|
||||
if (!('scale' in editor.sel_comp)) return;
|
||||
editor.scalelist.push({
|
||||
obj: editor.sel_comp,
|
||||
scale: editor.sel_comp.scale,
|
||||
scaleoffset: scaleoffset,
|
||||
});
|
||||
editor.scalelist.push(editor.sel_comp);
|
||||
return;
|
||||
}
|
||||
|
||||
editor.selectlist.forEach(function(x) {
|
||||
editor.scalelist.push({
|
||||
obj: x,
|
||||
scale: x.scale,
|
||||
offset: x.pos.sub(editor.cursor),
|
||||
scaleoffset: scaleoffset,
|
||||
});
|
||||
});
|
||||
editor.scalelist = editor.selectlist;
|
||||
};
|
||||
editor.inputs.s.doc = "Scale selected.";
|
||||
|
||||
|
@ -1416,7 +1376,7 @@ var inputpanel = {
|
|||
toString() { return this.title; },
|
||||
value: "",
|
||||
on: false,
|
||||
pos:[100,Window.height-50],
|
||||
pos:[100,window.size.y-50],
|
||||
wh:[350,600],
|
||||
anchor: [0,1],
|
||||
padding:[5,-15],
|
||||
|
@ -1427,14 +1387,12 @@ var inputpanel = {
|
|||
if (!Array.isArray(itms)) itms = [itms];
|
||||
if (this.title)
|
||||
this.win.items = [
|
||||
Mum.column({items: [
|
||||
Mum.text({str:this.title}),
|
||||
...itms
|
||||
]})
|
||||
Mum.column({items: [Mum.text({str:this.title}), ...itms ]})
|
||||
];
|
||||
else
|
||||
this.win.items = itms;
|
||||
this.win.draw(this.pos.slice());
|
||||
|
||||
this.win.draw([100, window.size.y-50]);
|
||||
},
|
||||
|
||||
guibody() {
|
||||
|
@ -1490,11 +1448,9 @@ var inputpanel = {
|
|||
};
|
||||
|
||||
inputpanel.inputs = {};
|
||||
inputpanel.inputs.block = true;
|
||||
|
||||
inputpanel.inputs.post = function()
|
||||
{
|
||||
this.keycb();
|
||||
}
|
||||
inputpanel.inputs.post = function() { this.keycb(); }
|
||||
|
||||
inputpanel.inputs.char = function(c) {
|
||||
this.value = this.value.slice(0,this.caret) + c + this.value.slice(this.caret);
|
||||
|
@ -1536,26 +1492,20 @@ inputpanel.inputs['C-k'] = function() {
|
|||
this.value = this.value.slice(0,this.caret);
|
||||
};
|
||||
|
||||
inputpanel.inputs.lm = function()
|
||||
{
|
||||
GUI.controls.check_submit();
|
||||
}
|
||||
|
||||
//load("scripts/textedit.js");
|
||||
inputpanel.inputs.lm = function() { gui.controls.check_submit(); }
|
||||
|
||||
var replpanel = Object.copy(inputpanel, {
|
||||
title: "",
|
||||
closeonsubmit:false,
|
||||
wh: [700,300],
|
||||
pos: [50,50],
|
||||
anchor: [0,0],
|
||||
anchor: [0,1],
|
||||
padding: [0,0],
|
||||
scrolloffset: [0,0],
|
||||
|
||||
guibody() {
|
||||
this.win.selectable = true;
|
||||
//var log = cmd(84);
|
||||
log = log.slice(-5000);
|
||||
var log = console.transcript;
|
||||
return [
|
||||
Mum.text({str:log, anchor:[0,0], offset:[0,-300].sub(this.scrolloffset), selectable: true}),
|
||||
Mum.text({str:this.value,color:Color.green, offset:[0,-290], caret: this.caret})
|
||||
|
@ -1580,7 +1530,7 @@ var replpanel = Object.copy(inputpanel, {
|
|||
this.caret = 0;
|
||||
var ret = function() {return eval(ecode);}.call(repl_obj);
|
||||
if (typeof ret === 'object') ret = json.encode(ret,null,1);
|
||||
say(ret);
|
||||
if (typeof ret !== 'undefined') say(ret);
|
||||
},
|
||||
|
||||
resetscroll() {
|
||||
|
@ -1592,7 +1542,7 @@ replpanel.inputs = Object.create(inputpanel.inputs);
|
|||
replpanel.inputs.block = true;
|
||||
replpanel.inputs.lm = function()
|
||||
{
|
||||
var mg = physics.pos_query(Mouse.worldpos());
|
||||
var mg = physics.pos_query(input.mouse.worldpos());
|
||||
if (!mg) return;
|
||||
var p = mg.path_from(editor.get_this());
|
||||
this.value = p;
|
||||
|
@ -1779,16 +1729,8 @@ var objectexplorer = Object.copy(inputpanel, {
|
|||
switch (typeof val) {
|
||||
case 'object':
|
||||
if (val) {
|
||||
if (Array.isArray(val)) {
|
||||
// this.obj[key] = Nuke.pprop(key,val);
|
||||
break;
|
||||
}
|
||||
|
||||
// Nuke.newline(2);
|
||||
items.push(Mum.text({str:name}));
|
||||
items.push(Mum.text({str:val.toString(), action: this.goto_obj.bind(val)}));
|
||||
} else {
|
||||
// this.obj[key] = Nuke.pprop(key,val);
|
||||
}
|
||||
break;
|
||||
|
||||
|
@ -1798,28 +1740,13 @@ var objectexplorer = Object.copy(inputpanel, {
|
|||
break;
|
||||
|
||||
default:
|
||||
if (!hidden) {// && Object.getOwnPropertyDescriptor(this.obj, key).writable) {
|
||||
// this.obj[key] = Nuke.pprop(key, this.obj[key]);
|
||||
|
||||
/* if (key in this.obj.__proto__) {
|
||||
if (Nuke.button("delete " + key)) {
|
||||
if ("_"+key in this.obj)
|
||||
delete this.obj["_"+key];
|
||||
else
|
||||
delete this.obj[key];
|
||||
}
|
||||
}*/
|
||||
}
|
||||
else {
|
||||
items.push(Mum.text({str:name}));
|
||||
items.push(Mum.text({str:val.toString()}));
|
||||
}
|
||||
break;
|
||||
}
|
||||
});
|
||||
|
||||
items.push(Mum.text({str:"Properties that can be pulled in ..."}));
|
||||
// Nuke.newline(3);
|
||||
var pullprops = [];
|
||||
for (var key in this.obj.__proto__) {
|
||||
if (!this.obj.hasOwn(key)) {
|
||||
|
@ -1832,25 +1759,10 @@ var objectexplorer = Object.copy(inputpanel, {
|
|||
|
||||
pullprops.forEach(function(key) {
|
||||
items.push(Mum.text({str:key}));
|
||||
// this.obj[key] = this.obj[key];
|
||||
});
|
||||
|
||||
return items;
|
||||
},
|
||||
|
||||
|
||||
});
|
||||
|
||||
var helppanel = Object.copy(inputpanel, {
|
||||
title: "help",
|
||||
|
||||
start() {
|
||||
this.helptext = slurp("editor.adoc");
|
||||
},
|
||||
|
||||
guibody() {
|
||||
Nuke.label(this.helptext);
|
||||
},
|
||||
});
|
||||
|
||||
var openlevelpanel = Object.copy(inputpanel, {
|
||||
|
@ -1928,9 +1840,7 @@ var groupsaveaspanel = Object.copy(inputpanel, {
|
|||
|
||||
var quitpanel = Object.copy(inputpanel, {
|
||||
title: "really quit?",
|
||||
action() {
|
||||
Game.quit();
|
||||
},
|
||||
action() { os.quit(); },
|
||||
|
||||
guibody () {
|
||||
return Mum.text({str: "Really quit?"});
|
||||
|
@ -2016,19 +1926,6 @@ function tab_complete(val, list) {
|
|||
return ret ? ret : val;
|
||||
}
|
||||
|
||||
var texgui = Object.copy(inputpanel, {
|
||||
get path() { return this._path; },
|
||||
set path(x) {
|
||||
this._path = x;
|
||||
this.title = "texture " + x;
|
||||
},
|
||||
|
||||
guibody() {
|
||||
Nuke.label("texture");
|
||||
Nuke.img(this.path);
|
||||
},
|
||||
});
|
||||
|
||||
var entitylistpanel = Object.copy(inputpanel, {
|
||||
title: "Level object list",
|
||||
level: {},
|
||||
|
@ -2043,16 +1940,16 @@ limited_editor.inputs = {};
|
|||
|
||||
limited_editor.inputs['C-p'] = function()
|
||||
{
|
||||
if (Game.playing())
|
||||
Game.pause();
|
||||
if (sim.playing())
|
||||
sim.pause();
|
||||
else
|
||||
Game.play();
|
||||
sim.play();
|
||||
}
|
||||
|
||||
limited_editor.inputs['M-p'] = function()
|
||||
{
|
||||
Game.pause();
|
||||
Game.step();
|
||||
sim.pause();
|
||||
sim.step();
|
||||
}
|
||||
|
||||
limited_editor.inputs['C-q'] = function()
|
||||
|
@ -2068,13 +1965,10 @@ limited_editor.inputs['C-q'] = function()
|
|||
var limited_editing = {};
|
||||
limited_editing.inputs = {};
|
||||
|
||||
if (io.exists("editor.config"))
|
||||
load_configs("editor.config");
|
||||
|
||||
/* This is the editor level & camera - NOT the currently edited level, but a level to hold editor things */
|
||||
Game.stop();
|
||||
Window.editor = true;
|
||||
Debug.draw_phys(true);
|
||||
sim.pause();
|
||||
window.editor = true;
|
||||
debug.draw_phys = true;
|
||||
|
||||
return {
|
||||
editor
|
||||
|
|
|
@ -1,37 +1,234 @@
|
|||
"use math";
|
||||
|
||||
Object.defineProperty(String.prototype, 'tolast', {
|
||||
value: function(val) {
|
||||
var idx = this.lastIndexOf(val);
|
||||
if (idx === -1) return this.slice();
|
||||
return this.slice(0,idx);
|
||||
}
|
||||
});
|
||||
|
||||
Object.defineProperty(String.prototype, 'dir', {
|
||||
value: function() {
|
||||
if (!this.includes('/')) return "";
|
||||
return this.tolast('/');
|
||||
}
|
||||
});
|
||||
|
||||
globalThis.Resources = {};
|
||||
|
||||
Resources.replpath = function(str, path)
|
||||
{
|
||||
if (!str) return str;
|
||||
if (str[0] === "/")
|
||||
return str.rm(0);
|
||||
|
||||
if (str[0] === "@")
|
||||
return os.prefpath() + "/" + str.rm(0);
|
||||
|
||||
if (!path) return str;
|
||||
|
||||
var stem = path.dir();
|
||||
while (stem) {
|
||||
var tr = stem + "/" +str;
|
||||
if (io.exists(tr)) return tr;
|
||||
stem = stem.updir();
|
||||
}
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
Resources.replstrs = function(path)
|
||||
{
|
||||
if (!path) return;
|
||||
var script = io.slurp(path);
|
||||
var regexp = /"[^"\s]*?\.[^"\s]+?"/g;
|
||||
var stem = path.dir();
|
||||
|
||||
script = script.replace(regexp,function(str) {
|
||||
var newstr = Resources.replpath(str.trimchr('"'), path);
|
||||
return `"${newstr}"`;
|
||||
});
|
||||
|
||||
return script;
|
||||
}
|
||||
|
||||
globalThis.json = {};
|
||||
json.encode = function(value, replacer, space = 1)
|
||||
{
|
||||
return JSON.stringify(value, replacer, space);
|
||||
}
|
||||
|
||||
json.decode = function(text, reviver)
|
||||
{
|
||||
if (!text) return undefined;
|
||||
return JSON.parse(text,reviver);
|
||||
}
|
||||
|
||||
json.readout = function(obj)
|
||||
{
|
||||
var j = {};
|
||||
for (var k in obj)
|
||||
if (typeof obj[k] === 'function')
|
||||
j[k] = 'function ' + obj[k].toString();
|
||||
else
|
||||
j[k] = obj[k];
|
||||
|
||||
return json.encode(j);
|
||||
}
|
||||
|
||||
json.doc = {
|
||||
doc: "json implementation.",
|
||||
encode: "Encode a value to json.",
|
||||
decode: "Decode a json string to a value.",
|
||||
readout: "Encode an object fully, including function definitions."
|
||||
};
|
||||
|
||||
Resources.scripts = ["jsoc", "jsc", "jso", "js"];
|
||||
Resources.images = ["png", "gif", "jpg", "jpeg"];
|
||||
Resources.sounds = ["wav", 'flac', 'mp3', "qoa"];
|
||||
Resources.is_image = function(path) {
|
||||
var ext = path.ext();
|
||||
return Resources.images.any(x => x === ext);
|
||||
}
|
||||
|
||||
function find_ext(file, ext)
|
||||
{
|
||||
if (io.exists(file)) return file;
|
||||
for (var e of ext) {
|
||||
var nf = `${file}.${e}`;
|
||||
if (io.exists(nf)) return nf;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
Resources.find_image = function(file) { return find_ext(file,Resources.images); }
|
||||
Resources.find_sound = function(file) { return find_ext(file,Resources.sounds); }
|
||||
Resources.find_script = function(file) { return find_ext(file,Resources.scripts); }
|
||||
|
||||
profile.best_t = function(t) {
|
||||
var qq = 'ns';
|
||||
if (t > 1000) {
|
||||
t /= 1000;
|
||||
qq = 'us';
|
||||
if (t > 1000) {
|
||||
t /= 1000;
|
||||
qq = 'ms';
|
||||
}
|
||||
}
|
||||
return `${t.toPrecision(4)} ${qq}`;
|
||||
}
|
||||
|
||||
profile.report = function(start, msg = "[undefined report]")
|
||||
{
|
||||
console.info(`${msg} in ${profile.best_t(profile.now()-start)}`);
|
||||
}
|
||||
|
||||
profile.addreport = function(cache, line, start)
|
||||
{
|
||||
cache[line] ??= [];
|
||||
cache[line].push(profile.now()-start);
|
||||
}
|
||||
|
||||
profile.printreport = function(cache, name)
|
||||
{
|
||||
var report = name + "\n";
|
||||
for (var i in cache) {
|
||||
report += `${i} ${profile.best_t(profcache[i].reduce((a,b) => a+b)/profcache[i].length)}\n`;
|
||||
}
|
||||
|
||||
return report;
|
||||
}
|
||||
|
||||
console.transcript = "";
|
||||
console.say = function(msg) {
|
||||
msg += "\n";
|
||||
console.print(msg);
|
||||
console.transcript += msg;
|
||||
};
|
||||
console.log = console.say;
|
||||
var say = console.say;
|
||||
var print = console.print;
|
||||
|
||||
console.pprint = function(msg,lvl = 0) {
|
||||
if (typeof msg === 'object')
|
||||
msg = JSON.stringify(msg, null, 2);
|
||||
|
||||
var file = "nofile";
|
||||
var line = 0;
|
||||
|
||||
var caller = (new Error()).stack.split('\n')[2];
|
||||
if (caller) {
|
||||
var md = caller.match(/\((.*)\:/);
|
||||
var m = md ? md[1] : "SCRIPT";
|
||||
if (m) file = m;
|
||||
md = caller.match(/\:(\d*)\)/);
|
||||
m = md ? md[1] : 0;
|
||||
if (m) line = m;
|
||||
}
|
||||
|
||||
console.rec(lvl, msg, file, line);
|
||||
};
|
||||
|
||||
console.spam = function(msg) { console.pprint (msg,0); };
|
||||
console.debug = function(msg) { console.pprint(msg,1); };
|
||||
console.info = function(msg) { console.pprint(msg, 2); };
|
||||
console.warn = function(msg) { console.pprint(msg, 3); };
|
||||
console.error = function(msg) { console.pprint(msg + "\n" + console.stackstr(2), 4);};
|
||||
console.panic = function(msg) { console.pprint(msg + "\n" + console.stackstr(2), 5); };
|
||||
console.stackstr = function(skip=0) {
|
||||
var err = new Error();
|
||||
var stack = err.stack.split('\n');
|
||||
return stack.slice(skip,stack.length).join('\n');
|
||||
};
|
||||
|
||||
console.stack = function(skip = 0) { console.log(console.stackstr(skip+1)); };
|
||||
|
||||
console.stdout_lvl = 1;
|
||||
console.trace = console.stack;
|
||||
|
||||
console.doc = {
|
||||
level: "Set level to output logging to console.",
|
||||
info: "Output info level message.",
|
||||
warn: "Output warn level message.",
|
||||
error: "Output error level message, and print stacktrace.",
|
||||
critical: "Output critical level message, and exit game immediately.",
|
||||
write: "Write raw text to console.",
|
||||
say: "Write raw text to console, plus a newline.",
|
||||
stack: "Output a stacktrace to console.",
|
||||
console: "Output directly to in game console.",
|
||||
clear: "Clear console."
|
||||
};
|
||||
|
||||
globalThis.global = globalThis;
|
||||
|
||||
function use(file)
|
||||
var profcache = {};
|
||||
|
||||
function use(file, env = {}, script)
|
||||
{
|
||||
if (use.files[file]) return use.files[file];
|
||||
if (globalThis.console)
|
||||
console.info(`running ${file}`);
|
||||
file = Resources.find_script(file);
|
||||
var st = profile.now();
|
||||
|
||||
var c = io.slurp(file);
|
||||
profcache[file] ??= [];
|
||||
|
||||
var script = `(function() { ${c} })();`;
|
||||
use.files[file] = cmd(123,script,global,file);
|
||||
|
||||
return use.files[file];
|
||||
if (use.cache[file]) {
|
||||
var ret = use.cache[file].call(env);
|
||||
profile.report(st, `CACHE eval ${file}`);
|
||||
profile.addreport(profcache, file, st);
|
||||
return;
|
||||
}
|
||||
use.files = {};
|
||||
|
||||
function include(file,that)
|
||||
{
|
||||
if (!that) return;
|
||||
if (globalThis.console) console.info(`running ${file}`);
|
||||
var c = io.slurp(file);
|
||||
eval_env(c, that, file);
|
||||
console.info(`slurping ${file}`);
|
||||
script ??= Resources.replstrs(file);
|
||||
script = `(function() { var self = this; ${script}; })`;
|
||||
var fn = os.eval(file,script);
|
||||
use.cache[file] = fn;
|
||||
var ret = fn.call(env);
|
||||
profile.report(st, `eval ${file}`);
|
||||
profile.addreport(profcache, file, st);
|
||||
return ret;
|
||||
}
|
||||
|
||||
function eval_env(script, env, file)
|
||||
{
|
||||
env ??= {};
|
||||
file ??= "SCRIPT";
|
||||
if (globalThis.console) console.info(`eval ${file}`);
|
||||
script = `(function() { ${script}; }).call(this);\n`;
|
||||
return cmd(123,script,env,file);
|
||||
}
|
||||
use.cache = {};
|
||||
|
||||
global.check_registers = function(obj)
|
||||
{
|
||||
|
@ -41,12 +238,6 @@ global.check_registers = function(obj)
|
|||
if (typeof obj.physupdate === 'function')
|
||||
obj.timers.push(Register.physupdate.register(obj.physupdate.bind(obj)));
|
||||
|
||||
if (typeof obj.collide === 'function')
|
||||
register_collide(0, obj.collide.bind(obj), obj.body);
|
||||
|
||||
if (typeof obj.separate === 'function')
|
||||
register_collide(3,obj.separate.bind(obj), obj.body);
|
||||
|
||||
if (typeof obj.draw === 'function')
|
||||
obj.timers.push(Register.draw.register(obj.draw.bind(obj), obj));
|
||||
|
||||
|
@ -63,105 +254,147 @@ global.check_registers = function(obj)
|
|||
};
|
||||
}
|
||||
|
||||
eval_env.dov = `Counterpart to /load_env/, but with a string.`;
|
||||
|
||||
function feval_env(file, env)
|
||||
{
|
||||
eval_env(io.slurp(file), env, file);
|
||||
}
|
||||
|
||||
function load_env(file,env)
|
||||
{
|
||||
env ??= global;
|
||||
// var script = io.slurp(file);
|
||||
var script = io.slurp(file);
|
||||
eval_env(script, env, file);
|
||||
// cmd(16, file, env);
|
||||
// var script = io.slurp(file);
|
||||
// cmd(123, script, env, file);
|
||||
}
|
||||
load_env.doc = `Load a given file with 'env' as **this**. Does not add to the global namespace.`;
|
||||
|
||||
var load = use;
|
||||
|
||||
Object.assign(global, use("scripts/base.js"));
|
||||
Object.assign(global, use("scripts/base"));
|
||||
global.obscure('global');
|
||||
global.mixin("scripts/render.js");
|
||||
global.mixin("scripts/render");
|
||||
global.mixin("scripts/debug");
|
||||
|
||||
global.Game = {
|
||||
engine_start(fn) {
|
||||
console.info("Starting rendering and sound ...");
|
||||
cmd(257, fn);
|
||||
},
|
||||
var frame_t = profile.secs(profile.now());
|
||||
var phys_step = 1/240;
|
||||
|
||||
object_count() {
|
||||
return cmd(214);
|
||||
},
|
||||
var sim = {};
|
||||
sim.mode = "play";
|
||||
sim.play = function() { this.mode = "play"; os.reindex_static(); };
|
||||
sim.playing = function() { return this.mode === 'play'; };
|
||||
sim.pause = function() { this.mode = "pause"; };
|
||||
sim.paused = function() { return this.mode === 'pause'; };
|
||||
sim.step = function() { this.mode = 'step'; };
|
||||
sim.stepping = function() { return this.mode === 'step'; }
|
||||
|
||||
all_objects(fn) {
|
||||
/* Wind down from Primum */
|
||||
},
|
||||
var physlag = 0;
|
||||
|
||||
/* Returns a list of objects by name */
|
||||
find(name) {
|
||||
var gggstart = game.engine_start;
|
||||
game.engine_start = function(s) {
|
||||
game.startengine = 1;
|
||||
gggstart(function() {
|
||||
global.mixin("scripts/sound.js");
|
||||
world_start();
|
||||
go_init();
|
||||
window.set_icon(os.make_texture("icons/moon.gif"))
|
||||
Object.readonly(window.__proto__, 'vsync');
|
||||
Object.readonly(window.__proto__, 'enable_dragndrop');
|
||||
Object.readonly(window.__proto__, 'enable_clipboard');
|
||||
Object.readonly(window.__proto__, 'high_dpi');
|
||||
Object.readonly(window.__proto__, 'sample_count');
|
||||
s();
|
||||
}, process);
|
||||
}
|
||||
|
||||
},
|
||||
game.startengine = 0;
|
||||
|
||||
/* Return a list of objects derived from a specific prototype */
|
||||
find_proto(proto) {
|
||||
function process()
|
||||
{
|
||||
var dt = profile.secs(profile.now()) - frame_t;
|
||||
frame_t = profile.secs(profile.now());
|
||||
|
||||
},
|
||||
prosperon.appupdate(dt);
|
||||
prosperon.emitters_step(dt);
|
||||
input.procdown();
|
||||
|
||||
/* List of all objects spawned that have a specific tag */
|
||||
find_tag(tag){
|
||||
if (sim.mode === "play" || sim.mode === "step") {
|
||||
prosperon.update(dt*game.timescale);
|
||||
if (sim.mode === "step")
|
||||
sim.pause();
|
||||
|
||||
},
|
||||
physlag += dt;
|
||||
|
||||
quit() {
|
||||
sys_cmd(0);
|
||||
},
|
||||
while (physlag > phys_step) {
|
||||
physlag -= phys_step;
|
||||
prosperon.phys2d_step(phys_step*game.timescale);
|
||||
prosperon.physupdate(phys_step*game.timescale);
|
||||
}
|
||||
}
|
||||
|
||||
pause() { sys_cmd(3); },
|
||||
stop() { Game.pause(); },
|
||||
step() { sys_cmd(4);},
|
||||
playing() { return sys_cmd(5); },
|
||||
paused() { return sys_cmd(6); },
|
||||
stepping() { return cmd(79); },
|
||||
play() { sys_cmd(1); },
|
||||
|
||||
wait_fns: [],
|
||||
|
||||
wait_exec(fn) {
|
||||
if (!phys_stepping())
|
||||
fn();
|
||||
if (!game.camera)
|
||||
prosperon.window_render(world, 1);
|
||||
else
|
||||
this.wait_fns.push(fn);
|
||||
},
|
||||
prosperon.window_render(game.camera, game.camera.zoom);
|
||||
|
||||
exec() {
|
||||
this.wait_fns.forEach(function(x) { x(); });
|
||||
render.set_camera();
|
||||
render.sprites(); // blits all sprites
|
||||
render.models(); // blits all models
|
||||
render.emitters(); // blits emitters
|
||||
prosperon.draw(); // draw calls
|
||||
debug.draw(); // calls needed debugs
|
||||
render.flush();
|
||||
|
||||
this.wait_fns = [];
|
||||
},
|
||||
};
|
||||
render.set_window();
|
||||
prosperon.gui();
|
||||
render.flush();
|
||||
|
||||
Game.gc = function() { cmd(259); }
|
||||
Game.gc.doc = "Force the garbage collector to run.";
|
||||
render.end_pass();
|
||||
}
|
||||
|
||||
Game.doc = {};
|
||||
Game.doc.object = "Returns the entity belonging to a given id.";
|
||||
Game.doc.quit = "Immediately quit the game.";
|
||||
Game.doc.pause = "Pause game simulation.";
|
||||
Game.doc.stop = "Stop game simulation. This does the same thing as 'pause', and if the game is a debug build, starts its editor.";
|
||||
Game.doc.play = "Resume or start game simulation.";
|
||||
Game.doc.editor_mode = "Set to true for the game to only update on input; otherwise the game updates every frame.";
|
||||
Game.doc.dt = "Current frame dt.";
|
||||
Game.doc.view_camera = "Set the camera for the current view.";
|
||||
Game.doc.camera = "Current camera.";
|
||||
game.timescale = 1;
|
||||
|
||||
global.prosperon = {};
|
||||
prosperon.version = cmd(255);
|
||||
prosperon.revision = cmd(256);
|
||||
var eachobj = function(obj,fn)
|
||||
{
|
||||
var val = fn(obj);
|
||||
if (val) return val;
|
||||
for (var o in obj.objects) {
|
||||
if (obj.objects[o] === obj)
|
||||
console.error(`Object ${obj.toString()} is referenced by itself.`);
|
||||
val = eachobj(obj.objects[o],fn);
|
||||
if (val) return val;
|
||||
}
|
||||
}
|
||||
|
||||
game.all_objects = function(fn, startobj = world) { return eachobj(startobj,fn); };
|
||||
game.find_object = function(fn, startobj = world) {
|
||||
|
||||
}
|
||||
|
||||
game.tags = {};
|
||||
game.tag_add = function(tag, obj) {
|
||||
game.tags[tag] ??= {};
|
||||
game.tags[tag][obj.guid] = obj;
|
||||
}
|
||||
|
||||
game.tag_rm = function(tag, obj) {
|
||||
delete game.tags[tag][obj.guid];
|
||||
}
|
||||
|
||||
game.tag_clear_guid = function(guid)
|
||||
{
|
||||
for (var tag in game.tags)
|
||||
delete game.tags[tag][guid];
|
||||
}
|
||||
|
||||
game.objects_with_tag = function(tag)
|
||||
{
|
||||
if (!game.tags[tag]) return;
|
||||
return Object.values(game.tags[tag]);
|
||||
}
|
||||
|
||||
game.doc = {};
|
||||
game.doc.object = "Returns the entity belonging to a given id.";
|
||||
game.doc.pause = "Pause game simulation.";
|
||||
game.doc.play = "Resume or start game simulation.";
|
||||
game.doc.camera = "Current camera.";
|
||||
|
||||
game.texture = function(path)
|
||||
{
|
||||
if (game.texture.cache[path]) return game.texture.cache[path];
|
||||
|
||||
if (!io.exists(path)) {
|
||||
console.warn(`Missing texture: ${path}`);
|
||||
game.texture.cache[path] = game.texture("icons/no_tex.gif");
|
||||
} else
|
||||
game.texture.cache[path] ??= os.make_texture(path);
|
||||
|
||||
return game.texture.cache[path];
|
||||
}
|
||||
game.texture.cache = {};
|
||||
|
||||
prosperon.semver = {};
|
||||
prosperon.semver.valid = function(v, range)
|
||||
|
@ -222,13 +455,22 @@ prosperon.touchpress = function(touches){};
|
|||
prosperon.touchrelease = function(touches){};
|
||||
prosperon.touchmove = function(touches){};
|
||||
prosperon.clipboardpaste = function(str){};
|
||||
prosperon.quit = function(){
|
||||
console.info(profile.printreport(profcache, "USE REPORT"));
|
||||
console.info(profile.printreport(entityreport, "ENTITY REPORT"));
|
||||
|
||||
global.mixin("scripts/input.js");
|
||||
global.mixin("scripts/std.js");
|
||||
console.level = 1;
|
||||
global.mixin("scripts/diff.js");
|
||||
global.mixin("scripts/color.js");
|
||||
global.mixin("scripts/gui.js");
|
||||
console.info("QUITTING");
|
||||
for (var i in debug.log.time)
|
||||
console.warn(debug.log.time[i].map(x=>profile.ms(x)));
|
||||
};
|
||||
|
||||
global.mixin("scripts/input");
|
||||
global.mixin("scripts/std");
|
||||
global.mixin("scripts/diff");
|
||||
global.mixin("scripts/color");
|
||||
global.mixin("scripts/gui");
|
||||
global.mixin("scripts/tween");
|
||||
global.mixin("scripts/ai");
|
||||
|
||||
var timer = {
|
||||
update(dt) {
|
||||
|
@ -241,7 +483,7 @@ var timer = {
|
|||
|
||||
kill() {
|
||||
this.end();
|
||||
this.fn = undefined;
|
||||
delete this.fn;
|
||||
},
|
||||
|
||||
delay(fn, secs) {
|
||||
|
@ -250,68 +492,20 @@ var timer = {
|
|||
t.remain = secs;
|
||||
t.fn = fn;
|
||||
t.end = Register.update.register(timer.update.bind(t));
|
||||
return function() { t.kill(); };
|
||||
var returnfn = timer.kill.bind(t);
|
||||
returnfn.remain = secs;
|
||||
return returnfn;
|
||||
},
|
||||
};
|
||||
|
||||
global.mixin("scripts/tween.js");
|
||||
global.mixin("scripts/physics.js");
|
||||
global.mixin("scripts/ai.js");
|
||||
global.mixin("scripts/geometry.js");
|
||||
global.mixin("scripts/physics");
|
||||
global.mixin("scripts/geometry");
|
||||
|
||||
/*
|
||||
Factory for creating registries. Register one with 'X.register',
|
||||
which returns a function that, when invoked, cancels the registry.
|
||||
*/
|
||||
var Register = {
|
||||
kbm_input(mode, btn, state, ...args) {
|
||||
if (state === 'released') {
|
||||
btn = btn.split('-').last();
|
||||
}
|
||||
|
||||
switch(mode) {
|
||||
case "emacs":
|
||||
player[0].raw_input(btn, state, ...args);
|
||||
break;
|
||||
|
||||
case "mouse":
|
||||
player[0].mouse_input(btn, state, ...args);
|
||||
break;
|
||||
|
||||
case "char":
|
||||
player[0].char_input(btn);
|
||||
break;
|
||||
};
|
||||
},
|
||||
|
||||
gamepad_playermap: [],
|
||||
gamepad_input(pad, btn, state, ...args) {
|
||||
var player = this.gamepad_playermap[pad];
|
||||
if (!player) return;
|
||||
|
||||
var statestr = Input.state2str(state);
|
||||
|
||||
var rawfn = `gamepad_${btn}_${statestr}`;
|
||||
player.input(rawfn, ...args);
|
||||
|
||||
input.action.actions.forEach(x => {
|
||||
if (x.inputs.includes(btn))
|
||||
player.input(`action_${x.name}_${statestr}`, ...args);
|
||||
});
|
||||
},
|
||||
|
||||
unregister_obj(obj) { Player.uncontrol(obj); },
|
||||
|
||||
endofloop(fn) {
|
||||
if (!this.inloop)
|
||||
fn();
|
||||
else {
|
||||
this.loopcbs.push(fn);
|
||||
}
|
||||
},
|
||||
|
||||
clear() {
|
||||
Register.registries.forEach(function(n) {
|
||||
n.entries = [];
|
||||
});
|
||||
},
|
||||
|
||||
registries: [],
|
||||
|
||||
add_cb(name) {
|
||||
|
@ -323,9 +517,12 @@ var Register = {
|
|||
if (typeof obj === 'object')
|
||||
fn = fn.bind(obj);
|
||||
fns.push(fn);
|
||||
return function() { fns.remove(fn); };
|
||||
return function() {
|
||||
fns.remove(fn);
|
||||
};
|
||||
}
|
||||
prosperon[name] = function(...args) { fns.forEach(x => x(...args)); }
|
||||
prosperon[name].fns = fns;
|
||||
n.clear = function() { fns = []; }
|
||||
|
||||
Register[name] = n;
|
||||
|
@ -335,16 +532,13 @@ var Register = {
|
|||
},
|
||||
};
|
||||
|
||||
Register.add_cb("update").doc = "Called once per frame.";
|
||||
Register.add_cb("appupdate");
|
||||
Register.add_cb("update").doc = "Called once per frame.";
|
||||
Register.add_cb("physupdate");
|
||||
Register.add_cb("gui");
|
||||
Register.add_cb("debug");
|
||||
Register.add_cb("gamepad_input");
|
||||
Register.add_cb("draw");
|
||||
|
||||
Register.gamepad_playermap[0] = Player.players[0];
|
||||
|
||||
var Event = {
|
||||
events: {},
|
||||
|
||||
|
@ -361,84 +555,60 @@ var Event = {
|
|||
Object.keys(this.events).forEach(name => Event.unobserve(name,obj));
|
||||
},
|
||||
|
||||
notify(name) {
|
||||
notify(name, ...args) {
|
||||
if (!this.events[name]) return;
|
||||
this.events[name].forEach(function(x) {
|
||||
x[1].call(x[0]);
|
||||
x[1].call(x[0], ...args);
|
||||
});
|
||||
},
|
||||
};
|
||||
|
||||
Window.modetypes = {
|
||||
stretch: 0, // stretch to fill window
|
||||
keep: 1, // keep exact dimensions
|
||||
width: 2, // keep width
|
||||
height: 3, // keep height
|
||||
// window.rendersize is the resolution the game renders at
|
||||
// window.size is the physical size of the window on the desktop
|
||||
window.modetypes = {
|
||||
stretch: 0, // stretch render to fill window
|
||||
keep: 1, // keep render exact dimensions, with no stretching
|
||||
width: 2, // keep render at width
|
||||
height: 3, // keep render at height
|
||||
expand: 4, // expand width or height
|
||||
full: 5 // expand out beyond window
|
||||
};
|
||||
|
||||
Window.size = [640, 480];
|
||||
window.size = [640, 480];
|
||||
|
||||
Window.screen2world = function(screenpos) {
|
||||
if (Game.camera)
|
||||
return Game.camera.view2world(screenpos);
|
||||
window.set_icon.doc = "Set the icon of the window using the PNG image at path.";
|
||||
|
||||
return screenpos;
|
||||
}
|
||||
global.mixin("scripts/spline");
|
||||
global.mixin("scripts/components");
|
||||
|
||||
Window.world2screen = function(worldpos) {
|
||||
return Game.camera.world2view(worldpos);
|
||||
}
|
||||
window.doc = {};
|
||||
window.doc.dimensions = "Window width and height packaged in an array [width,height]";
|
||||
window.doc.title = "Name in the title bar of the window.";
|
||||
window.doc.boundingbox = "Boundingbox of the window, with top and right being its height and width.";
|
||||
|
||||
Window.icon = function(path) { cmd(90, path); };
|
||||
Window.icon.doc = "Set the icon of the window using the PNG image at path.";
|
||||
|
||||
global.mixin("scripts/debug.js");
|
||||
global.mixin("scripts/spline.js");
|
||||
global.mixin("scripts/components.js");
|
||||
|
||||
Window.doc = {};
|
||||
Window.doc.width = "Width of the game window.";
|
||||
Window.doc.height = "Height of the game window.";
|
||||
Window.doc.dimensions = "Window width and height packaged in an array [width,height]";
|
||||
Window.doc.title = "Name in the title bar of the window.";
|
||||
Window.doc.boundingbox = "Boundingbox of the window, with top and right being its height and width.";
|
||||
|
||||
Register.update.register(Game.exec, Game);
|
||||
|
||||
global.mixin("scripts/actor.js");
|
||||
global.mixin("scripts/entity.js");
|
||||
global.mixin("scripts/actor");
|
||||
global.mixin("scripts/entity");
|
||||
|
||||
function world_start() {
|
||||
globalThis.world = Object.create(gameobject);
|
||||
globalThis.world = os.make_gameobject();
|
||||
world.objects = {};
|
||||
world.check_dirty = function() {};
|
||||
world.namestr = function(){};
|
||||
world._ed = {
|
||||
selectable:false,
|
||||
dirty:false,
|
||||
};
|
||||
world.toString = function() { return "world"; };
|
||||
world.master = gameobject;
|
||||
world.ur = "world";
|
||||
world.kill = function() { this.clear(); };
|
||||
world.phys = 2;
|
||||
|
||||
gameobject.level = world;
|
||||
gameobject.body = make_gameobject();
|
||||
cmd(113,gameobject.body, gameobject);
|
||||
Object.hide(gameobject, 'timescale');
|
||||
var cam = world.spawn("scripts/camera2d.jso");
|
||||
Game.view_camera(cam);
|
||||
world.zoom = 1;
|
||||
world._ed = { selectable: false };
|
||||
world.ur = {};
|
||||
world.ur.fresh = {};
|
||||
game.cam = world;
|
||||
}
|
||||
|
||||
global.mixin("scripts/physics.js");
|
||||
global.mixin("scripts/physics");
|
||||
|
||||
Game.view_camera = function(cam)
|
||||
{
|
||||
Game.camera = cam;
|
||||
cmd(61, Game.camera.body);
|
||||
window.title = `Prosperon v${prosperon.version}`;
|
||||
window.size = [500,500];
|
||||
window.boundingbox = function() {
|
||||
var pos = game.camera.pos;
|
||||
var wh = window.rendersize.scale(game.camera.zoom);
|
||||
return bbox.fromcwh(pos,wh);
|
||||
}
|
||||
|
||||
Window.title = `Prosperon v${prosperon.version}`;
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -2,11 +2,9 @@ var shape = {};
|
|||
shape.sphere = {};
|
||||
shape.circle = {};
|
||||
shape.sphere.volume = function(r) { return Math.pi*r*r*r*4/3; };
|
||||
shape.sphere.random = function(r,theta,phi)
|
||||
shape.sphere.random = function(r,theta = [0,1], phi = [-0.5,0.5])
|
||||
{
|
||||
if (typeof r === 'number') r = [r,r];
|
||||
theta ??= [0,1];
|
||||
phi ??= [-0.5,0.5];
|
||||
if (typeof theta === 'number') theta = [theta,theta];
|
||||
if (typeof phi === 'number') phi = [phi,phi];
|
||||
|
||||
|
@ -44,8 +42,7 @@ shape.ngon = function(radius, n) {
|
|||
return shape.arc(radius,360,n);
|
||||
};
|
||||
|
||||
shape.arc = function(radius, angle, n, start) {
|
||||
start ??= 0;
|
||||
shape.arc = function(radius, angle, n, start = 0) {
|
||||
start = Math.deg2rad(start);
|
||||
if (angle >= 360)
|
||||
angle = 360;
|
||||
|
|
183
scripts/gui.js
183
scripts/gui.js
|
@ -1,100 +1,41 @@
|
|||
/*
|
||||
GUI functions take screen space coordinates
|
||||
gui functions take screen space coordinates
|
||||
*/
|
||||
|
||||
var GUI = {
|
||||
text(str, pos, size, color, wrap, anchor, cursor) {
|
||||
size ??= 1;
|
||||
color ??= Color.white;
|
||||
wrap ??= -1;
|
||||
anchor ??= [0,1];
|
||||
gui.scissor_win = function() { gui.scissor(0,0,window.size.x,window.y); }
|
||||
|
||||
cursor ??= -1;
|
||||
gui.input_lmouse_pressed = function() {
|
||||
if (gui.selected)
|
||||
gui.selected.action();
|
||||
};
|
||||
|
||||
var bb = cmd(118, str, size, wrap);
|
||||
var w = bb.r*2;
|
||||
var h = bb.t*2;
|
||||
|
||||
//ui_text draws with an anchor on top left corner
|
||||
var p = pos.slice();
|
||||
p.x -= w * anchor.x;
|
||||
bb.r += (w*anchor.x);
|
||||
bb.l += (w*anchor.x);
|
||||
p.y += h * (1 - anchor.y);
|
||||
bb.t += h*(1-anchor.y);
|
||||
bb.b += h*(1-anchor.y);
|
||||
ui_text(str, p, size, color, wrap, cursor);
|
||||
|
||||
return bb;
|
||||
},
|
||||
|
||||
scissor(x,y,w,h) {
|
||||
cmd(140,x,y,w,h);
|
||||
},
|
||||
|
||||
scissor_win() { cmd(140,0,0,Window.width,Window.height); },
|
||||
|
||||
image(path,pos,color) {
|
||||
color ??= Color.black;
|
||||
var wh = cmd(64,path);
|
||||
gui_img(path,pos, [1.0,1.0], 0.0, false, [0.0,0.0], Color.white);
|
||||
return bbox.fromcwh([0,0], wh);
|
||||
},
|
||||
|
||||
newmg(img) {
|
||||
var def = {
|
||||
path: "",
|
||||
pos: [0,0],
|
||||
size:[0,0],
|
||||
frame: {
|
||||
x: 0,
|
||||
y: 0,
|
||||
w: 1,
|
||||
h: 1
|
||||
},
|
||||
angle: 0,
|
||||
anchor: [0,0],
|
||||
color: Color.white,
|
||||
}
|
||||
for (var i in def)
|
||||
img[i] ??= def[i];
|
||||
|
||||
gui_newmg
|
||||
},
|
||||
|
||||
input_lmouse_pressed() {
|
||||
if (GUI.selected)
|
||||
GUI.selected.action();
|
||||
},
|
||||
|
||||
input_s_pressed() {
|
||||
if (GUI.selected?.down) {
|
||||
GUI.selected.selected = false;
|
||||
GUI.selected = GUI.selected.down;
|
||||
GUI.selected.selected = true;
|
||||
}
|
||||
},
|
||||
|
||||
input_w_pressed() {
|
||||
if (GUI.selected?.up) {
|
||||
GUI.selected.selected = false;
|
||||
GUI.selected = GUI.selected.up;
|
||||
GUI.selected.selected = true;
|
||||
}
|
||||
},
|
||||
|
||||
input_enter_pressed() {
|
||||
if (GUI.selected) {
|
||||
GUI.selected.action();
|
||||
}
|
||||
gui.input_s_pressed = function() {
|
||||
if (gui.selected?.down) {
|
||||
gui.selected.selected = false;
|
||||
gui.selected = gui.selected.down;
|
||||
gui.selected.selected = true;
|
||||
}
|
||||
};
|
||||
|
||||
GUI.controls = {};
|
||||
GUI.controls.toString = function() { return "GUI controls"; };
|
||||
GUI.controls.update = function() { };
|
||||
gui.input_w_pressed = function() {
|
||||
if (gui.selected?.up) {
|
||||
gui.selected.selected = false;
|
||||
gui.selected = gui.selected.up;
|
||||
gui.selected.selected = true;
|
||||
}
|
||||
};
|
||||
|
||||
GUI.controls.set_mum = function(mum)
|
||||
gui.input_enter_pressed = function() {
|
||||
if (gui.selected) {
|
||||
gui.selected.action();
|
||||
}
|
||||
}
|
||||
|
||||
gui.controls = {};
|
||||
gui.controls.toString = function() { return "gui controls"; };
|
||||
gui.controls.update = function() { };
|
||||
|
||||
gui.controls.set_mum = function(mum)
|
||||
{
|
||||
mum.selected = true;
|
||||
|
||||
|
@ -103,22 +44,22 @@ GUI.controls.set_mum = function(mum)
|
|||
|
||||
this.selected = mum;
|
||||
}
|
||||
GUI.controls.check_bb = function(mum)
|
||||
gui.controls.check_bb = function(mum)
|
||||
{
|
||||
if (bbox.pointin(mum.bb, Mouse.screenpos()))
|
||||
GUI.controls.set_mum(mum);
|
||||
if (bbox.pointin(mum.bb, input.mouse.screenpos()))
|
||||
gui.controls.set_mum(mum);
|
||||
}
|
||||
GUI.controls.inputs = {};
|
||||
GUI.controls.inputs.fallthru = false;
|
||||
GUI.controls.inputs.mouse = {};
|
||||
GUI.controls.inputs.mouse.move = function(pos,dpos)
|
||||
gui.controls.inputs = {};
|
||||
gui.controls.inputs.fallthru = false;
|
||||
gui.controls.inputs.mouse = {};
|
||||
gui.controls.inputs.mouse.move = function(pos,dpos)
|
||||
{
|
||||
}
|
||||
GUI.controls.inputs.mouse.scroll = function(scroll)
|
||||
gui.controls.inputs.mouse.scroll = function(scroll)
|
||||
{
|
||||
}
|
||||
|
||||
GUI.controls.check_submit = function() {
|
||||
gui.controls.check_submit = function() {
|
||||
if (this.selected && this.selected.action)
|
||||
this.selected.action(this.selected);
|
||||
}
|
||||
|
@ -177,11 +118,9 @@ var Mum = {
|
|||
}
|
||||
|
||||
Mum.text = Mum.extend({
|
||||
draw(cursor, cnt) {
|
||||
cursor ??= [0,0];
|
||||
cnt ??= Mum;
|
||||
draw(cursor = [0,0], cnt = Mum) {
|
||||
if (this.hide) return;
|
||||
if (this.selectable) GUI.controls.check_bb(this);
|
||||
if (this.selectable) gui.controls.check_bb(this);
|
||||
this.caret ??= -1;
|
||||
|
||||
/* if (!this.bb)
|
||||
|
@ -197,8 +136,8 @@ Mum.text = Mum.extend({
|
|||
this.height = this.wh.y;
|
||||
var aa = [0,1].sub(params.anchor);
|
||||
var pos = cursor.add(params.wh.scale(aa)).add(params.offset);
|
||||
cmd(263, params.font);
|
||||
ui_text(params.str, pos, params.font_size, params.color, this.width, params.caret);
|
||||
// gui.font_set(params.font);
|
||||
render.text(params.str, pos, params.font_size, params.color, this.width, undefined, params.caret);
|
||||
},
|
||||
|
||||
update_bb(cursor) {
|
||||
|
@ -206,7 +145,7 @@ Mum.text = Mum.extend({
|
|||
},
|
||||
|
||||
calc_bb(cursor) {
|
||||
var bb = cmd(118,this.str, this.font_size, this.width);
|
||||
var bb = render.text_size(this.str, this.font_size, this.width);
|
||||
this.wh = bbox.towh(bb);
|
||||
var pos = cursor.add(this.wh.scale([0,1].sub(this.anchor))).add(this.offset);
|
||||
this.bb = bbox.move(bb,pos.add([this.wh.x/2,0]));
|
||||
|
@ -230,23 +169,20 @@ Mum.window = Mum.extend({
|
|||
this.wh = [this.width, this.height];
|
||||
this.bb = bbox.fromcwh([0,0], this.wh);
|
||||
},
|
||||
draw(cursor, cnt) {
|
||||
cursor ??= [0,0];
|
||||
cnt ??= Mum;
|
||||
draw(cursor = [0,0], cnt = Mum) {
|
||||
var p = cursor.sub(this.wh.scale(this.anchor)).add(this.padding);
|
||||
GUI.window(p,this.wh, this.color);
|
||||
render.window(p,this.wh, this.color);
|
||||
this.bb = bbox.blwh(p, this.wh);
|
||||
GUI.flush();
|
||||
GUI.scissor(p.x,p.y,this.wh.x,this.wh.y);
|
||||
gui.flush();
|
||||
this.max_width = this.width;
|
||||
if (this.selectable) GUI.controls.check_bb(this);
|
||||
if (this.selectable) gui.controls.check_bb(this);
|
||||
var pos = [this.bb.l, this.bb.t].add(this.padding);
|
||||
this.items.forEach(function(item) {
|
||||
if (item.hide) return;
|
||||
item.draw(pos.slice(),this);
|
||||
}, this);
|
||||
GUI.flush();
|
||||
GUI.scissor_win();
|
||||
gui.flush();
|
||||
gui.scissor_win();
|
||||
},
|
||||
});
|
||||
|
||||
|
@ -258,7 +194,7 @@ Mum.image = Mum.extend({
|
|||
return;
|
||||
}
|
||||
|
||||
var tex_wh = cmd(64, this.path);
|
||||
var tex_wh = texture.dimensions(this.path);
|
||||
this.wh = tex_wh.slice();
|
||||
if (this.width !== 0) this.wh.x = this.width;
|
||||
if (this.height !== 0) this.wh.y = this.height;
|
||||
|
@ -279,9 +215,7 @@ Mum.image = Mum.extend({
|
|||
});
|
||||
|
||||
Mum.column = Mum.extend({
|
||||
draw(cursor, cnt) {
|
||||
cursor ??= [0,0];
|
||||
cnt ??= Mum;
|
||||
draw(cursor = [0,0], cnt = Mum) {
|
||||
if (this.hide) return;
|
||||
cursor = cursor.add(this.offset);
|
||||
this.max_width = cnt.width;
|
||||
|
@ -295,16 +229,6 @@ Mum.column = Mum.extend({
|
|||
},
|
||||
});
|
||||
|
||||
GUI.window = function(pos, wh, color)
|
||||
{
|
||||
var p = pos.slice();
|
||||
p.x += wh.x/2;
|
||||
p.y += wh.y/2;
|
||||
render.box(p,wh,color);
|
||||
}
|
||||
|
||||
GUI.flush = function() { cmd(141); };
|
||||
|
||||
Mum.debug_colors = {
|
||||
bounds: Color.red.slice(),
|
||||
margin: Color.blue.slice(),
|
||||
|
@ -313,7 +237,4 @@ Mum.debug_colors = {
|
|||
|
||||
Object.values(Mum.debug_colors).forEach(function(v) { v.a = 100; });
|
||||
|
||||
return {
|
||||
GUI,
|
||||
Mum
|
||||
};
|
||||
return { Mum };
|
||||
|
|
146
scripts/input.js
146
scripts/input.js
|
@ -1,25 +1,25 @@
|
|||
var keycodes = {
|
||||
259: "back",
|
||||
258: "tab",
|
||||
257: "enter",
|
||||
1: "escape",
|
||||
input.keycodes = {
|
||||
32: "space",
|
||||
45: "minus",
|
||||
256: "escape",
|
||||
257: "enter",
|
||||
258: "tab",
|
||||
259: "backspace",
|
||||
260: "insert",
|
||||
261: "delete",
|
||||
262: "right",
|
||||
263: "left",
|
||||
264: "down",
|
||||
265: "up",
|
||||
266: "pgup",
|
||||
267: "pgdown",
|
||||
268: "home",
|
||||
269: "end",
|
||||
263: "left",
|
||||
265: "up",
|
||||
262: "right",
|
||||
265: "down",
|
||||
260: "insert",
|
||||
261: "delete",
|
||||
45: "minus",
|
||||
};
|
||||
|
||||
var codekeys = {};
|
||||
for (var code in keycodes)
|
||||
codekeys[keycodes[code]] = code;
|
||||
input.codekeys = {};
|
||||
for (var code in input.keycodes)
|
||||
input.codekeys[input.keycodes[code]] = code;
|
||||
|
||||
var mod = {
|
||||
shift: 0,
|
||||
|
@ -36,6 +36,8 @@ pressrep
|
|||
down
|
||||
*/
|
||||
|
||||
function keycode(name) { return charCodeAt(name); }
|
||||
|
||||
function keyname_extd(key)
|
||||
{
|
||||
if (key > 289 && key < 302) {
|
||||
|
@ -48,7 +50,7 @@ function keyname_extd(key)
|
|||
return `kp${num}`;
|
||||
}
|
||||
|
||||
if (keycodes[key]) return keycodes[key];
|
||||
if (input.keycodes[key]) return input.keycodes[key];
|
||||
if (key >= 32 && key <= 126) return String.fromCharCode(key).lc();
|
||||
|
||||
return undefined;
|
||||
|
@ -67,7 +69,6 @@ function modstr()
|
|||
|
||||
prosperon.keydown = function(key, repeat)
|
||||
{
|
||||
|
||||
prosperon.keys[key] = true;
|
||||
|
||||
if (key == 341 || key == 345)
|
||||
|
@ -93,6 +94,7 @@ prosperon.keyup = function(key)
|
|||
prosperon.keys[key] = false;
|
||||
if (key == 341 || key == 345)
|
||||
mod.ctrl = 0;
|
||||
|
||||
else if (key == 342 || key == 346)
|
||||
mod.alt = 0;
|
||||
else if (key == 343 || key == 347)
|
||||
|
@ -112,51 +114,51 @@ prosperon.droppedfile = function(path)
|
|||
|
||||
var mousepos = [0,0];
|
||||
|
||||
prosperon.textinput = function(){};
|
||||
prosperon.textinput = function(c){
|
||||
player[0].raw_input("char", "pressed", c);
|
||||
};
|
||||
prosperon.mousemove = function(pos, dx){
|
||||
mousepos = pos;
|
||||
player[0].mouse_input(modstr() + "move", pos, dx);
|
||||
player[0].mouse_input("move", pos, dx);
|
||||
};
|
||||
prosperon.mousescroll = function(dx){
|
||||
player[0].mouse_input(modstr() + "scroll", dx);
|
||||
};
|
||||
prosperon.mousedown = function(b){
|
||||
player[0].raw_input(modstr() + Mouse.button[b], "pressed");
|
||||
player[0].raw_input(modstr() + input.mouse.button[b], "pressed");
|
||||
};
|
||||
prosperon.mouseup = function(b){
|
||||
player[0].raw_input(modstr() + Mouse.button[b], "released");
|
||||
player[0].raw_input(input.mouse.button[b], "released");
|
||||
};
|
||||
|
||||
var Mouse = {
|
||||
screenpos() { return mousepos.slice(); },
|
||||
worldpos() { return Window.screen2world(mousepos); },
|
||||
disabled() { cmd(46, 1); },
|
||||
normal() { cmd(46, 0);},
|
||||
|
||||
mode(m) {
|
||||
if (Mouse.custom[m])
|
||||
cmd(97, Mouse.custom[m]);
|
||||
input.mouse = {};
|
||||
input.mouse.screenpos = function() { return mousepos.slice(); };
|
||||
input.mouse.worldpos = function() { return game.camera.view2world(mousepos); };
|
||||
input.mouse.disabled = function() { input.mouse_mode(1); };
|
||||
input.mouse.normal = function() { input.mouse_mode(0); };
|
||||
input.mouse.mode = function(m) {
|
||||
if (input.mouse.custom[m])
|
||||
input.cursor_img(input.mouse.custom[m]);
|
||||
else
|
||||
cmd(17, m);
|
||||
},
|
||||
input.mouse_cursor(m);
|
||||
};
|
||||
|
||||
set_custom_cursor(img, mode) {
|
||||
mode ??= Mouse.cursor.default;
|
||||
input.mouse.set_custom_cursor = function(img, mode = input.mouse.cursor.default) {
|
||||
if (!img)
|
||||
delete Mouse.custom[mode];
|
||||
delete input.mouse.custom[mode];
|
||||
else {
|
||||
cmd(97, img);
|
||||
Mouse.custom[mode] = img;
|
||||
input.cursor_img(img);
|
||||
input.mouse.custom[mode] = img;
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
button: { /* left, right, middle mouse */
|
||||
input.mouse.button = { /* left, right, middle mouse */
|
||||
0: "lm",
|
||||
1: "rm",
|
||||
2: "mm"
|
||||
},
|
||||
custom:[],
|
||||
cursor: {
|
||||
};
|
||||
input.mouse.custom = [];
|
||||
input.mouse.cursor = {
|
||||
default: 0,
|
||||
arrow: 1,
|
||||
ibeam: 2,
|
||||
|
@ -168,22 +170,20 @@ var Mouse = {
|
|||
nesw: 8,
|
||||
resize: 9,
|
||||
no: 10
|
||||
},
|
||||
};
|
||||
|
||||
Mouse.doc = {};
|
||||
Mouse.doc.pos = "The screen position of the mouse.";
|
||||
Mouse.doc.worldpos = "The position in the game world of the mouse.";
|
||||
Mouse.disabled.doc = "Set the mouse to hidden. This locks it to the game and hides it, but still provides movement and click events.";
|
||||
Mouse.normal.doc = "Set the mouse to show again after hiding.";
|
||||
input.mouse.doc = {};
|
||||
input.mouse.doc.pos = "The screen position of the mouse.";
|
||||
input.mouse.doc.worldpos = "The position in the game world of the mouse.";
|
||||
input.mouse.disabled.doc = "Set the mouse to hidden. This locks it to the game and hides it, but still provides movement and click events.";
|
||||
input.mouse.normal.doc = "Set the mouse to show again after hiding.";
|
||||
|
||||
var Keys = {
|
||||
down(code) {
|
||||
return prosperon.keys[code];
|
||||
},
|
||||
};
|
||||
|
||||
var input = {};
|
||||
input.keyboard = {};
|
||||
input.keyboard.down = function(code) {
|
||||
if (typeof code === 'number') return prosperon.keys[code];
|
||||
if (typeof code === 'string') return (prosperon.keys[code.uc().charCodeAt()] || prosperon.keys[code.lc().charCodeAt()]);
|
||||
return undefined;
|
||||
}
|
||||
|
||||
input.state2str = function(state) {
|
||||
if (typeof state === 'string') return state;
|
||||
|
@ -207,6 +207,14 @@ input.print_pawn_kbm = function(pawn) {
|
|||
return str;
|
||||
};
|
||||
|
||||
input.procdown = function()
|
||||
{
|
||||
for (var k of prosperon.keys) {
|
||||
if (!k) continue;
|
||||
player[0].raw_input(keyname_extd(k), "down");
|
||||
}
|
||||
}
|
||||
|
||||
input.print_md_kbm = function(pawn) {
|
||||
if (!('inputs' in pawn)) return;
|
||||
|
||||
|
@ -237,13 +245,6 @@ input.action = {
|
|||
actions: [],
|
||||
};
|
||||
|
||||
input.keyboard_show = function(show)
|
||||
{
|
||||
cmd(250,show);
|
||||
}
|
||||
|
||||
input.keyboard_shown = function() { return cmd(248); }
|
||||
|
||||
/* May be a human player; may be an AI player */
|
||||
var Player = {
|
||||
players: [],
|
||||
|
@ -319,12 +320,6 @@ var Player = {
|
|||
}
|
||||
},
|
||||
|
||||
do_uncontrol(pawn) {
|
||||
this.players.forEach(function(p) {
|
||||
p.pawns = p.pawns.filter(x => x !== pawn);
|
||||
});
|
||||
},
|
||||
|
||||
obj_controlled(obj) {
|
||||
for (var p in Player.players) {
|
||||
if (p.pawns.contains(obj))
|
||||
|
@ -359,6 +354,13 @@ var Player = {
|
|||
},
|
||||
};
|
||||
|
||||
input.do_uncontrol = function(pawn)
|
||||
{
|
||||
Player.players.forEach(function(p) {
|
||||
p.pawns = p.pawns.filter(x => x !== pawn);
|
||||
});
|
||||
}
|
||||
|
||||
for (var i = 0; i < 4; i++) {
|
||||
Player.create();
|
||||
}
|
||||
|
@ -372,11 +374,5 @@ Player.doc.players = "A list of current players.";
|
|||
var player = Player;
|
||||
|
||||
return {
|
||||
Mouse,
|
||||
Keys,
|
||||
input,
|
||||
Player,
|
||||
player,
|
||||
keycodes,
|
||||
codekeys
|
||||
player
|
||||
};
|
||||
|
|
|
@ -1,79 +1,57 @@
|
|||
/* On collisions, entities are sent a 'hit' object, which looks like this:
|
||||
var HIT = {
|
||||
normal: "The normal of the collision point.",
|
||||
hit: "The gameobject of the object that collided.",
|
||||
obj: "The gameobject of the object that collided.",
|
||||
sensor: "Boolean for if the colliding object was a sensor.",
|
||||
velocity: "Velocity of the contact.",
|
||||
pos: "Position in world space of the contact.",
|
||||
depth: "Depth of the contact.",
|
||||
};
|
||||
|
||||
*/
|
||||
|
||||
var physics = {
|
||||
physics.pos_query = function(pos, start = world, give = 10) {
|
||||
var ret;
|
||||
ret = physics.point_query_nearest(pos, 0);
|
||||
|
||||
if (ret)
|
||||
return ret.entity;
|
||||
|
||||
return game.all_objects(function(o) {
|
||||
var dist = Vector.length(o.pos.sub(pos));
|
||||
if (dist <= give) return o;
|
||||
});
|
||||
}
|
||||
|
||||
physics.box_point_query = function(box,points) {
|
||||
if (!box || !points) return [];
|
||||
var bbox = bbox.fromcwh(box.pos,box.wh);
|
||||
var inside = [];
|
||||
for (var i in points)
|
||||
if (bbox.pointin(bbox,points[i])) inside.push[i];
|
||||
return inside;
|
||||
}
|
||||
|
||||
Object.assign(physics, {
|
||||
dynamic: 0,
|
||||
kinematic: 1,
|
||||
static: 2,
|
||||
|
||||
pos_query(pos, give) {
|
||||
give ??= 25;
|
||||
return cmd(44, pos, give);
|
||||
},
|
||||
|
||||
/* Returns a list of body ids that a box collides with */
|
||||
box_query(box) { return cmd(52, box.pos, box.wh); },
|
||||
|
||||
box_point_query(box, points) {
|
||||
if (!box || !points)
|
||||
return [];
|
||||
|
||||
return cmd(86, box.pos, box.wh, points, points.length);
|
||||
},
|
||||
|
||||
shape_query(shape) { return cmd(80,shape); },
|
||||
|
||||
com(pos) {
|
||||
if (!Array.isArray(pos)) return [0,0];
|
||||
return pos.reduce((a,i) => a.add(i)).map(g => g/pos.length);
|
||||
},
|
||||
};
|
||||
});
|
||||
|
||||
physics.doc = {};
|
||||
physics.doc.pos_query = "Returns any object colliding with the given point.";
|
||||
physics.doc.box_query = "Returns an array of body ids that collide with a given box.";
|
||||
physics.doc.box_query = "Calls a given function on every shape object in the given bbox.";
|
||||
physics.doc.box_point_query = "Returns the subset of points from a given list that are inside a given box.";
|
||||
|
||||
physics.collision = {
|
||||
types: {},
|
||||
num: 32,
|
||||
set_collide(a, b, x) {
|
||||
this.types[a][b] = x;
|
||||
this.types[b][a] = x;
|
||||
this.sync();
|
||||
},
|
||||
sync() {
|
||||
for (var i = 0; i < this.num; i++)
|
||||
cmd(76,i,this.types[i]);
|
||||
},
|
||||
};
|
||||
|
||||
for (var i = 0; i < physics.collision.num; i++) {
|
||||
physics.collision.types[i] = [];
|
||||
for (var j = 0; j < physics.collision.num; j++)
|
||||
physics.collision.types[i][j] = false;
|
||||
};
|
||||
|
||||
physics.collision.sync();
|
||||
|
||||
physics.warp = {};
|
||||
physics.warp.gravity = function() { return cmd(253); }
|
||||
physics.warp.damp = function() { return cmd(254); }
|
||||
|
||||
physics.gravity = physics.warp.gravity();
|
||||
physics.gravity.mask = [true];
|
||||
physics.gravity = physics.make_gravity();
|
||||
physics.gravity.mask = ~1;
|
||||
physics.gravity.strength = 500;
|
||||
physics.damp = physics.warp.damp();
|
||||
physics.damp.mask = [true];
|
||||
physics.damp = physics.make_damp();
|
||||
physics.damp.mask = ~1;
|
||||
|
||||
return {
|
||||
physics
|
||||
|
|
|
@ -1,9 +1,3 @@
|
|||
var render = {
|
||||
normal() { cmd(67);},
|
||||
wireframe() { cmd(68); },
|
||||
pass() { },
|
||||
};
|
||||
|
||||
render.doc = {
|
||||
doc: "Functions for rendering modes.",
|
||||
normal: "Final render with all lighting.",
|
||||
|
@ -47,23 +41,16 @@ render.device = {
|
|||
render.device.doc = `Device resolutions given as [x,y,inches diagonal].`;
|
||||
|
||||
/* All draw in screen space */
|
||||
render.point = function(pos,size,color) {
|
||||
color ??= Color.blue;
|
||||
render.circle(pos,size,color);
|
||||
render.point = function(pos,size,color = Color.blue) {
|
||||
render.circle(pos,size,size,color);
|
||||
};
|
||||
|
||||
render.line = function(points, color, thickness) {
|
||||
thickness ??= 1;
|
||||
color ??= Color.white;
|
||||
cmd(83, points, color, thickness);
|
||||
var tmpline = render.line;
|
||||
render.line = function(points, color = Color.white, thickness = 1) {
|
||||
tmpline(points,color,thickness);
|
||||
};
|
||||
|
||||
render.poly = function(points, color) { cmd_points(0,points,color); };
|
||||
|
||||
render.circle = function(pos, radius, color) { cmd(115, pos, radius, color); };
|
||||
|
||||
render.cross = function(pos, size, color) {
|
||||
color ??= Color.red;
|
||||
render.cross = function(pos, size, color = Color.red) {
|
||||
var a = [
|
||||
pos.add([0,size]),
|
||||
pos.add([0,-size])
|
||||
|
@ -77,11 +64,7 @@ render.cross = function(pos, size, color) {
|
|||
render.line(b,color);
|
||||
};
|
||||
|
||||
render.arrow = function(start, end, color, wingspan, wingangle) {
|
||||
color ??= Color.red;
|
||||
wingspan ??= 4;
|
||||
wingangle ??=10;
|
||||
|
||||
render.arrow = function(start, end, color = Color.red, wingspan = 4, wingangle = 10) {
|
||||
var dir = end.sub(start).normalized();
|
||||
var wing1 = [
|
||||
Vector.rotate(dir, wingangle).scale(wingspan).add(end),
|
||||
|
@ -96,17 +79,65 @@ render.arrow = function(start, end, color, wingspan, wingangle) {
|
|||
render.line(wing2,color);
|
||||
};
|
||||
|
||||
render.coordinate = function(pos, size, color) {
|
||||
render.text(JSON.stringify(pos.map(p=>Math.round(p))), pos, size, color);
|
||||
render.point(pos, 2, color);
|
||||
}
|
||||
|
||||
render.boundingbox = function(bb, color = Color.white) {
|
||||
render.poly(bbox.topoints(bb), color);
|
||||
}
|
||||
|
||||
render.rectangle = function(lowerleft, upperright, color) {
|
||||
var pos = lowerleft.add(upperright).map(x=>x/2);
|
||||
var wh = [upperright.x-lowerleft.x,upperright.y-lowerleft.y];
|
||||
render.box(pos,wh,color);
|
||||
var points = [lowerleft, lowerleft.add([upperright.x-lowerleft.x,0]), upperright, lowerleft.add([0,upperright.y-lowerleft.y])];
|
||||
render.poly(points, color);
|
||||
};
|
||||
|
||||
render.box = function(pos, wh, color) {
|
||||
color ??= Color.white;
|
||||
cmd(53, pos, wh, color);
|
||||
render.box = function(pos, wh, color = Color.white) {
|
||||
var lower = pos.sub(wh.scale(0.5));
|
||||
var upper = pos.add(wh.scale(0.5));
|
||||
render.rectangle(lower,upper,color);
|
||||
};
|
||||
|
||||
render.window = function(pos, wh, color) {
|
||||
var p = pos.slice();
|
||||
p = p.add(wh.scale(0.5));
|
||||
render.box(p,wh,color);
|
||||
};
|
||||
|
||||
render.text = function(str, pos, size = 1, color = Color.white, wrap = -1, anchor = [0,1], cursor = -1) {
|
||||
var bb = render.text_size(str, size, wrap);
|
||||
var w = bb.r*2;
|
||||
var h = bb.t*2;
|
||||
|
||||
//render.text draws with an anchor on top left corner
|
||||
var p = pos.slice();
|
||||
p.x -= w * anchor.x;
|
||||
bb.r += (w*anchor.x);
|
||||
bb.l += (w*anchor.x);
|
||||
p.y += h * (1 - anchor.y);
|
||||
bb.t += h*(1-anchor.y);
|
||||
bb.b += h*(1-anchor.y);
|
||||
gui.text(str, p, size, color, wrap, cursor);
|
||||
|
||||
return bb;
|
||||
};
|
||||
|
||||
render.image = function(tex, pos, rotation = 0, color = Color.white, dimensions = [tex.width, tex.height]) {
|
||||
var scale = [dimensions.x/tex.width, dimensions.y/tex.height];
|
||||
gui.img(tex,pos, scale, 0.0, false, [0.0,0.0], color);
|
||||
return bbox.fromcwh([0,0], [tex.width,tex.height]);
|
||||
}
|
||||
|
||||
render.fontcache = {};
|
||||
render.set_font = function(path, size) {
|
||||
var fontstr = `${path}-${size}`;
|
||||
if (!render.fontcache[fontstr]) render.fontcache[fontstr] = os.make_font(path, size);
|
||||
|
||||
gui.font_set(render.fontcache[fontstr]);
|
||||
render.font = render.fontcache[fontstr];
|
||||
}
|
||||
|
||||
render.doc = "Draw shapes in screen space.";
|
||||
render.circle.doc = "Draw a circle at pos, with a given radius and color.";
|
||||
render.cross.doc = "Draw a cross centered at pos, with arm length size.";
|
||||
|
|
132
scripts/sound.js
132
scripts/sound.js
|
@ -1,45 +1,75 @@
|
|||
var audio = {};
|
||||
/* This file runs after the audio system is initiated */
|
||||
|
||||
var sound_pref = ['wav', 'flac', 'mp3', 'qoa'];
|
||||
var cries = {};
|
||||
|
||||
audio.sound = {
|
||||
bus: {},
|
||||
samplerate() { return cmd(198); },
|
||||
sounds: [], /* array of loaded sound files */
|
||||
play(file, bus) {
|
||||
Object.readonly(audio, 'samplerate');
|
||||
Object.readonly(audio, 'channels');
|
||||
Object.readonly(audio, 'buffer_frames');
|
||||
|
||||
audio.play = function(file,bus = audio.bus.master) {
|
||||
file = Resources.find_sound(file);
|
||||
if (!file) {
|
||||
console.error(`Cannot play sound ${file}: does not exist.`);
|
||||
return;
|
||||
}
|
||||
var src = audio.dsp.source(file);
|
||||
bus ??= audio.sound.bus.master;
|
||||
src.plugin(bus);
|
||||
src.guid = prosperon.guid();
|
||||
return src;
|
||||
},
|
||||
}
|
||||
audio.bus = {};
|
||||
audio.bus.master = dspsound.master();
|
||||
audio.dsp = {};
|
||||
audio.dsp = dspsound;
|
||||
|
||||
doc: {
|
||||
play: "Play the given file once.",
|
||||
volume: "Set the volume. 0 is no sound and 100 is loudest."
|
||||
},
|
||||
};
|
||||
audio.cry = function(file)
|
||||
{
|
||||
var player = audio.play(file);
|
||||
if (!player) return;
|
||||
|
||||
audio.dsp = {
|
||||
mix(to) {
|
||||
var n = cmd(181);
|
||||
player.guid = prosperon.guid();
|
||||
cries[player.guid] = player;
|
||||
player.ended = function() { delete cries[player.guid]; player = undefined; }
|
||||
return player.ended;
|
||||
}
|
||||
|
||||
var killer = Register.appupdate.register(function() {
|
||||
for (var i in cries) {
|
||||
var cry = cries[i];
|
||||
if (!cry.ended) continue;
|
||||
if (cry.frame < cry.lastframe || cry.frame === cry.frames())
|
||||
cry.ended();
|
||||
cry.lastframe = cry.frame;
|
||||
}
|
||||
});
|
||||
|
||||
var song;
|
||||
|
||||
audio.music = function(file, fade = 0) {
|
||||
if (!fade) {
|
||||
song = audio.play(file);
|
||||
song.loop = true;
|
||||
return;
|
||||
}
|
||||
|
||||
var temp = audio.play(file);
|
||||
if (!temp) return;
|
||||
|
||||
temp.volume = 0;
|
||||
var temp2 = song;
|
||||
tween(temp, 'volume', 1, fade);
|
||||
tween(temp2, 'volume', 0, fade);
|
||||
song = temp;
|
||||
song.loop = true;
|
||||
}
|
||||
|
||||
audio.dsp.mix = function(to) {
|
||||
var n = audio.dsp.mix();
|
||||
if (to) n.plugin(to);
|
||||
return n;
|
||||
},
|
||||
source(path) {
|
||||
return cmd(182,path);
|
||||
},
|
||||
delay(secs,decay) {
|
||||
return cmd(185, secs, decay);
|
||||
},
|
||||
fwd_delay(secs, decay) {
|
||||
return cmd(207,secs,decay);
|
||||
},
|
||||
allpass(secs, decay) {
|
||||
};
|
||||
|
||||
audio.dsp.allpass = function(secs, decay) {
|
||||
var composite = {};
|
||||
var fwd = audio.dsp.fwd_delay(secs,-decay);
|
||||
var fbk = audio.dsp.delay(secs,decay);
|
||||
|
@ -48,44 +78,7 @@ audio.dsp = {
|
|||
composite.unplug = dsp_node.unplug.bind(fbk);
|
||||
fwd.plugin(fbk);
|
||||
return composite;
|
||||
},
|
||||
lpf(f) {
|
||||
return cmd(186,f);
|
||||
},
|
||||
hpf(f) {
|
||||
return cmd(187,f);
|
||||
},
|
||||
mod(path) {
|
||||
return cmd(188,path);
|
||||
},
|
||||
midi(midi,sf) {
|
||||
return cmd(206,midi,sf);
|
||||
},
|
||||
crush(rate, depth) {
|
||||
return cmd(189,rate,depth);
|
||||
},
|
||||
compressor() {
|
||||
return cmd(190);
|
||||
},
|
||||
limiter(ceil) {
|
||||
return cmd(191,ceil);
|
||||
},
|
||||
noise_gate(floor) {
|
||||
return cmd(192,floor);
|
||||
},
|
||||
pitchshift(octaves) {
|
||||
return cmd(200,octaves);
|
||||
},
|
||||
noise() {
|
||||
return cmd(203);
|
||||
},
|
||||
pink() {
|
||||
return cmd(204);
|
||||
},
|
||||
red() {
|
||||
return cmd(205);
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
audio.dsp.doc = {
|
||||
delay: "Delays the input by secs, multiplied by decay",
|
||||
|
@ -103,18 +96,15 @@ audio.dsp.doc = {
|
|||
red: "Red noise"
|
||||
};
|
||||
|
||||
Object.mixin(cmd(180).__proto__, {
|
||||
Object.mixin(audio.bus.master.__proto__, {
|
||||
get db() { return 20*Math.log10(Math.abs(this.volume)); },
|
||||
set db(x) { x = Math.clamp(x,-100,0); this.volume = Math.pow(10, x/20); },
|
||||
get volume() { return this.gain; },
|
||||
set volume(x) { this.gain = x; },
|
||||
});
|
||||
|
||||
audio.sound.bus.master = cmd(180);
|
||||
|
||||
/*Object.mixin(audio.dsp.source().__proto__, {
|
||||
frames() { return cmd(197,this); },
|
||||
length() { return this.frames()/sound.samplerate(); },
|
||||
length() { return this.frames()/audio.samplerate(); },
|
||||
time() { return this.frame/sound.samplerate(); },
|
||||
pct() { return this.time()/this.length(); },
|
||||
});
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
var Spline = {};
|
||||
Spline.sample_angle = function(type, points, angle) {
|
||||
return spline_cmd(0, type, points[0].length, points, angle);
|
||||
if (type === 0) return spline.catmull(points, angle);
|
||||
else if (type === 1) return spline.bezier(points,angle);
|
||||
return undefined;
|
||||
}
|
||||
|
||||
Spline.bezier_loop = function(cp)
|
||||
|
|
2
scripts/sprite.jso
Normal file
2
scripts/sprite.jso
Normal file
|
@ -0,0 +1,2 @@
|
|||
this.phys = physics.static;
|
||||
this.add_component(component.sprite);
|
234
scripts/std.js
234
scripts/std.js
|
@ -6,17 +6,16 @@ if (os.sys() === 'windows')
|
|||
else
|
||||
os.user = os.env("USER");
|
||||
|
||||
|
||||
var appy = {};
|
||||
appy.inputs = {};
|
||||
if (os.sys() === 'macos') {
|
||||
appy.inputs['S-q'] = function() { Game.quit(); };
|
||||
appy.inputs['S-q'] = os.quit;
|
||||
appy.inputs['S-h'] = function() { };
|
||||
appy.inputs['S-g'] = os.gc;
|
||||
}
|
||||
|
||||
player[0].control(appy);
|
||||
|
||||
var steam = {};
|
||||
steam.appid = 480;
|
||||
steam.userid = 8437843;
|
||||
|
||||
|
@ -35,33 +34,18 @@ var otherpath = {
|
|||
}
|
||||
|
||||
os.prefpath = function() {
|
||||
return otherpath[os.sys()] + "/" + (Game.title ? Game.title : "Untitled Prosperon Game");
|
||||
return otherpath[os.sys()] + "/" + (game.title ? game.title : "Untitled Prosperon Game");
|
||||
}
|
||||
|
||||
os.openurl = function(url) {
|
||||
if (os.sys() === 'windows')
|
||||
os.system(`start ${url}`);
|
||||
else
|
||||
os.system(`open ${url}`);
|
||||
}
|
||||
|
||||
var projectfile = ".prosperon/project.json";
|
||||
|
||||
var Resources = {};
|
||||
Resources.images = ["png", "gif", "jpg", "jpeg"];
|
||||
Resources.sounds = ["wav", 'flac', 'mp3', "qoa"];
|
||||
Resources.scripts = "js";
|
||||
Resources.is_image = function(path) {
|
||||
var ext = path.ext();
|
||||
return Resources.images.any(x => x === ext);
|
||||
}
|
||||
|
||||
function find_ext(file, ext)
|
||||
{
|
||||
if (io.exists(file)) return file;
|
||||
for (var e of ext) {
|
||||
var nf = `${file}.${e}`;
|
||||
if (io.exists(nf)) return nf;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
Resources.find_image = function(file) { return find_ext(file,Resources.images); }
|
||||
Resources.find_sound = function(file) { return find_ext(file,Resources.sounds); }
|
||||
|
||||
Resources.is_sound = function(path) {
|
||||
var ext = path.ext();
|
||||
return Resources.sounds.any(x => x === ext);
|
||||
|
@ -81,121 +65,10 @@ Resources.is_path = function(str)
|
|||
}
|
||||
|
||||
Resources.texture = {};
|
||||
Resources.texture.dimensions = function(path) { return cmd(64,path); }
|
||||
Resources.texture.dimensions = function(path) { texture.dimensions(path); }
|
||||
|
||||
Resources.gif = {};
|
||||
Resources.gif.frames = function(path) { return cmd(139,path); }
|
||||
|
||||
Resources.replpath = function(str, path)
|
||||
{
|
||||
if (str[0] === "/")
|
||||
return str.rm(0);
|
||||
|
||||
if (str[0] === "@")
|
||||
return os.prefpath() + "/" + str.rm(0);
|
||||
|
||||
if (!path) return str;
|
||||
|
||||
var stem = path.dir();
|
||||
while (stem) {
|
||||
var tr = stem + "/" +str;
|
||||
if (io.exists(tr)) return tr;
|
||||
stem = stem.updir();
|
||||
}
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
Resources.replstrs = function(path)
|
||||
{
|
||||
var script = io.slurp(path);
|
||||
var regexp = /"[^"\s]*?\.[^"\s]+?"/g;
|
||||
var stem = path.dir();
|
||||
|
||||
script = script.replace(regexp,function(str) {
|
||||
var newstr = Resources.replpath(str.trimchr('"'), path);
|
||||
return `"${newstr}"`;
|
||||
});
|
||||
|
||||
return script;
|
||||
}
|
||||
|
||||
var console = {
|
||||
print(msg, lvl) {
|
||||
var lg;
|
||||
if (typeof msg === 'object') {
|
||||
lg = JSON.stringify(msg, null, 2);
|
||||
} else {
|
||||
lg = msg;
|
||||
}
|
||||
|
||||
var stack = (new Error()).stack;
|
||||
var n = stack.next('\n',0)+1;
|
||||
n = stack.next('\n', n)+1;
|
||||
var nnn = stack.slice(n);
|
||||
var fmatch = nnn.match(/\(.*\:/);
|
||||
var file = fmatch ? fmatch[0].shift(1).shift(-1) : "nofile";
|
||||
var lmatch = nnn.match(/\:\d*\)/);
|
||||
var line = lmatch ? lmatch[0].shift(1).shift(-1) : "0";
|
||||
|
||||
yughlog(lvl, lg, file, line);
|
||||
},
|
||||
|
||||
spam(msg) {
|
||||
this.print(msg,0);
|
||||
},
|
||||
|
||||
/* this always prints to stdout */
|
||||
debug(msg) {
|
||||
this.print(msg,1);
|
||||
},
|
||||
|
||||
info(msg) {
|
||||
this.print(msg, 2);
|
||||
},
|
||||
|
||||
warn(msg) {
|
||||
this.print(msg, 3);
|
||||
},
|
||||
|
||||
error(msg) {
|
||||
this.print(msg + "\n" + console.stackstr(3), 4);
|
||||
},
|
||||
|
||||
panic(msg) {
|
||||
this.print(msg + "\n" + console.stackstr(1), 5);
|
||||
},
|
||||
|
||||
log(msg) {
|
||||
if (typeof msg === 'object') msg = JSON.stringify(msg,null,1);
|
||||
cmd(91, msg + '\n');
|
||||
},
|
||||
stackstr(skip=0) {
|
||||
var err = new Error();
|
||||
var stack = err.stack.split('\n');
|
||||
return stack.slice(skip,stack.length-10).join('\n');
|
||||
},
|
||||
|
||||
stack(skip = 0) {
|
||||
console.log(stackstr(skip+1));
|
||||
},
|
||||
};
|
||||
|
||||
var say = console.log;
|
||||
say.doc = "Print to std out with an appended newline.";
|
||||
|
||||
console.doc = {
|
||||
level: "Set level to output logging to console.",
|
||||
info: "Output info level message.",
|
||||
warn: "Output warn level message.",
|
||||
error: "Output error level message, and print stacktrace.",
|
||||
critical: "Output critical level message, and exit game immediately.",
|
||||
write: "Write raw text to console.",
|
||||
say: "Write raw text to console, plus a newline.",
|
||||
stack: "Output a stacktrace to console.",
|
||||
console: "Output directly to in game console.",
|
||||
clear: "Clear console."
|
||||
};
|
||||
Resources.gif.frames = function(path) { return render.gif_frames(path); }
|
||||
|
||||
/*
|
||||
io path rules. Starts with, meaning:
|
||||
|
@ -265,12 +138,6 @@ io.mixin({
|
|||
paths = paths.filter(function(str) { return str.ext() === ext; });
|
||||
return paths;
|
||||
},
|
||||
compile(script) {
|
||||
return cmd(260, script);
|
||||
},
|
||||
run_bytecode(byte_file) {
|
||||
return cmd(261, byte_file);
|
||||
},
|
||||
|
||||
glob(pat) {
|
||||
var paths = io.ls('.');
|
||||
|
@ -311,10 +178,9 @@ Cmdline.register_cmd = function(flag, fn, doc) {
|
|||
});
|
||||
};
|
||||
|
||||
Cmdline.register_order = function(order, fn, doc, usage) {
|
||||
Cmdline.register_order = function(order, fn, doc, usage = "") {
|
||||
Cmdline.orders[order] = fn;
|
||||
fn.doc = doc;
|
||||
usage ??= "";
|
||||
fn.usage = `${order} ${usage}`;
|
||||
}
|
||||
|
||||
|
@ -324,24 +190,31 @@ Cmdline.register_order("edit", function() {
|
|||
return;
|
||||
}
|
||||
|
||||
Game.engine_start(function() {
|
||||
window.size = [1280, 720];
|
||||
window.mode = window.modetypes.full;
|
||||
sim.pause();
|
||||
|
||||
game.engine_start(function() {
|
||||
global.mixin("scripts/editor.js");
|
||||
use("editorconfig.js");
|
||||
use("config.js");
|
||||
render.set_font("fonts/c64.ttf", 8);
|
||||
editor.enter_editor();
|
||||
});
|
||||
}, "Edit the project in this folder. Give it the name of an UR to edit that specific object.", "?UR?");
|
||||
|
||||
Cmdline.register_order("init", function() {
|
||||
say('top of init');
|
||||
if (io.exists(projectfile)) {
|
||||
say("Already a game here.");
|
||||
return;
|
||||
}
|
||||
|
||||
say('top of ls');
|
||||
if (!(io.ls().length === 0)) {
|
||||
say("Directory is not empty. Make an empty one and init there.");
|
||||
return;
|
||||
}
|
||||
|
||||
say('top of mkdir');
|
||||
io.mkdir(".prosperon");
|
||||
var project = {};
|
||||
project.version = prosperon.version;
|
||||
|
@ -358,7 +231,7 @@ Cmdline.register_order("play", function(argv) {
|
|||
if (argv[0])
|
||||
io.chdir(argv[0]);
|
||||
|
||||
Game.loadurs();
|
||||
game.loadurs();
|
||||
|
||||
if (!io.exists(projectfile)) {
|
||||
say("No game to play. Try making one with 'prosperon init'.");
|
||||
|
@ -366,18 +239,19 @@ Cmdline.register_order("play", function(argv) {
|
|||
}
|
||||
|
||||
var project = json.decode(io.slurp(projectfile));
|
||||
Game.title = project.title;
|
||||
Window.mode = Window.modetypes.expand;
|
||||
game.title = project.title;
|
||||
window.mode = window.modetypes.expand;
|
||||
global.mixin("config.js");
|
||||
if (project.title) Window.title = project.title;
|
||||
if (project.title) window.title = project.title;
|
||||
|
||||
if (Window.rendersize.equal([0,0])) Window.rendersize = Window.size;
|
||||
console.info(`Starting game with window size ${Window.size} and render ${Window.rendersize}.`);
|
||||
if (window.rendersize.equal([0,0])) window.rendersize = window.size;
|
||||
console.info(`Starting game with window size ${window.size} and render ${window.rendersize}.`);
|
||||
|
||||
Game.engine_start(function() {
|
||||
global.mixin("scripts/sound.js");
|
||||
global.game = actor.spawn("game.js");
|
||||
if (project.icon) Window.icon(project.icon);
|
||||
game.engine_start(function() {
|
||||
render.set_font("fonts/c64.ttf", 8);
|
||||
global.app = actor.spawn("game.js");
|
||||
if (project.icon) window.set_icon(game.texture(project.icon));
|
||||
game.camera = world.spawn("scripts/camera2d");
|
||||
});
|
||||
}, "Play the game present in this folder.");
|
||||
|
||||
|
@ -393,7 +267,7 @@ Cmdline.register_order("pack", function(str) {
|
|||
|
||||
say(`Packing into ${packname}`);
|
||||
|
||||
cmd(124, packname);
|
||||
// io.pack_engine(packname);
|
||||
io.chmod(packname, 666);
|
||||
}, "Pack the game into the given name.", "NAME");
|
||||
|
||||
|
@ -414,7 +288,7 @@ Cmdline.register_order("qoa", function(argv) {
|
|||
for (var file of argv) {
|
||||
if (!sounds.includes(file.ext())) continue;
|
||||
say(`converting ${file}`);
|
||||
cmd(262,file);
|
||||
io.save_qoa(file);
|
||||
}
|
||||
}, "Convert file(s) to qoa.");
|
||||
|
||||
|
@ -433,7 +307,7 @@ Cmdline.register_order("about", function(argv) {
|
|||
}, "Get information about this game.");
|
||||
|
||||
Cmdline.register_order("ur", function(argv) {
|
||||
Game.loadurs();
|
||||
game.loadurs();
|
||||
for (var i of ur._list.sort()) say(i);
|
||||
}, "Get information about the ur types in your game.");
|
||||
|
||||
|
@ -500,23 +374,16 @@ Cmdline.register_order("api", function(obj) {
|
|||
return;
|
||||
}
|
||||
|
||||
load("scripts/editor.js");
|
||||
var api = Debug.api.print_doc(obj[0]);
|
||||
use("scripts/editor.js");
|
||||
var api = debug.api.print_doc(obj[0]);
|
||||
if (!api)
|
||||
return;
|
||||
|
||||
say(api);
|
||||
}, "Print the API for an object as markdown. Give it a file to save the output to.", "OBJECT");
|
||||
|
||||
Cmdline.register_order("compile", function(argv) {
|
||||
for (var file of argv) {
|
||||
var comp = io.compile(file);
|
||||
io.slurpwrite(file + "c", comp);
|
||||
}
|
||||
}, "Compile one or more provided files into bytecode.", "FILE ...");
|
||||
|
||||
Cmdline.register_order("input", function(pawn) {
|
||||
load("scripts/editor.js");
|
||||
use("scripts/editor.js");
|
||||
say(`## Input for ${pawn}`);
|
||||
eval(`say(input.print_md_kbm(${pawn}));`);
|
||||
}, "Print input documentation for a given object as markdown. Give it a file to save the output to", "OBJECT ?FILE?");
|
||||
|
@ -528,17 +395,7 @@ Cmdline.register_order("run", function(script) {
|
|||
return;
|
||||
}
|
||||
|
||||
if (io.exists(script))
|
||||
try {
|
||||
if (script.endswith("c"))
|
||||
cmd(261, script);
|
||||
else
|
||||
load(script);
|
||||
} catch(e) { }
|
||||
else {
|
||||
var ret = eval(script);
|
||||
if (ret) say(ret);
|
||||
}
|
||||
say(use(script));
|
||||
}, "Run a given script. SCRIPT can be the script itself, or a file containing the script", "SCRIPT");
|
||||
|
||||
Cmdline.orders.script = Cmdline.orders.run;
|
||||
|
@ -592,21 +449,24 @@ function cmd_args(cmdargs)
|
|||
}
|
||||
|
||||
Cmdline.orders[cmds[0]](cmds.slice(1));
|
||||
if (!game.startengine)
|
||||
os.exit(0);
|
||||
}
|
||||
|
||||
|
||||
Cmdline.register_order("clean", function(argv) {
|
||||
say("Cleaning not implemented.");
|
||||
}, "Clean up a given object file.", "JSON ...");
|
||||
|
||||
Cmdline.register_order("test", function(argv) {
|
||||
use("scripts/test.js");
|
||||
}, "Run tests.");
|
||||
|
||||
Cmdline.register_cmd("l", function(n) {
|
||||
console.level = n;
|
||||
}, "Set log level.");
|
||||
|
||||
return {
|
||||
console,
|
||||
Resources,
|
||||
say,
|
||||
Cmdline,
|
||||
cmd_args,
|
||||
steam
|
||||
|
|
38
scripts/test.js
Normal file
38
scripts/test.js
Normal file
|
@ -0,0 +1,38 @@
|
|||
/* Tests for prosperon */
|
||||
|
||||
var tests = [];
|
||||
var pass = 0;
|
||||
var fail = 0;
|
||||
var failed = [];
|
||||
|
||||
var test = function(name, fn)
|
||||
{
|
||||
var func = function() {
|
||||
print(`${pass+fail+1}/${tests.length}: ${name} ... `);
|
||||
var p = profile.now();
|
||||
var b = fn();
|
||||
p = profile.lap(p);
|
||||
print(`${b ? "pass" : "fail"} [${p}]`);
|
||||
return b;
|
||||
};
|
||||
func.testname = name;
|
||||
tests.push(func);
|
||||
}
|
||||
|
||||
say(`Testing ${tests.length} tests.`);
|
||||
for (var t of tests) {
|
||||
if (t())
|
||||
pass++;
|
||||
else {
|
||||
fail++;
|
||||
failed.push(t.testname);
|
||||
}
|
||||
print("\n");
|
||||
}
|
||||
|
||||
say(`Passed ${pass} tests and failed ${fail} [${(pass*100/(pass+fail)).toPrecision(4)}%].`);
|
||||
say(`Failed tests are:`);
|
||||
for (var f of failed)
|
||||
say(f);
|
||||
|
||||
os.quit();
|
|
@ -103,9 +103,24 @@ Ease.elastic = {
|
|||
Ease.elastic.c4 = 2*Math.PI/3;
|
||||
Ease.elastic.c5 = 2*Math.PI / 4.5;
|
||||
|
||||
var tween = function(obj, val, to, time)
|
||||
{
|
||||
var start = profile.secs(profile.now());
|
||||
var startval = obj[val];
|
||||
var update = function(dt) {
|
||||
var elapsed = profile.secs(profile.now()) - start;
|
||||
obj[val] = startval.lerp(to, elapsed/time);
|
||||
if (elapsed >= time) {
|
||||
obj[val] = to;
|
||||
stop();
|
||||
}
|
||||
};
|
||||
var stop = Register.update.register(update);
|
||||
}
|
||||
|
||||
var Tween = {
|
||||
default: {
|
||||
loop: "restart",
|
||||
loop: "hold",
|
||||
/*
|
||||
loop types
|
||||
none: when done, return to first value
|
||||
|
@ -197,4 +212,4 @@ var Tween = {
|
|||
|
||||
Tween.make = Tween.start;
|
||||
|
||||
return {Tween, Ease};
|
||||
return {Tween, Ease, tween};
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
#include "2dphysics.h"
|
||||
|
||||
#include "debug.h"
|
||||
#include "gameobject.h"
|
||||
#include <string.h>
|
||||
|
||||
|
@ -29,13 +28,13 @@ struct rgba dynamic_color = {255,70,46,255};
|
|||
struct rgba kinematic_color = {255, 194, 64, 255};
|
||||
struct rgba static_color = {73,209,80,255};
|
||||
|
||||
static JSValue fns[100];
|
||||
static JSValue hits[100];
|
||||
static int cb_idx = 0;
|
||||
|
||||
static const unsigned char col_alpha = 40;
|
||||
static const float sensor_seg = 10;
|
||||
|
||||
unsigned int category_masks[32];
|
||||
|
||||
void set_cat_mask(int cat, unsigned int mask) { category_masks[cat] = mask; }
|
||||
|
||||
cpTransform m3_to_cpt(HMM_Mat3 m)
|
||||
{
|
||||
cpTransform t;
|
||||
|
@ -49,13 +48,7 @@ cpTransform m3_to_cpt(HMM_Mat3 m)
|
|||
}
|
||||
|
||||
cpShape *phys2d_query_pos(cpVect pos) {
|
||||
cpShapeFilter filter;
|
||||
filter.group = CP_NO_GROUP;
|
||||
filter.mask = CP_ALL_CATEGORIES;
|
||||
filter.categories = CP_ALL_CATEGORIES;
|
||||
cpShape *find = cpSpacePointQueryNearest(space, pos, 0.f, filter, NULL);
|
||||
|
||||
return find;
|
||||
return cpSpacePointQueryNearest(space, pos, 0.f, CP_SHAPE_FILTER_ALL, NULL);
|
||||
}
|
||||
|
||||
|
||||
|
@ -70,17 +63,11 @@ void bbhit(cpShape *shape, int *data)
|
|||
qhit++;
|
||||
}
|
||||
|
||||
static cpShapeFilter ff = {
|
||||
.group = CP_NO_GROUP,
|
||||
.mask = CP_ALL_CATEGORIES,
|
||||
.categories = CP_ALL_CATEGORIES,
|
||||
};
|
||||
|
||||
int query_point(HMM_Vec2 pos)
|
||||
{
|
||||
qhit = 0;
|
||||
// cpSpacePointQuery(space, pos.cp, 0, filter, qpoint, &qhit);
|
||||
cpSpaceBBQuery(space, cpBBNewForCircle(pos.cp, 2), ff, bbhit, &qhit);
|
||||
cpSpaceBBQuery(space, cpBBNewForCircle(pos.cp, 2), CP_SHAPE_FILTER_ALL, bbhit, &qhit);
|
||||
return qhit;
|
||||
}
|
||||
|
||||
|
@ -104,65 +91,6 @@ gameobject **clean_ids(gameobject **ids)
|
|||
return ids;
|
||||
}
|
||||
|
||||
typedef struct querybox {
|
||||
cpBB bb;
|
||||
gameobject **ids;
|
||||
} querybox;
|
||||
|
||||
void querylist(cpShape *shape, cpContactPointSet *points, querybox *qb) {
|
||||
arrput(qb->ids, shape2go(shape));
|
||||
}
|
||||
|
||||
void querylistbodies(cpBody *body, querybox *qb) {
|
||||
if (cpBBContainsVect(qb->bb, cpBodyGetPosition(body)))
|
||||
arrput(qb->ids,body2go(body));
|
||||
}
|
||||
|
||||
/* Return all points from a list of points in the given boundingbox */
|
||||
int *phys2d_query_box_points(HMM_Vec2 pos, HMM_Vec2 wh, HMM_Vec2 *points, int n) {
|
||||
cpBB bbox;
|
||||
bbox = cpBBExpand(bbox, cpvadd(pos.cp, cpvmult(wh.cp,0.5)));
|
||||
bbox = cpBBExpand(bbox, cpvsub(pos.cp, cpvmult(wh.cp,0.5)));
|
||||
int *hits = NULL;
|
||||
|
||||
for (int i = 0; i < n; i++)
|
||||
if (cpBBContainsVect(bbox, points[i].cp))
|
||||
arrpush(hits, i);
|
||||
|
||||
return hits;
|
||||
}
|
||||
|
||||
/* Return all gameobjects within the given box */
|
||||
gameobject **phys2d_query_box(HMM_Vec2 pos, HMM_Vec2 wh) {
|
||||
cpShape *box = cpBoxShapeNew(NULL, wh.x, wh.y, 0.f);
|
||||
cpTransform T = {0};
|
||||
T.a = 1;
|
||||
T.d = 1;
|
||||
T.tx = pos.x;
|
||||
T.ty = pos.y;
|
||||
cpShapeUpdate(box, T);
|
||||
|
||||
cpBB bbox = cpShapeGetBB(box);
|
||||
|
||||
querybox qb;
|
||||
qb.bb = bbox;
|
||||
qb.ids = NULL;
|
||||
|
||||
cpSpaceShapeQuery(space, box, querylist, &qb);
|
||||
cpSpaceEachBody(space, querylistbodies, &qb);
|
||||
|
||||
cpShapeFree(box);
|
||||
|
||||
return clean_ids(qb.ids);
|
||||
}
|
||||
|
||||
gameobject **phys2d_query_shape(struct phys2d_shape *shape)
|
||||
{
|
||||
gameobject **ids = NULL;
|
||||
cpSpaceShapeQuery(space, shape->shape, querylist, ids);
|
||||
return clean_ids(ids);
|
||||
}
|
||||
|
||||
int cpshape_enabled(cpShape *c) {
|
||||
cpShapeFilter filter = cpShapeGetFilter(c);
|
||||
if (filter.categories == ~CP_ALL_CATEGORIES && filter.mask == ~CP_ALL_CATEGORIES)
|
||||
|
@ -227,7 +155,7 @@ void constraint_break(constraint *constraint)
|
|||
cpSpaceRemoveConstraint(space, constraint->c);
|
||||
cpConstraintFree(constraint->c);
|
||||
constraint->c = NULL;
|
||||
script_call_sym(constraint->break_cb);
|
||||
script_call_sym(constraint->break_cb,0,NULL);
|
||||
}
|
||||
|
||||
void constraint_free(constraint *constraint)
|
||||
|
@ -248,6 +176,7 @@ void constraint_test(cpConstraint *constraint, float *dt)
|
|||
void phys2d_update(float deltaT) {
|
||||
cpSpaceStep(space, deltaT);
|
||||
cpSpaceEachConstraint(space, constraint_test, &deltaT);
|
||||
cb_idx = 0;
|
||||
}
|
||||
|
||||
void init_phys2dshape(struct phys2d_shape *shape, gameobject *go, void *data) {
|
||||
|
@ -288,9 +217,8 @@ float phys2d_circle_moi(struct phys2d_circle *c) {
|
|||
return cpMomentForCircle(m, 0, cpCircleShapeGetRadius(c->shape.shape), cpCircleShapeGetOffset(c->shape.shape));
|
||||
}
|
||||
|
||||
void phys2d_circledel(struct phys2d_circle *c) {
|
||||
phys2d_shape_del(&c->shape);
|
||||
}
|
||||
void phys2d_circledel(struct phys2d_circle *c) { phys2d_shape_del(&c->shape); }
|
||||
void circle2d_free(circle2d *c) { phys2d_circledel(c); }
|
||||
|
||||
void phys2d_dbgdrawcpcirc(cpShape *c) {
|
||||
HMM_Vec2 pos = mat_t_pos(t_go2world(shape2go(c)), (HMM_Vec2)cpCircleShapeGetOffset(c));
|
||||
|
@ -311,6 +239,7 @@ void phys2d_shape_apply(struct phys2d_shape *s)
|
|||
float newmoi = s->moi(s->data);
|
||||
moment-=moi;
|
||||
moment += newmoi;
|
||||
if (moment < 0) moment = 0;
|
||||
cpBodySetMoment(s->go->body, moment);
|
||||
}
|
||||
|
||||
|
@ -352,6 +281,10 @@ void phys2d_poly_free(struct phys2d_poly *poly)
|
|||
float phys2d_poly_moi(struct phys2d_poly *poly) {
|
||||
float m = poly->shape.go->mass;
|
||||
int len = cpPolyShapeGetCount(poly->shape.shape);
|
||||
if (!len) {
|
||||
YughWarn("Cannot evaluate the MOI of a polygon of length %d.", len);
|
||||
return 0;
|
||||
}
|
||||
cpVect points[len];
|
||||
for (int i = 0; i < len; i++)
|
||||
points[i] = cpPolyShapeGetVert(poly->shape.shape, i);
|
||||
|
@ -565,10 +498,13 @@ void phys2d_dbgdrawedge(struct phys2d_edge *edge) {
|
|||
|
||||
/************ COLLIDER ****************/
|
||||
void shape_enabled(struct phys2d_shape *shape, int enabled) {
|
||||
if (enabled)
|
||||
cpShapeSetFilter(shape->shape, CP_SHAPE_FILTER_ALL);
|
||||
else
|
||||
cpShapeSetFilter(shape->shape, CP_SHAPE_FILTER_NONE);
|
||||
cpShapeFilter set = enabled ? CP_SHAPE_FILTER_ALL : CP_SHAPE_FILTER_NONE;
|
||||
if (!shape->shape) {
|
||||
struct phys2d_edge *edge = shape->data;
|
||||
for (int i = 0; i < arrlen(edge->shapes[i]); i++)
|
||||
cpShapeSetFilter(edge->shapes[i], set);
|
||||
} else
|
||||
cpShapeSetFilter(shape->shape, set);
|
||||
}
|
||||
|
||||
int shape_is_enabled(struct phys2d_shape *shape) {
|
||||
|
@ -592,7 +528,6 @@ int shape_get_sensor(struct phys2d_shape *shape) {
|
|||
if (!shape->shape) {
|
||||
struct phys2d_edge *edge = shape->data;
|
||||
if (arrlen(edge->shapes) > 0) return cpShapeGetSensor(edge->shapes[0]);
|
||||
YughInfo("Attempted to get the sensor of an edge with no shapes. It has %d points.", arrlen(edge->points));
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -601,33 +536,24 @@ int shape_get_sensor(struct phys2d_shape *shape) {
|
|||
|
||||
void phys2d_reindex_body(cpBody *body) { cpSpaceReindexShapesForBody(space, body); }
|
||||
|
||||
int arb_valid(cpArbiter *arb)
|
||||
{
|
||||
cpBody *body1;
|
||||
cpBody *body2;
|
||||
cpArbiterGetBodies(arb, &body1, &body2);
|
||||
gameobject *go2 = cpBodyGetUserData(body2);
|
||||
return !JS_IsUndefined(go2->ref);
|
||||
}
|
||||
|
||||
JSValue arb2js(cpArbiter *arb)
|
||||
{
|
||||
cpBody *body1;
|
||||
cpBody *body2;
|
||||
cpArbiterGetBodies(arb, &body1, &body2);
|
||||
gameobject *go2 = cpBodyGetUserData(body2);
|
||||
if (JS_IsUndefined(go2->ref)) return JS_UNDEFINED;
|
||||
|
||||
cpShape *shape1;
|
||||
cpShape *shape2;
|
||||
cpArbiterGetShapes(arb, &shape1, &shape2);
|
||||
|
||||
HMM_Vec2 norm;
|
||||
norm.cp = cpArbiterGetNormal(arb);
|
||||
struct phys2d_shape *pshape = cpShapeGetUserData(shape2);
|
||||
gameobject *go2 = cpBodyGetUserData(body2);
|
||||
|
||||
JSValue obj = JS_NewObject(js);
|
||||
JS_SetPropertyStr(js, obj, "normal", vec22js(norm));
|
||||
JS_SetPropertyStr(js, obj, "normal", vec22js((HMM_Vec2)cpArbiterGetNormal(arb)));
|
||||
JS_SetPropertyStr(js, obj, "obj", JS_DupValue(js,go2->ref));
|
||||
JS_SetPropertyStr(js, obj, "sensor", JS_NewBool(js, cpShapeGetSensor(shape2)));
|
||||
JS_SetPropertyStr(js, obj, "shape", JS_DupValue(js, pshape->ref));
|
||||
// JS_SetPropertyStr(js, obj, "point", vec22js((HMM_Vec2)cpArbiterGetPointA(arb, 0)));
|
||||
|
||||
HMM_Vec2 srfv;
|
||||
srfv.cp = cpArbiterGetSurfaceVelocity(arb);
|
||||
|
@ -638,56 +564,47 @@ JSValue arb2js(cpArbiter *arb)
|
|||
|
||||
void phys_run_post(cpSpace *space, JSValue *fn, JSValue *hit)
|
||||
{
|
||||
script_call_fn_arg(*fn, *hit);
|
||||
script_call_sym(*fn, 1, hit);
|
||||
JS_FreeValue(js, *hit);
|
||||
JS_FreeValue(js, *fn);
|
||||
}
|
||||
|
||||
/* TODO: Limitation, cannot handle multiple collision same frame */
|
||||
int script_phys_cb_begin(cpArbiter *arb, cpSpace *space, gameobject *go)
|
||||
void register_hit(cpArbiter *arb, gameobject *go, const char *name)
|
||||
{
|
||||
if (!arb_valid(arb)) return 1;
|
||||
|
||||
if (!JS_IsUndefined(go->cbs.begin) && cpSpaceAddPostStepCallback(space, phys_run_post, &go->cbs.begin, &go->cbs.bhit))
|
||||
go->cbs.bhit = arb2js(arb);
|
||||
|
||||
cpShape *shape1;
|
||||
cpShape *shape2;
|
||||
cpArbiterGetShapes(arb, &shape1, &shape2);
|
||||
struct phys2d_shape *pshape1 = cpShapeGetUserData(shape1);
|
||||
|
||||
for (int i = 0; i < arrlen(go->shape_cbs); i++) {
|
||||
if (go->shape_cbs[i].shape != pshape1) continue;
|
||||
if (!JS_IsUndefined(go->shape_cbs[i].cbs.begin) && cpSpaceAddPostStepCallback(space, phys_run_post, &go->shape_cbs[i].cbs.begin, &go->shape_cbs[i].cbs.bhit))
|
||||
go->shape_cbs[i].cbs.bhit = arb2js(arb);
|
||||
}
|
||||
return 1;
|
||||
if (JS_IsUndefined(go->ref)) return;
|
||||
JSValue cb = JS_GetPropertyStr(js, go->ref, name);
|
||||
if (!JS_IsUndefined(cb)) {
|
||||
JSValue jarb = arb2js(arb);
|
||||
fns[cb_idx] = JS_DupValue(js, cb);
|
||||
hits[cb_idx] = jarb;
|
||||
cpSpaceAddPostStepCallback(space, phys_run_post, &fns[cb_idx], &hits[cb_idx]);
|
||||
cb_idx++;
|
||||
}
|
||||
|
||||
void script_phys_cb_separate(cpArbiter *arb, cpSpace *space, gameobject *go)
|
||||
{
|
||||
if (!arb_valid(arb)) return;
|
||||
if (JS_IsUndefined(go->cbs.separate)) return;
|
||||
go->cbs.shit = arb2js(arb);
|
||||
cpSpaceAddPostStepCallback(space, phys_run_post, &go->cbs.separate, &go->cbs.shit);
|
||||
cpShape *s1, *s2;
|
||||
cpArbiterGetShapes(arb, &s1, &s2);
|
||||
gameobject *g1, *g2;
|
||||
g1 = shape2go(s1);
|
||||
g2 = shape2go(g2);
|
||||
if (!g1) return;
|
||||
if (!g2) return;
|
||||
if (JS_IsUndefined(g1->ref)) return;
|
||||
if (JS_IsUndefined(g2->ref)) return;
|
||||
struct phys2d_shape *pshape1 = cpShapeGetUserData(s1);
|
||||
|
||||
if (JS_IsUndefined(pshape1->ref)) return;
|
||||
cb = JS_GetPropertyStr(js, pshape1->ref, name);
|
||||
if (!JS_IsUndefined(cb)) {
|
||||
JSValue jarb = arb2js(arb);
|
||||
fns[cb_idx] = JS_DupValue(js,cb);
|
||||
hits[cb_idx] = jarb;
|
||||
cpSpaceAddPostStepCallback(space, phys_run_post, &fns[cb_idx], &hits[cb_idx]);
|
||||
cb_idx++;
|
||||
}
|
||||
}
|
||||
|
||||
void phys2d_rm_go_handlers(gameobject *go) {
|
||||
cpCollisionHandler *handler = cpSpaceAddWildcardHandler(space, (cpCollisionType)go);
|
||||
|
||||
if (!JS_IsUndefined(go->cbs.begin)) {
|
||||
JS_FreeValue(js,go->cbs.begin);
|
||||
go->cbs.begin = JS_UNDEFINED;
|
||||
}
|
||||
if (JS_IsFunction(js,go->cbs.separate)) {
|
||||
JS_FreeValue(js,go->cbs.separate);
|
||||
go->cbs.separate = JS_UNDEFINED;
|
||||
}
|
||||
|
||||
for (int i = 0; i < arrlen(go->shape_cbs); i++) {
|
||||
JS_FreeValue(js, go->shape_cbs[i].cbs.begin);
|
||||
go->shape_cbs[i].cbs.begin = JS_UNDEFINED;
|
||||
}
|
||||
}
|
||||
int script_phys_cb_begin(cpArbiter *arb, cpSpace *space, gameobject *go) { register_hit(arb, go, "collide"); return 1; }
|
||||
void script_phys_cb_separate(cpArbiter *arb, cpSpace *space, gameobject *go) { register_hit(arb, go, "separate"); }
|
||||
|
||||
void phys2d_setup_handlers(gameobject *go) {
|
||||
cpCollisionHandler *handler = cpSpaceAddWildcardHandler(space, (cpCollisionType)go);
|
||||
|
@ -695,16 +612,3 @@ void phys2d_setup_handlers(gameobject *go) {
|
|||
handler->beginFunc = script_phys_cb_begin;
|
||||
handler->separateFunc = script_phys_cb_separate;
|
||||
}
|
||||
|
||||
static int airborne = 0;
|
||||
|
||||
void inair(cpBody *body, cpArbiter *arbiter, void *data) {
|
||||
airborne = 0;
|
||||
}
|
||||
|
||||
int phys2d_in_air(cpBody *body) {
|
||||
airborne = 1;
|
||||
cpBodyEachArbiter(body, inair, NULL);
|
||||
|
||||
return airborne;
|
||||
}
|
||||
|
|
|
@ -29,6 +29,7 @@ void constraint_free(constraint *constraint);
|
|||
|
||||
struct phys2d_shape {
|
||||
cpShape *shape; /* user data is this phys2d_shape */
|
||||
JSValue ref;
|
||||
transform2d t;
|
||||
gameobject *go;
|
||||
void *data; /* The specific subtype; phys2d_circle, etc */
|
||||
|
@ -47,6 +48,8 @@ struct phys2d_circle {
|
|||
struct phys2d_shape shape;
|
||||
};
|
||||
|
||||
typedef struct phys2d_circle circle2d;
|
||||
|
||||
/* A convex polygon; defined as the convex hull around the given set of points */
|
||||
struct phys2d_poly {
|
||||
HMM_Vec2 *points;
|
||||
|
@ -66,6 +69,7 @@ struct phys2d_edge {
|
|||
|
||||
struct phys2d_circle *Make2DCircle(gameobject *go);
|
||||
void phys2d_circledel(struct phys2d_circle *c);
|
||||
void circle2d_free(circle2d *c);
|
||||
void phys2d_applycircle(struct phys2d_circle *circle);
|
||||
void phys2d_dbgdrawcircle(struct phys2d_circle *circle);
|
||||
float phys2d_circle_moi(struct phys2d_circle *c);
|
||||
|
@ -99,7 +103,7 @@ void phys2d_edge_set_enabled(struct phys2d_edge *edge, int enabled);
|
|||
void phys2d_init();
|
||||
void phys2d_update(float deltaT);
|
||||
cpShape *phys2d_query_pos(cpVect pos);
|
||||
gameobject **phys2d_query_box(HMM_Vec2 pos, HMM_Vec2 wh);
|
||||
void phys2d_query_ray(HMM_Vec2 start, HMM_Vec2 end, float radius, cpShapeFilter filter, JSValue cb);
|
||||
|
||||
struct shape_cb {
|
||||
struct phys2d_shape *shape;
|
||||
|
@ -108,7 +112,6 @@ struct shape_cb {
|
|||
|
||||
void fire_hits();
|
||||
|
||||
void phys2d_rm_go_handlers(gameobject *go);
|
||||
void phys2d_set_gravity(HMM_Vec2 v);
|
||||
|
||||
void shape_enabled(struct phys2d_shape *shape, int enabled);
|
||||
|
@ -120,14 +123,8 @@ struct rgba shape_color_s(cpShape *shape);
|
|||
|
||||
void shape_gui(struct phys2d_shape *shape);
|
||||
void phys2d_setup_handlers(gameobject *go);
|
||||
gameobject **phys2d_query_shape(struct phys2d_shape *shape);
|
||||
int *phys2d_query_box_points(HMM_Vec2 pos, HMM_Vec2 wh, HMM_Vec2 *points, int n);
|
||||
int query_point(HMM_Vec2 pos);
|
||||
|
||||
void flush_collide_cbs();
|
||||
|
||||
void phys2d_reindex_body(cpBody *body);
|
||||
extern unsigned int category_masks[32];
|
||||
void set_cat_mask(int cat, unsigned int mask);
|
||||
int phys2d_in_air(cpBody *body);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -167,7 +167,9 @@ sg_buffer texcoord_floats(float *f, int verts, int comp)
|
|||
|
||||
return sg_make_buffer(&(sg_buffer_desc){
|
||||
.data.ptr = packed,
|
||||
.data.size = sizeof(unsigned short) * verts});
|
||||
.data.size = sizeof(unsigned short) * verts,
|
||||
.label = "tex coord vert buffer",
|
||||
});
|
||||
}
|
||||
|
||||
sg_buffer normal_floats(float *f, int verts, int comp)
|
||||
|
@ -178,7 +180,9 @@ sg_buffer normal_floats(float *f, int verts, int comp)
|
|||
|
||||
return sg_make_buffer(&(sg_buffer_desc){
|
||||
.data.ptr = packed_norms,
|
||||
.data.size = sizeof(uint32_t) * verts});
|
||||
.data.size = sizeof(uint32_t) * verts,
|
||||
.label = "normal vert buffer",
|
||||
});
|
||||
}
|
||||
|
||||
HMM_Vec3 index_to_vert(uint32_t idx, float *f)
|
||||
|
@ -197,7 +201,9 @@ void mesh_add_primitive(mesh *mesh, cgltf_primitive *prim)
|
|||
mesh->bind.index_buffer = sg_make_buffer(&(sg_buffer_desc){
|
||||
.data.ptr = idxs,
|
||||
.data.size = sizeof(uint16_t) * c,
|
||||
.type = SG_BUFFERTYPE_INDEXBUFFER});
|
||||
.type = SG_BUFFERTYPE_INDEXBUFFER,
|
||||
.label = "mesh index buffer",
|
||||
});
|
||||
|
||||
mesh->idx_count = c;
|
||||
} else {
|
||||
|
@ -233,7 +239,9 @@ void mesh_add_primitive(mesh *mesh, cgltf_primitive *prim)
|
|||
case cgltf_attribute_type_position:
|
||||
mesh->bind.vertex_buffers[0] = sg_make_buffer(&(sg_buffer_desc){
|
||||
.data.ptr = vs,
|
||||
.data.size = sizeof(float) * n});
|
||||
.data.size = sizeof(float) * n,
|
||||
.label = "mesh vert buffer"
|
||||
});
|
||||
break;
|
||||
|
||||
case cgltf_attribute_type_normal:
|
||||
|
@ -369,11 +377,10 @@ struct model *MakeModel(const char *path)
|
|||
/* eye position */
|
||||
HMM_Vec3 eye = {0,0,100};
|
||||
|
||||
void draw_model(struct model *model, HMM_Mat4 amodel) {
|
||||
HMM_Mat4 proj = projection;
|
||||
void draw_model(struct model *model, HMM_Mat4 amodel, HMM_Mat4 *proj) {
|
||||
HMM_Vec3 center = {0.f, 0.f, 0.f};
|
||||
HMM_Mat4 view = HMM_LookAt_RH(eye, center, vUP);
|
||||
HMM_Mat4 vp = HMM_MulM4(proj, view);
|
||||
HMM_Mat4 vp = HMM_MulM4(*proj, view);
|
||||
|
||||
HMM_Vec3 dir_dir = HMM_NormV3(HMM_SubV3(center, dirl_pos));
|
||||
|
||||
|
@ -411,10 +418,10 @@ void draw_drawmodel(struct drawmodel *dm)
|
|||
if (!dm->model) return;
|
||||
struct gameobject *go = dm->go;
|
||||
HMM_Mat4 rst = t3d_go2world(go);
|
||||
draw_model(dm->model, rst);
|
||||
draw_model(dm->model, rst, &useproj);
|
||||
}
|
||||
|
||||
void free_drawmodel(struct drawmodel *dm) {
|
||||
void drawmodel_free(struct drawmodel *dm) {
|
||||
int rm;
|
||||
for (int i = 0; i < arrlen(models); i++)
|
||||
if (models[i] == dm) {
|
||||
|
|
|
@ -28,11 +28,11 @@ typedef struct model {
|
|||
} model;
|
||||
|
||||
/* A model with draw information */
|
||||
struct drawmodel {
|
||||
typedef struct drawmodel {
|
||||
struct model *model;
|
||||
HMM_Mat4 amodel;
|
||||
gameobject *go;
|
||||
};
|
||||
} drawmodel;
|
||||
|
||||
typedef struct bone {
|
||||
transform3d t;
|
||||
|
@ -53,7 +53,7 @@ void model_init();
|
|||
struct drawmodel *make_drawmodel(gameobject *go);
|
||||
void draw_drawmodel(struct drawmodel *dm);
|
||||
void model_draw_all();
|
||||
void free_drawmodel(struct drawmodel *dm);
|
||||
void drawmodel_free(struct drawmodel *dm);
|
||||
|
||||
material *material_make();
|
||||
void material_free(material *mat);
|
||||
|
|
|
@ -2,7 +2,6 @@
|
|||
|
||||
#define SOKOL_TRACE_HOOKS
|
||||
#define SOKOL_IMPL
|
||||
#define SOKOL_NO_ENTRY
|
||||
#include "sokol/sokol_audio.h"
|
||||
#include "sokol/sokol_time.h"
|
||||
#include "sokol/sokol_args.h"
|
||||
|
|
|
@ -1,45 +0,0 @@
|
|||
#include "debug.h"
|
||||
|
||||
#include "stb_ds.h"
|
||||
#include "log.h"
|
||||
#include "sokol/sokol_time.h"
|
||||
|
||||
unsigned long long triCount = 0;
|
||||
|
||||
void prof_start(struct d_prof *prof)
|
||||
{
|
||||
arrsetlen(prof->ms, prof->laps);
|
||||
}
|
||||
|
||||
void prof_reset(struct d_prof *prof)
|
||||
{
|
||||
prof->lap = stm_now();
|
||||
}
|
||||
|
||||
float prof_lap_avg(struct d_prof *prof)
|
||||
{
|
||||
float avg;
|
||||
for (int i = 0; i < arrlen(prof->ms); i++)
|
||||
avg += prof->ms[i];
|
||||
|
||||
avg /= arrlen(prof->ms);
|
||||
return avg;
|
||||
}
|
||||
|
||||
void prof_lap(struct d_prof *prof)
|
||||
{
|
||||
if (prof->ms == NULL)
|
||||
prof_start(prof);
|
||||
|
||||
if (arrlen(prof->ms) >= prof->laps) {
|
||||
YughWarn("Profiled time of %s is avg %g", prof->name, prof_lap_avg(prof));
|
||||
arrsetlen(prof->ms, 0);
|
||||
}
|
||||
uint64_t t = stm_since(prof->lap);
|
||||
arrput(prof->ms, stm_sec(t));
|
||||
}
|
||||
|
||||
void resetTriangles()
|
||||
{
|
||||
triCount = 0;
|
||||
}
|
|
@ -1,20 +0,0 @@
|
|||
#ifndef DEBUG_GUI_H
|
||||
#define DEBUG_GUI_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
struct d_prof {
|
||||
char *name;
|
||||
float *ms;
|
||||
uint64_t lap;
|
||||
int laps;
|
||||
};
|
||||
|
||||
extern unsigned long long triCount;
|
||||
void resetTriangles();
|
||||
void prof_start(struct d_prof *prof);
|
||||
void prof_reset(struct d_prof *prof);
|
||||
void prof_lap(struct d_prof *prof);
|
||||
float prof_lap_avg(struct d_prof *prof);
|
||||
|
||||
#endif
|
|
@ -4,7 +4,6 @@
|
|||
#include "yugine.h"
|
||||
#include "log.h"
|
||||
#include <assert.h>
|
||||
#include "debug.h"
|
||||
#include "window.h"
|
||||
#include "2dphysics.h"
|
||||
#include "stb_ds.h"
|
||||
|
@ -21,7 +20,7 @@
|
|||
|
||||
#include "font.h"
|
||||
|
||||
#define v_amt 5000
|
||||
#define v_amt 500000
|
||||
|
||||
struct flush {
|
||||
sg_shader shader;
|
||||
|
@ -110,6 +109,26 @@ struct circle_vertex {
|
|||
float fill;
|
||||
};
|
||||
|
||||
void debug_nextpass()
|
||||
{
|
||||
point_sc = point_c;
|
||||
point_c = 0;
|
||||
|
||||
circle_sc = circle_count;
|
||||
circle_count = 0;
|
||||
|
||||
line_sv = line_v;
|
||||
line_v = 0;
|
||||
line_sc = line_c;
|
||||
line_c = 0;
|
||||
|
||||
poly_sc = poly_c;
|
||||
poly_c = 0;
|
||||
|
||||
poly_sv = poly_v;
|
||||
poly_v = 0;
|
||||
}
|
||||
|
||||
/* Writes debug data to buffers, and draws */
|
||||
void debug_flush(HMM_Mat4 *view)
|
||||
{
|
||||
|
@ -143,26 +162,8 @@ void debug_flush(HMM_Mat4 *view)
|
|||
sg_apply_uniforms(SG_SHADERSTAGE_VS, 0, SG_RANGE_REF(*view));
|
||||
sg_draw(circle_sc,4,circle_count);
|
||||
}
|
||||
}
|
||||
|
||||
void debug_nextpass()
|
||||
{
|
||||
point_sc = point_c;
|
||||
point_c = 0;
|
||||
|
||||
circle_sc = circle_count;
|
||||
circle_count = 0;
|
||||
|
||||
line_sv = line_v;
|
||||
line_v = 0;
|
||||
line_sc = line_c;
|
||||
line_c = 0;
|
||||
|
||||
poly_sc = poly_c;
|
||||
poly_c = 0;
|
||||
|
||||
poly_sv = poly_v;
|
||||
poly_v = 0;
|
||||
debug_nextpass();
|
||||
}
|
||||
|
||||
void debug_newframe()
|
||||
|
@ -175,7 +176,7 @@ void debug_newframe()
|
|||
}
|
||||
|
||||
static sg_shader_uniform_block_desc projection_ubo = {
|
||||
.size = sizeof(projection),
|
||||
.size = sizeof(useproj),
|
||||
.uniforms = {
|
||||
[0] = { .name = "proj", .type = SG_UNIFORMTYPE_MAT4 },
|
||||
}
|
||||
|
@ -208,7 +209,8 @@ void debugdraw_init()
|
|||
|
||||
point_bind.vertex_buffers[0] = sg_make_buffer(&(sg_buffer_desc){
|
||||
.size = sizeof(struct point_vertex)*v_amt,
|
||||
.usage = SG_USAGE_STREAM
|
||||
.usage = SG_USAGE_STREAM,
|
||||
.label = "point vertex buffer"
|
||||
});
|
||||
|
||||
line_shader = sg_make_shader(line_shader_desc(sg_query_backend()));
|
||||
|
@ -232,13 +234,15 @@ void debugdraw_init()
|
|||
|
||||
line_bind.vertex_buffers[0] = sg_make_buffer(&(sg_buffer_desc){
|
||||
.size = sizeof(struct line_vert)*v_amt,
|
||||
.usage = SG_USAGE_STREAM
|
||||
.usage = SG_USAGE_STREAM,
|
||||
.label = "line vertex buffer",
|
||||
});
|
||||
|
||||
line_bind.index_buffer = sg_make_buffer(&(sg_buffer_desc){
|
||||
.size = sizeof(uint16_t)*v_amt,
|
||||
.usage = SG_USAGE_STREAM,
|
||||
.type = SG_BUFFERTYPE_INDEXBUFFER
|
||||
.type = SG_BUFFERTYPE_INDEXBUFFER,
|
||||
.label = "line index buffer",
|
||||
});
|
||||
|
||||
csg = sg_make_shader(circle_shader_desc(sg_query_backend()));
|
||||
|
@ -265,6 +269,7 @@ void debugdraw_init()
|
|||
circle_bind.vertex_buffers[0] = sg_make_buffer(&(sg_buffer_desc){
|
||||
.size = sizeof(struct circle_vertex)*v_amt,
|
||||
.usage = SG_USAGE_STREAM,
|
||||
.label = "circle vert buffer",
|
||||
});
|
||||
|
||||
float circleverts[8] = {
|
||||
|
@ -277,6 +282,7 @@ void debugdraw_init()
|
|||
circle_bind.vertex_buffers[1] = sg_make_buffer(&(sg_buffer_desc){
|
||||
.data = (sg_range){.ptr = circleverts, .size = sizeof(float)*8},
|
||||
.usage = SG_USAGE_IMMUTABLE,
|
||||
.label = "circle quarter buffer",
|
||||
});
|
||||
|
||||
grid_shader = sg_make_shader(grid_shader_desc(sg_query_backend()));
|
||||
|
@ -314,12 +320,14 @@ void debugdraw_init()
|
|||
.size = sizeof(struct poly_vertex)*v_amt,
|
||||
.usage = SG_USAGE_STREAM,
|
||||
.type = SG_BUFFERTYPE_VERTEXBUFFER,
|
||||
.label = "poly vert buffer",
|
||||
});
|
||||
|
||||
poly_bind.index_buffer = sg_make_buffer(&(sg_buffer_desc){
|
||||
.size = sizeof(uint32_t)*6*v_amt,
|
||||
.usage = SG_USAGE_STREAM,
|
||||
.type = SG_BUFFERTYPE_INDEXBUFFER
|
||||
.type = SG_BUFFERTYPE_INDEXBUFFER,
|
||||
.label = "poly index buffer"
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -364,6 +372,7 @@ void draw_line(HMM_Vec2 *points, int n, struct rgba color, float seg_len, float
|
|||
.size = sizeof(uint16_t)*i_c
|
||||
};
|
||||
|
||||
if (sg_query_buffer_will_overflow(line_bind.vertex_buffers[0], vr.size) || sg_query_buffer_will_overflow(line_bind.index_buffer, ir.size)) return;
|
||||
sg_append_buffer(line_bind.vertex_buffers[0], &vr);
|
||||
sg_append_buffer(line_bind.index_buffer, &ir);
|
||||
|
||||
|
@ -427,10 +436,10 @@ HMM_Vec2 *inflatepoints(HMM_Vec2 *p, float d, int n)
|
|||
}
|
||||
|
||||
/* Given a strip of points, draws them as segments. So 5 points is 4 segments, and ultimately 8 vertices */
|
||||
void draw_edge(HMM_Vec2 *points, int n, struct rgba color, int thickness, int flags, struct rgba line_color, float line_seg)
|
||||
void draw_edge(HMM_Vec2 *points, int n, struct rgba color, float thickness, int flags, struct rgba line_color, float line_seg)
|
||||
{
|
||||
int closed = 0;
|
||||
if (thickness <= 1) {
|
||||
if (thickness <= 0) {
|
||||
draw_line(points,n,line_color,0,0);
|
||||
return;
|
||||
}
|
||||
|
@ -547,8 +556,8 @@ void draw_box(HMM_Vec2 c, HMM_Vec2 wh, struct rgba color)
|
|||
|
||||
void draw_grid(float width, float span, struct rgba color)
|
||||
{
|
||||
HMM_Vec2 offset = (HMM_Vec2)cam_pos();
|
||||
offset = HMM_MulV2F(offset, 1/cam_zoom());
|
||||
HMM_Vec2 offset = campos;
|
||||
offset = HMM_MulV2F(offset, 1/camzoom);
|
||||
|
||||
float ubo[4];
|
||||
ubo[0] = offset.x;
|
||||
|
@ -563,7 +572,7 @@ void draw_grid(float width, float span, struct rgba color)
|
|||
|
||||
fs_params_t pt;
|
||||
pt.thickness = (float)width;
|
||||
pt.span = span/cam_zoom();
|
||||
pt.span = span/camzoom;
|
||||
memcpy(&pt.color, col, sizeof(float)*4);
|
||||
sg_apply_uniforms(SG_SHADERSTAGE_VS, 0, SG_RANGE_REF(ubo));
|
||||
sg_apply_uniforms(SG_SHADERSTAGE_FS, 0, SG_RANGE_REF(pt));
|
||||
|
|
|
@ -9,7 +9,7 @@ void draw_cppoint(HMM_Vec2 point, float r, struct rgba color);
|
|||
void draw_points(HMM_Vec2 *points, int n, float size, struct rgba color);
|
||||
|
||||
void draw_line(HMM_Vec2 *points, int n, struct rgba color, float seg_len, float seg_speed);
|
||||
void draw_edge(HMM_Vec2 *points, int n, struct rgba color, int thickness, int flags, struct rgba line_color, float line_seg);
|
||||
void draw_edge(HMM_Vec2 *points, int n, struct rgba color, float thickness, int flags, struct rgba line_color, float line_seg);
|
||||
|
||||
/* pixels - how many pixels thick, segsize - dashed line seg len */
|
||||
void draw_circle(HMM_Vec2 c, float radius, float pixels, struct rgba color, float seg);
|
||||
|
@ -20,7 +20,6 @@ void draw_grid(float width, float span, struct rgba color);
|
|||
|
||||
void debug_flush(HMM_Mat4 *view);
|
||||
void debug_newframe();
|
||||
void debug_nextpass();
|
||||
|
||||
HMM_Vec2 *inflatepoints(HMM_Vec2 *p, float d, int n);
|
||||
|
||||
|
|
|
@ -7,22 +7,52 @@
|
|||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <stdio.h>
|
||||
#include <signal.h>
|
||||
#include <fcntl.h>
|
||||
#include "yugine.h"
|
||||
#include "resources.h"
|
||||
#include "quickjs/quickjs.h"
|
||||
|
||||
#include "script.h"
|
||||
|
||||
#define ESC "\033["
|
||||
#define BLACK 30
|
||||
#define RED 31
|
||||
#define GREEN 32
|
||||
#define YELLOW 33
|
||||
#define BLUE 34
|
||||
#define MAGENTA 35
|
||||
#define CYAN 36
|
||||
#define WHITE 37
|
||||
|
||||
#define COLOR(TXT, _C) ESC #_C "m" #TXT ESC "0m"
|
||||
|
||||
char *logstr[] = { "spam", "debug", "info", "warn", "error", "panic"};
|
||||
char *logcolor[] = { COLOR(spam,37), COLOR(debug,32), COLOR(info,36), COLOR(warn,33), COLOR(error,31), COLOR(panic,45) };
|
||||
char *catstr[] = {"engine", "script", "render"};
|
||||
|
||||
static FILE *logout; /* where logs are written to */
|
||||
static FILE *writeout; /* where console is written to */
|
||||
static FILE *dump; /* where data is dumped to */
|
||||
|
||||
int stdout_lvl = LOG_ERROR;
|
||||
|
||||
void log_init()
|
||||
{
|
||||
#ifndef NDEBUG
|
||||
if (!fexists(".prosperon")) {
|
||||
logout = tmpfile();
|
||||
dump = tmpfile();
|
||||
writeout = stdout;
|
||||
}
|
||||
else {
|
||||
logout = fopen(".prosperon/log.txt", "w");
|
||||
writeout = fopen(".prosperon/transcript.txt", "w");
|
||||
dump = fopen(".prosperon/quickjs.txt", "w");
|
||||
quickjs_set_dumpout(dump);
|
||||
}
|
||||
|
||||
quickjs_set_dumpout(dump);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -30,6 +60,7 @@ void log_shutdown()
|
|||
{
|
||||
fclose(logout);
|
||||
fclose(writeout);
|
||||
fclose(dump);
|
||||
}
|
||||
|
||||
const char *logfmt = "%s:%d: [%s] %s, %s: ";
|
||||
|
@ -49,15 +80,24 @@ void mYughLog(int category, int priority, int line, const char *file, const char
|
|||
va_end(args);
|
||||
fprintf(logout, "\n");
|
||||
|
||||
if (priority == LOG_DEBUG) {
|
||||
printf(logfmt, file, line, timebuf, logstr[priority], catstr[category]);
|
||||
if (priority == LOG_DEBUG || priority >= stdout_lvl) {
|
||||
printf(logfmt, file, line, timebuf, logcolor[priority], catstr[category]);
|
||||
va_list args;
|
||||
va_start(args,message);
|
||||
vprintf(message, args);
|
||||
va_end(args);
|
||||
printf("\n");
|
||||
fflush(stdout);
|
||||
}
|
||||
|
||||
if (priority >= LOG_PANIC) {
|
||||
js_stacktrace();
|
||||
#ifdef __WIN32
|
||||
DebugBreak();
|
||||
#else
|
||||
raise(SIGTRAP);
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -67,7 +107,6 @@ void log_print(const char *str)
|
|||
#ifndef NDEBUG
|
||||
fprintf(writeout, str);
|
||||
#endif
|
||||
printf(str);
|
||||
fflush(stdout);
|
||||
}
|
||||
|
||||
|
|
|
@ -18,6 +18,8 @@
|
|||
void log_init();
|
||||
void log_shutdown();
|
||||
|
||||
extern int stdout_lvl;
|
||||
|
||||
#ifndef NDEBUG
|
||||
#define YughLog(cat, pri, msg, ...) mYughLog(cat, pri, __LINE__, __FILE__, msg, ##__VA_ARGS__)
|
||||
#define YughSpam(msg, ...) mYughLog(0, LOG_SPAM, __LINE__, __FILE__, msg, ##__VA_ARGS__);
|
||||
|
@ -27,6 +29,7 @@ void log_shutdown();
|
|||
#define YughCritical(msg, ...) mYughLog(0, LOG_PANIC, __LINE__, __FILE__, msg, ##__VA_ARGS__);
|
||||
#else
|
||||
#define YughLog(cat, pri, msg, ...)
|
||||
#define YughSpam(msg,...)
|
||||
#define YughInfo(msg, ...)
|
||||
#define YughWarn(msg, ...)
|
||||
#define YughError(msg, ...)
|
||||
|
|
|
@ -17,18 +17,12 @@
|
|||
#include "stb_image_write.h"
|
||||
#include "stb_rect_pack.h"
|
||||
#include "stb_truetype.h"
|
||||
#include "stb_ds.h"
|
||||
|
||||
#include "HandmadeMath.h"
|
||||
|
||||
struct sFont *font;
|
||||
struct sFont *use_font;
|
||||
|
||||
static struct {
|
||||
char *key;
|
||||
struct sFont *value;
|
||||
} *fonthash = NULL;
|
||||
|
||||
#define max_chars 10000
|
||||
#define max_chars 100000
|
||||
|
||||
static sg_shader fontshader;
|
||||
static sg_bindings bind_text;
|
||||
|
@ -74,7 +68,8 @@ void font_init() {
|
|||
|
||||
bind_text.vertex_buffers[1] = sg_make_buffer(&(sg_buffer_desc){
|
||||
.data = SG_RANGE(text_verts),
|
||||
.usage = SG_USAGE_IMMUTABLE
|
||||
.usage = SG_USAGE_IMMUTABLE,
|
||||
.label = "text rectangle buffer",
|
||||
});
|
||||
|
||||
bind_text.vertex_buffers[0] = sg_make_buffer(&(sg_buffer_desc){
|
||||
|
@ -84,31 +79,19 @@ void font_init() {
|
|||
.label = "text buffer"
|
||||
});
|
||||
|
||||
font_set("fonts/c64.ttf");
|
||||
bind_text.fs.images[0] = font->texID;
|
||||
bind_text.fs.samplers[0] = sg_make_sampler(&(sg_sampler_desc){});
|
||||
}
|
||||
|
||||
void font_set(const char *path)
|
||||
void font_free(font *f)
|
||||
{
|
||||
if (shlen(fonthash) == 0) sh_new_arena(fonthash);
|
||||
int index = shgeti(fonthash, path);
|
||||
if (index != -1) {
|
||||
if (font == fonthash[index].value) return;
|
||||
font = fonthash[index].value;
|
||||
bind_text.fs.images[0] = font->texID;
|
||||
return;
|
||||
sg_destroy_image(f->texID);
|
||||
free(f);
|
||||
}
|
||||
|
||||
struct sFont *newfont = MakeFont(path, 8);
|
||||
if (!newfont) {
|
||||
YughError("Could not make font from %s.", path);
|
||||
return;
|
||||
}
|
||||
|
||||
font = newfont;
|
||||
shput(fonthash, path, newfont);
|
||||
bind_text.fs.images[0] = font->texID;
|
||||
void font_set(font *f)
|
||||
{
|
||||
use_font = f;
|
||||
bind_text.fs.images[0] = f->texID;
|
||||
}
|
||||
|
||||
struct sFont *MakeSDFFont(const char *fontfile, int height)
|
||||
|
@ -145,6 +128,10 @@ struct sFont *MakeFont(const char *fontfile, int height) {
|
|||
newfont->height = height;
|
||||
|
||||
unsigned char *ttf_buffer = slurp_file(fontfile, NULL);
|
||||
if (!ttf_buffer) {
|
||||
YughWarn("Could not find font at %s.");
|
||||
return NULL;
|
||||
}
|
||||
unsigned char *bitmap = malloc(packsize * packsize);
|
||||
|
||||
stbtt_packedchar glyphs[95];
|
||||
|
@ -163,8 +150,9 @@ struct sFont *MakeFont(const char *fontfile, int height) {
|
|||
}
|
||||
|
||||
stbtt_GetFontVMetrics(&fontinfo, &newfont->ascent, &newfont->descent, &newfont->linegap);
|
||||
newfont->emscale = stbtt_ScaleForMappingEmToPixels(&fontinfo, 16);
|
||||
newfont->linegap = (newfont->ascent - newfont->descent) * newfont->emscale;
|
||||
//newfont->emscale = stbtt_ScaleForMappingEmToPixels(&fontinfo, 16);
|
||||
newfont->emscale = stbtt_ScaleForPixelHeight(&fontinfo, height);
|
||||
newfont->linegap = (newfont->ascent - newfont->descent) * newfont->emscale*1.5;
|
||||
|
||||
newfont->texID = sg_make_image(&(sg_image_desc){
|
||||
.type = SG_IMAGETYPE_2D,
|
||||
|
@ -174,8 +162,9 @@ struct sFont *MakeFont(const char *fontfile, int height) {
|
|||
.usage = SG_USAGE_IMMUTABLE,
|
||||
.data.subimage[0][0] = {
|
||||
.ptr = bitmap,
|
||||
.size = packsize * packsize}});
|
||||
|
||||
.size = packsize * packsize
|
||||
}
|
||||
});
|
||||
|
||||
for (unsigned char c = 32; c < 127; c++) {
|
||||
stbtt_packedchar glyph = glyphs[c - 32];
|
||||
|
@ -208,7 +197,7 @@ static int curchar = 0;
|
|||
void draw_underline_cursor(HMM_Vec2 pos, float scale, struct rgba color)
|
||||
{
|
||||
pos.Y -= 2;
|
||||
sdrawCharacter(font->Characters['_'], pos, scale, color);
|
||||
sdrawCharacter(use_font->Characters['_'], pos, scale, color);
|
||||
}
|
||||
|
||||
void draw_char_box(struct Character c, HMM_Vec2 cursor, float scale, struct rgba color)
|
||||
|
@ -244,7 +233,7 @@ void text_flush(HMM_Mat4 *proj) {
|
|||
}
|
||||
|
||||
void sdrawCharacter(struct Character c, HMM_Vec2 cursor, float scale, struct rgba color) {
|
||||
if (curchar+1 >= max_chars)
|
||||
if (curchar-10 >= max_chars)
|
||||
return;
|
||||
|
||||
struct rgba colorbox = {0,0,0,255};
|
||||
|
@ -270,10 +259,6 @@ void sdrawCharacter(struct Character c, HMM_Vec2 cursor, float scale, struct rgb
|
|||
curchar++;
|
||||
}
|
||||
|
||||
void text_settype(struct sFont *mfont) {
|
||||
font = mfont;
|
||||
}
|
||||
|
||||
const char *esc_color(const char *c, struct rgba *color, struct rgba defc)
|
||||
{
|
||||
struct rgba d;
|
||||
|
@ -303,6 +288,7 @@ const char *esc_color(const char *c, struct rgba *color, struct rgba defc)
|
|||
|
||||
struct boundingbox text_bb(const char *text, float scale, float lw, float tracking)
|
||||
{
|
||||
if (!use_font) return cwh2bb((HMM_Vec2){0,0}, (HMM_Vec2){0,0});
|
||||
struct rgba dummy;
|
||||
HMM_Vec2 cursor = {0,0};
|
||||
const char *line, *wordstart;
|
||||
|
@ -310,10 +296,10 @@ struct boundingbox text_bb(const char *text, float scale, float lw, float tracki
|
|||
|
||||
while (*line != '\0') {
|
||||
if (isblank(*line)) {
|
||||
cursor.X += font->Characters[*line].Advance * tracking * scale;
|
||||
cursor.X += use_font->Characters[*line].Advance * tracking * scale;
|
||||
line++;
|
||||
} else if (isspace(*line)) {
|
||||
cursor.Y -= scale * font->linegap;
|
||||
cursor.Y -= scale * use_font->linegap;
|
||||
cursor.X = 0;
|
||||
line++;
|
||||
} else {
|
||||
|
@ -324,26 +310,26 @@ struct boundingbox text_bb(const char *text, float scale, float lw, float tracki
|
|||
int wordWidth = 0;
|
||||
|
||||
while (!isspace(*line) && *line != '\0') {
|
||||
wordWidth += font->Characters[*line].Advance * tracking * scale;
|
||||
wordWidth += use_font->Characters[*line].Advance * tracking * scale;
|
||||
line++;
|
||||
}
|
||||
|
||||
if (lw > 0 && (cursor.X + wordWidth) >= lw) {
|
||||
cursor.X = 0;
|
||||
cursor.Y -= scale * font->linegap;
|
||||
cursor.Y -= scale * use_font->linegap;
|
||||
}
|
||||
|
||||
while (wordstart < line) {
|
||||
if (*wordstart == '\e')
|
||||
line = esc_color(wordstart, NULL, dummy);
|
||||
|
||||
cursor.X += font->Characters[*wordstart].Advance * tracking * scale;
|
||||
cursor.X += use_font->Characters[*wordstart].Advance * tracking * scale;
|
||||
wordstart++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return cwh2bb((HMM_Vec2){0,0}, (HMM_Vec2){cursor.X,font->linegap-cursor.Y});
|
||||
return cwh2bb((HMM_Vec2){0,0}, (HMM_Vec2){cursor.X,use_font->linegap-cursor.Y});
|
||||
}
|
||||
|
||||
void check_caret(int caret, int l, HMM_Vec2 pos, float scale, struct rgba color)
|
||||
|
@ -354,6 +340,11 @@ void check_caret(int caret, int l, HMM_Vec2 pos, float scale, struct rgba color)
|
|||
|
||||
/* pos given in screen coordinates */
|
||||
int renderText(const char *text, HMM_Vec2 pos, float scale, struct rgba color, float lw, int caret, float tracking) {
|
||||
if (!use_font) {
|
||||
YughError("Cannot render text before a font is set.");
|
||||
return pos.y;
|
||||
}
|
||||
|
||||
int len = strlen(text);
|
||||
|
||||
HMM_Vec2 cursor = pos;
|
||||
|
@ -366,13 +357,13 @@ int renderText(const char *text, HMM_Vec2 pos, float scale, struct rgba color, f
|
|||
|
||||
while (*line != '\0') {
|
||||
if (isblank(*line)) {
|
||||
sdrawCharacter(font->Characters[*line], cursor, scale, usecolor);
|
||||
cursor.X += font->Characters[*line].Advance * tracking * scale;
|
||||
sdrawCharacter(use_font->Characters[*line], cursor, scale, usecolor);
|
||||
cursor.X += use_font->Characters[*line].Advance * tracking * scale;
|
||||
line++;
|
||||
check_caret(caret, line-drawstart, cursor, scale, usecolor);
|
||||
} else if (isspace(*line)) {
|
||||
sdrawCharacter(font->Characters[*line], cursor, scale, usecolor);
|
||||
cursor.Y -= scale * font->linegap;
|
||||
sdrawCharacter(use_font->Characters[*line], cursor, scale, usecolor);
|
||||
cursor.Y -= scale * use_font->linegap;
|
||||
cursor.X = pos.X;
|
||||
line++;
|
||||
check_caret(caret, line-drawstart, cursor, scale, usecolor);
|
||||
|
@ -385,23 +376,23 @@ int renderText(const char *text, HMM_Vec2 pos, float scale, struct rgba color, f
|
|||
|
||||
while (!isspace(*line) && *line != '\0') {
|
||||
|
||||
wordWidth += font->Characters[*line].Advance * tracking * scale;
|
||||
wordWidth += use_font->Characters[*line].Advance * tracking * scale;
|
||||
line++;
|
||||
}
|
||||
|
||||
if (lw > 0 && (cursor.X + wordWidth - pos.X) >= lw) {
|
||||
cursor.X = pos.X;
|
||||
cursor.Y -= scale * font->linegap;
|
||||
cursor.Y -= scale * use_font->linegap;
|
||||
}
|
||||
|
||||
while (wordstart < line) {
|
||||
if (*wordstart == '\e')
|
||||
wordstart = esc_color(wordstart, &usecolor, color);
|
||||
|
||||
sdrawCharacter(font->Characters[*wordstart], HMM_AddV2(cursor, HMM_MulV2F((HMM_Vec2){1,-1},scale)), scale, (rgba){0,0,0,255});
|
||||
sdrawCharacter(font->Characters[*wordstart], cursor, scale, usecolor);
|
||||
sdrawCharacter(use_font->Characters[*wordstart], HMM_AddV2(cursor, HMM_MulV2F((HMM_Vec2){1,-1},scale)), scale, (rgba){0,0,0,255});
|
||||
sdrawCharacter(use_font->Characters[*wordstart], cursor, scale, usecolor);
|
||||
|
||||
cursor.X += font->Characters[*wordstart].Advance * tracking * scale;
|
||||
cursor.X += use_font->Characters[*wordstart].Advance * tracking * scale;
|
||||
wordstart++;
|
||||
check_caret(caret, wordstart-drawstart, cursor, scale, usecolor);
|
||||
}
|
||||
|
|
|
@ -28,9 +28,13 @@ struct sFont {
|
|||
sg_image texID;
|
||||
};
|
||||
|
||||
typedef struct sFont font;
|
||||
|
||||
void font_free(font *f);
|
||||
|
||||
void font_init();
|
||||
struct sFont *MakeFont(const char *fontfile, int height);
|
||||
void font_set(const char *path);
|
||||
void font_set(font *f);
|
||||
void sdrawCharacter(struct Character c, HMM_Vec2 cursor, float scale, struct rgba color);
|
||||
void text_settype(struct sFont *font);
|
||||
struct boundingbox text_bb(const char *text, float scale, float lw, float tracking);
|
||||
|
|
|
@ -8,12 +8,12 @@
|
|||
|
||||
#include "stb_ds.h"
|
||||
|
||||
static gameobject **gameobjects;
|
||||
|
||||
int go_count() { return arrlen(gameobjects); }
|
||||
|
||||
gameobject *body2go(cpBody *body) { return cpBodyGetUserData(body); }
|
||||
gameobject *shape2go(cpShape *shape) { return ((struct phys2d_shape *)cpShapeGetUserData(shape))->go; }
|
||||
gameobject *shape2go(cpShape *shape) {
|
||||
struct phys2d_shape *pshape = cpShapeGetUserData(shape);
|
||||
if (!pshape) return NULL;
|
||||
return pshape->go;
|
||||
}
|
||||
|
||||
HMM_Vec2 go_pos(gameobject *go)
|
||||
{
|
||||
|
@ -44,23 +44,6 @@ HMM_Mat3 t_world2go(gameobject *go) { return HMM_InvGeneralM3(t_go2world(go)); }
|
|||
HMM_Mat4 t3d_go2world(gameobject *go) { return transform3d2mat(go2t3(go)); }
|
||||
HMM_Mat4 t3d_world2go(gameobject *go) { return HMM_InvGeneralM4(t3d_go2world(go)); }
|
||||
|
||||
gameobject *pos2gameobject(HMM_Vec2 pos, float give) {
|
||||
cpShape *hit = phys2d_query_pos(pos.cp);
|
||||
|
||||
if (hit)
|
||||
return shape2go(hit);
|
||||
|
||||
for (int i = 0; i < arrlen(gameobjects); i++) {
|
||||
if (!gameobjects[i]->body) continue;
|
||||
HMM_Vec2 gpos = go_pos(gameobjects[i]);
|
||||
float dist = HMM_DistV2(gpos,pos);
|
||||
|
||||
if (dist <= give) return gameobjects[i];
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
transform2d go2t(gameobject *go)
|
||||
{
|
||||
transform2d t;
|
||||
|
@ -72,17 +55,15 @@ transform2d go2t(gameobject *go)
|
|||
return t;
|
||||
}
|
||||
|
||||
unsigned int editor_cat = 1<<31;
|
||||
|
||||
void go_shape_apply(cpBody *body, cpShape *shape, gameobject *go) {
|
||||
cpShapeSetFriction(shape, go->f);
|
||||
cpShapeSetElasticity(shape, go->e);
|
||||
cpShapeSetFriction(shape, go->friction);
|
||||
cpShapeSetElasticity(shape, go->elasticity);
|
||||
cpShapeSetCollisionType(shape, (cpCollisionType)go);
|
||||
|
||||
cpShapeFilter filter;
|
||||
filter.group = (cpCollisionType)go;
|
||||
filter.categories = 1<<go->layer | editor_cat;
|
||||
filter.mask = category_masks[go->layer] | editor_cat;
|
||||
filter.categories = go->categories;
|
||||
filter.mask = go->mask;
|
||||
// filter.mask = CP_ALL_CATEGORIES;
|
||||
cpShapeSetFilter(shape, filter);
|
||||
|
||||
|
@ -105,18 +86,17 @@ void go_shape_moi(cpBody *body, cpShape *shape, gameobject *go) {
|
|||
}
|
||||
|
||||
void gameobject_apply(gameobject *go) {
|
||||
cpBodySetType(go->body, go->bodytype);
|
||||
YughSpam("Applying gameobject %p", go);
|
||||
cpBodySetType(go->body, go->phys);
|
||||
cpBodyEachShape(go->body, go_shape_apply, go);
|
||||
|
||||
if (go->bodytype == CP_BODY_TYPE_DYNAMIC) {
|
||||
if (go->phys == CP_BODY_TYPE_DYNAMIC) {
|
||||
cpBodySetMass(go->body, go->mass);
|
||||
cpBodySetMoment(go->body, 0.f);
|
||||
cpBodyEachShape(go->body, go_shape_moi, go);
|
||||
|
||||
if (cpBodyGetMoment(go->body) <= 0.f)
|
||||
cpBodySetMoment(go->body, 1.f);
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -124,7 +104,7 @@ static void velocityFn(cpBody *body, cpVect gravity, cpFloat damping, cpFloat dt
|
|||
{
|
||||
gameobject *go = body2go(body);
|
||||
cpVect pos = cpBodyGetPosition(body);
|
||||
HMM_Vec2 g = warp_force((HMM_Vec3){pos.x, pos.y, 0}, go->warp_filter).xy;
|
||||
HMM_Vec2 g = warp_force((HMM_Vec3){pos.x, pos.y, 0}, go->warp_mask).xy;
|
||||
if (!go) {
|
||||
cpBodyUpdateVelocity(body,g.cp,damping,dt);
|
||||
return;
|
||||
|
@ -149,40 +129,43 @@ gameobject *MakeGameobject() {
|
|||
gameobject *ngo = malloc(sizeof(*ngo));
|
||||
gameobject go = {
|
||||
.scale = (HMM_Vec3){1.f,1.f,1.f},
|
||||
.bodytype = CP_BODY_TYPE_STATIC,
|
||||
.phys = CP_BODY_TYPE_STATIC,
|
||||
.maxvelocity = INFINITY,
|
||||
.maxangularvelocity = INFINITY,
|
||||
.mass = 1.f,
|
||||
.next = -1,
|
||||
.drawlayer = 0,
|
||||
.shape_cbs = NULL,
|
||||
.damping = INFINITY,
|
||||
.timescale = 1.0,
|
||||
.ref = JS_UNDEFINED,
|
||||
.mask = ~0,
|
||||
.categories = 1,
|
||||
.warp_mask = ~0
|
||||
};
|
||||
|
||||
go.cbs.begin = JS_UNDEFINED;
|
||||
go.cbs.separate = JS_UNDEFINED;
|
||||
|
||||
go.body = cpSpaceAddBody(space, cpBodyNew(go.mass, 1.f));
|
||||
cpBodySetVelocityUpdateFunc(go.body, velocityFn);
|
||||
|
||||
*ngo = go;
|
||||
cpBodySetUserData(go.body, ngo);
|
||||
phys2d_setup_handlers(ngo);
|
||||
arrpush(gameobjects, ngo);
|
||||
return ngo;
|
||||
}
|
||||
|
||||
void rm_body_shapes(cpBody *body, cpShape *shape, void *data) {
|
||||
struct phys2d_shape *s = cpShapeGetUserData(shape);
|
||||
|
||||
if (s) {
|
||||
JS_FreeValue(js, s->ref);
|
||||
s->ref = JS_UNDEFINED;
|
||||
if (s->free)
|
||||
s->free(s->data);
|
||||
else
|
||||
free(s->data);
|
||||
}
|
||||
|
||||
cpShapeSetFilter(shape, CP_SHAPE_FILTER_NONE);
|
||||
|
||||
cpSpaceRemoveShape(space, shape);
|
||||
cpShapeFree(shape);
|
||||
}
|
||||
|
@ -193,22 +176,12 @@ void rm_body_constraints(cpBody *body, cpConstraint *constraint, void *data)
|
|||
}
|
||||
|
||||
void gameobject_free(gameobject *go) {
|
||||
arrfree(go->shape_cbs);
|
||||
go->ref = JS_UNDEFINED;
|
||||
cpBodyEachShape(go->body, rm_body_shapes, NULL);
|
||||
cpBodyEachConstraint(go->body, rm_body_constraints, NULL);
|
||||
cpSpaceRemoveBody(space, go->body);
|
||||
cpBodyFree(go->body);
|
||||
|
||||
go->body = NULL;
|
||||
|
||||
free(go);
|
||||
for (int i = arrlen(gameobjects)-1; i >= 0; i--) {
|
||||
if (gameobjects[i] == go) {
|
||||
arrdelswap(gameobjects,i);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void gameobject_setangle(gameobject *go, float angle) {
|
||||
|
@ -230,12 +203,5 @@ void body_draw_shapes_dbg(cpBody *body, cpShape *shape, void *data) {
|
|||
void gameobject_draw_debug(gameobject *go) {
|
||||
if (!go || !go->body) return;
|
||||
|
||||
cpVect pos = cpBodyGetPosition(go->body);
|
||||
cpBodyEachShape(go->body, body_draw_shapes_dbg, NULL);
|
||||
}
|
||||
|
||||
void gameobject_draw_debugs()
|
||||
{
|
||||
for (int i = 0; i < arrlen(gameobjects); i++)
|
||||
gameobject_draw_debug(gameobjects[i]);
|
||||
}
|
||||
|
|
|
@ -27,23 +27,21 @@
|
|||
}while(0)
|
||||
|
||||
struct gameobject {
|
||||
cpBodyType bodytype;
|
||||
cpBodyType phys;
|
||||
cpBody *body; /* NULL if this object is dead; has 2d position and rotation, relative to global 0 */
|
||||
HMM_Vec3 scale; /* local */
|
||||
int next;
|
||||
float mass;
|
||||
float f; /* friction */
|
||||
float e; /* elasticity */
|
||||
float friction;
|
||||
float elasticity;
|
||||
float damping;
|
||||
float timescale;
|
||||
float maxvelocity;
|
||||
float maxangularvelocity;
|
||||
unsigned int layer;
|
||||
cpShapeFilter filter;
|
||||
unsigned int warp_filter;
|
||||
// warpmask warpmask;
|
||||
struct phys_cbs cbs;
|
||||
struct shape_cb *shape_cbs;
|
||||
cpBitmask categories;
|
||||
cpBitmask mask;
|
||||
unsigned int warp_mask;
|
||||
JSValue ref;
|
||||
HMM_Mat4 world;
|
||||
float drawlayer;
|
||||
|
@ -67,7 +65,6 @@ struct gameobject {
|
|||
typedef struct gameobject gameobject;
|
||||
|
||||
gameobject *MakeGameobject();
|
||||
int go_count();
|
||||
void gameobject_apply(gameobject *go);
|
||||
void gameobject_free(gameobject *go);
|
||||
|
||||
|
@ -93,8 +90,6 @@ gameobject *shape2go(cpShape *shape);
|
|||
void go_shape_apply(cpBody *body, cpShape *shape, gameobject *go);
|
||||
|
||||
/* Tries a few methods to select a gameobject; if none is selected returns -1 */
|
||||
gameobject *pos2gameobject(HMM_Vec2 pos, float give);
|
||||
|
||||
void gameobject_draw_debug(gameobject *go);
|
||||
void gameobject_draw_debugs();
|
||||
#endif
|
||||
|
|
299
source/engine/gif_load.h
Normal file
299
source/engine/gif_load.h
Normal file
|
@ -0,0 +1,299 @@
|
|||
#ifndef GIF_LOAD_H
|
||||
#define GIF_LOAD_H
|
||||
|
||||
/** gif_load: A slim, fast and header-only GIF loader written in C.
|
||||
Original author: hidefromkgb (hidefromkgb@gmail.com)
|
||||
_________________________________________________________________________
|
||||
|
||||
This is free and unencumbered software released into the public domain.
|
||||
|
||||
Anyone is free to copy, modify, publish, use, compile, sell, or
|
||||
distribute this software, either in source code form or as a compiled
|
||||
binary, for any purpose, commercial or non-commercial, and by any means.
|
||||
|
||||
In jurisdictions that recognize copyright laws, the author or authors
|
||||
of this software dedicate any and all copyright interest in the
|
||||
software to the public domain. We make this dedication for the benefit
|
||||
of the public at large and to the detriment of our heirs and
|
||||
successors. We intend this dedication to be an overt act of
|
||||
relinquishment in perpetuity of all present and future rights to this
|
||||
software under copyright law.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
||||
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
OTHER DEALINGS IN THE SOFTWARE.
|
||||
_________________________________________________________________________
|
||||
**/
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
#include <stdint.h> /** imports uint8_t, uint16_t and uint32_t **/
|
||||
#ifndef GIF_MGET
|
||||
#include <stdlib.h>
|
||||
#define GIF_MGET(m,s,a,c) m = (uint8_t*)realloc((c)? 0 : m, (c)? s : 0UL);
|
||||
#endif
|
||||
#ifndef GIF_BIGE
|
||||
#define GIF_BIGE 0
|
||||
#endif
|
||||
#ifndef GIF_EXTR
|
||||
#define GIF_EXTR static
|
||||
#endif
|
||||
#define _GIF_SWAP(h) ((GIF_BIGE)? ((uint16_t)(h << 8) | (h >> 8)) : h)
|
||||
|
||||
#pragma pack(push, 1)
|
||||
struct GIF_WHDR { /** ======== frame writer info: ======== **/
|
||||
long xdim, ydim, clrs, /** global dimensions, palette size **/
|
||||
bkgd, tran, /** background index, transparent index **/
|
||||
intr, mode, /** interlace flag, frame blending mode **/
|
||||
frxd, fryd, frxo, fryo, /** current frame dimensions and offset **/
|
||||
time, ifrm, nfrm; /** delay, frame number, frame count **/
|
||||
uint8_t *bptr; /** frame pixel indices or metadata **/
|
||||
struct { /** [==== GIF RGB palette element: ====] **/
|
||||
uint8_t R, G, B; /** [color values - red, green, blue ] **/
|
||||
} *cpal; /** current palette **/
|
||||
};
|
||||
#pragma pack(pop)
|
||||
|
||||
enum {GIF_NONE = 0, GIF_CURR = 1, GIF_BKGD = 2, GIF_PREV = 3};
|
||||
|
||||
/** [ internal function, do not use ] **/
|
||||
static long _GIF_SkipChunk(uint8_t **buff, long size) {
|
||||
long skip;
|
||||
|
||||
for (skip = 2, ++size, ++(*buff); ((size -= skip) > 0) && (skip > 1);
|
||||
*buff += (skip = 1 + **buff));
|
||||
return size;
|
||||
}
|
||||
|
||||
/** [ internal function, do not use ] **/
|
||||
static long _GIF_LoadHeader(unsigned gflg, uint8_t **buff, void **rpal,
|
||||
unsigned fflg, long *size, long flen) {
|
||||
if (flen && (!(*buff += flen) || ((*size -= flen) <= 0)))
|
||||
return -2; /** v--[ 0x80: "palette is present" flag ]--, **/
|
||||
if (flen && (fflg & 0x80)) { /** local palette has priority | **/
|
||||
*rpal = *buff; /** [ 3L: 3 uint8_t color channels ]--, | **/
|
||||
*buff += (flen = 2 << (fflg & 7)) * 3L; /** <--| | **/
|
||||
return ((*size -= flen * 3L) > 0)? flen : -1; /** <--' | **/
|
||||
} /** no local palette found, checking for the global one | **/
|
||||
return (gflg & 0x80)? (2 << (gflg & 7)) : 0; /** <-----' **/
|
||||
}
|
||||
|
||||
/** [ internal function, do not use ] **/
|
||||
static long _GIF_LoadFrame(uint8_t **buff, long *size,
|
||||
uint8_t *bptr, uint8_t *blen) {
|
||||
typedef uint16_t GIF_H;
|
||||
const long GIF_HLEN = sizeof(GIF_H), /** to rid the scope of sizeof **/
|
||||
GIF_CLEN = 1 << 12; /** code table length: 4096 items **/
|
||||
GIF_H accu, mask; /** bit accumulator / bit mask **/
|
||||
long ctbl, iter, /** last code table index / index string iterator **/
|
||||
prev, curr, /** codes from the stream: previous / current **/
|
||||
ctsz, ccsz, /** code table bit sizes: min LZW / current **/
|
||||
bseq, bszc; /** counters: block sequence / bit size **/
|
||||
uint32_t *code = (uint32_t*)bptr - GIF_CLEN; /** code table pointer **/
|
||||
|
||||
/** preparing initial values **/
|
||||
if ((--(*size) <= GIF_HLEN) || !*++(*buff))
|
||||
return -4; /** unexpected end of the stream: insufficient size **/
|
||||
mask = (GIF_H)((1 << (ccsz = (ctsz = *(*buff - 1)) + 1)) - 1);
|
||||
if ((ctsz < 2) || (ctsz > 8))
|
||||
return -3; /** min LZW size is out of its nominal [2; 8] bounds **/
|
||||
if ((ctbl = (1L << ctsz)) != (mask & _GIF_SWAP(*(GIF_H*)(*buff + 1))))
|
||||
return -2; /** initial code is not equal to min LZW size **/
|
||||
for (curr = ++ctbl; curr; code[--curr] = 0); /** actual color codes **/
|
||||
|
||||
/** getting codes from stream (--size makes up for end-of-stream mark) **/
|
||||
for (--(*size), bszc = -ccsz, prev = curr = 0;
|
||||
((*size -= (bseq = *(*buff)++) + 1) >= 0) && bseq; *buff += bseq)
|
||||
for (; bseq > 0; bseq -= GIF_HLEN, *buff += GIF_HLEN)
|
||||
for (accu = (GIF_H)(_GIF_SWAP(*(GIF_H*)*buff)
|
||||
& ((bseq < GIF_HLEN)? ((1U << (8 * bseq)) - 1U) : ~0U)),
|
||||
curr |= accu << (ccsz + bszc), accu = (GIF_H)(accu >> -bszc),
|
||||
bszc += 8 * ((bseq < GIF_HLEN)? bseq : GIF_HLEN);
|
||||
bszc >= 0; bszc -= ccsz, prev = curr, curr = accu,
|
||||
accu = (GIF_H)(accu >> ccsz))
|
||||
if (((curr &= mask) & ~1L) == (1L << ctsz)) {
|
||||
if (~(ctbl = curr + 1) & 1) /** end-of-data code (ED). **/
|
||||
/** -1: no end-of-stream mark after ED; 1: decoded **/
|
||||
return (*((*buff += bseq + 1) - 1))? -1 : 1;
|
||||
mask = (GIF_H)((1 << (ccsz = ctsz + 1)) - 1);
|
||||
} /** ^- table drop code (TD). TD = 1 << ctsz, ED = TD + 1 **/
|
||||
else { /** single-pixel (SP) or multi-pixel (MP) code. **/
|
||||
if (ctbl < GIF_CLEN) { /** is the code table full? **/
|
||||
if ((ctbl == mask) && (ctbl < GIF_CLEN - 1)) {
|
||||
mask = (GIF_H)(mask + mask + 1);
|
||||
ccsz++; /** yes; extending **/
|
||||
} /** prev = TD? => curr < ctbl = prev **/
|
||||
code[ctbl] = (uint32_t)prev + (code[prev] & 0xFFF000);
|
||||
} /** appending SP / MP decoded pixels to the frame **/
|
||||
prev = (long)code[iter = (ctbl > curr)? curr : prev];
|
||||
if ((bptr += (prev = (prev >> 12) & 0xFFF)) > blen)
|
||||
continue; /** skipping pixels above frame capacity **/
|
||||
for (prev++; (iter &= 0xFFF) >> ctsz;
|
||||
*bptr-- = (uint8_t)((iter = (long)code[iter]) >> 24));
|
||||
(bptr += prev)[-prev] = (uint8_t)iter;
|
||||
if (ctbl < GIF_CLEN) { /** appending the code table **/
|
||||
if (ctbl == curr)
|
||||
*bptr++ = (uint8_t)iter;
|
||||
else if (ctbl < curr)
|
||||
return -5; /** wrong code in the stream **/
|
||||
code[ctbl++] += ((uint32_t)iter << 24) + 0x1000;
|
||||
}
|
||||
} /** 0: no ED before end-of-stream mark; -4: see above **/
|
||||
return (++(*size) >= 0)? 0 : -4; /** ^- N.B.: 0 error is recoverable **/
|
||||
}
|
||||
|
||||
/** _________________________________________________________________________
|
||||
The main loading function. Returns the total number of frames if the data
|
||||
includes proper GIF ending, and otherwise it returns the number of frames
|
||||
loaded per current call, multiplied by -1. So, the data may be incomplete
|
||||
and in this case the function can be called again when more data arrives,
|
||||
just remember to keep SKIP up to date.
|
||||
_________________________________________________________________________
|
||||
DATA: raw data chunk, may be partial
|
||||
SIZE: size of the data chunk that`s currently present
|
||||
GWFR: frame writer function, MANDATORY
|
||||
EAMF: metadata reader function, set to 0 if not needed
|
||||
ANIM: implementation-specific data (e.g. a structure or a pointer to it)
|
||||
SKIP: number of frames to skip before resuming
|
||||
**/
|
||||
GIF_EXTR long GIF_Load(void *data, long size,
|
||||
void (*gwfr)(void*, struct GIF_WHDR*),
|
||||
void (*eamf)(void*, struct GIF_WHDR*),
|
||||
void *anim, long skip) {
|
||||
const long GIF_BLEN = (1 << 12) * sizeof(uint32_t);
|
||||
const uint8_t GIF_EHDM = 0x21, /** extension header mark **/
|
||||
GIF_FHDM = 0x2C, /** frame header mark **/
|
||||
GIF_EOFM = 0x3B, /** end-of-file mark **/
|
||||
GIF_EGCM = 0xF9, /** extension: graphics control mark **/
|
||||
GIF_EAMM = 0xFF; /** extension: app metadata mark **/
|
||||
#pragma pack(push, 1)
|
||||
struct GIF_GHDR { /** ========== GLOBAL GIF HEADER: ========== **/
|
||||
uint8_t head[6]; /** 'GIF87a' / 'GIF89a' header signature **/
|
||||
uint16_t xdim, ydim; /** total image width, total image height **/
|
||||
uint8_t flgs; /** FLAGS:
|
||||
GlobalPlt bit 7 1: global palette exists
|
||||
0: local in each frame
|
||||
ClrRes bit 6-4 bits/channel = ClrRes+1
|
||||
[reserved] bit 3 0
|
||||
PixelBits bit 2-0 |Plt| = 2 * 2^PixelBits
|
||||
**/
|
||||
uint8_t bkgd, aspr; /** background color index, aspect ratio **/
|
||||
} *ghdr = (struct GIF_GHDR*)data;
|
||||
struct GIF_FHDR { /** ======= GIF FRAME MASTER HEADER: ======= **/
|
||||
uint16_t frxo, fryo; /** offset of this frame in a "full" image **/
|
||||
uint16_t frxd, fryd; /** frame width, frame height **/
|
||||
uint8_t flgs; /** FLAGS:
|
||||
LocalPlt bit 7 1: local palette exists
|
||||
0: global is used
|
||||
Interlaced bit 6 1: interlaced frame
|
||||
0: non-interlaced frame
|
||||
Sorted bit 5 usually 0
|
||||
[reserved] bit 4-3 [undefined]
|
||||
PixelBits bit 2-0 |Plt| = 2 * 2^PixelBits
|
||||
**/
|
||||
} *fhdr;
|
||||
struct GIF_EGCH { /** ==== [EXT] GRAPHICS CONTROL HEADER: ==== **/
|
||||
uint8_t flgs; /** FLAGS:
|
||||
[reserved] bit 7-5 [undefined]
|
||||
BlendMode bit 4-2 000: not set; static GIF
|
||||
001: leave result as is
|
||||
010: restore background
|
||||
011: restore previous
|
||||
1--: [undefined]
|
||||
UserInput bit 1 1: show frame till input
|
||||
0: default; ~99% of GIFs
|
||||
TransColor bit 0 1: got transparent color
|
||||
0: frame is fully opaque
|
||||
**/
|
||||
uint16_t time; /** delay in GIF time units; 1 unit = 10 ms **/
|
||||
uint8_t tran; /** transparent color index **/
|
||||
} *egch = 0;
|
||||
#pragma pack(pop)
|
||||
struct GIF_WHDR wtmp, whdr = {0};
|
||||
long desc, blen;
|
||||
uint8_t *buff;
|
||||
|
||||
/** checking if the stream is not empty and has a 'GIF8[79]a' signature,
|
||||
the data has sufficient size and frameskip value is non-negative **/
|
||||
if (!ghdr || (size <= (long)sizeof(*ghdr)) || (*(buff = ghdr->head) != 71)
|
||||
|| (buff[1] != 73) || (buff[2] != 70) || (buff[3] != 56) || (skip < 0)
|
||||
|| ((buff[4] != 55) && (buff[4] != 57)) || (buff[5] != 97) || !gwfr)
|
||||
return 0;
|
||||
|
||||
buff = (uint8_t*)(ghdr + 1) /** skipping the global header and palette **/
|
||||
+ _GIF_LoadHeader(ghdr->flgs, 0, 0, 0, 0, 0L) * 3L;
|
||||
if ((size -= buff - (uint8_t*)ghdr) <= 0)
|
||||
return 0;
|
||||
|
||||
whdr.xdim = _GIF_SWAP(ghdr->xdim);
|
||||
whdr.ydim = _GIF_SWAP(ghdr->ydim);
|
||||
for (whdr.bptr = buff, whdr.bkgd = ghdr->bkgd, blen = --size;
|
||||
(blen >= 0) && ((desc = *whdr.bptr++) != GIF_EOFM); /** sic: '>= 0' **/
|
||||
blen = _GIF_SkipChunk(&whdr.bptr, blen) - 1) /** count all frames **/
|
||||
if (desc == GIF_FHDM) {
|
||||
fhdr = (struct GIF_FHDR*)whdr.bptr;
|
||||
if (_GIF_LoadHeader(ghdr->flgs, &whdr.bptr, (void**)&whdr.cpal,
|
||||
fhdr->flgs, &blen, sizeof(*fhdr)) <= 0)
|
||||
break;
|
||||
whdr.frxd = _GIF_SWAP(fhdr->frxd);
|
||||
whdr.fryd = _GIF_SWAP(fhdr->fryd);
|
||||
whdr.frxo = (whdr.frxd > whdr.frxo)? whdr.frxd : whdr.frxo;
|
||||
whdr.fryo = (whdr.fryd > whdr.fryo)? whdr.fryd : whdr.fryo;
|
||||
whdr.ifrm++;
|
||||
}
|
||||
blen = whdr.frxo * whdr.fryo * (long)sizeof(*whdr.bptr);
|
||||
GIF_MGET(whdr.bptr, (unsigned long)(blen + GIF_BLEN + 2), anim, 1)
|
||||
whdr.nfrm = (desc != GIF_EOFM)? -whdr.ifrm : whdr.ifrm;
|
||||
for (whdr.bptr += GIF_BLEN, whdr.ifrm = -1; blen /** load all frames **/
|
||||
&& (skip < ((whdr.nfrm < 0)? -whdr.nfrm : whdr.nfrm)) && (size >= 0);
|
||||
size = (desc != GIF_EOFM)? ((desc != GIF_FHDM) || (skip > whdr.ifrm))?
|
||||
_GIF_SkipChunk(&buff, size) - 1 : size - 1 : -1)
|
||||
if ((desc = *buff++) == GIF_FHDM) { /** found a frame **/
|
||||
whdr.intr = !!((fhdr = (struct GIF_FHDR*)buff)->flgs & 0x40);
|
||||
*(void**)&whdr.cpal = (void*)(ghdr + 1); /** interlaced? -^ **/
|
||||
whdr.clrs = _GIF_LoadHeader(ghdr->flgs, &buff, (void**)&whdr.cpal,
|
||||
fhdr->flgs, &size, sizeof(*fhdr));
|
||||
if ((skip <= ++whdr.ifrm) && ((whdr.clrs <= 0)
|
||||
|| (_GIF_LoadFrame(&buff, &size,
|
||||
whdr.bptr, whdr.bptr + blen) < 0)))
|
||||
size = -(whdr.ifrm--) - 1; /** failed to load the frame **/
|
||||
else if (skip <= whdr.ifrm) {
|
||||
whdr.frxd = _GIF_SWAP(fhdr->frxd);
|
||||
whdr.fryd = _GIF_SWAP(fhdr->fryd);
|
||||
whdr.frxo = _GIF_SWAP(fhdr->frxo);
|
||||
whdr.fryo = _GIF_SWAP(fhdr->fryo);
|
||||
whdr.time = (egch)? _GIF_SWAP(egch->time) : 0;
|
||||
whdr.tran = (egch && (egch->flgs & 0x01))? egch->tran : -1;
|
||||
whdr.time = (egch && (egch->flgs & 0x02))? -whdr.time - 1
|
||||
: whdr.time;
|
||||
whdr.mode = (egch && !(egch->flgs & 0x10))?
|
||||
(egch->flgs & 0x0C) >> 2 : GIF_NONE;
|
||||
egch = 0;
|
||||
wtmp = whdr;
|
||||
gwfr(anim, &wtmp); /** passing the frame to the caller **/
|
||||
}
|
||||
}
|
||||
else if (desc == GIF_EHDM) { /** found an extension **/
|
||||
if (*buff == GIF_EGCM) /** graphics control ext. **/
|
||||
egch = (struct GIF_EGCH*)(buff + 1 + 1);
|
||||
else if ((*buff == GIF_EAMM) && eamf) { /** app metadata ext. **/
|
||||
wtmp = whdr;
|
||||
wtmp.bptr = buff + 1 + 1; /** just passing the raw chunk **/
|
||||
eamf(anim, &wtmp);
|
||||
}
|
||||
}
|
||||
whdr.bptr -= GIF_BLEN; /** for excess pixel codes ----v (here & above) **/
|
||||
GIF_MGET(whdr.bptr, (unsigned long)(blen + GIF_BLEN + 2), anim, 0)
|
||||
return (whdr.nfrm < 0)? (skip - whdr.ifrm - 1) : (whdr.ifrm + 1);
|
||||
}
|
||||
|
||||
#undef _GIF_SWAP
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif /** GIF_LOAD_H **/
|
|
@ -18,8 +18,4 @@ void touch_cancelled(sapp_touchpoint *touch, int n);
|
|||
void input_dropped_files(int n);
|
||||
void input_clipboard_paste(char *str);
|
||||
|
||||
const char *keyname_extd(int key);
|
||||
|
||||
void quit();
|
||||
|
||||
#endif
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -3,7 +3,121 @@
|
|||
|
||||
#include "quickjs/quickjs.h"
|
||||
#include "HandmadeMath.h"
|
||||
#include "dsp.h"
|
||||
#include <stdarg.h>
|
||||
|
||||
#define MIST_CFUNC_DEF(name, length, func1) { name, JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE | JS_PROP_ENUMERABLE, JS_DEF_CFUNC, 0, .u = { .func = { length, JS_CFUNC_generic, { .generic = func1 } } } }
|
||||
|
||||
#define MIST_FUNC_DEF(TYPE, FN, LEN) MIST_CFUNC_DEF(#FN, LEN, js_##TYPE##_##FN)
|
||||
|
||||
#define GETFN(ID, ENTRY, TYPE) JSC_CCALL(ID##_##ENTRY, return TYPE##2js(js2##ID (this)->ENTRY))
|
||||
|
||||
#define JSC_SCALL(NAME, FN) JSC_CCALL(NAME, \
|
||||
const char *str = js2str(argv[0]); \
|
||||
FN ; \
|
||||
JS_FreeCString(js,str); \
|
||||
) \
|
||||
|
||||
#define JSC_SSCALL(NAME, FN) JSC_CCALL(NAME, \
|
||||
const char *str = js2str(argv[0]); \
|
||||
const char *str2 = js2str(argv[1]); \
|
||||
FN ; \
|
||||
JS_FreeCString(js,str2); \
|
||||
JS_FreeCString(js,str); \
|
||||
) \
|
||||
|
||||
#define MIST_CGETSET_BASE(name, fgetter, fsetter, props) { name, props, JS_DEF_CGETSET, 0, .u = { .getset = { .get = { .getter = fgetter }, .set = { .setter = fsetter } } } }
|
||||
#define MIST_CGETSET_DEF(name, fgetter, fsetter) MIST_CGETSET_BASE(name, fgetter, fsetter, JS_PROP_CONFIGURABLE | JS_PROP_ENUMERABLE)
|
||||
#define MIST_CGETET_HID(name, fgetter, fsetter) MIST_CGETSET_BASE(name, fgetter, fsetter, JS_PROP_CONFIGURABLE)
|
||||
#define MIST_GET(name, fgetter) { #fgetter , JS_PROP_CONFIGURABLE | JS_PROP_ENUMERABLE, JS_DEF_CGETSET, 0, .u = { .getset = { .get = { .getter = js_##name##_get_##fgetter } } } }
|
||||
|
||||
#define CGETSET_ADD_NAME(ID, ENTRY, NAME) MIST_CGETSET_DEF(#NAME, js_##ID##_get_##ENTRY, js_##ID##_set_##ENTRY)
|
||||
#define CGETSET_ADD(ID, ENTRY) MIST_CGETSET_DEF(#ENTRY, js_##ID##_get_##ENTRY, js_##ID##_set_##ENTRY)
|
||||
#define CGETSET_ADD_HID(ID, ENTRY) MIST_CGETSET_BASE(#ENTRY, js_##ID##_get_##ENTRY, js_##ID##_set_##ENTRY, JS_PROP_CONFIGURABLE)
|
||||
|
||||
#define JSC_CCALL(NAME, FN) JSValue js_##NAME (JSContext *js, JSValue this, int argc, JSValue *argv) { \
|
||||
JSValue ret = JS_UNDEFINED; \
|
||||
{FN;} \
|
||||
return ret; \
|
||||
} \
|
||||
|
||||
#define GETSETPAIR(ID, ENTRY, TYPE, FN) \
|
||||
JSValue js_##ID##_set_##ENTRY (JSContext *js, JSValue this, JSValue val) { \
|
||||
js2##ID (this)->ENTRY = js2##TYPE (val); \
|
||||
{FN;} \
|
||||
return JS_UNDEFINED; \
|
||||
} \
|
||||
\
|
||||
JSValue js_##ID##_get_##ENTRY (JSContext *js, JSValue this) { \
|
||||
return TYPE##2js(js2##ID (this)->ENTRY); \
|
||||
} \
|
||||
|
||||
#define JSC_GETSET(ID, ENTRY, TYPE) GETSETPAIR( ID , ENTRY , TYPE , ; )
|
||||
#define JSC_GETSET_APPLY(ID, ENTRY, TYPE) GETSETPAIR(ID, ENTRY, TYPE, ID##_apply(js2##ID (this));)
|
||||
#define JSC_GETSET_HOOK(ID, ENTRY) GETSETPAIR(ID, ENTRY, JSValue, ;)
|
||||
|
||||
#define JSC_GETSET_GLOBAL(ENTRY, TYPE) \
|
||||
JSValue js_global_set_##ENTRY (JSContext *js, JSValue this, JSValue val) { \
|
||||
ENTRY = js2##TYPE (val); \
|
||||
return JS_UNDEFINED; \
|
||||
} \
|
||||
\
|
||||
JSValue js_global_get_##ENTRY (JSContext *js, JSValue this) { \
|
||||
return TYPE##2js(ENTRY); \
|
||||
} \
|
||||
|
||||
#define JSC_GETSET_BODY(ENTRY, CPENTRY, TYPE) \
|
||||
JSValue js_gameobject_set_##ENTRY (JSContext *js, JSValue this, JSValue val) { \
|
||||
cpBody *b = js2gameobject(this)->body; \
|
||||
cpBodySet##CPENTRY (b, js2##TYPE (val)); \
|
||||
return JS_UNDEFINED; \
|
||||
} \
|
||||
\
|
||||
JSValue js_gameobject_get_##ENTRY (JSContext *js, JSValue this) { \
|
||||
cpBody *b = js2gameobject(this)->body; \
|
||||
return TYPE##2js (cpBodyGet##CPENTRY (b)); \
|
||||
} \
|
||||
|
||||
#define JSC_GET(ID, ENTRY, TYPE) \
|
||||
JSValue js_##ID##_get_##ENTRY (JSContext *js, JSValue this) { \
|
||||
return TYPE##2js(js2##ID (this)->ENTRY); } \
|
||||
|
||||
#define QJSCLASS(TYPE)\
|
||||
static JSClassID js_##TYPE##_id;\
|
||||
static void js_##TYPE##_finalizer(JSRuntime *rt, JSValue val){\
|
||||
TYPE *n = JS_GetOpaque(val, js_##TYPE##_id);\
|
||||
YughSpam("Freeing " #TYPE " at %p", n); \
|
||||
TYPE##_free(n);}\
|
||||
static JSClassDef js_##TYPE##_class = {\
|
||||
#TYPE,\
|
||||
.finalizer = js_##TYPE##_finalizer,\
|
||||
};\
|
||||
static TYPE *js2##TYPE (JSValue val) { return JS_GetOpaque(val,js_##TYPE##_id); }\
|
||||
static JSValue TYPE##2js(TYPE *n) { \
|
||||
JSValue j = JS_NewObjectClass(js,js_##TYPE##_id);\
|
||||
YughSpam("Created " #TYPE " at %p", n); \
|
||||
JS_SetOpaque(j,n);\
|
||||
return j; }\
|
||||
\
|
||||
static JSValue js_##TYPE##_memid (JSContext *js, JSValue this) { return str2js("%p", js2##TYPE(this)); } \
|
||||
|
||||
#define QJSGLOBALCLASS(NAME) \
|
||||
JSValue NAME = JS_NewObject(js); \
|
||||
JS_SetPropertyFunctionList(js, NAME, js_##NAME##_funcs, countof(js_##NAME##_funcs)); \
|
||||
JS_SetPropertyStr(js, globalThis, #NAME, NAME); \
|
||||
|
||||
#define QJSCLASSPREP(TYPE) \
|
||||
JS_NewClassID(&js_##TYPE##_id);\
|
||||
JS_NewClass(JS_GetRuntime(js), js_##TYPE##_id, &js_##TYPE##_class);\
|
||||
|
||||
/* Defines a class and uses its function list as its prototype */
|
||||
#define QJSCLASSPREP_FUNCS(TYPE) \
|
||||
QJSCLASSPREP(TYPE); \
|
||||
JSValue TYPE##_proto = JS_NewObject(js); \
|
||||
JS_SetPropertyFunctionList(js, TYPE##_proto, js_##TYPE##_funcs, countof(js_##TYPE##_funcs)); \
|
||||
JS_SetPropertyStr(js, TYPE##_proto, "memid", JS_NewCFunction(js, &js_##TYPE##_memid, "memid", 0)); \
|
||||
JS_SetClassProto(js, js_##TYPE##_id, TYPE##_proto); \
|
||||
|
||||
#define countof(x) (sizeof(x)/sizeof((x)[0]))
|
||||
|
||||
void ffi_load();
|
||||
void ffi_stop();
|
||||
|
@ -18,8 +132,7 @@ int js_print_exception(JSValue v);
|
|||
struct rgba js2color(JSValue v);
|
||||
double js2number(JSValue v);
|
||||
JSValue number2js(double g);
|
||||
JSValue int2js(int i);
|
||||
JSValue str2js(const char *c);
|
||||
JSValue str2js(const char *c, ...);
|
||||
|
||||
void nota_int(char *blob);
|
||||
|
||||
|
|
7833
source/engine/miniz.c
Normal file
7833
source/engine/miniz.c
Normal file
File diff suppressed because it is too large
Load diff
1422
source/engine/miniz.h
Normal file
1422
source/engine/miniz.h
Normal file
File diff suppressed because it is too large
Load diff
|
@ -80,7 +80,8 @@ void particle_init()
|
|||
|
||||
par_bind.vertex_buffers[1] = sg_make_buffer(&(sg_buffer_desc){
|
||||
.data = (sg_range){.ptr = circleverts, .size = sizeof(float)*8},
|
||||
.usage = SG_USAGE_IMMUTABLE
|
||||
.usage = SG_USAGE_IMMUTABLE,
|
||||
.label = "particle quater buffer"
|
||||
});
|
||||
|
||||
par_bind.fs.samplers[0] = sg_make_sampler(&(sg_sampler_desc){});
|
||||
|
@ -99,7 +100,7 @@ emitter *make_emitter() {
|
|||
sampler_add(&e->color, 0, (HMM_Vec4){1,1,1,1});
|
||||
e->scale = 1;
|
||||
e->speed = 20;
|
||||
e->texture = texture_from_file("glass_chunk2.gif");
|
||||
e->texture = NULL;
|
||||
arrpush(emitters,e);
|
||||
return e;
|
||||
}
|
||||
|
@ -166,12 +167,12 @@ void parallel_pv(emitter *e, struct scheduler *sched, struct sched_task_partitio
|
|||
s = lerp(p->time/e->grow_for, 0, p->scale);
|
||||
else if (p->time > (p->life - e->shrink_for))
|
||||
s = lerp((p->time-(p->life-e->shrink_for))/e->shrink_for, p->scale, 0);
|
||||
pv[i].scale = HMM_ScaleV2(tex_get_dimensions(e->texture), s);
|
||||
pv[i].scale = HMM_ScaleV2((HMM_Vec2){e->texture->width,e->texture->height}, s);
|
||||
pv[i].color = vec2rgba(p->color);
|
||||
}
|
||||
}
|
||||
|
||||
void emitters_draw()
|
||||
void emitters_draw(HMM_Mat4 *proj)
|
||||
{
|
||||
if (arrlen(emitters) == 0) return;
|
||||
int draw_count = 0;
|
||||
|
@ -188,7 +189,7 @@ void emitters_draw()
|
|||
}
|
||||
|
||||
sg_apply_pipeline(par_pipe);
|
||||
sg_apply_uniforms(SG_SHADERSTAGE_VS, 0, SG_RANGE_REF(projection));
|
||||
sg_apply_uniforms(SG_SHADERSTAGE_VS, 0, SG_RANGE_REF(*proj));
|
||||
sg_apply_bindings(&par_bind);
|
||||
sg_draw(0, 4, draw_count);
|
||||
}
|
||||
|
|
|
@ -70,7 +70,7 @@ void stop_emitter(emitter *e);
|
|||
|
||||
void emitter_emit(emitter *e, int count);
|
||||
void emitters_step(double dt);
|
||||
void emitters_draw();
|
||||
void emitters_draw(HMM_Mat4 *proj);
|
||||
void emitter_step(emitter *e, double dt);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -24,8 +24,13 @@
|
|||
#include "sokol/sokol_gfx.h"
|
||||
#include "sokol_gfx_ext.h"
|
||||
|
||||
#include "crt.sglsl.h"
|
||||
|
||||
#include "msf_gif.h"
|
||||
|
||||
HMM_Vec2 campos = {0,0};
|
||||
float camzoom = 1;
|
||||
|
||||
static struct {
|
||||
sg_swapchain swap;
|
||||
sg_pipeline pipe;
|
||||
|
@ -35,6 +40,12 @@ static struct {
|
|||
sg_image depth;
|
||||
} sg_gif;
|
||||
|
||||
static struct {
|
||||
sg_pipeline pipe;
|
||||
sg_bindings bind;
|
||||
sg_shader shader;
|
||||
} sg_crt;
|
||||
|
||||
static struct {
|
||||
int w;
|
||||
int h;
|
||||
|
@ -110,143 +121,101 @@ void capture_screen(int x, int y, int w, int h, const char *path)
|
|||
|
||||
#include "HandmadeMath.h"
|
||||
|
||||
int renderMode = LIT;
|
||||
|
||||
struct shader *spriteShader = NULL;
|
||||
struct shader *wireframeShader = NULL;
|
||||
struct shader *animSpriteShader = NULL;
|
||||
static struct shader *textShader;
|
||||
|
||||
struct rgba editorClearColor = {35,60,92,255};
|
||||
|
||||
float shadowLookahead = 8.5f;
|
||||
|
||||
struct rgba gridSmallColor = {
|
||||
.r = 255 * 0.35f,
|
||||
.g = 255,
|
||||
.b = 255 * 0.9f
|
||||
};
|
||||
|
||||
struct rgba gridBigColor = {
|
||||
.r = 255 * 0.92f,
|
||||
.g = 255 * 0.92f,
|
||||
.b = 255 * 0.68f
|
||||
};
|
||||
|
||||
float gridScale = 500.f;
|
||||
float smallGridUnit = 1.f;
|
||||
float bigGridUnit = 10.f;
|
||||
float gridSmallThickness = 2.f;
|
||||
float gridBigThickness = 7.f;
|
||||
float gridOpacity = 0.3f;
|
||||
|
||||
// Debug render modes
|
||||
bool renderGizmos = false;
|
||||
bool showGrid = true;
|
||||
bool debugDrawPhysics = false;
|
||||
bool renderNav = false;
|
||||
|
||||
// Lighting effect flags
|
||||
bool renderAO = true;
|
||||
bool renderDynamicShadows = true;
|
||||
bool renderRefraction = true;
|
||||
bool renderReflection = true;
|
||||
|
||||
///// for editing
|
||||
struct gameobject *selectedobject = NULL;
|
||||
char objectName[200] = {'\0'}; // object name buffer
|
||||
|
||||
sg_image ddimg;
|
||||
|
||||
void debug_draw_phys(int draw) {
|
||||
debugDrawPhysics = draw;
|
||||
}
|
||||
|
||||
void opengl_rendermode(enum RenderMode r) {
|
||||
renderMode = r;
|
||||
}
|
||||
|
||||
sg_pipeline mainpip;
|
||||
sg_pass_action pass_action = {0};
|
||||
|
||||
static struct {
|
||||
sg_pass_action pass_action;
|
||||
|
||||
sg_pass pass;
|
||||
sg_pipeline pipe;
|
||||
sg_shader shader;
|
||||
} sg_shadow;
|
||||
|
||||
|
||||
void trace_make_image(const sg_image_desc *d, sg_image id, void *data)
|
||||
{
|
||||
YughSpam("Made image %s.", d->label);
|
||||
}
|
||||
|
||||
void trace_init_image(sg_image id, const sg_image_desc *d, void *data)
|
||||
{
|
||||
YughSpam("Init image %s", d->label);
|
||||
}
|
||||
|
||||
void trace_make_shader(const sg_shader_desc *d, sg_shader id, void *data)
|
||||
{
|
||||
YughSpam("Making shader %s", d->label);
|
||||
if (sg_query_shader_state(id) == SG_RESOURCESTATE_FAILED)
|
||||
YughError("FAILED MAKING A SHADER: %s\n%s\n%s", d->label);
|
||||
}
|
||||
|
||||
void trace_fail_shader(sg_shader id, void *data)
|
||||
{
|
||||
YughError("Shader %u did not compile.", id);
|
||||
}
|
||||
|
||||
void trace_destroy_shader(sg_shader id, void *data)
|
||||
{
|
||||
YughSpam("Destroyed shader %u.", id);
|
||||
}
|
||||
|
||||
void trace_fail_image(sg_image id, void *data)
|
||||
{
|
||||
sg_image_desc desc = sg_query_image_desc(id);
|
||||
YughError("Failed to make image %u %s", id, desc.label);
|
||||
}
|
||||
|
||||
void trace_make_pipeline(const sg_pipeline_desc *d, sg_pipeline id, void *data)
|
||||
{
|
||||
YughSpam("Making pipeline %u [%s].", id, d->label);
|
||||
}
|
||||
|
||||
void trace_apply_pipeline(sg_pipeline pip, void *data)
|
||||
{
|
||||
YughSpam("Applying pipeline %u %s.", pip, sg_query_pipeline_desc(pip).label);
|
||||
}
|
||||
|
||||
void trace_fail_pipeline(sg_pipeline pip, void *data)
|
||||
{
|
||||
YughError("Failed pipeline %s", sg_query_pipeline_desc(pip).label);
|
||||
}
|
||||
|
||||
void trace_make_attachments(const sg_attachment_desc *d, sg_attachments result, void *data)
|
||||
{
|
||||
YughSpam("Making attachments %s", "IMPLEMENT");
|
||||
// YughSpam("Applying pipeline %u %s.", pip, sg_query_pipeline_desc(pip).label);
|
||||
}
|
||||
|
||||
void trace_begin_pass(sg_pass pass, const sg_pass_action *action, void *data)
|
||||
{
|
||||
YughSpam("Begin pass %s", pass.label);
|
||||
// YughSpam("Begin pass %s", pass.label);
|
||||
}
|
||||
|
||||
#define SG_TRACE_SET(NAME) \
|
||||
void trace_alloc_##NAME (sg_##NAME id, void *data) \
|
||||
{ \
|
||||
sg_##NAME##_desc desc = sg_query_##NAME##_desc(id); \
|
||||
YughSpam("Alloc " #NAME " %d [%s]", id, desc.label); \
|
||||
} \
|
||||
\
|
||||
void trace_dealloc_##NAME(sg_##NAME id, void *data) \
|
||||
{ \
|
||||
sg_##NAME##_desc desc = sg_query_##NAME##_desc(id); \
|
||||
YughSpam("Dealloc " #NAME " %d [%s]", id, desc.label); \
|
||||
} \
|
||||
\
|
||||
void trace_make_##NAME(sg_##NAME##_desc *desc, void *data) \
|
||||
{ \
|
||||
YughSpam("Make " #NAME " [%s]", desc->label); \
|
||||
} \
|
||||
\
|
||||
void trace_destroy_##NAME(sg_##NAME id, void *data) \
|
||||
{ \
|
||||
sg_##NAME##_desc desc = sg_query_##NAME##_desc(id); \
|
||||
YughSpam("Destroy " #NAME " %d [%s]", id, desc.label); \
|
||||
} \
|
||||
\
|
||||
void trace_init_##NAME(sg_##NAME id, sg_##NAME##_desc *desc, void *data) \
|
||||
{ \
|
||||
YughSpam("Init " #NAME " %d [%s]", id, desc->label); \
|
||||
} \
|
||||
\
|
||||
void trace_uninit_##NAME(sg_##NAME id, void *data) \
|
||||
{ \
|
||||
sg_##NAME##_desc desc = sg_query_##NAME##_desc(id); \
|
||||
YughSpam("Init " #NAME " %d [%s]", id, desc.label); \
|
||||
} \
|
||||
\
|
||||
void trace_fail_##NAME(sg_##NAME id, void *data) \
|
||||
{ \
|
||||
sg_##NAME##_desc desc = sg_query_##NAME##_desc(id); \
|
||||
YughError("Failed " #NAME " %d: %s", id, desc.label); \
|
||||
} \
|
||||
|
||||
SG_TRACE_SET(buffer)
|
||||
SG_TRACE_SET(image)
|
||||
SG_TRACE_SET(sampler)
|
||||
SG_TRACE_SET(shader)
|
||||
SG_TRACE_SET(pipeline)
|
||||
SG_TRACE_SET(attachments)
|
||||
|
||||
#define SG_HOOK_SET(NAME) \
|
||||
.alloc_##NAME = trace_alloc_##NAME, \
|
||||
.dealloc_##NAME = trace_dealloc_##NAME, \
|
||||
.init_##NAME = trace_init_##NAME, \
|
||||
.uninit_##NAME = trace_uninit_##NAME, \
|
||||
.fail_##NAME = trace_fail_##NAME, \
|
||||
.destroy_##NAME = trace_destroy_##NAME, \
|
||||
.make_##NAME = trace_make_##NAME \
|
||||
|
||||
void trace_append_buffer(sg_buffer id, sg_range *data, void *user)
|
||||
{
|
||||
sg_buffer_desc desc = sg_query_buffer_desc(id);
|
||||
// YughSpam("Appending buffer %d [%s]", id, desc.label);
|
||||
}
|
||||
|
||||
static sg_trace_hooks hooks = {
|
||||
.fail_shader = trace_fail_shader,
|
||||
.make_shader = trace_make_shader,
|
||||
.destroy_shader = trace_destroy_shader,
|
||||
.fail_image = trace_fail_image,
|
||||
.make_image = trace_make_image,
|
||||
.init_image = trace_init_image,
|
||||
.make_pipeline = trace_make_pipeline,
|
||||
.fail_pipeline = trace_fail_pipeline,
|
||||
.apply_pipeline = trace_apply_pipeline,
|
||||
.begin_pass = trace_begin_pass,
|
||||
.make_attachments = trace_make_attachments,
|
||||
SG_HOOK_SET(buffer),
|
||||
SG_HOOK_SET(image),
|
||||
SG_HOOK_SET(shader),
|
||||
SG_HOOK_SET(sampler),
|
||||
SG_HOOK_SET(pipeline),
|
||||
SG_HOOK_SET(attachments),
|
||||
.append_buffer = trace_append_buffer
|
||||
};
|
||||
|
||||
void render_init() {
|
||||
|
@ -285,7 +254,6 @@ void render_init() {
|
|||
.label = "gif pipe",
|
||||
});
|
||||
|
||||
#if defined SOKOL_GLCORE33 || defined SOKOL_GLES3
|
||||
float crt_quad[] = {
|
||||
-1, 1, 0, 1,
|
||||
-1, -1, 0, 0,
|
||||
|
@ -294,16 +262,7 @@ void render_init() {
|
|||
1, -1, 1, 0,
|
||||
1, 1, 1, 1
|
||||
};
|
||||
#else
|
||||
float crt_quad[] = {
|
||||
-1, 1, 0, 0,
|
||||
-1, -1, 0, 1,
|
||||
1, -1, 1, 1,
|
||||
-1, 1, 0, 0,
|
||||
1, -1, 1, 1,
|
||||
1, 1, 1, 0
|
||||
};
|
||||
#endif
|
||||
|
||||
float gif_quad[] = {
|
||||
-1, 1, 0, 1,
|
||||
-1, -1, 0, 0,
|
||||
|
@ -316,78 +275,35 @@ void render_init() {
|
|||
sg_gif.bind.vertex_buffers[0] = sg_make_buffer(&(sg_buffer_desc){
|
||||
.size = sizeof(gif_quad),
|
||||
.data = gif_quad,
|
||||
.label = "gif vert buffer",
|
||||
});
|
||||
sg_gif.bind.fs.samplers[0] = sg_make_sampler(&(sg_sampler_desc){});
|
||||
|
||||
/*
|
||||
sg_image_desc shadow_desc = {
|
||||
.render_target = true,
|
||||
.width = 1024,
|
||||
.height = 1024,
|
||||
.pixel_format = SG_PIXELFORMAT_R32F,
|
||||
};
|
||||
sg_image depth_img = sg_make_image(&shadow_desc);
|
||||
shadow_desc.pixel_format = sapp_depth_format();
|
||||
ddimg = sg_make_image(&shadow_desc);
|
||||
|
||||
sg_shadow.pass = sg_make_pass(&(sg_pass_desc){
|
||||
.color_attachments[0].image = depth_img,
|
||||
.depth_stencil_attachment.image = ddimg,
|
||||
});
|
||||
|
||||
sg_shadow.pass_action = (sg_pass_action) {
|
||||
.colors[0] = { .action=SG_ACTION_CLEAR, .value = {1,1,1,1} } };
|
||||
|
||||
sg_shadow.shader = sg_make_shader(shadow_shader_desc(sg_query_backend()));
|
||||
|
||||
sg_shadow.pipe = sg_make_pipeline(&(sg_pipeline_desc){
|
||||
.shader = sg_shadow.shader,
|
||||
sg_crt.shader = sg_make_shader(crt_shader_desc(sg_query_backend()));
|
||||
sg_crt.pipe = sg_make_pipeline(&(sg_pipeline_desc){
|
||||
.shader = sg_crt.shader,
|
||||
.layout = {
|
||||
.attrs = {
|
||||
[0].format = SG_VERTEXFORMAT_FLOAT3,
|
||||
[0].format = SG_VERTEXFORMAT_FLOAT2,
|
||||
[1].format = SG_VERTEXFORMAT_FLOAT2
|
||||
}
|
||||
},
|
||||
.depth = {
|
||||
.compare = SG_COMPAREFUNC_LESS_EQUAL,
|
||||
.write_enabled = true,
|
||||
.pixel_format = sapp_depth_format()
|
||||
},
|
||||
.colors[0].pixel_format = SG_PIXELFORMAT_R32F,
|
||||
.index_type = SG_INDEXTYPE_UINT16,
|
||||
.cull_mode = SG_CULLMODE_BACK,
|
||||
.primitive_type = SG_PRIMITIVETYPE_TRIANGLE_STRIP,
|
||||
});
|
||||
|
||||
*/
|
||||
sg_crt.bind.vertex_buffers[0] = sg_make_buffer(&(sg_buffer_desc){
|
||||
.size = sizeof(crt_quad),
|
||||
.type = SG_BUFFERTYPE_VERTEXBUFFER,
|
||||
.usage = SG_USAGE_IMMUTABLE,
|
||||
.data = SG_RANGE(crt_quad),
|
||||
|
||||
}
|
||||
|
||||
static cpBody *camera = NULL;
|
||||
void set_cam_body(cpBody *body) { camera = body; }
|
||||
cpVect cam_pos() { return camera ? cpBodyGetPosition(camera) : cpvzero; }
|
||||
|
||||
static float zoom = 1.f;
|
||||
float cam_zoom() { return zoom; }
|
||||
void add_zoom(float val) { zoom = val; }
|
||||
|
||||
HMM_Vec2 world2screen(HMM_Vec2 pos)
|
||||
{
|
||||
pos = HMM_SubV2(pos, HMM_V2(cam_pos().x, cam_pos().y));
|
||||
pos = HMM_ScaleV2(pos, 1.0/zoom);
|
||||
pos = HMM_AddV2(pos, HMM_ScaleV2(mainwin.size,0.5));
|
||||
return pos;
|
||||
}
|
||||
|
||||
HMM_Vec2 screen2world(HMM_Vec2 pos)
|
||||
{
|
||||
pos = HMM_ScaleV2(pos, 1/mainwin.dpi);
|
||||
pos = HMM_SubV2(pos, HMM_ScaleV2(mainwin.size, 0.5));
|
||||
pos = HMM_ScaleV2(pos, zoom);
|
||||
pos = HMM_AddV2(pos, HMM_V2(cam_pos().x, cam_pos().y));
|
||||
return pos;
|
||||
.label = "crt vert buffer",
|
||||
});
|
||||
}
|
||||
|
||||
HMM_Mat4 projection = {0.f};
|
||||
HMM_Mat4 hudproj = {0.f};
|
||||
HMM_Mat4 useproj = {0};
|
||||
|
||||
HMM_Vec3 dirl_pos = {4, 100, 20};
|
||||
|
||||
|
@ -398,8 +314,14 @@ HMM_Vec3 dirl_pos = {4, 100, 20};
|
|||
#define MODE_EXPAND 4
|
||||
#define MODE_FULL 5
|
||||
|
||||
void full_2d_pass(struct window *window)
|
||||
{
|
||||
void openglRender(struct window *window, gameobject *cam, float zoom) {
|
||||
sg_swapchain sch = sglue_swapchain();
|
||||
sg_begin_pass(&(sg_pass){
|
||||
.action = pass_action,
|
||||
.swapchain = sglue_swapchain(),
|
||||
.label = "window pass"
|
||||
});
|
||||
|
||||
HMM_Vec2 usesize = window->rendersize;
|
||||
|
||||
switch(window->mode) {
|
||||
|
@ -427,70 +349,17 @@ void full_2d_pass(struct window *window)
|
|||
}
|
||||
|
||||
// 2D projection
|
||||
cpVect pos = cam_pos();
|
||||
campos = go_pos(cam);
|
||||
camzoom = zoom;
|
||||
|
||||
projection = HMM_Orthographic_LH_NO(
|
||||
pos.x - zoom * usesize.x / 2,
|
||||
pos.x + zoom * usesize.x / 2,
|
||||
pos.y - zoom * usesize.y / 2,
|
||||
pos.y + zoom * usesize.y / 2, -10000.f, 10000.f);
|
||||
campos.x - camzoom * usesize.x / 2,
|
||||
campos.x + camzoom * usesize.x / 2,
|
||||
campos.y - camzoom * usesize.y / 2,
|
||||
campos.y + camzoom * usesize.y / 2, -10000.f, 10000.f);
|
||||
|
||||
hudproj = HMM_Orthographic_LH_ZO(0, usesize.x, 0, usesize.y, -1.f, 1.f);
|
||||
|
||||
sprite_draw_all();
|
||||
model_draw_all();
|
||||
script_evalf("prosperon.draw();");
|
||||
emitters_draw();
|
||||
|
||||
//// DEBUG
|
||||
if (debugDrawPhysics) {
|
||||
gameobject_draw_debugs();
|
||||
script_evalf("prosperon.debug();");
|
||||
}
|
||||
|
||||
debug_flush(&projection);
|
||||
text_flush(&projection);
|
||||
|
||||
////// TEXT && GUI
|
||||
debug_nextpass();
|
||||
script_evalf("prosperon.gui();");
|
||||
debug_flush(&hudproj);
|
||||
text_flush(&hudproj);
|
||||
sprite_flush();
|
||||
}
|
||||
|
||||
void full_3d_pass(struct window *window)
|
||||
{
|
||||
HMM_Mat4 model = HMM_M4D(1.f);
|
||||
float scale = 0.08;
|
||||
model = HMM_MulM4(model, HMM_Scale((HMM_Vec3){scale,scale,scale}));
|
||||
|
||||
// Shadow pass
|
||||
// sg_begin_pass(sg_shadow.pass, &sg_shadow.pass_action);
|
||||
// sg_apply_pipeline(sg_shadow.pipe);
|
||||
|
||||
HMM_Mat4 light_proj = HMM_Orthographic_RH_ZO(-100.f, 100.f, -100.f, 100.f, 1.f, 100.f);
|
||||
HMM_Mat4 light_view = HMM_LookAt_RH(dirl_pos, (HMM_Vec3){0,0,0}, (HMM_Vec3){0,1,0});
|
||||
|
||||
HMM_Mat4 lsm = HMM_MulM4(light_proj, light_view);
|
||||
|
||||
HMM_Mat4 subo[2];
|
||||
subo[0] = lsm;
|
||||
subo[1] = model;
|
||||
|
||||
sg_apply_uniforms(SG_SHADERSTAGE_VS, 0, SG_RANGE_REF(subo));
|
||||
}
|
||||
|
||||
void openglRender(struct window *window) {
|
||||
sg_swapchain sch = sglue_swapchain();
|
||||
sg_begin_pass(&(sg_pass){
|
||||
.action = pass_action,
|
||||
.swapchain = sglue_swapchain(),
|
||||
.label = "window pass"
|
||||
});
|
||||
full_2d_pass(window);
|
||||
sg_end_pass();
|
||||
|
||||
/* if (gif.rec && (apptime() - gif.timer) > gif.spf) {
|
||||
sg_begin_pass(&(sg_pass){
|
||||
.action = pass_action,
|
||||
|
@ -506,30 +375,8 @@ void openglRender(struct window *window) {
|
|||
msf_gif_frame(&gif_state, gif.buffer, gif.cpf, gif.depth, gif.w * -4);
|
||||
}
|
||||
*/
|
||||
|
||||
sg_commit();
|
||||
|
||||
debug_newframe();
|
||||
}
|
||||
|
||||
sg_shader sg_compile_shader(const char *v, const char *f, sg_shader_desc *d)
|
||||
{
|
||||
YughInfo("Making shader with %s and %s", v, f);
|
||||
char *vs = slurp_text(v, NULL);
|
||||
char *fs = slurp_text(f, NULL);
|
||||
|
||||
d->vs.source = vs;
|
||||
d->fs.source = fs;
|
||||
d->label = v;
|
||||
|
||||
sg_shader ret = sg_make_shader(d);
|
||||
|
||||
free(vs);
|
||||
free(fs);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
struct boundingbox cwh2bb(HMM_Vec2 c, HMM_Vec2 wh) {
|
||||
struct boundingbox bb = {
|
||||
.t = c.Y + wh.Y/2,
|
||||
|
|
|
@ -7,13 +7,13 @@
|
|||
#define SOKOL_GLES3
|
||||
#elif __WIN32
|
||||
#define SOKOL_D3D11
|
||||
#define SOKOL_WIN32_FORCE_MAIN
|
||||
#elif __APPLE__
|
||||
#define SOKOL_METAL
|
||||
#endif
|
||||
|
||||
#include "sokol/sokol_gfx.h"
|
||||
#include "HandmadeMath.h"
|
||||
#include "gameobject.h"
|
||||
|
||||
#define RGBA_MAX 255
|
||||
|
||||
|
@ -29,12 +29,7 @@ extern HMM_Vec3 dirl_pos;
|
|||
|
||||
extern HMM_Mat4 projection;
|
||||
extern HMM_Mat4 hudproj;
|
||||
|
||||
struct camera3d {
|
||||
|
||||
};
|
||||
|
||||
typedef struct camera3d camera3d;
|
||||
extern HMM_Mat4 useproj;
|
||||
|
||||
struct draw_p {
|
||||
float x;
|
||||
|
@ -52,24 +47,15 @@ enum RenderMode {
|
|||
};
|
||||
|
||||
void render_init();
|
||||
void openglRender(struct window *window);
|
||||
extern HMM_Vec2 campos;
|
||||
extern float camzoom;
|
||||
|
||||
void openglRender(struct window *window, gameobject *cam, float zoom);
|
||||
void opengl_rendermode(enum RenderMode r);
|
||||
|
||||
void openglInit3d(struct window *window);
|
||||
void openglRender3d(struct window *window, camera3d *camera);
|
||||
void capture_screen(int x, int y, int w, int h, const char *path);
|
||||
|
||||
void debug_draw_phys(int draw);
|
||||
|
||||
void set_cam_body(cpBody *body);
|
||||
cpVect cam_pos();
|
||||
float cam_zoom();
|
||||
void add_zoom(float val);
|
||||
HMM_Vec2 world2screen(HMM_Vec2 pos);
|
||||
HMM_Vec2 screen2world(HMM_Vec2 pos);
|
||||
|
||||
sg_shader sg_compile_shader(const char *v, const char *f, sg_shader_desc *d);
|
||||
|
||||
void gif_rec_start(int w, int h, int cpf, int bitdepth);
|
||||
void gif_rec_end(const char *path);
|
||||
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
#include "font.h"
|
||||
|
||||
#include <fcntl.h>
|
||||
#include "cdb.h"
|
||||
#include "miniz.h"
|
||||
|
||||
#ifndef __EMSCRIPTEN__
|
||||
#include <ftw.h>
|
||||
|
@ -40,8 +40,8 @@ struct dirent *c_dirent = NULL;
|
|||
|
||||
char pathbuf[MAXPATH + 1];
|
||||
|
||||
static struct cdb corecdb;
|
||||
static struct cdb game_cdb;
|
||||
static mz_zip_archive corecdb;
|
||||
static mz_zip_archive game_cdb;
|
||||
|
||||
int LOADED_GAME = 0;
|
||||
uint8_t *gamebuf;
|
||||
|
@ -49,7 +49,7 @@ uint8_t *gamebuf;
|
|||
static void response_cb(const sfetch_response_t *r)
|
||||
{
|
||||
if (r->fetched) {
|
||||
cdb_initf(&game_cdb, r->data.ptr, r->data.size);
|
||||
mz_zip_reader_init_mem(&game_cdb, r->data.ptr, r->data.size,0);
|
||||
LOADED_GAME = 1;
|
||||
}
|
||||
if (r->finished) {
|
||||
|
@ -78,7 +78,7 @@ void resources_init() {
|
|||
}
|
||||
});
|
||||
|
||||
cdb_initf(&corecdb, core_cdb, core_cdb_len);
|
||||
mz_zip_reader_init_mem(&corecdb, core_cdb, core_cdb_len, 0);
|
||||
}
|
||||
|
||||
char *get_filename_from_path(char *path, int extension) {
|
||||
|
@ -137,6 +137,12 @@ static int ls_ftw(const char *path, const struct stat *sb, int typeflag)
|
|||
return 0;
|
||||
}
|
||||
|
||||
time_t file_mod_secs(const char *file) {
|
||||
struct stat attr;
|
||||
stat(file, &attr);
|
||||
return attr.st_mtime;
|
||||
}
|
||||
|
||||
// TODO: Not reentrant
|
||||
char **ls(const char *path)
|
||||
{
|
||||
|
@ -154,6 +160,7 @@ char **ls(const char *path)
|
|||
#else
|
||||
void fill_extensions(char *paths, const char *path, const char *ext)
|
||||
{};
|
||||
char **ls(const char *path) { return NULL; }
|
||||
#endif
|
||||
|
||||
char *str_replace_ext(const char *s, const char *newext) {
|
||||
|
@ -166,32 +173,11 @@ char *str_replace_ext(const char *s, const char *newext) {
|
|||
return ret;
|
||||
}
|
||||
|
||||
FILE *path_open(const char *tag, const char *fmt, ...) {
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
vsnprintf(pathbuf, MAXPATH+1, fmt, args);
|
||||
va_end(args);
|
||||
|
||||
FILE *f = fopen(pathbuf, tag);
|
||||
return f;
|
||||
}
|
||||
|
||||
void *cdb_slurp(struct cdb *cdb, const char *file, size_t *size)
|
||||
{
|
||||
unsigned vlen, vpos;
|
||||
vpos = cdb_datapos(cdb);
|
||||
vlen = cdb_datalen(cdb);
|
||||
char *data = malloc(vlen+1);
|
||||
cdb_read(cdb, data, vlen, vpos);
|
||||
if (size) *size = vlen;
|
||||
return data;
|
||||
}
|
||||
|
||||
int fexists(const char *path)
|
||||
{
|
||||
int len = strlen(path);
|
||||
if (cdb_find(&game_cdb, path, len)) return 1;
|
||||
else if (cdb_find(&corecdb, path, len)) return 1;
|
||||
if (mz_zip_reader_locate_file(&game_cdb, path, NULL, 0) != -1) return 1;
|
||||
else if (mz_zip_reader_locate_file(&corecdb, path, NULL, 0) != -1) return 1;
|
||||
else if (!access(path, R_OK)) return 1;
|
||||
|
||||
return 0;
|
||||
|
@ -220,12 +206,13 @@ void *os_slurp(const char *file, size_t *size)
|
|||
|
||||
void *slurp_file(const char *filename, size_t *size)
|
||||
{
|
||||
void *ret;
|
||||
if (!access(filename, R_OK))
|
||||
return os_slurp(filename, size);
|
||||
else if (cdb_find(&game_cdb, filename, strlen(filename)))
|
||||
return cdb_slurp(&game_cdb, filename, size);
|
||||
else if (cdb_find(&corecdb, filename, strlen(filename)))
|
||||
return cdb_slurp(&corecdb, filename, size);
|
||||
else if (ret = mz_zip_reader_extract_file_to_heap(&game_cdb, filename, size, 0))
|
||||
return ret;
|
||||
else if (ret = mz_zip_reader_extract_file_to_heap(&corecdb, filename, size, 0))
|
||||
return ret;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
@ -304,58 +291,3 @@ int slurp_write(const char *txt, const char *filename, size_t len) {
|
|||
fclose(f);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifndef __EMSCRIPTEN__
|
||||
static struct cdb_make cdbm;
|
||||
|
||||
static const char *pack_ext[] = {".qoi", ".qoa", ".js", ".wav", ".mp3", ".png", ".sf2", ".midi", ".lvl", ".glsl", ".ttf", ".json", ".jso"};
|
||||
|
||||
static int ftw_pack(const char *path, const struct stat *sb, int flag)
|
||||
{
|
||||
if (flag != FTW_F) return 0;
|
||||
int pack = 0;
|
||||
char *ext = strrchr(path, '.');
|
||||
|
||||
if (!ext)
|
||||
return 0;
|
||||
|
||||
for (int i = 0; i < 13; i++) {
|
||||
if (!strcmp(ext, pack_ext[i])) {
|
||||
pack = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!pack) return 0;
|
||||
|
||||
size_t len;
|
||||
void *file = slurp_file(path, &len);
|
||||
cdb_make_add(&cdbm, &path[2], strlen(&path[2]), file, len);
|
||||
|
||||
free(file);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void pack_engine(const char *fname)
|
||||
{
|
||||
int fd;
|
||||
char *key, *va;
|
||||
unsigned klen, vlen;
|
||||
fd = creat(fname, O_RDWR);
|
||||
if (fd == -1) {
|
||||
YughError("Couldn't make file at %s.", fname);
|
||||
return;
|
||||
}
|
||||
cdb_make_start(&cdbm, fd);
|
||||
ftw(".", ftw_pack, 20);
|
||||
cdb_make_finish(&cdbm);
|
||||
close(fd);
|
||||
}
|
||||
#else
|
||||
void pack_engine(const char *fname){
|
||||
YughError("Cannot pack engine on a web build.");
|
||||
}
|
||||
|
||||
char **ls(const char *path) { return NULL; }
|
||||
#endif
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
#include <stdio.h>
|
||||
#include "stb_ds.h"
|
||||
#include "string.h"
|
||||
#include <time.h>
|
||||
|
||||
extern char *DATA_PATH;
|
||||
extern int LOADED_GAME;
|
||||
|
@ -13,10 +14,10 @@ char *get_filename_from_path(char *path, int extension);
|
|||
char *get_directory_from_path(char *path);
|
||||
char *str_replace_ext(const char *s, const char *newext);
|
||||
FILE *res_open(char *path, const char *tag);
|
||||
FILE *path_open(const char *tag, const char *fmt, ...);
|
||||
char **ls(const char *path);
|
||||
int cp(const char *p1, const char *p2);
|
||||
int fexists(const char *path);
|
||||
time_t file_mod_secs(const char *file);
|
||||
|
||||
char *dirname(const char *path);
|
||||
|
||||
|
@ -26,8 +27,6 @@ int slurp_write(const char *txt, const char *filename, size_t len);
|
|||
|
||||
char *seprint(char *fmt, ...);
|
||||
|
||||
void pack_engine(const char *fname);
|
||||
|
||||
static inline void *stbarrdup(void *mem, size_t size, int len) {
|
||||
void *out = NULL;
|
||||
arrsetlen(out, len);
|
||||
|
|
|
@ -1,22 +1,8 @@
|
|||
#include "script.h"
|
||||
|
||||
#include "log.h"
|
||||
#include "stdio.h"
|
||||
|
||||
#include "jsffi.h"
|
||||
#include "font.h"
|
||||
|
||||
#include "gameobject.h"
|
||||
|
||||
#include "ftw.h"
|
||||
|
||||
#include "stb_ds.h"
|
||||
|
||||
#include "sys/stat.h"
|
||||
#include "sys/types.h"
|
||||
#include "time.h"
|
||||
#include "resources.h"
|
||||
#include "input.h"
|
||||
|
||||
#include <stdarg.h>
|
||||
|
||||
|
@ -29,100 +15,40 @@ JSRuntime *rt = NULL;
|
|||
#define JS_EVAL_FLAGS JS_EVAL_FLAG_STRICT | JS_EVAL_FLAG_STRIP
|
||||
#endif
|
||||
|
||||
static struct {
|
||||
char *key;
|
||||
JSValue value;
|
||||
} *jsstrs = NULL;
|
||||
|
||||
JSValue jstr(const char *str)
|
||||
{
|
||||
int index = shgeti(jsstrs, str);
|
||||
if (index != -1) return jsstrs[index].value;
|
||||
|
||||
JSValue v = str2js(str);
|
||||
shput(jsstrs, str, v);
|
||||
return v;
|
||||
}
|
||||
|
||||
static int load_prefab(const char *fpath, const struct stat *sb, int typeflag) {
|
||||
if (typeflag != FTW_F)
|
||||
return 0;
|
||||
|
||||
if (!strcmp(".prefab", strrchr(fpath, '.')))
|
||||
script_dofile(fpath);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void script_startup() {
|
||||
rt = JS_NewRuntime();
|
||||
js = JS_NewContext(rt);
|
||||
|
||||
sh_new_arena(jsstrs);
|
||||
|
||||
ffi_load();
|
||||
|
||||
for (int i = 0; i < 100; i++)
|
||||
num_cache[i] = int2js(i);
|
||||
|
||||
script_dofile("scripts/engine.js");
|
||||
// jso_file("scripts/engine.js");
|
||||
size_t len;
|
||||
char *eng = slurp_text("scripts/engine.js", &len);
|
||||
JSValue v = script_eval("scripts/engine.js", eng);
|
||||
JS_FreeValue(js,v);
|
||||
free(eng);
|
||||
}
|
||||
|
||||
static int stopped = 0;
|
||||
void script_stop()
|
||||
{
|
||||
script_evalf("Event.notify('quit');");
|
||||
send_signal("quit",0,NULL);
|
||||
script_evalf("prosperon.quit();");
|
||||
#ifndef LEAK
|
||||
return;
|
||||
#endif
|
||||
printf("FREEING CONTEXT\n");
|
||||
ffi_stop();
|
||||
for (int i = 0; i < shlen(jsstrs); i++)
|
||||
JS_FreeValue(js,jsstrs[i].value);
|
||||
|
||||
#if LEAK
|
||||
JS_FreeContext(js);
|
||||
script_gc();
|
||||
JS_FreeRuntime(rt);
|
||||
#endif
|
||||
js = NULL;
|
||||
rt = NULL;
|
||||
}
|
||||
|
||||
void script_gc()
|
||||
{
|
||||
JS_RunGC(rt);
|
||||
}
|
||||
void script_gc() { JS_RunGC(rt); }
|
||||
|
||||
JSValue num_cache[100] = {0};
|
||||
|
||||
/*int js_print_exception(JSValue v) {
|
||||
void js_stacktrace() {
|
||||
#ifndef NDEBUG
|
||||
if (JS_IsException(v)) {
|
||||
JSValue exception = JS_GetException(js);
|
||||
|
||||
if (JS_IsNull(exception)) {
|
||||
JS_FreeValue(js,exception);
|
||||
return 0;
|
||||
}
|
||||
|
||||
JSValue val = JS_ToCStringJS_GetPropertyStr(js, exception, "stack");
|
||||
const char *name = JS_ToCString(js, JS_GetPropertyStr(js, exception, "name"));
|
||||
const char *msg = JS_ToCString(js, JS_GetPropertyStr(js, exception, "message"));
|
||||
const char *stack = JS_ToCString(js, val);
|
||||
YughLog(LOG_SCRIPT, LOG_ERROR, "%s :: %s\n%s", name, msg,stack);
|
||||
js_stacktrace();
|
||||
|
||||
JS_FreeCString(js, name);
|
||||
JS_FreeCString(js, msg);
|
||||
JS_FreeCString(js, stack);
|
||||
JS_FreeValue(js,val);
|
||||
JS_FreeValue(js,exception);
|
||||
|
||||
return 1;
|
||||
}
|
||||
script_evalf("console.stack();");
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
*/
|
||||
void script_run(const char *script, const char *file) {
|
||||
JSValue obj = JS_Eval(js, script, strlen(script), file, JS_EVAL_FLAGS);
|
||||
js_print_exception(obj);
|
||||
JS_FreeValue(js,obj);
|
||||
}
|
||||
|
||||
void script_evalf(const char *format, ...)
|
||||
|
@ -138,121 +64,16 @@ void script_evalf(const char *format, ...)
|
|||
JS_FreeValue(js,obj);
|
||||
}
|
||||
|
||||
uint8_t *script_compile(const char *file, size_t *len) {
|
||||
size_t file_len;
|
||||
char *script = slurp_text(file, &file_len);
|
||||
JSValue obj = JS_Eval(js, script, file_len, file, JS_EVAL_FLAG_COMPILE_ONLY | JS_EVAL_TYPE_GLOBAL | JS_EVAL_FLAGS);
|
||||
free(script);
|
||||
uint8_t *out = JS_WriteObject(js, len, obj, JS_WRITE_OBJ_BYTECODE);
|
||||
JS_FreeValue(js,obj);
|
||||
return out;
|
||||
}
|
||||
|
||||
JSValue script_run_bytecode(uint8_t *code, size_t len)
|
||||
JSValue script_eval(const char *file, const char *script)
|
||||
{
|
||||
JSValue b = JS_ReadObject(js, code, len, JS_READ_OBJ_BYTECODE);
|
||||
JSValue ret = JS_EvalFunction(js, b);
|
||||
js_print_exception(ret);
|
||||
JS_FreeValue(js,b);
|
||||
return ret;
|
||||
}
|
||||
|
||||
struct callee stacktrace_callee;
|
||||
|
||||
time_t file_mod_secs(const char *file) {
|
||||
struct stat attr;
|
||||
stat(file, &attr);
|
||||
return attr.st_mtime;
|
||||
}
|
||||
|
||||
void js_stacktrace() {
|
||||
#ifndef NDEBUG
|
||||
script_evalf("console.stack();");
|
||||
#endif
|
||||
}
|
||||
|
||||
void js_dump_stack() {
|
||||
js_stacktrace();
|
||||
}
|
||||
|
||||
int script_dofile(const char *file) {
|
||||
JSValue ret = script_runfile(file);
|
||||
JS_FreeValue(js,ret);
|
||||
return file_mod_secs(file);
|
||||
}
|
||||
|
||||
JSValue script_runjso(const uint8_t *buf, size_t len)
|
||||
{
|
||||
JSValue obj = JS_ReadObject(js, buf, len, JS_EVAL_FLAGS);
|
||||
JSValue ret = JS_EvalFunction(js, obj);
|
||||
js_print_exception(ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
time_t jso_file(const char *file)
|
||||
{
|
||||
size_t len;
|
||||
uint8_t *byte = slurp_file(file, &len);
|
||||
JSValue obj = JS_ReadObject(js, byte, len, JS_READ_OBJ_BYTECODE);
|
||||
JSValue ret = JS_EvalFunction(js, obj);
|
||||
js_print_exception(ret);
|
||||
JS_FreeValue(js,ret);
|
||||
JS_FreeValue(js,obj);
|
||||
free(byte);
|
||||
return file_mod_secs(file);
|
||||
}
|
||||
|
||||
JSValue script_runfile(const char *file)
|
||||
{
|
||||
size_t len;
|
||||
char *script = slurp_text(file, &len);
|
||||
if (!script) return JS_UNDEFINED;
|
||||
YughWarn("Eval %s.", file);
|
||||
JSValue obj = JS_Eval(js, script, len, file, JS_EVAL_FLAGS);
|
||||
js_print_exception(obj);
|
||||
|
||||
free(script);
|
||||
return obj;
|
||||
}
|
||||
|
||||
/* env is an object in the scripting environment;
|
||||
s is the function to call on that object
|
||||
*/
|
||||
void script_eval_w_env(const char *s, JSValue env, const char *file) {
|
||||
JSValue v = JS_EvalThis(js, env, s, strlen(s), file, JS_EVAL_FLAGS);
|
||||
js_print_exception(v);
|
||||
JS_FreeValue(js, v);
|
||||
}
|
||||
|
||||
JSValue eval_file_env(const char *script, const char *file, JSValue env)
|
||||
{
|
||||
JSValue v = JS_EvalThis(js, env, script, strlen(script), file, JS_EVAL_FLAGS);
|
||||
JSValue v = JS_Eval(js, script, strlen(script), file, JS_EVAL_FLAGS);
|
||||
js_print_exception(v);
|
||||
return v;
|
||||
}
|
||||
|
||||
JSValue file_eval_env(const char *file, JSValue env)
|
||||
{
|
||||
size_t len;
|
||||
char *script = slurp_text(file, &len);
|
||||
JSValue v = JS_EvalThis(js, env, script, len, file, JS_EVAL_FLAGS);
|
||||
free(script);
|
||||
js_print_exception(v);
|
||||
return v;
|
||||
}
|
||||
|
||||
void script_call_sym(JSValue sym) {
|
||||
void script_call_sym(JSValue sym, int argc, JSValue *argv) {
|
||||
if (!JS_IsFunction(js, sym)) return;
|
||||
struct callee c;
|
||||
c.fn = sym;
|
||||
c.obj = JS_GetGlobalObject(js);
|
||||
call_callee(&c);
|
||||
}
|
||||
|
||||
void script_call_fn_arg(JSValue fn, JSValue arg)
|
||||
{
|
||||
if (!JS_IsFunction(js,fn)) return;
|
||||
JSValue ret = JS_Call(js, fn, JS_GetGlobalObject(js), 1, &arg);
|
||||
JSValue ret = JS_Call(js, sym, JS_UNDEFINED, argc, argv);
|
||||
js_print_exception(ret);
|
||||
JS_FreeValue(js, ret);
|
||||
}
|
||||
|
@ -266,62 +87,3 @@ void out_memusage(const char *file)
|
|||
JS_DumpMemoryUsage(f, &jsmem, rt);
|
||||
fclose(f);
|
||||
}
|
||||
|
||||
JSValue js_callee_exec(struct callee *c, int argc, JSValue *argv)
|
||||
{
|
||||
if (JS_IsUndefined(c->fn)) return JS_UNDEFINED;
|
||||
if (JS_IsUndefined(c->obj)) return JS_UNDEFINED;
|
||||
|
||||
JSValue ret = JS_Call(js, c->fn, c->obj, argc, argv);
|
||||
js_print_exception(ret);
|
||||
JS_FreeValue(js, ret);
|
||||
return JS_UNDEFINED;
|
||||
}
|
||||
|
||||
void call_callee(struct callee *c) {
|
||||
js_callee_exec(c, 0, NULL);
|
||||
}
|
||||
|
||||
void callee_dbl(struct callee c, double d) {
|
||||
JSValue v = number2js(d);
|
||||
js_callee_exec(&c, 1, &v);
|
||||
JS_FreeValue(js, v);
|
||||
}
|
||||
|
||||
void callee_int(struct callee c, int i) {
|
||||
JSValue v = int2js(i);
|
||||
js_callee_exec(&c, 1, &v);
|
||||
JS_FreeValue(js, v);
|
||||
}
|
||||
|
||||
void callee_vec2(struct callee c, HMM_Vec2 vec) {
|
||||
JSValue v = vec22js(vec);
|
||||
js_callee_exec(&c, 1, &v);
|
||||
JS_FreeValue(js, v);
|
||||
}
|
||||
|
||||
void script_callee(struct callee c, int argc, JSValue *argv) {
|
||||
js_callee_exec(&c, argc, argv);
|
||||
}
|
||||
|
||||
void free_callee(struct callee c)
|
||||
{
|
||||
JS_FreeValue(js,c.fn);
|
||||
JS_FreeValue(js,c.obj);
|
||||
}
|
||||
|
||||
void send_signal(const char *signal, int argc, JSValue *argv)
|
||||
{
|
||||
JSValue globalThis = JS_GetGlobalObject(js);
|
||||
JSValue sig = JS_GetPropertyStr(js, globalThis, "Signal");
|
||||
JS_FreeValue(js, globalThis);
|
||||
JSValue fn = JS_GetPropertyStr(js, sig, "call");
|
||||
JSValue args[argc+1];
|
||||
args[0] = jstr(signal);
|
||||
for (int i = 0; i < argc; i++)
|
||||
args[1+i] = argv[i];
|
||||
|
||||
JS_FreeValue(js,JS_Call(js, fn, sig, argc+1, args));
|
||||
JS_FreeValue(js, sig);
|
||||
JS_FreeValue(js, fn);
|
||||
}
|
||||
|
|
|
@ -6,56 +6,24 @@
|
|||
|
||||
extern JSContext *js;
|
||||
|
||||
struct callee {
|
||||
JSValue fn;
|
||||
JSValue obj;
|
||||
};
|
||||
|
||||
struct phys_cbs {
|
||||
JSValue begin;
|
||||
JSValue bhit;
|
||||
JSValue separate;
|
||||
JSValue shit;
|
||||
};
|
||||
void script_call_fn_arg(JSValue fn, JSValue arg);
|
||||
|
||||
extern struct callee stacktrace_callee;
|
||||
extern JSValue num_cache[100];
|
||||
|
||||
JSValue jstr(const char *str);
|
||||
void js_stacktrace();
|
||||
void script_startup();
|
||||
void script_stop();
|
||||
void script_run(const char *script, const char *file);
|
||||
void script_evalf(const char *format, ...);
|
||||
int script_dofile(const char *file);
|
||||
time_t jso_file(const char *file);
|
||||
JSValue script_runfile(const char *file);
|
||||
JSValue eval_file_env(const char *script, const char *file, JSValue env);
|
||||
void script_update(double dt);
|
||||
void script_draw();
|
||||
void free_callee(struct callee c);
|
||||
|
||||
void duk_run_err();
|
||||
void js_dump_stack();
|
||||
|
||||
void out_memusage(const char *f);
|
||||
void js_stacktrace();
|
||||
|
||||
void script_editor();
|
||||
void script_call(const char *f);
|
||||
void script_call_sym(JSValue sym);
|
||||
void call_callee(struct callee *c);
|
||||
void script_callee(struct callee c, int argc, JSValue *argv);
|
||||
int script_has_sym(void *sym);
|
||||
void script_eval_w_env(const char *s, JSValue env, const char *file);
|
||||
JSValue file_eval_env(const char *file, JSValue env);
|
||||
void script_evalf(const char *format, ...);
|
||||
JSValue script_eval(const char *file, const char *script);
|
||||
|
||||
time_t file_mod_secs(const char *file);
|
||||
void script_call_sym(JSValue sym, int argc, JSValue *argv);
|
||||
|
||||
void send_signal(const char *signal, int argc, JSValue *argv);
|
||||
void script_gc();
|
||||
|
||||
JSValue script_run_bytecode(uint8_t *code, size_t len);
|
||||
uint8_t *script_compile(const char *file, size_t *len);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -13,6 +13,10 @@
|
|||
|
||||
#define PI 3.14159265
|
||||
|
||||
int SAMPLERATE = 44100;
|
||||
int BUF_FRAMES = 2048;
|
||||
int CHANNELS = 2;
|
||||
|
||||
dsp_node *masterbus = NULL;
|
||||
|
||||
void iir_free(struct dsp_iir *iir)
|
||||
|
@ -136,11 +140,14 @@ void dsp_node_run(dsp_node *node)
|
|||
}
|
||||
}
|
||||
|
||||
static int node_count = 0;
|
||||
|
||||
dsp_node *make_node(void *data, void (*proc)(void *data, soundbyte *out, int samples), void (*fr)(void *data))
|
||||
{
|
||||
dsp_node *self = malloc(sizeof(dsp_node));
|
||||
memset(self, 0, sizeof(*self));
|
||||
self->data = data;
|
||||
self->cache = calloc(BUF_FRAMES*CHANNELS*sizeof(soundbyte),1);
|
||||
self->proc = proc;
|
||||
self->pass = 0;
|
||||
self->gain = 1;
|
||||
|
@ -149,7 +156,10 @@ dsp_node *make_node(void *data, void (*proc)(void *data, soundbyte *out, int sam
|
|||
|
||||
void node_free(dsp_node *node)
|
||||
{
|
||||
if (node == masterbus) return; /* Simple check to not delete the masterbus */
|
||||
if (node == masterbus) {
|
||||
YughWarn("Attempted to delete the master bus.");
|
||||
return; /* Simple check to not delete the masterbus */
|
||||
}
|
||||
pthread_mutex_lock(&soundrun);
|
||||
unplug_node(node);
|
||||
if (node->data) {
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
#ifndef DSP_H
|
||||
#define DSP_H
|
||||
|
||||
#define SAMPLERATE 44100
|
||||
#define BUF_FRAMES 2048 /* At 48k, 128 needed for 240fps consistency */
|
||||
#define CHANNELS 2
|
||||
extern int SAMPLERATE;
|
||||
extern int BUF_FRAMES;
|
||||
extern int CHANNELS;
|
||||
|
||||
#include "sound.h"
|
||||
#include "cbuf.h"
|
||||
|
@ -15,7 +15,7 @@ typedef struct dsp_node {
|
|||
void (*proc)(void *dsp, soundbyte *buf, int samples); /* processor */
|
||||
void *data; /* Node specific data to use in the proc function, passed in as dsp */
|
||||
void (*data_free)(void *data);
|
||||
soundbyte cache[BUF_FRAMES*CHANNELS]; /* Cached process */
|
||||
soundbyte *cache;
|
||||
struct dsp_node **ins; /* Array of in nodes */
|
||||
struct dsp_node *out; /* node this one is connected to */
|
||||
int pass; /* True if the filter should be bypassed */
|
||||
|
|
|
@ -8,7 +8,6 @@
|
|||
#include "time.h"
|
||||
#include <stdlib.h>
|
||||
#include "pthread.h"
|
||||
#include "debug.h"
|
||||
#include "jsffi.h"
|
||||
|
||||
pthread_mutex_t soundrun = PTHREAD_MUTEX_INITIALIZER;
|
||||
|
@ -138,6 +137,10 @@ void sound_init() {
|
|||
.buffer_frames = BUF_FRAMES,
|
||||
.logger.func = sg_logging,
|
||||
});
|
||||
|
||||
SAMPLERATE = saudio_sample_rate();
|
||||
CHANNELS = saudio_channels();
|
||||
BUF_FRAMES = saudio_buffer_frames();
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
|
@ -279,14 +282,11 @@ void sound_fillbuf(struct sound *s, soundbyte *buf, int n) {
|
|||
if(end) {
|
||||
if (s->loop)
|
||||
s->frame = 0;
|
||||
|
||||
script_call_sym(s->hook);
|
||||
}
|
||||
}
|
||||
|
||||
void free_source(struct sound *s)
|
||||
{
|
||||
JS_FreeValue(js, s->hook);
|
||||
src_delete(s->src);
|
||||
free(s);
|
||||
}
|
||||
|
@ -307,7 +307,6 @@ struct dsp_node *dsp_source(const char *path)
|
|||
self->loop = false;
|
||||
self->src = src_callback_new(src_cb, SRC_SINC_MEDIUM_QUALITY, 2, NULL, self);
|
||||
self->timescale = 1;
|
||||
self->hook = JS_UNDEFINED;
|
||||
dsp_node *n = make_node(self, sound_fillbuf, free_source);
|
||||
return n;
|
||||
}
|
||||
|
|
|
@ -17,7 +17,6 @@ typedef struct sound {
|
|||
int loop;
|
||||
float timescale;
|
||||
SRC_STATE *src;
|
||||
JSValue hook;
|
||||
} sound;
|
||||
|
||||
/* Represents a sound file source, fulled loaded*/
|
||||
|
|
|
@ -5,7 +5,6 @@
|
|||
#include "render.h"
|
||||
#include "stb_ds.h"
|
||||
#include "texture.h"
|
||||
#include "timer.h"
|
||||
#include "HandmadeMath.h"
|
||||
|
||||
#include "sprite.sglsl.h"
|
||||
|
@ -52,7 +51,7 @@ sprite *sprite_make()
|
|||
sp->color = color_white;
|
||||
sp->emissive = color_clear;
|
||||
sp->go = NULL;
|
||||
sp->tex = texture_from_file(NULL);
|
||||
sp->tex = NULL;
|
||||
sp->frame = ST_UNIT;
|
||||
sp->drawmode = DRAW_SIMPLE;
|
||||
sp->enabled = 1;
|
||||
|
@ -65,8 +64,6 @@ sprite *sprite_make()
|
|||
|
||||
void sprite_free(sprite *sprite)
|
||||
{
|
||||
YughWarn("Freeing sprite %p.", sprite);
|
||||
|
||||
free(sprite);
|
||||
for (int i = arrlen(sprites)-1; i >= 0; i--)
|
||||
if (sprites[i] == sprite) {
|
||||
|
@ -88,8 +85,9 @@ int sprite_sort(sprite **sa, sprite **sb)
|
|||
if (!goa && !gob) return 0;
|
||||
if (!goa) return -1;
|
||||
if (!gob) return 1;
|
||||
if (goa->drawlayer == gob->drawlayer) return 0;
|
||||
if (goa->drawlayer > gob->drawlayer) return 1;
|
||||
if (gob->drawlayer > goa->drawlayer) return -1;
|
||||
if (*sa > *sb) return 1;
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
@ -97,16 +95,17 @@ void sprite_draw_all() {
|
|||
if (arrlen(sprites) == 0) return;
|
||||
|
||||
sg_apply_pipeline(pip_sprite);
|
||||
sg_apply_uniforms(SG_SHADERSTAGE_VS, 0, SG_RANGE_REF(projection));
|
||||
sg_apply_uniforms(SG_SHADERSTAGE_VS, 0, SG_RANGE_REF(useproj));
|
||||
|
||||
qsort(sprites, arrlen(sprites), sizeof(*sprites), sprite_sort);
|
||||
|
||||
for (int i = 0; i < arrlen(sprites); i++)
|
||||
for (int i = 0; i < arrlen(sprites); i++) {
|
||||
if (!sprites[i]->enabled) continue;
|
||||
sprite_draw(sprites[i]);
|
||||
}
|
||||
}
|
||||
|
||||
void sprite_initialize() {
|
||||
|
||||
shader_sprite = sg_make_shader(sprite_shader_desc(sg_query_backend()));
|
||||
|
||||
pip_sprite = sg_make_pipeline(&(sg_pipeline_desc){
|
||||
|
@ -149,6 +148,7 @@ void sprite_initialize() {
|
|||
.size = sizeof(struct slice9_vert) * 100,
|
||||
.type = SG_BUFFERTYPE_VERTEXBUFFER,
|
||||
.usage = SG_USAGE_STREAM,
|
||||
.label = "slice9 buffer"
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -198,7 +198,7 @@ transform2d sprite2t(sprite *s)
|
|||
return (transform2d){
|
||||
.pos = s->pos,
|
||||
.scale = s->scale,
|
||||
.angle = s->angle
|
||||
.angle = HMM_TurnToRad*s->angle
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -208,16 +208,20 @@ void sprite_draw(struct sprite *sprite) {
|
|||
if (!sprite->go) t = t2d_unit;
|
||||
else t = go2t(sprite->go);
|
||||
|
||||
t.pos.x += (cam_pos().x - (cam_pos().x/sprite->parallax));
|
||||
t.pos.y += (cam_pos().y - (cam_pos().y/sprite->parallax));
|
||||
t.pos.x += (campos.x - (campos.x/sprite->parallax));
|
||||
t.pos.y += (campos.y - (campos.y/sprite->parallax));
|
||||
HMM_Mat3 m = transform2d2mat(t);
|
||||
HMM_Mat3 sm = transform2d2mat(sprite2t(sprite));
|
||||
tex_draw(sprite->tex, HMM_MulM3(m,sm), sprite->frame, sprite->color, sprite->drawmode, (HMM_Vec2){0,0}, sprite->scale, sprite->emissive, sprite->parallax);
|
||||
}
|
||||
|
||||
void gui_draw_img(const char *img, transform2d t, int wrap, HMM_Vec2 wrapoffset, float wrapscale, struct rgba color) {
|
||||
void gui_draw_img(texture *tex, transform2d t, int wrap, HMM_Vec2 wrapoffset, float wrapscale, struct rgba color) {
|
||||
sg_apply_pipeline(pip_sprite);
|
||||
sg_apply_uniforms(SG_SHADERSTAGE_VS, 0, SG_RANGE_REF(hudproj));
|
||||
struct texture *tex = texture_from_file(img);
|
||||
sg_apply_uniforms(SG_SHADERSTAGE_VS, 0, SG_RANGE_REF(useproj));
|
||||
tex_draw(tex, transform2d2mat(t), ST_UNIT, color, wrap, wrapoffset, (HMM_Vec2){wrapscale,wrapscale}, (struct rgba){0,0,0,0}, 0);
|
||||
}
|
||||
|
||||
void slice9_draw(texture *tex, transform2d *t, HMM_Vec4 border, struct rgba color)
|
||||
{
|
||||
|
||||
}
|
|
@ -36,6 +36,6 @@ void sprite_draw(struct sprite *sprite);
|
|||
void sprite_draw_all();
|
||||
void sprite_flush();
|
||||
|
||||
void gui_draw_img(const char *img, transform2d t, int wrap, HMM_Vec2 wrapoffset, float wrapscale, struct rgba color);
|
||||
void gui_draw_img(texture *tex, transform2d t, int wrap, HMM_Vec2 wrapoffset, float wrapscale, struct rgba color);
|
||||
|
||||
#endif
|
||||
|
|
21
source/engine/steam.cpp
Normal file
21
source/engine/steam.cpp
Normal file
|
@ -0,0 +1,21 @@
|
|||
#include "steam.h"
|
||||
|
||||
#include <steam/steam_api.h>
|
||||
#include <steam/steam_api_flat.h>
|
||||
|
||||
static JSValue js_steam_init(JSContext *js, JSValue this_v, int argc, JSValue *argv)
|
||||
{
|
||||
SteamAPI_Init();
|
||||
return JS_UNDEFINED;
|
||||
}
|
||||
|
||||
static const JSCFunctionListEntry js_steam_funcs[] = {
|
||||
MIST_FUNC_DEF(steam, init, 1),
|
||||
};
|
||||
|
||||
JSValue js_init_steam(JSContext *js)
|
||||
{
|
||||
JSValue steam = JS_NewObject(js);
|
||||
JS_SetPropertyFunctionList(js, steam, js_steam_funcs, countof(js_steam_funcs));
|
||||
return steam;
|
||||
}
|
15
source/engine/steam.h
Normal file
15
source/engine/steam.h
Normal file
|
@ -0,0 +1,15 @@
|
|||
#ifndef QJS_STEAM_H
|
||||
#define QJS_STEAM_H
|
||||
|
||||
#include "jsffi.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
JSValue js_init_steam(JSContext *js);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
|
@ -1,9 +0,0 @@
|
|||
#include "steamffi.h"
|
||||
|
||||
#ifdef STEAM
|
||||
#include "steam/steam_api_flat.h"
|
||||
void steaminit()
|
||||
{
|
||||
SteamAPI_Init();
|
||||
}
|
||||
#endif
|
|
@ -1,13 +0,0 @@
|
|||
#ifndef STEAMFFI
|
||||
#define STEAMFFI
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"{
|
||||
#endif
|
||||
|
||||
void steaminit();
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif
|
|
@ -4,7 +4,6 @@
|
|||
#include "render.h"
|
||||
#include "sokol/sokol_gfx.h"
|
||||
#include <math.h>
|
||||
#include <stb_ds.h>
|
||||
#include <stb_image.h>
|
||||
|
||||
#include "resources.h"
|
||||
|
@ -23,14 +22,6 @@
|
|||
|
||||
struct rect ST_UNIT = {0.f, 0.f, 1.f, 1.f};
|
||||
|
||||
static struct {
|
||||
char *key;
|
||||
struct texture *value;
|
||||
} *texhash = NULL;
|
||||
|
||||
struct texture *tex_default;
|
||||
struct texture *texture_notex() { return texture_from_file("icons/no_tex.gif"); }
|
||||
|
||||
unsigned int next_pow2(unsigned int v)
|
||||
{
|
||||
v--;
|
||||
|
@ -70,31 +61,14 @@ int mip_wh(int w, int h, int *mw, int *mh, int lvl)
|
|||
return 0;
|
||||
}
|
||||
|
||||
int gif_nframes(const char *path)
|
||||
{
|
||||
struct texture *t = texture_from_file(path);
|
||||
return t->frames;
|
||||
}
|
||||
|
||||
int *gif_delays(const char *path)
|
||||
{
|
||||
struct texture *t = texture_from_file(path);
|
||||
return t->delays;
|
||||
}
|
||||
|
||||
/* If an empty string or null is put for path, loads default texture */
|
||||
struct texture *texture_from_file(const char *path) {
|
||||
if (!path) return texture_notex();
|
||||
if (shlen(texhash) == 0) sh_new_arena(texhash);
|
||||
|
||||
int index = shgeti(texhash, path);
|
||||
if (index != -1)
|
||||
return texhash[index].value;
|
||||
if (!path) return NULL;
|
||||
|
||||
size_t rawlen;
|
||||
unsigned char *raw = slurp_file(path, &rawlen);
|
||||
|
||||
if (!raw) return texture_notex();
|
||||
if (!raw) return NULL;
|
||||
|
||||
unsigned char *data;
|
||||
|
||||
|
@ -115,8 +89,7 @@ struct texture *texture_from_file(const char *path) {
|
|||
int *dd = tex->delays;
|
||||
tex->delays = NULL;
|
||||
arrsetlen(tex->delays, tex->frames);
|
||||
for (int i = 0; i < tex->frames;i++)
|
||||
tex->delays[i] = dd[i];
|
||||
for (int i = 0; i < tex->frames; i++) tex->delays[i] = dd[i];
|
||||
free(dd);
|
||||
tex->height *= tex->frames;
|
||||
} else if (!strcmp(ext, ".svg")) {
|
||||
|
@ -141,20 +114,19 @@ struct texture *texture_from_file(const char *path) {
|
|||
}
|
||||
free(raw);
|
||||
|
||||
if (data == NULL) {
|
||||
YughError("STBI failed to load file %s with message: %s\nOpening default instead.", path, stbi_failure_reason());
|
||||
return texture_notex();
|
||||
}
|
||||
if (data == NULL)
|
||||
return NULL;
|
||||
|
||||
tex->data = data;
|
||||
|
||||
unsigned int nw = next_pow2(tex->width);
|
||||
unsigned int nh = next_pow2(tex->height);
|
||||
|
||||
tex->data = data;
|
||||
|
||||
int filter = SG_FILTER_NEAREST;
|
||||
|
||||
sg_image_data sg_img_data;
|
||||
|
||||
sg_img_data.subimage[0][0] = (sg_range){.ptr = data, .size=tex->width*tex->height*4};
|
||||
/*
|
||||
int mips = mip_levels(tex->width, tex->height)+1;
|
||||
|
||||
YughInfo("Has %d mip levels, from wxh %dx%d, pow2 is %ux%u.", mips, tex->width, tex->height,nw,nh);
|
||||
|
@ -170,7 +142,7 @@ struct texture *texture_from_file(const char *path) {
|
|||
|
||||
for (int i = 1; i < mips; i++) {
|
||||
int w, h, mipw, miph;
|
||||
mip_wh(tex->width, tex->height, &mipw, &miph, i-1); /* mipw miph are previous iteration */
|
||||
mip_wh(tex->width, tex->height, &mipw, &miph, i-1); // mipw miph are previous iteration
|
||||
mip_wh(tex->width, tex->height, &w, &h, i);
|
||||
mipdata[i] = malloc(w * h * 4);
|
||||
stbir_resize_uint8_linear(mipdata[i-1], mipw, miph, 0, mipdata[i], w, h, 0, 4);
|
||||
|
@ -179,40 +151,29 @@ struct texture *texture_from_file(const char *path) {
|
|||
mipw = w;
|
||||
miph = h;
|
||||
}
|
||||
|
||||
*/
|
||||
tex->id = sg_make_image(&(sg_image_desc){
|
||||
.type = SG_IMAGETYPE_2D,
|
||||
.width = tex->width,
|
||||
.height = tex->height,
|
||||
.usage = SG_USAGE_IMMUTABLE,
|
||||
.num_mipmaps = mips,
|
||||
//.num_mipmaps = mips,
|
||||
.data = sg_img_data
|
||||
});
|
||||
|
||||
shput(texhash, path, tex);
|
||||
|
||||
for (int i = 1; i < mips; i++)
|
||||
free(mipdata[i]);
|
||||
/*for (int i = 1; i < mips; i++)
|
||||
free(mipdata[i]);*/
|
||||
|
||||
return tex;
|
||||
}
|
||||
|
||||
void texture_sync(const char *path) { YughWarn("Need to implement texture sync."); }
|
||||
|
||||
void texture_free(texture *tex)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
char *tex_get_path(struct texture *tex) {
|
||||
for (int i = 0; i < shlen(texhash); i++) {
|
||||
if (tex == texhash[i].value) {
|
||||
YughSpam("Found key %s", texhash[i].key);
|
||||
return texhash[i].key;
|
||||
}
|
||||
}
|
||||
|
||||
return "";
|
||||
if (!tex) return;
|
||||
free(tex->data);
|
||||
if (tex->delays) arrfree(tex->delays);
|
||||
sg_destroy_image(tex->id);
|
||||
free(tex);
|
||||
}
|
||||
|
||||
struct texture *texture_fromdata(void *raw, long size)
|
||||
|
@ -222,10 +183,8 @@ struct texture *texture_fromdata(void *raw, long size)
|
|||
int n;
|
||||
void *data = stbi_load_from_memory(raw, size, &tex->width, &tex->height, &n, 4);
|
||||
|
||||
if (data == NULL) {
|
||||
YughError("Given raw data not valid. Loading default instead.");
|
||||
return texture_notex();
|
||||
}
|
||||
if (data == NULL)
|
||||
NULL;
|
||||
|
||||
unsigned int nw = next_pow2(tex->width);
|
||||
unsigned int nh = next_pow2(tex->height);
|
||||
|
@ -276,14 +235,6 @@ struct texture *texture_fromdata(void *raw, long size)
|
|||
return tex;
|
||||
}
|
||||
|
||||
HMM_Vec2 tex_get_dimensions(struct texture *tex) {
|
||||
if (!tex) return (HMM_Vec2){0,0};
|
||||
HMM_Vec2 d;
|
||||
d.x = tex->width;
|
||||
d.y = tex->height;
|
||||
return d;
|
||||
}
|
||||
|
||||
static double fade (double t) { return t*t*t*(t*(t*6-15)+10); }
|
||||
double grad (int hash, double x, double y, double z)
|
||||
{
|
||||
|
|
|
@ -37,21 +37,10 @@ typedef struct img_sampler{
|
|||
int mip_filter;
|
||||
} img_sampler;
|
||||
|
||||
struct texture *texture_from_file(const char *path); // Create texture from image
|
||||
struct texture *texture_fromdata(void *raw, long size);
|
||||
|
||||
texture *texture_from_file(const char *path);
|
||||
void texture_free(texture *tex);
|
||||
|
||||
/* Hot reloads a texture, if needed */
|
||||
void texture_sync(const char *path);
|
||||
|
||||
char * tex_get_path(struct texture *tex); // Get image path for texture
|
||||
|
||||
int gif_nframes(const char *path);
|
||||
int *gif_delays(const char *path);
|
||||
|
||||
struct glrect tex_get_rect(struct texture *tex);
|
||||
HMM_Vec2 tex_get_dimensions(struct texture *tex);
|
||||
struct texture *texture_fromdata(void *raw, long size);
|
||||
|
||||
double perlin(double x, double y, double z);
|
||||
|
||||
|
|
|
@ -1,15 +0,0 @@
|
|||
name: build
|
||||
|
||||
on: [push, pull_request]
|
||||
|
||||
jobs:
|
||||
generic:
|
||||
strategy:
|
||||
matrix:
|
||||
os: [windows, ubuntu, macos]
|
||||
name: ${{matrix.os}}
|
||||
runs-on: ${{matrix.os}}-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v1
|
||||
- name: test
|
||||
run: cd test && python test_all.py
|
|
@ -1 +0,0 @@
|
|||
{"textures":[{"extensions":{"KHR_texture_basisu":{""}}:{""""},""}]}
|
BIN
source/engine/thirdparty/cgltf/fuzz/data/Box.glb
vendored
BIN
source/engine/thirdparty/cgltf/fuzz/data/Box.glb
vendored
Binary file not shown.
|
@ -1,53 +0,0 @@
|
|||
{
|
||||
"scenes" : [
|
||||
{
|
||||
"nodes" : [ 0 ]
|
||||
}
|
||||
],
|
||||
|
||||
"nodes" : [
|
||||
{
|
||||
"mesh" : 0
|
||||
}
|
||||
],
|
||||
|
||||
"meshes" : [
|
||||
{
|
||||
"primitives" : [ {
|
||||
"attributes" : {
|
||||
"POSITION" : 0
|
||||
}
|
||||
} ]
|
||||
}
|
||||
],
|
||||
|
||||
"buffers" : [
|
||||
{
|
||||
"uri" : "data:application/octet-stream;base64,AAAAAAAAAAAAAAAAAACAPwAAAAAAAAAAAAAAAAAAgD8AAAAA",
|
||||
"byteLength" : 36
|
||||
}
|
||||
],
|
||||
"bufferViews" : [
|
||||
{
|
||||
"buffer" : 0,
|
||||
"byteOffset" : 0,
|
||||
"byteLength" : 36,
|
||||
"target" : 34962
|
||||
}
|
||||
],
|
||||
"accessors" : [
|
||||
{
|
||||
"bufferView" : 0,
|
||||
"byteOffset" : 0,
|
||||
"componentType" : 5126,
|
||||
"count" : 3,
|
||||
"type" : "VEC3",
|
||||
"max" : [ 1.0, 1.0, 0.0 ],
|
||||
"min" : [ 0.0, 0.0, 0.0 ]
|
||||
}
|
||||
],
|
||||
|
||||
"asset" : {
|
||||
"version" : "2.0"
|
||||
}
|
||||
}
|
|
@ -1,172 +0,0 @@
|
|||
{
|
||||
"accessors": [
|
||||
{
|
||||
"bufferView": 0,
|
||||
"componentType": 5126,
|
||||
"count": 2549,
|
||||
"type": "VEC2"
|
||||
},
|
||||
{
|
||||
"bufferView": 1,
|
||||
"componentType": 5126,
|
||||
"count": 2549,
|
||||
"type": "VEC3"
|
||||
},
|
||||
{
|
||||
"bufferView": 2,
|
||||
"componentType": 5126,
|
||||
"count": 2549,
|
||||
"type": "VEC4"
|
||||
},
|
||||
{
|
||||
"bufferView": 3,
|
||||
"componentType": 5126,
|
||||
"count": 2549,
|
||||
"type": "VEC3",
|
||||
"max": [
|
||||
0.05445001,
|
||||
0.130220339,
|
||||
0.0544500239
|
||||
],
|
||||
"min": [
|
||||
-0.05445001,
|
||||
-0.130220339,
|
||||
-0.0544500239
|
||||
]
|
||||
},
|
||||
{
|
||||
"bufferView": 4,
|
||||
"componentType": 5123,
|
||||
"count": 13530,
|
||||
"type": "SCALAR"
|
||||
}
|
||||
],
|
||||
"asset": {
|
||||
"generator": "glTF Tools for Unity",
|
||||
"version": "2.0"
|
||||
},
|
||||
"bufferViews": [
|
||||
{
|
||||
"buffer": 0,
|
||||
"byteLength": 20392
|
||||
},
|
||||
{
|
||||
"buffer": 0,
|
||||
"byteOffset": 20392,
|
||||
"byteLength": 30588
|
||||
},
|
||||
{
|
||||
"buffer": 0,
|
||||
"byteOffset": 50980,
|
||||
"byteLength": 40784
|
||||
},
|
||||
{
|
||||
"buffer": 0,
|
||||
"byteOffset": 91764,
|
||||
"byteLength": 30588
|
||||
},
|
||||
{
|
||||
"buffer": 0,
|
||||
"byteOffset": 122352,
|
||||
"byteLength": 27060
|
||||
}
|
||||
],
|
||||
"buffers": [
|
||||
{
|
||||
"uri": "WaterBottle.bin",
|
||||
"byteLength": 149412
|
||||
}
|
||||
],
|
||||
"images": [
|
||||
{
|
||||
"uri": "WaterBottle_baseColor.png"
|
||||
},
|
||||
{
|
||||
"uri": "WaterBottle_occlusionRoughnessMetallic.png"
|
||||
},
|
||||
{
|
||||
"uri": "WaterBottle_normal.png"
|
||||
},
|
||||
{
|
||||
"uri": "WaterBottle_emissive.png"
|
||||
}
|
||||
],
|
||||
"meshes": [
|
||||
{
|
||||
"primitives": [
|
||||
{
|
||||
"attributes": {
|
||||
"TEXCOORD_0": 0,
|
||||
"NORMAL": 1,
|
||||
"TANGENT": 2,
|
||||
"POSITION": 3
|
||||
},
|
||||
"indices": 4,
|
||||
"material": 0
|
||||
}
|
||||
],
|
||||
"name": "WaterBottle"
|
||||
}
|
||||
],
|
||||
"materials": [
|
||||
{
|
||||
"pbrMetallicRoughness": {
|
||||
"baseColorTexture": {
|
||||
"index": 0
|
||||
},
|
||||
"metallicRoughnessTexture": {
|
||||
"index": 1
|
||||
}
|
||||
},
|
||||
"normalTexture": {
|
||||
"index": 2
|
||||
},
|
||||
"occlusionTexture": {
|
||||
"index": 1
|
||||
},
|
||||
"emissiveFactor": [
|
||||
1.0,
|
||||
1.0,
|
||||
1.0
|
||||
],
|
||||
"emissiveTexture": {
|
||||
"index": 3
|
||||
},
|
||||
"name": "BottleMat"
|
||||
}
|
||||
],
|
||||
"nodes": [
|
||||
{
|
||||
"mesh": 0,
|
||||
"rotation": [
|
||||
0.0,
|
||||
1.0,
|
||||
0.0,
|
||||
0.0
|
||||
],
|
||||
"name": "WaterBottle"
|
||||
}
|
||||
],
|
||||
"scene": 0,
|
||||
"scenes": [
|
||||
{
|
||||
"nodes": [
|
||||
0
|
||||
]
|
||||
}
|
||||
],
|
||||
"textures": [
|
||||
{
|
||||
"source": 0
|
||||
},
|
||||
{
|
||||
"source": 1
|
||||
},
|
||||
{
|
||||
"source": 2
|
||||
},
|
||||
{
|
||||
"source": 3
|
||||
}
|
||||
]
|
||||
}
|
224
source/engine/thirdparty/cgltf/fuzz/gltf.dict
vendored
224
source/engine/thirdparty/cgltf/fuzz/gltf.dict
vendored
|
@ -1,224 +0,0 @@
|
|||
#
|
||||
# AFL dictionary for JSON
|
||||
# -----------------------
|
||||
#
|
||||
# Just the very basics.
|
||||
#
|
||||
# Inspired by a dictionary by Jakub Wilk <jwilk@jwilk.net>
|
||||
#
|
||||
|
||||
"0"
|
||||
",0"
|
||||
":0"
|
||||
"0:"
|
||||
"-1.2e+3"
|
||||
|
||||
"true"
|
||||
"false"
|
||||
"null"
|
||||
|
||||
"\"\""
|
||||
",\"\""
|
||||
":\"\""
|
||||
"\"\":"
|
||||
|
||||
"{}"
|
||||
",{}"
|
||||
":{}"
|
||||
"{\"\":0}"
|
||||
"{{}}"
|
||||
|
||||
"[]"
|
||||
",[]"
|
||||
":[]"
|
||||
"[0]"
|
||||
"[[]]"
|
||||
|
||||
"''"
|
||||
"\\"
|
||||
"\\b"
|
||||
"\\f"
|
||||
"\\n"
|
||||
"\\r"
|
||||
"\\t"
|
||||
"\\u0000"
|
||||
"\\x00"
|
||||
"\\0"
|
||||
"\\uD800\\uDC00"
|
||||
"\\uDBFF\\uDFFF"
|
||||
|
||||
"\"\":0"
|
||||
"//"
|
||||
"/**/"
|
||||
|
||||
#
|
||||
# AFL dictionary for GLTF core
|
||||
# -----------------------
|
||||
|
||||
"5120"
|
||||
"5121"
|
||||
"5122"
|
||||
"5123"
|
||||
"5125"
|
||||
"5126"
|
||||
"\"BLEND\""
|
||||
"\"CUBICSPLINE\""
|
||||
"\"LINEAR\""
|
||||
"\"MASK\""
|
||||
"\"MAT2\""
|
||||
"\"MAT3\""
|
||||
"\"MAT4\""
|
||||
"\"OPAQUE\""
|
||||
"\"SCALAR\""
|
||||
"\"STEP\""
|
||||
"\"VEC2\""
|
||||
"\"VEC3\""
|
||||
"\"VEC4\""
|
||||
"\"accessor\""
|
||||
"\"accessors\""
|
||||
"\"alphaCutoff\""
|
||||
"\"alphaMode\""
|
||||
"\"animations\""
|
||||
"\"aspectRatio\""
|
||||
"\"asset\""
|
||||
"\"attributes\""
|
||||
"\"baseColorFactor\""
|
||||
"\"baseColorTexture\""
|
||||
"\"bufferView\""
|
||||
"\"bufferViews\""
|
||||
"\"buffer\""
|
||||
"\"buffers\""
|
||||
"\"byteLength\""
|
||||
"\"byteOffset\""
|
||||
"\"byteStride\""
|
||||
"\"camera\""
|
||||
"\"cameras\""
|
||||
"\"channel\""
|
||||
"\"channels\""
|
||||
"\"children\""
|
||||
"\"componentType\""
|
||||
"\"copyright\""
|
||||
"\"count\""
|
||||
"\"doubleSided\""
|
||||
"\"emissiveFactor\""
|
||||
"\"emissiveTexture\""
|
||||
"\"extensionsRequired\""
|
||||
"\"extensionsUsed\""
|
||||
"\"extensions\""
|
||||
"\"extras\""
|
||||
"\"generator\""
|
||||
"\"image\""
|
||||
"\"images\""
|
||||
"\"index\""
|
||||
"\"indices\""
|
||||
"\"input\""
|
||||
"\"interpolation\""
|
||||
"\"inverseBindMatrices\""
|
||||
"\"joints\""
|
||||
"\"magFilter\""
|
||||
"\"material\""
|
||||
"\"materials\""
|
||||
"\"matrix\""
|
||||
"\"max\""
|
||||
"\"mesh\""
|
||||
"\"meshes\""
|
||||
"\"metallicFactor\""
|
||||
"\"metallicRoughnessTexture\""
|
||||
"\"mimeType\""
|
||||
"\"minFilter\""
|
||||
"\"minVersion\""
|
||||
"\"min\""
|
||||
"\"mode\""
|
||||
"\"name\""
|
||||
"\"node\""
|
||||
"\"nodes\""
|
||||
"\"normalTextureInfo\""
|
||||
"\"normalTexture\""
|
||||
"\"normalized\""
|
||||
"\"occlusionTextureInfo\""
|
||||
"\"occlusionTexture\""
|
||||
"\"orthographic\""
|
||||
"\"output\""
|
||||
"\"path\""
|
||||
"\"pbrMetallicRoughness\""
|
||||
"\"perspective\""
|
||||
"\"primitive\""
|
||||
"\"primitives\""
|
||||
"\"rotation\""
|
||||
"\"roughnessFactor\""
|
||||
"\"sampler\""
|
||||
"\"samplers\""
|
||||
"\"scale\""
|
||||
"\"scene\""
|
||||
"\"scenes\""
|
||||
"\"skeleton\""
|
||||
"\"skin\""
|
||||
"\"skins\""
|
||||
"\"source\""
|
||||
"\"sparse\""
|
||||
"\"strength\""
|
||||
"\"target\""
|
||||
"\"targets\""
|
||||
"\"texCoord\""
|
||||
"\"textureInfo\""
|
||||
"\"texture\""
|
||||
"\"textures\""
|
||||
"\"translation\""
|
||||
"\"type\""
|
||||
"\"uri\""
|
||||
"\"values\""
|
||||
"\"version\""
|
||||
"\"weights\""
|
||||
"\"wrapS\""
|
||||
"\"wrapT\""
|
||||
"\"xmag\""
|
||||
"\"yfov\""
|
||||
"\"ymag\""
|
||||
"\"zfar\""
|
||||
"\"znear\""
|
||||
|
||||
#
|
||||
# AFL dictionary for GLTF extensions
|
||||
# -----------------------
|
||||
"\"KHR_materials_unlit\""
|
||||
"\"KHR_texture_basisu\""
|
||||
|
||||
"\"KHR_materials_pbrSpecularGlossiness\""
|
||||
"\"diffuseFactor\""
|
||||
"\"diffuseTexture\""
|
||||
"\"specularFactor\""
|
||||
"\"glossinessFactor\""
|
||||
"\"specularGlossinessTexture\""
|
||||
|
||||
"\"KHR_texture_transform\""
|
||||
"\"offset\""
|
||||
"\"rotation\""
|
||||
"\"scale\""
|
||||
"\"texCoord\""
|
||||
|
||||
"\"KHR_lights_punctual\""
|
||||
"\"color\""
|
||||
"\"intensity\""
|
||||
"\"type\""
|
||||
"\"range\""
|
||||
"\"innerConeAngle\""
|
||||
"\"outerConeAngle\""
|
||||
|
||||
"\"KHR_materials_transmission\""
|
||||
"\"transmissionFactor\""
|
||||
"\"transmissionTexture\""
|
||||
|
||||
"\"KHR_materials_volume\""
|
||||
"\"thicknessFactor\""
|
||||
"\"thicknessTexture\""
|
||||
"\"attenuationColor\""
|
||||
"\"attenuationDistance\""
|
||||
|
||||
"\"KHR_materials_sheen\""
|
||||
"\"sheenColorFactor\""
|
||||
"\"sheenColorTexture\""
|
||||
"\"sheenRoughnessFactor\""
|
||||
"\"sheenRoughnessTexture\""
|
||||
|
||||
"\"KHR_materials_emissive_strength\""
|
||||
"\"emissiveStrength"\""
|
22
source/engine/thirdparty/cgltf/fuzz/main.c
vendored
22
source/engine/thirdparty/cgltf/fuzz/main.c
vendored
|
@ -1,22 +0,0 @@
|
|||
/* How to fuzz:
|
||||
|
||||
clang main.c -O2 -g -fsanitize=address,fuzzer -o fuzz
|
||||
cp -r data temp
|
||||
./fuzz temp/ -dict=gltf.dict -jobs=12 -workers=12
|
||||
|
||||
*/
|
||||
#define CGLTF_IMPLEMENTATION
|
||||
#include "../cgltf.h"
|
||||
|
||||
int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size)
|
||||
{
|
||||
cgltf_options options = {cgltf_file_type_invalid};
|
||||
cgltf_data* data = NULL;
|
||||
cgltf_result res = cgltf_parse(&options, Data, Size, &data);
|
||||
if (res == cgltf_result_success)
|
||||
{
|
||||
cgltf_validate(data);
|
||||
cgltf_free(data);
|
||||
}
|
||||
return 0;
|
||||
}
|
|
@ -1,68 +0,0 @@
|
|||
cmake_minimum_required( VERSION 2.8 )
|
||||
|
||||
include_directories( ${CMAKE_CURRENT_SOURCE_DIR} )
|
||||
|
||||
set( EXE_NAME cgltf_test )
|
||||
add_executable( ${EXE_NAME} main.c )
|
||||
set_property( TARGET ${EXE_NAME} PROPERTY C_STANDARD 99 )
|
||||
if(MSVC)
|
||||
target_compile_options(${EXE_NAME} PRIVATE /W4 /WX)
|
||||
add_definitions( -D_CRT_SECURE_NO_WARNINGS)
|
||||
else()
|
||||
target_compile_options(${EXE_NAME} PRIVATE -Wall -Wextra -pedantic -Werror)
|
||||
target_compile_options(${EXE_NAME} PUBLIC -fsanitize=address)
|
||||
target_link_options(${EXE_NAME} PUBLIC -fsanitize=address)
|
||||
endif()
|
||||
install( TARGETS ${EXE_NAME} RUNTIME DESTINATION bin )
|
||||
|
||||
set( EXE_NAME test_conversion )
|
||||
add_executable( ${EXE_NAME} test_conversion.cpp )
|
||||
set_property( TARGET ${EXE_NAME} PROPERTY CXX_STANDARD 11 )
|
||||
if(MSVC)
|
||||
target_compile_options(${EXE_NAME} PRIVATE /W4 /WX)
|
||||
add_definitions( -D_CRT_SECURE_NO_WARNINGS)
|
||||
else()
|
||||
target_compile_options(${EXE_NAME} PRIVATE -Wall -Wextra -pedantic -Werror)
|
||||
target_compile_options(${EXE_NAME} PUBLIC -fsanitize=address)
|
||||
target_link_options(${EXE_NAME} PUBLIC -fsanitize=address)
|
||||
endif()
|
||||
install( TARGETS ${EXE_NAME} RUNTIME DESTINATION bin )
|
||||
|
||||
set( EXE_NAME test_write )
|
||||
add_executable( ${EXE_NAME} test_write.cpp )
|
||||
set_property( TARGET ${EXE_NAME} PROPERTY CXX_STANDARD 11 )
|
||||
if(MSVC)
|
||||
target_compile_options(${EXE_NAME} PRIVATE /W4 /WX)
|
||||
add_definitions( -D_CRT_SECURE_NO_WARNINGS)
|
||||
else()
|
||||
target_compile_options(${EXE_NAME} PRIVATE -Wall -Wextra -pedantic -Werror)
|
||||
target_compile_options(${EXE_NAME} PUBLIC -fsanitize=address)
|
||||
target_link_options(${EXE_NAME} PUBLIC -fsanitize=address)
|
||||
endif()
|
||||
install( TARGETS ${EXE_NAME} RUNTIME DESTINATION bin )
|
||||
|
||||
set( EXE_NAME test_math )
|
||||
add_executable( ${EXE_NAME} test_math.cpp )
|
||||
set_property( TARGET ${EXE_NAME} PROPERTY CXX_STANDARD 11 )
|
||||
if(MSVC)
|
||||
target_compile_options(${EXE_NAME} PRIVATE /W4 /WX)
|
||||
add_definitions( -D_CRT_SECURE_NO_WARNINGS)
|
||||
else()
|
||||
target_compile_options(${EXE_NAME} PRIVATE -Wall -Wextra -pedantic -Werror)
|
||||
target_compile_options(${EXE_NAME} PUBLIC -fsanitize=address)
|
||||
target_link_options(${EXE_NAME} PUBLIC -fsanitize=address)
|
||||
endif()
|
||||
install( TARGETS ${EXE_NAME} RUNTIME DESTINATION bin )
|
||||
|
||||
set( EXE_NAME test_strings )
|
||||
add_executable( ${EXE_NAME} test_strings.cpp )
|
||||
set_property( TARGET ${EXE_NAME} PROPERTY CXX_STANDARD 11 )
|
||||
if(MSVC)
|
||||
target_compile_options(${EXE_NAME} PRIVATE /W4 /WX)
|
||||
add_definitions( -D_CRT_SECURE_NO_WARNINGS)
|
||||
else()
|
||||
target_compile_options(${EXE_NAME} PRIVATE -Wall -Wextra -pedantic -Werror)
|
||||
target_compile_options(${EXE_NAME} PUBLIC -fsanitize=address)
|
||||
target_link_options(${EXE_NAME} PUBLIC -fsanitize=address)
|
||||
endif()
|
||||
install( TARGETS ${EXE_NAME} RUNTIME DESTINATION bin )
|
38
source/engine/thirdparty/cgltf/test/main.c
vendored
38
source/engine/thirdparty/cgltf/test/main.c
vendored
|
@ -1,38 +0,0 @@
|
|||
|
||||
|
||||
#define CGLTF_IMPLEMENTATION
|
||||
#include "../cgltf.h"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
if (argc < 2)
|
||||
{
|
||||
printf("err\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
cgltf_options options;
|
||||
memset(&options, 0, sizeof(cgltf_options));
|
||||
cgltf_data* data = NULL;
|
||||
cgltf_result result = cgltf_parse_file(&options, argv[1], &data);
|
||||
|
||||
if (result == cgltf_result_success)
|
||||
result = cgltf_load_buffers(&options, data, argv[1]);
|
||||
|
||||
if (result == cgltf_result_success)
|
||||
result = cgltf_validate(data);
|
||||
|
||||
printf("Result: %d\n", result);
|
||||
|
||||
if (result == cgltf_result_success)
|
||||
{
|
||||
printf("Type: %u\n", data->file_type);
|
||||
printf("Meshes: %u\n", (unsigned)data->meshes_count);
|
||||
}
|
||||
|
||||
cgltf_free(data);
|
||||
|
||||
return result;
|
||||
}
|
76
source/engine/thirdparty/cgltf/test/test_all.py
vendored
76
source/engine/thirdparty/cgltf/test/test_all.py
vendored
|
@ -1,76 +0,0 @@
|
|||
#!/usr/bin/env python
|
||||
|
||||
import os, sys
|
||||
from sys import platform
|
||||
|
||||
num_tested = 0
|
||||
num_errors = 0
|
||||
|
||||
def get_executable_path(name):
|
||||
if platform == "win32":
|
||||
return "build\\Debug\\" + name
|
||||
else:
|
||||
return "build/" + name
|
||||
|
||||
def is_ascii(s):
|
||||
return all(ord(c) < 128 for c in s)
|
||||
|
||||
def collect_files(path, type, name):
|
||||
global num_tested
|
||||
global num_errors
|
||||
exe = get_executable_path(name)
|
||||
for the_file in os.listdir(path):
|
||||
file_path = os.path.join(os.path.normpath(path), the_file)
|
||||
if os.path.isfile(file_path):
|
||||
if the_file.endswith(type):
|
||||
num_tested = num_tested +1
|
||||
if is_ascii(file_path):
|
||||
print("### " + name + " " + file_path)
|
||||
result = os.system("{0} \"{1}\"".format(exe, file_path))
|
||||
print("### Result: " + str(result) + "\n")
|
||||
if result != 0:
|
||||
num_errors = num_errors + 1
|
||||
print("Error.")
|
||||
sys.exit(1)
|
||||
elif os.path.isdir(file_path):
|
||||
collect_files(file_path, type, name)
|
||||
|
||||
if __name__ == "__main__":
|
||||
if not os.path.exists("build/"):
|
||||
os.makedirs("build/")
|
||||
os.chdir("build/")
|
||||
os.system("cmake ..")
|
||||
if os.system("cmake --build .") != 0:
|
||||
print("Unable to build.")
|
||||
exit(1)
|
||||
os.chdir("..")
|
||||
if not os.path.exists("glTF-Sample-Models/"):
|
||||
os.system("git init glTF-Sample-Models")
|
||||
os.chdir("glTF-Sample-Models")
|
||||
os.system("git remote add origin https://github.com/KhronosGroup/glTF-Sample-Models.git")
|
||||
os.system("git config core.sparsecheckout true")
|
||||
f = open(".git/info/sparse-checkout", "w+")
|
||||
f.write("2.0/*\n")
|
||||
f.close()
|
||||
os.system("git pull --depth=1 origin master")
|
||||
os.chdir("..")
|
||||
collect_files("glTF-Sample-Models/2.0/", ".glb", "cgltf_test")
|
||||
collect_files("glTF-Sample-Models/2.0/", ".gltf", "cgltf_test")
|
||||
collect_files("glTF-Sample-Models/2.0/", ".glb", "test_conversion")
|
||||
collect_files("glTF-Sample-Models/2.0/", ".gltf", "test_conversion")
|
||||
collect_files("glTF-Sample-Models/2.0/", ".gltf", "test_write")
|
||||
|
||||
result = os.system(get_executable_path("test_math"))
|
||||
if result != 0:
|
||||
num_errors = num_errors + 1
|
||||
print("Error.")
|
||||
sys.exit(1)
|
||||
|
||||
result = os.system(get_executable_path("test_strings"))
|
||||
if result != 0:
|
||||
num_errors = num_errors + 1
|
||||
print("Error.")
|
||||
sys.exit(1)
|
||||
|
||||
print("Tested files: " + str(num_tested))
|
||||
print("Errors: " + str(num_errors))
|
|
@ -1,92 +0,0 @@
|
|||
#define CGLTF_IMPLEMENTATION
|
||||
#include "../cgltf.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cmath>
|
||||
#include <cstdio>
|
||||
#include <limits>
|
||||
|
||||
static bool is_near(cgltf_float a, cgltf_float b)
|
||||
{
|
||||
return std::abs(a - b) < 10 * std::numeric_limits<cgltf_float>::min();
|
||||
}
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
if (argc < 2)
|
||||
{
|
||||
printf("err\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
cgltf_options options = {};
|
||||
cgltf_data* data = NULL;
|
||||
cgltf_result result = cgltf_parse_file(&options, argv[1], &data);
|
||||
|
||||
if (result == cgltf_result_success)
|
||||
result = cgltf_load_buffers(&options, data, argv[1]);
|
||||
|
||||
if (strstr(argv[1], "Draco"))
|
||||
{
|
||||
cgltf_free(data);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (result != cgltf_result_success)
|
||||
return result;
|
||||
|
||||
//const cgltf_accessor* blobs = data->accessors;
|
||||
cgltf_float element_float[16];
|
||||
cgltf_uint element_uint[4];
|
||||
for (cgltf_size blob_index = 0; blob_index < data->accessors_count; ++blob_index)
|
||||
{
|
||||
const cgltf_accessor* blob = data->accessors + blob_index;
|
||||
if (blob->is_sparse)
|
||||
{
|
||||
cgltf_size nfloats = cgltf_num_components(blob->type) * blob->count;
|
||||
cgltf_float* dense = (cgltf_float*) malloc(nfloats * sizeof(cgltf_float));
|
||||
if (cgltf_accessor_unpack_floats(blob, dense, nfloats) < nfloats) {
|
||||
printf("Unable to completely unpack a sparse accessor.\n");
|
||||
return -1;
|
||||
}
|
||||
free(dense);
|
||||
continue;
|
||||
}
|
||||
if (blob->has_max && blob->has_min)
|
||||
{
|
||||
cgltf_float min0 = std::numeric_limits<float>::max();
|
||||
cgltf_float max0 = std::numeric_limits<float>::lowest();
|
||||
for (cgltf_size index = 0; index < blob->count; index++)
|
||||
{
|
||||
cgltf_accessor_read_float(blob, index, element_float, 16);
|
||||
min0 = std::min(min0, element_float[0]);
|
||||
max0 = std::max(max0, element_float[0]);
|
||||
}
|
||||
if (!is_near(min0, blob->min[0]) || !is_near(max0, blob->max[0]))
|
||||
{
|
||||
printf("Computed [%f, %f] but expected [%f, %f]\n", min0, max0, blob->min[0], blob->max[0]);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
if (blob->has_max && blob->has_min && blob->component_type != cgltf_component_type_r_32f && blob->component_type != cgltf_component_type_invalid)
|
||||
{
|
||||
cgltf_uint min0 = std::numeric_limits<unsigned int>::max();
|
||||
cgltf_uint max0 = std::numeric_limits<unsigned int>::lowest();
|
||||
for ( cgltf_size index = 0; index < blob->count; index++ )
|
||||
{
|
||||
cgltf_accessor_read_uint( blob, index, element_uint, 4 );
|
||||
min0 = std::min( min0, element_uint[0] );
|
||||
max0 = std::max( max0, element_uint[0] );
|
||||
}
|
||||
if ( min0 != (unsigned int) blob->min[0] || max0 != (unsigned int) blob->max[0] )
|
||||
{
|
||||
printf( "Computed [%u, %u] but expected [%u, %u]\n", min0, max0, (unsigned int) blob->min[0], (unsigned int) blob->max[0] );
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
cgltf_free(data);
|
||||
|
||||
return result;
|
||||
}
|
|
@ -1,52 +0,0 @@
|
|||
#define CGLTF_IMPLEMENTATION
|
||||
#include "../cgltf.h"
|
||||
|
||||
// Performs matrix-vector multiplication, as in (4x4) * (4x1) = (4x1)
|
||||
static void transform(const cgltf_float matrix[16], const cgltf_float source[4], cgltf_float target[4]) {
|
||||
target[0] = matrix[0] * source[0] + matrix[4] * source[1] + matrix[ 8] * source[2] + matrix[12] * source[3];
|
||||
target[1] = matrix[1] * source[0] + matrix[5] * source[1] + matrix[ 9] * source[2] + matrix[13] * source[3];
|
||||
target[2] = matrix[2] * source[0] + matrix[6] * source[1] + matrix[10] * source[2] + matrix[14] * source[3];
|
||||
target[3] = matrix[3] * source[0] + matrix[7] * source[1] + matrix[11] * source[2] + matrix[15] * source[3];
|
||||
}
|
||||
|
||||
static void set(cgltf_float target[3], float x, float y, float z) {
|
||||
target[0] = x;
|
||||
target[1] = y;
|
||||
target[2] = z;
|
||||
}
|
||||
|
||||
static void check(cgltf_float target[3], float x, float y, float z) {
|
||||
if (target[0] != x || target[1] != y || target[2] != z) {
|
||||
fprintf(stderr, "Mismatch detected.\n");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
int main(int, char**)
|
||||
{
|
||||
cgltf_node node = {};
|
||||
|
||||
cgltf_float matrix[16];
|
||||
cgltf_float source[4] = {1, 2, 3, 1};
|
||||
cgltf_float target[4];
|
||||
|
||||
set(node.scale, 1, 1, 1);
|
||||
set(node.translation, 1, 0, 0);
|
||||
cgltf_node_transform_local(&node, matrix);
|
||||
transform(matrix, source, target);
|
||||
check(target, 2, 2, 3);
|
||||
|
||||
set(node.scale, 3, 1, 1);
|
||||
set(node.translation, 0, 0, 0);
|
||||
cgltf_node_transform_local(&node, matrix);
|
||||
transform(matrix, source, target);
|
||||
check(target, 3, 2, 3);
|
||||
|
||||
set(node.scale, 1, 3, 1);
|
||||
set(node.translation, 1, 0, 0);
|
||||
cgltf_node_transform_local(&node, matrix);
|
||||
transform(matrix, source, target);
|
||||
check(target, 2, 6, 3);
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -1,57 +0,0 @@
|
|||
#define CGLTF_IMPLEMENTATION
|
||||
#include "../cgltf.h"
|
||||
|
||||
#include <cstring>
|
||||
|
||||
static void check(const char* a, const char* b, cgltf_size size) {
|
||||
if (strcmp(a, b) != 0 || strlen(a) != size) {
|
||||
fprintf(stderr, "Mismatch detected.\n");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
int main(int, char**)
|
||||
{
|
||||
char string[64];
|
||||
cgltf_size size;
|
||||
|
||||
// cgltf_decode_string
|
||||
strcpy(string, "");
|
||||
size = cgltf_decode_string(string);
|
||||
check(string, "", size);
|
||||
|
||||
strcpy(string, "nothing to replace");
|
||||
size = cgltf_decode_string(string);
|
||||
check(string, "nothing to replace", size);
|
||||
|
||||
strcpy(string, "\\\" \\/ \\\\ \\b \\f \\r \\n \\t \\u0030");
|
||||
size = cgltf_decode_string(string);
|
||||
check(string, "\" / \\ \b \f \r \n \t 0", size);
|
||||
|
||||
strcpy(string, "test \\u121b\\u130d\\u1294\\u1276\\u127d test");
|
||||
size = cgltf_decode_string(string);
|
||||
check(string, "test ማግኔቶች test", size);
|
||||
|
||||
// cgltf_decode_uri
|
||||
strcpy(string, "");
|
||||
size = cgltf_decode_uri(string);
|
||||
check(string, "", size);
|
||||
|
||||
strcpy(string, "nothing to replace");
|
||||
size = cgltf_decode_uri(string);
|
||||
check(string, "nothing to replace", size);
|
||||
|
||||
strcpy(string, "%2F%D0%BA%D0%B8%D1%80%D0%B8%D0%BB%D0%BB%D0%B8%D1%86%D0%B0");
|
||||
size = cgltf_decode_uri(string);
|
||||
check(string, "/кириллица", size);
|
||||
|
||||
strcpy(string, "test%20%E1%88%9B%E1%8C%8D%E1%8A%94%E1%89%B6%E1%89%BD%20test");
|
||||
size = cgltf_decode_uri(string);
|
||||
check(string, "test ማግኔቶች test", size);
|
||||
|
||||
strcpy(string, "%%2F%X%AX%%2F%%");
|
||||
size = cgltf_decode_uri(string);
|
||||
check(string, "%/%X%AX%/%%", size);
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -1,45 +0,0 @@
|
|||
#define CGLTF_IMPLEMENTATION
|
||||
#define CGLTF_WRITE_IMPLEMENTATION
|
||||
#include "../cgltf_write.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cmath>
|
||||
#include <cstdio>
|
||||
#include <limits>
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
if (argc < 2)
|
||||
{
|
||||
printf("err\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
cgltf_options options = {};
|
||||
cgltf_data* data0 = NULL;
|
||||
cgltf_result result = cgltf_parse_file(&options, argv[1], &data0);
|
||||
|
||||
// Silently skip over files that are unreadable since this is a writing test.
|
||||
if (result != cgltf_result_success)
|
||||
{
|
||||
return cgltf_result_success;
|
||||
}
|
||||
|
||||
result = cgltf_write_file(&options, "out.gltf", data0);
|
||||
if (result != cgltf_result_success)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
cgltf_data* data1 = NULL;
|
||||
result = cgltf_parse_file(&options, "out.gltf", &data1);
|
||||
if (result != cgltf_result_success)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
if (data0->meshes_count != data1->meshes_count) {
|
||||
return -1;
|
||||
}
|
||||
cgltf_free(data1);
|
||||
cgltf_free(data0);
|
||||
return cgltf_result_success;
|
||||
}
|
|
@ -1 +0,0 @@
|
|||
github: mackron
|
12
source/engine/thirdparty/dr_libs/.gitignore
vendored
12
source/engine/thirdparty/dr_libs/.gitignore
vendored
|
@ -1,12 +0,0 @@
|
|||
docs
|
||||
tests/testvectors/opus/*
|
||||
!tests/testvectors/opus/DO_NOT_DELETE.md
|
||||
tests/bin/*
|
||||
!tests/bin/DO_NOT_DELETE.md
|
||||
tests/build
|
||||
tests/flac/include
|
||||
tests/flac/lib
|
||||
tests/testvectors/flac/tests/*
|
||||
!tests/testvectors/flac/tests/DO_NOT_DELETE.md
|
||||
todo
|
||||
_private
|
3
source/engine/thirdparty/dr_libs/.gitmodules
vendored
3
source/engine/thirdparty/dr_libs/.gitmodules
vendored
|
@ -1,3 +0,0 @@
|
|||
[submodule "tests/external/miniaudio"]
|
||||
path = tests/external/miniaudio
|
||||
url = https://github.com/dr-soft/miniaudio.git
|
4755
source/engine/thirdparty/dr_libs/old/dr.h
vendored
4755
source/engine/thirdparty/dr_libs/old/dr.h
vendored
File diff suppressed because it is too large
Load diff
3417
source/engine/thirdparty/dr_libs/old/dr_2d.h
vendored
3417
source/engine/thirdparty/dr_libs/old/dr_2d.h
vendored
File diff suppressed because it is too large
Load diff
5307
source/engine/thirdparty/dr_libs/old/dr_audio.h
vendored
5307
source/engine/thirdparty/dr_libs/old/dr_audio.h
vendored
File diff suppressed because it is too large
Load diff
4310
source/engine/thirdparty/dr_libs/old/dr_audio_ancient.h
vendored
4310
source/engine/thirdparty/dr_libs/old/dr_audio_ancient.h
vendored
File diff suppressed because it is too large
Load diff
8051
source/engine/thirdparty/dr_libs/old/dr_fs.h
vendored
8051
source/engine/thirdparty/dr_libs/old/dr_fs.h
vendored
File diff suppressed because it is too large
Load diff
1625
source/engine/thirdparty/dr_libs/old/dr_fsw.h
vendored
1625
source/engine/thirdparty/dr_libs/old/dr_fsw.h
vendored
File diff suppressed because it is too large
Load diff
17167
source/engine/thirdparty/dr_libs/old/dr_gui.h
vendored
17167
source/engine/thirdparty/dr_libs/old/dr_gui.h
vendored
File diff suppressed because it is too large
Load diff
676
source/engine/thirdparty/dr_libs/old/dr_math.h
vendored
676
source/engine/thirdparty/dr_libs/old/dr_math.h
vendored
|
@ -1,676 +0,0 @@
|
|||
// Public Domain. See "unlicense" statement at the end of this file.
|
||||
|
||||
// NOTE: This is still very much work in progress and is only being updated as I need it. You don't want to be using this library
|
||||
// in its current state.
|
||||
|
||||
// QUICK NOTES
|
||||
// - This library does not use SSE for its basic types (vec4, etc.). Rationale: 1) It keeps things simple; 2) SSE is not always
|
||||
// faster than the FPU(s) on modern CPUs; 3) The library can always implement functions that work on __m128 variables directly
|
||||
// in the future if the need arises; 4) It doesn't work well with the pass-by-value API this library uses.
|
||||
// - Use DISABLE_SSE to disable SSE optimized functions.
|
||||
// - Angles are always specified in radians, unless otherwise noted. Rationale: Consistency with the standard library and most
|
||||
// other math libraries.
|
||||
// - Use radians() and degrees() to convert between the two.
|
||||
|
||||
#ifndef dr_math_h
|
||||
#define dr_math_h
|
||||
|
||||
#include <math.h>
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#define DR_MATHCALL static __forceinline
|
||||
#else
|
||||
#define DR_MATHCALL static inline
|
||||
#endif
|
||||
|
||||
#define DR_PI 3.14159265358979323846
|
||||
#define DR_PIF 3.14159265358979323846f
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef struct
|
||||
{
|
||||
float x;
|
||||
float y;
|
||||
float z;
|
||||
float w;
|
||||
} vec4;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
float x;
|
||||
float y;
|
||||
float z;
|
||||
} vec3;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
float x;
|
||||
float y;
|
||||
} vec2;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
vec4 col[4];
|
||||
} mat4;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
float x;
|
||||
float y;
|
||||
float z;
|
||||
float w;
|
||||
} quat;
|
||||
|
||||
|
||||
// Radians to degrees.
|
||||
DR_MATHCALL float dr_degrees(float radians)
|
||||
{
|
||||
return radians * 57.29577951308232087685f;
|
||||
}
|
||||
|
||||
// Degrees to radians.
|
||||
DR_MATHCALL float dr_radians(float degrees)
|
||||
{
|
||||
return degrees * 0.01745329251994329577f;
|
||||
}
|
||||
|
||||
|
||||
|
||||
///////////////////////////////////////////////
|
||||
//
|
||||
// VEC4
|
||||
//
|
||||
///////////////////////////////////////////////
|
||||
|
||||
DR_MATHCALL vec4 vec4f(float x, float y, float z, float w)
|
||||
{
|
||||
vec4 result;
|
||||
result.x = x;
|
||||
result.y = y;
|
||||
result.z = z;
|
||||
result.w = w;
|
||||
|
||||
return result;
|
||||
}
|
||||
DR_MATHCALL vec4 vec4v(const float* v)
|
||||
{
|
||||
return vec4f(v[0], v[1], v[2], v[3]);
|
||||
}
|
||||
DR_MATHCALL vec4 vec4_zero()
|
||||
{
|
||||
return vec4f(0, 0, 0, 0);
|
||||
}
|
||||
DR_MATHCALL vec4 vec4_one()
|
||||
{
|
||||
return vec4f(1, 1, 1, 1);
|
||||
}
|
||||
|
||||
|
||||
|
||||
DR_MATHCALL vec4 vec4_add(vec4 a, vec4 b)
|
||||
{
|
||||
return vec4f(a.x + b.x, a.y + b.y, a.z + b.z, a.w + b.w);
|
||||
}
|
||||
|
||||
DR_MATHCALL vec4 vec4_sub(vec4 a, vec4 b)
|
||||
{
|
||||
return vec4f(a.x - b.x, a.y - b.y, a.z - b.z, a.w - b.w);
|
||||
}
|
||||
|
||||
|
||||
DR_MATHCALL vec4 vec4_mul(vec4 a, vec4 b)
|
||||
{
|
||||
return vec4f(a.x * b.x, a.y * b.y, a.z * b.z, a.w * b.w);
|
||||
}
|
||||
DR_MATHCALL vec4 vec4_mul_1f(vec4 a, float x)
|
||||
{
|
||||
return vec4f(a.x * x, a.y * x, a.z * x, a.w * x);
|
||||
}
|
||||
DR_MATHCALL vec4 vec4_mul_mat4(vec4 v, mat4 m)
|
||||
{
|
||||
const vec4 m0 = m.col[0];
|
||||
const vec4 m1 = m.col[1];
|
||||
const vec4 m2 = m.col[2];
|
||||
const vec4 m3 = m.col[3];
|
||||
|
||||
return vec4f(
|
||||
m0.x*v.x + m0.y*v.y + m0.z*v.z + m0.w*v.w,
|
||||
m1.x*v.x + m1.y*v.y + m1.z*v.z + m1.w*v.w,
|
||||
m2.x*v.x + m2.y*v.y + m2.z*v.z + m2.w*v.w,
|
||||
m3.x*v.x + m3.y*v.y + m3.z*v.z + m3.w*v.w
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
DR_MATHCALL vec4 vec4_div(vec4 a, vec4 b)
|
||||
{
|
||||
return vec4f(a.x / b.x, a.y / b.y, a.z / b.z, a.w / b.w);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
///////////////////////////////////////////////
|
||||
//
|
||||
// VEC3
|
||||
//
|
||||
///////////////////////////////////////////////
|
||||
|
||||
DR_MATHCALL vec3 vec3f(float x, float y, float z)
|
||||
{
|
||||
vec3 result;
|
||||
result.x = x;
|
||||
result.y = y;
|
||||
result.z = z;
|
||||
|
||||
return result;
|
||||
}
|
||||
DR_MATHCALL vec3 vec3v(const float* v)
|
||||
{
|
||||
return vec3f(v[0], v[1], v[2]);
|
||||
}
|
||||
DR_MATHCALL vec3 vec3_zero()
|
||||
{
|
||||
return vec3f(0, 0, 0);
|
||||
}
|
||||
DR_MATHCALL vec3 vec3_one()
|
||||
{
|
||||
return vec3f(1, 1, 1);
|
||||
}
|
||||
|
||||
|
||||
DR_MATHCALL vec3 vec3_add(vec3 a, vec3 b)
|
||||
{
|
||||
return vec3f(a.x + b.x, a.y + b.y, a.z + b.z);
|
||||
}
|
||||
|
||||
DR_MATHCALL vec3 vec3_sub(vec3 a, vec3 b)
|
||||
{
|
||||
return vec3f(a.x - b.x, a.y - b.y, a.z - b.z);
|
||||
}
|
||||
|
||||
|
||||
DR_MATHCALL vec3 vec3_mul(vec3 a, vec3 b)
|
||||
{
|
||||
return vec3f(a.x * b.x, a.y * b.y, a.z * b.z);
|
||||
}
|
||||
DR_MATHCALL vec3 vec3_mul_1f(vec3 a, float x)
|
||||
{
|
||||
return vec3f(a.x * x, a.y * x, a.z * x);
|
||||
}
|
||||
|
||||
|
||||
DR_MATHCALL vec3 vec3_div(vec3 a, vec3 b)
|
||||
{
|
||||
return vec3f(a.x / b.x, a.y / b.y, a.z / b.z);
|
||||
}
|
||||
|
||||
|
||||
DR_MATHCALL float vec3_dot(vec3 a, vec3 b)
|
||||
{
|
||||
return a.x*b.x + a.y*b.y + a.z*b.z;
|
||||
}
|
||||
|
||||
|
||||
DR_MATHCALL float vec3_length2(vec3 a)
|
||||
{
|
||||
return vec3_dot(a, a);
|
||||
}
|
||||
|
||||
DR_MATHCALL float vec3_length(vec3 a)
|
||||
{
|
||||
return sqrtf(vec3_length2(a));
|
||||
}
|
||||
|
||||
|
||||
DR_MATHCALL vec3 vec3_normalize(vec3 a)
|
||||
{
|
||||
float len = vec3_length(a);
|
||||
|
||||
return vec3f(
|
||||
a.x / len,
|
||||
a.y / len,
|
||||
a.z / len
|
||||
);
|
||||
}
|
||||
|
||||
DR_MATHCALL vec3 vec3_cross(vec3 a, vec3 b)
|
||||
{
|
||||
return vec3f(
|
||||
a.y*b.z - a.z*b.y,
|
||||
a.z*b.x - a.x*b.z,
|
||||
a.x*b.y - a.y*b.x
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
DR_MATHCALL vec3 vec3_triangle_normal(vec3 p1, vec3 p2, vec3 p3)
|
||||
{
|
||||
vec3 u = vec3_sub(p2, p1);
|
||||
vec3 v = vec3_sub(p3, p1);
|
||||
return vec3_normalize(vec3_cross(u, v));
|
||||
}
|
||||
|
||||
|
||||
|
||||
///////////////////////////////////////////////
|
||||
//
|
||||
// VEC2
|
||||
//
|
||||
///////////////////////////////////////////////
|
||||
|
||||
DR_MATHCALL vec2 vec2f(float x, float y)
|
||||
{
|
||||
vec2 result;
|
||||
result.x = x;
|
||||
result.y = y;
|
||||
|
||||
return result;
|
||||
}
|
||||
DR_MATHCALL vec2 vec2v(const float* v)
|
||||
{
|
||||
return vec2f(v[0], v[1]);
|
||||
}
|
||||
DR_MATHCALL vec2 vec2_zero()
|
||||
{
|
||||
return vec2f(0, 0);
|
||||
}
|
||||
DR_MATHCALL vec2 vec2_one()
|
||||
{
|
||||
return vec2f(1, 1);
|
||||
}
|
||||
|
||||
|
||||
DR_MATHCALL vec2 vec2_add(vec2 a, vec2 b)
|
||||
{
|
||||
return vec2f(a.x + b.x, a.y + b.y);
|
||||
}
|
||||
|
||||
DR_MATHCALL vec2 vec2_sub(vec2 a, vec2 b)
|
||||
{
|
||||
return vec2f(a.x - b.x, a.y - b.y);
|
||||
}
|
||||
|
||||
|
||||
DR_MATHCALL vec2 vec2_mul(vec2 a, vec2 b)
|
||||
{
|
||||
return vec2f(a.x * b.x, a.y * b.y);
|
||||
}
|
||||
DR_MATHCALL vec2 vec2_mul_1f(vec2 a, float x)
|
||||
{
|
||||
return vec2f(a.x * x, a.y * x);
|
||||
}
|
||||
|
||||
|
||||
DR_MATHCALL vec2 vec2_div(vec2 a, vec2 b)
|
||||
{
|
||||
return vec2f(a.x / b.x, a.y / b.y);
|
||||
}
|
||||
|
||||
|
||||
DR_MATHCALL float vec2_dot(vec2 a, vec2 b)
|
||||
{
|
||||
return a.x*b.x + a.y*b.y;
|
||||
}
|
||||
|
||||
|
||||
DR_MATHCALL float vec2_length2(vec2 a)
|
||||
{
|
||||
return vec2_dot(a, a);
|
||||
}
|
||||
|
||||
DR_MATHCALL float vec2_length(vec2 a)
|
||||
{
|
||||
return sqrtf(vec2_length2(a));
|
||||
}
|
||||
|
||||
|
||||
DR_MATHCALL vec2 vec2_normalize(vec2 a)
|
||||
{
|
||||
float len = vec2_length(a);
|
||||
|
||||
return vec2f(
|
||||
a.x / len,
|
||||
a.y / len
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
DR_MATHCALL float vec2_angle(vec2 a, vec2 b)
|
||||
{
|
||||
return atanf(a.y / a.x) - atanf(b.y / b.x);
|
||||
}
|
||||
|
||||
DR_MATHCALL vec2 vec2_rotate(vec2 a, float angleInRadians)
|
||||
{
|
||||
float c = cosf(angleInRadians);
|
||||
float s = sinf(angleInRadians);
|
||||
|
||||
return vec2f(
|
||||
a.x*c - a.y*s,
|
||||
a.x*s + a.y*c
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////
|
||||
//
|
||||
// MAT4
|
||||
//
|
||||
///////////////////////////////////////////////
|
||||
|
||||
DR_MATHCALL mat4 mat4f(vec4 col0, vec4 col1, vec4 col2, vec4 col3)
|
||||
{
|
||||
mat4 result;
|
||||
result.col[0] = col0;
|
||||
result.col[1] = col1;
|
||||
result.col[2] = col2;
|
||||
result.col[3] = col3;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
DR_MATHCALL mat4 mat4_identity()
|
||||
{
|
||||
mat4 result;
|
||||
result.col[0] = vec4f(1, 0, 0, 0);
|
||||
result.col[1] = vec4f(0, 1, 0, 0);
|
||||
result.col[2] = vec4f(0, 0, 1, 0);
|
||||
result.col[3] = vec4f(0, 0, 0, 1);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
DR_MATHCALL mat4 mat4_ortho(float left, float right, float bottom, float top, float znear, float zfar)
|
||||
{
|
||||
float rml = right - left;
|
||||
float tmb = top - bottom;
|
||||
float fmn = zfar - znear;
|
||||
|
||||
float rpl = right + left;
|
||||
float tpb = top + bottom;
|
||||
float fpn = zfar + znear;
|
||||
|
||||
mat4 result;
|
||||
result.col[0] = vec4f(2/rml, 0, 0, 0);
|
||||
result.col[1] = vec4f(0, 2/tmb, 0, 0);
|
||||
result.col[2] = vec4f(0, 0, -2/fmn, 0);
|
||||
result.col[3] = vec4f(-(rpl/rml), -(tpb/tmb), -(fpn/fmn), 1);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
DR_MATHCALL mat4 mat4_perspective(float fovy, float aspect, float znear, float zfar)
|
||||
{
|
||||
float f = (float)tan(DR_PI/2 - fovy/2);
|
||||
|
||||
mat4 result;
|
||||
result.col[0] = vec4f(f / aspect, 0, 0, 0);
|
||||
result.col[1] = vec4f(0, f, 0, 0);
|
||||
result.col[2] = vec4f(0, 0, (zfar + znear) / (znear - zfar), -1);
|
||||
result.col[3] = vec4f(0, 0, (2 * zfar * znear) / (znear - zfar), 0);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
DR_MATHCALL mat4 mat4_vulkan_clip_correction()
|
||||
{
|
||||
mat4 result;
|
||||
result.col[0] = vec4f(1, 0, 0, 0);
|
||||
result.col[1] = vec4f(0, -1, 0, 0);
|
||||
result.col[2] = vec4f(0, 0, 0.5f, 0);
|
||||
result.col[3] = vec4f(0, 0, 0.5f, 1);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
DR_MATHCALL mat4 mat4_translate(vec3 translation)
|
||||
{
|
||||
mat4 result;
|
||||
result.col[0] = vec4f(1, 0, 0, 0);
|
||||
result.col[1] = vec4f(0, 1, 0, 0);
|
||||
result.col[2] = vec4f(0, 0, 1, 0);
|
||||
result.col[3] = vec4f(translation.x, translation.y, translation.z, 1);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
DR_MATHCALL mat4 mat4_rotate(float angleInRadians, vec3 axis)
|
||||
{
|
||||
float c = cosf(angleInRadians);
|
||||
float s = sinf(angleInRadians);
|
||||
|
||||
float x = axis.x;
|
||||
float y = axis.y;
|
||||
float z = axis.z;
|
||||
|
||||
float xx = x*x;
|
||||
float xy = x*y;
|
||||
float xz = x*z;
|
||||
float yy = y*y;
|
||||
float yz = y*z;
|
||||
float zz = z*z;
|
||||
|
||||
float xs = x*s;
|
||||
float ys = y*s;
|
||||
float zs = z*s;
|
||||
|
||||
mat4 result;
|
||||
result.col[0] = vec4f(xx * (1 - c) + c, xy * (1 - c) - zs, xz * (1 - c) + ys, 0);
|
||||
result.col[1] = vec4f(xy * (1 - c) + zs, yy * (1 - c) + c, yz * (1 - c) - xs, 0);
|
||||
result.col[2] = vec4f(xz * (1 - c) - ys, yz * (1 - c) + xs, zz * (1 - c) + c, 0);
|
||||
result.col[3] = vec4f(0, 0, 0, 1);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
DR_MATHCALL mat4 mat4_scale(vec3 scale)
|
||||
{
|
||||
mat4 result;
|
||||
result.col[0] = vec4f(scale.x, 0, 0, 0);
|
||||
result.col[1] = vec4f(0, scale.y, 0, 0);
|
||||
result.col[2] = vec4f(0, 0, scale.z, 0);
|
||||
result.col[3] = vec4f(0, 0, 0, 1);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
DR_MATHCALL mat4 mat4_mul(mat4 a, mat4 b)
|
||||
{
|
||||
const vec4 a0 = a.col[0];
|
||||
const vec4 a1 = a.col[1];
|
||||
const vec4 a2 = a.col[2];
|
||||
const vec4 a3 = a.col[3];
|
||||
|
||||
const vec4 b0 = b.col[0];
|
||||
const vec4 b1 = b.col[1];
|
||||
const vec4 b2 = b.col[2];
|
||||
const vec4 b3 = b.col[3];
|
||||
|
||||
mat4 result;
|
||||
result.col[0] = vec4f(
|
||||
a0.x*b0.x + a1.x*b0.y + a2.x*b0.z + a3.x*b0.w,
|
||||
a0.y*b0.x + a1.y*b0.y + a2.y*b0.z + a3.y*b0.w,
|
||||
a0.z*b0.x + a1.z*b0.y + a2.z*b0.z + a3.z*b0.w,
|
||||
a0.w*b0.x + a1.w*b0.y + a2.w*b0.z + a3.w*b0.w
|
||||
);
|
||||
|
||||
result.col[1] = vec4f(
|
||||
a0.x*b1.x + a1.x*b1.y + a2.x*b1.z + a3.x*b1.w,
|
||||
a0.y*b1.x + a1.y*b1.y + a2.y*b1.z + a3.y*b1.w,
|
||||
a0.z*b1.x + a1.z*b1.y + a2.z*b1.z + a3.z*b1.w,
|
||||
a0.w*b1.x + a1.w*b1.y + a2.w*b1.z + a3.w*b1.w
|
||||
);
|
||||
|
||||
result.col[2] = vec4f(
|
||||
a0.x*b2.x + a1.x*b2.y + a2.x*b2.z + a3.x*b2.w,
|
||||
a0.y*b2.x + a1.y*b2.y + a2.y*b2.z + a3.y*b2.w,
|
||||
a0.z*b2.x + a1.z*b2.y + a2.z*b2.z + a3.z*b2.w,
|
||||
a0.w*b2.x + a1.w*b2.y + a2.w*b2.z + a3.w*b2.w
|
||||
);
|
||||
|
||||
result.col[3] = vec4f(
|
||||
a0.x*b3.x + a1.x*b3.y + a2.x*b3.z + a3.x*b3.w,
|
||||
a0.y*b3.x + a1.y*b3.y + a2.y*b3.z + a3.y*b3.w,
|
||||
a0.z*b3.x + a1.z*b3.y + a2.z*b3.z + a3.z*b3.w,
|
||||
a0.w*b3.x + a1.w*b3.y + a2.w*b3.z + a3.w*b3.w
|
||||
);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
DR_MATHCALL vec4 mat4_mul_vec4(mat4 m, vec4 v)
|
||||
{
|
||||
const vec4 m0 = m.col[0];
|
||||
const vec4 m1 = m.col[1];
|
||||
const vec4 m2 = m.col[2];
|
||||
const vec4 m3 = m.col[3];
|
||||
|
||||
return vec4f(
|
||||
m0.x*v.x + m1.x*v.y + m2.x*v.z + m3.x*v.w,
|
||||
m0.y*v.x + m1.y*v.y + m2.y*v.z + m3.y*v.w,
|
||||
m0.z*v.x + m1.z*v.y + m2.z*v.z + m3.z*v.w,
|
||||
m0.w*v.x + m1.w*v.y + m2.w*v.z + m3.w*v.w
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////
|
||||
//
|
||||
// QUAT
|
||||
//
|
||||
///////////////////////////////////////////////
|
||||
|
||||
DR_MATHCALL quat quatf(float x, float y, float z, float w)
|
||||
{
|
||||
quat result;
|
||||
result.x = x;
|
||||
result.y = y;
|
||||
result.z = z;
|
||||
result.w = w;
|
||||
|
||||
return result;
|
||||
}
|
||||
DR_MATHCALL quat quatv(const float* v)
|
||||
{
|
||||
return quatf(v[0], v[1], v[2], v[3]);
|
||||
}
|
||||
|
||||
DR_MATHCALL quat quat_identity()
|
||||
{
|
||||
return quatf(0, 0, 0, 1);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
///////////////////////////////////////////////
|
||||
//
|
||||
// TRANSFORM
|
||||
//
|
||||
///////////////////////////////////////////////
|
||||
|
||||
typedef struct
|
||||
{
|
||||
vec3 position;
|
||||
quat rotation;
|
||||
vec3 scale;
|
||||
}transform_t;
|
||||
|
||||
DR_MATHCALL transform_t transform_init(vec3 position, quat rotation, vec3 scale)
|
||||
{
|
||||
transform_t result;
|
||||
result.position = position;
|
||||
result.rotation = rotation;
|
||||
result.scale = scale;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
DR_MATHCALL transform_t transform_identity()
|
||||
{
|
||||
transform_t result;
|
||||
result.position = vec3_zero();
|
||||
result.rotation = quat_identity();
|
||||
result.scale = vec3_one();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
DR_MATHCALL transform_t transform_translate(transform_t transform, vec3 offset)
|
||||
{
|
||||
transform_t result = transform;
|
||||
result.position = vec3_add(transform.position, offset);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
///////////////////////////////////////////////
|
||||
//
|
||||
// SSE IMPLEMENTATION
|
||||
//
|
||||
///////////////////////////////////////////////
|
||||
|
||||
// Not supporting SSE on x86/MSVC due to pass-by-value errors with aligned types.
|
||||
#if (defined(_MSC_VER) && defined(_M_X64)) || defined(__SSE2__)
|
||||
#define SUPPORTS_SSE
|
||||
#endif
|
||||
|
||||
#if !defined(DISABLE_SSE) && defined(SUPPORTS_SSE)
|
||||
#define ENABLE_SSE
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_SSE
|
||||
#if defined(__MINGW32__)
|
||||
#include <intrin.h>
|
||||
#endif
|
||||
#include <emmintrin.h>
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif //dr_math_h
|
||||
|
||||
/*
|
||||
This is free and unencumbered software released into the public domain.
|
||||
|
||||
Anyone is free to copy, modify, publish, use, compile, sell, or
|
||||
distribute this software, either in source code form or as a compiled
|
||||
binary, for any purpose, commercial or non-commercial, and by any
|
||||
means.
|
||||
|
||||
In jurisdictions that recognize copyright laws, the author or authors
|
||||
of this software dedicate any and all copyright interest in the
|
||||
software to the public domain. We make this dedication for the benefit
|
||||
of the public at large and to the detriment of our heirs and
|
||||
successors. We intend this dedication to be an overt act of
|
||||
relinquishment in perpetuity of all present and future rights to this
|
||||
software under copyright law.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
||||
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
For more information, please refer to <http://unlicense.org/>
|
||||
*/
|
4512
source/engine/thirdparty/dr_libs/old/dr_mtl.h
vendored
4512
source/engine/thirdparty/dr_libs/old/dr_mtl.h
vendored
File diff suppressed because it is too large
Load diff
793
source/engine/thirdparty/dr_libs/old/dr_pcx.h
vendored
793
source/engine/thirdparty/dr_libs/old/dr_pcx.h
vendored
|
@ -1,793 +0,0 @@
|
|||
// PCX image loader. Public domain. See "unlicense" statement at the end of this file.
|
||||
// dr_pcx - v0.3.1 - 2018-09-11
|
||||
//
|
||||
// David Reid - mackron@gmail.com
|
||||
|
||||
// USAGE
|
||||
//
|
||||
// dr_pcx is a single-file library. To use it, do something like the following in one .c file.
|
||||
// #define DR_PCX_IMPLEMENTATION
|
||||
// #include "dr_pcx.h"
|
||||
//
|
||||
// You can then #include this file in other parts of the program as you would with any other header file. Do something like
|
||||
// the following to load and decode an image:
|
||||
//
|
||||
// int width;
|
||||
// int height;
|
||||
// int components
|
||||
// drpcx_uint8* pImageData = drpcx_load_file("my_image.pcx", DRPCX_FALSE, &width, &height, &components, 0);
|
||||
// if (pImageData == NULL) {
|
||||
// // Failed to load image.
|
||||
// }
|
||||
//
|
||||
// ...
|
||||
//
|
||||
// drpcx_free(pImageData);
|
||||
//
|
||||
// The boolean parameter (second argument in the above example) is whether or not the image should be flipped upside down.
|
||||
//
|
||||
//
|
||||
//
|
||||
// OPTIONS
|
||||
// #define these options before including this file.
|
||||
//
|
||||
// #define DR_PCX_NO_STDIO
|
||||
// Disable drpcx_load_file().
|
||||
//
|
||||
//
|
||||
//
|
||||
// QUICK NOTES
|
||||
// - 2-bpp/4-plane and 4-bpp/1-plane formats have not been tested.
|
||||
|
||||
#ifndef dr_pcx_h
|
||||
#define dr_pcx_h
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#if defined(_MSC_VER) && _MSC_VER < 1600
|
||||
typedef signed char drpcx_int8;
|
||||
typedef unsigned char drpcx_uint8;
|
||||
typedef signed short drpcx_int16;
|
||||
typedef unsigned short drpcx_uint16;
|
||||
typedef signed int drpcx_int32;
|
||||
typedef unsigned int drpcx_uint32;
|
||||
typedef signed __int64 drpcx_int64;
|
||||
typedef unsigned __int64 drpcx_uint64;
|
||||
#else
|
||||
#include <stdint.h>
|
||||
typedef int8_t drpcx_int8;
|
||||
typedef uint8_t drpcx_uint8;
|
||||
typedef int16_t drpcx_int16;
|
||||
typedef uint16_t drpcx_uint16;
|
||||
typedef int32_t drpcx_int32;
|
||||
typedef uint32_t drpcx_uint32;
|
||||
typedef int64_t drpcx_int64;
|
||||
typedef uint64_t drpcx_uint64;
|
||||
#endif
|
||||
typedef drpcx_uint8 drpcx_bool8;
|
||||
typedef drpcx_uint32 drpcx_bool32;
|
||||
#define DRPCX_TRUE 1
|
||||
#define DRPCX_FALSE 0
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
// Callback for when data is read. Return value is the number of bytes actually read.
|
||||
typedef size_t (* drpcx_read_proc)(void* userData, void* bufferOut, size_t bytesToRead);
|
||||
|
||||
|
||||
// Loads a PCX file using the given callbacks.
|
||||
drpcx_uint8* drpcx_load(drpcx_read_proc onRead, void* pUserData, drpcx_bool32 flipped, int* x, int* y, int* internalComponents, int desiredComponents);
|
||||
|
||||
// Frees memory returned by drpcx_load() and family.
|
||||
void drpcx_free(void* pReturnValueFromLoad);
|
||||
|
||||
|
||||
#ifndef DR_PCX_NO_STDIO
|
||||
// Loads an PCX file from an actual file.
|
||||
drpcx_uint8* drpcx_load_file(const char* filename, drpcx_bool32 flipped, int* x, int* y, int* internalComponents, int desiredComponents);
|
||||
#endif
|
||||
|
||||
// Helper for loading an PCX file from a block of memory.
|
||||
drpcx_uint8* drpcx_load_memory(const void* data, size_t dataSize, drpcx_bool32 flipped, int* x, int* y, int* internalComponents, int desiredComponents);
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // dr_pcx_h
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// IMPLEMENTATION
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
#ifdef DR_PCX_IMPLEMENTATION
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
|
||||
#ifndef DR_PCX_NO_STDIO
|
||||
#include <stdio.h>
|
||||
|
||||
static size_t drpcx__on_read_stdio(void* pUserData, void* bufferOut, size_t bytesToRead)
|
||||
{
|
||||
return fread(bufferOut, 1, bytesToRead, (FILE*)pUserData);
|
||||
}
|
||||
|
||||
drpcx_uint8* drpcx_load_file(const char* filename, drpcx_bool32 flipped, int* x, int* y, int* internalComponents, int desiredComponents)
|
||||
{
|
||||
FILE* pFile;
|
||||
#ifdef _MSC_VER
|
||||
if (fopen_s(&pFile, filename, "rb") != 0) {
|
||||
return NULL;
|
||||
}
|
||||
#else
|
||||
pFile = fopen(filename, "rb");
|
||||
if (pFile == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
drpcx_uint8* pImageData = drpcx_load(drpcx__on_read_stdio, pFile, flipped, x, y, internalComponents, desiredComponents);
|
||||
|
||||
fclose(pFile);
|
||||
return pImageData;
|
||||
}
|
||||
#endif // DR_PCX_NO_STDIO
|
||||
|
||||
|
||||
typedef struct
|
||||
{
|
||||
// A pointer to the beginning of the data. We use a char as the type here for easy offsetting.
|
||||
const unsigned char* data;
|
||||
size_t dataSize;
|
||||
size_t currentReadPos;
|
||||
} drpcx_memory;
|
||||
|
||||
static size_t drpcx__on_read_memory(void* pUserData, void* bufferOut, size_t bytesToRead)
|
||||
{
|
||||
drpcx_memory* memory = (drpcx_memory*)pUserData;
|
||||
assert(memory != NULL);
|
||||
assert(memory->dataSize >= memory->currentReadPos);
|
||||
|
||||
size_t bytesRemaining = memory->dataSize - memory->currentReadPos;
|
||||
if (bytesToRead > bytesRemaining) {
|
||||
bytesToRead = bytesRemaining;
|
||||
}
|
||||
|
||||
if (bytesToRead > 0) {
|
||||
memcpy(bufferOut, memory->data + memory->currentReadPos, bytesToRead);
|
||||
memory->currentReadPos += bytesToRead;
|
||||
}
|
||||
|
||||
return bytesToRead;
|
||||
}
|
||||
|
||||
drpcx_uint8* drpcx_load_memory(const void* data, size_t dataSize, drpcx_bool32 flipped, int* x, int* y, int* internalComponents, int desiredComponents)
|
||||
{
|
||||
drpcx_memory memory;
|
||||
memory.data = (const unsigned char*)data;
|
||||
memory.dataSize = dataSize;
|
||||
memory.currentReadPos = 0;
|
||||
return drpcx_load(drpcx__on_read_memory, &memory, flipped, x, y, internalComponents, desiredComponents);
|
||||
}
|
||||
|
||||
|
||||
typedef struct
|
||||
{
|
||||
drpcx_uint8 header;
|
||||
drpcx_uint8 version;
|
||||
drpcx_uint8 encoding;
|
||||
drpcx_uint8 bpp;
|
||||
drpcx_uint16 left;
|
||||
drpcx_uint16 top;
|
||||
drpcx_uint16 right;
|
||||
drpcx_uint16 bottom;
|
||||
drpcx_uint16 hres;
|
||||
drpcx_uint16 vres;
|
||||
drpcx_uint8 palette16[48];
|
||||
drpcx_uint8 reserved1;
|
||||
drpcx_uint8 bitPlanes;
|
||||
drpcx_uint16 bytesPerLine;
|
||||
drpcx_uint16 paletteType;
|
||||
drpcx_uint16 screenSizeH;
|
||||
drpcx_uint16 screenSizeV;
|
||||
drpcx_uint8 reserved2[54];
|
||||
} drpcx_header;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
drpcx_read_proc onRead;
|
||||
void* pUserData;
|
||||
drpcx_bool32 flipped;
|
||||
drpcx_header header;
|
||||
|
||||
drpcx_uint32 width;
|
||||
drpcx_uint32 height;
|
||||
drpcx_uint32 components; // 3 = RGB; 4 = RGBA. Only 3 and 4 are supported.
|
||||
drpcx_uint8* pImageData;
|
||||
} drpcx;
|
||||
|
||||
|
||||
static drpcx_uint8 drpcx__read_byte(drpcx* pPCX)
|
||||
{
|
||||
drpcx_uint8 byte = 0;
|
||||
pPCX->onRead(pPCX->pUserData, &byte, 1);
|
||||
|
||||
return byte;
|
||||
}
|
||||
|
||||
static drpcx_uint8* drpcx__row_ptr(drpcx* pPCX, drpcx_uint32 row)
|
||||
{
|
||||
drpcx_uint32 stride = pPCX->width * pPCX->components;
|
||||
|
||||
drpcx_uint8* pRow = pPCX->pImageData;
|
||||
if (pPCX->flipped) {
|
||||
pRow += (pPCX->height - row - 1) * stride;
|
||||
} else {
|
||||
pRow += row * stride;
|
||||
}
|
||||
|
||||
return pRow;
|
||||
}
|
||||
|
||||
static drpcx_uint8 drpcx__rle(drpcx* pPCX, drpcx_uint8* pRLEValueOut)
|
||||
{
|
||||
drpcx_uint8 rleCount;
|
||||
drpcx_uint8 rleValue;
|
||||
|
||||
rleValue = drpcx__read_byte(pPCX);
|
||||
if ((rleValue & 0xC0) == 0xC0) {
|
||||
rleCount = rleValue & 0x3F;
|
||||
rleValue = drpcx__read_byte(pPCX);
|
||||
} else {
|
||||
rleCount = 1;
|
||||
}
|
||||
|
||||
|
||||
*pRLEValueOut = rleValue;
|
||||
return rleCount;
|
||||
}
|
||||
|
||||
|
||||
drpcx_bool32 drpcx__decode_1bit(drpcx* pPCX)
|
||||
{
|
||||
drpcx_uint8 rleCount = 0;
|
||||
drpcx_uint8 rleValue = 0;
|
||||
|
||||
switch (pPCX->header.bitPlanes)
|
||||
{
|
||||
case 1:
|
||||
{
|
||||
for (drpcx_uint32 y = 0; y < pPCX->height; ++y) {
|
||||
drpcx_uint8* pRow = drpcx__row_ptr(pPCX, y);
|
||||
for (drpcx_uint32 x = 0; x < pPCX->header.bytesPerLine; ++x) {
|
||||
if (rleCount == 0) {
|
||||
rleCount = drpcx__rle(pPCX, &rleValue);
|
||||
}
|
||||
rleCount -= 1;
|
||||
|
||||
for (int bit = 0; (bit < 8) && ((x*8 + bit) < pPCX->width); ++bit) {
|
||||
drpcx_uint8 mask = (1 << (7 - bit));
|
||||
drpcx_uint8 paletteIndex = (rleValue & mask) >> (7 - bit);
|
||||
|
||||
pRow[0] = paletteIndex * 255;
|
||||
pRow[1] = paletteIndex * 255;
|
||||
pRow[2] = paletteIndex * 255;
|
||||
pRow += 3;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return DRPCX_TRUE;
|
||||
|
||||
} break;
|
||||
|
||||
case 2:
|
||||
case 3:
|
||||
case 4:
|
||||
{
|
||||
for (drpcx_uint32 y = 0; y < pPCX->height; ++y) {
|
||||
for (drpcx_uint32 c = 0; c < pPCX->header.bitPlanes; ++c) {
|
||||
drpcx_uint8* pRow = drpcx__row_ptr(pPCX, y);
|
||||
for (drpcx_uint32 x = 0; x < pPCX->header.bytesPerLine; ++x) {
|
||||
if (rleCount == 0) {
|
||||
rleCount = drpcx__rle(pPCX, &rleValue);
|
||||
}
|
||||
rleCount -= 1;
|
||||
|
||||
for (int bit = 0; (bit < 8) && ((x*8 + bit) < pPCX->width); ++bit) {
|
||||
drpcx_uint8 mask = (1 << (7 - bit));
|
||||
drpcx_uint8 paletteIndex = (rleValue & mask) >> (7 - bit);
|
||||
|
||||
pRow[0] |= ((paletteIndex & 0x01) << c);
|
||||
pRow += pPCX->components;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
drpcx_uint8* pRow = drpcx__row_ptr(pPCX, y);
|
||||
for (drpcx_uint32 x = 0; x < pPCX->width; ++x) {
|
||||
drpcx_uint8 paletteIndex = pRow[0];
|
||||
for (drpcx_uint32 c = 0; c < pPCX->components; ++c) {
|
||||
pRow[c] = pPCX->header.palette16[paletteIndex*3 + c];
|
||||
}
|
||||
|
||||
pRow += pPCX->components;
|
||||
}
|
||||
}
|
||||
|
||||
return DRPCX_TRUE;
|
||||
}
|
||||
|
||||
default: return DRPCX_FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
drpcx_bool32 drpcx__decode_2bit(drpcx* pPCX)
|
||||
{
|
||||
drpcx_uint8 rleCount = 0;
|
||||
drpcx_uint8 rleValue = 0;
|
||||
|
||||
switch (pPCX->header.bitPlanes)
|
||||
{
|
||||
case 1:
|
||||
{
|
||||
drpcx_uint8 paletteCGA[48];
|
||||
paletteCGA[ 0] = 0x00; paletteCGA[ 1] = 0x00; paletteCGA[ 2] = 0x00; // #000000
|
||||
paletteCGA[ 3] = 0x00; paletteCGA[ 4] = 0x00; paletteCGA[ 5] = 0xAA; // #0000AA
|
||||
paletteCGA[ 6] = 0x00; paletteCGA[ 7] = 0xAA; paletteCGA[ 8] = 0x00; // #00AA00
|
||||
paletteCGA[ 9] = 0x00; paletteCGA[10] = 0xAA; paletteCGA[11] = 0xAA; // #00AAAA
|
||||
paletteCGA[12] = 0xAA; paletteCGA[13] = 0x00; paletteCGA[14] = 0x00; // #AA0000
|
||||
paletteCGA[15] = 0xAA; paletteCGA[16] = 0x00; paletteCGA[17] = 0xAA; // #AA00AA
|
||||
paletteCGA[18] = 0xAA; paletteCGA[19] = 0x55; paletteCGA[20] = 0x00; // #AA5500
|
||||
paletteCGA[21] = 0xAA; paletteCGA[22] = 0xAA; paletteCGA[23] = 0xAA; // #AAAAAA
|
||||
paletteCGA[24] = 0x55; paletteCGA[25] = 0x55; paletteCGA[26] = 0x55; // #555555
|
||||
paletteCGA[27] = 0x55; paletteCGA[28] = 0x55; paletteCGA[29] = 0xFF; // #5555FF
|
||||
paletteCGA[30] = 0x55; paletteCGA[31] = 0xFF; paletteCGA[32] = 0x55; // #55FF55
|
||||
paletteCGA[33] = 0x55; paletteCGA[34] = 0xFF; paletteCGA[35] = 0xFF; // #55FFFF
|
||||
paletteCGA[36] = 0xFF; paletteCGA[37] = 0x55; paletteCGA[38] = 0x55; // #FF5555
|
||||
paletteCGA[39] = 0xFF; paletteCGA[40] = 0x55; paletteCGA[41] = 0xFF; // #FF55FF
|
||||
paletteCGA[42] = 0xFF; paletteCGA[43] = 0xFF; paletteCGA[44] = 0x55; // #FFFF55
|
||||
paletteCGA[45] = 0xFF; paletteCGA[46] = 0xFF; paletteCGA[47] = 0xFF; // #FFFFFF
|
||||
|
||||
drpcx_uint8 cgaBGColor = pPCX->header.palette16[0] >> 4;
|
||||
drpcx_uint8 i = (pPCX->header.palette16[3] & 0x20) >> 5;
|
||||
drpcx_uint8 p = (pPCX->header.palette16[3] & 0x40) >> 6;
|
||||
//drpcx_uint8 c = (pPCX->header.palette16[3] & 0x80) >> 7; // Color or monochrome. How is monochrome handled?
|
||||
|
||||
for (drpcx_uint32 y = 0; y < pPCX->height; ++y) {
|
||||
drpcx_uint8* pRow = drpcx__row_ptr(pPCX, y);
|
||||
for (drpcx_uint32 x = 0; x < pPCX->header.bytesPerLine; ++x) {
|
||||
if (rleCount == 0) {
|
||||
rleCount = drpcx__rle(pPCX, &rleValue);
|
||||
}
|
||||
rleCount -= 1;
|
||||
|
||||
for (int bit = 0; bit < 4; ++bit) {
|
||||
if (x*4 + bit < pPCX->width) {
|
||||
drpcx_uint8 mask = (3 << ((3 - bit) * 2));
|
||||
drpcx_uint8 paletteIndex = (rleValue & mask) >> ((3 - bit) * 2);
|
||||
|
||||
drpcx_uint8 cgaIndex;
|
||||
if (paletteIndex == 0) { // Background.
|
||||
cgaIndex = cgaBGColor;
|
||||
} else { // Foreground
|
||||
cgaIndex = (((paletteIndex << 1) + p) + (i << 3));
|
||||
}
|
||||
|
||||
pRow[0] = paletteCGA[cgaIndex*3 + 0];
|
||||
pRow[1] = paletteCGA[cgaIndex*3 + 1];
|
||||
pRow[2] = paletteCGA[cgaIndex*3 + 2];
|
||||
pRow += 3;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: According to http://www.fysnet.net/pcxfile.htm, we should use the palette at the end of the file
|
||||
// instead of the standard CGA palette if the version is equal to 5. With my test files the palette
|
||||
// at the end of the file does not exist. Research this one.
|
||||
if (pPCX->header.version == 5) {
|
||||
drpcx_uint8 paletteMarker = drpcx__read_byte(pPCX);
|
||||
if (paletteMarker == 0x0C) {
|
||||
// TODO: Implement Me.
|
||||
}
|
||||
}
|
||||
|
||||
return DRPCX_TRUE;
|
||||
};
|
||||
|
||||
case 4:
|
||||
{
|
||||
// NOTE: This is completely untested. If anybody knows where I can get a test file please let me know or send it through to me!
|
||||
// TODO: Test Me.
|
||||
|
||||
for (drpcx_uint32 y = 0; y < pPCX->height; ++y) {
|
||||
for (drpcx_uint32 c = 0; c < pPCX->header.bitPlanes; ++c) {
|
||||
drpcx_uint8* pRow = drpcx__row_ptr(pPCX, y);
|
||||
for (drpcx_uint32 x = 0; x < pPCX->header.bytesPerLine; ++x) {
|
||||
if (rleCount == 0) {
|
||||
rleCount = drpcx__rle(pPCX, &rleValue);
|
||||
}
|
||||
rleCount -= 1;
|
||||
|
||||
for (int bitpair = 0; (bitpair < 4) && ((x*4 + bitpair) < pPCX->width); ++bitpair) {
|
||||
drpcx_uint8 mask = (4 << (3 - bitpair));
|
||||
drpcx_uint8 paletteIndex = (rleValue & mask) >> (3 - bitpair);
|
||||
|
||||
pRow[0] |= ((paletteIndex & 0x03) << (c*2));
|
||||
pRow += pPCX->components;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
drpcx_uint8* pRow = drpcx__row_ptr(pPCX, y);
|
||||
for (drpcx_uint32 x = 0; x < pPCX->width; ++x) {
|
||||
drpcx_uint8 paletteIndex = pRow[0];
|
||||
for (drpcx_uint32 c = 0; c < pPCX->header.bitPlanes; ++c) {
|
||||
pRow[c] = pPCX->header.palette16[paletteIndex*3 + c];
|
||||
}
|
||||
|
||||
pRow += pPCX->components;
|
||||
}
|
||||
}
|
||||
|
||||
return DRPCX_TRUE;
|
||||
};
|
||||
|
||||
default: return DRPCX_FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
drpcx_bool32 drpcx__decode_4bit(drpcx* pPCX)
|
||||
{
|
||||
// NOTE: This is completely untested. If anybody knows where I can get a test file please let me know or send it through to me!
|
||||
// TODO: Test Me.
|
||||
|
||||
if (pPCX->header.bitPlanes > 1) {
|
||||
return DRPCX_FALSE;
|
||||
}
|
||||
|
||||
drpcx_uint8 rleCount = 0;
|
||||
drpcx_uint8 rleValue = 0;
|
||||
|
||||
for (drpcx_uint32 y = 0; y < pPCX->height; ++y) {
|
||||
for (drpcx_uint32 c = 0; c < pPCX->header.bitPlanes; ++c) {
|
||||
drpcx_uint8* pRow = drpcx__row_ptr(pPCX, y);
|
||||
for (drpcx_uint32 x = 0; x < pPCX->header.bytesPerLine; ++x) {
|
||||
if (rleCount == 0) {
|
||||
rleCount = drpcx__rle(pPCX, &rleValue);
|
||||
}
|
||||
rleCount -= 1;
|
||||
|
||||
for (int nibble = 0; (nibble < 2) && ((x*2 + nibble) < pPCX->width); ++nibble)
|
||||
{
|
||||
drpcx_uint8 mask = (4 << (1 - nibble));
|
||||
drpcx_uint8 paletteIndex = (rleValue & mask) >> (1 - nibble);
|
||||
|
||||
pRow[0] |= ((paletteIndex & 0x0F) << (c*4));
|
||||
pRow += pPCX->components;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
drpcx_uint8* pRow = drpcx__row_ptr(pPCX, y);
|
||||
for (drpcx_uint32 x = 0; x < pPCX->width; ++x) {
|
||||
drpcx_uint8 paletteIndex = pRow[0];
|
||||
for (drpcx_uint32 c = 0; c < pPCX->components; ++c) {
|
||||
pRow[c] = pPCX->header.palette16[paletteIndex*3 + c];
|
||||
}
|
||||
|
||||
pRow += pPCX->components;
|
||||
}
|
||||
}
|
||||
|
||||
return DRPCX_TRUE;
|
||||
}
|
||||
|
||||
drpcx_bool32 drpcx__decode_8bit(drpcx* pPCX)
|
||||
{
|
||||
drpcx_uint8 rleCount = 0;
|
||||
drpcx_uint8 rleValue = 0;
|
||||
drpcx_uint32 stride = pPCX->width * pPCX->components;
|
||||
|
||||
switch (pPCX->header.bitPlanes)
|
||||
{
|
||||
case 1:
|
||||
{
|
||||
for (drpcx_uint32 y = 0; y < pPCX->height; ++y) {
|
||||
drpcx_uint8* pRow = drpcx__row_ptr(pPCX, y);
|
||||
for (drpcx_uint32 x = 0; x < pPCX->header.bytesPerLine; ++x) {
|
||||
if (rleCount == 0) {
|
||||
rleCount = drpcx__rle(pPCX, &rleValue);
|
||||
}
|
||||
rleCount -= 1;
|
||||
|
||||
if (x < pPCX->width) {
|
||||
pRow[0] = rleValue;
|
||||
pRow[1] = rleValue;
|
||||
pRow[2] = rleValue;
|
||||
pRow += 3;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// At this point we can know if we are dealing with a palette or a grayscale image by checking the next byte. If it's equal to 0x0C, we
|
||||
// need to do a simple palette lookup.
|
||||
drpcx_uint8 paletteMarker = drpcx__read_byte(pPCX);
|
||||
if (paletteMarker == 0x0C) {
|
||||
// A palette is present - we need to do a second pass.
|
||||
drpcx_uint8 palette256[768];
|
||||
if (pPCX->onRead(pPCX->pUserData, palette256, sizeof(palette256)) != sizeof(palette256)) {
|
||||
return DRPCX_FALSE;
|
||||
}
|
||||
|
||||
for (drpcx_uint32 y = 0; y < pPCX->height; ++y) {
|
||||
drpcx_uint8* pRow = pPCX->pImageData + (y * stride);
|
||||
for (drpcx_uint32 x = 0; x < pPCX->width; ++x) {
|
||||
drpcx_uint8 index = pRow[0];
|
||||
pRow[0] = palette256[index*3 + 0];
|
||||
pRow[1] = palette256[index*3 + 1];
|
||||
pRow[2] = palette256[index*3 + 2];
|
||||
pRow += 3;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return DRPCX_TRUE;
|
||||
}
|
||||
|
||||
case 3:
|
||||
case 4:
|
||||
{
|
||||
for (drpcx_uint32 y = 0; y < pPCX->height; ++y) {
|
||||
for (drpcx_uint32 c = 0; c < pPCX->components; ++c) {
|
||||
drpcx_uint8* pRow = drpcx__row_ptr(pPCX, y);
|
||||
for (drpcx_uint32 x = 0; x < pPCX->header.bytesPerLine; ++x) {
|
||||
if (rleCount == 0) {
|
||||
rleCount = drpcx__rle(pPCX, &rleValue);
|
||||
}
|
||||
rleCount -= 1;
|
||||
|
||||
if (x < pPCX->width) {
|
||||
pRow[c] = rleValue;
|
||||
pRow += pPCX->components;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return DRPCX_TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
return DRPCX_TRUE;
|
||||
}
|
||||
|
||||
drpcx_uint8* drpcx_load(drpcx_read_proc onRead, void* pUserData, drpcx_bool32 flipped, int* x, int* y, int* internalComponents, int desiredComponents)
|
||||
{
|
||||
if (onRead == NULL) return NULL;
|
||||
if (desiredComponents > 4) return NULL;
|
||||
|
||||
drpcx pcx;
|
||||
pcx.onRead = onRead;
|
||||
pcx.pUserData = pUserData;
|
||||
pcx.flipped = flipped;
|
||||
if (onRead(pUserData, &pcx.header, sizeof(pcx.header)) != sizeof(pcx.header)) {
|
||||
return NULL; // Failed to read the header.
|
||||
}
|
||||
|
||||
if (pcx.header.header != 10) {
|
||||
return NULL; // Not a PCX file.
|
||||
}
|
||||
|
||||
if (pcx.header.encoding != 1) {
|
||||
return NULL; // Not supporting non-RLE encoding. Would assume a value of 0 indicates raw, unencoded, but that is apparently never used.
|
||||
}
|
||||
|
||||
if (pcx.header.bpp != 1 && pcx.header.bpp != 2 && pcx.header.bpp != 4 && pcx.header.bpp != 8) {
|
||||
return NULL; // Unsupported pixel format.
|
||||
}
|
||||
|
||||
|
||||
if (pcx.header.left > pcx.header.right) {
|
||||
drpcx_uint16 temp = pcx.header.left;
|
||||
pcx.header.left = pcx.header.right;
|
||||
pcx.header.right = temp;
|
||||
}
|
||||
if (pcx.header.top > pcx.header.bottom) {
|
||||
drpcx_uint16 temp = pcx.header.top;
|
||||
pcx.header.top = pcx.header.bottom;
|
||||
pcx.header.bottom = temp;
|
||||
}
|
||||
|
||||
pcx.width = pcx.header.right - pcx.header.left + 1;
|
||||
pcx.height = pcx.header.bottom - pcx.header.top + 1;
|
||||
pcx.components = (pcx.header.bpp == 8 && pcx.header.bitPlanes == 4) ? 4 : 3;
|
||||
|
||||
size_t dataSize = pcx.width * pcx.height * pcx.components;
|
||||
pcx.pImageData = (drpcx_uint8*)calloc(1, dataSize); // <-- Clearing to zero is important! Required for proper decoding.
|
||||
if (pcx.pImageData == NULL) {
|
||||
return NULL; // Failed to allocate memory.
|
||||
}
|
||||
|
||||
drpcx_bool32 result = DRPCX_FALSE;
|
||||
switch (pcx.header.bpp)
|
||||
{
|
||||
case 1:
|
||||
{
|
||||
result = drpcx__decode_1bit(&pcx);
|
||||
} break;
|
||||
|
||||
case 2:
|
||||
{
|
||||
result = drpcx__decode_2bit(&pcx);
|
||||
} break;
|
||||
|
||||
case 4:
|
||||
{
|
||||
result = drpcx__decode_4bit(&pcx);
|
||||
} break;
|
||||
|
||||
case 8:
|
||||
{
|
||||
result = drpcx__decode_8bit(&pcx);
|
||||
} break;
|
||||
}
|
||||
|
||||
if (!result) {
|
||||
free(pcx.pImageData);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// There's an annoying amount of branching when loading PCX files so for simplicity I'm doing the component conversion as
|
||||
// a second pass.
|
||||
if (desiredComponents == 0) desiredComponents = pcx.components;
|
||||
if (desiredComponents != (int)pcx.components) {
|
||||
drpcx_uint8* pNewImageData = (drpcx_uint8*)malloc(pcx.width * pcx.height * desiredComponents);
|
||||
if (pNewImageData == NULL) {
|
||||
free(pcx.pImageData);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
drpcx_uint8* pSrcData = pcx.pImageData;
|
||||
drpcx_uint8* pDstData = pNewImageData;
|
||||
if (desiredComponents < (int)pcx.components) {
|
||||
// We're reducing the number of components. Just drop the excess.
|
||||
for (drpcx_uint32 i = 0; i < pcx.width*pcx.height; ++i) {
|
||||
for (int c = 0; c < desiredComponents; ++c) {
|
||||
pDstData[c] = pSrcData[c];
|
||||
}
|
||||
|
||||
pSrcData += pcx.components;
|
||||
pDstData += desiredComponents;
|
||||
}
|
||||
} else {
|
||||
// We're increasing the number of components. Always ensure the alpha channel is set to 0xFF.
|
||||
if (pcx.components == 1) {
|
||||
for (drpcx_uint32 i = 0; i < pcx.width*pcx.height; ++i) {
|
||||
for (int c = 0; c < desiredComponents; ++c) {
|
||||
pDstData[c] = pSrcData[0];
|
||||
}
|
||||
|
||||
pSrcData += pcx.components;
|
||||
pDstData += desiredComponents;
|
||||
}
|
||||
} else if (pcx.components == 2) {
|
||||
for (drpcx_uint32 i = 0; i < pcx.width*pcx.height; ++i) {
|
||||
pDstData[0] = pSrcData[0];
|
||||
pDstData[1] = pSrcData[1];
|
||||
pDstData[2] = 0x00;
|
||||
if (desiredComponents == 4) pDstData[3] = 0xFF;
|
||||
|
||||
pSrcData += pcx.components;
|
||||
pDstData += desiredComponents;
|
||||
}
|
||||
} else {
|
||||
assert(pcx.components == 3);
|
||||
assert(desiredComponents == 4);
|
||||
for (drpcx_uint32 i = 0; i < pcx.width*pcx.height; ++i) {
|
||||
pDstData[0] = pSrcData[0];
|
||||
pDstData[1] = pSrcData[1];
|
||||
pDstData[2] = pSrcData[2];
|
||||
pDstData[3] = 0xFF;
|
||||
|
||||
pSrcData += pcx.components;
|
||||
pDstData += desiredComponents;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
free(pcx.pImageData);
|
||||
pcx.pImageData = pNewImageData;
|
||||
}
|
||||
|
||||
if (x) *x = pcx.width;
|
||||
if (y) *y = pcx.height;
|
||||
if (internalComponents) *internalComponents = pcx.components;
|
||||
return pcx.pImageData;
|
||||
}
|
||||
|
||||
void drpcx_free(void* pReturnValueFromLoad)
|
||||
{
|
||||
free(pReturnValueFromLoad);
|
||||
}
|
||||
|
||||
#endif // DR_PCX_IMPLEMENTATION
|
||||
|
||||
|
||||
// REVISION HISTORY
|
||||
//
|
||||
// v0.3.1 - 2018-09-11
|
||||
// - Styling fixes.
|
||||
// - Fix a typo.
|
||||
//
|
||||
// v0.3 - 2018-02-08
|
||||
// - API CHANGE: Rename dr_* types to drpcx_*.
|
||||
//
|
||||
// v0.2c - 2018-02-07
|
||||
// - Fix a crash.
|
||||
//
|
||||
// v0.2b - 2018-02-02
|
||||
// - Fix compilation error.
|
||||
//
|
||||
// v0.2a - 2017-07-16
|
||||
// - Change underlying type for booleans to unsigned.
|
||||
//
|
||||
// v0.2 - 2016-10-28
|
||||
// - API CHANGE: Add a parameter to drpcx_load() and family to control the number of output components.
|
||||
// - Use custom sized types rather than built-in ones to improve support for older MSVC compilers.
|
||||
//
|
||||
// v0.1c - 2016-10-23
|
||||
// - A minor change to drpcx_bool8 and drpcx_bool32 types.
|
||||
//
|
||||
// v0.1b - 2016-10-11
|
||||
// - Use drpcx_bool32 instead of the built-in "bool" type. The reason for this change is that it helps maintain API/ABI consistency
|
||||
// between C and C++ builds.
|
||||
//
|
||||
// v0.1a - 2016-09-18
|
||||
// - Change date format to ISO 8601 (YYYY-MM-DD)
|
||||
//
|
||||
// v0.1 - 2016-05-04
|
||||
// - Initial versioned release.
|
||||
|
||||
|
||||
// TODO
|
||||
// - Test 2-bpp/4-plane and 4-bpp/1-plane formats.
|
||||
|
||||
|
||||
/*
|
||||
This is free and unencumbered software released into the public domain.
|
||||
|
||||
Anyone is free to copy, modify, publish, use, compile, sell, or
|
||||
distribute this software, either in source code form or as a compiled
|
||||
binary, for any purpose, commercial or non-commercial, and by any
|
||||
means.
|
||||
|
||||
In jurisdictions that recognize copyright laws, the author or authors
|
||||
of this software dedicate any and all copyright interest in the
|
||||
software to the public domain. We make this dedication for the benefit
|
||||
of the public at large and to the detriment of our heirs and
|
||||
successors. We intend this dedication to be an overt act of
|
||||
relinquishment in perpetuity of all present and future rights to this
|
||||
software under copyright law.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
||||
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
For more information, please refer to <http://unlicense.org/>
|
||||
*/
|
||||
|
49
source/engine/thirdparty/dr_libs/tests/README.md
vendored
49
source/engine/thirdparty/dr_libs/tests/README.md
vendored
|
@ -1,49 +0,0 @@
|
|||
Building
|
||||
========
|
||||
Move into this directory and run the build script for the relevant platform. Run from this directory.
|
||||
|
||||
clear && ./build_opus && ./bin/dr_opus_test_0
|
||||
|
||||
Alternatively you can compile a specific test manually:
|
||||
|
||||
clear && gcc ./opus/dr_opus_test_0 -o ./bin/dr_opus_test_0 && ./bin/dr_opus_test_0
|
||||
|
||||
Test vectors will be loaded from the "testvectors" folder, relative to this directory. Therefore, you need to run
|
||||
each test program from this directory:
|
||||
|
||||
./bin/dr_opus_test_0
|
||||
|
||||
|
||||
Building and Running WAV Tests
|
||||
------------------------------
|
||||
The WAV tests use libsndfile as a benchmark. The tests programs dynamically link to libsndfile at runtime which
|
||||
means you don't need to link to it at compile time. However, you will need the headers installed in a standard
|
||||
location. The batch files for the Windows build will allow you to customize the include path. On the Windows build
|
||||
you will need to drop two versions of libsndfile-1.dll into the bin directory. For the 32-bit build you need to
|
||||
name it libsndfile-1-x86.dll and for the 64-bit build you need to name it libsndfile-1-x64.dll.
|
||||
|
||||
|
||||
Test Vectors
|
||||
============
|
||||
In order to run certain tests you will need to download test vectors for the relevant project and place them into the
|
||||
"testvectors" folder.
|
||||
|
||||
Opus
|
||||
----
|
||||
- Download both the original and new test vectors from https://opus-codec.org/testvectors/ and place them into
|
||||
the "testvectors/opus" folder.
|
||||
- Download the Ogg Opus test vectors from https://wiki.xiph.org/OggOpus/testvectors and place them into the
|
||||
"testvectors/opus" folder.
|
||||
- The folder structure should like like the following:
|
||||
- testvectors
|
||||
- opus
|
||||
- opus_testvectors
|
||||
- opus_newvectors
|
||||
- oggopus
|
||||
- failure_cases
|
||||
- opus_multichannel_examples
|
||||
|
||||
FLAC
|
||||
----
|
||||
- Download the FLAC testbench from https://wiki.hydrogenaud.io/index.php?title=FLAC_decoder_testbench and place
|
||||
them into the "testvectors/flac/testbench" folder.
|
|
@ -1,4 +0,0 @@
|
|||
#!/bin/sh
|
||||
gcc ./flac/dr_flac_test_0.c -o ./bin/dr_flac_test_0 -std=c89 -ansi -pedantic -O3 -s -Wall -ldl
|
||||
gcc ./flac/dr_flac_decoding.c -o ./bin/dr_flac_decoding -std=c89 -ansi -pedantic -Wall -O3 -s -lFLAC -ldl
|
||||
gcc ./flac/dr_flac_seeking.c -o ./bin/dr_flac_seeking -std=c89 -ansi -pedantic -Wall -O3 -s -lFLAC -ldl
|
|
@ -1,37 +0,0 @@
|
|||
:: NOTES
|
||||
::
|
||||
:: These tests use libFLAC as a benchmark. Since Windows doesn't have good standard paths for library files, this
|
||||
:: script will use "flac/include" as an additional search path for headers and "flac/lib/win32" as an additional
|
||||
:: search path for libraries. You will need to place FLAC headers in the "flac/include/FLAC" directory and libogg
|
||||
:: headers int the "flac/include/ogg" directory.
|
||||
::
|
||||
:: Examples are linked against "-lFLAC" and "-logg". These need to be placed in a standard directory or "flac/lib/win32".
|
||||
|
||||
@echo off
|
||||
SET c_compiler=gcc
|
||||
SET cpp_compiler=g++
|
||||
|
||||
:: Configure the "arch" option to test different instruction sets.
|
||||
SET arch=
|
||||
SET arch=-msse4.1
|
||||
::SET arch=-mfpu=neon
|
||||
|
||||
:: libFLAC and libogg are required for benchmarking.
|
||||
SET libFLAC=-I./flac/include -L./flac/lib/win32 -lFLAC -logg
|
||||
|
||||
:: C options
|
||||
SET c_options=-std=c89 -ansi
|
||||
|
||||
:: C++ options
|
||||
SET cpp_options=
|
||||
|
||||
SET options=-Wall -Wpedantic -pedantic -O3 -s -DNDEBUG %arch% %libFLAC%
|
||||
|
||||
SET buildc=%c_compiler% %c_options%
|
||||
SET buildcpp=%cpp_compiler% %cpp_options%
|
||||
@echo on
|
||||
|
||||
%buildc% ./flac/dr_flac_test_0.c -o ./bin/dr_flac_test_0.exe %options%
|
||||
%buildcpp% ./flac/dr_flac_test_0.cpp -o ./bin/dr_flac_test_0_cpp.exe %options%
|
||||
%buildc% ./flac/dr_flac_decoding.c -o ./bin/dr_flac_decoding.exe %options%
|
||||
%buildcpp% ./flac/dr_flac_decoding.cpp -o ./bin/dr_flac_decoding_cpp.exe %options%
|
|
@ -1,2 +0,0 @@
|
|||
gcc ./mp3/dr_mp3_test_0.c -o ./bin/dr_mp3_test_0.exe -std=c89 -ansi -pedantic -Wall
|
||||
g++ ./mp3/dr_mp3_test_0.cpp -o ./bin/dr_mp3_test_0.exe -pedantic -Wall
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue