Web Build!!!
This commit is contained in:
parent
b855732e29
commit
c31ebea3bd
1
.gitignore
vendored
1
.gitignore
vendored
@ -17,3 +17,4 @@ atlas.png
|
||||
pdbs/
|
||||
game_web/
|
||||
.venv
|
||||
build/
|
||||
|
@ -1,3 +0,0 @@
|
||||
@echo off
|
||||
|
||||
odin build main_release -out:game_debug.exe -strict-style -vet -debug
|
@ -1,3 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
odin build main_release -collection:common=./common -collection:game=./game -collection:libs=./libs -out:game_debug.bin -strict-style -vet -debug
|
@ -1,78 +0,0 @@
|
||||
@echo off
|
||||
|
||||
set GAME_RUNNING=false
|
||||
set EXE=game_hot_reload.exe
|
||||
|
||||
:: Check if game is running
|
||||
FOR /F %%x IN ('tasklist /NH /FI "IMAGENAME eq %EXE%"') DO IF %%x == %EXE% set GAME_RUNNING=true
|
||||
|
||||
:: If game isn't running then:
|
||||
:: - delete all game_XXX.dll files
|
||||
:: - delete all PDBs in pdbs subdir
|
||||
:: - optionally create the pdbs subdir
|
||||
:: - write 0 into pdbs\pdb_number so game.dll PDBs start counting from zero
|
||||
::
|
||||
:: This makes sure we start over "fresh" at PDB number 0 when starting up the
|
||||
:: game and it also makes sure we don't have so many PDBs laying around.
|
||||
if %GAME_RUNNING% == false (
|
||||
del /q game_*.dll 2> nul
|
||||
|
||||
if exist "pdbs" (
|
||||
del /q pdbs\*.pdb
|
||||
) else (
|
||||
mkdir pdbs
|
||||
)
|
||||
|
||||
echo 0 > pdbs\pdb_number
|
||||
)
|
||||
|
||||
:: Load PDB number from file, increment and store back. For as long as the game
|
||||
:: is running the pdb_number file won't be reset to 0, so we'll get a PDB of a
|
||||
:: unique name on each hot reload.
|
||||
set /p PDB_NUMBER=<pdbs\pdb_number
|
||||
set /a PDB_NUMBER=%PDB_NUMBER%+1
|
||||
echo %PDB_NUMBER% > pdbs\pdb_number
|
||||
|
||||
:: Build game dll, use pdbs\game_%PDB_NUMBER%.pdb as PDB name so each dll gets
|
||||
:: its own PDB. This PDB stuff is done in order to make debugging work.
|
||||
:: Debuggers tend to lock PDBs or just misbehave if you reuse the same PDB while
|
||||
:: the debugger is attached. So each time we compile `game.dll` we give the
|
||||
:: PDB a unique PDB.
|
||||
::
|
||||
:: Note that we could not just rename the PDB after creation; the DLL contains a
|
||||
:: reference to where the PDB is.
|
||||
::
|
||||
:: Also note that we always write game.dll to the same file. game_hot_reload.exe
|
||||
:: monitors this file and does the hot reload when it changes.
|
||||
echo Building game.dll
|
||||
odin build game -strict-style -vet -debug -define:RAYLIB_SHARED=true -build-mode:dll -out:game.dll -pdb-name:pdbs\game_%PDB_NUMBER%.pdb > nul
|
||||
IF %ERRORLEVEL% NEQ 0 exit /b 1
|
||||
|
||||
:: If game.exe already running: Then only compile game.dll and exit cleanly
|
||||
if %GAME_RUNNING% == true (
|
||||
echo Game running, hot reloading... && exit /b 1
|
||||
)
|
||||
|
||||
:: Build game.exe, which starts the program and loads game.dll och does the logic for hot reloading.
|
||||
echo Building %EXE%
|
||||
odin build main_hot_reload -strict-style -vet -debug -out:%EXE%
|
||||
IF %ERRORLEVEL% NEQ 0 exit /b 1
|
||||
|
||||
:: Warning about raylib DLL not existing and where to find it.
|
||||
if exist "raylib.dll" (
|
||||
exit /b 0
|
||||
)
|
||||
|
||||
:: Don't name this one ODIN_ROOT as the odin exe will start using that one then.
|
||||
set ODIN_PATH=
|
||||
|
||||
for /f %%i in ('odin root') do set "ODIN_PATH=%%i"
|
||||
|
||||
if exist "%ODIN_PATH%\vendor\raylib\windows\raylib.dll" (
|
||||
echo raylib.dll not found in current directory. Copying from %ODIN_PATH%\vendor\raylib\windows\raylib.dll
|
||||
copy "%ODIN_PATH%\vendor\raylib\windows\raylib.dll" .
|
||||
exit /b 0
|
||||
)
|
||||
|
||||
echo "Please copy raylib.dll from <your_odin_compiler>/vendor/raylib/windows/raylib.dll to the same directory as game.exe"
|
||||
exit /b 1
|
@ -1,52 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
# NOTE: this is a recent addition to the Odin compiler, if you don't have this command
|
||||
# you can change this to the path to the Odin folder that contains vendor, eg: "~/Odin".
|
||||
ROOT=$(odin root)
|
||||
if [ ! $? -eq 0 ]; then
|
||||
echo "Your Odin compiler does not have the 'odin root' command, please update or hardcode it in the script."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
set -eu
|
||||
|
||||
# Figure out the mess that is dynamic libraries.
|
||||
case $(uname) in
|
||||
"Darwin")
|
||||
case $(uname -m) in
|
||||
"arm64") LIB_PATH="macos-arm64" ;;
|
||||
*) LIB_PATH="macos" ;;
|
||||
esac
|
||||
|
||||
DLL_EXT=".dylib"
|
||||
EXTRA_LINKER_FLAGS="-Wl,-rpath $ROOT/vendor/raylib/$LIB_PATH"
|
||||
;;
|
||||
*)
|
||||
DLL_EXT=".so"
|
||||
EXTRA_LINKER_FLAGS="'-Wl,-rpath=\$ORIGIN/linux'"
|
||||
|
||||
# Copy the linux libraries into the project automatically.
|
||||
if [ ! -d "linux" ]; then
|
||||
mkdir linux
|
||||
cp -r libs/raylib/src/libraylib*.so* linux
|
||||
cp -r libs/physfs/libphysfs.so* linux
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
|
||||
# Build the game.
|
||||
echo "Building game$DLL_EXT"
|
||||
odin build game -extra-linker-flags:"$EXTRA_LINKER_FLAGS" -define:RAYLIB_SHARED=true -define:PHYSFS_SHARED=true -define:TRACY_ENABLE=true -collection:libs=./libs -collection:common=./common -collection:game=./game -build-mode:dll -out:game_tmp$DLL_EXT -strict-style -vet -debug -o:speed
|
||||
|
||||
# Need to use a temp file on Linux because it first writes an empty `game.so`, which the game will load before it is actually fully written.
|
||||
mv game_tmp$DLL_EXT game$DLL_EXT
|
||||
|
||||
# Do not build the game_hot_reload.bin if it is already running.
|
||||
# -f is there to make sure we match against full name, including .bin
|
||||
if pgrep -f game_hot_reload.bin > /dev/null; then
|
||||
echo "Game running, hot reloading..."
|
||||
exit 1
|
||||
else
|
||||
echo "Building game_hot_reload.bin"
|
||||
odin build main_hot_reload -define:TRACY_ENABLE=true -collection:libs=./libs -out:game_hot_reload.bin -strict-style -vet -debug
|
||||
fi
|
@ -1,3 +0,0 @@
|
||||
@echo off
|
||||
|
||||
odin build main_release -out:game_release.exe -strict-style -vet -no-bounds-check -o:speed -subsystem:windows
|
@ -1,3 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
odin build main_release -collection:common=./common -collection:game=./game -out:game_release.bin -strict-style -vet -no-bounds-check -o:speed -debug
|
@ -1,19 +0,0 @@
|
||||
@echo off
|
||||
|
||||
set EMSCRIPTEN_SDK_DIR=c:\emsdk
|
||||
set OUT_DIR=game_web
|
||||
|
||||
if not exist %OUT_DIR% mkdir %OUT_DIR%
|
||||
|
||||
set EMSDK_QUIET=1
|
||||
call %EMSCRIPTEN_SDK_DIR%\emsdk_env.bat
|
||||
|
||||
odin build main_web -target:freestanding_wasm32 -build-mode:obj -define:RAYLIB_WASM_LIB=env.o -vet -strict-style -out:%OUT_DIR%/game
|
||||
IF %ERRORLEVEL% NEQ 0 exit /b 1
|
||||
|
||||
for /f %%i in ('odin root') do set "ODIN_PATH=%%i"
|
||||
|
||||
set files=main_web/main_web.c %OUT_DIR%/game.wasm.o %ODIN_PATH%\vendor\raylib\wasm\libraylib.a
|
||||
set flags=-sUSE_GLFW=3 -sASYNCIFY -sASSERTIONS -DPLATFORM_WEB
|
||||
set custom=--shell-file main_web/index_template.html
|
||||
emcc -o %OUT_DIR%/index.html %files% %flags% %custom% && del %OUT_DIR%\game.wasm.o
|
@ -4,7 +4,9 @@ import "core:flags"
|
||||
import "core:fmt"
|
||||
import "core:log"
|
||||
import os "core:os/os2"
|
||||
import "core:path/filepath"
|
||||
import "core:slice"
|
||||
import "core:strings"
|
||||
|
||||
Build_Variant :: enum {
|
||||
Hot_Reload,
|
||||
@ -20,10 +22,9 @@ Options :: struct {
|
||||
tracy: bool `usage:"Enable tracy profiler"`,
|
||||
}
|
||||
|
||||
Error :: union #shared_nil {
|
||||
Run_Error,
|
||||
Copy_Error,
|
||||
os.Error,
|
||||
temp_concat :: proc(left, right: []string) -> []string {
|
||||
result := slice.concatenate([][]string{left, right}, context.temp_allocator)
|
||||
return result
|
||||
}
|
||||
|
||||
build_deps :: proc(opts: Options) {
|
||||
@ -39,7 +40,7 @@ build_deps :: proc(opts: Options) {
|
||||
}
|
||||
|
||||
target := opts.variant == .Web ? "wasm32-emscripten" : "native"
|
||||
handle_error(
|
||||
|
||||
run_cmd(
|
||||
{
|
||||
"zig",
|
||||
@ -50,7 +51,6 @@ build_deps :: proc(opts: Options) {
|
||||
fmt.tprintf("-Dtarget=%s", target),
|
||||
},
|
||||
cwd,
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
@ -59,16 +59,33 @@ build_deps :: proc(opts: Options) {
|
||||
cwd := "./libs/physfs"
|
||||
file_name := shared ? "libphysfs.so" : "libphysfs.a"
|
||||
is_built := os.is_file(fmt.tprintf("./libs/physfs/%s", file_name))
|
||||
if is_built && force {
|
||||
handle_error(run_cmd({"make", "clean"}, cwd))
|
||||
if force {
|
||||
remove_all("./libs/physfs/build")
|
||||
}
|
||||
prepare_cmd := []string {
|
||||
"cmake",
|
||||
"-B",
|
||||
"build",
|
||||
fmt.tprintf("-DPHYSFS_BUILD_SHARED=%v", shared),
|
||||
"-DCMAKE_BUILD_TYPE=MinSizeRel",
|
||||
"./physfs",
|
||||
}
|
||||
build_cmd := []string{"cmake", "--build", "build", "--config", "MinSizeRel"}
|
||||
if !is_built || force {
|
||||
handle_error(run_cmd({"make", file_name}, cwd))
|
||||
if opts.variant == .Web {
|
||||
run_cmd(temp_concat({"emcmake"}, prepare_cmd), cwd)
|
||||
run_cmd(temp_concat({"emmake"}, build_cmd), cwd)
|
||||
} else {
|
||||
run_cmd(prepare_cmd, cwd)
|
||||
run_cmd(build_cmd, cwd)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Tracy
|
||||
if opts.tracy {
|
||||
assert(opts.variant != .Web)
|
||||
|
||||
cwd := "./libs/tracy"
|
||||
|
||||
when ODIN_OS == .Windows {
|
||||
@ -90,7 +107,6 @@ build_deps :: proc(opts: Options) {
|
||||
}
|
||||
|
||||
if !is_built || force {
|
||||
handle_error(
|
||||
run_cmd(
|
||||
slice.concatenate(
|
||||
[][]string {
|
||||
@ -108,11 +124,10 @@ build_deps :: proc(opts: Options) {
|
||||
context.temp_allocator,
|
||||
),
|
||||
cwd,
|
||||
),
|
||||
)
|
||||
|
||||
if !shared {
|
||||
handle_error(run_cmd({"zig", "ar", "rc", TRACY_NAME_STATIC, "tracy.o"}, cwd))
|
||||
run_cmd({"zig", "ar", "rc", TRACY_NAME_STATIC, "tracy.o"}, cwd)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -126,6 +141,35 @@ COMMON_FLAGS :: []string {
|
||||
"-vet",
|
||||
}
|
||||
|
||||
setup_emsdk_env :: proc() {
|
||||
when ODIN_OS == .Windows {
|
||||
PATH_ENV_DELIMITER :: ";"
|
||||
} else {
|
||||
PATH_ENV_DELIMITER :: ":"
|
||||
}
|
||||
|
||||
PATHS :: [2]string{"./libs/emsdk/upstream/bin", "./libs/emsdk/upstream/emscripten"}
|
||||
|
||||
paths: [len(PATHS)]string
|
||||
for path, i in PATHS {
|
||||
paths[i] = absolute_path(path)
|
||||
}
|
||||
|
||||
set_env(
|
||||
"PATH",
|
||||
strings.join(
|
||||
{paths[0], paths[1], os.get_env("PATH", context.temp_allocator)},
|
||||
":",
|
||||
context.temp_allocator,
|
||||
),
|
||||
)
|
||||
|
||||
set_env("EMSDK", absolute_path("./libs/emsdk"))
|
||||
}
|
||||
|
||||
archive_assets :: proc() {
|
||||
}
|
||||
|
||||
main :: proc() {
|
||||
context.logger = log.create_console_logger()
|
||||
opts := Options {
|
||||
@ -136,6 +180,8 @@ main :: proc() {
|
||||
if opts.variant == .Web {
|
||||
log.warnf("tracy is not supported on Web")
|
||||
opts.tracy = false
|
||||
|
||||
setup_emsdk_env()
|
||||
}
|
||||
|
||||
tracy_flag: []string = opts.tracy ? {"-define:TRACY_ENABLE=true"} : {}
|
||||
@ -144,8 +190,10 @@ main :: proc() {
|
||||
|
||||
build_deps(opts)
|
||||
|
||||
#partial switch opts.variant {
|
||||
switch opts.variant {
|
||||
case .Hot_Reload:
|
||||
remove_all("./build/hotreload")
|
||||
mkdir_all("./build/hotreload")
|
||||
cmd := slice.concatenate(
|
||||
[][]string {
|
||||
[]string {
|
||||
@ -155,7 +203,7 @@ main :: proc() {
|
||||
"-define:RAYLIB_SHARED=true",
|
||||
"-define:PHYSFS_SHARED=true",
|
||||
"-build-mode:dll",
|
||||
"-out:game_tmp.so",
|
||||
"-out:./build/hotreload/game_tmp.so",
|
||||
},
|
||||
tracy_flag,
|
||||
debug_flag,
|
||||
@ -164,12 +212,14 @@ main :: proc() {
|
||||
},
|
||||
context.temp_allocator,
|
||||
)
|
||||
handle_error(run_cmd(cmd, "."))
|
||||
handle_error(os.rename("game_tmp.so", "game.so"))
|
||||
run_cmd(cmd, "")
|
||||
rename("./build/hotreload/game_tmp.so", "./build/hotreload/game.so")
|
||||
case .Desktop:
|
||||
remove_all("./build/desktop")
|
||||
mkdir_all("./build/desktop")
|
||||
cmd := slice.concatenate(
|
||||
[][]string {
|
||||
[]string{"odin", "build", "main_release", "-out:game.bin"},
|
||||
[]string{"odin", "build", "main_release", "-out:./build/desktop/game"},
|
||||
tracy_flag,
|
||||
debug_flag,
|
||||
optimize_flag,
|
||||
@ -177,17 +227,58 @@ main :: proc() {
|
||||
},
|
||||
context.temp_allocator,
|
||||
)
|
||||
handle_error(run_cmd(cmd, "."))
|
||||
case:
|
||||
run_cmd(cmd, "")
|
||||
case .Web:
|
||||
remove_all("./build/web")
|
||||
mkdir_all("./build/web")
|
||||
|
||||
odin_root := run_cmd({"odin", "root"}, "")
|
||||
|
||||
cmd := slice.concatenate(
|
||||
[][]string {
|
||||
[]string{"odin", "build", "main_web", "-build-mode:obj", "-out:game_web/game"},
|
||||
[]string {
|
||||
"odin",
|
||||
"build",
|
||||
"main_web",
|
||||
"-target:js_wasm32",
|
||||
"-build-mode:obj",
|
||||
"-out:main_web/game",
|
||||
},
|
||||
COMMON_FLAGS,
|
||||
debug_flag,
|
||||
optimize_flag,
|
||||
},
|
||||
)
|
||||
run_cmd(cmd, "")
|
||||
|
||||
run_cmd(
|
||||
{
|
||||
"emcc",
|
||||
"-g",
|
||||
"-o",
|
||||
"build/web/index.html",
|
||||
"main_web/game.wasm.o",
|
||||
"libs/raylib/zig-out-static/lib/libraylib.a",
|
||||
"libs/physfs/build/libphysfs.a",
|
||||
"-sUSE_GLFW=3",
|
||||
"-sWASM_BIGINT",
|
||||
"-sWARN_ON_UNDEFINED_SYMBOLS=0",
|
||||
"-sALLOW_MEMORY_GROWTH",
|
||||
"-sASSERTIONS",
|
||||
"--shell-file",
|
||||
"main_web/index_template.html",
|
||||
"--preload-file",
|
||||
"assets",
|
||||
},
|
||||
"",
|
||||
)
|
||||
|
||||
handle_error(run_cmd(cmd, "."))
|
||||
copy_file(
|
||||
filepath.join(
|
||||
{odin_root, "core", "sys", "wasm", "js", "odin.js"},
|
||||
context.temp_allocator,
|
||||
),
|
||||
"./build/web/odin.js",
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -1,11 +1,14 @@
|
||||
package builder
|
||||
|
||||
import "base:intrinsics"
|
||||
import "core:bufio"
|
||||
import "core:fmt"
|
||||
import "core:io"
|
||||
import "core:log"
|
||||
import os "core:os/os2"
|
||||
import "core:path/filepath"
|
||||
import "core:strings"
|
||||
import "core:thread"
|
||||
|
||||
Process_Error :: enum {
|
||||
OK,
|
||||
@ -18,37 +21,104 @@ Run_Error :: union #shared_nil {
|
||||
os.Error,
|
||||
}
|
||||
|
||||
@(require_results)
|
||||
run_cmd :: proc(cmd: []string, cwd: string, loc := #caller_location) -> Run_Error {
|
||||
run_cmd_internal :: proc(
|
||||
cmd: []string,
|
||||
cwd: string,
|
||||
loc := #caller_location,
|
||||
) -> (
|
||||
result: string,
|
||||
err: Run_Error,
|
||||
) {
|
||||
if len(cwd) > 0 {
|
||||
log.infof(
|
||||
"running [%s]: %s",
|
||||
cwd,
|
||||
strings.join(cmd, " ", context.temp_allocator),
|
||||
location = loc,
|
||||
)
|
||||
} else {
|
||||
log.infof("running: %s", strings.join(cmd, " ", context.temp_allocator), location = loc)
|
||||
}
|
||||
|
||||
r, w := os.pipe() or_return
|
||||
defer os.close(r)
|
||||
desc := os.Process_Desc {
|
||||
command = cmd,
|
||||
working_dir = cwd,
|
||||
stderr = os.stderr,
|
||||
stdout = os.stdout,
|
||||
stdout = w,
|
||||
}
|
||||
|
||||
Read_Context :: struct {
|
||||
r: ^os.File,
|
||||
result: ^string,
|
||||
}
|
||||
|
||||
read_ctx := Read_Context {
|
||||
r = r,
|
||||
result = &result,
|
||||
}
|
||||
|
||||
thread_ctx := context
|
||||
thread_ctx.user_ptr = &read_ctx
|
||||
read_thread := thread.create_and_start(
|
||||
proc() {
|
||||
ctx := cast(^Read_Context)context.user_ptr
|
||||
|
||||
builder: strings.Builder
|
||||
string_writer := strings.to_writer(&builder)
|
||||
defer io.destroy(string_writer)
|
||||
|
||||
mw: io.Multi_Writer
|
||||
w := io.multi_writer_init(&mw, string_writer, os.to_writer(os.stderr))
|
||||
|
||||
tee: io.Tee_Reader
|
||||
reader := io.tee_reader_init(&tee, os.to_reader(ctx.r), w)
|
||||
buf: [1024]u8
|
||||
|
||||
err: io.Error
|
||||
for {
|
||||
n: int
|
||||
n, err = io.read(reader, buf[:], nil)
|
||||
if err == .EOF {
|
||||
break
|
||||
}
|
||||
handle_error(err)
|
||||
}
|
||||
|
||||
// NOTE: mem leak, but who cares
|
||||
ctx.result^ = strings.clone(strings.to_string(builder))
|
||||
},
|
||||
thread_ctx,
|
||||
)
|
||||
|
||||
process := os.process_start(desc) or_return
|
||||
os.close(w)
|
||||
|
||||
state := os.process_wait(process) or_return
|
||||
|
||||
thread.join(read_thread)
|
||||
|
||||
if !state.success {
|
||||
return .Crash
|
||||
return "", .Crash
|
||||
}
|
||||
|
||||
if state.exit_code != 0 {
|
||||
return .Invalid_Exit_Code
|
||||
return "", .Invalid_Exit_Code
|
||||
}
|
||||
|
||||
return nil
|
||||
return result, nil
|
||||
}
|
||||
|
||||
Copy_Error :: union #shared_nil {
|
||||
os.Error,
|
||||
filepath.Match_Error,
|
||||
run_cmd :: proc(
|
||||
cmd: []string,
|
||||
cwd: string,
|
||||
expr := #caller_expression,
|
||||
loc := #caller_location,
|
||||
) -> string {
|
||||
result, err := run_cmd_internal(cmd, cwd, loc)
|
||||
handle_error(err, "", expr, loc)
|
||||
return result
|
||||
}
|
||||
|
||||
handle_error :: proc(
|
||||
@ -78,3 +148,35 @@ remove_all :: proc(path: string, expr := #caller_expression, loc := #caller_loca
|
||||
handle_error(err, fmt.tprintf("failed to remove %s", path), expr = expr, loc = loc)
|
||||
}
|
||||
}
|
||||
|
||||
copy_file :: proc(src, dst: string, expr := #caller_expression, loc := #caller_location) {
|
||||
log.infof("cp %s %s", src, dst)
|
||||
handle_error(os.copy_file(dst, src), "", expr, loc)
|
||||
}
|
||||
|
||||
rename :: proc(src, dst: string, expr := #caller_expression, loc := #caller_location) {
|
||||
log.infof("rename %s -> %s", src, dst)
|
||||
handle_error(os.rename(src, dst), "", expr, loc)
|
||||
}
|
||||
|
||||
mkdir_all :: proc(path: string, expr := #caller_expression, loc := #caller_location) {
|
||||
log.infof("mkdir -p %s", path)
|
||||
handle_error(os.mkdir_all(path), "", expr, loc)
|
||||
}
|
||||
|
||||
absolute_path :: proc(
|
||||
path: string,
|
||||
allocator := context.temp_allocator,
|
||||
expr := #caller_expression,
|
||||
loc := #caller_location,
|
||||
) -> string {
|
||||
abs_path, err := os.get_absolute_path(path, allocator)
|
||||
handle_error(err, "", expr, loc)
|
||||
|
||||
return abs_path
|
||||
}
|
||||
|
||||
set_env :: proc(env, val: string) {
|
||||
log.infof("set_env(%s, %s)", env, val)
|
||||
handle_error(os.set_env(env, val))
|
||||
}
|
||||
|
@ -1,6 +1,5 @@
|
||||
package assets
|
||||
|
||||
import "core:c"
|
||||
import "core:log"
|
||||
import "core:math"
|
||||
import lg "core:math/linalg"
|
||||
@ -21,7 +20,7 @@ Loaded_BVH :: struct {
|
||||
aabb: bvh.AABB,
|
||||
// BVH for each mesh in a model
|
||||
bvhs: []bvh.BVH,
|
||||
modtime: c.long,
|
||||
modtime: physfs.sint64,
|
||||
}
|
||||
|
||||
Loaded_Convex :: struct {
|
||||
@ -198,7 +197,7 @@ assetcache_fetch_or_load :: proc(
|
||||
payload: Asset_Cache_Loader_Payload = nil,
|
||||
) -> (
|
||||
value: E,
|
||||
modtime: i64,
|
||||
modtime: physfs.sint64,
|
||||
result: Asset_Cache_Result,
|
||||
) {
|
||||
tracy.Zone()
|
||||
@ -275,10 +274,10 @@ get_texture :: proc(assetman: ^Asset_Manager, path: cstring) -> rl.Texture2D {
|
||||
get_model_ex :: proc(
|
||||
assetman: ^Asset_Manager,
|
||||
path: cstring,
|
||||
ref_modtime: c.long = 0, // will check reload status using reference load time. When 0 reloaded will be true only if this call triggered reload
|
||||
ref_modtime: physfs.sint64 = 0, // will check reload status using reference load time. When 0 reloaded will be true only if this call triggered reload
|
||||
) -> (
|
||||
model: rl.Model,
|
||||
modtime: c.long,
|
||||
modtime: physfs.sint64,
|
||||
reloaded: bool,
|
||||
) {
|
||||
tracy.Zone()
|
||||
|
@ -1011,25 +1011,25 @@ draw_world :: proc(world: ^World) {
|
||||
car_matrix =
|
||||
(auto_cast linalg.matrix4_translate_f32(physics.body_get_shape_pos(car_body))) * car_matrix
|
||||
|
||||
basic_shader := assets.get_shader(
|
||||
&g_mem.assetman,
|
||||
"assets/shaders/lit_vs.glsl",
|
||||
"assets/shaders/lit_ps.glsl",
|
||||
{.Ambient, .LightDir, .LightColor},
|
||||
)
|
||||
light_dir := linalg.normalize(rl.Vector3{1, -1, 0})
|
||||
ambient := rl.Vector3{0.1, 0.1, 0.1}
|
||||
light_color := rl.Vector3{0.816, 0.855, 0.89}
|
||||
rl.SetShaderValue(basic_shader.shader, basic_shader.locations[.LightDir], &light_dir, .VEC3)
|
||||
rl.SetShaderValue(basic_shader.shader, basic_shader.locations[.Ambient], &ambient, .VEC3)
|
||||
rl.SetShaderValue(
|
||||
basic_shader.shader,
|
||||
basic_shader.locations[.LightColor],
|
||||
&light_color,
|
||||
.VEC3,
|
||||
)
|
||||
// basic_shader := assets.get_shader(
|
||||
// &g_mem.assetman,
|
||||
// "assets/shaders/lit_vs.glsl",
|
||||
// "assets/shaders/lit_ps.glsl",
|
||||
// {.Ambient, .LightDir, .LightColor},
|
||||
// )
|
||||
// light_dir := linalg.normalize(rl.Vector3{1, -1, 0})
|
||||
// ambient := rl.Vector3{0.1, 0.1, 0.1}
|
||||
// light_color := rl.Vector3{0.816, 0.855, 0.89}
|
||||
// rl.SetShaderValue(basic_shader.shader, basic_shader.locations[.LightDir], &light_dir, .VEC3)
|
||||
// rl.SetShaderValue(basic_shader.shader, basic_shader.locations[.Ambient], &ambient, .VEC3)
|
||||
// rl.SetShaderValue(
|
||||
// basic_shader.shader,
|
||||
// basic_shader.locations[.LightColor],
|
||||
// &light_color,
|
||||
// .VEC3,
|
||||
// )
|
||||
|
||||
render.draw_model(car_model, basic_shader.shader, car_matrix)
|
||||
render.draw_model(car_model, {}, car_matrix)
|
||||
|
||||
render.draw_mesh_light(
|
||||
assets.get_model(&g_mem.assetman, "assets/ae86_lights.glb"),
|
||||
@ -1262,7 +1262,14 @@ game_update :: proc() -> bool {
|
||||
|
||||
update()
|
||||
draw()
|
||||
return !rl.WindowShouldClose()
|
||||
|
||||
when ODIN_OS != .JS {
|
||||
// Never run this proc in browser. It contains a 16 ms sleep on web!
|
||||
if rl.WindowShouldClose() {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
@(export)
|
||||
|
@ -138,7 +138,7 @@ draw_debug_scene :: proc(scene: ^Scene) {
|
||||
}
|
||||
}
|
||||
|
||||
if true {
|
||||
if false {
|
||||
for &contact, contact_idx in sim_state.contact_container.contacts {
|
||||
points_a := contact.manifold.points_a
|
||||
points_b := contact.manifold.points_b
|
||||
|
@ -30,9 +30,9 @@ draw_model :: proc(
|
||||
color: rl.Color = rl.WHITE,
|
||||
) {
|
||||
model := model
|
||||
for i in 0 ..< model.materialCount {
|
||||
model.materials[i].shader = shader
|
||||
}
|
||||
// for i in 0 ..< model.materialCount {
|
||||
// model.materials[i].shader = shader
|
||||
// }
|
||||
model.transform = transform
|
||||
|
||||
rl.DrawModel(model, rl.Vector3{}, 1, color)
|
||||
@ -42,7 +42,7 @@ draw_mesh_light :: proc(model: rl.Model, transform: rl.Matrix, color: rl.Color)
|
||||
model := model
|
||||
model.transform = transform
|
||||
|
||||
light_shader := assets.get_shader(assetman, nil, "assets/shaders/light_ps.glsl", {}).shader
|
||||
// light_shader := assets.get_shader(assetman, nil, "assets/shaders/light_ps.glsl", {}).shader
|
||||
|
||||
rlgl.DrawRenderBatchActive()
|
||||
|
||||
@ -56,7 +56,7 @@ draw_mesh_light :: proc(model: rl.Model, transform: rl.Matrix, color: rl.Color)
|
||||
gl.ColorMask(false, false, false, false)
|
||||
rlgl.SetCullFace(.FRONT)
|
||||
|
||||
draw_model(model, light_shader, transform, color)
|
||||
draw_model(model, {}, transform, color)
|
||||
rlgl.DrawRenderBatchActive()
|
||||
}
|
||||
|
||||
@ -68,7 +68,7 @@ draw_mesh_light :: proc(model: rl.Model, transform: rl.Matrix, color: rl.Color)
|
||||
gl.ColorMask(true, true, true, true)
|
||||
rlgl.SetCullFace(.BACK)
|
||||
|
||||
draw_model(model, light_shader, transform, color)
|
||||
draw_model(model, {}, transform, color)
|
||||
rlgl.DrawRenderBatchActive()
|
||||
}
|
||||
|
||||
@ -78,7 +78,7 @@ draw_mesh_light :: proc(model: rl.Model, transform: rl.Matrix, color: rl.Color)
|
||||
gl.DepthFunc(gl.GREATER)
|
||||
rlgl.SetCullFace(.FRONT)
|
||||
|
||||
draw_model(model, light_shader, transform, color)
|
||||
draw_model(model, {}, transform, color)
|
||||
rlgl.DrawRenderBatchActive()
|
||||
}
|
||||
|
||||
|
@ -29,7 +29,7 @@ rl_init :: proc() {
|
||||
rl.SetTextureFilter(default_atlas_texture, .POINT)
|
||||
|
||||
gl.BindTexture(gl.TEXTURE_2D, default_atlas_texture.id)
|
||||
gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_SWIZZLE_A, gl.RED)
|
||||
// gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_SWIZZLE_A, gl.RED)
|
||||
gl.BindTexture(gl.TEXTURE_2D, 0)
|
||||
}
|
||||
|
||||
|
@ -10,6 +10,8 @@ when ODIN_OS == .Linux || ODIN_OS == .Darwin {
|
||||
} else {
|
||||
foreign import lib "libphysfs.a"
|
||||
}
|
||||
} else when ODIN_ARCH == .wasm32 || ODIN_ARCH == .wasm64p32 {
|
||||
foreign import lib "env.o"
|
||||
}
|
||||
|
||||
@(default_calling_convention = "c", link_prefix = "PHYSFS_")
|
||||
|
@ -109,7 +109,7 @@ when ODIN_OS == .Windows {
|
||||
} else when ODIN_OS == .Darwin {
|
||||
foreign import lib {"zig-out-shared/lib/libraylib.dylib" when RAYLIB_SHARED else "zig-out-static/lib/libraylib.a", "system:Cocoa.framework", "system:OpenGL.framework", "system:IOKit.framework"}
|
||||
} else when ODIN_ARCH == .wasm32 || ODIN_ARCH == .wasm64p32 {
|
||||
foreign import lib "zig-out-static/lib/libraylib.a"
|
||||
foreign import lib "env.o"
|
||||
} else {
|
||||
foreign import lib "system:raylib"
|
||||
}
|
||||
|
@ -126,6 +126,8 @@ when ODIN_OS == .Windows {
|
||||
foreign import lib {"../zig-out-shared/lib/libraylib.so" when RAYLIB_SHARED else "../zig-out-static/lib/libraylib.a", "system:dl", "system:pthread"} // Note(bumbread): I'm not sure why in `linux/` folder there are// multiple copies of raylib.so, but since these bindings are for// particular version of the library, I better specify it. Ideally,// though, it's best specified in terms of major (.so.4)
|
||||
} else when ODIN_OS == .Darwin {
|
||||
foreign import lib {"../zig-out-shared/lib/libraylib.dylib" when RAYLIB_SHARED else "../zig-out-static/lib/libraylib.a", "system:Cocoa.framework", "system:OpenGL.framework", "system:IOKit.framework"}
|
||||
} else when ODIN_ARCH == .wasm32 || ODIN_ARCH == .wasm64p32 {
|
||||
foreign import lib "env.o"
|
||||
} else {
|
||||
foreign import lib "system:raylib"
|
||||
}
|
||||
|
@ -3,6 +3,8 @@ package tracy
|
||||
import "core:c"
|
||||
import "core:mem"
|
||||
|
||||
_ :: c
|
||||
|
||||
ProfiledAllocatorData :: struct {
|
||||
backing_allocator: mem.Allocator,
|
||||
profiled_allocator: mem.Allocator,
|
||||
@ -14,16 +16,35 @@ MakeProfiledAllocator :: proc(
|
||||
self: ^ProfiledAllocatorData,
|
||||
callstack_size: i32 = TRACY_CALLSTACK,
|
||||
secure: b32 = false,
|
||||
backing_allocator := context.allocator) -> mem.Allocator {
|
||||
backing_allocator := context.allocator,
|
||||
) -> mem.Allocator {
|
||||
|
||||
self.callstack_size = callstack_size
|
||||
self.secure = secure
|
||||
self.backing_allocator = backing_allocator
|
||||
self.profiled_allocator = mem.Allocator {
|
||||
data = self,
|
||||
procedure = proc(allocator_data: rawptr, mode: mem.Allocator_Mode, size, alignment: int, old_memory: rawptr, old_size: int, location := #caller_location) -> ([]byte, mem.Allocator_Error) {
|
||||
procedure = proc(
|
||||
allocator_data: rawptr,
|
||||
mode: mem.Allocator_Mode,
|
||||
size, alignment: int,
|
||||
old_memory: rawptr,
|
||||
old_size: int,
|
||||
location := #caller_location,
|
||||
) -> (
|
||||
[]byte,
|
||||
mem.Allocator_Error,
|
||||
) {
|
||||
using self := cast(^ProfiledAllocatorData)allocator_data
|
||||
new_memory, error := self.backing_allocator.procedure(self.backing_allocator.data, mode, size, alignment, old_memory, old_size, location)
|
||||
new_memory, error := self.backing_allocator.procedure(
|
||||
self.backing_allocator.data,
|
||||
mode,
|
||||
size,
|
||||
alignment,
|
||||
old_memory,
|
||||
old_size,
|
||||
location,
|
||||
)
|
||||
if error == .None {
|
||||
switch mode {
|
||||
case .Alloc, .Alloc_Non_Zeroed:
|
||||
@ -51,18 +72,27 @@ MakeProfiledAllocator :: proc(
|
||||
EmitAlloc :: #force_inline proc(new_memory: []byte, size: int, callstack_size: i32, secure: b32) {
|
||||
when TRACY_HAS_CALLSTACK {
|
||||
if callstack_size > 0 {
|
||||
___tracy_emit_memory_alloc_callstack(raw_data(new_memory), c.size_t(size), callstack_size, secure)
|
||||
___tracy_emit_memory_alloc_callstack(
|
||||
raw_data(new_memory),
|
||||
c.size_t(size),
|
||||
callstack_size,
|
||||
secure,
|
||||
)
|
||||
} else {
|
||||
___tracy_emit_memory_alloc(raw_data(new_memory), c.size_t(size), secure)
|
||||
}
|
||||
} else {
|
||||
when TRACY_ENABLE {
|
||||
___tracy_emit_memory_alloc(raw_data(new_memory), c.size_t(size), secure)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@(private = "file")
|
||||
EmitFree :: #force_inline proc(old_memory: rawptr, callstack_size: i32, secure: b32) {
|
||||
when TRACY_ENABLE {
|
||||
if old_memory == nil {return}
|
||||
|
||||
when TRACY_HAS_CALLSTACK {
|
||||
if callstack_size > 0 {
|
||||
___tracy_emit_memory_free_callstack(old_memory, callstack_size, secure)
|
||||
@ -73,5 +103,4 @@ EmitFree :: #force_inline proc(old_memory: rawptr, callstack_size: i32, secure:
|
||||
___tracy_emit_memory_free(old_memory, secure)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
@ -2,9 +2,13 @@ package tracy
|
||||
|
||||
import "core:c"
|
||||
|
||||
_ :: c
|
||||
|
||||
when TRACY_ENABLE {
|
||||
when ODIN_OS == .Darwin do foreign import tracy "tracy.dylib"
|
||||
when ODIN_OS == .Windows do foreign import tracy "tracy.lib"
|
||||
when ODIN_OS == .Linux do foreign import tracy "tracy.so"
|
||||
}
|
||||
|
||||
TracyPlotFormatEnum :: enum i32 {
|
||||
TracyPlotFormatNumber,
|
||||
@ -77,6 +81,7 @@ ___tracy_gpu_time_sync_data :: struct {
|
||||
|
||||
__tracy_lockable_context_data :: struct {} // NOTE(oskar): opaque
|
||||
|
||||
when TRACY_ENABLE {
|
||||
when #config(TRACY_MANUAL_LIFETIME, false) {
|
||||
@(default_calling_convention = "c")
|
||||
foreign tracy {
|
||||
@ -85,7 +90,6 @@ when #config(TRACY_MANUAL_LIFETIME, false) {
|
||||
___tracy_profiler_started :: proc() -> b32 ---
|
||||
}
|
||||
}
|
||||
|
||||
@(default_calling_convention = "c")
|
||||
foreign tracy {
|
||||
___tracy_set_thread_name :: proc(name: cstring) ---
|
||||
@ -169,3 +173,4 @@ when #config(TRACY_FIBERS, false) {
|
||||
___tracy_fiber_leave :: proc() ---
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2,6 +2,8 @@ package tracy
|
||||
|
||||
import "core:c"
|
||||
|
||||
_ :: c
|
||||
|
||||
TRACY_ENABLE :: #config(TRACY_ENABLE, false)
|
||||
TRACY_CALLSTACK :: #config(TRACY_CALLSTACK, 1)
|
||||
TRACY_HAS_CALLSTACK :: #config(TRACY_HAS_CALLSTACK, false)
|
||||
@ -62,19 +64,25 @@ ZoneCS :: ZoneC
|
||||
ZoneNCS :: ZoneNC
|
||||
|
||||
@(disabled = !TRACY_ENABLE)
|
||||
ZoneText :: #force_inline proc(ctx: ZoneCtx, text: string) {___tracy_emit_zone_text(
|
||||
ctx,
|
||||
_sl(text),
|
||||
)}
|
||||
ZoneText :: #force_inline proc(
|
||||
ctx: ZoneCtx,
|
||||
text: string,
|
||||
) {when TRACY_ENABLE {___tracy_emit_zone_text(ctx, _sl(text))}}
|
||||
@(disabled = !TRACY_ENABLE)
|
||||
ZoneName :: #force_inline proc(ctx: ZoneCtx, name: string) {___tracy_emit_zone_name(
|
||||
ctx,
|
||||
_sl(name),
|
||||
)}
|
||||
ZoneName :: #force_inline proc(
|
||||
ctx: ZoneCtx,
|
||||
name: string,
|
||||
) {when TRACY_ENABLE {___tracy_emit_zone_name(ctx, _sl(name))}}
|
||||
@(disabled = !TRACY_ENABLE)
|
||||
ZoneColor :: #force_inline proc(ctx: ZoneCtx, color: u32) {___tracy_emit_zone_color(ctx, color)}
|
||||
ZoneColor :: #force_inline proc(
|
||||
ctx: ZoneCtx,
|
||||
color: u32,
|
||||
) {when TRACY_ENABLE {___tracy_emit_zone_color(ctx, color)}}
|
||||
@(disabled = !TRACY_ENABLE)
|
||||
ZoneValue :: #force_inline proc(ctx: ZoneCtx, value: u64) {___tracy_emit_zone_value(ctx, value)}
|
||||
ZoneValue :: #force_inline proc(
|
||||
ctx: ZoneCtx,
|
||||
value: u64,
|
||||
) {when TRACY_ENABLE {___tracy_emit_zone_value(ctx, value)}}
|
||||
|
||||
// NOTE: scoped Zone*() procs also exists, no need of calling this directly.
|
||||
ZoneBegin :: proc(active: bool, depth: i32, loc := #caller_location) -> (ctx: ZoneCtx) {
|
||||
@ -98,7 +106,7 @@ ZoneBegin :: proc(active: bool, depth: i32, loc := #caller_location) -> (ctx: Zo
|
||||
|
||||
// NOTE: scoped Zone*() procs also exists, no need of calling this directly.
|
||||
@(disabled = !TRACY_ENABLE)
|
||||
ZoneEnd :: #force_inline proc(ctx: ZoneCtx) {___tracy_emit_zone_end(ctx)}
|
||||
ZoneEnd :: #force_inline proc(ctx: ZoneCtx) {when TRACY_ENABLE {___tracy_emit_zone_end(ctx)}}
|
||||
|
||||
// Memory profiling
|
||||
// (See allocator.odin for an implementation of an Odin custom allocator using memory profiling.)
|
||||
@ -107,89 +115,91 @@ Alloc :: #force_inline proc(
|
||||
ptr: rawptr,
|
||||
size: c.size_t,
|
||||
depth: i32 = TRACY_CALLSTACK,
|
||||
) {when TRACY_HAS_CALLSTACK {___tracy_emit_memory_alloc_callstack(
|
||||
) {when TRACY_ENABLE {when TRACY_HAS_CALLSTACK {___tracy_emit_memory_alloc_callstack(
|
||||
ptr,
|
||||
size,
|
||||
depth,
|
||||
false,
|
||||
)} else {___tracy_emit_memory_alloc(ptr, size, false)}}
|
||||
)} else {___tracy_emit_memory_alloc(ptr, size, false)}}}
|
||||
@(disabled = !TRACY_ENABLE)
|
||||
Free :: #force_inline proc(
|
||||
ptr: rawptr,
|
||||
depth: i32 = TRACY_CALLSTACK,
|
||||
) {when TRACY_HAS_CALLSTACK {___tracy_emit_memory_free_callstack(
|
||||
) {when TRACY_ENABLE {when TRACY_HAS_CALLSTACK {___tracy_emit_memory_free_callstack(
|
||||
ptr,
|
||||
depth,
|
||||
false,
|
||||
)} else {___tracy_emit_memory_free(ptr, false)}}
|
||||
)} else {___tracy_emit_memory_free(ptr, false)}}}
|
||||
@(disabled = !TRACY_ENABLE)
|
||||
SecureAlloc :: #force_inline proc(
|
||||
ptr: rawptr,
|
||||
size: c.size_t,
|
||||
depth: i32 = TRACY_CALLSTACK,
|
||||
) {when TRACY_HAS_CALLSTACK {___tracy_emit_memory_alloc_callstack(
|
||||
) {when TRACY_ENABLE {when TRACY_HAS_CALLSTACK {___tracy_emit_memory_alloc_callstack(
|
||||
ptr,
|
||||
size,
|
||||
depth,
|
||||
true,
|
||||
)} else {___tracy_emit_memory_alloc(ptr, size, true)}}
|
||||
)} else {___tracy_emit_memory_alloc(ptr, size, true)}}}
|
||||
@(disabled = !TRACY_ENABLE)
|
||||
SecureFree :: #force_inline proc(
|
||||
ptr: rawptr,
|
||||
depth: i32 = TRACY_CALLSTACK,
|
||||
) {when TRACY_HAS_CALLSTACK {___tracy_emit_memory_free_callstack(
|
||||
) {when TRACY_ENABLE {when TRACY_HAS_CALLSTACK {___tracy_emit_memory_free_callstack(
|
||||
ptr,
|
||||
depth,
|
||||
true,
|
||||
)} else {___tracy_emit_memory_free(ptr, true)}}
|
||||
)} else {___tracy_emit_memory_free(ptr, true)}}}
|
||||
@(disabled = !TRACY_ENABLE)
|
||||
AllocN :: #force_inline proc(
|
||||
ptr: rawptr,
|
||||
size: c.size_t,
|
||||
name: cstring,
|
||||
depth: i32 = TRACY_CALLSTACK,
|
||||
) {when TRACY_HAS_CALLSTACK {___tracy_emit_memory_alloc_callstack_named(
|
||||
ptr,
|
||||
size,
|
||||
depth,
|
||||
false,
|
||||
name,
|
||||
)} else {___tracy_emit_memory_alloc_named(ptr, size, false, name)}}
|
||||
) {
|
||||
when TRACY_ENABLE {
|
||||
when TRACY_HAS_CALLSTACK {
|
||||
___tracy_emit_memory_alloc_callstack_named(ptr, size, depth, false, name)
|
||||
} else {
|
||||
__tracy_emit_memory_alloc_named(ptr, size, false, name)
|
||||
}
|
||||
}
|
||||
}
|
||||
@(disabled = !TRACY_ENABLE)
|
||||
FreeN :: #force_inline proc(
|
||||
ptr: rawptr,
|
||||
name: cstring,
|
||||
depth: i32 = TRACY_CALLSTACK,
|
||||
) {when TRACY_HAS_CALLSTACK {___tracy_emit_memory_free_callstack_named(
|
||||
) {when TRACY_ENABLE {when TRACY_HAS_CALLSTACK {___tracy_emit_memory_free_callstack_named(
|
||||
ptr,
|
||||
depth,
|
||||
false,
|
||||
name,
|
||||
)} else {___tracy_emit_memory_free_named(ptr, false, name)}}
|
||||
)} else {___tracy_emit_memory_free_named(ptr, false, name)}}}
|
||||
@(disabled = !TRACY_ENABLE)
|
||||
SecureAllocN :: #force_inline proc(
|
||||
ptr: rawptr,
|
||||
size: c.size_t,
|
||||
name: cstring,
|
||||
depth: i32 = TRACY_CALLSTACK,
|
||||
) {when TRACY_HAS_CALLSTACK {___tracy_emit_memory_alloc_callstack_named(
|
||||
) {when TRACY_ENABLE {when TRACY_HAS_CALLSTACK {___tracy_emit_memory_alloc_callstack_named(
|
||||
ptr,
|
||||
size,
|
||||
depth,
|
||||
true,
|
||||
name,
|
||||
)} else {___tracy_emit_memory_alloc_named(ptr, size, true, name)}}
|
||||
)} else {when TRACY_ENABLE {___tracy_emit_memory_alloc_named(ptr, size, true, name)}}}}
|
||||
@(disabled = !TRACY_ENABLE)
|
||||
SecureFreeN :: #force_inline proc(
|
||||
ptr: rawptr,
|
||||
name: cstring,
|
||||
depth: i32 = TRACY_CALLSTACK,
|
||||
) {when TRACY_HAS_CALLSTACK {___tracy_emit_memory_free_callstack_named(
|
||||
) {when TRACY_ENABLE {when TRACY_HAS_CALLSTACK {___tracy_emit_memory_free_callstack_named(
|
||||
ptr,
|
||||
depth,
|
||||
true,
|
||||
name,
|
||||
)} else {___tracy_emit_memory_free_named(ptr, true, name)}}
|
||||
)} else {___tracy_emit_memory_free_named(ptr, true, name)}}}
|
||||
|
||||
// Dummy aliases to match C API (only difference is the `depth` parameter,
|
||||
// which we declare as optional for the non-S procs.)
|
||||
@ -204,48 +214,67 @@ SecureFreeNS :: SecureFreeN
|
||||
|
||||
// Frame markup
|
||||
@(disabled = !TRACY_ENABLE)
|
||||
FrameMark :: #force_inline proc(name: cstring = nil) {___tracy_emit_frame_mark(name)}
|
||||
FrameMark :: #force_inline proc(name: cstring = nil) {when TRACY_ENABLE {___tracy_emit_frame_mark(
|
||||
name,
|
||||
)}}
|
||||
@(disabled = !TRACY_ENABLE)
|
||||
FrameMarkStart :: #force_inline proc(name: cstring) {___tracy_emit_frame_mark_start(name)}
|
||||
FrameMarkStart :: #force_inline proc(
|
||||
name: cstring,
|
||||
) {when TRACY_ENABLE {___tracy_emit_frame_mark_start(name)}}
|
||||
@(disabled = !TRACY_ENABLE)
|
||||
FrameMarkEnd :: #force_inline proc(name: cstring) {___tracy_emit_frame_mark_end(name)}
|
||||
FrameMarkEnd :: #force_inline proc(
|
||||
name: cstring,
|
||||
) {when TRACY_ENABLE {___tracy_emit_frame_mark_end(name)}}
|
||||
@(disabled = !TRACY_ENABLE)
|
||||
FrameImage :: #force_inline proc(
|
||||
image: rawptr,
|
||||
w, h: u16,
|
||||
offset: u8,
|
||||
flip: b32,
|
||||
) {___tracy_emit_frame_image(image, w, h, offset, flip)}
|
||||
) {when TRACY_ENABLE {___tracy_emit_frame_image(image, w, h, offset, flip)}}
|
||||
|
||||
// Plots and messages
|
||||
@(disabled = !TRACY_ENABLE)
|
||||
Plot :: #force_inline proc(name: cstring, value: f64) {___tracy_emit_plot(name, value)}
|
||||
Plot :: #force_inline proc(name: cstring, value: f64) {when TRACY_ENABLE {___tracy_emit_plot(
|
||||
name,
|
||||
value,
|
||||
)}}
|
||||
@(disabled = !TRACY_ENABLE)
|
||||
PlotF :: #force_inline proc(name: cstring, value: f32) {___tracy_emit_plot_float(name, value)}
|
||||
PlotF :: #force_inline proc(
|
||||
name: cstring,
|
||||
value: f32,
|
||||
) {when TRACY_ENABLE {___tracy_emit_plot_float(name, value)}}
|
||||
@(disabled = !TRACY_ENABLE)
|
||||
PlotI :: #force_inline proc(name: cstring, value: i64) {___tracy_emit_plot_int(name, value)}
|
||||
PlotI :: #force_inline proc(name: cstring, value: i64) {when TRACY_ENABLE {___tracy_emit_plot_int(
|
||||
name,
|
||||
value,
|
||||
)}}
|
||||
@(disabled = !TRACY_ENABLE)
|
||||
PlotConfig :: #force_inline proc(
|
||||
name: cstring,
|
||||
type: TracyPlotFormatEnum,
|
||||
step, fill: b32,
|
||||
color: u32,
|
||||
) {___tracy_emit_plot_config(name, type, step, fill, color)}
|
||||
) {when TRACY_ENABLE {___tracy_emit_plot_config(name, type, step, fill, color)}}
|
||||
@(disabled = !TRACY_ENABLE)
|
||||
Message :: #force_inline proc(txt: string) {___tracy_emit_message(
|
||||
Message :: #force_inline proc(txt: string) {when TRACY_ENABLE {___tracy_emit_message(
|
||||
_sl(txt),
|
||||
TRACY_CALLSTACK when TRACY_HAS_CALLSTACK else 0,
|
||||
)}
|
||||
)}}
|
||||
@(disabled = !TRACY_ENABLE)
|
||||
MessageC :: #force_inline proc(txt: string, color: u32) {___tracy_emit_message(
|
||||
MessageC :: #force_inline proc(txt: string, color: u32) {when TRACY_ENABLE {___tracy_emit_message(
|
||||
_sl(txt),
|
||||
TRACY_CALLSTACK when TRACY_HAS_CALLSTACK else 0,
|
||||
)}
|
||||
)}}
|
||||
@(disabled = !TRACY_ENABLE)
|
||||
AppInfo :: #force_inline proc(name: string) {___tracy_emit_message_appinfo(_sl(name))}
|
||||
AppInfo :: #force_inline proc(name: string) {when TRACY_ENABLE {___tracy_emit_message_appinfo(
|
||||
_sl(name),
|
||||
)}}
|
||||
|
||||
@(disabled = !TRACY_ENABLE)
|
||||
SetThreadName :: #force_inline proc(name: cstring) {___tracy_set_thread_name(name)}
|
||||
SetThreadName :: #force_inline proc(name: cstring) {when TRACY_ENABLE {___tracy_set_thread_name(
|
||||
name,
|
||||
)}}
|
||||
|
||||
// Connection status
|
||||
IsConnected :: #force_inline proc() -> bool {return(
|
||||
@ -299,28 +328,38 @@ LockAnnounce :: #force_inline proc(loc := #caller_location) -> (ctx: LockCtx) {
|
||||
return
|
||||
}
|
||||
@(disabled = !TRACY_ENABLE)
|
||||
LockTerminate :: #force_inline proc(lock: LockCtx) {___tracy_terminate_lockable_ctx(lock)}
|
||||
LockTerminate :: #force_inline proc(
|
||||
lock: LockCtx,
|
||||
) {when TRACY_ENABLE {___tracy_terminate_lockable_ctx(lock)}}
|
||||
@(disabled = !TRACY_ENABLE)
|
||||
LockBeforeLock :: #force_inline proc(lock: LockCtx) {___tracy_before_lock_lockable_ctx(lock)}
|
||||
LockBeforeLock :: #force_inline proc(
|
||||
lock: LockCtx,
|
||||
) {when TRACY_ENABLE {___tracy_before_lock_lockable_ctx(lock)}}
|
||||
@(disabled = !TRACY_ENABLE)
|
||||
LockAfterLock :: #force_inline proc(lock: LockCtx) {___tracy_after_lock_lockable_ctx(lock)}
|
||||
LockAfterLock :: #force_inline proc(
|
||||
lock: LockCtx,
|
||||
) {when TRACY_ENABLE {___tracy_after_lock_lockable_ctx(lock)}}
|
||||
@(disabled = !TRACY_ENABLE)
|
||||
LockAfterUnlock :: #force_inline proc(lock: LockCtx) {___tracy_after_unlock_lockable_ctx(lock)}
|
||||
LockAfterUnlock :: #force_inline proc(
|
||||
lock: LockCtx,
|
||||
) {when TRACY_ENABLE {___tracy_after_unlock_lockable_ctx(lock)}}
|
||||
@(disabled = !TRACY_ENABLE)
|
||||
LockAfterTryLock :: #force_inline proc(
|
||||
lock: LockCtx,
|
||||
acquired: bool,
|
||||
) {___tracy_after_try_lock_lockable_ctx(lock, b32(acquired))}
|
||||
) {when TRACY_ENABLE {___tracy_after_try_lock_lockable_ctx(lock, b32(acquired))}}
|
||||
@(disabled = !TRACY_ENABLE)
|
||||
LockMark :: #force_inline proc(lock: LockCtx, loc := #caller_location) {
|
||||
when TRACY_ENABLE {
|
||||
id := ___tracy_alloc_srcloc(u32(loc.line), _sl(loc.file_path), _sl(loc.procedure))
|
||||
___tracy_mark_lockable_ctx(lock, (^___tracy_source_location_data)(uintptr(id)))
|
||||
}
|
||||
}
|
||||
@(disabled = !TRACY_ENABLE)
|
||||
LockCustomName :: #force_inline proc(
|
||||
lock: LockCtx,
|
||||
name: string,
|
||||
) {___tracy_custom_name_lockable_ctx(lock, _sl(name))}
|
||||
) {when TRACY_ENABLE {___tracy_custom_name_lockable_ctx(lock, _sl(name))}}
|
||||
|
||||
// Helper for passing cstring+length to Tracy functions.
|
||||
@(private = "file")
|
||||
|
BIN
main_web/game.wasm.o
Normal file
BIN
main_web/game.wasm.o
Normal file
Binary file not shown.
@ -5,24 +5,19 @@
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
|
||||
|
||||
<title>Odin + Raylib on the web</title>
|
||||
|
||||
<meta name="title" content="Odin + Raylib on the web">
|
||||
<meta name="description" content="Make games using Odin + Raylib that work in the browser">
|
||||
<meta name="viewport" content="width=device-width">
|
||||
|
||||
<!-- Favicon -->
|
||||
<link rel="shortcut icon" href="https://www.raylib.com/favicon.ico">
|
||||
|
||||
<!-- Web Style -->
|
||||
<style>
|
||||
body {
|
||||
margin: 0px;
|
||||
overflow: hidden;
|
||||
background-color: black;
|
||||
}
|
||||
canvas.emscripten {
|
||||
canvas.game_canvas {
|
||||
border: 0px none;
|
||||
background-color: black;}
|
||||
background-color: black;
|
||||
padding-left: 0;
|
||||
padding-right: 0;
|
||||
margin-left: auto;
|
||||
@ -30,33 +25,73 @@
|
||||
display: block;
|
||||
}
|
||||
</style>
|
||||
<script type='text/javascript' src="https://cdn.jsdelivr.net/gh/eligrey/FileSaver.js/dist/FileSaver.min.js"> </script>
|
||||
<script type='text/javascript'>
|
||||
function saveFileFromMEMFSToDisk(memoryFSname, localFSname) // This can be called by C/C++ code
|
||||
{
|
||||
var isSafari = false; // Not supported, navigator.userAgent access is being restricted
|
||||
//var isSafari = /^((?!chrome|android).)*safari/i.test(navigator.userAgent);
|
||||
var data = FS.readFile(memoryFSname);
|
||||
var blob;
|
||||
|
||||
if (isSafari) blob = new Blob([data.buffer], { type: "application/octet-stream" });
|
||||
else blob = new Blob([data.buffer], { type: "application/octet-binary" });
|
||||
|
||||
// NOTE: SaveAsDialog is a browser setting. For example, in Google Chrome,
|
||||
// in Settings/Advanced/Downloads section you have a setting:
|
||||
// 'Ask where to save each file before downloading' - which you can set true/false.
|
||||
// If you enable this setting it would always ask you and bring the SaveAsDialog
|
||||
saveAs(blob, localFSname);
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<canvas class=emscripten id=canvas oncontextmenu=event.preventDefault() tabindex=-1></canvas>
|
||||
<p id="output" />
|
||||
<canvas class="game_canvas" id="canvas" oncontextmenu="event.preventDefault()" tabindex="-1" onmousedown="event.target.focus()" onkeydown="event.preventDefault()"></canvas>
|
||||
<script type="text/javascript" src="odin.js"></script>
|
||||
<script>
|
||||
var odinMemoryInterface = new odin.WasmMemoryInterface();
|
||||
odinMemoryInterface.setIntSize(4);
|
||||
var odinImports = odin.setupDefaultImports(odinMemoryInterface);
|
||||
|
||||
// The Module is used as configuration for emscripten.
|
||||
var Module = {
|
||||
// This is called by emscripten when it starts up.
|
||||
instantiateWasm: (imports, successCallback) => {
|
||||
const newImports = {
|
||||
...odinImports,
|
||||
...imports
|
||||
}
|
||||
|
||||
return WebAssembly.instantiateStreaming(fetch("index.wasm"), newImports).then(function(output) {
|
||||
var e = output.instance.exports;
|
||||
odinMemoryInterface.setExports(e);
|
||||
odinMemoryInterface.setMemory(e.memory);
|
||||
return successCallback(output.instance);
|
||||
});
|
||||
},
|
||||
// This happens a bit after `instantiateWasm`, when everything is
|
||||
// done setting up. At that point we can run code.
|
||||
onRuntimeInitialized: () => {
|
||||
var e = wasmExports;
|
||||
|
||||
// Calls any procedure marked with @init
|
||||
e._start();
|
||||
|
||||
// See source/main_web/main_web.odin for main_start,
|
||||
// main_update and main_end.
|
||||
e.main_start();
|
||||
|
||||
function send_resize() {
|
||||
var canvas = document.getElementById('canvas');
|
||||
e.web_window_size_changed(canvas.width, canvas.height);
|
||||
}
|
||||
|
||||
window.addEventListener('resize', function(event) {
|
||||
send_resize();
|
||||
}, true);
|
||||
|
||||
// This can probably be done better: Ideally we'd feed the
|
||||
// initial size to `main_start`. But there seems to be a
|
||||
// race condition. `canvas` doesn't have it's correct size yet.
|
||||
send_resize();
|
||||
|
||||
// Runs the "main loop".
|
||||
function do_main_update() {
|
||||
if (!e.main_update()) {
|
||||
e.main_end();
|
||||
|
||||
// Calls procedures marked with @fini
|
||||
e._end();
|
||||
return;
|
||||
}
|
||||
window.requestAnimationFrame(do_main_update);
|
||||
}
|
||||
|
||||
window.requestAnimationFrame(do_main_update);
|
||||
},
|
||||
print: (function() {
|
||||
var element = document.getElementById('output');
|
||||
var element = document.getElementById("output");
|
||||
if (element) element.value = ''; // clear browser cache
|
||||
return function(text) {
|
||||
if (arguments.length > 1) text = Array.prototype.slice.call(arguments).join(' ');
|
||||
@ -68,11 +103,12 @@
|
||||
};
|
||||
})(),
|
||||
canvas: (function() {
|
||||
var canvas = document.getElementById('canvas');
|
||||
return canvas;
|
||||
return document.getElementById("canvas");
|
||||
})()
|
||||
};
|
||||
</script>
|
||||
|
||||
<!-- Emscripten injects its javascript here -->
|
||||
{{{ SCRIPT }}}
|
||||
</body>
|
||||
</html>
|
||||
|
@ -1,37 +0,0 @@
|
||||
#include <stdlib.h>
|
||||
#include <emscripten/emscripten.h>
|
||||
#include <emscripten/html5.h>
|
||||
|
||||
extern void web_init();
|
||||
extern void web_update();
|
||||
extern void web_window_size_changed(int w, int h);
|
||||
|
||||
void update_window_size() {
|
||||
double w, h;
|
||||
emscripten_get_element_css_size("#canvas", &w, &h);
|
||||
web_window_size_changed((int)w, (int)h);
|
||||
}
|
||||
|
||||
static EM_BOOL on_web_display_size_changed(
|
||||
int event_type,
|
||||
const EmscriptenUiEvent *event,
|
||||
void *user_data
|
||||
) {
|
||||
update_window_size();
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main(void) {
|
||||
emscripten_set_resize_callback(
|
||||
EMSCRIPTEN_EVENT_TARGET_WINDOW,
|
||||
0, 0, on_web_display_size_changed
|
||||
);
|
||||
|
||||
web_init();
|
||||
update_window_size();
|
||||
emscripten_set_main_loop(web_update, 0, 1);
|
||||
|
||||
// We don't really "shutdown" the game, since web browser tabs just close.
|
||||
|
||||
return 0;
|
||||
}
|
@ -29,7 +29,7 @@ main_start :: proc "c" () {
|
||||
|
||||
web_context = context
|
||||
|
||||
game.game_init_window({})
|
||||
game.game_init_window({"."})
|
||||
game.game_init()
|
||||
}
|
||||
|
||||
|
@ -1,120 +0,0 @@
|
||||
/*
|
||||
This file implements logger and temp allocator for the web build. The logger
|
||||
is based on the one found here: https://github.com/Aronicu/Raylib-WASM/tree/main
|
||||
*/
|
||||
|
||||
#+build wasm32, wasm64p32
|
||||
|
||||
package main_web
|
||||
|
||||
import "base:runtime"
|
||||
import "core:c"
|
||||
import "core:fmt"
|
||||
import "core:log"
|
||||
import "core:strings"
|
||||
|
||||
|
||||
// WASM logger
|
||||
|
||||
WASM_Logger_Opts :: log.Options{.Level, .Short_File_Path, .Line}
|
||||
|
||||
create_wasm_logger :: proc (lowest := log.Level.Debug, opt := WASM_Logger_Opts) -> log.Logger {
|
||||
return log.Logger{data = nil, procedure = wasm_logger_proc, lowest_level = lowest, options = opt}
|
||||
}
|
||||
|
||||
@(private="file")
|
||||
wasm_logger_proc :: proc(
|
||||
logger_data: rawptr,
|
||||
level: log.Level,
|
||||
text: string,
|
||||
options: log.Options,
|
||||
location := #caller_location
|
||||
) {
|
||||
b := strings.builder_make(context.temp_allocator)
|
||||
strings.write_string(&b, Wasm_Logger_Level_Headers[level])
|
||||
do_location_header(options, &b, location)
|
||||
fmt.sbprint(&b, text)
|
||||
puts(strings.to_cstring(&b))
|
||||
}
|
||||
|
||||
@(private="file")
|
||||
Wasm_Logger_Level_Headers := [?]string {
|
||||
0 ..< 10 = "[DEBUG] --- ",
|
||||
10 ..< 20 = "[INFO ] --- ",
|
||||
20 ..< 30 = "[WARN ] --- ",
|
||||
30 ..< 40 = "[ERROR] --- ",
|
||||
40 ..< 50 = "[FATAL] --- ",
|
||||
}
|
||||
|
||||
@(private="file")
|
||||
do_location_header :: proc(opts: log.Options, buf: ^strings.Builder, location := #caller_location) {
|
||||
if log.Location_Header_Opts & opts == nil {
|
||||
return
|
||||
}
|
||||
fmt.sbprint(buf, "[")
|
||||
file := location.file_path
|
||||
if .Short_File_Path in opts {
|
||||
last := 0
|
||||
for r, i in location.file_path {
|
||||
if r == '/' {
|
||||
last = i + 1
|
||||
}
|
||||
}
|
||||
file = location.file_path[last:]
|
||||
}
|
||||
|
||||
if log.Location_File_Opts & opts != nil {
|
||||
fmt.sbprint(buf, file)
|
||||
}
|
||||
if .Line in opts {
|
||||
if log.Location_File_Opts & opts != nil {
|
||||
fmt.sbprint(buf, ":")
|
||||
}
|
||||
fmt.sbprint(buf, location.line)
|
||||
}
|
||||
|
||||
if .Procedure in opts {
|
||||
if (log.Location_File_Opts | {.Line}) & opts != nil {
|
||||
fmt.sbprint(buf, ":")
|
||||
}
|
||||
fmt.sbprintf(buf, "%s()", location.procedure)
|
||||
}
|
||||
|
||||
fmt.sbprint(buf, "] ")
|
||||
}
|
||||
|
||||
@(default_calling_convention = "c")
|
||||
foreign {
|
||||
puts :: proc(buffer: cstring) -> c.int ---
|
||||
}
|
||||
|
||||
|
||||
// Temp Allocator
|
||||
// More or less a copy from base:runtime (that one is disabled in freestanding
|
||||
// build mode).
|
||||
|
||||
WASM_Temp_Allocator :: struct {
|
||||
arena: runtime.Arena,
|
||||
}
|
||||
|
||||
wasm_temp_allocator_init :: proc(s: ^WASM_Temp_Allocator, size: int, backing_allocator := context.allocator) {
|
||||
_ = runtime.arena_init(&s.arena, uint(size), backing_allocator)
|
||||
}
|
||||
|
||||
wasm_temp_allocator_proc :: proc(
|
||||
allocator_data: rawptr,
|
||||
mode: runtime.Allocator_Mode,
|
||||
size, alignment: int,
|
||||
old_memory: rawptr,
|
||||
old_size: int,
|
||||
loc := #caller_location) -> (data: []byte, err: runtime.Allocator_Error) {
|
||||
s := (^WASM_Temp_Allocator)(allocator_data)
|
||||
return runtime.arena_allocator_proc(&s.arena, mode, size, alignment, old_memory, old_size, loc)
|
||||
}
|
||||
|
||||
wasm_temp_allocator :: proc(allocator: ^WASM_Temp_Allocator) -> runtime.Allocator {
|
||||
return runtime.Allocator{
|
||||
procedure = wasm_temp_allocator_proc,
|
||||
data = allocator,
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user