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
|
*.gz
|
||||||
*.tar
|
*.tar
|
||||||
.nova/
|
.nova/
|
||||||
packer
|
packer*
|
||||||
primum
|
primum
|
||||||
sokol-shdc
|
sokol-shdc*
|
||||||
source/shaders/*.h
|
source/shaders/*.h
|
||||||
core.cdb
|
core.cdb
|
||||||
primum.exe
|
primum.exe
|
||||||
core.cdb.h
|
core.cdb.h
|
||||||
jsc
|
jsc
|
||||||
.DS_Store
|
.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
|
UNAME != uname
|
||||||
MAKEDIR != pwd
|
MAKEDIR != pwd
|
||||||
# Options
|
# Options
|
||||||
# DBG --- build with debugging symbols and logging
|
# NDEBUG --- build with debugging symbols and logging
|
||||||
|
|
||||||
CXX:=$(CC)
|
CXX:=$(CC)
|
||||||
|
|
||||||
ifeq ($(CXX), tcc)
|
|
||||||
CXX=clang
|
|
||||||
endif
|
|
||||||
|
|
||||||
ifeq ($(CC),cc)
|
|
||||||
CC=clang
|
|
||||||
endif
|
|
||||||
# Temp to strip long emcc paths to just emcc
|
# Temp to strip long emcc paths to just emcc
|
||||||
CC := $(notdir $(CC))
|
CC := $(notdir $(CC))
|
||||||
|
|
||||||
DBG ?= 1
|
|
||||||
OPT ?= 0
|
OPT ?= 0
|
||||||
LEAK ?= 0
|
|
||||||
|
|
||||||
INFO :=
|
INFO :=
|
||||||
LD = $(CC)
|
LD = $(CC)
|
||||||
|
|
||||||
ifeq ($(CC), x86_64-w64-mingw32-gcc)
|
STEAM = steam/sdk
|
||||||
AR = x86_64-w64-mingw32-ar
|
STEAMAPI = steam_api
|
||||||
|
|
||||||
|
CCC != $(CC) -v
|
||||||
|
ifneq ($(findstring clangcc , $(CCC)),)
|
||||||
|
LDFLAGS += -Wl,-rpath=./
|
||||||
endif
|
endif
|
||||||
|
|
||||||
ifdef NEDITOR
|
ifdef NEDITOR
|
||||||
|
@ -47,56 +42,49 @@ ifdef NQOA
|
||||||
CPPFLAGS += -DNQOA
|
CPPFLAGS += -DNQOA
|
||||||
endif
|
endif
|
||||||
|
|
||||||
CPPFLAGS += -ffast-math
|
|
||||||
|
|
||||||
ifeq ($(CC), emcc)
|
ifeq ($(CC), emcc)
|
||||||
LDFLAGS += #--closure 1
|
LDFLAGS += #--closure 1 --emrun
|
||||||
CPPFLAGS += -O0
|
CPPFLAGS += -O0
|
||||||
OPT = 0
|
OPT = 0
|
||||||
DBG = 0
|
NDEBUG = 1
|
||||||
AR = emar
|
AR = emar
|
||||||
endif
|
endif
|
||||||
|
|
||||||
ifeq ($(DBG),1)
|
ifdef NDEBUG
|
||||||
CPPFLAGS += -g
|
|
||||||
INFO += _dbg
|
|
||||||
else
|
|
||||||
CPPFLAGS += -DNDEBUG
|
CPPFLAGS += -DNDEBUG
|
||||||
LDFLAGS += -s
|
else
|
||||||
|
CPPFLAGS += -g -DDUMP
|
||||||
|
INFO :=$(INFO)_dbg
|
||||||
endif
|
endif
|
||||||
|
|
||||||
ifeq ($(LEAK),1)
|
ifdef LEAK
|
||||||
CPPFLAGS += -fsanitize=address
|
CPPFLAGS += -fsanitize=address -fsanitize=undefined -fno-omit-frame-pointer -DLEAK
|
||||||
endif
|
endif
|
||||||
|
|
||||||
CPPFLAGS += -DLEAK=$(LEAK)
|
|
||||||
|
|
||||||
ifeq ($(OPT),small)
|
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
|
LDFLAGS += -flto
|
||||||
|
|
||||||
ifeq ($(CC), emcc)
|
ifeq ($(CC), emcc)
|
||||||
LDFLAGS += --closure 1
|
LDFLAGS += --closure 1
|
||||||
endif
|
endif
|
||||||
|
|
||||||
INFO := $(addsuffix _small,$(INFO))
|
INFO :=$(INFO)_small
|
||||||
else
|
else ifeq ($(OPT), 1)
|
||||||
ifeq ($(OPT), 1)
|
|
||||||
CPPFLAGS += -O2 -flto
|
CPPFLAGS += -O2 -flto
|
||||||
INFO := $(addsuffix _opt,$(INFO))
|
INFO :=$(INFO)_opt
|
||||||
else
|
else
|
||||||
CPPFLAGS += -O0
|
CPPFLAGS += -O2
|
||||||
endif
|
|
||||||
endif
|
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 += -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
|
||||||
CPPFLAGS += -D_FILE_OFFSET_BITS=64 # for tinycdb
|
|
||||||
|
|
||||||
# ENABLE_SINC_[BEST|FAST|MEDIUM]_CONVERTER
|
# ENABLE_SINC_[BEST|FAST|MEDIUM]_CONVERTER
|
||||||
# default, fast and medium available in game at runtime; best available in editor
|
# 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
|
ZIP = .tar.gz
|
||||||
UNZIP = cp $(DISTDIR)/$(DIST) $(DESTDIR) && tar xzf $(DESTDIR)/$(DIST) -C $(DESTDIR) && rm $(DESTDIR)/$(DIST)
|
UNZIP = cp $(DISTDIR)/$(DIST) $(DESTDIR) && tar xzf $(DESTDIR)/$(DIST) -C $(DESTDIR) && rm $(DESTDIR)/$(DIST)
|
||||||
|
|
||||||
|
@ -104,30 +92,31 @@ ifeq ($(ARCH),)
|
||||||
ARCH != uname -m
|
ARCH != uname -m
|
||||||
endif
|
endif
|
||||||
|
|
||||||
STEAMPATH = steam/sdk/redistributable_bin
|
INFO :=$(INFO)_$(ARCH)
|
||||||
DISCORDPATH = discord/lib
|
|
||||||
|
|
||||||
ifdef DISCORD
|
ifeq ($(OS), Windows_NT) # then WINDOWS
|
||||||
LDPATHS += $(DISCORDPATH)/$(ARCH)
|
PLATFORM := win64
|
||||||
LDLIBS += discord_game_sdk
|
DEPS += resource.o
|
||||||
CPPFLAGS += -DDISCORD
|
STEAMAPI := steam_api64
|
||||||
endif
|
|
||||||
|
|
||||||
ifdef STEAM
|
|
||||||
LDLIBS += steam_api
|
|
||||||
LDPATHS += $(STEAMPATH)/$(ARCH)
|
|
||||||
endif
|
|
||||||
|
|
||||||
ifeq ($(OS), Windows_NT)
|
|
||||||
LDFLAGS += -mwin32 -static
|
LDFLAGS += -mwin32 -static
|
||||||
CPPFLAGS += -mwin32
|
CPPFLAGS += -mwin32
|
||||||
LDLIBS += mingw32 kernel32 d3d11 user32 shell32 dxgi gdi32 ws2_32 ole32 winmm setupapi m pthread
|
LDLIBS += mingw32 kernel32 d3d11 user32 shell32 dxgi gdi32 ws2_32 ole32 winmm setupapi m pthread
|
||||||
EXT = .exe
|
|
||||||
ARCH := x86_64
|
PKGCMD = zip -q -r $(MAKEDIR)/$(DISTDIR)/$(DIST) . -x \*.a ./obj/\*
|
||||||
PKGCMD = cd $(BIN); zip -q -r $(MAKEDIR)/$(DISTDIR)/$(DIST) . -x \*.a ./obj/\*
|
|
||||||
ZIP = .zip
|
ZIP = .zip
|
||||||
UNZIP = unzip -o -q $(DISTDIR)/$(DIST) -d $(DESTDIR)
|
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
|
OS := Web
|
||||||
LDFLAGS += -sMIN_WEBGL_VERSION=2 -sMAX_WEBGL_VERSION=2 -pthread -sTOTAL_MEMORY=128MB
|
LDFLAGS += -sMIN_WEBGL_VERSION=2 -sMAX_WEBGL_VERSION=2 -pthread -sTOTAL_MEMORY=128MB
|
||||||
CPPFLAGS += -pthread
|
CPPFLAGS += -pthread
|
||||||
|
@ -135,213 +124,165 @@ else ifeq ($(CC), emcc)
|
||||||
EXT = .html
|
EXT = .html
|
||||||
else
|
else
|
||||||
UNAME != uname -s
|
UNAME != uname -s
|
||||||
ifeq ($(UNAME), Linux)
|
ifeq ($(UNAME), Linux) # then LINUX
|
||||||
OS := Linux
|
OS := Linux
|
||||||
|
PLATFORM := linux64
|
||||||
LDFLAGS += -pthread -rdynamic
|
LDFLAGS += -pthread -rdynamic
|
||||||
LDLIBS += GL pthread c m dl X11 Xi Xcursor EGL asound
|
LDLIBS += GL pthread c m dl X11 Xi Xcursor EGL asound
|
||||||
|
INFO :=$(INFO)_linux
|
||||||
endif
|
endif
|
||||||
|
|
||||||
ifeq ($(UNAME), Darwin)
|
ifeq ($(UNAME), Darwin)
|
||||||
OS := macos
|
OS := macos
|
||||||
|
PLATFORM := osx
|
||||||
CPPFLAGS += -arch $(ARCH)
|
CPPFLAGS += -arch $(ARCH)
|
||||||
CFLAGS += -x objective-c
|
CFLAGS += -x objective-c
|
||||||
CXXFLAGS += -std=c++11
|
CXXFLAGS += -std=c++11
|
||||||
LDFLAGS += -framework Cocoa -framework QuartzCore -framework AudioToolbox -framework Metal -framework MetalKit
|
LDFLAGS += -framework Cocoa -framework QuartzCore -framework AudioToolbox -framework Metal -framework MetalKit
|
||||||
|
INFO :=$(INFO)_macos
|
||||||
endif
|
endif
|
||||||
endif
|
endif
|
||||||
|
|
||||||
BIN = bin/$(OS)/$(ARCH)$(INFO)
|
|
||||||
|
|
||||||
ifdef STEAM
|
|
||||||
BIN := $(addsuffix /steam, $(BIN))
|
|
||||||
endif
|
|
||||||
|
|
||||||
OBJDIR = $(BIN)/obj
|
|
||||||
|
|
||||||
# All other sources
|
# All other sources
|
||||||
OBJS != find source/engine -type f -name '*.c' | grep -vE 'test|tool|example|fuzz|main' | grep -vE 'quickjs'
|
OBJS != find source -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'
|
CPPOBJS != find source -type f -name '*.cpp' | grep -vE 'test|tool|example|fuzz|main'
|
||||||
OBJS += $(CPPOBJS)
|
OBJS += $(CPPOBJS)
|
||||||
|
OBJS += source/engine/yugine.c
|
||||||
OBJS += $(shell find source/engine -type f -name '*.m')
|
OBJS += $(shell find source/engine -type f -name '*.m')
|
||||||
OBJS := $(patsubst %.cpp, %.o, $(OBJS))
|
QUICKJS := source/engine/thirdparty/quickjs
|
||||||
OBJS := $(patsubst %.c, %.o,$(OBJS))
|
OBJS += $(addprefix $(QUICKJS)/, libregexp.c quickjs.c libunicode.c cutils.c libbf.c)
|
||||||
OBJS := $(patsubst %.m, %.o, $(OBJS))
|
OBJS := $(patsubst %.cpp, %$(INFO).o, $(OBJS))
|
||||||
OBJS := $(addprefix $(BIN)/obj/, $(OBJS))
|
OBJS := $(patsubst %.c, %$(INFO).o,$(OBJS))
|
||||||
|
OBJS := $(patsubst %.m, %$(INFO).o, $(OBJS))
|
||||||
|
|
||||||
engineincs != find source/engine -maxdepth 1 -type d
|
engineincs != find source/engine -maxdepth 1 -type d
|
||||||
includeflag != find source -type d -name include
|
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))
|
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
|
WARNING_FLAGS = -Wno-incompatible-function-pointer-types -Wno-incompatible-pointer-types
|
||||||
|
|
||||||
NAME = primum$(EXT)
|
APP = prosperon
|
||||||
SEM = 0.3.0
|
NAME = $(APP)$(INFO)$(EXT)
|
||||||
COM != fossil describe
|
SEM != git describe --tags --abbrev=0
|
||||||
VER = $(SEM)
|
COM != git rev-parse --short HEAD
|
||||||
|
|
||||||
|
LDLIBS += $(STEAMAPI)
|
||||||
LDLIBS := $(addprefix -l, $(LDLIBS))
|
LDLIBS := $(addprefix -l, $(LDLIBS))
|
||||||
|
LDPATHS := $(STEAM)/redistributable_bin/$(PLATFORM)
|
||||||
LDPATHS := $(addprefix -L, $(LDPATHS))
|
LDPATHS := $(addprefix -L, $(LDPATHS))
|
||||||
|
|
||||||
DEPENDS = $(OBJS:.o=.d)
|
DEPENDS = $(OBJS:.o=.d)
|
||||||
-include $(DEPENDS)
|
-include $(DEPENDS)
|
||||||
|
|
||||||
DIST = yugine-$(OS)$(ARCH)$(INFO)-$(COM)$(ZIP)
|
|
||||||
DISTDIR = ./dist
|
|
||||||
|
|
||||||
.DEFAULT_GOAL := all
|
.DEFAULT_GOAL := all
|
||||||
primum: all
|
all: $(NAME)
|
||||||
all: $(BIN)/$(NAME)
|
cp -f $(NAME) $(APP)$(EXT)
|
||||||
cp $(BIN)/$(NAME) .
|
|
||||||
|
|
||||||
DESTDIR ?= ~/.bin
|
|
||||||
|
|
||||||
CDB = source/engine/thirdparty/tinycdb
|
|
||||||
|
|
||||||
SHADERS = $(shell ls source/shaders/*.sglsl)
|
SHADERS = $(shell ls source/shaders/*.sglsl)
|
||||||
SHADERS := $(patsubst %.sglsl, %.sglsl.h, $(SHADERS))
|
SHADERS := $(patsubst %.sglsl, %.sglsl.h, $(SHADERS))
|
||||||
|
|
||||||
install: $(BIN)/$(NAME)
|
prereqs: $(SHADERS) source/engine/core.cdb.h
|
||||||
cp -f $(BIN)/$(NAME) $(DESTDIR)
|
|
||||||
|
|
||||||
$(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)
|
@echo Linking $(NAME)
|
||||||
$(LD) $^ $(CPPFLAGS) $(LDFLAGS) -L$(BIN) $(LDPATHS) $(LDLIBS) -o $@
|
$(LD) $^ $(CPPFLAGS) $(LDFLAGS) -L. $(LDPATHS) $(LDLIBS) -o $@
|
||||||
@echo Finished build
|
@echo Finished build
|
||||||
|
|
||||||
$(DISTDIR)/$(DIST): $(BIN)/$(NAME)
|
%$(INFO).o: %.c
|
||||||
@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)
|
|
||||||
@echo Making C object $@
|
@echo Making C object $@
|
||||||
@$(CC) $(CPPFLAGS) $(CFLAGS) -c $< -o $@
|
$(CC) $(CPPFLAGS) $(CFLAGS) -c $< -o $@
|
||||||
|
|
||||||
$(OBJDIR)/%.o: %.cpp
|
%$(INFO).o: %.cpp
|
||||||
@mkdir -p $(@D)
|
|
||||||
@echo Making C++ object $@
|
@echo Making C++ object $@
|
||||||
@$(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $< -o $@
|
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -fpermissive -c $< -o $@
|
||||||
|
|
||||||
$(OBJDIR)/%.o: %.m
|
%$(INFO).o: %.m
|
||||||
@mkdir -p $(@D)
|
|
||||||
@echo Making Objective-C object $@
|
@echo Making Objective-C object $@
|
||||||
@$(CC) $(CPPFLAGS) $(CFLAGS) -c $< -o $@
|
$(CC) $(CPPFLAGS) $(CFLAGS) -c $< -o $@
|
||||||
|
|
||||||
shaders: $(SHADERS)
|
shaders: $(SHADERS)
|
||||||
@echo Making shaders
|
@echo Making shaders
|
||||||
|
|
||||||
%.sglsl.h:%.sglsl
|
%.sglsl.h:%.sglsl
|
||||||
@echo Creating shader $^
|
@echo Creating shader $^
|
||||||
@./sokol-shdc --ifdef -i $^ --slang=glsl330:hlsl5:metal_macos:metal_ios:metal_sim:glsl300es -o $@
|
./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 $< > $@
|
|
||||||
|
|
||||||
SCRIPTS := $(shell ls scripts/*.js*)
|
SCRIPTS := $(shell ls scripts/*.js*)
|
||||||
SCRIPT_O := $(addsuffix o, $(SCRIPTS))
|
|
||||||
CORE != (ls icons/* fonts/*)
|
CORE != (ls icons/* fonts/*)
|
||||||
CORE := $(CORE) $(SCRIPTS)
|
CORE := $(CORE) $(SCRIPTS)
|
||||||
|
|
||||||
core.cdb: packer $(CORE)
|
packer$(EXT): tools/packer.c source/engine/miniz.c
|
||||||
./packer $(CORE)
|
@echo Making packer
|
||||||
chmod 644 out.cdb
|
$(CC) -O2 $^ -Isource/engine -o packer
|
||||||
mv out.cdb core.cdb
|
|
||||||
|
|
||||||
packer: tools/packer.c tools/libcdb.a
|
core.cdb: packer$(EXT) $(CORE)
|
||||||
cc $^ -I$(CDB) -o packer
|
@echo Packing core.cdb
|
||||||
|
./packer$(EXT) $@ $(CORE)
|
||||||
|
|
||||||
jsc: tools/jso.c tools/libquickjs.a
|
source/engine/core.cdb.h: core.cdb
|
||||||
$(CC) $^ -lm -Iquickjs -o $@
|
@echo Making $@
|
||||||
|
xxd -i $< > $@
|
||||||
|
|
||||||
tools/libquickjs.a: $(BIN)/libquickjs.a
|
ICNSIZE = 16 32 128 256 512 1024
|
||||||
cp -f $(BIN)/libquickjs.a tools
|
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
|
resource.o: resource.rc resource.manifest icon.ico
|
||||||
#WINCC = i686-w64-mingw32-g++
|
windres -i $< -o $@
|
||||||
.PHONY: crosswin
|
|
||||||
crosswin:
|
|
||||||
make packer
|
|
||||||
make CC=$(WINCC) OS=Windows_NT
|
|
||||||
|
|
||||||
crossmac:
|
crossios:
|
||||||
make ARCH=arm64
|
make OS=IOS ARCH=arm64 DEBUG=$(DEBUG) OPT=$(OPT)
|
||||||
mv primum primum_arm64
|
|
||||||
make ARCH=x86_64
|
Prosperon.icns: $(ICON)
|
||||||
mv primum primum_x86_64
|
mkdir -p Prosperon.iconset
|
||||||
lipo primum_arm64 primum_x86_64 -create -output primum
|
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:
|
crossweb:
|
||||||
make packer
|
|
||||||
make CC=emcc
|
make CC=emcc
|
||||||
|
|
||||||
|
playweb:
|
||||||
|
make crossweb
|
||||||
|
emrun $(NAME).html
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
@echo Cleaning project
|
@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 $(APP)* *.icns *.ico
|
||||||
rm -f source/shaders/*.h core.cdb jso cdb packer TAGS source/engine/core.cdb.h tools/libcdb.a $(CDB)/libcdb.a
|
find . -type f -name "*.[oad]" -delete
|
||||||
rm -f $(CDB)/*.o
|
rm -rf Prosperon.app
|
||||||
@make -C $(QUICKJS) clean
|
|
||||||
|
|
||||||
docs: doc/prosperon.org
|
docs: doc/prosperon.org
|
||||||
make -C doc
|
make -C doc
|
||||||
mv doc/html .
|
mv doc/html .
|
||||||
|
|
||||||
test:
|
|
||||||
@echo No tests yet ...
|
|
||||||
|
|
||||||
TAGINC != find . -name "*.[chj]"
|
TAGINC != find . -name "*.[chj]"
|
||||||
tags: $(TAGINC)
|
tags: $(TAGINC)
|
||||||
@echo Making tags.
|
@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.
|
While components can be added via scripting, it is easier to add them via the editor, as we will later see.
|
||||||
|
|
||||||
*** Ur system
|
*** 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
|
#+begin_scholium
|
||||||
Create an ur from the *hello* files above, and then spawn it.
|
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.
|
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
|
#+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.
|
Each ur has the following fields.
|
||||||
|
|
||||||
| field | description |
|
| 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 actor = {};
|
||||||
var a_db = {};
|
|
||||||
|
|
||||||
actor.spawn = function(script, config){
|
actor.spawn = function(script, config, callback){
|
||||||
if (typeof script !== 'string') return undefined;
|
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);
|
var padawan = Object.create(actor);
|
||||||
eval_env(a_db[script], padawan, script);
|
use(script, padawan);
|
||||||
|
|
||||||
if (typeof config === 'object')
|
if (typeof config === 'object')
|
||||||
Object.merge(padawan,config);
|
Object.merge(padawan,config);
|
||||||
|
@ -30,7 +29,7 @@ actor.timers = [];
|
||||||
actor.kill = function(){
|
actor.kill = function(){
|
||||||
if (this.__dead__) return;
|
if (this.__dead__) return;
|
||||||
this.timers.forEach(t => t());
|
this.timers.forEach(t => t());
|
||||||
Player.do_uncontrol(this);
|
input.do_uncontrol(this);
|
||||||
Event.rm_obj(this);
|
Event.rm_obj(this);
|
||||||
if (this.master) this.master.rm_pawn(this);
|
if (this.master) this.master.rm_pawn(this);
|
||||||
this.padawans.forEach(p => p.kill());
|
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.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) {
|
actor.delay = function(fn, seconds) {
|
||||||
var t = timer.delay(fn.bind(this), seconds);
|
var timers = this.timers;
|
||||||
this.timers.push(t);
|
var stop = function() {
|
||||||
return t;
|
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.`;
|
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 = [];
|
actor.padawans = [];
|
||||||
|
|
||||||
global.app = Object.create(actor);
|
global.app = Object.create(actor);
|
||||||
|
app.die = function() { os.quit(); }
|
||||||
app.die = function()
|
|
||||||
{
|
|
||||||
Game.quit();
|
|
||||||
}
|
|
||||||
|
|
||||||
return {actor, app};
|
return {actor, app};
|
||||||
|
|
|
@ -2,26 +2,28 @@ var ai = {
|
||||||
race(list) {
|
race(list) {
|
||||||
return function(dt) {
|
return function(dt) {
|
||||||
var good = false;
|
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;
|
return good;
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
do(times, list) {
|
|
||||||
|
|
||||||
},
|
|
||||||
|
|
||||||
sequence(list) {
|
sequence(list) {
|
||||||
var i = 0;
|
var i = 0;
|
||||||
return function(dt) {
|
var fn = function(dt) {
|
||||||
while (i !== list.length) {
|
while (i !== list.length) {
|
||||||
if (list[i].call(this,dt))
|
if (list[i].call(this,dt))
|
||||||
i++;
|
i++;
|
||||||
else
|
else
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
if (fn.done) fn.done();
|
||||||
return true;
|
return true;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
fn.restart = function() { i = 0; };
|
||||||
|
return fn;
|
||||||
},
|
},
|
||||||
|
|
||||||
parallel(list) {
|
parallel(list) {
|
||||||
|
@ -32,30 +34,21 @@ var ai = {
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
moveto() {
|
dofor(secs, fn) {
|
||||||
return function(dt) {
|
return ai.race([
|
||||||
var dir = this.randomloc.sub(this.pos);
|
ai.wait(secs),
|
||||||
if (Vector.length(dir) < 10) return true;
|
fn
|
||||||
|
]);
|
||||||
this.velocity = Vector.norm(this.randomloc.sub(this.pos)).scale(20);
|
|
||||||
return False;
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
|
|
||||||
move() {
|
wait(secs = 1) {
|
||||||
return function(dt) {
|
|
||||||
this.velocity = this.left().scale(20);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
wait(secs) {
|
|
||||||
secs ??= 1;
|
|
||||||
var accum = 0;
|
var accum = 0;
|
||||||
return function(dt) {
|
return function(dt) {
|
||||||
accum += dt;
|
accum += dt;
|
||||||
if (accum >= secs)
|
if (accum >= secs) {
|
||||||
|
accum = 0;
|
||||||
return true;
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
return false;
|
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.
|
In addition to the removal of a bunch of stuff as seen here.
|
||||||
Access prototypes through __proto__ instead of the long-winded Object.getProtoTypeOf.
|
Access prototypes through __proto__ instead of the long-winded Object.getProtoTypeOf.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Object.getPrototypeOf = undefined;
|
Object.getPrototypeOf = undefined;
|
||||||
Object.setPrototypeOf = 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 */
|
/* Time values are always expressed in terms of real earth-seconds */
|
||||||
var time = {
|
Object.assign(time, {
|
||||||
get hour2minute() { return this.hour/this.minute; },
|
hour2minute() { return this.hour/this.minute; },
|
||||||
get day2hour() { return this.day/this.hour; },
|
day2hour() { return this.day/this.hour; },
|
||||||
get minute2second() { return this.minute/this.second; },
|
minute2second() { return this.minute/this.second; },
|
||||||
get week2day() { return this.week/this.day; },
|
week2day() { return this.week/this.day; },
|
||||||
};
|
});
|
||||||
|
|
||||||
time.strparse = {
|
time.strparse = {
|
||||||
yyyy: "year",
|
yyyy: "year",
|
||||||
|
@ -106,8 +107,6 @@ time.doc = {
|
||||||
text: "Return a text formatted time."
|
text: "Return a text formatted time."
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
time.second = 1;
|
time.second = 1;
|
||||||
time.minute = 60;
|
time.minute = 60;
|
||||||
time.hour = 3_600;
|
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.monthstr = ["January", "February", "March", 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'];
|
||||||
|
|
||||||
time.epoch = 1970;
|
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 = function(year) { return this.yearsize(year) === 366; }
|
||||||
time.isleap.doc = "Return true if the given year is a leapyear.";
|
time.isleap.doc = "Return true if the given year is a leapyear.";
|
||||||
|
|
||||||
|
@ -129,14 +125,20 @@ time.yearsize = function(y) {
|
||||||
return 365;
|
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.monthdays = [31,28,31,30,31,30,31,31,30,31,30,31];
|
||||||
time.zones = {};
|
time.zones = {};
|
||||||
time.zones['-12'] = 'IDLW';
|
time.zones['-12'] = 'IDLW';
|
||||||
time.record = function(num, zone)
|
time.record = function(num, zone = this.computer_zone())
|
||||||
{
|
{
|
||||||
if (typeof num === 'object') return num;
|
if (typeof num === 'object') return num;
|
||||||
else if (typeof num === 'number') {
|
else if (typeof num === 'number') {
|
||||||
zone ??= this.computer_zone();
|
|
||||||
var monthdays = this.monthdays.slice();
|
var monthdays = this.monthdays.slice();
|
||||||
var rec = {
|
var rec = {
|
||||||
second: 0,
|
second: 0,
|
||||||
|
@ -215,9 +217,9 @@ time.number = function(rec)
|
||||||
c += this.day*this.yearsize(i);
|
c += this.day*this.yearsize(i);
|
||||||
|
|
||||||
c += (this.yearsize(year)-yday-1)*this.day;
|
c += (this.yearsize(year)-yday-1)*this.day;
|
||||||
c += (this.day2hour-hour-1)*this.hour;
|
c += (this.day2hour()-hour-1)*this.hour;
|
||||||
c += (this.hour2minute-minute-1)*this.minute;
|
c += (this.hour2minute()-minute-1)*this.minute;
|
||||||
c += (this.minute2second-second);
|
c += (this.minute2second()-second);
|
||||||
c += zone*this.hour;
|
c += zone*this.hour;
|
||||||
c *= -1;
|
c *= -1;
|
||||||
return c;
|
return c;
|
||||||
|
@ -258,9 +260,8 @@ time.number = function(rec)
|
||||||
time.fmt = "vB mB d h:nn:ss TZz a y c";
|
time.fmt = "vB mB d h:nn:ss TZz a y c";
|
||||||
|
|
||||||
/* If num is a number, converts to a rec first. */
|
/* 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;
|
var rec = num;
|
||||||
|
|
||||||
if (typeof rec === 'number')
|
if (typeof rec === 'number')
|
||||||
|
@ -312,37 +313,6 @@ time.text = function(num, fmt, zone)
|
||||||
return fmt;
|
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)
|
Object.methods = function(o)
|
||||||
{
|
{
|
||||||
var m = [];
|
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.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('.');
|
var pp = path.split('.');
|
||||||
for (var i = 0; i < pp.length-1; i++) {
|
for (var i = 0; i < pp.length-1; i++) {
|
||||||
obj = obj[pp[i]] = obj[pp[i]] || {};
|
obj = obj[pp[i]] = obj[pp[i]] || {};
|
||||||
|
@ -364,17 +333,6 @@ Object.dig = function(obj, path, def)
|
||||||
return 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)
|
Object.rkeys = function(o)
|
||||||
{
|
{
|
||||||
var keys = [];
|
var keys = [];
|
||||||
|
@ -386,6 +344,20 @@ Object.rkeys = function(o)
|
||||||
return keys;
|
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)
|
Object.extend = function(from)
|
||||||
{
|
{
|
||||||
var n = {};
|
var n = {};
|
||||||
|
@ -587,10 +559,8 @@ Object.defineProperty(Object.prototype, 'obscure', {
|
||||||
|
|
||||||
Object.defineProperty(Object.prototype, 'mixin', {
|
Object.defineProperty(Object.prototype, 'mixin', {
|
||||||
value: function(obj) {
|
value: function(obj) {
|
||||||
if (typeof obj === 'string') {
|
if (typeof obj === 'string')
|
||||||
var script = io.slurp(obj);
|
obj = use(obj, this);
|
||||||
obj = eval_env(script, this, obj);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (obj)
|
if (obj)
|
||||||
Object.mixin(this, 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', {
|
Object.defineProperty(String.prototype, 'tofirst', {
|
||||||
value: function(val) {
|
value: function(val) {
|
||||||
var idx = this.indexOf(val);
|
var idx = this.indexOf(val);
|
||||||
|
@ -852,13 +814,6 @@ Object.defineProperty(String.prototype, 'base', {
|
||||||
value: function() { return this.fromlast('/'); }
|
value: function() { return this.fromlast('/'); }
|
||||||
});
|
});
|
||||||
|
|
||||||
Object.defineProperty(String.prototype, 'dir', {
|
|
||||||
value: function() {
|
|
||||||
if (!this.includes('/')) return "";
|
|
||||||
return this.tolast('/');
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
Object.defineProperty(String.prototype, 'splice', {
|
Object.defineProperty(String.prototype, 'splice', {
|
||||||
value: function(index, str) {
|
value: function(index, str) {
|
||||||
return this.slice(0,index) + str + this.slice(index);
|
return this.slice(0,index) + str + this.slice(index);
|
||||||
|
@ -866,10 +821,7 @@ Object.defineProperty(String.prototype, 'splice', {
|
||||||
});
|
});
|
||||||
|
|
||||||
Object.defineProperty(String.prototype, 'rm', {
|
Object.defineProperty(String.prototype, 'rm', {
|
||||||
value: function(index, endidx) {
|
value: function(index, endidx = index+1) { return this.slice(0,index) + this.slice(endidx); }
|
||||||
endidx ??= index+1;
|
|
||||||
return this.slice(0,index) + this.slice(endidx);
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
Object.defineProperty(String.prototype, 'updir', {
|
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(); }});
|
Object.defineProperty(String.prototype, 'lc', {value:function() { return this.toLowerCase(); }});
|
||||||
|
|
||||||
/* ARRAY DEFS */
|
/* ARRAY DEFS */
|
||||||
|
Object.defineProperty(Array.prototype, 'aspect', {
|
||||||
|
value: function() {
|
||||||
|
return this.x/this.y;
|
||||||
|
}
|
||||||
|
});
|
||||||
Object.defineProperty(Array.prototype, 'copy', {
|
Object.defineProperty(Array.prototype, 'copy', {
|
||||||
value: function() {
|
value: function() {
|
||||||
var c = [];
|
var c = [];
|
||||||
|
@ -941,14 +898,12 @@ Object.defineProperty(Array.prototype, 'copy', {
|
||||||
|
|
||||||
Object.defineProperty(Array.prototype, 'dofilter', {
|
Object.defineProperty(Array.prototype, 'dofilter', {
|
||||||
value: function(fn) {
|
value: function(fn) {
|
||||||
var j = 0;
|
for (let i = 0; i < this.length; i++) {
|
||||||
this.forEach(function(val,i) {
|
if (!fn.call(this, this[i], i, this)) {
|
||||||
if (fn(val)) {
|
this.splice(i, 1);
|
||||||
if (i !== j) this[j] = val;
|
i--;
|
||||||
j++;
|
}
|
||||||
}
|
}
|
||||||
}, this);
|
|
||||||
this.length = j;
|
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -1138,13 +1093,19 @@ Object.defineProperty(Array.prototype, 'scale', {
|
||||||
return this.map(function(x) { return x*s; });
|
return this.map(function(x) { return x*s; });
|
||||||
}});
|
}});
|
||||||
|
|
||||||
|
Object.defineProperty(Array.prototype, 'sorted', {
|
||||||
|
value: function() {
|
||||||
|
return this.toSorted();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
Object.defineProperty(Array.prototype, 'equal', {
|
Object.defineProperty(Array.prototype, 'equal', {
|
||||||
value: function(b) {
|
value: function(b) {
|
||||||
if (this.length !== b.length) return false;
|
if (this.length !== b.length) return false;
|
||||||
if (b == null) return false;
|
if (b == null) return false;
|
||||||
if (this === b) return true;
|
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++) {
|
for (var i = 0; i < this.length; i++) {
|
||||||
if (!this[i] === b[i])
|
if (!this[i] === b[i])
|
||||||
|
@ -1401,6 +1362,21 @@ Math.randomint = function(max) { return Math.clamp(Math.floor(Math.random() * ma
|
||||||
/* BOUNDINGBOXES */
|
/* BOUNDINGBOXES */
|
||||||
var bbox = {};
|
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) {
|
bbox.fromcwh = function(c, wh) {
|
||||||
return {
|
return {
|
||||||
t: c.y+(wh.y/2),
|
t: c.y+(wh.y/2),
|
||||||
|
@ -1499,42 +1475,32 @@ bbox.fromobjs = function(objs)
|
||||||
};
|
};
|
||||||
|
|
||||||
/* VECTORS */
|
/* VECTORS */
|
||||||
var Vector = {
|
var Vector = {};
|
||||||
length(v) {
|
Vector.length = function(v) {
|
||||||
var sum = v.reduce(function(acc, val) { return acc + val**2; }, 0);
|
var sum = v.reduce(function(acc, val) { return acc + val**2; }, 0);
|
||||||
return Math.sqrt(sum);
|
return Math.sqrt(sum);
|
||||||
},
|
}
|
||||||
|
Vector.norm = function(v) {
|
||||||
norm(v) {
|
|
||||||
var len = Vector.length(v);
|
var len = Vector.length(v);
|
||||||
|
if (!len) return [0,0];
|
||||||
return [v.x/len, v.y/len];
|
return [v.x/len, v.y/len];
|
||||||
},
|
}
|
||||||
|
Vector.project = function(a, b) { return vector.project(a,b); }
|
||||||
project(a, b) {
|
Vector.dot = function(a, b) { return vector.dot(a,b); },
|
||||||
return cmd(85, a, b);
|
Vector.random = function() {
|
||||||
},
|
|
||||||
|
|
||||||
dot(a, b) {
|
|
||||||
return cmd(88,a,b);
|
|
||||||
},
|
|
||||||
|
|
||||||
random() {
|
|
||||||
var vec = [Math.random()-0.5, Math.random()-0.5];
|
var vec = [Math.random()-0.5, Math.random()-0.5];
|
||||||
return Vector.norm(vec);
|
return Vector.norm(vec);
|
||||||
},
|
}
|
||||||
|
|
||||||
angle(v) {
|
Vector.angle = function(v) { return Math.rad2turn(Math.atan2(v.y, v.x)); }
|
||||||
return Math.rad2turn(Math.atan2(v.y, v.x));
|
Vector.rotate = function(v,angle) {
|
||||||
},
|
|
||||||
|
|
||||||
rotate(v,angle) {
|
|
||||||
var r = Vector.length(v);
|
var r = Vector.length(v);
|
||||||
angle += Vector.angle(v);
|
angle += Vector.angle(v);
|
||||||
angle = Math.turn2rad(angle);
|
angle = Math.turn2rad(angle);
|
||||||
return [r*Math.cos(angle), r*Math.sin(angle)];
|
return [r*Math.cos(angle), r*Math.sin(angle)];
|
||||||
},
|
}
|
||||||
|
|
||||||
equal(v1, v2, tol) {
|
Vector.equal = function(v1, v2, tol) {
|
||||||
if (!tol)
|
if (!tol)
|
||||||
return v1.equal(v2);
|
return v1.equal(v2);
|
||||||
|
|
||||||
|
@ -1548,18 +1514,14 @@ var Vector = {
|
||||||
});
|
});
|
||||||
|
|
||||||
return eql;
|
return eql;
|
||||||
},
|
}
|
||||||
|
|
||||||
reflect(vec, plane) {
|
Vector.reflect = function(vec, plane) {
|
||||||
var p = Vector.norm(plane);
|
var p = Vector.norm(plane);
|
||||||
return vec.sub(p.scale(2*Vector.dot(vec, p)));
|
return vec.sub(p.scale(2*Vector.dot(vec, p)));
|
||||||
},
|
}
|
||||||
|
|
||||||
reflect_point(vec, point) {
|
Vector.reflect_point = function(vec, point) { return point.add(vec.sub(point).scale(-1)); }
|
||||||
return point.add(vec.sub(point).scale(-1));
|
|
||||||
},
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
/* POINT ASSISTANCE */
|
/* POINT ASSISTANCE */
|
||||||
|
|
||||||
|
|
|
@ -1,29 +1,44 @@
|
||||||
this.phys = physics.kinematic;
|
this.phys = physics.kinematic;
|
||||||
this.dir_view2world = function(dir) { return dir.scale(this.realzoom()); };
|
this.dir_view2world = function(dir) { return dir.scale(this.zoom); };
|
||||||
this.view2world = function(pos) { return cmd(137,pos); };
|
this.view2world = function(pos) {
|
||||||
this.world2view = function(pos) { return cmd(136,pos); };
|
var useren = window.rendersize.scale(this.zoom);
|
||||||
this.realzoom = function() { return cmd(135); };
|
if (window.mode === window.modetypes.stretch) {
|
||||||
|
pos = pos.scale([window.rendersize.x/window.size.x, window.rendersize.y/window.size.y]);
|
||||||
this.right = function()
|
pos = pos.sub(window.rendersize.scale(0.5));
|
||||||
{
|
pos = pos.scale(this.zoom);
|
||||||
return this.pos.x + (Window.rendersize.x/2);
|
pos = pos.add(this.pos);
|
||||||
}
|
}
|
||||||
|
if (window.mode === window.modetypes.full) {
|
||||||
this.left = function()
|
pos = pos.sub(window.size.scale(0.5));
|
||||||
{
|
pos = pos.scale(this.zoom);
|
||||||
return this.pos.x - (Window.rendersize.x/2);
|
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({
|
this.screenright = function() { return this.view2world(window.size).x; }
|
||||||
get zoom() {
|
this.screenleft = function() { return this.view2world([0,0]).x; }
|
||||||
// var z = Game.native.y / Window.dimensions.y;
|
|
||||||
return cmd(135);///z;
|
|
||||||
},
|
|
||||||
|
|
||||||
|
var zoom = 1;
|
||||||
|
|
||||||
|
Object.mixin(self, {
|
||||||
set zoom(x) {
|
set zoom(x) {
|
||||||
x = Math.clamp(x,0.1,10);
|
zoom = x;
|
||||||
// var z = Game.native.y / Window.dimensions.y;
|
if (zoom <= 0.1) zoom = 0.1;
|
||||||
// z *= x;
|
|
||||||
cmd(62,x);
|
|
||||||
},
|
},
|
||||||
});
|
get zoom() { return zoom; }
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
|
@ -173,9 +173,8 @@ ColorMap.Viridis = ColorMap.makemap({
|
||||||
|
|
||||||
Color.normalize(ColorMap);
|
Color.normalize(ColorMap);
|
||||||
|
|
||||||
ColorMap.sample = function(t, map)
|
ColorMap.sample = function(t, map = this)
|
||||||
{
|
{
|
||||||
map ??= this;
|
|
||||||
if (t < 0) return map[0];
|
if (t < 0) return map[0];
|
||||||
if (t > 1) return map[1];
|
if (t > 1) return map[1];
|
||||||
|
|
||||||
|
|
|
@ -22,10 +22,11 @@ var component = {
|
||||||
make(go) {
|
make(go) {
|
||||||
var nc = Object.create(this);
|
var nc = Object.create(this);
|
||||||
nc.gameobject = go;
|
nc.gameobject = go;
|
||||||
Object.mixin(nc, this._enghook(go.body));
|
Object.mixin(nc, this._enghook(go, nc));
|
||||||
assign_impl(nc,this.impl);
|
assign_impl(nc,this.impl);
|
||||||
Object.hide(nc, 'gameobject', 'id');
|
Object.hide(nc, 'gameobject', 'id');
|
||||||
nc.post();
|
nc.post();
|
||||||
|
nc.make = undefined;
|
||||||
return nc;
|
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([
|
toJSON:json_from_whitelist([
|
||||||
"path",
|
"path",
|
||||||
"pos",
|
"pos",
|
||||||
|
@ -88,36 +90,66 @@ Object.mixin(cmd(268,true), {
|
||||||
]),
|
]),
|
||||||
anim:{},
|
anim:{},
|
||||||
playing: 0,
|
playing: 0,
|
||||||
play(str) {
|
play(str = 0) {
|
||||||
var sp = this;
|
this.del_anim?.();
|
||||||
str ??= 0;
|
var self = this;
|
||||||
var playing = this.anim[str];
|
var stop;
|
||||||
if (!playing) return; //TODO: ERROR
|
self.del_anim = function() {
|
||||||
|
self.del_anim = undefined;
|
||||||
|
self = undefined;
|
||||||
|
advance = undefined;
|
||||||
|
stop?.();
|
||||||
|
}
|
||||||
|
var playing = self.anim[str];
|
||||||
|
if (!playing) return;
|
||||||
var f = 0;
|
var f = 0;
|
||||||
|
self.path = playing.path;
|
||||||
|
|
||||||
function advance() {
|
function advance() {
|
||||||
sp.path = playing.path;
|
if (!self) return;
|
||||||
sp.frame = playing.frames[f].rect;
|
if (!self.gameobject) return;
|
||||||
|
//self.path = playing.path;
|
||||||
|
self.frame = playing.frames[f].rect;
|
||||||
f = (f+1)%playing.frames.length;
|
f = (f+1)%playing.frames.length;
|
||||||
if (f === 0)
|
if (f === 0) {
|
||||||
sp.anim_done?.();
|
self.anim_done?.();
|
||||||
sp.gameobject?.delay(advance, playing.frames[f].time);
|
if (!self.loop) { self.stop(); return; }
|
||||||
}
|
}
|
||||||
|
stop = self.gameobject.delay(advance, playing.frames[f].time);
|
||||||
|
}
|
||||||
|
this.tex(game.texture(playing.path));
|
||||||
advance();
|
advance();
|
||||||
},
|
},
|
||||||
stop() {},
|
stop() {
|
||||||
|
this.del_anim?.();
|
||||||
|
},
|
||||||
set path(p) {
|
set path(p) {
|
||||||
p = Resources.find_image(p);
|
p = Resources.find_image(p);
|
||||||
if (!p) return;
|
if (!p) {
|
||||||
|
console.warn(`Could not find image ${p}.`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (p === this.path) 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);
|
var anim = SpriteAnim.make(p);
|
||||||
if (!anim) return;
|
if (!anim) return;
|
||||||
this.anim = anim;
|
this.anim = anim;
|
||||||
this.play();
|
this.play();
|
||||||
|
|
||||||
|
this.pos = this.dimensions().scale(this.anchor);
|
||||||
},
|
},
|
||||||
get path() {
|
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"; },
|
toString() { return "sprite"; },
|
||||||
move(d) { this.pos = this.pos.add(d); },
|
move(d) { this.pos = this.pos.add(d); },
|
||||||
|
@ -125,7 +157,7 @@ Object.mixin(cmd(268,true), {
|
||||||
this.scale = this.scale.scale(x);
|
this.scale = this.scale.scale(x);
|
||||||
this.pos = this.pos.scale(x);
|
this.pos = this.pos.scale(x);
|
||||||
},
|
},
|
||||||
|
anchor:[0,0],
|
||||||
sync() { },
|
sync() { },
|
||||||
pick() { return this; },
|
pick() { return this; },
|
||||||
boundingbox() {
|
boundingbox() {
|
||||||
|
@ -136,7 +168,7 @@ Object.mixin(cmd(268,true), {
|
||||||
},
|
},
|
||||||
|
|
||||||
dimensions() {
|
dimensions() {
|
||||||
var dim = [this.tex.width(), this.tex.height()];
|
var dim = [this.texture.width, this.texture.height];
|
||||||
dim.x *= this.frame.w;
|
dim.x *= this.frame.w;
|
||||||
dim.y *= this.frame.h;
|
dim.y *= this.frame.h;
|
||||||
return dim;
|
return dim;
|
||||||
|
@ -145,28 +177,15 @@ Object.mixin(cmd(268,true), {
|
||||||
height() { return this.dimensions().y; },
|
height() { return this.dimensions().y; },
|
||||||
});
|
});
|
||||||
|
|
||||||
cmd(268,true).make = function(go)
|
os.sprite(true).make = function(go)
|
||||||
{
|
{
|
||||||
var sp = cmd(268);
|
var sp = os.sprite();
|
||||||
sp.go = go.body;
|
sp.go = go;
|
||||||
sp.gameobject = go;
|
sp.gameobject = go;
|
||||||
return sp;
|
return sp;
|
||||||
}
|
}
|
||||||
|
|
||||||
component.sprite = cmd(268,true);
|
component.sprite = os.sprite(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); },
|
|
||||||
};
|
|
||||||
|
|
||||||
var sprite = component.sprite;
|
var sprite = component.sprite;
|
||||||
|
|
||||||
|
@ -176,16 +195,34 @@ sprite.doc = {
|
||||||
pos: "The offset position of the sprite, relative to its entity."
|
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 = {};
|
||||||
sprite.inputs.kp9 = function() { this.pos = this.dimensions().scale([0,0]); };
|
sprite.inputs.kp9 = function() { this.setanchor("ll"); }
|
||||||
sprite.inputs.kp8 = function() { this.pos = this.dimensions().scale([-0.5, 0]); };
|
sprite.inputs.kp8 = function() { this.setanchor("lm"); }
|
||||||
sprite.inputs.kp7 = function() { this.pos = this.dimensions().scale([-1,0]); };
|
sprite.inputs.kp7 = function() { this.setanchor("lr"); }
|
||||||
sprite.inputs.kp6 = function() { this.pos = this.dimensions().scale([0,-0.5]); };
|
sprite.inputs.kp6 = function() { this.setanchor("ml"); }
|
||||||
sprite.inputs.kp5 = function() { this.pos = this.dimensions().scale([-0.5,-0.5]); };
|
sprite.inputs.kp5 = function() { this.setanchor("mm"); }
|
||||||
sprite.inputs.kp4 = function() { this.pos = this.dimensions().scale([-1,-0.5]); };
|
sprite.inputs.kp4 = function() { this.setanchor("mr"); }
|
||||||
sprite.inputs.kp3 = function() { this.pos = this.dimensions().scale([0, -1]); };
|
sprite.inputs.kp3 = function() { this.setanchor("ur"); }
|
||||||
sprite.inputs.kp2 = function() { this.pos = this.dimensions().scale([-0.5,-1]); };
|
sprite.inputs.kp2 = function() { this.setanchor("um"); }
|
||||||
sprite.inputs.kp1 = function() { this.pos = this.dimensions().scale([-1,-1]); };
|
sprite.inputs.kp1 = function() { this.setanchor("ul"); }
|
||||||
|
|
||||||
Object.seal(sprite);
|
Object.seal(sprite);
|
||||||
|
|
||||||
/* sprite anim returns a data structure for the given file path
|
/* 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
|
time: miliseconds to hold the frame for
|
||||||
loop: true if it should be looped
|
loop: true if it should be looped
|
||||||
*/
|
*/
|
||||||
var SpriteAnim = {
|
var animcache = {};
|
||||||
make(path) {
|
var SpriteAnim = {};
|
||||||
if (path.ext() === 'gif')
|
SpriteAnim.make = function(path) {
|
||||||
return SpriteAnim.gif(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')
|
else if (path.ext() === 'ase')
|
||||||
return SpriteAnim.aseprite(path);
|
anim = SpriteAnim.aseprite(path);
|
||||||
|
else if (path.ext() === 'gif')
|
||||||
|
anim = SpriteAnim.gif(path);
|
||||||
else
|
else
|
||||||
return undefined;
|
anim = undefined;
|
||||||
},
|
|
||||||
gif(path) {
|
animcache[path] = anim;
|
||||||
|
return animcache[path];
|
||||||
|
};
|
||||||
|
SpriteAnim.gif = function(path) {
|
||||||
|
console.info(`making an anim from ${path}`);
|
||||||
var anim = {};
|
var anim = {};
|
||||||
anim.frames = [];
|
anim.frames = [];
|
||||||
anim.path = path;
|
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;
|
var yslice = 1/frames;
|
||||||
for (var f = 0; f < frames; f++) {
|
for (var f = 0; f < frames; f++) {
|
||||||
var frame = {};
|
var frame = {};
|
||||||
|
@ -220,17 +271,18 @@ var SpriteAnim = {
|
||||||
frame.time = 0.05;
|
frame.time = 0.05;
|
||||||
anim.frames.push(frame);
|
anim.frames.push(frame);
|
||||||
}
|
}
|
||||||
var times = cmd(224,path);
|
var times = tex.delays;
|
||||||
for (var i = 0; i < frames; i++)
|
for (var i = 0; i < frames; i++)
|
||||||
anim.frames[i].time = times[i]/1000;
|
anim.frames[i].time = times[i]/1000;
|
||||||
anim.loop = true;
|
anim.loop = true;
|
||||||
var dim = Resources.texture.dimensions(path);
|
var dim = [tex.width,tex.height];
|
||||||
|
console.info(`dimensions are ${dim}`);
|
||||||
dim.y /= frames;
|
dim.y /= frames;
|
||||||
anim.dim = dim;
|
anim.dim = dim;
|
||||||
return {0:anim};
|
return {0:anim};
|
||||||
},
|
};
|
||||||
|
|
||||||
strip(path, frames, time=0.05) {
|
SpriteAnim.strip = function(path, frames, time=0.05) {
|
||||||
var anim = {};
|
var anim = {};
|
||||||
anim.frames = [];
|
anim.frames = [];
|
||||||
anim.path = path;
|
anim.path = path;
|
||||||
|
@ -244,16 +296,16 @@ var SpriteAnim = {
|
||||||
anim.dim = Resources.texture.dimensions(path);
|
anim.dim = Resources.texture.dimensions(path);
|
||||||
anim.dim.x /= frames;
|
anim.dim.x /= frames;
|
||||||
return anim;
|
return anim;
|
||||||
},
|
};
|
||||||
|
|
||||||
aseprite(path) {
|
SpriteAnim.aseprite = function(path) {
|
||||||
function aseframeset2anim(frameset, meta) {
|
function aseframeset2anim(frameset, meta) {
|
||||||
var anim = {};
|
var anim = {};
|
||||||
anim.frames = [];
|
anim.frames = [];
|
||||||
anim.path = meta.image;
|
anim.path = path.dir() + "/" + meta.image;
|
||||||
var dim = meta.size;
|
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 f = ase_frame.frame;
|
||||||
var frame = {};
|
var frame = {};
|
||||||
frame.rect = {
|
frame.rect = {
|
||||||
|
@ -267,38 +319,35 @@ var SpriteAnim = {
|
||||||
};
|
};
|
||||||
|
|
||||||
frameset.forEach(ase_make_frame);
|
frameset.forEach(ase_make_frame);
|
||||||
anim.dim = [frameset[0].sourceSize.x, frameset[0].sourceSize.y];
|
anim.dim = frameset[0].sourceSize;
|
||||||
anim.loop = true;
|
anim.loop = true;
|
||||||
return anim;
|
return anim;
|
||||||
};
|
};
|
||||||
|
|
||||||
var json = io.slurp(path);
|
var data = json.decode(io.slurp(path));
|
||||||
json = JSON.parse(json);
|
if (!data?.meta?.app.includes("aseprite")) return;
|
||||||
var anims = {};
|
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;
|
var f = 0;
|
||||||
for (var tag of json.meta.frameTags) {
|
for (var tag of data.meta.frameTags) {
|
||||||
anims[tag.name] = aseframeset2anim(frames.slice(tag.from, tag.to+1), json.meta);
|
anims[tag.name] = aseframeset2anim(frames.slice(tag.from, tag.to+1), data.meta);
|
||||||
anims[f] = anims[tag.name];
|
anims[f] = anims[tag.name];
|
||||||
f++;
|
f++;
|
||||||
}
|
}
|
||||||
|
|
||||||
return anims;
|
return anims;
|
||||||
},
|
};
|
||||||
|
|
||||||
validate(anim)
|
SpriteAnim.validate = function(anim) {
|
||||||
{
|
|
||||||
if (!Object.isObject(anim)) return false;
|
if (!Object.isObject(anim)) return false;
|
||||||
if (typeof anim.path !== 'string') return false;
|
if (typeof anim.path !== 'string') return false;
|
||||||
if (typeof anim.dim !== 'object') return false;
|
if (typeof anim.dim !== 'object') return false;
|
||||||
return true;
|
return true;
|
||||||
},
|
};
|
||||||
|
|
||||||
find(path) {
|
SpriteAnim.find = function(path) {
|
||||||
if (!io.exists(path + ".asset")) return;
|
if (!io.exists(path + ".asset")) return;
|
||||||
var asset = JSON.parse(io.slurp(path + ".asset"));
|
var asset = JSON.parse(io.slurp(path + ".asset"));
|
||||||
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
|
|
||||||
SpriteAnim.doc = 'Functions to create Primum animations from varying sources.';
|
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 */
|
/* For all colliders, "shape" is a pointer to a phys2d_shape, "id" is a pointer to the shape data */
|
||||||
var collider2d = Object.copy(component, {
|
var collider2d = Object.copy(component, {
|
||||||
name: "collider 2d",
|
|
||||||
sensor: false,
|
|
||||||
|
|
||||||
kill() {}, /* No killing is necessary - it is done through the gameobject's kill */
|
|
||||||
|
|
||||||
impl: {
|
impl: {
|
||||||
set sensor(x) { cmd(18,this.shape,x); },
|
set sensor(x) { pshape.set_sensor(this.shape,x); },
|
||||||
get sensor() { return cmd(21,this.shape); },
|
get sensor() { return pshape.get_sensor(this.shape); },
|
||||||
set enabled(x) { cmd(22,this.shape,x); },
|
set enabled(x) { pshape.set_enabled(this.shape,x); },
|
||||||
get enabled() { return cmd(23,this.shape); }
|
get enabled() { return pshape.get_enabled(this.shape); }
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -345,7 +389,7 @@ component.polygon2d = Object.copy(collider2d, {
|
||||||
},
|
},
|
||||||
|
|
||||||
hides: ['id', 'shape', 'gameobject'],
|
hides: ['id', 'shape', 'gameobject'],
|
||||||
_enghook: make_poly2d,
|
_enghook: os.make_poly2d,
|
||||||
points:[],
|
points:[],
|
||||||
setpoints(points) {
|
setpoints(points) {
|
||||||
this.points = points;
|
this.points = points;
|
||||||
|
@ -376,7 +420,7 @@ component.polygon2d = Object.copy(collider2d, {
|
||||||
|
|
||||||
gizmo() {
|
gizmo() {
|
||||||
this.spoints().forEach(x => render.point(this.gameobject.this2screen(x), 3, Color.green));
|
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) {
|
pick(pos) {
|
||||||
|
@ -398,8 +442,8 @@ function pointscaler(x) {
|
||||||
}
|
}
|
||||||
|
|
||||||
component.polygon2d.impl = Object.mix(collider2d.impl, {
|
component.polygon2d.impl = Object.mix(collider2d.impl, {
|
||||||
sync() { cmd_poly2d(0, this.id, this.spoints());},
|
sync() { poly2d.setverts(this.id,this.spoints()); },
|
||||||
query() { return cmd(80, this.shape); },
|
query() { return physics.shape_query(this.shape); },
|
||||||
grow: pointscaler,
|
grow: pointscaler,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -413,14 +457,14 @@ polygon2d.inputs.f10 = function() {
|
||||||
polygon2d.inputs.f10.doc = "Sort all points to be CCW order.";
|
polygon2d.inputs.f10.doc = "Sort all points to be CCW order.";
|
||||||
|
|
||||||
polygon2d.inputs['C-lm'] = function() {
|
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['C-lm'].doc = "Add a point to location of mouse.";
|
||||||
polygon2d.inputs.lm = function(){};
|
polygon2d.inputs.lm = function(){};
|
||||||
polygon2d.inputs.lm.released = function(){};
|
polygon2d.inputs.lm.released = function(){};
|
||||||
|
|
||||||
polygon2d.inputs['C-M-lm'] = 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;
|
if (idx === -1) return;
|
||||||
this.points.splice(idx, 1);
|
this.points.splice(idx, 1);
|
||||||
};
|
};
|
||||||
|
@ -440,6 +484,7 @@ component.edge2d = Object.copy(collider2d, {
|
||||||
'points',
|
'points',
|
||||||
'hollow',
|
'hollow',
|
||||||
'hollowt',
|
'hollowt',
|
||||||
|
'angle',
|
||||||
]),
|
]),
|
||||||
dimensions:2,
|
dimensions:2,
|
||||||
thickness:0,
|
thickness:0,
|
||||||
|
@ -484,7 +529,7 @@ component.edge2d = Object.copy(collider2d, {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.hollow) {
|
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;
|
if (hpoints.length === spoints.length) return spoints;
|
||||||
var arr1 = hpoints.filter(function(x,i) { return i % 2 === 0; });
|
var arr1 = hpoints.filter(function(x,i) { return i % 2 === 0; });
|
||||||
var arr2 = 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))); },
|
boundingbox() { return bbox.frompoints(this.points.map(x => x.scale(this.gameobject.scale))); },
|
||||||
|
|
||||||
hides: ['gameobject', 'id', 'shape'],
|
hides: ['gameobject', 'id', 'shape'],
|
||||||
_enghook: make_edge2d,
|
_enghook: os.make_edge2d,
|
||||||
|
|
||||||
/* EDITOR */
|
/* EDITOR */
|
||||||
gizmo() {
|
gizmo() {
|
||||||
if (this.type === Spline.type.catmull || this.type === -1) {
|
if (this.type === Spline.type.catmull || this.type === -1) {
|
||||||
this.spoints().forEach(x => render.point(this.gameobject.this2screen(x), 3, Color.teal));
|
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 {
|
} else {
|
||||||
for (var i = 0; i < this.points.length; i += 3)
|
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) {
|
for (var i = 1; i < this.points.length; i+=3) {
|
||||||
Debug.numbered_point(this.gameobject.this2screen(this.points[i]), i, Color.green);
|
render.coordinate(this.gameobject.this2screen(this.points[i]), 1, 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]), 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])], Color.yellow);
|
||||||
render.line([this.gameobject.this2screen(this.points[i+1]), this.gameobject.this2screen(this.points[i+2])], 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;
|
var idx = 0;
|
||||||
if (Spline.is_catmull(this.type) || this.type === -1) {
|
if (Spline.is_catmull(this.type) || this.type === -1) {
|
||||||
if (this.points.length >= 2)
|
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)
|
if (idx === this.points.length)
|
||||||
this.points.push(pos);
|
this.points.push(pos);
|
||||||
|
@ -616,7 +661,7 @@ component.edge2d = Object.copy(collider2d, {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Spline.is_bezier(this.type)) {
|
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;
|
if (idx < 0) return;
|
||||||
|
|
||||||
|
@ -642,16 +687,14 @@ component.edge2d = Object.copy(collider2d, {
|
||||||
});
|
});
|
||||||
|
|
||||||
component.edge2d.impl = Object.mix(collider2d.impl, {
|
component.edge2d.impl = Object.mix(collider2d.impl, {
|
||||||
set thickness(x) {
|
set thickness(x) { edge2d.set_thickness(this.id,x); },
|
||||||
cmd_edge2d(1,this.id,x);
|
get thickness() { return edge2d.get_thickness(this.id); },
|
||||||
},
|
|
||||||
get thickness() { return cmd(112,this.id); },
|
|
||||||
grow: pointscaler,
|
grow: pointscaler,
|
||||||
sync() {
|
sync() {
|
||||||
var sensor = this.sensor;
|
var sensor = this.sensor;
|
||||||
var points = this.sample();
|
var points = this.sample();
|
||||||
if (!points) return;
|
if (!points) return;
|
||||||
cmd_edge2d(0,this.id,points);
|
edge2d.setverts(this.id,points);
|
||||||
this.sensor = sensor;
|
this.sensor = sensor;
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
@ -659,7 +702,6 @@ component.edge2d.impl = Object.mix(collider2d.impl, {
|
||||||
var bucket = component.edge2d;
|
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.spoints.doc = "Returns the controls points after modifiers are applied, such as it being hollow or mirrored on its axises.";
|
||||||
bucket.inputs = {};
|
bucket.inputs = {};
|
||||||
//bucket.inputs.post = function() { this.sync(); };
|
|
||||||
bucket.inputs.h = function() { this.hollow = !this.hollow; };
|
bucket.inputs.h = function() { this.hollow = !this.hollow; };
|
||||||
bucket.inputs.h.doc = "Toggle 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() {
|
bucket.inputs['C-M-lm'] = function() {
|
||||||
if (Spline.is_catmull(this.type)) {
|
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;
|
if (idx === -1) return;
|
||||||
} else {
|
} 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-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-lm'].doc = "Add a point to the spline at the mouse position.";
|
||||||
|
|
||||||
bucket.inputs['C-M-lm'] = function() {
|
bucket.inputs['C-M-lm'] = function() {
|
||||||
var idx = -1;
|
var idx = -1;
|
||||||
if (Spline.is_catmull(this.type))
|
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 {
|
else {
|
||||||
var nodes = Spline.bezier_nodes(this.points);
|
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;
|
idx *= 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -791,11 +833,11 @@ component.circle2d = Object.copy(collider2d, {
|
||||||
toString() { return "circle2d"; },
|
toString() { return "circle2d"; },
|
||||||
|
|
||||||
boundingbox() {
|
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'],
|
hides: ['gameobject', 'id', 'shape', 'scale'],
|
||||||
_enghook: make_circle2d,
|
_enghook: os.make_circle2d,
|
||||||
});
|
});
|
||||||
|
|
||||||
component.circle2d.impl = Object.mix({
|
component.circle2d.impl = Object.mix({
|
||||||
|
@ -804,17 +846,17 @@ component.circle2d.impl = Object.mix({
|
||||||
"radius",
|
"radius",
|
||||||
]),
|
]),
|
||||||
|
|
||||||
set radius(x) { cmd_circle2d(0,this.id,x); },
|
set radius(x) { circle2d.set_radius(this.id,x); circle2d.sync(this.id); },
|
||||||
get radius() { return cmd_circle2d(2,this.id); },
|
get radius() { return circle2d.get_radius(this.id); },
|
||||||
|
|
||||||
set scale(x) { this.radius = x; },
|
set scale(x) { this.radius = x; },
|
||||||
get scale() { return this.radius; },
|
get scale() { return this.radius; },
|
||||||
|
|
||||||
set offset(x) { cmd_circle2d(1,this.id,x); },
|
set offset(x) { circle2d.set_offset(this.id,x); circle2d.sync(this.id); },
|
||||||
get offset() { return cmd_circle2d(3,this.id); },
|
get offset() { circle2d.get_offset(this.id); },
|
||||||
|
|
||||||
get pos() { return cmd_circle2d(3,this.id); },
|
get pos() { return this.offset; },
|
||||||
set pos(x) { cmd_circle2d(1,this.id,x); },
|
set pos(x) { this.offset = x; },
|
||||||
|
|
||||||
grow(x) {
|
grow(x) {
|
||||||
if (typeof x === 'number') this.scale *= x;
|
if (typeof x === 'number') this.scale *= x;
|
||||||
|
|
276
scripts/debug.js
276
scripts/debug.js
|
@ -1,95 +1,59 @@
|
||||||
var Debug = {
|
debug.fn_break = function(fn,obj = globalThis) {
|
||||||
fn_break(fn, obj) {
|
|
||||||
if (typeof fn !== 'function') return;
|
if (typeof fn !== 'function') return;
|
||||||
obj ??= globalThis;
|
|
||||||
|
|
||||||
var newfn = function() {
|
var newfn = function() {
|
||||||
console.log("broke");
|
console.log("broke");
|
||||||
fn();
|
fn();
|
||||||
};
|
};
|
||||||
obj[fn.name] = newfn;
|
obj[fn.name] = newfn;
|
||||||
},
|
}
|
||||||
|
|
||||||
draw_grid(width, span, color) {
|
debug.draw_phys = false;
|
||||||
color = color ? color : Color.green;
|
debug.draw_bb = false;
|
||||||
cmd(47, width, span, color);
|
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)
|
if (this.draw_bb)
|
||||||
Game.all_objects(function(x) { Debug.boundingbox(x.boundingbox(), Color.Debug.boundingbox.alpha(0.05)); });
|
game.all_objects(function(x) { debug.boundingbox(x.boundingbox(), Color.debug.boundingbox.alpha(0.05)); });
|
||||||
|
|
||||||
if (Game.paused()) GUI.text("PAUSED", [0,0],1);
|
|
||||||
|
|
||||||
if (this.draw_gizmos)
|
if (this.draw_gizmos)
|
||||||
Game.all_objects(function(x) {
|
game.all_objects(function(x) {
|
||||||
if (!x.icon) return;
|
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)
|
if (this.draw_names)
|
||||||
Game.all_objects(function(x) {
|
game.all_objects(function(x) {
|
||||||
GUI.text(x, Window.world2screen(x.pos).add([0,32]), 1, Color.Debug.names);
|
render.text(x, game.camera.view2screen(x.pos).add([0,32]), 1, Color.debug.names);
|
||||||
});
|
});
|
||||||
|
|
||||||
if (Debug.Options.gif.rec) {
|
if (debug.gif.rec) {
|
||||||
GUI.text("REC", [0,40], 1);
|
render.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);
|
render.text(time.timecode(time.timenow() - debug.gif.start_time, debug.gif.fps), [0,30], 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
GUI.text(Game.playing() ? "PLAYING"
|
return;
|
||||||
: Game.stepping() ?
|
|
||||||
|
if (sim.paused()) render.text("PAUSED", [0,0],1);
|
||||||
|
|
||||||
|
render.text(sim.playing() ? "PLAYING"
|
||||||
|
: sim.stepping() ?
|
||||||
"STEP" :
|
"STEP" :
|
||||||
Game.paused() ?
|
sim.paused() ?
|
||||||
"PAUSED; EDITING" :
|
"PAUSED; EDITING" :
|
||||||
"EDIT", [0, 0], 1);
|
"EDIT", [0, 0], 1);
|
||||||
},
|
}
|
||||||
};
|
|
||||||
|
|
||||||
function assert(op, str)
|
function assert(op, str = `assertion failed [value '${op}']`)
|
||||||
{
|
{
|
||||||
str ??= `assertion failed [value '${op}']`;
|
|
||||||
if (!op) {
|
if (!op) {
|
||||||
console.error(`Assertion failed: ${str}`);
|
console.error(str);
|
||||||
Game.quit();
|
os.quit();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Debug.Options = { };
|
|
||||||
Debug.Options.Color = {
|
|
||||||
set trigger(x) { cmd(17,x); },
|
|
||||||
set debug(x) { cmd(16, x); },
|
|
||||||
};
|
|
||||||
|
|
||||||
var Gizmos = {
|
var Gizmos = {
|
||||||
pick_gameobject_points(worldpos, gameobject, points) {
|
pick_gameobject_points(worldpos, gameobject, points) {
|
||||||
var idx = Math.grab_from_points(worldpos, points.map(gameobject.this2world,gameobject), 25);
|
var idx = Math.grab_from_points(worldpos, points.map(gameobject.this2world,gameobject), 25);
|
||||||
|
@ -98,83 +62,34 @@ var Gizmos = {
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
Object.assign(performance, {
|
profile.cpu = function(fn, times = 1, q = "unnamed") {
|
||||||
tick_now() { return cmd(127); },
|
var start = profile.now();
|
||||||
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();
|
|
||||||
for (var i = 0; i < times; i++)
|
for (var i = 0; i < times; i++)
|
||||||
fn();
|
fn();
|
||||||
|
|
||||||
var elapsed = performance.tick_now() - start;
|
var elapsed = profile.now() - start;
|
||||||
var avgt = performance.best_t(elapsed/times);
|
var avgt = profile.best_t(elapsed/times);
|
||||||
var totalt = performance.best_t(elapsed);
|
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); },
|
profile.ms = function(t) { return t/1000000; }
|
||||||
|
profile.secs = function(t) { return t/1000000000; }
|
||||||
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.`;
|
|
||||||
|
|
||||||
/* These controls are available during editing, and during play of debug builds */
|
/* These controls are available during editing, and during play of debug builds */
|
||||||
Debug.inputs = {};
|
debug.inputs = {};
|
||||||
Debug.inputs.f1 = function () { Debug.draw_phys(!Debug.phys_drawing); };
|
debug.inputs.f1 = function () { debug.draw_phys = !debug.draw_phys; };
|
||||||
Debug.inputs.f1.doc = "Draw physics debugging aids.";
|
debug.inputs.f1.doc = "Draw physics debugging aids.";
|
||||||
//Debug.inputs.f3 = function() { Debug.draw_bb = !Debug.draw_bb; };
|
debug.inputs.f3 = function() { debug.draw_bb = !debug.draw_bb; };
|
||||||
//Debug.inputs.f3.doc = "Toggle drawing bounding boxes.";
|
debug.inputs.f3.doc = "Toggle drawing bounding boxes.";
|
||||||
Debug.inputs.f4 = function() {
|
debug.inputs.f4 = function() {
|
||||||
Debug.draw_names = !Debug.draw_names;
|
debug.draw_names = !debug.draw_names;
|
||||||
Debug.draw_gizmos = !Debug.draw_gizmos;
|
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 */
|
w: 640, /* Max width */
|
||||||
h: 480, /* Max height */
|
h: 480, /* Max height */
|
||||||
stretch: false, /* True if you want to stretch */
|
stretch: false, /* True if you want to stretch */
|
||||||
|
@ -189,7 +104,7 @@ Debug.Options.gif = {
|
||||||
var w = this.w;
|
var w = this.w;
|
||||||
var h = this.h;
|
var h = this.h;
|
||||||
if (!this.stretch) {
|
if (!this.stretch) {
|
||||||
var win = Window.height / Window.width;
|
var win = window.height / window.width;
|
||||||
var gif = h/w;
|
var gif = h/w;
|
||||||
if (gif > win)
|
if (gif > win)
|
||||||
h = w * win;
|
h = w * win;
|
||||||
|
@ -197,84 +112,43 @@ Debug.Options.gif = {
|
||||||
w = h / win;
|
w = h / win;
|
||||||
}
|
}
|
||||||
|
|
||||||
cmd(131, w, h, this.cpf, this.depth);
|
// cmd(131, w, h, this.cpf, this.depth);
|
||||||
this.rec = true;
|
this.rec = true;
|
||||||
this.fps = (1/this.cpf)*100;
|
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);
|
timer.oneshot(this.stop.bind(this), this.secs, this, true);
|
||||||
},
|
},
|
||||||
|
|
||||||
stop() {
|
stop() {
|
||||||
if (!this.rec) return;
|
if (!this.rec) return;
|
||||||
cmd(132, this.file);
|
// cmd(132, this.file);
|
||||||
this.rec = false;
|
this.rec = false;
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
Debug.inputs.f8 = function() {
|
debug.inputs.f8 = function() {
|
||||||
var now = new Date();
|
var now = new Date();
|
||||||
Debug.Options.gif.file = now.toISOString() + ".gif";
|
debug.gif.file = now.toISOString() + ".gif";
|
||||||
Debug.Options.gif.start();
|
debug.gif.start();
|
||||||
};
|
};
|
||||||
Debug.inputs.f9 = function() {
|
debug.inputs.f9 = function() {
|
||||||
Debug.Options.gif.stop();
|
debug.gif.stop();
|
||||||
}
|
}
|
||||||
|
|
||||||
Debug.inputs.f10 = function() { Time.timescale = 0.1; };
|
debug.inputs.f10 = function() { time.timescale = 0.1; };
|
||||||
Debug.inputs.f10.doc = "Toggle timescale to 1/10.";
|
debug.inputs.f10.doc = "Toggle timescale to 1/10.";
|
||||||
Debug.inputs.f10.released = function () { Time.timescale = 1.0; };
|
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 = function() { gui.defaults.debug = !gui.defaults.debug; console.warn("gui toggle debug");};
|
||||||
Debug.inputs.f12.doc = "Toggle drawing GUI debugging aids.";
|
debug.inputs.f12.doc = "Toggle drawing gui debugging aids.";
|
||||||
|
|
||||||
Debug.inputs['M-1'] = render.normal;
|
debug.inputs['M-1'] = render.normal;
|
||||||
Debug.inputs['M-2'] = render.wireframe;
|
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.api = {};
|
||||||
Debug.inputs['C-M-f'].doc = "Enter camera fly mode.";
|
debug.api.doc_entry = function(obj, key)
|
||||||
|
|
||||||
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)
|
|
||||||
{
|
{
|
||||||
if (typeof key !== 'string') {
|
if (typeof key !== 'string') {
|
||||||
console.warn("Cannot print a key that isn't a 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;
|
var obj = name;
|
||||||
if (typeof name === 'string') {
|
if (typeof name === 'string') {
|
||||||
|
@ -343,16 +217,24 @@ Debug.api.print_doc = function(name)
|
||||||
if (key === 'doc') continue;
|
if (key === 'doc') continue;
|
||||||
if (key === 'toString') continue;
|
if (key === 'toString') continue;
|
||||||
|
|
||||||
mdoc += Debug.api.doc_entry(obj, key) + "\n";
|
mdoc += debug.api.doc_entry(obj, key) + "\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
return mdoc;
|
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 {
|
return {
|
||||||
Debug,
|
debug,
|
||||||
Time,
|
|
||||||
Gizmos,
|
Gizmos,
|
||||||
performance,
|
|
||||||
assert
|
assert
|
||||||
}
|
}
|
||||||
|
|
|
@ -47,14 +47,14 @@ function ediff(from,to)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (typeof v === 'object') {
|
if (typeof v === 'object' && v !== null) {
|
||||||
var diff = ediff(v, to[key]);
|
var diff = ediff(v, to[key]);
|
||||||
if (diff && !Object.empty(diff))
|
if (diff && !Object.empty(diff))
|
||||||
ret[key] = diff;
|
ret[key] = diff;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (typeof v === 'number') {
|
if (typeof v === 'number' || v === null) {
|
||||||
if (!isFinite(v)) v = null; // Squash infinity to null
|
if (!isFinite(v)) v = null; // Squash infinity to null
|
||||||
if (v !== to[key])
|
if (v !== to[key])
|
||||||
ret[key] = v;
|
ret[key] = v;
|
||||||
|
|
|
@ -3,11 +3,13 @@
|
||||||
selectable
|
selectable
|
||||||
*/
|
*/
|
||||||
|
|
||||||
Window.mode = Window.modetypes.full;
|
game.loadurs();
|
||||||
Game.loadurs();
|
|
||||||
|
|
||||||
player[0].control(Debug);
|
console.info(`window size: ${window.size}, render size: ${window.rendersize}`);
|
||||||
Register.gui.register(Debug.draw, Debug);
|
|
||||||
|
player[0].control(debug);
|
||||||
|
|
||||||
|
var show_frame = true;
|
||||||
|
|
||||||
var editor = {
|
var editor = {
|
||||||
toString() { return "editor"; },
|
toString() { return "editor"; },
|
||||||
|
@ -24,22 +26,19 @@ var editor = {
|
||||||
desktop: undefined, /* The editor desktop, where all editing objects live */
|
desktop: undefined, /* The editor desktop, where all editing objects live */
|
||||||
working_layer: 0,
|
working_layer: 0,
|
||||||
get cursor() {
|
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));
|
return physics.com(this.selectlist.map(x => x.pos));
|
||||||
},
|
},
|
||||||
edit_mode: "basic",
|
edit_mode: "basic",
|
||||||
|
|
||||||
get_this() { return this.edit_level; },
|
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 */
|
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);
|
return this.do_select(go);
|
||||||
},
|
},
|
||||||
|
|
||||||
/* Tries to select id */
|
do_select(obj) { /* select an object, if it is selectable given the current editor state */
|
||||||
do_select(obj) {
|
|
||||||
if (!obj) return;
|
if (!obj) return;
|
||||||
if (!obj._ed.selectable) return undefined;
|
if (!obj._ed.selectable) return undefined;
|
||||||
|
|
||||||
|
@ -84,7 +83,7 @@ var editor = {
|
||||||
return function(go) { go.pos = go.pos.add(amt)};
|
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) {
|
on_grid(pos) {
|
||||||
return pos.every(function(x) { return x % editor.grid_size === 0; });
|
return pos.every(function(x) { return x % editor.grid_size === 0; });
|
||||||
|
@ -99,7 +98,7 @@ var editor = {
|
||||||
|
|
||||||
key_move(dir) {
|
key_move(dir) {
|
||||||
if (!editor.grabselect) return;
|
if (!editor.grabselect) return;
|
||||||
if (Keys.ctrl())
|
if (input.keyboard.down('ctrl'))
|
||||||
this.selectlist.forEach(this.snapper(dir.scale(1.01), editor.grid_size));
|
this.selectlist.forEach(this.snapper(dir.scale(1.01), editor.grid_size));
|
||||||
else
|
else
|
||||||
this.selectlist.forEach(this.mover(dir.scale(this.step_amt())));
|
this.selectlist.forEach(this.mover(dir.scale(this.step_amt())));
|
||||||
|
@ -156,7 +155,7 @@ var editor = {
|
||||||
},
|
},
|
||||||
|
|
||||||
input_num_pressed(num) {
|
input_num_pressed(num) {
|
||||||
if (Keys.ctrl()) {
|
if (input.keyboard.down('ctrl')) {
|
||||||
this.camera_recalls[num] = {
|
this.camera_recalls[num] = {
|
||||||
pos:this.camera.pos,
|
pos:this.camera.pos,
|
||||||
zoom:this.camera.zoom
|
zoom:this.camera.zoom
|
||||||
|
@ -171,8 +170,8 @@ var editor = {
|
||||||
zoom_to_bb(bb) {
|
zoom_to_bb(bb) {
|
||||||
var cwh = bbox.tocwh(bb);
|
var cwh = bbox.tocwh(bb);
|
||||||
|
|
||||||
var xscale = cwh.wh.x / Window.width;
|
var xscale = cwh.wh.x / window.width;
|
||||||
var yscale = cwh.wh.y / Window.height;
|
var yscale = cwh.wh.y / window.height;
|
||||||
|
|
||||||
var zoom = yscale > xscale ? yscale : xscale;
|
var zoom = yscale > xscale ? yscale : xscale;
|
||||||
|
|
||||||
|
@ -191,7 +190,7 @@ var editor = {
|
||||||
this.stash = this.desktop.instance_obj();
|
this.stash = this.desktop.instance_obj();
|
||||||
world.clear();
|
world.clear();
|
||||||
global.mixin("config.js");
|
global.mixin("config.js");
|
||||||
Game.play();
|
sim.play();
|
||||||
player[0].uncontrol(this);
|
player[0].uncontrol(this);
|
||||||
player[0].control(limited_editor);
|
player[0].control(limited_editor);
|
||||||
editor.cbs.forEach(cb => cb());
|
editor.cbs.forEach(cb => cb());
|
||||||
|
@ -206,7 +205,7 @@ var editor = {
|
||||||
start_play() {
|
start_play() {
|
||||||
world.clear();
|
world.clear();
|
||||||
global.mixin("config.js");
|
global.mixin("config.js");
|
||||||
Game.play();
|
sim.play();
|
||||||
player[0].uncontrol(this);
|
player[0].uncontrol(this);
|
||||||
player[0].control(limited_editor);
|
player[0].control(limited_editor);
|
||||||
editor.cbs.forEach(cb=>cb());
|
editor.cbs.forEach(cb=>cb());
|
||||||
|
@ -217,14 +216,14 @@ var editor = {
|
||||||
cbs: [],
|
cbs: [],
|
||||||
|
|
||||||
enter_editor() {
|
enter_editor() {
|
||||||
Game.pause();
|
sim.pause();
|
||||||
player[0].control(this);
|
player[0].control(this);
|
||||||
player[0].uncontrol(limited_editor);
|
player[0].uncontrol(limited_editor);
|
||||||
|
|
||||||
editor.cbs.push(Register.gui.register(editor.gui.bind(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.draw.register(editor.draw.bind(editor)));
|
||||||
editor.cbs.push(Register.debug.register(editor.ed_debug.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();
|
this.desktop = world.spawn();
|
||||||
world.rename_obj(this.desktop.toString(), "desktop");
|
world.rename_obj(this.desktop.toString(), "desktop");
|
||||||
|
@ -237,11 +236,7 @@ var editor = {
|
||||||
this.selectlist = [];
|
this.selectlist = [];
|
||||||
editor.camera = world.spawn("scripts/camera2d.jso");
|
editor.camera = world.spawn("scripts/camera2d.jso");
|
||||||
editor.camera._ed.selectable = false;
|
editor.camera._ed.selectable = false;
|
||||||
Game.view_camera(editor.camera);
|
game.camera = editor.camera;
|
||||||
},
|
|
||||||
|
|
||||||
end_debug() {
|
|
||||||
|
|
||||||
},
|
},
|
||||||
|
|
||||||
openpanel(panel) {
|
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) return;
|
||||||
if (!obj.objects) return;
|
if (!obj.objects) return;
|
||||||
depth ??= 0;
|
|
||||||
root = root ? root + "." : root;
|
root = root ? root + "." : root;
|
||||||
Object.entries(obj.objects).forEach(function(x) {
|
Object.entries(obj.objects).forEach(function(x) {
|
||||||
var p = root + x[0];
|
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);
|
editor.draw_objects_names(x[1], p, depth+1);
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
@ -362,10 +356,8 @@ var editor = {
|
||||||
|
|
||||||
this._sel_comp = x;
|
this._sel_comp = x;
|
||||||
|
|
||||||
if (this._sel_comp) {
|
if (this._sel_comp)
|
||||||
console.info("sel comp is now " + this._sel_comp);
|
|
||||||
player[0].control(this._sel_comp);
|
player[0].control(this._sel_comp);
|
||||||
}
|
|
||||||
},
|
},
|
||||||
|
|
||||||
time: 0,
|
time: 0,
|
||||||
|
@ -377,11 +369,11 @@ var editor = {
|
||||||
x.gizmo();
|
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 */
|
/* Draw selection box */
|
||||||
if (this.sel_start) {
|
if (this.sel_start) {
|
||||||
var endpos = Mouse.worldpos();
|
var endpos = input.mouse.worldpos();
|
||||||
var c = [];
|
var c = [];
|
||||||
c[0] = (endpos[0] - this.sel_start[0]) / 2;
|
c[0] = (endpos[0] - this.sel_start[0]) / 2;
|
||||||
c[0] += this.sel_start[0];
|
c[0] += this.sel_start[0];
|
||||||
|
@ -391,21 +383,23 @@ var editor = {
|
||||||
wh[0] = Math.abs(endpos[0] - this.sel_start[0]);
|
wh[0] = Math.abs(endpos[0] - this.sel_start[0]);
|
||||||
wh[1] = Math.abs(endpos[1] - this.sel_start[1]);
|
wh[1] = Math.abs(endpos[1] - this.sel_start[1]);
|
||||||
var bb = bbox.fromcwh(c,wh);
|
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);
|
render.line(bbox.topoints(bb).wrapped(1), Color.white);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
gui() {
|
gui() {
|
||||||
/* Clean out killed objects */
|
/* Clean out killed objects */
|
||||||
this.selectlist = this.selectlist.filter(function(x) { return x.alive; });
|
if (show_frame)
|
||||||
GUI.text([0,0], Window.world2screen([0,0]));
|
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]);
|
render.text([0,0], game.camera.world2view([0,0]));
|
||||||
GUI.text("MODE: " + this.edit_mode, [0,500]);
|
|
||||||
|
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)
|
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);
|
render.cross(editor.edit_level.screenpos(),3,Color.blue);
|
||||||
|
|
||||||
|
@ -428,9 +422,11 @@ var editor = {
|
||||||
var depth = 0;
|
var depth = 0;
|
||||||
var alldirty = false;
|
var alldirty = false;
|
||||||
for (var lvl of lvlchain) {
|
for (var lvl of lvlchain) {
|
||||||
|
if (!lvl._ed?.selectable) continue;
|
||||||
if (alldirty)
|
if (alldirty)
|
||||||
lvl._ed.dirty = true;
|
lvl._ed.dirty = true;
|
||||||
else {
|
else {
|
||||||
|
if (!lvl._ed) continue;
|
||||||
lvl.check_dirty();
|
lvl.check_dirty();
|
||||||
if (lvl._ed.dirty) alldirty = true;
|
if (lvl._ed.dirty) alldirty = true;
|
||||||
}
|
}
|
||||||
|
@ -440,43 +436,44 @@ var editor = {
|
||||||
depth = i;
|
depth = i;
|
||||||
var lvlstr = x.namestr();
|
var lvlstr = x.namestr();
|
||||||
if (i === lvlchain.length-1) lvlstr += "[this]";
|
if (i === lvlchain.length-1) lvlstr += "[this]";
|
||||||
GUI.text(lvlstr, [0, ypos], 1, editor.color_depths[depth]);
|
render.text(lvlstr, [0, ypos], 1, editor.color_depths[depth]);
|
||||||
|
ypos += render.font.linegap;
|
||||||
GUI.text("^^^^^^", [0,ypos+=5],1);
|
render.text("^^^^^^", [0,ypos],1);
|
||||||
ypos += 15;
|
ypos += render.font.linegap;
|
||||||
});
|
});
|
||||||
|
|
||||||
depth++;
|
depth++;
|
||||||
GUI.text("$$$$$$", [0,ypos],1,editor.color_depths[depth]);
|
render.text("$$$$$$", [0,ypos],1,editor.color_depths[depth]);
|
||||||
|
|
||||||
this.selectlist.forEach(function(x) {
|
this.selectlist.forEach(function(x) {
|
||||||
GUI.text(x.urstr(), x.screenpos().add([0, 32]), 1, Color.editor.ur);
|
render.text(x.urstr(), x.screenpos().add([0, render.font.linegap*2]), 1, Color.editor.ur);
|
||||||
GUI.text(x.worldpos().map(function(x) { return Math.round(x); }), x.screenpos(), 1, Color.white);
|
render.text(x.pos.map(function(x) { return Math.round(x); }), x.screenpos());
|
||||||
render.cross(x.screenpos(), 10, Color.blue);
|
render.cross(x.screenpos(), 10, Color.blue);
|
||||||
});
|
});
|
||||||
|
|
||||||
Object.entries(thiso.objects).forEach(function(x) {
|
Object.entries(thiso.objects).forEach(function(x) {
|
||||||
var p = x[1].namestr();
|
var p = x[1].namestr();
|
||||||
GUI.text(p, x[1].screenpos().add([0,16]),1,editor.color_depths[depth]);
|
render.text(p, x[1].screenpos().add([0,render.font.linegap]),1,editor.color_depths[depth]);
|
||||||
render.circle(x[1].screenpos(),10,Color.blue.alpha(0.3));
|
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);
|
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)
|
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) {
|
if (this.selectlist.length === 1) {
|
||||||
var i = 1;
|
var i = 1;
|
||||||
for (var key in this.selectlist[0].components) {
|
for (var key in this.selectlist[0].components) {
|
||||||
var selected = this.sel_comp === this.selectlist[0].components[key];
|
var selected = this.sel_comp === this.selectlist[0].components[key];
|
||||||
var str = (selected ? ">" : " ") + key + " [" + this.selectlist[0].components[key].toString() + "]";
|
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) {
|
if (this.sel_comp) {
|
||||||
|
@ -486,26 +483,26 @@ var editor = {
|
||||||
|
|
||||||
editor.edit_level.objects.forEach(function(obj) {
|
editor.edit_level.objects.forEach(function(obj) {
|
||||||
if (!obj._ed.selectable)
|
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));
|
render.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 startgrid = game.camera.view2world([-20,0]).map(function(x) { return Math.snap(x, editor.grid_size); });
|
||||||
var endgrid = Window.screen2world([Window.width, Window.height]);
|
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;
|
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;
|
if (h_step === 0) h_step = editor.grid_size;
|
||||||
|
|
||||||
while(startgrid[0] <= endgrid[0]) {
|
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;
|
startgrid[0] += w_step;
|
||||||
}
|
}
|
||||||
|
|
||||||
while(startgrid[1] <= endgrid[1]) {
|
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;
|
startgrid[1] += h_step;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -518,8 +515,8 @@ var editor = {
|
||||||
},
|
},
|
||||||
|
|
||||||
ed_debug() {
|
ed_debug() {
|
||||||
if (!Debug.phys_drawing)
|
if (!debug.phys_drawing)
|
||||||
this.selectlist.forEach(function(x) { Debug.draw_obj_phys(x); });
|
this.selectlist.forEach(function(x) { debug.draw_obj_phys(x); });
|
||||||
},
|
},
|
||||||
|
|
||||||
killring: [],
|
killring: [],
|
||||||
|
@ -528,8 +525,10 @@ var editor = {
|
||||||
lvl_history: [],
|
lvl_history: [],
|
||||||
|
|
||||||
load(urstr) {
|
load(urstr) {
|
||||||
var obj = editor.edit_level.spawn(urstr);
|
var mur = ur[urstr];
|
||||||
obj.set_worldpos(Mouse.worldpos());
|
if (!mur) return;
|
||||||
|
var obj = editor.edit_level.spawn(mur);
|
||||||
|
obj.set_pos(input.mouse.worldpos());
|
||||||
this.selectlist = [obj];
|
this.selectlist = [obj];
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -567,7 +566,7 @@ var editor = {
|
||||||
ur[sub] = {
|
ur[sub] = {
|
||||||
name: sub,
|
name: sub,
|
||||||
data: file,
|
data: file,
|
||||||
proto: json.decode(json.encode(obj))
|
fresh: json.decode(json.encode(obj))
|
||||||
}
|
}
|
||||||
obj.ur = sub;
|
obj.ur = sub;
|
||||||
|
|
||||||
|
@ -610,7 +609,7 @@ var editor = {
|
||||||
editor.new_object = function()
|
editor.new_object = function()
|
||||||
{
|
{
|
||||||
var obj = editor.edit_level.spawn();
|
var obj = editor.edit_level.spawn();
|
||||||
obj.set_worldpos(Mouse.worldpos());
|
obj.set_pos(input.mouse.worldpos());
|
||||||
this.selectlist = [obj];
|
this.selectlist = [obj];
|
||||||
return obj;
|
return obj;
|
||||||
}
|
}
|
||||||
|
@ -638,7 +637,7 @@ editor.inputs['C-b'] = function() {
|
||||||
c.grow(obj.scale);
|
c.grow(obj.scale);
|
||||||
c.sync?.();
|
c.sync?.();
|
||||||
});
|
});
|
||||||
obj.scale = [1,1,1];
|
obj.set_scale([1,1,1]);
|
||||||
}
|
}
|
||||||
|
|
||||||
editor.inputs.drop = function(str) {
|
editor.inputs.drop = function(str) {
|
||||||
|
@ -656,24 +655,22 @@ editor.inputs.drop = function(str) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var mg = physics.pos_query(Mouse.worldpos(),10);
|
var mg = physics.pos_query(input.mouse.worldpos());
|
||||||
if (!mg) return;
|
if (!mg) return;
|
||||||
var img = mg.get_comp_by_name('sprite');
|
var img = mg.get_comp_by_name('sprite');
|
||||||
if (!img) return;
|
if (!img) return;
|
||||||
img[0].path = str;
|
img[0].path = str;
|
||||||
}
|
}
|
||||||
|
|
||||||
editor.inputs.f9 = function() {
|
editor.inputs.f9 = function() { os.capture( "capture.bmp", 0, 0, 500, 500); }
|
||||||
console.warn("CAPTURING");
|
|
||||||
cmd(173, "capture.bmp", 0, 0, 500, 500);
|
|
||||||
}
|
|
||||||
|
|
||||||
editor.inputs.release_post = function() {
|
editor.inputs.release_post = function() {
|
||||||
editor.snapshot();
|
editor.snapshot();
|
||||||
editor.edit_level.check_dirty();
|
|
||||||
|
editor.selectlist?.forEach(x => x.check_dirty());
|
||||||
|
|
||||||
/* snap all objects to be pixel perfect */
|
/* 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() {
|
editor.inputs['C-a'] = function() {
|
||||||
if (!Object.empty(editor.selectlist)) { editor.unselect(); return; }
|
if (!Object.empty(editor.selectlist)) { editor.unselect(); return; }
|
||||||
|
@ -692,9 +689,9 @@ editor.inputs.n = function() {
|
||||||
if (o === editor.selectlist[0]) return;
|
if (o === editor.selectlist[0]) return;
|
||||||
if (o.master !== editor.selectlist[0].master) 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;
|
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.n.doc = "Set the hovered object's position to mirror the selected object's position on the X axis."
|
||||||
editor.inputs['M-n'] = function()
|
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-d'].doc = "Duplicate all selected objects.";
|
||||||
|
|
||||||
|
|
||||||
editor.inputs['C-m'] = function() {
|
editor.inputs['C-m'] = function() {
|
||||||
if (editor.sel_comp) {
|
if (editor.sel_comp) {
|
||||||
if ('flipy' in editor.sel_comp)
|
if ('flipy' in editor.sel_comp)
|
||||||
|
@ -764,15 +760,15 @@ editor.inputs.m = function() {
|
||||||
return;
|
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.m.doc = "Mirror selected objects on the X axis.";
|
||||||
|
|
||||||
|
|
||||||
editor.inputs.q = function() { editor.comp_info = !editor.comp_info; };
|
editor.inputs.q = function() { editor.comp_info = !editor.comp_info; };
|
||||||
editor.inputs.q.doc = "Toggle help for the selected component.";
|
editor.inputs.q.doc = "Toggle help for the selected component.";
|
||||||
|
|
||||||
editor.inputs.f = function() {
|
editor.inputs.f = function() {
|
||||||
|
return;
|
||||||
if (editor.selectlist.length === 0) return;
|
if (editor.selectlist.length === 0) return;
|
||||||
var bb = editor.selectlist[0].boundingbox();
|
var bb = editor.selectlist[0].boundingbox();
|
||||||
editor.selectlist.forEach(function(obj) { bb = bbox.expand(bb, obj.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'].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;
|
if (editor.edit_level.master === world) return;
|
||||||
|
|
||||||
editor.edit_level = editor.edit_level.master;
|
editor.edit_level = editor.edit_level.master;
|
||||||
editor.unselect();
|
editor.unselect();
|
||||||
editor.reset_undos();
|
editor.reset_undos();
|
||||||
};
|
};
|
||||||
editor.inputs['C-F'].doc = "Tunnel out of the level you are editing, saving it in the process.";
|
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'] = function() { editor.selectlist.forEach(function(x) { x.angle = -x.angle; }); };
|
|
||||||
editor.inputs['C-r'].doc = "Negate the selected's angle.";
|
editor.inputs['C-r'].doc = "Negate the selected's angle.";
|
||||||
|
|
||||||
editor.inputs.r = function() {
|
editor.inputs.r = function() {
|
||||||
if (editor.sel_comp && 'angle' in editor.sel_comp) {
|
if (editor.sel_comp && 'angle' in editor.sel_comp) {
|
||||||
var relpos = Mouse.worldpos().sub(editor.sel_comp.gameobject.worldpos());
|
var relpos = input.mouse.worldpos().sub(editor.sel_comp.gameobject.pos);
|
||||||
editor.startoffset = Math.atan2(relpos.y, relpos.x);
|
|
||||||
editor.startrot = editor.sel_comp.angle;
|
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
editor.rotlist = [];
|
editor.rotlist = editor.selectlist;
|
||||||
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.inputs.r.doc = "Rotate selected using the mouse while held down.";
|
editor.inputs.r.doc = "Rotate selected using the mouse while held down.";
|
||||||
editor.inputs.r.released = function() { editor.rotlist = []; }
|
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.f6.doc = "Start game as if the player started it.";
|
||||||
|
|
||||||
editor.inputs['M-p'] = function() {
|
editor.inputs['M-p'] = function() {
|
||||||
if (Game.playing())
|
if (sim.playing())
|
||||||
Game.pause();
|
sim.pause();
|
||||||
|
|
||||||
Game.step();
|
sim.step();
|
||||||
}
|
}
|
||||||
editor.inputs['M-p'].doc = "Do one time step, pausing if necessary.";
|
editor.inputs['M-p'].doc = "Do one time step, pausing if necessary.";
|
||||||
|
|
||||||
editor.inputs['C-M-p'] = function() {
|
editor.inputs['C-M-p'] = function() {
|
||||||
if (!Game.playing()) {
|
if (!sim.playing()) {
|
||||||
editor.start_play_ed();
|
editor.start_play_ed();
|
||||||
}
|
}
|
||||||
console.warn(`Starting edited level ...`);
|
console.warn(`Starting edited level ...`);
|
||||||
|
@ -904,21 +886,20 @@ editor.inputs['C-s'] = function() {
|
||||||
if (!tur.data) {
|
if (!tur.data) {
|
||||||
io.slurpwrite(tur.text.set_ext(".json"), json.encode(savejs,null,1));
|
io.slurpwrite(tur.text.set_ext(".json"), json.encode(savejs,null,1));
|
||||||
tur.data = tur.text.set_ext(".json");
|
tur.data = tur.text.set_ext(".json");
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
var oldjs = json.decode(io.slurp(tur.data));
|
var oldjs = json.decode(io.slurp(tur.data));
|
||||||
Object.merge(oldjs, savejs);
|
Object.merge(oldjs, savejs);
|
||||||
io.slurpwrite(tur.data, json.encode(oldjs,null,1));
|
io.slurpwrite(tur.data, json.encode(oldjs,null,1));
|
||||||
}
|
}
|
||||||
|
|
||||||
Object.merge(tur.proto, savejs);
|
Object.merge(tur.fresh, savejs);
|
||||||
saveobj.check_dirty();
|
saveobj.check_dirty();
|
||||||
|
|
||||||
// Object.values(saveobj.objects).forEach(function(x) { x.check_dirty(); });
|
// Object.values(saveobj.objects).forEach(function(x) { x.check_dirty(); });
|
||||||
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
Game.all_objects(function(x) {
|
game.all_objects(function(x) {
|
||||||
if (typeof x !== 'object') return;
|
if (typeof x !== 'object') return;
|
||||||
if (!('_ed' in x)) return;
|
if (!('_ed' in x)) return;
|
||||||
if (x._ed.dirty) 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-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'] = function() { editor.programmode = !editor.programmode; };
|
||||||
editor.inputs['M-y'].doc = "Toggle program mode.";
|
editor.inputs['M-y'].doc = "Toggle program mode.";
|
||||||
|
|
||||||
|
@ -1025,11 +1010,11 @@ editor.inputs.f3 = function() {
|
||||||
this.openpanel(componentexplorer);
|
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.doc = "Selection box.";
|
||||||
|
|
||||||
editor.inputs.lm.released = function() {
|
editor.inputs.lm.released = function() {
|
||||||
Mouse.normal();
|
input.mouse.normal();
|
||||||
editor.unselect();
|
editor.unselect();
|
||||||
|
|
||||||
if (!editor.sel_start) return;
|
if (!editor.sel_start) return;
|
||||||
|
@ -1042,18 +1027,15 @@ editor.inputs.lm.released = function() {
|
||||||
var selects = [];
|
var selects = [];
|
||||||
|
|
||||||
/* TODO: selects somehow gets undefined objects in here */
|
/* 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();
|
var sel = editor.try_select();
|
||||||
if (sel) selects.push(sel);
|
if (sel) selects.push(sel);
|
||||||
} else {
|
} 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));
|
physics.box_query(bbox.tocwh(box), function(entity) {
|
||||||
|
var obj = editor.do_select(entity);
|
||||||
hits.forEach(function(x, i) {
|
if (obj) selects.push(obj);
|
||||||
var obj = editor.do_select(x);
|
|
||||||
if (obj)
|
|
||||||
selects.push(obj);
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1063,7 +1045,7 @@ editor.inputs.lm.released = function() {
|
||||||
|
|
||||||
if (Object.empty(selects)) return;
|
if (Object.empty(selects)) return;
|
||||||
|
|
||||||
if (Keys.shift()) {
|
if (input.keyboard.down('shift')) {
|
||||||
selects.forEach(function(x) {
|
selects.forEach(function(x) {
|
||||||
this.selectlist.push_unique(x);
|
this.selectlist.push_unique(x);
|
||||||
}, this);
|
}, this);
|
||||||
|
@ -1071,7 +1053,7 @@ editor.inputs.lm.released = function() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Keys.ctrl()) {
|
if (input.keyboard.down('ctrl')) {
|
||||||
selects.forEach(function(x) {
|
selects.forEach(function(x) {
|
||||||
delete this.selectlist[x.toString()];
|
delete this.selectlist[x.toString()];
|
||||||
}, this);
|
}, this);
|
||||||
|
@ -1103,7 +1085,7 @@ editor.try_pick = function()
|
||||||
editor.grabselect = [];
|
editor.grabselect = [];
|
||||||
|
|
||||||
if (editor.sel_comp && 'pick' in editor.sel_comp)
|
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();
|
return editor.try_select();
|
||||||
}
|
}
|
||||||
|
@ -1111,7 +1093,7 @@ editor.try_pick = function()
|
||||||
editor.inputs.mm = function() {
|
editor.inputs.mm = function() {
|
||||||
if (editor.brush_obj) {
|
if (editor.brush_obj) {
|
||||||
editor.selectlist = editor.dup_objects([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];
|
editor.grabselect = editor.selectlist[0];
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -1125,30 +1107,30 @@ editor.inputs['C-mm'] = editor.inputs.mm;
|
||||||
|
|
||||||
editor.inputs['C-M-lm'] = function()
|
editor.inputs['C-M-lm'] = function()
|
||||||
{
|
{
|
||||||
var go = physics.pos_query(Mouse.worldpos());
|
var go = physics.pos_query(input.mouse.worldpos());
|
||||||
if (!go) return;
|
if (!go) return;
|
||||||
editor.edit_level = go.master;
|
editor.edit_level = go.master;
|
||||||
}
|
}
|
||||||
|
|
||||||
editor.inputs['C-M-mm'] = function() {
|
editor.inputs['C-M-mm'] = function() {
|
||||||
editor.mousejoy = Mouse.screenpos();
|
editor.mousejoy = input.mouse.screenpos();
|
||||||
editor.joystart = editor.camera.pos;
|
editor.joystart = editor.camera.pos;
|
||||||
};
|
};
|
||||||
|
|
||||||
editor.inputs['C-M-rm'] = function() {
|
editor.inputs['C-M-rm'] = function() {
|
||||||
editor.mousejoy = Mouse.screenpos();
|
editor.mousejoy = input.mouse.screenpos();
|
||||||
editor.z_start = editor.camera.zoom;
|
editor.z_start = editor.camera.zoom;
|
||||||
Mouse.disabled();
|
input.mouse.disabled();
|
||||||
};
|
};
|
||||||
|
|
||||||
editor.inputs.rm.released = function() {
|
editor.inputs.rm.released = function() {
|
||||||
editor.mousejoy = undefined;
|
editor.mousejoy = undefined;
|
||||||
editor.z_start = undefined;
|
editor.z_start = undefined;
|
||||||
Mouse.normal();
|
input.mouse.normal();
|
||||||
};
|
};
|
||||||
|
|
||||||
editor.inputs.mm.released = function () {
|
editor.inputs.mm.released = function () {
|
||||||
Mouse.normal();
|
input.mouse.normal();
|
||||||
this.grabselect = [];
|
this.grabselect = [];
|
||||||
editor.mousejoy = undefined;
|
editor.mousejoy = undefined;
|
||||||
editor.joystart = undefined;
|
editor.joystart = undefined;
|
||||||
|
@ -1160,43 +1142,36 @@ editor.inputs.mouse.move = function(pos, dpos)
|
||||||
if (editor.z_start)
|
if (editor.z_start)
|
||||||
editor.camera.zoom -= dpos.y/500;
|
editor.camera.zoom -= dpos.y/500;
|
||||||
else if (editor.joystart)
|
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) {
|
editor.grabselect?.forEach(function(x) {
|
||||||
if (!x) return;
|
x.move(game.camera.dir_view2world(dpos));
|
||||||
x.move(Game.camera.dir_view2world(dpos));
|
|
||||||
x.sync();
|
x.sync();
|
||||||
});
|
});
|
||||||
|
|
||||||
var relpos = Mouse.worldpos().sub(editor.cursor);
|
var relpos = input.mouse.worldpos().sub(editor.cursor);
|
||||||
var dist = Vector.length(relpos);
|
var lastpos = relpos.sub(dpos);
|
||||||
|
|
||||||
editor.scalelist?.forEach(function(x) {
|
var dist = Vector.length(relpos.add(dpos)) - Vector.length(relpos);
|
||||||
var scalediff = dist / x.scaleoffset;
|
var scalediff = 1+(dist/editor.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));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
|
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) {
|
editor.rotlist?.forEach(function(x) {
|
||||||
var anglediff = Math.atan2(relpos.y, relpos.x) - x.rotoffset;
|
x.rotate(anglediff/(2*Math.PI));
|
||||||
x.obj.angle = x.angle + Math.rad2turn(anglediff);
|
if (input.keyboard.down('shift')) {
|
||||||
if (Keys.shift())
|
var rotate = Math.nearest(x.angle, 1/24) - x.angle;
|
||||||
x.obj.angle = Math.nearest(x.obj.angle, (1/24));
|
x.rotate(rotate)
|
||||||
if (x.pos)
|
}
|
||||||
x.obj.pos = x.pos.sub(x.offset).add(x.offset.rotate(anglediff));
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
editor.inputs.mouse.scroll = function(scroll)
|
editor.inputs.mouse.scroll = function(scroll)
|
||||||
{
|
{
|
||||||
scroll.y *= -1;
|
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)
|
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.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['C-M-S-lm'].doc = "Set world center to mouse position.";
|
||||||
|
|
||||||
editor.inputs.delete = function() {
|
editor.inputs.delete = function() {
|
||||||
|
@ -1215,11 +1190,7 @@ editor.inputs.delete.doc = "Delete selected objects.";
|
||||||
editor.inputs['S-d'] = editor.inputs.delete;
|
editor.inputs['S-d'] = editor.inputs.delete;
|
||||||
editor.inputs['C-k'] = editor.inputs.delete;
|
editor.inputs['C-k'] = editor.inputs.delete;
|
||||||
|
|
||||||
editor.inputs['C-u'] = function() {
|
editor.inputs['C-u'] = function() { this.selectlist.forEach(x => x.revert()); };
|
||||||
this.selectlist.forEach(function(x) {
|
|
||||||
x.revert();
|
|
||||||
});
|
|
||||||
};
|
|
||||||
editor.inputs['C-u'].doc = "Revert selected objects back to their prefab form.";
|
editor.inputs['C-u'].doc = "Revert selected objects back to their prefab form.";
|
||||||
|
|
||||||
editor.inputs['M-u'] = function() {
|
editor.inputs['M-u'] = function() {
|
||||||
|
@ -1241,7 +1212,7 @@ editor.inputs.g = function() {
|
||||||
|
|
||||||
if (editor.sel_comp) {
|
if (editor.sel_comp) {
|
||||||
if ('pick' in 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;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1258,7 +1229,7 @@ editor.inputs.g = function() {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (editor.sel_comp && 'pick' in editor.sel_comp) {
|
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];
|
if (o) editor.grabselect = [o];
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -1267,7 +1238,7 @@ editor.inputs.g = function() {
|
||||||
};
|
};
|
||||||
|
|
||||||
editor.inputs.g.doc = "Move selected objects.";
|
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 = function() { this.key_move([0,1]); };
|
||||||
editor.inputs.up.rep = true;
|
editor.inputs.up.rep = true;
|
||||||
|
@ -1314,13 +1285,13 @@ editor.inputs['M-g'] = function()
|
||||||
editor.inputs['M-g'].doc = "Move all.";
|
editor.inputs['M-g'].doc = "Move all.";
|
||||||
|
|
||||||
editor.inputs['C-lb'] = function() {
|
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;
|
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'].doc = "Decrease grid size. Hold shift to decrease it more.";
|
||||||
editor.inputs['C-lb'].rep = true;
|
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'].doc = "Increase grid size. Hold shift to increase it more.";
|
||||||
editor.inputs['C-rb'].rep = true;
|
editor.inputs['C-rb'].rep = true;
|
||||||
|
|
||||||
|
@ -1385,27 +1356,16 @@ compmode.inputs['C-x'] = function() {};
|
||||||
|
|
||||||
editor.scalelist = [];
|
editor.scalelist = [];
|
||||||
editor.inputs.s = function() {
|
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 = [];
|
editor.scalelist = [];
|
||||||
|
|
||||||
if (editor.sel_comp) {
|
if (editor.sel_comp) {
|
||||||
if (!('scale' in editor.sel_comp)) return;
|
if (!('scale' in editor.sel_comp)) return;
|
||||||
editor.scalelist.push({
|
editor.scalelist.push(editor.sel_comp);
|
||||||
obj: editor.sel_comp,
|
|
||||||
scale: editor.sel_comp.scale,
|
|
||||||
scaleoffset: scaleoffset,
|
|
||||||
});
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
editor.selectlist.forEach(function(x) {
|
editor.scalelist = editor.selectlist;
|
||||||
editor.scalelist.push({
|
|
||||||
obj: x,
|
|
||||||
scale: x.scale,
|
|
||||||
offset: x.pos.sub(editor.cursor),
|
|
||||||
scaleoffset: scaleoffset,
|
|
||||||
});
|
|
||||||
});
|
|
||||||
};
|
};
|
||||||
editor.inputs.s.doc = "Scale selected.";
|
editor.inputs.s.doc = "Scale selected.";
|
||||||
|
|
||||||
|
@ -1416,7 +1376,7 @@ var inputpanel = {
|
||||||
toString() { return this.title; },
|
toString() { return this.title; },
|
||||||
value: "",
|
value: "",
|
||||||
on: false,
|
on: false,
|
||||||
pos:[100,Window.height-50],
|
pos:[100,window.size.y-50],
|
||||||
wh:[350,600],
|
wh:[350,600],
|
||||||
anchor: [0,1],
|
anchor: [0,1],
|
||||||
padding:[5,-15],
|
padding:[5,-15],
|
||||||
|
@ -1427,14 +1387,12 @@ var inputpanel = {
|
||||||
if (!Array.isArray(itms)) itms = [itms];
|
if (!Array.isArray(itms)) itms = [itms];
|
||||||
if (this.title)
|
if (this.title)
|
||||||
this.win.items = [
|
this.win.items = [
|
||||||
Mum.column({items: [
|
Mum.column({items: [Mum.text({str:this.title}), ...itms ]})
|
||||||
Mum.text({str:this.title}),
|
|
||||||
...itms
|
|
||||||
]})
|
|
||||||
];
|
];
|
||||||
else
|
else
|
||||||
this.win.items = itms;
|
this.win.items = itms;
|
||||||
this.win.draw(this.pos.slice());
|
|
||||||
|
this.win.draw([100, window.size.y-50]);
|
||||||
},
|
},
|
||||||
|
|
||||||
guibody() {
|
guibody() {
|
||||||
|
@ -1490,11 +1448,9 @@ var inputpanel = {
|
||||||
};
|
};
|
||||||
|
|
||||||
inputpanel.inputs = {};
|
inputpanel.inputs = {};
|
||||||
|
inputpanel.inputs.block = true;
|
||||||
|
|
||||||
inputpanel.inputs.post = function()
|
inputpanel.inputs.post = function() { this.keycb(); }
|
||||||
{
|
|
||||||
this.keycb();
|
|
||||||
}
|
|
||||||
|
|
||||||
inputpanel.inputs.char = function(c) {
|
inputpanel.inputs.char = function(c) {
|
||||||
this.value = this.value.slice(0,this.caret) + c + this.value.slice(this.caret);
|
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);
|
this.value = this.value.slice(0,this.caret);
|
||||||
};
|
};
|
||||||
|
|
||||||
inputpanel.inputs.lm = function()
|
inputpanel.inputs.lm = function() { gui.controls.check_submit(); }
|
||||||
{
|
|
||||||
GUI.controls.check_submit();
|
|
||||||
}
|
|
||||||
|
|
||||||
//load("scripts/textedit.js");
|
|
||||||
|
|
||||||
var replpanel = Object.copy(inputpanel, {
|
var replpanel = Object.copy(inputpanel, {
|
||||||
title: "",
|
title: "",
|
||||||
closeonsubmit:false,
|
closeonsubmit:false,
|
||||||
wh: [700,300],
|
wh: [700,300],
|
||||||
pos: [50,50],
|
pos: [50,50],
|
||||||
anchor: [0,0],
|
anchor: [0,1],
|
||||||
padding: [0,0],
|
padding: [0,0],
|
||||||
scrolloffset: [0,0],
|
scrolloffset: [0,0],
|
||||||
|
|
||||||
guibody() {
|
guibody() {
|
||||||
this.win.selectable = true;
|
this.win.selectable = true;
|
||||||
//var log = cmd(84);
|
var log = console.transcript;
|
||||||
log = log.slice(-5000);
|
|
||||||
return [
|
return [
|
||||||
Mum.text({str:log, anchor:[0,0], offset:[0,-300].sub(this.scrolloffset), selectable: true}),
|
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})
|
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;
|
this.caret = 0;
|
||||||
var ret = function() {return eval(ecode);}.call(repl_obj);
|
var ret = function() {return eval(ecode);}.call(repl_obj);
|
||||||
if (typeof ret === 'object') ret = json.encode(ret,null,1);
|
if (typeof ret === 'object') ret = json.encode(ret,null,1);
|
||||||
say(ret);
|
if (typeof ret !== 'undefined') say(ret);
|
||||||
},
|
},
|
||||||
|
|
||||||
resetscroll() {
|
resetscroll() {
|
||||||
|
@ -1592,7 +1542,7 @@ replpanel.inputs = Object.create(inputpanel.inputs);
|
||||||
replpanel.inputs.block = true;
|
replpanel.inputs.block = true;
|
||||||
replpanel.inputs.lm = function()
|
replpanel.inputs.lm = function()
|
||||||
{
|
{
|
||||||
var mg = physics.pos_query(Mouse.worldpos());
|
var mg = physics.pos_query(input.mouse.worldpos());
|
||||||
if (!mg) return;
|
if (!mg) return;
|
||||||
var p = mg.path_from(editor.get_this());
|
var p = mg.path_from(editor.get_this());
|
||||||
this.value = p;
|
this.value = p;
|
||||||
|
@ -1779,16 +1729,8 @@ var objectexplorer = Object.copy(inputpanel, {
|
||||||
switch (typeof val) {
|
switch (typeof val) {
|
||||||
case 'object':
|
case 'object':
|
||||||
if (val) {
|
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:name}));
|
||||||
items.push(Mum.text({str:val.toString(), action: this.goto_obj.bind(val)}));
|
items.push(Mum.text({str:val.toString(), action: this.goto_obj.bind(val)}));
|
||||||
} else {
|
|
||||||
// this.obj[key] = Nuke.pprop(key,val);
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -1798,28 +1740,13 @@ var objectexplorer = Object.copy(inputpanel, {
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
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:name}));
|
||||||
items.push(Mum.text({str:val.toString()}));
|
items.push(Mum.text({str:val.toString()}));
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
items.push(Mum.text({str:"Properties that can be pulled in ..."}));
|
items.push(Mum.text({str:"Properties that can be pulled in ..."}));
|
||||||
// Nuke.newline(3);
|
|
||||||
var pullprops = [];
|
var pullprops = [];
|
||||||
for (var key in this.obj.__proto__) {
|
for (var key in this.obj.__proto__) {
|
||||||
if (!this.obj.hasOwn(key)) {
|
if (!this.obj.hasOwn(key)) {
|
||||||
|
@ -1832,25 +1759,10 @@ var objectexplorer = Object.copy(inputpanel, {
|
||||||
|
|
||||||
pullprops.forEach(function(key) {
|
pullprops.forEach(function(key) {
|
||||||
items.push(Mum.text({str:key}));
|
items.push(Mum.text({str:key}));
|
||||||
// this.obj[key] = this.obj[key];
|
|
||||||
});
|
});
|
||||||
|
|
||||||
return items;
|
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, {
|
var openlevelpanel = Object.copy(inputpanel, {
|
||||||
|
@ -1928,9 +1840,7 @@ var groupsaveaspanel = Object.copy(inputpanel, {
|
||||||
|
|
||||||
var quitpanel = Object.copy(inputpanel, {
|
var quitpanel = Object.copy(inputpanel, {
|
||||||
title: "really quit?",
|
title: "really quit?",
|
||||||
action() {
|
action() { os.quit(); },
|
||||||
Game.quit();
|
|
||||||
},
|
|
||||||
|
|
||||||
guibody () {
|
guibody () {
|
||||||
return Mum.text({str: "Really quit?"});
|
return Mum.text({str: "Really quit?"});
|
||||||
|
@ -2016,19 +1926,6 @@ function tab_complete(val, list) {
|
||||||
return ret ? ret : val;
|
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, {
|
var entitylistpanel = Object.copy(inputpanel, {
|
||||||
title: "Level object list",
|
title: "Level object list",
|
||||||
level: {},
|
level: {},
|
||||||
|
@ -2043,16 +1940,16 @@ limited_editor.inputs = {};
|
||||||
|
|
||||||
limited_editor.inputs['C-p'] = function()
|
limited_editor.inputs['C-p'] = function()
|
||||||
{
|
{
|
||||||
if (Game.playing())
|
if (sim.playing())
|
||||||
Game.pause();
|
sim.pause();
|
||||||
else
|
else
|
||||||
Game.play();
|
sim.play();
|
||||||
}
|
}
|
||||||
|
|
||||||
limited_editor.inputs['M-p'] = function()
|
limited_editor.inputs['M-p'] = function()
|
||||||
{
|
{
|
||||||
Game.pause();
|
sim.pause();
|
||||||
Game.step();
|
sim.step();
|
||||||
}
|
}
|
||||||
|
|
||||||
limited_editor.inputs['C-q'] = function()
|
limited_editor.inputs['C-q'] = function()
|
||||||
|
@ -2068,13 +1965,10 @@ limited_editor.inputs['C-q'] = function()
|
||||||
var limited_editing = {};
|
var limited_editing = {};
|
||||||
limited_editing.inputs = {};
|
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 */
|
/* This is the editor level & camera - NOT the currently edited level, but a level to hold editor things */
|
||||||
Game.stop();
|
sim.pause();
|
||||||
Window.editor = true;
|
window.editor = true;
|
||||||
Debug.draw_phys(true);
|
debug.draw_phys = true;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
editor
|
editor
|
||||||
|
|
|
@ -1,37 +1,234 @@
|
||||||
"use math";
|
"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;
|
globalThis.global = globalThis;
|
||||||
|
|
||||||
function use(file)
|
var profcache = {};
|
||||||
|
|
||||||
|
function use(file, env = {}, script)
|
||||||
{
|
{
|
||||||
if (use.files[file]) return use.files[file];
|
file = Resources.find_script(file);
|
||||||
if (globalThis.console)
|
var st = profile.now();
|
||||||
console.info(`running ${file}`);
|
|
||||||
|
|
||||||
var c = io.slurp(file);
|
profcache[file] ??= [];
|
||||||
|
|
||||||
var script = `(function() { ${c} })();`;
|
if (use.cache[file]) {
|
||||||
use.files[file] = cmd(123,script,global,file);
|
var ret = use.cache[file].call(env);
|
||||||
|
profile.report(st, `CACHE eval ${file}`);
|
||||||
return use.files[file];
|
profile.addreport(profcache, file, st);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
use.files = {};
|
console.info(`slurping ${file}`);
|
||||||
|
script ??= Resources.replstrs(file);
|
||||||
function include(file,that)
|
script = `(function() { var self = this; ${script}; })`;
|
||||||
{
|
var fn = os.eval(file,script);
|
||||||
if (!that) return;
|
use.cache[file] = fn;
|
||||||
if (globalThis.console) console.info(`running ${file}`);
|
var ret = fn.call(env);
|
||||||
var c = io.slurp(file);
|
profile.report(st, `eval ${file}`);
|
||||||
eval_env(c, that, file);
|
profile.addreport(profcache, file, st);
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
function eval_env(script, env, file)
|
use.cache = {};
|
||||||
{
|
|
||||||
env ??= {};
|
|
||||||
file ??= "SCRIPT";
|
|
||||||
if (globalThis.console) console.info(`eval ${file}`);
|
|
||||||
script = `(function() { ${script}; }).call(this);\n`;
|
|
||||||
return cmd(123,script,env,file);
|
|
||||||
}
|
|
||||||
|
|
||||||
global.check_registers = function(obj)
|
global.check_registers = function(obj)
|
||||||
{
|
{
|
||||||
|
@ -41,12 +238,6 @@ global.check_registers = function(obj)
|
||||||
if (typeof obj.physupdate === 'function')
|
if (typeof obj.physupdate === 'function')
|
||||||
obj.timers.push(Register.physupdate.register(obj.physupdate.bind(obj)));
|
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')
|
if (typeof obj.draw === 'function')
|
||||||
obj.timers.push(Register.draw.register(obj.draw.bind(obj), obj));
|
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.`;
|
Object.assign(global, use("scripts/base"));
|
||||||
|
|
||||||
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"));
|
|
||||||
global.obscure('global');
|
global.obscure('global');
|
||||||
global.mixin("scripts/render.js");
|
global.mixin("scripts/render");
|
||||||
|
global.mixin("scripts/debug");
|
||||||
|
|
||||||
global.Game = {
|
var frame_t = profile.secs(profile.now());
|
||||||
engine_start(fn) {
|
var phys_step = 1/240;
|
||||||
console.info("Starting rendering and sound ...");
|
|
||||||
cmd(257, fn);
|
|
||||||
},
|
|
||||||
|
|
||||||
object_count() {
|
var sim = {};
|
||||||
return cmd(214);
|
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) {
|
var physlag = 0;
|
||||||
/* Wind down from Primum */
|
|
||||||
},
|
|
||||||
|
|
||||||
/* Returns a list of objects by name */
|
var gggstart = game.engine_start;
|
||||||
find(name) {
|
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 */
|
function process()
|
||||||
find_proto(proto) {
|
{
|
||||||
|
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 */
|
if (sim.mode === "play" || sim.mode === "step") {
|
||||||
find_tag(tag){
|
prosperon.update(dt*game.timescale);
|
||||||
|
if (sim.mode === "step")
|
||||||
|
sim.pause();
|
||||||
|
|
||||||
},
|
physlag += dt;
|
||||||
|
|
||||||
quit() {
|
while (physlag > phys_step) {
|
||||||
sys_cmd(0);
|
physlag -= phys_step;
|
||||||
},
|
prosperon.phys2d_step(phys_step*game.timescale);
|
||||||
|
prosperon.physupdate(phys_step*game.timescale);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pause() { sys_cmd(3); },
|
if (!game.camera)
|
||||||
stop() { Game.pause(); },
|
prosperon.window_render(world, 1);
|
||||||
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();
|
|
||||||
else
|
else
|
||||||
this.wait_fns.push(fn);
|
prosperon.window_render(game.camera, game.camera.zoom);
|
||||||
},
|
|
||||||
|
|
||||||
exec() {
|
render.set_camera();
|
||||||
this.wait_fns.forEach(function(x) { x(); });
|
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); }
|
render.end_pass();
|
||||||
Game.gc.doc = "Force the garbage collector to run.";
|
}
|
||||||
|
|
||||||
Game.doc = {};
|
game.timescale = 1;
|
||||||
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.";
|
|
||||||
|
|
||||||
global.prosperon = {};
|
var eachobj = function(obj,fn)
|
||||||
prosperon.version = cmd(255);
|
{
|
||||||
prosperon.revision = cmd(256);
|
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 = {};
|
||||||
prosperon.semver.valid = function(v, range)
|
prosperon.semver.valid = function(v, range)
|
||||||
|
@ -222,13 +455,22 @@ prosperon.touchpress = function(touches){};
|
||||||
prosperon.touchrelease = function(touches){};
|
prosperon.touchrelease = function(touches){};
|
||||||
prosperon.touchmove = function(touches){};
|
prosperon.touchmove = function(touches){};
|
||||||
prosperon.clipboardpaste = function(str){};
|
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");
|
console.info("QUITTING");
|
||||||
global.mixin("scripts/std.js");
|
for (var i in debug.log.time)
|
||||||
console.level = 1;
|
console.warn(debug.log.time[i].map(x=>profile.ms(x)));
|
||||||
global.mixin("scripts/diff.js");
|
};
|
||||||
global.mixin("scripts/color.js");
|
|
||||||
global.mixin("scripts/gui.js");
|
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 = {
|
var timer = {
|
||||||
update(dt) {
|
update(dt) {
|
||||||
|
@ -241,7 +483,7 @@ var timer = {
|
||||||
|
|
||||||
kill() {
|
kill() {
|
||||||
this.end();
|
this.end();
|
||||||
this.fn = undefined;
|
delete this.fn;
|
||||||
},
|
},
|
||||||
|
|
||||||
delay(fn, secs) {
|
delay(fn, secs) {
|
||||||
|
@ -250,68 +492,20 @@ var timer = {
|
||||||
t.remain = secs;
|
t.remain = secs;
|
||||||
t.fn = fn;
|
t.fn = fn;
|
||||||
t.end = Register.update.register(timer.update.bind(t));
|
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");
|
||||||
global.mixin("scripts/physics.js");
|
global.mixin("scripts/geometry");
|
||||||
global.mixin("scripts/ai.js");
|
|
||||||
global.mixin("scripts/geometry.js");
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
Factory for creating registries. Register one with 'X.register',
|
||||||
|
which returns a function that, when invoked, cancels the registry.
|
||||||
|
*/
|
||||||
var Register = {
|
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: [],
|
registries: [],
|
||||||
|
|
||||||
add_cb(name) {
|
add_cb(name) {
|
||||||
|
@ -323,9 +517,12 @@ var Register = {
|
||||||
if (typeof obj === 'object')
|
if (typeof obj === 'object')
|
||||||
fn = fn.bind(obj);
|
fn = fn.bind(obj);
|
||||||
fns.push(fn);
|
fns.push(fn);
|
||||||
return function() { fns.remove(fn); };
|
return function() {
|
||||||
|
fns.remove(fn);
|
||||||
|
};
|
||||||
}
|
}
|
||||||
prosperon[name] = function(...args) { fns.forEach(x => x(...args)); }
|
prosperon[name] = function(...args) { fns.forEach(x => x(...args)); }
|
||||||
|
prosperon[name].fns = fns;
|
||||||
n.clear = function() { fns = []; }
|
n.clear = function() { fns = []; }
|
||||||
|
|
||||||
Register[name] = n;
|
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("appupdate");
|
||||||
|
Register.add_cb("update").doc = "Called once per frame.";
|
||||||
Register.add_cb("physupdate");
|
Register.add_cb("physupdate");
|
||||||
Register.add_cb("gui");
|
Register.add_cb("gui");
|
||||||
Register.add_cb("debug");
|
Register.add_cb("debug");
|
||||||
Register.add_cb("gamepad_input");
|
|
||||||
Register.add_cb("draw");
|
Register.add_cb("draw");
|
||||||
|
|
||||||
Register.gamepad_playermap[0] = Player.players[0];
|
|
||||||
|
|
||||||
var Event = {
|
var Event = {
|
||||||
events: {},
|
events: {},
|
||||||
|
|
||||||
|
@ -361,84 +555,60 @@ var Event = {
|
||||||
Object.keys(this.events).forEach(name => Event.unobserve(name,obj));
|
Object.keys(this.events).forEach(name => Event.unobserve(name,obj));
|
||||||
},
|
},
|
||||||
|
|
||||||
notify(name) {
|
notify(name, ...args) {
|
||||||
if (!this.events[name]) return;
|
if (!this.events[name]) return;
|
||||||
this.events[name].forEach(function(x) {
|
this.events[name].forEach(function(x) {
|
||||||
x[1].call(x[0]);
|
x[1].call(x[0], ...args);
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
Window.modetypes = {
|
// window.rendersize is the resolution the game renders at
|
||||||
stretch: 0, // stretch to fill window
|
// window.size is the physical size of the window on the desktop
|
||||||
keep: 1, // keep exact dimensions
|
window.modetypes = {
|
||||||
width: 2, // keep width
|
stretch: 0, // stretch render to fill window
|
||||||
height: 3, // keep height
|
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
|
expand: 4, // expand width or height
|
||||||
full: 5 // expand out beyond window
|
full: 5 // expand out beyond window
|
||||||
};
|
};
|
||||||
|
|
||||||
Window.size = [640, 480];
|
window.size = [640, 480];
|
||||||
|
|
||||||
Window.screen2world = function(screenpos) {
|
window.set_icon.doc = "Set the icon of the window using the PNG image at path.";
|
||||||
if (Game.camera)
|
|
||||||
return Game.camera.view2world(screenpos);
|
|
||||||
|
|
||||||
return screenpos;
|
global.mixin("scripts/spline");
|
||||||
}
|
global.mixin("scripts/components");
|
||||||
|
|
||||||
Window.world2screen = function(worldpos) {
|
window.doc = {};
|
||||||
return Game.camera.world2view(worldpos);
|
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); };
|
global.mixin("scripts/actor");
|
||||||
Window.icon.doc = "Set the icon of the window using the PNG image at path.";
|
global.mixin("scripts/entity");
|
||||||
|
|
||||||
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");
|
|
||||||
|
|
||||||
function world_start() {
|
function world_start() {
|
||||||
globalThis.world = Object.create(gameobject);
|
globalThis.world = os.make_gameobject();
|
||||||
world.objects = {};
|
world.objects = {};
|
||||||
world.check_dirty = function() {};
|
|
||||||
world.namestr = function(){};
|
|
||||||
world._ed = {
|
|
||||||
selectable:false,
|
|
||||||
dirty:false,
|
|
||||||
};
|
|
||||||
world.toString = function() { return "world"; };
|
world.toString = function() { return "world"; };
|
||||||
world.master = gameobject;
|
|
||||||
world.ur = "world";
|
world.ur = "world";
|
||||||
world.kill = function() { this.clear(); };
|
world.kill = function() { this.clear(); };
|
||||||
world.phys = 2;
|
world.phys = 2;
|
||||||
|
world.zoom = 1;
|
||||||
gameobject.level = world;
|
world._ed = { selectable: false };
|
||||||
gameobject.body = make_gameobject();
|
world.ur = {};
|
||||||
cmd(113,gameobject.body, gameobject);
|
world.ur.fresh = {};
|
||||||
Object.hide(gameobject, 'timescale');
|
game.cam = world;
|
||||||
var cam = world.spawn("scripts/camera2d.jso");
|
|
||||||
Game.view_camera(cam);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
global.mixin("scripts/physics.js");
|
global.mixin("scripts/physics");
|
||||||
|
|
||||||
Game.view_camera = function(cam)
|
window.title = `Prosperon v${prosperon.version}`;
|
||||||
{
|
window.size = [500,500];
|
||||||
Game.camera = cam;
|
window.boundingbox = function() {
|
||||||
cmd(61, Game.camera.body);
|
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.sphere = {};
|
||||||
shape.circle = {};
|
shape.circle = {};
|
||||||
shape.sphere.volume = function(r) { return Math.pi*r*r*r*4/3; };
|
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];
|
if (typeof r === 'number') r = [r,r];
|
||||||
theta ??= [0,1];
|
|
||||||
phi ??= [-0.5,0.5];
|
|
||||||
if (typeof theta === 'number') theta = [theta,theta];
|
if (typeof theta === 'number') theta = [theta,theta];
|
||||||
if (typeof phi === 'number') phi = [phi,phi];
|
if (typeof phi === 'number') phi = [phi,phi];
|
||||||
|
|
||||||
|
@ -44,8 +42,7 @@ shape.ngon = function(radius, n) {
|
||||||
return shape.arc(radius,360,n);
|
return shape.arc(radius,360,n);
|
||||||
};
|
};
|
||||||
|
|
||||||
shape.arc = function(radius, angle, n, start) {
|
shape.arc = function(radius, angle, n, start = 0) {
|
||||||
start ??= 0;
|
|
||||||
start = Math.deg2rad(start);
|
start = Math.deg2rad(start);
|
||||||
if (angle >= 360)
|
if (angle >= 360)
|
||||||
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 = {
|
gui.scissor_win = function() { gui.scissor(0,0,window.size.x,window.y); }
|
||||||
text(str, pos, size, color, wrap, anchor, cursor) {
|
|
||||||
size ??= 1;
|
|
||||||
color ??= Color.white;
|
|
||||||
wrap ??= -1;
|
|
||||||
anchor ??= [0,1];
|
|
||||||
|
|
||||||
cursor ??= -1;
|
gui.input_lmouse_pressed = function() {
|
||||||
|
if (gui.selected)
|
||||||
|
gui.selected.action();
|
||||||
|
};
|
||||||
|
|
||||||
var bb = cmd(118, str, size, wrap);
|
gui.input_s_pressed = function() {
|
||||||
var w = bb.r*2;
|
if (gui.selected?.down) {
|
||||||
var h = bb.t*2;
|
gui.selected.selected = false;
|
||||||
|
gui.selected = gui.selected.down;
|
||||||
//ui_text draws with an anchor on top left corner
|
gui.selected.selected = true;
|
||||||
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.controls = {};
|
gui.input_w_pressed = function() {
|
||||||
GUI.controls.toString = function() { return "GUI controls"; };
|
if (gui.selected?.up) {
|
||||||
GUI.controls.update = function() { };
|
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;
|
mum.selected = true;
|
||||||
|
|
||||||
|
@ -103,22 +44,22 @@ GUI.controls.set_mum = function(mum)
|
||||||
|
|
||||||
this.selected = mum;
|
this.selected = mum;
|
||||||
}
|
}
|
||||||
GUI.controls.check_bb = function(mum)
|
gui.controls.check_bb = function(mum)
|
||||||
{
|
{
|
||||||
if (bbox.pointin(mum.bb, Mouse.screenpos()))
|
if (bbox.pointin(mum.bb, input.mouse.screenpos()))
|
||||||
GUI.controls.set_mum(mum);
|
gui.controls.set_mum(mum);
|
||||||
}
|
}
|
||||||
GUI.controls.inputs = {};
|
gui.controls.inputs = {};
|
||||||
GUI.controls.inputs.fallthru = false;
|
gui.controls.inputs.fallthru = false;
|
||||||
GUI.controls.inputs.mouse = {};
|
gui.controls.inputs.mouse = {};
|
||||||
GUI.controls.inputs.mouse.move = function(pos,dpos)
|
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)
|
if (this.selected && this.selected.action)
|
||||||
this.selected.action(this.selected);
|
this.selected.action(this.selected);
|
||||||
}
|
}
|
||||||
|
@ -177,11 +118,9 @@ var Mum = {
|
||||||
}
|
}
|
||||||
|
|
||||||
Mum.text = Mum.extend({
|
Mum.text = Mum.extend({
|
||||||
draw(cursor, cnt) {
|
draw(cursor = [0,0], cnt = Mum) {
|
||||||
cursor ??= [0,0];
|
|
||||||
cnt ??= Mum;
|
|
||||||
if (this.hide) return;
|
if (this.hide) return;
|
||||||
if (this.selectable) GUI.controls.check_bb(this);
|
if (this.selectable) gui.controls.check_bb(this);
|
||||||
this.caret ??= -1;
|
this.caret ??= -1;
|
||||||
|
|
||||||
/* if (!this.bb)
|
/* if (!this.bb)
|
||||||
|
@ -197,8 +136,8 @@ Mum.text = Mum.extend({
|
||||||
this.height = this.wh.y;
|
this.height = this.wh.y;
|
||||||
var aa = [0,1].sub(params.anchor);
|
var aa = [0,1].sub(params.anchor);
|
||||||
var pos = cursor.add(params.wh.scale(aa)).add(params.offset);
|
var pos = cursor.add(params.wh.scale(aa)).add(params.offset);
|
||||||
cmd(263, params.font);
|
// gui.font_set(params.font);
|
||||||
ui_text(params.str, pos, params.font_size, params.color, this.width, params.caret);
|
render.text(params.str, pos, params.font_size, params.color, this.width, undefined, params.caret);
|
||||||
},
|
},
|
||||||
|
|
||||||
update_bb(cursor) {
|
update_bb(cursor) {
|
||||||
|
@ -206,7 +145,7 @@ Mum.text = Mum.extend({
|
||||||
},
|
},
|
||||||
|
|
||||||
calc_bb(cursor) {
|
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);
|
this.wh = bbox.towh(bb);
|
||||||
var pos = cursor.add(this.wh.scale([0,1].sub(this.anchor))).add(this.offset);
|
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]));
|
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.wh = [this.width, this.height];
|
||||||
this.bb = bbox.fromcwh([0,0], this.wh);
|
this.bb = bbox.fromcwh([0,0], this.wh);
|
||||||
},
|
},
|
||||||
draw(cursor, cnt) {
|
draw(cursor = [0,0], cnt = Mum) {
|
||||||
cursor ??= [0,0];
|
|
||||||
cnt ??= Mum;
|
|
||||||
var p = cursor.sub(this.wh.scale(this.anchor)).add(this.padding);
|
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);
|
this.bb = bbox.blwh(p, this.wh);
|
||||||
GUI.flush();
|
gui.flush();
|
||||||
GUI.scissor(p.x,p.y,this.wh.x,this.wh.y);
|
|
||||||
this.max_width = this.width;
|
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);
|
var pos = [this.bb.l, this.bb.t].add(this.padding);
|
||||||
this.items.forEach(function(item) {
|
this.items.forEach(function(item) {
|
||||||
if (item.hide) return;
|
if (item.hide) return;
|
||||||
item.draw(pos.slice(),this);
|
item.draw(pos.slice(),this);
|
||||||
}, this);
|
}, this);
|
||||||
GUI.flush();
|
gui.flush();
|
||||||
GUI.scissor_win();
|
gui.scissor_win();
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -258,7 +194,7 @@ Mum.image = Mum.extend({
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var tex_wh = cmd(64, this.path);
|
var tex_wh = texture.dimensions(this.path);
|
||||||
this.wh = tex_wh.slice();
|
this.wh = tex_wh.slice();
|
||||||
if (this.width !== 0) this.wh.x = this.width;
|
if (this.width !== 0) this.wh.x = this.width;
|
||||||
if (this.height !== 0) this.wh.y = this.height;
|
if (this.height !== 0) this.wh.y = this.height;
|
||||||
|
@ -279,9 +215,7 @@ Mum.image = Mum.extend({
|
||||||
});
|
});
|
||||||
|
|
||||||
Mum.column = Mum.extend({
|
Mum.column = Mum.extend({
|
||||||
draw(cursor, cnt) {
|
draw(cursor = [0,0], cnt = Mum) {
|
||||||
cursor ??= [0,0];
|
|
||||||
cnt ??= Mum;
|
|
||||||
if (this.hide) return;
|
if (this.hide) return;
|
||||||
cursor = cursor.add(this.offset);
|
cursor = cursor.add(this.offset);
|
||||||
this.max_width = cnt.width;
|
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 = {
|
Mum.debug_colors = {
|
||||||
bounds: Color.red.slice(),
|
bounds: Color.red.slice(),
|
||||||
margin: Color.blue.slice(),
|
margin: Color.blue.slice(),
|
||||||
|
@ -313,7 +237,4 @@ Mum.debug_colors = {
|
||||||
|
|
||||||
Object.values(Mum.debug_colors).forEach(function(v) { v.a = 100; });
|
Object.values(Mum.debug_colors).forEach(function(v) { v.a = 100; });
|
||||||
|
|
||||||
return {
|
return { Mum };
|
||||||
GUI,
|
|
||||||
Mum
|
|
||||||
};
|
|
||||||
|
|
146
scripts/input.js
146
scripts/input.js
|
@ -1,25 +1,25 @@
|
||||||
var keycodes = {
|
input.keycodes = {
|
||||||
259: "back",
|
|
||||||
258: "tab",
|
|
||||||
257: "enter",
|
|
||||||
1: "escape",
|
|
||||||
32: "space",
|
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",
|
266: "pgup",
|
||||||
267: "pgdown",
|
267: "pgdown",
|
||||||
268: "home",
|
268: "home",
|
||||||
269: "end",
|
269: "end",
|
||||||
263: "left",
|
|
||||||
265: "up",
|
|
||||||
262: "right",
|
|
||||||
265: "down",
|
|
||||||
260: "insert",
|
|
||||||
261: "delete",
|
|
||||||
45: "minus",
|
|
||||||
};
|
};
|
||||||
|
|
||||||
var codekeys = {};
|
input.codekeys = {};
|
||||||
for (var code in keycodes)
|
for (var code in input.keycodes)
|
||||||
codekeys[keycodes[code]] = code;
|
input.codekeys[input.keycodes[code]] = code;
|
||||||
|
|
||||||
var mod = {
|
var mod = {
|
||||||
shift: 0,
|
shift: 0,
|
||||||
|
@ -36,6 +36,8 @@ pressrep
|
||||||
down
|
down
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
function keycode(name) { return charCodeAt(name); }
|
||||||
|
|
||||||
function keyname_extd(key)
|
function keyname_extd(key)
|
||||||
{
|
{
|
||||||
if (key > 289 && key < 302) {
|
if (key > 289 && key < 302) {
|
||||||
|
@ -48,7 +50,7 @@ function keyname_extd(key)
|
||||||
return `kp${num}`;
|
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();
|
if (key >= 32 && key <= 126) return String.fromCharCode(key).lc();
|
||||||
|
|
||||||
return undefined;
|
return undefined;
|
||||||
|
@ -67,7 +69,6 @@ function modstr()
|
||||||
|
|
||||||
prosperon.keydown = function(key, repeat)
|
prosperon.keydown = function(key, repeat)
|
||||||
{
|
{
|
||||||
|
|
||||||
prosperon.keys[key] = true;
|
prosperon.keys[key] = true;
|
||||||
|
|
||||||
if (key == 341 || key == 345)
|
if (key == 341 || key == 345)
|
||||||
|
@ -93,6 +94,7 @@ prosperon.keyup = function(key)
|
||||||
prosperon.keys[key] = false;
|
prosperon.keys[key] = false;
|
||||||
if (key == 341 || key == 345)
|
if (key == 341 || key == 345)
|
||||||
mod.ctrl = 0;
|
mod.ctrl = 0;
|
||||||
|
|
||||||
else if (key == 342 || key == 346)
|
else if (key == 342 || key == 346)
|
||||||
mod.alt = 0;
|
mod.alt = 0;
|
||||||
else if (key == 343 || key == 347)
|
else if (key == 343 || key == 347)
|
||||||
|
@ -112,51 +114,51 @@ prosperon.droppedfile = function(path)
|
||||||
|
|
||||||
var mousepos = [0,0];
|
var mousepos = [0,0];
|
||||||
|
|
||||||
prosperon.textinput = function(){};
|
prosperon.textinput = function(c){
|
||||||
|
player[0].raw_input("char", "pressed", c);
|
||||||
|
};
|
||||||
prosperon.mousemove = function(pos, dx){
|
prosperon.mousemove = function(pos, dx){
|
||||||
mousepos = pos;
|
mousepos = pos;
|
||||||
player[0].mouse_input(modstr() + "move", pos, dx);
|
player[0].mouse_input("move", pos, dx);
|
||||||
};
|
};
|
||||||
prosperon.mousescroll = function(dx){
|
prosperon.mousescroll = function(dx){
|
||||||
player[0].mouse_input(modstr() + "scroll", dx);
|
player[0].mouse_input(modstr() + "scroll", dx);
|
||||||
};
|
};
|
||||||
prosperon.mousedown = function(b){
|
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){
|
prosperon.mouseup = function(b){
|
||||||
player[0].raw_input(modstr() + Mouse.button[b], "released");
|
player[0].raw_input(input.mouse.button[b], "released");
|
||||||
};
|
};
|
||||||
|
|
||||||
var Mouse = {
|
input.mouse = {};
|
||||||
screenpos() { return mousepos.slice(); },
|
input.mouse.screenpos = function() { return mousepos.slice(); };
|
||||||
worldpos() { return Window.screen2world(mousepos); },
|
input.mouse.worldpos = function() { return game.camera.view2world(mousepos); };
|
||||||
disabled() { cmd(46, 1); },
|
input.mouse.disabled = function() { input.mouse_mode(1); };
|
||||||
normal() { cmd(46, 0);},
|
input.mouse.normal = function() { input.mouse_mode(0); };
|
||||||
|
input.mouse.mode = function(m) {
|
||||||
mode(m) {
|
if (input.mouse.custom[m])
|
||||||
if (Mouse.custom[m])
|
input.cursor_img(input.mouse.custom[m]);
|
||||||
cmd(97, Mouse.custom[m]);
|
|
||||||
else
|
else
|
||||||
cmd(17, m);
|
input.mouse_cursor(m);
|
||||||
},
|
};
|
||||||
|
|
||||||
set_custom_cursor(img, mode) {
|
input.mouse.set_custom_cursor = function(img, mode = input.mouse.cursor.default) {
|
||||||
mode ??= Mouse.cursor.default;
|
|
||||||
if (!img)
|
if (!img)
|
||||||
delete Mouse.custom[mode];
|
delete input.mouse.custom[mode];
|
||||||
else {
|
else {
|
||||||
cmd(97, img);
|
input.cursor_img(img);
|
||||||
Mouse.custom[mode] = img;
|
input.mouse.custom[mode] = img;
|
||||||
}
|
}
|
||||||
},
|
};
|
||||||
|
|
||||||
button: { /* left, right, middle mouse */
|
input.mouse.button = { /* left, right, middle mouse */
|
||||||
0: "lm",
|
0: "lm",
|
||||||
1: "rm",
|
1: "rm",
|
||||||
2: "mm"
|
2: "mm"
|
||||||
},
|
};
|
||||||
custom:[],
|
input.mouse.custom = [];
|
||||||
cursor: {
|
input.mouse.cursor = {
|
||||||
default: 0,
|
default: 0,
|
||||||
arrow: 1,
|
arrow: 1,
|
||||||
ibeam: 2,
|
ibeam: 2,
|
||||||
|
@ -168,22 +170,20 @@ var Mouse = {
|
||||||
nesw: 8,
|
nesw: 8,
|
||||||
resize: 9,
|
resize: 9,
|
||||||
no: 10
|
no: 10
|
||||||
},
|
|
||||||
};
|
};
|
||||||
|
|
||||||
Mouse.doc = {};
|
input.mouse.doc = {};
|
||||||
Mouse.doc.pos = "The screen position of the mouse.";
|
input.mouse.doc.pos = "The screen position of the mouse.";
|
||||||
Mouse.doc.worldpos = "The position in the game world of the mouse.";
|
input.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.";
|
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.";
|
||||||
Mouse.normal.doc = "Set the mouse to show again after hiding.";
|
input.mouse.normal.doc = "Set the mouse to show again after hiding.";
|
||||||
|
|
||||||
var Keys = {
|
input.keyboard = {};
|
||||||
down(code) {
|
input.keyboard.down = function(code) {
|
||||||
return prosperon.keys[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;
|
||||||
|
}
|
||||||
var input = {};
|
|
||||||
|
|
||||||
input.state2str = function(state) {
|
input.state2str = function(state) {
|
||||||
if (typeof state === 'string') return state;
|
if (typeof state === 'string') return state;
|
||||||
|
@ -207,6 +207,14 @@ input.print_pawn_kbm = function(pawn) {
|
||||||
return str;
|
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) {
|
input.print_md_kbm = function(pawn) {
|
||||||
if (!('inputs' in pawn)) return;
|
if (!('inputs' in pawn)) return;
|
||||||
|
|
||||||
|
@ -237,13 +245,6 @@ input.action = {
|
||||||
actions: [],
|
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 */
|
/* May be a human player; may be an AI player */
|
||||||
var Player = {
|
var Player = {
|
||||||
players: [],
|
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) {
|
obj_controlled(obj) {
|
||||||
for (var p in Player.players) {
|
for (var p in Player.players) {
|
||||||
if (p.pawns.contains(obj))
|
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++) {
|
for (var i = 0; i < 4; i++) {
|
||||||
Player.create();
|
Player.create();
|
||||||
}
|
}
|
||||||
|
@ -372,11 +374,5 @@ Player.doc.players = "A list of current players.";
|
||||||
var player = Player;
|
var player = Player;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
Mouse,
|
player
|
||||||
Keys,
|
|
||||||
input,
|
|
||||||
Player,
|
|
||||||
player,
|
|
||||||
keycodes,
|
|
||||||
codekeys
|
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,79 +1,57 @@
|
||||||
/* On collisions, entities are sent a 'hit' object, which looks like this:
|
/* On collisions, entities are sent a 'hit' object, which looks like this:
|
||||||
var HIT = {
|
var HIT = {
|
||||||
normal: "The normal of the collision point.",
|
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.",
|
sensor: "Boolean for if the colliding object was a sensor.",
|
||||||
velocity: "Velocity of the contact.",
|
velocity: "Velocity of the contact.",
|
||||||
pos: "Position in world space of the contact.",
|
pos: "Position in world space of the contact.",
|
||||||
depth: "Depth 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,
|
dynamic: 0,
|
||||||
kinematic: 1,
|
kinematic: 1,
|
||||||
static: 2,
|
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) {
|
com(pos) {
|
||||||
if (!Array.isArray(pos)) return [0,0];
|
if (!Array.isArray(pos)) return [0,0];
|
||||||
return pos.reduce((a,i) => a.add(i)).map(g => g/pos.length);
|
return pos.reduce((a,i) => a.add(i)).map(g => g/pos.length);
|
||||||
},
|
},
|
||||||
};
|
});
|
||||||
|
|
||||||
physics.doc = {};
|
physics.doc = {};
|
||||||
physics.doc.pos_query = "Returns any object colliding with the given point.";
|
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.doc.box_point_query = "Returns the subset of points from a given list that are inside a given box.";
|
||||||
|
|
||||||
physics.collision = {
|
physics.gravity = physics.make_gravity();
|
||||||
types: {},
|
physics.gravity.mask = ~1;
|
||||||
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.strength = 500;
|
physics.gravity.strength = 500;
|
||||||
physics.damp = physics.warp.damp();
|
physics.damp = physics.make_damp();
|
||||||
physics.damp.mask = [true];
|
physics.damp.mask = ~1;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
physics
|
physics
|
||||||
|
|
|
@ -1,9 +1,3 @@
|
||||||
var render = {
|
|
||||||
normal() { cmd(67);},
|
|
||||||
wireframe() { cmd(68); },
|
|
||||||
pass() { },
|
|
||||||
};
|
|
||||||
|
|
||||||
render.doc = {
|
render.doc = {
|
||||||
doc: "Functions for rendering modes.",
|
doc: "Functions for rendering modes.",
|
||||||
normal: "Final render with all lighting.",
|
normal: "Final render with all lighting.",
|
||||||
|
@ -47,23 +41,16 @@ render.device = {
|
||||||
render.device.doc = `Device resolutions given as [x,y,inches diagonal].`;
|
render.device.doc = `Device resolutions given as [x,y,inches diagonal].`;
|
||||||
|
|
||||||
/* All draw in screen space */
|
/* All draw in screen space */
|
||||||
render.point = function(pos,size,color) {
|
render.point = function(pos,size,color = Color.blue) {
|
||||||
color ??= Color.blue;
|
render.circle(pos,size,size,color);
|
||||||
render.circle(pos,size,color);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
render.line = function(points, color, thickness) {
|
var tmpline = render.line;
|
||||||
thickness ??= 1;
|
render.line = function(points, color = Color.white, thickness = 1) {
|
||||||
color ??= Color.white;
|
tmpline(points,color,thickness);
|
||||||
cmd(83, points, color, thickness);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
render.poly = function(points, color) { cmd_points(0,points,color); };
|
render.cross = function(pos, size, color = Color.red) {
|
||||||
|
|
||||||
render.circle = function(pos, radius, color) { cmd(115, pos, radius, color); };
|
|
||||||
|
|
||||||
render.cross = function(pos, size, color) {
|
|
||||||
color ??= Color.red;
|
|
||||||
var a = [
|
var a = [
|
||||||
pos.add([0,size]),
|
pos.add([0,size]),
|
||||||
pos.add([0,-size])
|
pos.add([0,-size])
|
||||||
|
@ -77,11 +64,7 @@ render.cross = function(pos, size, color) {
|
||||||
render.line(b,color);
|
render.line(b,color);
|
||||||
};
|
};
|
||||||
|
|
||||||
render.arrow = function(start, end, color, wingspan, wingangle) {
|
render.arrow = function(start, end, color = Color.red, wingspan = 4, wingangle = 10) {
|
||||||
color ??= Color.red;
|
|
||||||
wingspan ??= 4;
|
|
||||||
wingangle ??=10;
|
|
||||||
|
|
||||||
var dir = end.sub(start).normalized();
|
var dir = end.sub(start).normalized();
|
||||||
var wing1 = [
|
var wing1 = [
|
||||||
Vector.rotate(dir, wingangle).scale(wingspan).add(end),
|
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.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) {
|
render.rectangle = function(lowerleft, upperright, color) {
|
||||||
var pos = lowerleft.add(upperright).map(x=>x/2);
|
var points = [lowerleft, lowerleft.add([upperright.x-lowerleft.x,0]), upperright, lowerleft.add([0,upperright.y-lowerleft.y])];
|
||||||
var wh = [upperright.x-lowerleft.x,upperright.y-lowerleft.y];
|
render.poly(points, color);
|
||||||
render.box(pos,wh,color);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
render.box = function(pos, wh, color) {
|
render.box = function(pos, wh, color = Color.white) {
|
||||||
color ??= Color.white;
|
var lower = pos.sub(wh.scale(0.5));
|
||||||
cmd(53, pos, wh, color);
|
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.doc = "Draw shapes in screen space.";
|
||||||
render.circle.doc = "Draw a circle at pos, with a given radius and color.";
|
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.";
|
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 = {
|
Object.readonly(audio, 'samplerate');
|
||||||
bus: {},
|
Object.readonly(audio, 'channels');
|
||||||
samplerate() { return cmd(198); },
|
Object.readonly(audio, 'buffer_frames');
|
||||||
sounds: [], /* array of loaded sound files */
|
|
||||||
play(file, bus) {
|
audio.play = function(file,bus = audio.bus.master) {
|
||||||
file = Resources.find_sound(file);
|
file = Resources.find_sound(file);
|
||||||
if (!file) {
|
if (!file) {
|
||||||
console.error(`Cannot play sound ${file}: does not exist.`);
|
console.error(`Cannot play sound ${file}: does not exist.`);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
var src = audio.dsp.source(file);
|
var src = audio.dsp.source(file);
|
||||||
bus ??= audio.sound.bus.master;
|
|
||||||
src.plugin(bus);
|
src.plugin(bus);
|
||||||
|
src.guid = prosperon.guid();
|
||||||
return src;
|
return src;
|
||||||
},
|
}
|
||||||
|
audio.bus = {};
|
||||||
|
audio.bus.master = dspsound.master();
|
||||||
|
audio.dsp = {};
|
||||||
|
audio.dsp = dspsound;
|
||||||
|
|
||||||
doc: {
|
audio.cry = function(file)
|
||||||
play: "Play the given file once.",
|
{
|
||||||
volume: "Set the volume. 0 is no sound and 100 is loudest."
|
var player = audio.play(file);
|
||||||
},
|
if (!player) return;
|
||||||
};
|
|
||||||
|
|
||||||
audio.dsp = {
|
player.guid = prosperon.guid();
|
||||||
mix(to) {
|
cries[player.guid] = player;
|
||||||
var n = cmd(181);
|
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);
|
if (to) n.plugin(to);
|
||||||
return n;
|
return n;
|
||||||
},
|
};
|
||||||
source(path) {
|
|
||||||
return cmd(182,path);
|
audio.dsp.allpass = function(secs, decay) {
|
||||||
},
|
|
||||||
delay(secs,decay) {
|
|
||||||
return cmd(185, secs, decay);
|
|
||||||
},
|
|
||||||
fwd_delay(secs, decay) {
|
|
||||||
return cmd(207,secs,decay);
|
|
||||||
},
|
|
||||||
allpass(secs, decay) {
|
|
||||||
var composite = {};
|
var composite = {};
|
||||||
var fwd = audio.dsp.fwd_delay(secs,-decay);
|
var fwd = audio.dsp.fwd_delay(secs,-decay);
|
||||||
var fbk = audio.dsp.delay(secs,decay);
|
var fbk = audio.dsp.delay(secs,decay);
|
||||||
|
@ -48,44 +78,7 @@ audio.dsp = {
|
||||||
composite.unplug = dsp_node.unplug.bind(fbk);
|
composite.unplug = dsp_node.unplug.bind(fbk);
|
||||||
fwd.plugin(fbk);
|
fwd.plugin(fbk);
|
||||||
return composite;
|
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 = {
|
audio.dsp.doc = {
|
||||||
delay: "Delays the input by secs, multiplied by decay",
|
delay: "Delays the input by secs, multiplied by decay",
|
||||||
|
@ -103,18 +96,15 @@ audio.dsp.doc = {
|
||||||
red: "Red noise"
|
red: "Red noise"
|
||||||
};
|
};
|
||||||
|
|
||||||
Object.mixin(cmd(180).__proto__, {
|
Object.mixin(audio.bus.master.__proto__, {
|
||||||
get db() { return 20*Math.log10(Math.abs(this.volume)); },
|
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); },
|
set db(x) { x = Math.clamp(x,-100,0); this.volume = Math.pow(10, x/20); },
|
||||||
get volume() { return this.gain; },
|
get volume() { return this.gain; },
|
||||||
set volume(x) { this.gain = x; },
|
set volume(x) { this.gain = x; },
|
||||||
});
|
});
|
||||||
|
|
||||||
audio.sound.bus.master = cmd(180);
|
|
||||||
|
|
||||||
/*Object.mixin(audio.dsp.source().__proto__, {
|
/*Object.mixin(audio.dsp.source().__proto__, {
|
||||||
frames() { return cmd(197,this); },
|
length() { return this.frames()/audio.samplerate(); },
|
||||||
length() { return this.frames()/sound.samplerate(); },
|
|
||||||
time() { return this.frame/sound.samplerate(); },
|
time() { return this.frame/sound.samplerate(); },
|
||||||
pct() { return this.time()/this.length(); },
|
pct() { return this.time()/this.length(); },
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
var Spline = {};
|
var Spline = {};
|
||||||
Spline.sample_angle = function(type, points, angle) {
|
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)
|
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
|
else
|
||||||
os.user = os.env("USER");
|
os.user = os.env("USER");
|
||||||
|
|
||||||
|
|
||||||
var appy = {};
|
var appy = {};
|
||||||
appy.inputs = {};
|
appy.inputs = {};
|
||||||
if (os.sys() === 'macos') {
|
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-h'] = function() { };
|
||||||
|
appy.inputs['S-g'] = os.gc;
|
||||||
}
|
}
|
||||||
|
|
||||||
player[0].control(appy);
|
player[0].control(appy);
|
||||||
|
|
||||||
var steam = {};
|
|
||||||
steam.appid = 480;
|
steam.appid = 480;
|
||||||
steam.userid = 8437843;
|
steam.userid = 8437843;
|
||||||
|
|
||||||
|
@ -35,33 +34,18 @@ var otherpath = {
|
||||||
}
|
}
|
||||||
|
|
||||||
os.prefpath = function() {
|
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 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) {
|
Resources.is_sound = function(path) {
|
||||||
var ext = path.ext();
|
var ext = path.ext();
|
||||||
return Resources.sounds.any(x => x === ext);
|
return Resources.sounds.any(x => x === ext);
|
||||||
|
@ -81,121 +65,10 @@ Resources.is_path = function(str)
|
||||||
}
|
}
|
||||||
|
|
||||||
Resources.texture = {};
|
Resources.texture = {};
|
||||||
Resources.texture.dimensions = function(path) { return cmd(64,path); }
|
Resources.texture.dimensions = function(path) { texture.dimensions(path); }
|
||||||
|
|
||||||
Resources.gif = {};
|
Resources.gif = {};
|
||||||
Resources.gif.frames = function(path) { return cmd(139,path); }
|
Resources.gif.frames = function(path) { return render.gif_frames(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."
|
|
||||||
};
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
io path rules. Starts with, meaning:
|
io path rules. Starts with, meaning:
|
||||||
|
@ -265,12 +138,6 @@ io.mixin({
|
||||||
paths = paths.filter(function(str) { return str.ext() === ext; });
|
paths = paths.filter(function(str) { return str.ext() === ext; });
|
||||||
return paths;
|
return paths;
|
||||||
},
|
},
|
||||||
compile(script) {
|
|
||||||
return cmd(260, script);
|
|
||||||
},
|
|
||||||
run_bytecode(byte_file) {
|
|
||||||
return cmd(261, byte_file);
|
|
||||||
},
|
|
||||||
|
|
||||||
glob(pat) {
|
glob(pat) {
|
||||||
var paths = io.ls('.');
|
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;
|
Cmdline.orders[order] = fn;
|
||||||
fn.doc = doc;
|
fn.doc = doc;
|
||||||
usage ??= "";
|
|
||||||
fn.usage = `${order} ${usage}`;
|
fn.usage = `${order} ${usage}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -324,24 +190,31 @@ Cmdline.register_order("edit", function() {
|
||||||
return;
|
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");
|
global.mixin("scripts/editor.js");
|
||||||
use("editorconfig.js");
|
use("editorconfig.js");
|
||||||
|
use("config.js");
|
||||||
|
render.set_font("fonts/c64.ttf", 8);
|
||||||
editor.enter_editor();
|
editor.enter_editor();
|
||||||
});
|
});
|
||||||
}, "Edit the project in this folder. Give it the name of an UR to edit that specific object.", "?UR?");
|
}, "Edit the project in this folder. Give it the name of an UR to edit that specific object.", "?UR?");
|
||||||
|
|
||||||
Cmdline.register_order("init", function() {
|
Cmdline.register_order("init", function() {
|
||||||
|
say('top of init');
|
||||||
if (io.exists(projectfile)) {
|
if (io.exists(projectfile)) {
|
||||||
say("Already a game here.");
|
say("Already a game here.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
say('top of ls');
|
||||||
if (!(io.ls().length === 0)) {
|
if (!(io.ls().length === 0)) {
|
||||||
say("Directory is not empty. Make an empty one and init there.");
|
say("Directory is not empty. Make an empty one and init there.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
say('top of mkdir');
|
||||||
io.mkdir(".prosperon");
|
io.mkdir(".prosperon");
|
||||||
var project = {};
|
var project = {};
|
||||||
project.version = prosperon.version;
|
project.version = prosperon.version;
|
||||||
|
@ -358,7 +231,7 @@ Cmdline.register_order("play", function(argv) {
|
||||||
if (argv[0])
|
if (argv[0])
|
||||||
io.chdir(argv[0]);
|
io.chdir(argv[0]);
|
||||||
|
|
||||||
Game.loadurs();
|
game.loadurs();
|
||||||
|
|
||||||
if (!io.exists(projectfile)) {
|
if (!io.exists(projectfile)) {
|
||||||
say("No game to play. Try making one with 'prosperon init'.");
|
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));
|
var project = json.decode(io.slurp(projectfile));
|
||||||
Game.title = project.title;
|
game.title = project.title;
|
||||||
Window.mode = Window.modetypes.expand;
|
window.mode = window.modetypes.expand;
|
||||||
global.mixin("config.js");
|
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;
|
if (window.rendersize.equal([0,0])) window.rendersize = window.size;
|
||||||
console.info(`Starting game with window size ${Window.size} and render ${Window.rendersize}.`);
|
console.info(`Starting game with window size ${window.size} and render ${window.rendersize}.`);
|
||||||
|
|
||||||
Game.engine_start(function() {
|
game.engine_start(function() {
|
||||||
global.mixin("scripts/sound.js");
|
render.set_font("fonts/c64.ttf", 8);
|
||||||
global.game = actor.spawn("game.js");
|
global.app = actor.spawn("game.js");
|
||||||
if (project.icon) Window.icon(project.icon);
|
if (project.icon) window.set_icon(game.texture(project.icon));
|
||||||
|
game.camera = world.spawn("scripts/camera2d");
|
||||||
});
|
});
|
||||||
}, "Play the game present in this folder.");
|
}, "Play the game present in this folder.");
|
||||||
|
|
||||||
|
@ -393,7 +267,7 @@ Cmdline.register_order("pack", function(str) {
|
||||||
|
|
||||||
say(`Packing into ${packname}`);
|
say(`Packing into ${packname}`);
|
||||||
|
|
||||||
cmd(124, packname);
|
// io.pack_engine(packname);
|
||||||
io.chmod(packname, 666);
|
io.chmod(packname, 666);
|
||||||
}, "Pack the game into the given name.", "NAME");
|
}, "Pack the game into the given name.", "NAME");
|
||||||
|
|
||||||
|
@ -414,7 +288,7 @@ Cmdline.register_order("qoa", function(argv) {
|
||||||
for (var file of argv) {
|
for (var file of argv) {
|
||||||
if (!sounds.includes(file.ext())) continue;
|
if (!sounds.includes(file.ext())) continue;
|
||||||
say(`converting ${file}`);
|
say(`converting ${file}`);
|
||||||
cmd(262,file);
|
io.save_qoa(file);
|
||||||
}
|
}
|
||||||
}, "Convert file(s) to qoa.");
|
}, "Convert file(s) to qoa.");
|
||||||
|
|
||||||
|
@ -433,7 +307,7 @@ Cmdline.register_order("about", function(argv) {
|
||||||
}, "Get information about this game.");
|
}, "Get information about this game.");
|
||||||
|
|
||||||
Cmdline.register_order("ur", function(argv) {
|
Cmdline.register_order("ur", function(argv) {
|
||||||
Game.loadurs();
|
game.loadurs();
|
||||||
for (var i of ur._list.sort()) say(i);
|
for (var i of ur._list.sort()) say(i);
|
||||||
}, "Get information about the ur types in your game.");
|
}, "Get information about the ur types in your game.");
|
||||||
|
|
||||||
|
@ -500,23 +374,16 @@ Cmdline.register_order("api", function(obj) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
load("scripts/editor.js");
|
use("scripts/editor.js");
|
||||||
var api = Debug.api.print_doc(obj[0]);
|
var api = debug.api.print_doc(obj[0]);
|
||||||
if (!api)
|
if (!api)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
say(api);
|
say(api);
|
||||||
}, "Print the API for an object as markdown. Give it a file to save the output to.", "OBJECT");
|
}, "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) {
|
Cmdline.register_order("input", function(pawn) {
|
||||||
load("scripts/editor.js");
|
use("scripts/editor.js");
|
||||||
say(`## Input for ${pawn}`);
|
say(`## Input for ${pawn}`);
|
||||||
eval(`say(input.print_md_kbm(${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?");
|
}, "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;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (io.exists(script))
|
say(use(script));
|
||||||
try {
|
|
||||||
if (script.endswith("c"))
|
|
||||||
cmd(261, script);
|
|
||||||
else
|
|
||||||
load(script);
|
|
||||||
} catch(e) { }
|
|
||||||
else {
|
|
||||||
var ret = eval(script);
|
|
||||||
if (ret) say(ret);
|
|
||||||
}
|
|
||||||
}, "Run a given script. SCRIPT can be the script itself, or a file containing the script", "SCRIPT");
|
}, "Run a given script. SCRIPT can be the script itself, or a file containing the script", "SCRIPT");
|
||||||
|
|
||||||
Cmdline.orders.script = Cmdline.orders.run;
|
Cmdline.orders.script = Cmdline.orders.run;
|
||||||
|
@ -592,21 +449,24 @@ function cmd_args(cmdargs)
|
||||||
}
|
}
|
||||||
|
|
||||||
Cmdline.orders[cmds[0]](cmds.slice(1));
|
Cmdline.orders[cmds[0]](cmds.slice(1));
|
||||||
|
if (!game.startengine)
|
||||||
|
os.exit(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Cmdline.register_order("clean", function(argv) {
|
Cmdline.register_order("clean", function(argv) {
|
||||||
say("Cleaning not implemented.");
|
say("Cleaning not implemented.");
|
||||||
}, "Clean up a given object file.", "JSON ...");
|
}, "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) {
|
Cmdline.register_cmd("l", function(n) {
|
||||||
console.level = n;
|
console.level = n;
|
||||||
}, "Set log level.");
|
}, "Set log level.");
|
||||||
|
|
||||||
return {
|
return {
|
||||||
console,
|
|
||||||
Resources,
|
Resources,
|
||||||
say,
|
|
||||||
Cmdline,
|
Cmdline,
|
||||||
cmd_args,
|
cmd_args,
|
||||||
steam
|
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.c4 = 2*Math.PI/3;
|
||||||
Ease.elastic.c5 = 2*Math.PI / 4.5;
|
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 = {
|
var Tween = {
|
||||||
default: {
|
default: {
|
||||||
loop: "restart",
|
loop: "hold",
|
||||||
/*
|
/*
|
||||||
loop types
|
loop types
|
||||||
none: when done, return to first value
|
none: when done, return to first value
|
||||||
|
@ -197,4 +212,4 @@ var Tween = {
|
||||||
|
|
||||||
Tween.make = Tween.start;
|
Tween.make = Tween.start;
|
||||||
|
|
||||||
return {Tween, Ease};
|
return {Tween, Ease, tween};
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
#include "2dphysics.h"
|
#include "2dphysics.h"
|
||||||
|
|
||||||
#include "debug.h"
|
|
||||||
#include "gameobject.h"
|
#include "gameobject.h"
|
||||||
#include <string.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 kinematic_color = {255, 194, 64, 255};
|
||||||
struct rgba static_color = {73,209,80,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 unsigned char col_alpha = 40;
|
||||||
static const float sensor_seg = 10;
|
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 m3_to_cpt(HMM_Mat3 m)
|
||||||
{
|
{
|
||||||
cpTransform t;
|
cpTransform t;
|
||||||
|
@ -49,13 +48,7 @@ cpTransform m3_to_cpt(HMM_Mat3 m)
|
||||||
}
|
}
|
||||||
|
|
||||||
cpShape *phys2d_query_pos(cpVect pos) {
|
cpShape *phys2d_query_pos(cpVect pos) {
|
||||||
cpShapeFilter filter;
|
return cpSpacePointQueryNearest(space, pos, 0.f, CP_SHAPE_FILTER_ALL, NULL);
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -70,17 +63,11 @@ void bbhit(cpShape *shape, int *data)
|
||||||
qhit++;
|
qhit++;
|
||||||
}
|
}
|
||||||
|
|
||||||
static cpShapeFilter ff = {
|
|
||||||
.group = CP_NO_GROUP,
|
|
||||||
.mask = CP_ALL_CATEGORIES,
|
|
||||||
.categories = CP_ALL_CATEGORIES,
|
|
||||||
};
|
|
||||||
|
|
||||||
int query_point(HMM_Vec2 pos)
|
int query_point(HMM_Vec2 pos)
|
||||||
{
|
{
|
||||||
qhit = 0;
|
qhit = 0;
|
||||||
// cpSpacePointQuery(space, pos.cp, 0, filter, qpoint, &qhit);
|
// 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;
|
return qhit;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -104,65 +91,6 @@ gameobject **clean_ids(gameobject **ids)
|
||||||
return 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) {
|
int cpshape_enabled(cpShape *c) {
|
||||||
cpShapeFilter filter = cpShapeGetFilter(c);
|
cpShapeFilter filter = cpShapeGetFilter(c);
|
||||||
if (filter.categories == ~CP_ALL_CATEGORIES && filter.mask == ~CP_ALL_CATEGORIES)
|
if (filter.categories == ~CP_ALL_CATEGORIES && filter.mask == ~CP_ALL_CATEGORIES)
|
||||||
|
@ -227,7 +155,7 @@ void constraint_break(constraint *constraint)
|
||||||
cpSpaceRemoveConstraint(space, constraint->c);
|
cpSpaceRemoveConstraint(space, constraint->c);
|
||||||
cpConstraintFree(constraint->c);
|
cpConstraintFree(constraint->c);
|
||||||
constraint->c = NULL;
|
constraint->c = NULL;
|
||||||
script_call_sym(constraint->break_cb);
|
script_call_sym(constraint->break_cb,0,NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
void constraint_free(constraint *constraint)
|
void constraint_free(constraint *constraint)
|
||||||
|
@ -248,6 +176,7 @@ void constraint_test(cpConstraint *constraint, float *dt)
|
||||||
void phys2d_update(float deltaT) {
|
void phys2d_update(float deltaT) {
|
||||||
cpSpaceStep(space, deltaT);
|
cpSpaceStep(space, deltaT);
|
||||||
cpSpaceEachConstraint(space, constraint_test, &deltaT);
|
cpSpaceEachConstraint(space, constraint_test, &deltaT);
|
||||||
|
cb_idx = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void init_phys2dshape(struct phys2d_shape *shape, gameobject *go, void *data) {
|
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));
|
return cpMomentForCircle(m, 0, cpCircleShapeGetRadius(c->shape.shape), cpCircleShapeGetOffset(c->shape.shape));
|
||||||
}
|
}
|
||||||
|
|
||||||
void phys2d_circledel(struct phys2d_circle *c) {
|
void phys2d_circledel(struct phys2d_circle *c) { phys2d_shape_del(&c->shape); }
|
||||||
phys2d_shape_del(&c->shape);
|
void circle2d_free(circle2d *c) { phys2d_circledel(c); }
|
||||||
}
|
|
||||||
|
|
||||||
void phys2d_dbgdrawcpcirc(cpShape *c) {
|
void phys2d_dbgdrawcpcirc(cpShape *c) {
|
||||||
HMM_Vec2 pos = mat_t_pos(t_go2world(shape2go(c)), (HMM_Vec2)cpCircleShapeGetOffset(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);
|
float newmoi = s->moi(s->data);
|
||||||
moment-=moi;
|
moment-=moi;
|
||||||
moment += newmoi;
|
moment += newmoi;
|
||||||
|
if (moment < 0) moment = 0;
|
||||||
cpBodySetMoment(s->go->body, moment);
|
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 phys2d_poly_moi(struct phys2d_poly *poly) {
|
||||||
float m = poly->shape.go->mass;
|
float m = poly->shape.go->mass;
|
||||||
int len = cpPolyShapeGetCount(poly->shape.shape);
|
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];
|
cpVect points[len];
|
||||||
for (int i = 0; i < len; i++)
|
for (int i = 0; i < len; i++)
|
||||||
points[i] = cpPolyShapeGetVert(poly->shape.shape, i);
|
points[i] = cpPolyShapeGetVert(poly->shape.shape, i);
|
||||||
|
@ -565,10 +498,13 @@ void phys2d_dbgdrawedge(struct phys2d_edge *edge) {
|
||||||
|
|
||||||
/************ COLLIDER ****************/
|
/************ COLLIDER ****************/
|
||||||
void shape_enabled(struct phys2d_shape *shape, int enabled) {
|
void shape_enabled(struct phys2d_shape *shape, int enabled) {
|
||||||
if (enabled)
|
cpShapeFilter set = enabled ? CP_SHAPE_FILTER_ALL : CP_SHAPE_FILTER_NONE;
|
||||||
cpShapeSetFilter(shape->shape, CP_SHAPE_FILTER_ALL);
|
if (!shape->shape) {
|
||||||
else
|
struct phys2d_edge *edge = shape->data;
|
||||||
cpShapeSetFilter(shape->shape, CP_SHAPE_FILTER_NONE);
|
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) {
|
int shape_is_enabled(struct phys2d_shape *shape) {
|
||||||
|
@ -592,7 +528,6 @@ int shape_get_sensor(struct phys2d_shape *shape) {
|
||||||
if (!shape->shape) {
|
if (!shape->shape) {
|
||||||
struct phys2d_edge *edge = shape->data;
|
struct phys2d_edge *edge = shape->data;
|
||||||
if (arrlen(edge->shapes) > 0) return cpShapeGetSensor(edge->shapes[0]);
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -601,33 +536,24 @@ int shape_get_sensor(struct phys2d_shape *shape) {
|
||||||
|
|
||||||
void phys2d_reindex_body(cpBody *body) { cpSpaceReindexShapesForBody(space, body); }
|
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)
|
JSValue arb2js(cpArbiter *arb)
|
||||||
{
|
{
|
||||||
cpBody *body1;
|
cpBody *body1;
|
||||||
cpBody *body2;
|
cpBody *body2;
|
||||||
cpArbiterGetBodies(arb, &body1, &body2);
|
cpArbiterGetBodies(arb, &body1, &body2);
|
||||||
gameobject *go2 = cpBodyGetUserData(body2);
|
|
||||||
if (JS_IsUndefined(go2->ref)) return JS_UNDEFINED;
|
|
||||||
cpShape *shape1;
|
cpShape *shape1;
|
||||||
cpShape *shape2;
|
cpShape *shape2;
|
||||||
cpArbiterGetShapes(arb, &shape1, &shape2);
|
cpArbiterGetShapes(arb, &shape1, &shape2);
|
||||||
|
|
||||||
HMM_Vec2 norm;
|
struct phys2d_shape *pshape = cpShapeGetUserData(shape2);
|
||||||
norm.cp = cpArbiterGetNormal(arb);
|
gameobject *go2 = cpBodyGetUserData(body2);
|
||||||
|
|
||||||
JSValue obj = JS_NewObject(js);
|
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, "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;
|
HMM_Vec2 srfv;
|
||||||
srfv.cp = cpArbiterGetSurfaceVelocity(arb);
|
srfv.cp = cpArbiterGetSurfaceVelocity(arb);
|
||||||
|
@ -638,56 +564,47 @@ JSValue arb2js(cpArbiter *arb)
|
||||||
|
|
||||||
void phys_run_post(cpSpace *space, JSValue *fn, JSValue *hit)
|
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, *hit);
|
||||||
|
JS_FreeValue(js, *fn);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* TODO: Limitation, cannot handle multiple collision same frame */
|
void register_hit(cpArbiter *arb, gameobject *go, const char *name)
|
||||||
int script_phys_cb_begin(cpArbiter *arb, cpSpace *space, gameobject *go)
|
|
||||||
{
|
{
|
||||||
if (!arb_valid(arb)) return 1;
|
if (JS_IsUndefined(go->ref)) return;
|
||||||
|
JSValue cb = JS_GetPropertyStr(js, go->ref, name);
|
||||||
if (!JS_IsUndefined(go->cbs.begin) && cpSpaceAddPostStepCallback(space, phys_run_post, &go->cbs.begin, &go->cbs.bhit))
|
if (!JS_IsUndefined(cb)) {
|
||||||
go->cbs.bhit = arb2js(arb);
|
JSValue jarb = arb2js(arb);
|
||||||
|
fns[cb_idx] = JS_DupValue(js, cb);
|
||||||
cpShape *shape1;
|
hits[cb_idx] = jarb;
|
||||||
cpShape *shape2;
|
cpSpaceAddPostStepCallback(space, phys_run_post, &fns[cb_idx], &hits[cb_idx]);
|
||||||
cpArbiterGetShapes(arb, &shape1, &shape2);
|
cb_idx++;
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void script_phys_cb_separate(cpArbiter *arb, cpSpace *space, gameobject *go)
|
cpShape *s1, *s2;
|
||||||
{
|
cpArbiterGetShapes(arb, &s1, &s2);
|
||||||
if (!arb_valid(arb)) return;
|
gameobject *g1, *g2;
|
||||||
if (JS_IsUndefined(go->cbs.separate)) return;
|
g1 = shape2go(s1);
|
||||||
go->cbs.shit = arb2js(arb);
|
g2 = shape2go(g2);
|
||||||
cpSpaceAddPostStepCallback(space, phys_run_post, &go->cbs.separate, &go->cbs.shit);
|
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) {
|
int script_phys_cb_begin(cpArbiter *arb, cpSpace *space, gameobject *go) { register_hit(arb, go, "collide"); return 1; }
|
||||||
cpCollisionHandler *handler = cpSpaceAddWildcardHandler(space, (cpCollisionType)go);
|
void script_phys_cb_separate(cpArbiter *arb, cpSpace *space, gameobject *go) { register_hit(arb, go, "separate"); }
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void phys2d_setup_handlers(gameobject *go) {
|
void phys2d_setup_handlers(gameobject *go) {
|
||||||
cpCollisionHandler *handler = cpSpaceAddWildcardHandler(space, (cpCollisionType)go);
|
cpCollisionHandler *handler = cpSpaceAddWildcardHandler(space, (cpCollisionType)go);
|
||||||
|
@ -695,16 +612,3 @@ void phys2d_setup_handlers(gameobject *go) {
|
||||||
handler->beginFunc = script_phys_cb_begin;
|
handler->beginFunc = script_phys_cb_begin;
|
||||||
handler->separateFunc = script_phys_cb_separate;
|
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 {
|
struct phys2d_shape {
|
||||||
cpShape *shape; /* user data is this phys2d_shape */
|
cpShape *shape; /* user data is this phys2d_shape */
|
||||||
|
JSValue ref;
|
||||||
transform2d t;
|
transform2d t;
|
||||||
gameobject *go;
|
gameobject *go;
|
||||||
void *data; /* The specific subtype; phys2d_circle, etc */
|
void *data; /* The specific subtype; phys2d_circle, etc */
|
||||||
|
@ -47,6 +48,8 @@ struct phys2d_circle {
|
||||||
struct phys2d_shape shape;
|
struct phys2d_shape shape;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
typedef struct phys2d_circle circle2d;
|
||||||
|
|
||||||
/* A convex polygon; defined as the convex hull around the given set of points */
|
/* A convex polygon; defined as the convex hull around the given set of points */
|
||||||
struct phys2d_poly {
|
struct phys2d_poly {
|
||||||
HMM_Vec2 *points;
|
HMM_Vec2 *points;
|
||||||
|
@ -66,6 +69,7 @@ struct phys2d_edge {
|
||||||
|
|
||||||
struct phys2d_circle *Make2DCircle(gameobject *go);
|
struct phys2d_circle *Make2DCircle(gameobject *go);
|
||||||
void phys2d_circledel(struct phys2d_circle *c);
|
void phys2d_circledel(struct phys2d_circle *c);
|
||||||
|
void circle2d_free(circle2d *c);
|
||||||
void phys2d_applycircle(struct phys2d_circle *circle);
|
void phys2d_applycircle(struct phys2d_circle *circle);
|
||||||
void phys2d_dbgdrawcircle(struct phys2d_circle *circle);
|
void phys2d_dbgdrawcircle(struct phys2d_circle *circle);
|
||||||
float phys2d_circle_moi(struct phys2d_circle *c);
|
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_init();
|
||||||
void phys2d_update(float deltaT);
|
void phys2d_update(float deltaT);
|
||||||
cpShape *phys2d_query_pos(cpVect pos);
|
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 shape_cb {
|
||||||
struct phys2d_shape *shape;
|
struct phys2d_shape *shape;
|
||||||
|
@ -108,7 +112,6 @@ struct shape_cb {
|
||||||
|
|
||||||
void fire_hits();
|
void fire_hits();
|
||||||
|
|
||||||
void phys2d_rm_go_handlers(gameobject *go);
|
|
||||||
void phys2d_set_gravity(HMM_Vec2 v);
|
void phys2d_set_gravity(HMM_Vec2 v);
|
||||||
|
|
||||||
void shape_enabled(struct phys2d_shape *shape, int enabled);
|
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 shape_gui(struct phys2d_shape *shape);
|
||||||
void phys2d_setup_handlers(gameobject *go);
|
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);
|
int query_point(HMM_Vec2 pos);
|
||||||
|
|
||||||
void flush_collide_cbs();
|
|
||||||
|
|
||||||
void phys2d_reindex_body(cpBody *body);
|
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
|
#endif
|
||||||
|
|
|
@ -167,7 +167,9 @@ sg_buffer texcoord_floats(float *f, int verts, int comp)
|
||||||
|
|
||||||
return sg_make_buffer(&(sg_buffer_desc){
|
return sg_make_buffer(&(sg_buffer_desc){
|
||||||
.data.ptr = packed,
|
.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)
|
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){
|
return sg_make_buffer(&(sg_buffer_desc){
|
||||||
.data.ptr = packed_norms,
|
.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)
|
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){
|
mesh->bind.index_buffer = sg_make_buffer(&(sg_buffer_desc){
|
||||||
.data.ptr = idxs,
|
.data.ptr = idxs,
|
||||||
.data.size = sizeof(uint16_t) * c,
|
.data.size = sizeof(uint16_t) * c,
|
||||||
.type = SG_BUFFERTYPE_INDEXBUFFER});
|
.type = SG_BUFFERTYPE_INDEXBUFFER,
|
||||||
|
.label = "mesh index buffer",
|
||||||
|
});
|
||||||
|
|
||||||
mesh->idx_count = c;
|
mesh->idx_count = c;
|
||||||
} else {
|
} else {
|
||||||
|
@ -233,7 +239,9 @@ void mesh_add_primitive(mesh *mesh, cgltf_primitive *prim)
|
||||||
case cgltf_attribute_type_position:
|
case cgltf_attribute_type_position:
|
||||||
mesh->bind.vertex_buffers[0] = sg_make_buffer(&(sg_buffer_desc){
|
mesh->bind.vertex_buffers[0] = sg_make_buffer(&(sg_buffer_desc){
|
||||||
.data.ptr = vs,
|
.data.ptr = vs,
|
||||||
.data.size = sizeof(float) * n});
|
.data.size = sizeof(float) * n,
|
||||||
|
.label = "mesh vert buffer"
|
||||||
|
});
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case cgltf_attribute_type_normal:
|
case cgltf_attribute_type_normal:
|
||||||
|
@ -369,11 +377,10 @@ struct model *MakeModel(const char *path)
|
||||||
/* eye position */
|
/* eye position */
|
||||||
HMM_Vec3 eye = {0,0,100};
|
HMM_Vec3 eye = {0,0,100};
|
||||||
|
|
||||||
void draw_model(struct model *model, HMM_Mat4 amodel) {
|
void draw_model(struct model *model, HMM_Mat4 amodel, HMM_Mat4 *proj) {
|
||||||
HMM_Mat4 proj = projection;
|
|
||||||
HMM_Vec3 center = {0.f, 0.f, 0.f};
|
HMM_Vec3 center = {0.f, 0.f, 0.f};
|
||||||
HMM_Mat4 view = HMM_LookAt_RH(eye, center, vUP);
|
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));
|
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;
|
if (!dm->model) return;
|
||||||
struct gameobject *go = dm->go;
|
struct gameobject *go = dm->go;
|
||||||
HMM_Mat4 rst = t3d_go2world(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;
|
int rm;
|
||||||
for (int i = 0; i < arrlen(models); i++)
|
for (int i = 0; i < arrlen(models); i++)
|
||||||
if (models[i] == dm) {
|
if (models[i] == dm) {
|
||||||
|
|
|
@ -28,11 +28,11 @@ typedef struct model {
|
||||||
} model;
|
} model;
|
||||||
|
|
||||||
/* A model with draw information */
|
/* A model with draw information */
|
||||||
struct drawmodel {
|
typedef struct drawmodel {
|
||||||
struct model *model;
|
struct model *model;
|
||||||
HMM_Mat4 amodel;
|
HMM_Mat4 amodel;
|
||||||
gameobject *go;
|
gameobject *go;
|
||||||
};
|
} drawmodel;
|
||||||
|
|
||||||
typedef struct bone {
|
typedef struct bone {
|
||||||
transform3d t;
|
transform3d t;
|
||||||
|
@ -53,7 +53,7 @@ void model_init();
|
||||||
struct drawmodel *make_drawmodel(gameobject *go);
|
struct drawmodel *make_drawmodel(gameobject *go);
|
||||||
void draw_drawmodel(struct drawmodel *dm);
|
void draw_drawmodel(struct drawmodel *dm);
|
||||||
void model_draw_all();
|
void model_draw_all();
|
||||||
void free_drawmodel(struct drawmodel *dm);
|
void drawmodel_free(struct drawmodel *dm);
|
||||||
|
|
||||||
material *material_make();
|
material *material_make();
|
||||||
void material_free(material *mat);
|
void material_free(material *mat);
|
||||||
|
|
|
@ -2,7 +2,6 @@
|
||||||
|
|
||||||
#define SOKOL_TRACE_HOOKS
|
#define SOKOL_TRACE_HOOKS
|
||||||
#define SOKOL_IMPL
|
#define SOKOL_IMPL
|
||||||
#define SOKOL_NO_ENTRY
|
|
||||||
#include "sokol/sokol_audio.h"
|
#include "sokol/sokol_audio.h"
|
||||||
#include "sokol/sokol_time.h"
|
#include "sokol/sokol_time.h"
|
||||||
#include "sokol/sokol_args.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 "yugine.h"
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include "debug.h"
|
|
||||||
#include "window.h"
|
#include "window.h"
|
||||||
#include "2dphysics.h"
|
#include "2dphysics.h"
|
||||||
#include "stb_ds.h"
|
#include "stb_ds.h"
|
||||||
|
@ -21,7 +20,7 @@
|
||||||
|
|
||||||
#include "font.h"
|
#include "font.h"
|
||||||
|
|
||||||
#define v_amt 5000
|
#define v_amt 500000
|
||||||
|
|
||||||
struct flush {
|
struct flush {
|
||||||
sg_shader shader;
|
sg_shader shader;
|
||||||
|
@ -110,6 +109,26 @@ struct circle_vertex {
|
||||||
float fill;
|
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 */
|
/* Writes debug data to buffers, and draws */
|
||||||
void debug_flush(HMM_Mat4 *view)
|
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_apply_uniforms(SG_SHADERSTAGE_VS, 0, SG_RANGE_REF(*view));
|
||||||
sg_draw(circle_sc,4,circle_count);
|
sg_draw(circle_sc,4,circle_count);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
void debug_nextpass()
|
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void debug_newframe()
|
void debug_newframe()
|
||||||
|
@ -175,7 +176,7 @@ void debug_newframe()
|
||||||
}
|
}
|
||||||
|
|
||||||
static sg_shader_uniform_block_desc projection_ubo = {
|
static sg_shader_uniform_block_desc projection_ubo = {
|
||||||
.size = sizeof(projection),
|
.size = sizeof(useproj),
|
||||||
.uniforms = {
|
.uniforms = {
|
||||||
[0] = { .name = "proj", .type = SG_UNIFORMTYPE_MAT4 },
|
[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){
|
point_bind.vertex_buffers[0] = sg_make_buffer(&(sg_buffer_desc){
|
||||||
.size = sizeof(struct point_vertex)*v_amt,
|
.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()));
|
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){
|
line_bind.vertex_buffers[0] = sg_make_buffer(&(sg_buffer_desc){
|
||||||
.size = sizeof(struct line_vert)*v_amt,
|
.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){
|
line_bind.index_buffer = sg_make_buffer(&(sg_buffer_desc){
|
||||||
.size = sizeof(uint16_t)*v_amt,
|
.size = sizeof(uint16_t)*v_amt,
|
||||||
.usage = SG_USAGE_STREAM,
|
.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()));
|
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){
|
circle_bind.vertex_buffers[0] = sg_make_buffer(&(sg_buffer_desc){
|
||||||
.size = sizeof(struct circle_vertex)*v_amt,
|
.size = sizeof(struct circle_vertex)*v_amt,
|
||||||
.usage = SG_USAGE_STREAM,
|
.usage = SG_USAGE_STREAM,
|
||||||
|
.label = "circle vert buffer",
|
||||||
});
|
});
|
||||||
|
|
||||||
float circleverts[8] = {
|
float circleverts[8] = {
|
||||||
|
@ -277,6 +282,7 @@ void debugdraw_init()
|
||||||
circle_bind.vertex_buffers[1] = sg_make_buffer(&(sg_buffer_desc){
|
circle_bind.vertex_buffers[1] = sg_make_buffer(&(sg_buffer_desc){
|
||||||
.data = (sg_range){.ptr = circleverts, .size = sizeof(float)*8},
|
.data = (sg_range){.ptr = circleverts, .size = sizeof(float)*8},
|
||||||
.usage = SG_USAGE_IMMUTABLE,
|
.usage = SG_USAGE_IMMUTABLE,
|
||||||
|
.label = "circle quarter buffer",
|
||||||
});
|
});
|
||||||
|
|
||||||
grid_shader = sg_make_shader(grid_shader_desc(sg_query_backend()));
|
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,
|
.size = sizeof(struct poly_vertex)*v_amt,
|
||||||
.usage = SG_USAGE_STREAM,
|
.usage = SG_USAGE_STREAM,
|
||||||
.type = SG_BUFFERTYPE_VERTEXBUFFER,
|
.type = SG_BUFFERTYPE_VERTEXBUFFER,
|
||||||
|
.label = "poly vert buffer",
|
||||||
});
|
});
|
||||||
|
|
||||||
poly_bind.index_buffer = sg_make_buffer(&(sg_buffer_desc){
|
poly_bind.index_buffer = sg_make_buffer(&(sg_buffer_desc){
|
||||||
.size = sizeof(uint32_t)*6*v_amt,
|
.size = sizeof(uint32_t)*6*v_amt,
|
||||||
.usage = SG_USAGE_STREAM,
|
.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
|
.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.vertex_buffers[0], &vr);
|
||||||
sg_append_buffer(line_bind.index_buffer, &ir);
|
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 */
|
/* 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;
|
int closed = 0;
|
||||||
if (thickness <= 1) {
|
if (thickness <= 0) {
|
||||||
draw_line(points,n,line_color,0,0);
|
draw_line(points,n,line_color,0,0);
|
||||||
return;
|
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)
|
void draw_grid(float width, float span, struct rgba color)
|
||||||
{
|
{
|
||||||
HMM_Vec2 offset = (HMM_Vec2)cam_pos();
|
HMM_Vec2 offset = campos;
|
||||||
offset = HMM_MulV2F(offset, 1/cam_zoom());
|
offset = HMM_MulV2F(offset, 1/camzoom);
|
||||||
|
|
||||||
float ubo[4];
|
float ubo[4];
|
||||||
ubo[0] = offset.x;
|
ubo[0] = offset.x;
|
||||||
|
@ -563,7 +572,7 @@ void draw_grid(float width, float span, struct rgba color)
|
||||||
|
|
||||||
fs_params_t pt;
|
fs_params_t pt;
|
||||||
pt.thickness = (float)width;
|
pt.thickness = (float)width;
|
||||||
pt.span = span/cam_zoom();
|
pt.span = span/camzoom;
|
||||||
memcpy(&pt.color, col, sizeof(float)*4);
|
memcpy(&pt.color, col, sizeof(float)*4);
|
||||||
sg_apply_uniforms(SG_SHADERSTAGE_VS, 0, SG_RANGE_REF(ubo));
|
sg_apply_uniforms(SG_SHADERSTAGE_VS, 0, SG_RANGE_REF(ubo));
|
||||||
sg_apply_uniforms(SG_SHADERSTAGE_FS, 0, SG_RANGE_REF(pt));
|
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_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_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 */
|
/* 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);
|
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_flush(HMM_Mat4 *view);
|
||||||
void debug_newframe();
|
void debug_newframe();
|
||||||
void debug_nextpass();
|
|
||||||
|
|
||||||
HMM_Vec2 *inflatepoints(HMM_Vec2 *p, float d, int n);
|
HMM_Vec2 *inflatepoints(HMM_Vec2 *p, float d, int n);
|
||||||
|
|
||||||
|
|
|
@ -7,22 +7,52 @@
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
#include <signal.h>
|
||||||
|
#include <fcntl.h>
|
||||||
#include "yugine.h"
|
#include "yugine.h"
|
||||||
#include "resources.h"
|
#include "resources.h"
|
||||||
|
#include "quickjs/quickjs.h"
|
||||||
|
|
||||||
#include "script.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 *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"};
|
char *catstr[] = {"engine", "script", "render"};
|
||||||
|
|
||||||
static FILE *logout; /* where logs are written to */
|
static FILE *logout; /* where logs are written to */
|
||||||
static FILE *writeout; /* where console is 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()
|
void log_init()
|
||||||
{
|
{
|
||||||
#ifndef NDEBUG
|
#ifndef NDEBUG
|
||||||
|
if (!fexists(".prosperon")) {
|
||||||
|
logout = tmpfile();
|
||||||
|
dump = tmpfile();
|
||||||
|
writeout = stdout;
|
||||||
|
}
|
||||||
|
else {
|
||||||
logout = fopen(".prosperon/log.txt", "w");
|
logout = fopen(".prosperon/log.txt", "w");
|
||||||
writeout = fopen(".prosperon/transcript.txt", "w");
|
writeout = fopen(".prosperon/transcript.txt", "w");
|
||||||
|
dump = fopen(".prosperon/quickjs.txt", "w");
|
||||||
|
quickjs_set_dumpout(dump);
|
||||||
|
}
|
||||||
|
|
||||||
|
quickjs_set_dumpout(dump);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -30,6 +60,7 @@ void log_shutdown()
|
||||||
{
|
{
|
||||||
fclose(logout);
|
fclose(logout);
|
||||||
fclose(writeout);
|
fclose(writeout);
|
||||||
|
fclose(dump);
|
||||||
}
|
}
|
||||||
|
|
||||||
const char *logfmt = "%s:%d: [%s] %s, %s: ";
|
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);
|
va_end(args);
|
||||||
fprintf(logout, "\n");
|
fprintf(logout, "\n");
|
||||||
|
|
||||||
if (priority == LOG_DEBUG) {
|
if (priority == LOG_DEBUG || priority >= stdout_lvl) {
|
||||||
printf(logfmt, file, line, timebuf, logstr[priority], catstr[category]);
|
printf(logfmt, file, line, timebuf, logcolor[priority], catstr[category]);
|
||||||
va_list args;
|
va_list args;
|
||||||
va_start(args,message);
|
va_start(args,message);
|
||||||
vprintf(message, args);
|
vprintf(message, args);
|
||||||
va_end(args);
|
va_end(args);
|
||||||
printf("\n");
|
printf("\n");
|
||||||
fflush(stdout);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (priority >= LOG_PANIC) {
|
||||||
|
js_stacktrace();
|
||||||
|
#ifdef __WIN32
|
||||||
|
DebugBreak();
|
||||||
|
#else
|
||||||
|
raise(SIGTRAP);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -67,7 +107,6 @@ void log_print(const char *str)
|
||||||
#ifndef NDEBUG
|
#ifndef NDEBUG
|
||||||
fprintf(writeout, str);
|
fprintf(writeout, str);
|
||||||
#endif
|
#endif
|
||||||
printf(str);
|
|
||||||
fflush(stdout);
|
fflush(stdout);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -18,6 +18,8 @@
|
||||||
void log_init();
|
void log_init();
|
||||||
void log_shutdown();
|
void log_shutdown();
|
||||||
|
|
||||||
|
extern int stdout_lvl;
|
||||||
|
|
||||||
#ifndef NDEBUG
|
#ifndef NDEBUG
|
||||||
#define YughLog(cat, pri, msg, ...) mYughLog(cat, pri, __LINE__, __FILE__, msg, ##__VA_ARGS__)
|
#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__);
|
#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__);
|
#define YughCritical(msg, ...) mYughLog(0, LOG_PANIC, __LINE__, __FILE__, msg, ##__VA_ARGS__);
|
||||||
#else
|
#else
|
||||||
#define YughLog(cat, pri, msg, ...)
|
#define YughLog(cat, pri, msg, ...)
|
||||||
|
#define YughSpam(msg,...)
|
||||||
#define YughInfo(msg, ...)
|
#define YughInfo(msg, ...)
|
||||||
#define YughWarn(msg, ...)
|
#define YughWarn(msg, ...)
|
||||||
#define YughError(msg, ...)
|
#define YughError(msg, ...)
|
||||||
|
|
|
@ -17,18 +17,12 @@
|
||||||
#include "stb_image_write.h"
|
#include "stb_image_write.h"
|
||||||
#include "stb_rect_pack.h"
|
#include "stb_rect_pack.h"
|
||||||
#include "stb_truetype.h"
|
#include "stb_truetype.h"
|
||||||
#include "stb_ds.h"
|
|
||||||
|
|
||||||
#include "HandmadeMath.h"
|
#include "HandmadeMath.h"
|
||||||
|
|
||||||
struct sFont *font;
|
struct sFont *use_font;
|
||||||
|
|
||||||
static struct {
|
#define max_chars 100000
|
||||||
char *key;
|
|
||||||
struct sFont *value;
|
|
||||||
} *fonthash = NULL;
|
|
||||||
|
|
||||||
#define max_chars 10000
|
|
||||||
|
|
||||||
static sg_shader fontshader;
|
static sg_shader fontshader;
|
||||||
static sg_bindings bind_text;
|
static sg_bindings bind_text;
|
||||||
|
@ -74,7 +68,8 @@ void font_init() {
|
||||||
|
|
||||||
bind_text.vertex_buffers[1] = sg_make_buffer(&(sg_buffer_desc){
|
bind_text.vertex_buffers[1] = sg_make_buffer(&(sg_buffer_desc){
|
||||||
.data = SG_RANGE(text_verts),
|
.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){
|
bind_text.vertex_buffers[0] = sg_make_buffer(&(sg_buffer_desc){
|
||||||
|
@ -84,31 +79,19 @@ void font_init() {
|
||||||
.label = "text buffer"
|
.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){});
|
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);
|
sg_destroy_image(f->texID);
|
||||||
int index = shgeti(fonthash, path);
|
free(f);
|
||||||
if (index != -1) {
|
|
||||||
if (font == fonthash[index].value) return;
|
|
||||||
font = fonthash[index].value;
|
|
||||||
bind_text.fs.images[0] = font->texID;
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
struct sFont *newfont = MakeFont(path, 8);
|
void font_set(font *f)
|
||||||
if (!newfont) {
|
{
|
||||||
YughError("Could not make font from %s.", path);
|
use_font = f;
|
||||||
return;
|
bind_text.fs.images[0] = f->texID;
|
||||||
}
|
|
||||||
|
|
||||||
font = newfont;
|
|
||||||
shput(fonthash, path, newfont);
|
|
||||||
bind_text.fs.images[0] = font->texID;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
struct sFont *MakeSDFFont(const char *fontfile, int height)
|
struct sFont *MakeSDFFont(const char *fontfile, int height)
|
||||||
|
@ -145,6 +128,10 @@ struct sFont *MakeFont(const char *fontfile, int height) {
|
||||||
newfont->height = height;
|
newfont->height = height;
|
||||||
|
|
||||||
unsigned char *ttf_buffer = slurp_file(fontfile, NULL);
|
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);
|
unsigned char *bitmap = malloc(packsize * packsize);
|
||||||
|
|
||||||
stbtt_packedchar glyphs[95];
|
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);
|
stbtt_GetFontVMetrics(&fontinfo, &newfont->ascent, &newfont->descent, &newfont->linegap);
|
||||||
newfont->emscale = stbtt_ScaleForMappingEmToPixels(&fontinfo, 16);
|
//newfont->emscale = stbtt_ScaleForMappingEmToPixels(&fontinfo, 16);
|
||||||
newfont->linegap = (newfont->ascent - newfont->descent) * newfont->emscale;
|
newfont->emscale = stbtt_ScaleForPixelHeight(&fontinfo, height);
|
||||||
|
newfont->linegap = (newfont->ascent - newfont->descent) * newfont->emscale*1.5;
|
||||||
|
|
||||||
newfont->texID = sg_make_image(&(sg_image_desc){
|
newfont->texID = sg_make_image(&(sg_image_desc){
|
||||||
.type = SG_IMAGETYPE_2D,
|
.type = SG_IMAGETYPE_2D,
|
||||||
|
@ -174,8 +162,9 @@ struct sFont *MakeFont(const char *fontfile, int height) {
|
||||||
.usage = SG_USAGE_IMMUTABLE,
|
.usage = SG_USAGE_IMMUTABLE,
|
||||||
.data.subimage[0][0] = {
|
.data.subimage[0][0] = {
|
||||||
.ptr = bitmap,
|
.ptr = bitmap,
|
||||||
.size = packsize * packsize}});
|
.size = packsize * packsize
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
for (unsigned char c = 32; c < 127; c++) {
|
for (unsigned char c = 32; c < 127; c++) {
|
||||||
stbtt_packedchar glyph = glyphs[c - 32];
|
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)
|
void draw_underline_cursor(HMM_Vec2 pos, float scale, struct rgba color)
|
||||||
{
|
{
|
||||||
pos.Y -= 2;
|
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)
|
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) {
|
void sdrawCharacter(struct Character c, HMM_Vec2 cursor, float scale, struct rgba color) {
|
||||||
if (curchar+1 >= max_chars)
|
if (curchar-10 >= max_chars)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
struct rgba colorbox = {0,0,0,255};
|
struct rgba colorbox = {0,0,0,255};
|
||||||
|
@ -270,10 +259,6 @@ void sdrawCharacter(struct Character c, HMM_Vec2 cursor, float scale, struct rgb
|
||||||
curchar++;
|
curchar++;
|
||||||
}
|
}
|
||||||
|
|
||||||
void text_settype(struct sFont *mfont) {
|
|
||||||
font = mfont;
|
|
||||||
}
|
|
||||||
|
|
||||||
const char *esc_color(const char *c, struct rgba *color, struct rgba defc)
|
const char *esc_color(const char *c, struct rgba *color, struct rgba defc)
|
||||||
{
|
{
|
||||||
struct rgba d;
|
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)
|
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;
|
struct rgba dummy;
|
||||||
HMM_Vec2 cursor = {0,0};
|
HMM_Vec2 cursor = {0,0};
|
||||||
const char *line, *wordstart;
|
const char *line, *wordstart;
|
||||||
|
@ -310,10 +296,10 @@ struct boundingbox text_bb(const char *text, float scale, float lw, float tracki
|
||||||
|
|
||||||
while (*line != '\0') {
|
while (*line != '\0') {
|
||||||
if (isblank(*line)) {
|
if (isblank(*line)) {
|
||||||
cursor.X += font->Characters[*line].Advance * tracking * scale;
|
cursor.X += use_font->Characters[*line].Advance * tracking * scale;
|
||||||
line++;
|
line++;
|
||||||
} else if (isspace(*line)) {
|
} else if (isspace(*line)) {
|
||||||
cursor.Y -= scale * font->linegap;
|
cursor.Y -= scale * use_font->linegap;
|
||||||
cursor.X = 0;
|
cursor.X = 0;
|
||||||
line++;
|
line++;
|
||||||
} else {
|
} else {
|
||||||
|
@ -324,26 +310,26 @@ struct boundingbox text_bb(const char *text, float scale, float lw, float tracki
|
||||||
int wordWidth = 0;
|
int wordWidth = 0;
|
||||||
|
|
||||||
while (!isspace(*line) && *line != '\0') {
|
while (!isspace(*line) && *line != '\0') {
|
||||||
wordWidth += font->Characters[*line].Advance * tracking * scale;
|
wordWidth += use_font->Characters[*line].Advance * tracking * scale;
|
||||||
line++;
|
line++;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (lw > 0 && (cursor.X + wordWidth) >= lw) {
|
if (lw > 0 && (cursor.X + wordWidth) >= lw) {
|
||||||
cursor.X = 0;
|
cursor.X = 0;
|
||||||
cursor.Y -= scale * font->linegap;
|
cursor.Y -= scale * use_font->linegap;
|
||||||
}
|
}
|
||||||
|
|
||||||
while (wordstart < line) {
|
while (wordstart < line) {
|
||||||
if (*wordstart == '\e')
|
if (*wordstart == '\e')
|
||||||
line = esc_color(wordstart, NULL, dummy);
|
line = esc_color(wordstart, NULL, dummy);
|
||||||
|
|
||||||
cursor.X += font->Characters[*wordstart].Advance * tracking * scale;
|
cursor.X += use_font->Characters[*wordstart].Advance * tracking * scale;
|
||||||
wordstart++;
|
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)
|
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 */
|
/* pos given in screen coordinates */
|
||||||
int renderText(const char *text, HMM_Vec2 pos, float scale, struct rgba color, float lw, int caret, float tracking) {
|
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);
|
int len = strlen(text);
|
||||||
|
|
||||||
HMM_Vec2 cursor = pos;
|
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') {
|
while (*line != '\0') {
|
||||||
if (isblank(*line)) {
|
if (isblank(*line)) {
|
||||||
sdrawCharacter(font->Characters[*line], cursor, scale, usecolor);
|
sdrawCharacter(use_font->Characters[*line], cursor, scale, usecolor);
|
||||||
cursor.X += font->Characters[*line].Advance * tracking * scale;
|
cursor.X += use_font->Characters[*line].Advance * tracking * scale;
|
||||||
line++;
|
line++;
|
||||||
check_caret(caret, line-drawstart, cursor, scale, usecolor);
|
check_caret(caret, line-drawstart, cursor, scale, usecolor);
|
||||||
} else if (isspace(*line)) {
|
} else if (isspace(*line)) {
|
||||||
sdrawCharacter(font->Characters[*line], cursor, scale, usecolor);
|
sdrawCharacter(use_font->Characters[*line], cursor, scale, usecolor);
|
||||||
cursor.Y -= scale * font->linegap;
|
cursor.Y -= scale * use_font->linegap;
|
||||||
cursor.X = pos.X;
|
cursor.X = pos.X;
|
||||||
line++;
|
line++;
|
||||||
check_caret(caret, line-drawstart, cursor, scale, usecolor);
|
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') {
|
while (!isspace(*line) && *line != '\0') {
|
||||||
|
|
||||||
wordWidth += font->Characters[*line].Advance * tracking * scale;
|
wordWidth += use_font->Characters[*line].Advance * tracking * scale;
|
||||||
line++;
|
line++;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (lw > 0 && (cursor.X + wordWidth - pos.X) >= lw) {
|
if (lw > 0 && (cursor.X + wordWidth - pos.X) >= lw) {
|
||||||
cursor.X = pos.X;
|
cursor.X = pos.X;
|
||||||
cursor.Y -= scale * font->linegap;
|
cursor.Y -= scale * use_font->linegap;
|
||||||
}
|
}
|
||||||
|
|
||||||
while (wordstart < line) {
|
while (wordstart < line) {
|
||||||
if (*wordstart == '\e')
|
if (*wordstart == '\e')
|
||||||
wordstart = esc_color(wordstart, &usecolor, color);
|
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(use_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], cursor, scale, usecolor);
|
||||||
|
|
||||||
cursor.X += font->Characters[*wordstart].Advance * tracking * scale;
|
cursor.X += use_font->Characters[*wordstart].Advance * tracking * scale;
|
||||||
wordstart++;
|
wordstart++;
|
||||||
check_caret(caret, wordstart-drawstart, cursor, scale, usecolor);
|
check_caret(caret, wordstart-drawstart, cursor, scale, usecolor);
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,9 +28,13 @@ struct sFont {
|
||||||
sg_image texID;
|
sg_image texID;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
typedef struct sFont font;
|
||||||
|
|
||||||
|
void font_free(font *f);
|
||||||
|
|
||||||
void font_init();
|
void font_init();
|
||||||
struct sFont *MakeFont(const char *fontfile, int height);
|
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 sdrawCharacter(struct Character c, HMM_Vec2 cursor, float scale, struct rgba color);
|
||||||
void text_settype(struct sFont *font);
|
void text_settype(struct sFont *font);
|
||||||
struct boundingbox text_bb(const char *text, float scale, float lw, float tracking);
|
struct boundingbox text_bb(const char *text, float scale, float lw, float tracking);
|
||||||
|
|
|
@ -8,12 +8,12 @@
|
||||||
|
|
||||||
#include "stb_ds.h"
|
#include "stb_ds.h"
|
||||||
|
|
||||||
static gameobject **gameobjects;
|
|
||||||
|
|
||||||
int go_count() { return arrlen(gameobjects); }
|
|
||||||
|
|
||||||
gameobject *body2go(cpBody *body) { return cpBodyGetUserData(body); }
|
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)
|
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_go2world(gameobject *go) { return transform3d2mat(go2t3(go)); }
|
||||||
HMM_Mat4 t3d_world2go(gameobject *go) { return HMM_InvGeneralM4(t3d_go2world(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 go2t(gameobject *go)
|
||||||
{
|
{
|
||||||
transform2d t;
|
transform2d t;
|
||||||
|
@ -72,17 +55,15 @@ transform2d go2t(gameobject *go)
|
||||||
return t;
|
return t;
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned int editor_cat = 1<<31;
|
|
||||||
|
|
||||||
void go_shape_apply(cpBody *body, cpShape *shape, gameobject *go) {
|
void go_shape_apply(cpBody *body, cpShape *shape, gameobject *go) {
|
||||||
cpShapeSetFriction(shape, go->f);
|
cpShapeSetFriction(shape, go->friction);
|
||||||
cpShapeSetElasticity(shape, go->e);
|
cpShapeSetElasticity(shape, go->elasticity);
|
||||||
cpShapeSetCollisionType(shape, (cpCollisionType)go);
|
cpShapeSetCollisionType(shape, (cpCollisionType)go);
|
||||||
|
|
||||||
cpShapeFilter filter;
|
cpShapeFilter filter;
|
||||||
filter.group = (cpCollisionType)go;
|
filter.group = (cpCollisionType)go;
|
||||||
filter.categories = 1<<go->layer | editor_cat;
|
filter.categories = go->categories;
|
||||||
filter.mask = category_masks[go->layer] | editor_cat;
|
filter.mask = go->mask;
|
||||||
// filter.mask = CP_ALL_CATEGORIES;
|
// filter.mask = CP_ALL_CATEGORIES;
|
||||||
cpShapeSetFilter(shape, filter);
|
cpShapeSetFilter(shape, filter);
|
||||||
|
|
||||||
|
@ -105,18 +86,17 @@ void go_shape_moi(cpBody *body, cpShape *shape, gameobject *go) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void gameobject_apply(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);
|
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);
|
cpBodySetMass(go->body, go->mass);
|
||||||
cpBodySetMoment(go->body, 0.f);
|
cpBodySetMoment(go->body, 0.f);
|
||||||
cpBodyEachShape(go->body, go_shape_moi, go);
|
cpBodyEachShape(go->body, go_shape_moi, go);
|
||||||
|
|
||||||
if (cpBodyGetMoment(go->body) <= 0.f)
|
if (cpBodyGetMoment(go->body) <= 0.f)
|
||||||
cpBodySetMoment(go->body, 1.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);
|
gameobject *go = body2go(body);
|
||||||
cpVect pos = cpBodyGetPosition(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) {
|
if (!go) {
|
||||||
cpBodyUpdateVelocity(body,g.cp,damping,dt);
|
cpBodyUpdateVelocity(body,g.cp,damping,dt);
|
||||||
return;
|
return;
|
||||||
|
@ -149,40 +129,43 @@ gameobject *MakeGameobject() {
|
||||||
gameobject *ngo = malloc(sizeof(*ngo));
|
gameobject *ngo = malloc(sizeof(*ngo));
|
||||||
gameobject go = {
|
gameobject go = {
|
||||||
.scale = (HMM_Vec3){1.f,1.f,1.f},
|
.scale = (HMM_Vec3){1.f,1.f,1.f},
|
||||||
.bodytype = CP_BODY_TYPE_STATIC,
|
.phys = CP_BODY_TYPE_STATIC,
|
||||||
.maxvelocity = INFINITY,
|
.maxvelocity = INFINITY,
|
||||||
.maxangularvelocity = INFINITY,
|
.maxangularvelocity = INFINITY,
|
||||||
.mass = 1.f,
|
.mass = 1.f,
|
||||||
.next = -1,
|
.next = -1,
|
||||||
.drawlayer = 0,
|
.drawlayer = 0,
|
||||||
.shape_cbs = NULL,
|
|
||||||
.damping = INFINITY,
|
.damping = INFINITY,
|
||||||
.timescale = 1.0,
|
.timescale = 1.0,
|
||||||
.ref = JS_UNDEFINED,
|
.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));
|
go.body = cpSpaceAddBody(space, cpBodyNew(go.mass, 1.f));
|
||||||
cpBodySetVelocityUpdateFunc(go.body, velocityFn);
|
cpBodySetVelocityUpdateFunc(go.body, velocityFn);
|
||||||
|
|
||||||
*ngo = go;
|
*ngo = go;
|
||||||
cpBodySetUserData(go.body, ngo);
|
cpBodySetUserData(go.body, ngo);
|
||||||
phys2d_setup_handlers(ngo);
|
phys2d_setup_handlers(ngo);
|
||||||
arrpush(gameobjects, ngo);
|
|
||||||
return ngo;
|
return ngo;
|
||||||
}
|
}
|
||||||
|
|
||||||
void rm_body_shapes(cpBody *body, cpShape *shape, void *data) {
|
void rm_body_shapes(cpBody *body, cpShape *shape, void *data) {
|
||||||
struct phys2d_shape *s = cpShapeGetUserData(shape);
|
struct phys2d_shape *s = cpShapeGetUserData(shape);
|
||||||
|
|
||||||
if (s) {
|
if (s) {
|
||||||
|
JS_FreeValue(js, s->ref);
|
||||||
|
s->ref = JS_UNDEFINED;
|
||||||
if (s->free)
|
if (s->free)
|
||||||
s->free(s->data);
|
s->free(s->data);
|
||||||
else
|
else
|
||||||
free(s->data);
|
free(s->data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
cpShapeSetFilter(shape, CP_SHAPE_FILTER_NONE);
|
||||||
|
|
||||||
cpSpaceRemoveShape(space, shape);
|
cpSpaceRemoveShape(space, shape);
|
||||||
cpShapeFree(shape);
|
cpShapeFree(shape);
|
||||||
}
|
}
|
||||||
|
@ -193,22 +176,12 @@ void rm_body_constraints(cpBody *body, cpConstraint *constraint, void *data)
|
||||||
}
|
}
|
||||||
|
|
||||||
void gameobject_free(gameobject *go) {
|
void gameobject_free(gameobject *go) {
|
||||||
arrfree(go->shape_cbs);
|
|
||||||
go->ref = JS_UNDEFINED;
|
go->ref = JS_UNDEFINED;
|
||||||
cpBodyEachShape(go->body, rm_body_shapes, NULL);
|
cpBodyEachShape(go->body, rm_body_shapes, NULL);
|
||||||
cpBodyEachConstraint(go->body, rm_body_constraints, NULL);
|
cpBodyEachConstraint(go->body, rm_body_constraints, NULL);
|
||||||
cpSpaceRemoveBody(space, go->body);
|
cpSpaceRemoveBody(space, go->body);
|
||||||
cpBodyFree(go->body);
|
cpBodyFree(go->body);
|
||||||
|
|
||||||
go->body = NULL;
|
|
||||||
|
|
||||||
free(go);
|
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) {
|
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) {
|
void gameobject_draw_debug(gameobject *go) {
|
||||||
if (!go || !go->body) return;
|
if (!go || !go->body) return;
|
||||||
|
|
||||||
cpVect pos = cpBodyGetPosition(go->body);
|
|
||||||
cpBodyEachShape(go->body, body_draw_shapes_dbg, NULL);
|
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)
|
}while(0)
|
||||||
|
|
||||||
struct gameobject {
|
struct gameobject {
|
||||||
cpBodyType bodytype;
|
cpBodyType phys;
|
||||||
cpBody *body; /* NULL if this object is dead; has 2d position and rotation, relative to global 0 */
|
cpBody *body; /* NULL if this object is dead; has 2d position and rotation, relative to global 0 */
|
||||||
HMM_Vec3 scale; /* local */
|
HMM_Vec3 scale; /* local */
|
||||||
int next;
|
int next;
|
||||||
float mass;
|
float mass;
|
||||||
float f; /* friction */
|
float friction;
|
||||||
float e; /* elasticity */
|
float elasticity;
|
||||||
float damping;
|
float damping;
|
||||||
float timescale;
|
float timescale;
|
||||||
float maxvelocity;
|
float maxvelocity;
|
||||||
float maxangularvelocity;
|
float maxangularvelocity;
|
||||||
unsigned int layer;
|
unsigned int layer;
|
||||||
cpShapeFilter filter;
|
cpBitmask categories;
|
||||||
unsigned int warp_filter;
|
cpBitmask mask;
|
||||||
// warpmask warpmask;
|
unsigned int warp_mask;
|
||||||
struct phys_cbs cbs;
|
|
||||||
struct shape_cb *shape_cbs;
|
|
||||||
JSValue ref;
|
JSValue ref;
|
||||||
HMM_Mat4 world;
|
HMM_Mat4 world;
|
||||||
float drawlayer;
|
float drawlayer;
|
||||||
|
@ -67,7 +65,6 @@ struct gameobject {
|
||||||
typedef struct gameobject gameobject;
|
typedef struct gameobject gameobject;
|
||||||
|
|
||||||
gameobject *MakeGameobject();
|
gameobject *MakeGameobject();
|
||||||
int go_count();
|
|
||||||
void gameobject_apply(gameobject *go);
|
void gameobject_apply(gameobject *go);
|
||||||
void gameobject_free(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);
|
void go_shape_apply(cpBody *body, cpShape *shape, gameobject *go);
|
||||||
|
|
||||||
/* Tries a few methods to select a gameobject; if none is selected returns -1 */
|
/* 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_debug(gameobject *go);
|
||||||
void gameobject_draw_debugs();
|
|
||||||
#endif
|
#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_dropped_files(int n);
|
||||||
void input_clipboard_paste(char *str);
|
void input_clipboard_paste(char *str);
|
||||||
|
|
||||||
const char *keyname_extd(int key);
|
|
||||||
|
|
||||||
void quit();
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -3,7 +3,121 @@
|
||||||
|
|
||||||
#include "quickjs/quickjs.h"
|
#include "quickjs/quickjs.h"
|
||||||
#include "HandmadeMath.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_load();
|
||||||
void ffi_stop();
|
void ffi_stop();
|
||||||
|
@ -18,8 +132,7 @@ int js_print_exception(JSValue v);
|
||||||
struct rgba js2color(JSValue v);
|
struct rgba js2color(JSValue v);
|
||||||
double js2number(JSValue v);
|
double js2number(JSValue v);
|
||||||
JSValue number2js(double g);
|
JSValue number2js(double g);
|
||||||
JSValue int2js(int i);
|
JSValue str2js(const char *c, ...);
|
||||||
JSValue str2js(const char *c);
|
|
||||||
|
|
||||||
void nota_int(char *blob);
|
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){
|
par_bind.vertex_buffers[1] = sg_make_buffer(&(sg_buffer_desc){
|
||||||
.data = (sg_range){.ptr = circleverts, .size = sizeof(float)*8},
|
.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){});
|
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});
|
sampler_add(&e->color, 0, (HMM_Vec4){1,1,1,1});
|
||||||
e->scale = 1;
|
e->scale = 1;
|
||||||
e->speed = 20;
|
e->speed = 20;
|
||||||
e->texture = texture_from_file("glass_chunk2.gif");
|
e->texture = NULL;
|
||||||
arrpush(emitters,e);
|
arrpush(emitters,e);
|
||||||
return 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);
|
s = lerp(p->time/e->grow_for, 0, p->scale);
|
||||||
else if (p->time > (p->life - e->shrink_for))
|
else if (p->time > (p->life - e->shrink_for))
|
||||||
s = lerp((p->time-(p->life-e->shrink_for))/e->shrink_for, p->scale, 0);
|
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);
|
pv[i].color = vec2rgba(p->color);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void emitters_draw()
|
void emitters_draw(HMM_Mat4 *proj)
|
||||||
{
|
{
|
||||||
if (arrlen(emitters) == 0) return;
|
if (arrlen(emitters) == 0) return;
|
||||||
int draw_count = 0;
|
int draw_count = 0;
|
||||||
|
@ -188,7 +189,7 @@ void emitters_draw()
|
||||||
}
|
}
|
||||||
|
|
||||||
sg_apply_pipeline(par_pipe);
|
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_apply_bindings(&par_bind);
|
||||||
sg_draw(0, 4, draw_count);
|
sg_draw(0, 4, draw_count);
|
||||||
}
|
}
|
||||||
|
|
|
@ -70,7 +70,7 @@ void stop_emitter(emitter *e);
|
||||||
|
|
||||||
void emitter_emit(emitter *e, int count);
|
void emitter_emit(emitter *e, int count);
|
||||||
void emitters_step(double dt);
|
void emitters_step(double dt);
|
||||||
void emitters_draw();
|
void emitters_draw(HMM_Mat4 *proj);
|
||||||
void emitter_step(emitter *e, double dt);
|
void emitter_step(emitter *e, double dt);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -24,8 +24,13 @@
|
||||||
#include "sokol/sokol_gfx.h"
|
#include "sokol/sokol_gfx.h"
|
||||||
#include "sokol_gfx_ext.h"
|
#include "sokol_gfx_ext.h"
|
||||||
|
|
||||||
|
#include "crt.sglsl.h"
|
||||||
|
|
||||||
#include "msf_gif.h"
|
#include "msf_gif.h"
|
||||||
|
|
||||||
|
HMM_Vec2 campos = {0,0};
|
||||||
|
float camzoom = 1;
|
||||||
|
|
||||||
static struct {
|
static struct {
|
||||||
sg_swapchain swap;
|
sg_swapchain swap;
|
||||||
sg_pipeline pipe;
|
sg_pipeline pipe;
|
||||||
|
@ -35,6 +40,12 @@ static struct {
|
||||||
sg_image depth;
|
sg_image depth;
|
||||||
} sg_gif;
|
} sg_gif;
|
||||||
|
|
||||||
|
static struct {
|
||||||
|
sg_pipeline pipe;
|
||||||
|
sg_bindings bind;
|
||||||
|
sg_shader shader;
|
||||||
|
} sg_crt;
|
||||||
|
|
||||||
static struct {
|
static struct {
|
||||||
int w;
|
int w;
|
||||||
int h;
|
int h;
|
||||||
|
@ -110,143 +121,101 @@ void capture_screen(int x, int y, int w, int h, const char *path)
|
||||||
|
|
||||||
#include "HandmadeMath.h"
|
#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};
|
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};
|
sg_pass_action pass_action = {0};
|
||||||
|
|
||||||
static struct {
|
static struct {
|
||||||
sg_pass_action pass_action;
|
sg_pass_action pass_action;
|
||||||
|
|
||||||
sg_pass pass;
|
sg_pass pass;
|
||||||
sg_pipeline pipe;
|
sg_pipeline pipe;
|
||||||
sg_shader shader;
|
sg_shader shader;
|
||||||
} sg_shadow;
|
} 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)
|
void trace_apply_pipeline(sg_pipeline pip, void *data)
|
||||||
{
|
{
|
||||||
YughSpam("Applying pipeline %u %s.", pip, sg_query_pipeline_desc(pip).label);
|
// 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");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void trace_begin_pass(sg_pass pass, const sg_pass_action *action, void *data)
|
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 = {
|
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,
|
.apply_pipeline = trace_apply_pipeline,
|
||||||
.begin_pass = trace_begin_pass,
|
.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() {
|
void render_init() {
|
||||||
|
@ -285,7 +254,6 @@ void render_init() {
|
||||||
.label = "gif pipe",
|
.label = "gif pipe",
|
||||||
});
|
});
|
||||||
|
|
||||||
#if defined SOKOL_GLCORE33 || defined SOKOL_GLES3
|
|
||||||
float crt_quad[] = {
|
float crt_quad[] = {
|
||||||
-1, 1, 0, 1,
|
-1, 1, 0, 1,
|
||||||
-1, -1, 0, 0,
|
-1, -1, 0, 0,
|
||||||
|
@ -294,16 +262,7 @@ void render_init() {
|
||||||
1, -1, 1, 0,
|
1, -1, 1, 0,
|
||||||
1, 1, 1, 1
|
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[] = {
|
float gif_quad[] = {
|
||||||
-1, 1, 0, 1,
|
-1, 1, 0, 1,
|
||||||
-1, -1, 0, 0,
|
-1, -1, 0, 0,
|
||||||
|
@ -316,78 +275,35 @@ void render_init() {
|
||||||
sg_gif.bind.vertex_buffers[0] = sg_make_buffer(&(sg_buffer_desc){
|
sg_gif.bind.vertex_buffers[0] = sg_make_buffer(&(sg_buffer_desc){
|
||||||
.size = sizeof(gif_quad),
|
.size = sizeof(gif_quad),
|
||||||
.data = gif_quad,
|
.data = gif_quad,
|
||||||
|
.label = "gif vert buffer",
|
||||||
});
|
});
|
||||||
sg_gif.bind.fs.samplers[0] = sg_make_sampler(&(sg_sampler_desc){});
|
sg_gif.bind.fs.samplers[0] = sg_make_sampler(&(sg_sampler_desc){});
|
||||||
|
|
||||||
/*
|
sg_crt.shader = sg_make_shader(crt_shader_desc(sg_query_backend()));
|
||||||
sg_image_desc shadow_desc = {
|
sg_crt.pipe = sg_make_pipeline(&(sg_pipeline_desc){
|
||||||
.render_target = true,
|
.shader = sg_crt.shader,
|
||||||
.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,
|
|
||||||
.layout = {
|
.layout = {
|
||||||
.attrs = {
|
.attrs = {
|
||||||
[0].format = SG_VERTEXFORMAT_FLOAT3,
|
[0].format = SG_VERTEXFORMAT_FLOAT2,
|
||||||
|
[1].format = SG_VERTEXFORMAT_FLOAT2
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
.depth = {
|
.primitive_type = SG_PRIMITIVETYPE_TRIANGLE_STRIP,
|
||||||
.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,
|
|
||||||
});
|
});
|
||||||
|
|
||||||
*/
|
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),
|
||||||
|
|
||||||
}
|
.label = "crt vert buffer",
|
||||||
|
});
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
HMM_Mat4 projection = {0.f};
|
HMM_Mat4 projection = {0.f};
|
||||||
HMM_Mat4 hudproj = {0.f};
|
HMM_Mat4 hudproj = {0.f};
|
||||||
|
HMM_Mat4 useproj = {0};
|
||||||
|
|
||||||
HMM_Vec3 dirl_pos = {4, 100, 20};
|
HMM_Vec3 dirl_pos = {4, 100, 20};
|
||||||
|
|
||||||
|
@ -398,8 +314,14 @@ HMM_Vec3 dirl_pos = {4, 100, 20};
|
||||||
#define MODE_EXPAND 4
|
#define MODE_EXPAND 4
|
||||||
#define MODE_FULL 5
|
#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;
|
HMM_Vec2 usesize = window->rendersize;
|
||||||
|
|
||||||
switch(window->mode) {
|
switch(window->mode) {
|
||||||
|
@ -427,70 +349,17 @@ void full_2d_pass(struct window *window)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 2D projection
|
// 2D projection
|
||||||
cpVect pos = cam_pos();
|
campos = go_pos(cam);
|
||||||
|
camzoom = zoom;
|
||||||
|
|
||||||
projection = HMM_Orthographic_LH_NO(
|
projection = HMM_Orthographic_LH_NO(
|
||||||
pos.x - zoom * usesize.x / 2,
|
campos.x - camzoom * usesize.x / 2,
|
||||||
pos.x + zoom * usesize.x / 2,
|
campos.x + camzoom * usesize.x / 2,
|
||||||
pos.y - zoom * usesize.y / 2,
|
campos.y - camzoom * usesize.y / 2,
|
||||||
pos.y + zoom * usesize.y / 2, -10000.f, 10000.f);
|
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);
|
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) {
|
/* if (gif.rec && (apptime() - gif.timer) > gif.spf) {
|
||||||
sg_begin_pass(&(sg_pass){
|
sg_begin_pass(&(sg_pass){
|
||||||
.action = pass_action,
|
.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);
|
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 cwh2bb(HMM_Vec2 c, HMM_Vec2 wh) {
|
||||||
struct boundingbox bb = {
|
struct boundingbox bb = {
|
||||||
.t = c.Y + wh.Y/2,
|
.t = c.Y + wh.Y/2,
|
||||||
|
|
|
@ -7,13 +7,13 @@
|
||||||
#define SOKOL_GLES3
|
#define SOKOL_GLES3
|
||||||
#elif __WIN32
|
#elif __WIN32
|
||||||
#define SOKOL_D3D11
|
#define SOKOL_D3D11
|
||||||
#define SOKOL_WIN32_FORCE_MAIN
|
|
||||||
#elif __APPLE__
|
#elif __APPLE__
|
||||||
#define SOKOL_METAL
|
#define SOKOL_METAL
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "sokol/sokol_gfx.h"
|
#include "sokol/sokol_gfx.h"
|
||||||
#include "HandmadeMath.h"
|
#include "HandmadeMath.h"
|
||||||
|
#include "gameobject.h"
|
||||||
|
|
||||||
#define RGBA_MAX 255
|
#define RGBA_MAX 255
|
||||||
|
|
||||||
|
@ -29,12 +29,7 @@ extern HMM_Vec3 dirl_pos;
|
||||||
|
|
||||||
extern HMM_Mat4 projection;
|
extern HMM_Mat4 projection;
|
||||||
extern HMM_Mat4 hudproj;
|
extern HMM_Mat4 hudproj;
|
||||||
|
extern HMM_Mat4 useproj;
|
||||||
struct camera3d {
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef struct camera3d camera3d;
|
|
||||||
|
|
||||||
struct draw_p {
|
struct draw_p {
|
||||||
float x;
|
float x;
|
||||||
|
@ -52,24 +47,15 @@ enum RenderMode {
|
||||||
};
|
};
|
||||||
|
|
||||||
void render_init();
|
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 opengl_rendermode(enum RenderMode r);
|
||||||
|
|
||||||
void openglInit3d(struct window *window);
|
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 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_start(int w, int h, int cpf, int bitdepth);
|
||||||
void gif_rec_end(const char *path);
|
void gif_rec_end(const char *path);
|
||||||
|
|
||||||
|
|
|
@ -15,7 +15,7 @@
|
||||||
#include "font.h"
|
#include "font.h"
|
||||||
|
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include "cdb.h"
|
#include "miniz.h"
|
||||||
|
|
||||||
#ifndef __EMSCRIPTEN__
|
#ifndef __EMSCRIPTEN__
|
||||||
#include <ftw.h>
|
#include <ftw.h>
|
||||||
|
@ -40,8 +40,8 @@ struct dirent *c_dirent = NULL;
|
||||||
|
|
||||||
char pathbuf[MAXPATH + 1];
|
char pathbuf[MAXPATH + 1];
|
||||||
|
|
||||||
static struct cdb corecdb;
|
static mz_zip_archive corecdb;
|
||||||
static struct cdb game_cdb;
|
static mz_zip_archive game_cdb;
|
||||||
|
|
||||||
int LOADED_GAME = 0;
|
int LOADED_GAME = 0;
|
||||||
uint8_t *gamebuf;
|
uint8_t *gamebuf;
|
||||||
|
@ -49,7 +49,7 @@ uint8_t *gamebuf;
|
||||||
static void response_cb(const sfetch_response_t *r)
|
static void response_cb(const sfetch_response_t *r)
|
||||||
{
|
{
|
||||||
if (r->fetched) {
|
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;
|
LOADED_GAME = 1;
|
||||||
}
|
}
|
||||||
if (r->finished) {
|
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) {
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
time_t file_mod_secs(const char *file) {
|
||||||
|
struct stat attr;
|
||||||
|
stat(file, &attr);
|
||||||
|
return attr.st_mtime;
|
||||||
|
}
|
||||||
|
|
||||||
// TODO: Not reentrant
|
// TODO: Not reentrant
|
||||||
char **ls(const char *path)
|
char **ls(const char *path)
|
||||||
{
|
{
|
||||||
|
@ -154,6 +160,7 @@ char **ls(const char *path)
|
||||||
#else
|
#else
|
||||||
void fill_extensions(char *paths, const char *path, const char *ext)
|
void fill_extensions(char *paths, const char *path, const char *ext)
|
||||||
{};
|
{};
|
||||||
|
char **ls(const char *path) { return NULL; }
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
char *str_replace_ext(const char *s, const char *newext) {
|
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;
|
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 fexists(const char *path)
|
||||||
{
|
{
|
||||||
int len = strlen(path);
|
int len = strlen(path);
|
||||||
if (cdb_find(&game_cdb, path, len)) return 1;
|
if (mz_zip_reader_locate_file(&game_cdb, path, NULL, 0) != -1) return 1;
|
||||||
else if (cdb_find(&corecdb, path, len)) return 1;
|
else if (mz_zip_reader_locate_file(&corecdb, path, NULL, 0) != -1) return 1;
|
||||||
else if (!access(path, R_OK)) return 1;
|
else if (!access(path, R_OK)) return 1;
|
||||||
|
|
||||||
return 0;
|
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 *slurp_file(const char *filename, size_t *size)
|
||||||
{
|
{
|
||||||
|
void *ret;
|
||||||
if (!access(filename, R_OK))
|
if (!access(filename, R_OK))
|
||||||
return os_slurp(filename, size);
|
return os_slurp(filename, size);
|
||||||
else if (cdb_find(&game_cdb, filename, strlen(filename)))
|
else if (ret = mz_zip_reader_extract_file_to_heap(&game_cdb, filename, size, 0))
|
||||||
return cdb_slurp(&game_cdb, filename, size);
|
return ret;
|
||||||
else if (cdb_find(&corecdb, filename, strlen(filename)))
|
else if (ret = mz_zip_reader_extract_file_to_heap(&corecdb, filename, size, 0))
|
||||||
return cdb_slurp(&corecdb, filename, size);
|
return ret;
|
||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
@ -304,58 +291,3 @@ int slurp_write(const char *txt, const char *filename, size_t len) {
|
||||||
fclose(f);
|
fclose(f);
|
||||||
return 0;
|
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 <stdio.h>
|
||||||
#include "stb_ds.h"
|
#include "stb_ds.h"
|
||||||
#include "string.h"
|
#include "string.h"
|
||||||
|
#include <time.h>
|
||||||
|
|
||||||
extern char *DATA_PATH;
|
extern char *DATA_PATH;
|
||||||
extern int LOADED_GAME;
|
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 *get_directory_from_path(char *path);
|
||||||
char *str_replace_ext(const char *s, const char *newext);
|
char *str_replace_ext(const char *s, const char *newext);
|
||||||
FILE *res_open(char *path, const char *tag);
|
FILE *res_open(char *path, const char *tag);
|
||||||
FILE *path_open(const char *tag, const char *fmt, ...);
|
|
||||||
char **ls(const char *path);
|
char **ls(const char *path);
|
||||||
int cp(const char *p1, const char *p2);
|
int cp(const char *p1, const char *p2);
|
||||||
int fexists(const char *path);
|
int fexists(const char *path);
|
||||||
|
time_t file_mod_secs(const char *file);
|
||||||
|
|
||||||
char *dirname(const char *path);
|
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, ...);
|
char *seprint(char *fmt, ...);
|
||||||
|
|
||||||
void pack_engine(const char *fname);
|
|
||||||
|
|
||||||
static inline void *stbarrdup(void *mem, size_t size, int len) {
|
static inline void *stbarrdup(void *mem, size_t size, int len) {
|
||||||
void *out = NULL;
|
void *out = NULL;
|
||||||
arrsetlen(out, len);
|
arrsetlen(out, len);
|
||||||
|
|
|
@ -1,22 +1,8 @@
|
||||||
#include "script.h"
|
#include "script.h"
|
||||||
|
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
#include "stdio.h"
|
|
||||||
|
|
||||||
#include "jsffi.h"
|
#include "jsffi.h"
|
||||||
#include "font.h"
|
|
||||||
|
|
||||||
#include "gameobject.h"
|
|
||||||
|
|
||||||
#include "ftw.h"
|
|
||||||
|
|
||||||
#include "stb_ds.h"
|
#include "stb_ds.h"
|
||||||
|
|
||||||
#include "sys/stat.h"
|
|
||||||
#include "sys/types.h"
|
|
||||||
#include "time.h"
|
|
||||||
#include "resources.h"
|
#include "resources.h"
|
||||||
#include "input.h"
|
|
||||||
|
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
|
|
||||||
|
@ -29,100 +15,40 @@ JSRuntime *rt = NULL;
|
||||||
#define JS_EVAL_FLAGS JS_EVAL_FLAG_STRICT | JS_EVAL_FLAG_STRIP
|
#define JS_EVAL_FLAGS JS_EVAL_FLAG_STRICT | JS_EVAL_FLAG_STRIP
|
||||||
#endif
|
#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() {
|
void script_startup() {
|
||||||
rt = JS_NewRuntime();
|
rt = JS_NewRuntime();
|
||||||
js = JS_NewContext(rt);
|
js = JS_NewContext(rt);
|
||||||
|
|
||||||
sh_new_arena(jsstrs);
|
|
||||||
|
|
||||||
ffi_load();
|
ffi_load();
|
||||||
|
|
||||||
for (int i = 0; i < 100; i++)
|
size_t len;
|
||||||
num_cache[i] = int2js(i);
|
char *eng = slurp_text("scripts/engine.js", &len);
|
||||||
|
JSValue v = script_eval("scripts/engine.js", eng);
|
||||||
script_dofile("scripts/engine.js");
|
JS_FreeValue(js,v);
|
||||||
// jso_file("scripts/engine.js");
|
free(eng);
|
||||||
}
|
}
|
||||||
|
static int stopped = 0;
|
||||||
void script_stop()
|
void script_stop()
|
||||||
{
|
{
|
||||||
script_evalf("Event.notify('quit');");
|
script_evalf("prosperon.quit();");
|
||||||
send_signal("quit",0,NULL);
|
#ifndef LEAK
|
||||||
|
return;
|
||||||
|
#endif
|
||||||
|
printf("FREEING CONTEXT\n");
|
||||||
ffi_stop();
|
ffi_stop();
|
||||||
for (int i = 0; i < shlen(jsstrs); i++)
|
|
||||||
JS_FreeValue(js,jsstrs[i].value);
|
|
||||||
|
|
||||||
#if LEAK
|
|
||||||
JS_FreeContext(js);
|
JS_FreeContext(js);
|
||||||
|
script_gc();
|
||||||
JS_FreeRuntime(rt);
|
JS_FreeRuntime(rt);
|
||||||
#endif
|
js = NULL;
|
||||||
|
rt = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
void script_gc()
|
void script_gc() { JS_RunGC(rt); }
|
||||||
{
|
|
||||||
JS_RunGC(rt);
|
|
||||||
}
|
|
||||||
|
|
||||||
JSValue num_cache[100] = {0};
|
void js_stacktrace() {
|
||||||
|
|
||||||
/*int js_print_exception(JSValue v) {
|
|
||||||
#ifndef NDEBUG
|
#ifndef NDEBUG
|
||||||
if (JS_IsException(v)) {
|
script_evalf("console.stack();");
|
||||||
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;
|
|
||||||
}
|
|
||||||
#endif
|
#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, ...)
|
void script_evalf(const char *format, ...)
|
||||||
|
@ -138,121 +64,16 @@ void script_evalf(const char *format, ...)
|
||||||
JS_FreeValue(js,obj);
|
JS_FreeValue(js,obj);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t *script_compile(const char *file, size_t *len) {
|
JSValue script_eval(const char *file, const char *script)
|
||||||
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 b = JS_ReadObject(js, code, len, JS_READ_OBJ_BYTECODE);
|
JSValue v = JS_Eval(js, script, strlen(script), file, JS_EVAL_FLAGS);
|
||||||
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);
|
|
||||||
js_print_exception(v);
|
js_print_exception(v);
|
||||||
return v;
|
return v;
|
||||||
}
|
}
|
||||||
|
|
||||||
JSValue file_eval_env(const char *file, JSValue env)
|
void script_call_sym(JSValue sym, int argc, JSValue *argv) {
|
||||||
{
|
|
||||||
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) {
|
|
||||||
if (!JS_IsFunction(js, sym)) return;
|
if (!JS_IsFunction(js, sym)) return;
|
||||||
struct callee c;
|
JSValue ret = JS_Call(js, sym, JS_UNDEFINED, argc, argv);
|
||||||
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);
|
|
||||||
js_print_exception(ret);
|
js_print_exception(ret);
|
||||||
JS_FreeValue(js, ret);
|
JS_FreeValue(js, ret);
|
||||||
}
|
}
|
||||||
|
@ -266,62 +87,3 @@ void out_memusage(const char *file)
|
||||||
JS_DumpMemoryUsage(f, &jsmem, rt);
|
JS_DumpMemoryUsage(f, &jsmem, rt);
|
||||||
fclose(f);
|
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;
|
extern JSContext *js;
|
||||||
|
|
||||||
struct callee {
|
|
||||||
JSValue fn;
|
|
||||||
JSValue obj;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct phys_cbs {
|
struct phys_cbs {
|
||||||
JSValue begin;
|
JSValue begin;
|
||||||
JSValue bhit;
|
JSValue bhit;
|
||||||
JSValue separate;
|
JSValue separate;
|
||||||
JSValue shit;
|
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_startup();
|
||||||
void script_stop();
|
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 out_memusage(const char *f);
|
||||||
|
void js_stacktrace();
|
||||||
|
|
||||||
void script_editor();
|
void script_evalf(const char *format, ...);
|
||||||
void script_call(const char *f);
|
JSValue script_eval(const char *file, const char *script);
|
||||||
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);
|
|
||||||
|
|
||||||
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();
|
void script_gc();
|
||||||
|
|
||||||
JSValue script_run_bytecode(uint8_t *code, size_t len);
|
|
||||||
uint8_t *script_compile(const char *file, size_t *len);
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -13,6 +13,10 @@
|
||||||
|
|
||||||
#define PI 3.14159265
|
#define PI 3.14159265
|
||||||
|
|
||||||
|
int SAMPLERATE = 44100;
|
||||||
|
int BUF_FRAMES = 2048;
|
||||||
|
int CHANNELS = 2;
|
||||||
|
|
||||||
dsp_node *masterbus = NULL;
|
dsp_node *masterbus = NULL;
|
||||||
|
|
||||||
void iir_free(struct dsp_iir *iir)
|
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 *make_node(void *data, void (*proc)(void *data, soundbyte *out, int samples), void (*fr)(void *data))
|
||||||
{
|
{
|
||||||
dsp_node *self = malloc(sizeof(dsp_node));
|
dsp_node *self = malloc(sizeof(dsp_node));
|
||||||
memset(self, 0, sizeof(*self));
|
memset(self, 0, sizeof(*self));
|
||||||
self->data = data;
|
self->data = data;
|
||||||
|
self->cache = calloc(BUF_FRAMES*CHANNELS*sizeof(soundbyte),1);
|
||||||
self->proc = proc;
|
self->proc = proc;
|
||||||
self->pass = 0;
|
self->pass = 0;
|
||||||
self->gain = 1;
|
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)
|
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);
|
pthread_mutex_lock(&soundrun);
|
||||||
unplug_node(node);
|
unplug_node(node);
|
||||||
if (node->data) {
|
if (node->data) {
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
#ifndef DSP_H
|
#ifndef DSP_H
|
||||||
#define DSP_H
|
#define DSP_H
|
||||||
|
|
||||||
#define SAMPLERATE 44100
|
extern int SAMPLERATE;
|
||||||
#define BUF_FRAMES 2048 /* At 48k, 128 needed for 240fps consistency */
|
extern int BUF_FRAMES;
|
||||||
#define CHANNELS 2
|
extern int CHANNELS;
|
||||||
|
|
||||||
#include "sound.h"
|
#include "sound.h"
|
||||||
#include "cbuf.h"
|
#include "cbuf.h"
|
||||||
|
@ -15,7 +15,7 @@ typedef struct dsp_node {
|
||||||
void (*proc)(void *dsp, soundbyte *buf, int samples); /* processor */
|
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; /* Node specific data to use in the proc function, passed in as dsp */
|
||||||
void (*data_free)(void *data);
|
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 **ins; /* Array of in nodes */
|
||||||
struct dsp_node *out; /* node this one is connected to */
|
struct dsp_node *out; /* node this one is connected to */
|
||||||
int pass; /* True if the filter should be bypassed */
|
int pass; /* True if the filter should be bypassed */
|
||||||
|
|
|
@ -8,7 +8,6 @@
|
||||||
#include "time.h"
|
#include "time.h"
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include "pthread.h"
|
#include "pthread.h"
|
||||||
#include "debug.h"
|
|
||||||
#include "jsffi.h"
|
#include "jsffi.h"
|
||||||
|
|
||||||
pthread_mutex_t soundrun = PTHREAD_MUTEX_INITIALIZER;
|
pthread_mutex_t soundrun = PTHREAD_MUTEX_INITIALIZER;
|
||||||
|
@ -138,6 +137,10 @@ void sound_init() {
|
||||||
.buffer_frames = BUF_FRAMES,
|
.buffer_frames = BUF_FRAMES,
|
||||||
.logger.func = sg_logging,
|
.logger.func = sg_logging,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
SAMPLERATE = saudio_sample_rate();
|
||||||
|
CHANNELS = saudio_channels();
|
||||||
|
BUF_FRAMES = saudio_buffer_frames();
|
||||||
}
|
}
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
|
@ -279,14 +282,11 @@ void sound_fillbuf(struct sound *s, soundbyte *buf, int n) {
|
||||||
if(end) {
|
if(end) {
|
||||||
if (s->loop)
|
if (s->loop)
|
||||||
s->frame = 0;
|
s->frame = 0;
|
||||||
|
|
||||||
script_call_sym(s->hook);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void free_source(struct sound *s)
|
void free_source(struct sound *s)
|
||||||
{
|
{
|
||||||
JS_FreeValue(js, s->hook);
|
|
||||||
src_delete(s->src);
|
src_delete(s->src);
|
||||||
free(s);
|
free(s);
|
||||||
}
|
}
|
||||||
|
@ -307,7 +307,6 @@ struct dsp_node *dsp_source(const char *path)
|
||||||
self->loop = false;
|
self->loop = false;
|
||||||
self->src = src_callback_new(src_cb, SRC_SINC_MEDIUM_QUALITY, 2, NULL, self);
|
self->src = src_callback_new(src_cb, SRC_SINC_MEDIUM_QUALITY, 2, NULL, self);
|
||||||
self->timescale = 1;
|
self->timescale = 1;
|
||||||
self->hook = JS_UNDEFINED;
|
|
||||||
dsp_node *n = make_node(self, sound_fillbuf, free_source);
|
dsp_node *n = make_node(self, sound_fillbuf, free_source);
|
||||||
return n;
|
return n;
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,7 +17,6 @@ typedef struct sound {
|
||||||
int loop;
|
int loop;
|
||||||
float timescale;
|
float timescale;
|
||||||
SRC_STATE *src;
|
SRC_STATE *src;
|
||||||
JSValue hook;
|
|
||||||
} sound;
|
} sound;
|
||||||
|
|
||||||
/* Represents a sound file source, fulled loaded*/
|
/* Represents a sound file source, fulled loaded*/
|
||||||
|
|
|
@ -5,7 +5,6 @@
|
||||||
#include "render.h"
|
#include "render.h"
|
||||||
#include "stb_ds.h"
|
#include "stb_ds.h"
|
||||||
#include "texture.h"
|
#include "texture.h"
|
||||||
#include "timer.h"
|
|
||||||
#include "HandmadeMath.h"
|
#include "HandmadeMath.h"
|
||||||
|
|
||||||
#include "sprite.sglsl.h"
|
#include "sprite.sglsl.h"
|
||||||
|
@ -52,7 +51,7 @@ sprite *sprite_make()
|
||||||
sp->color = color_white;
|
sp->color = color_white;
|
||||||
sp->emissive = color_clear;
|
sp->emissive = color_clear;
|
||||||
sp->go = NULL;
|
sp->go = NULL;
|
||||||
sp->tex = texture_from_file(NULL);
|
sp->tex = NULL;
|
||||||
sp->frame = ST_UNIT;
|
sp->frame = ST_UNIT;
|
||||||
sp->drawmode = DRAW_SIMPLE;
|
sp->drawmode = DRAW_SIMPLE;
|
||||||
sp->enabled = 1;
|
sp->enabled = 1;
|
||||||
|
@ -65,8 +64,6 @@ sprite *sprite_make()
|
||||||
|
|
||||||
void sprite_free(sprite *sprite)
|
void sprite_free(sprite *sprite)
|
||||||
{
|
{
|
||||||
YughWarn("Freeing sprite %p.", sprite);
|
|
||||||
|
|
||||||
free(sprite);
|
free(sprite);
|
||||||
for (int i = arrlen(sprites)-1; i >= 0; i--)
|
for (int i = arrlen(sprites)-1; i >= 0; i--)
|
||||||
if (sprites[i] == sprite) {
|
if (sprites[i] == sprite) {
|
||||||
|
@ -88,8 +85,9 @@ int sprite_sort(sprite **sa, sprite **sb)
|
||||||
if (!goa && !gob) return 0;
|
if (!goa && !gob) return 0;
|
||||||
if (!goa) return -1;
|
if (!goa) return -1;
|
||||||
if (!gob) return 1;
|
if (!gob) return 1;
|
||||||
if (goa->drawlayer == gob->drawlayer) return 0;
|
|
||||||
if (goa->drawlayer > gob->drawlayer) return 1;
|
if (goa->drawlayer > gob->drawlayer) return 1;
|
||||||
|
if (gob->drawlayer > goa->drawlayer) return -1;
|
||||||
|
if (*sa > *sb) return 1;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -97,16 +95,17 @@ void sprite_draw_all() {
|
||||||
if (arrlen(sprites) == 0) return;
|
if (arrlen(sprites) == 0) return;
|
||||||
|
|
||||||
sg_apply_pipeline(pip_sprite);
|
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);
|
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]);
|
sprite_draw(sprites[i]);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void sprite_initialize() {
|
void sprite_initialize() {
|
||||||
|
|
||||||
shader_sprite = sg_make_shader(sprite_shader_desc(sg_query_backend()));
|
shader_sprite = sg_make_shader(sprite_shader_desc(sg_query_backend()));
|
||||||
|
|
||||||
pip_sprite = sg_make_pipeline(&(sg_pipeline_desc){
|
pip_sprite = sg_make_pipeline(&(sg_pipeline_desc){
|
||||||
|
@ -149,6 +148,7 @@ void sprite_initialize() {
|
||||||
.size = sizeof(struct slice9_vert) * 100,
|
.size = sizeof(struct slice9_vert) * 100,
|
||||||
.type = SG_BUFFERTYPE_VERTEXBUFFER,
|
.type = SG_BUFFERTYPE_VERTEXBUFFER,
|
||||||
.usage = SG_USAGE_STREAM,
|
.usage = SG_USAGE_STREAM,
|
||||||
|
.label = "slice9 buffer"
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -198,7 +198,7 @@ transform2d sprite2t(sprite *s)
|
||||||
return (transform2d){
|
return (transform2d){
|
||||||
.pos = s->pos,
|
.pos = s->pos,
|
||||||
.scale = s->scale,
|
.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;
|
if (!sprite->go) t = t2d_unit;
|
||||||
else t = go2t(sprite->go);
|
else t = go2t(sprite->go);
|
||||||
|
|
||||||
t.pos.x += (cam_pos().x - (cam_pos().x/sprite->parallax));
|
t.pos.x += (campos.x - (campos.x/sprite->parallax));
|
||||||
t.pos.y += (cam_pos().y - (cam_pos().y/sprite->parallax));
|
t.pos.y += (campos.y - (campos.y/sprite->parallax));
|
||||||
HMM_Mat3 m = transform2d2mat(t);
|
HMM_Mat3 m = transform2d2mat(t);
|
||||||
HMM_Mat3 sm = transform2d2mat(sprite2t(sprite));
|
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);
|
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_pipeline(pip_sprite);
|
||||||
sg_apply_uniforms(SG_SHADERSTAGE_VS, 0, SG_RANGE_REF(hudproj));
|
sg_apply_uniforms(SG_SHADERSTAGE_VS, 0, SG_RANGE_REF(useproj));
|
||||||
struct texture *tex = texture_from_file(img);
|
|
||||||
tex_draw(tex, transform2d2mat(t), ST_UNIT, color, wrap, wrapoffset, (HMM_Vec2){wrapscale,wrapscale}, (struct rgba){0,0,0,0}, 0);
|
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_draw_all();
|
||||||
void sprite_flush();
|
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
|
#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 "render.h"
|
||||||
#include "sokol/sokol_gfx.h"
|
#include "sokol/sokol_gfx.h"
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
#include <stb_ds.h>
|
|
||||||
#include <stb_image.h>
|
#include <stb_image.h>
|
||||||
|
|
||||||
#include "resources.h"
|
#include "resources.h"
|
||||||
|
@ -23,14 +22,6 @@
|
||||||
|
|
||||||
struct rect ST_UNIT = {0.f, 0.f, 1.f, 1.f};
|
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)
|
unsigned int next_pow2(unsigned int v)
|
||||||
{
|
{
|
||||||
v--;
|
v--;
|
||||||
|
@ -70,31 +61,14 @@ int mip_wh(int w, int h, int *mw, int *mh, int lvl)
|
||||||
return 0;
|
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 */
|
/* If an empty string or null is put for path, loads default texture */
|
||||||
struct texture *texture_from_file(const char *path) {
|
struct texture *texture_from_file(const char *path) {
|
||||||
if (!path) return texture_notex();
|
if (!path) return NULL;
|
||||||
if (shlen(texhash) == 0) sh_new_arena(texhash);
|
|
||||||
|
|
||||||
int index = shgeti(texhash, path);
|
|
||||||
if (index != -1)
|
|
||||||
return texhash[index].value;
|
|
||||||
|
|
||||||
size_t rawlen;
|
size_t rawlen;
|
||||||
unsigned char *raw = slurp_file(path, &rawlen);
|
unsigned char *raw = slurp_file(path, &rawlen);
|
||||||
|
|
||||||
if (!raw) return texture_notex();
|
if (!raw) return NULL;
|
||||||
|
|
||||||
unsigned char *data;
|
unsigned char *data;
|
||||||
|
|
||||||
|
@ -115,8 +89,7 @@ struct texture *texture_from_file(const char *path) {
|
||||||
int *dd = tex->delays;
|
int *dd = tex->delays;
|
||||||
tex->delays = NULL;
|
tex->delays = NULL;
|
||||||
arrsetlen(tex->delays, tex->frames);
|
arrsetlen(tex->delays, tex->frames);
|
||||||
for (int i = 0; i < tex->frames;i++)
|
for (int i = 0; i < tex->frames; i++) tex->delays[i] = dd[i];
|
||||||
tex->delays[i] = dd[i];
|
|
||||||
free(dd);
|
free(dd);
|
||||||
tex->height *= tex->frames;
|
tex->height *= tex->frames;
|
||||||
} else if (!strcmp(ext, ".svg")) {
|
} else if (!strcmp(ext, ".svg")) {
|
||||||
|
@ -141,20 +114,19 @@ struct texture *texture_from_file(const char *path) {
|
||||||
}
|
}
|
||||||
free(raw);
|
free(raw);
|
||||||
|
|
||||||
if (data == NULL) {
|
if (data == NULL)
|
||||||
YughError("STBI failed to load file %s with message: %s\nOpening default instead.", path, stbi_failure_reason());
|
return NULL;
|
||||||
return texture_notex();
|
|
||||||
}
|
tex->data = data;
|
||||||
|
|
||||||
unsigned int nw = next_pow2(tex->width);
|
unsigned int nw = next_pow2(tex->width);
|
||||||
unsigned int nh = next_pow2(tex->height);
|
unsigned int nh = next_pow2(tex->height);
|
||||||
|
|
||||||
tex->data = data;
|
|
||||||
|
|
||||||
int filter = SG_FILTER_NEAREST;
|
int filter = SG_FILTER_NEAREST;
|
||||||
|
|
||||||
sg_image_data sg_img_data;
|
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;
|
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);
|
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++) {
|
for (int i = 1; i < mips; i++) {
|
||||||
int w, h, mipw, miph;
|
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);
|
mip_wh(tex->width, tex->height, &w, &h, i);
|
||||||
mipdata[i] = malloc(w * h * 4);
|
mipdata[i] = malloc(w * h * 4);
|
||||||
stbir_resize_uint8_linear(mipdata[i-1], mipw, miph, 0, mipdata[i], w, h, 0, 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;
|
mipw = w;
|
||||||
miph = h;
|
miph = h;
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
tex->id = sg_make_image(&(sg_image_desc){
|
tex->id = sg_make_image(&(sg_image_desc){
|
||||||
.type = SG_IMAGETYPE_2D,
|
.type = SG_IMAGETYPE_2D,
|
||||||
.width = tex->width,
|
.width = tex->width,
|
||||||
.height = tex->height,
|
.height = tex->height,
|
||||||
.usage = SG_USAGE_IMMUTABLE,
|
.usage = SG_USAGE_IMMUTABLE,
|
||||||
.num_mipmaps = mips,
|
//.num_mipmaps = mips,
|
||||||
.data = sg_img_data
|
.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;
|
return tex;
|
||||||
}
|
}
|
||||||
|
|
||||||
void texture_sync(const char *path) { YughWarn("Need to implement texture sync."); }
|
|
||||||
|
|
||||||
void texture_free(texture *tex)
|
void texture_free(texture *tex)
|
||||||
{
|
{
|
||||||
|
if (!tex) return;
|
||||||
}
|
free(tex->data);
|
||||||
|
if (tex->delays) arrfree(tex->delays);
|
||||||
char *tex_get_path(struct texture *tex) {
|
sg_destroy_image(tex->id);
|
||||||
for (int i = 0; i < shlen(texhash); i++) {
|
free(tex);
|
||||||
if (tex == texhash[i].value) {
|
|
||||||
YughSpam("Found key %s", texhash[i].key);
|
|
||||||
return texhash[i].key;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return "";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
struct texture *texture_fromdata(void *raw, long size)
|
struct texture *texture_fromdata(void *raw, long size)
|
||||||
|
@ -222,10 +183,8 @@ struct texture *texture_fromdata(void *raw, long size)
|
||||||
int n;
|
int n;
|
||||||
void *data = stbi_load_from_memory(raw, size, &tex->width, &tex->height, &n, 4);
|
void *data = stbi_load_from_memory(raw, size, &tex->width, &tex->height, &n, 4);
|
||||||
|
|
||||||
if (data == NULL) {
|
if (data == NULL)
|
||||||
YughError("Given raw data not valid. Loading default instead.");
|
NULL;
|
||||||
return texture_notex();
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned int nw = next_pow2(tex->width);
|
unsigned int nw = next_pow2(tex->width);
|
||||||
unsigned int nh = next_pow2(tex->height);
|
unsigned int nh = next_pow2(tex->height);
|
||||||
|
@ -276,14 +235,6 @@ struct texture *texture_fromdata(void *raw, long size)
|
||||||
return tex;
|
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); }
|
static double fade (double t) { return t*t*t*(t*(t*6-15)+10); }
|
||||||
double grad (int hash, double x, double y, double z)
|
double grad (int hash, double x, double y, double z)
|
||||||
{
|
{
|
||||||
|
|
|
@ -37,21 +37,10 @@ typedef struct img_sampler{
|
||||||
int mip_filter;
|
int mip_filter;
|
||||||
} img_sampler;
|
} img_sampler;
|
||||||
|
|
||||||
struct texture *texture_from_file(const char *path); // Create texture from image
|
texture *texture_from_file(const char *path);
|
||||||
struct texture *texture_fromdata(void *raw, long size);
|
|
||||||
|
|
||||||
void texture_free(texture *tex);
|
void texture_free(texture *tex);
|
||||||
|
|
||||||
/* Hot reloads a texture, if needed */
|
struct texture *texture_fromdata(void *raw, long size);
|
||||||
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);
|
|
||||||
|
|
||||||
double perlin(double x, double y, double z);
|
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