Start implementing a proper build system
This commit is contained in:
parent
6e2ad6a3b0
commit
7cda6a3f7d
193
builder/builder.odin
Normal file
193
builder/builder.odin
Normal file
@ -0,0 +1,193 @@
|
||||
package builder
|
||||
|
||||
import "core:flags"
|
||||
import "core:fmt"
|
||||
import "core:log"
|
||||
import os "core:os/os2"
|
||||
import "core:slice"
|
||||
|
||||
Build_Variant :: enum {
|
||||
Hot_Reload,
|
||||
Desktop,
|
||||
Web,
|
||||
}
|
||||
|
||||
Options :: struct {
|
||||
variant: Build_Variant `usage:"Variant of the build"`,
|
||||
optimize: bool `args:"name=opt",usage:"Enable compiler optimizations"`,
|
||||
debug: bool `usage:"Enable debug symbols"`,
|
||||
rebuild_deps: bool `usage:"When enabled dependencies will be cleaned and rebuilt"`,
|
||||
tracy: bool `usage:"Enable tracy profiler"`,
|
||||
}
|
||||
|
||||
Error :: union #shared_nil {
|
||||
Run_Error,
|
||||
Copy_Error,
|
||||
os.Error,
|
||||
}
|
||||
|
||||
build_deps :: proc(opts: Options) {
|
||||
log.infof("build_deps")
|
||||
force := opts.rebuild_deps
|
||||
shared := opts.variant == .Hot_Reload
|
||||
// Raylib
|
||||
{
|
||||
cwd := "./libs/raylib"
|
||||
out_dir := shared ? "zig-out-shared" : "zig-out-static"
|
||||
if force {
|
||||
remove_all(fmt.tprintf("./libs/raylib/%s", out_dir))
|
||||
}
|
||||
|
||||
target := opts.variant == .Web ? "wasm32-emscripten" : "native"
|
||||
handle_error(
|
||||
run_cmd(
|
||||
{
|
||||
"zig",
|
||||
"build",
|
||||
"-p",
|
||||
out_dir,
|
||||
fmt.tprintf("-Dshared=%v", shared),
|
||||
fmt.tprintf("-Dtarget=%s", target),
|
||||
},
|
||||
cwd,
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
// Physfs
|
||||
{
|
||||
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 !is_built || force {
|
||||
handle_error(run_cmd({"make", file_name}, cwd))
|
||||
}
|
||||
}
|
||||
|
||||
// Tracy
|
||||
if opts.tracy {
|
||||
cwd := "./libs/tracy"
|
||||
|
||||
when ODIN_OS == .Windows {
|
||||
TRACY_NAME_SHARED :: "tracydll.lib"
|
||||
TRACY_NAME_STATIC :: "tracy.lib"
|
||||
} else when ODIN_OS == .Linux {
|
||||
TRACY_NAME_SHARED :: "tracy.so"
|
||||
TRACY_NAME_STATIC :: "tracy.a"
|
||||
} else when ODIN_OS == .Darwin {
|
||||
TRACY_NAME_SHARED :: "tracy.dynlib"
|
||||
TRACY_NAME_STATIC :: "tracy.a"
|
||||
}
|
||||
|
||||
file_path := fmt.tprintf("./libs/tracy/%s", shared ? TRACY_NAME_SHARED : TRACY_NAME_STATIC)
|
||||
|
||||
is_built := os.is_file(file_path)
|
||||
if is_built && force {
|
||||
remove_file(file_path)
|
||||
}
|
||||
|
||||
if !is_built || force {
|
||||
handle_error(
|
||||
run_cmd(
|
||||
slice.concatenate(
|
||||
[][]string {
|
||||
{
|
||||
"zig",
|
||||
"c++",
|
||||
"-std=c++11",
|
||||
"-DTRACY_ENABLE",
|
||||
"-O2",
|
||||
"vendor/tracy/public/TracyClient.cpp",
|
||||
"-fPIC",
|
||||
},
|
||||
shared ? {"-shared", "-o", TRACY_NAME_SHARED} : {"-c", "-o", "tracy.o"},
|
||||
},
|
||||
context.temp_allocator,
|
||||
),
|
||||
cwd,
|
||||
),
|
||||
)
|
||||
|
||||
if !shared {
|
||||
handle_error(run_cmd({"zig", "ar", "rc", TRACY_NAME_STATIC, "tracy.o"}, cwd))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
COMMON_FLAGS :: []string {
|
||||
"-collection:libs=./libs",
|
||||
"-collection:common=./common",
|
||||
"-collection:game=./game",
|
||||
"-strict-style",
|
||||
"-vet",
|
||||
}
|
||||
|
||||
main :: proc() {
|
||||
context.logger = log.create_console_logger()
|
||||
opts := Options {
|
||||
tracy = true,
|
||||
debug = true,
|
||||
}
|
||||
flags.parse_or_exit(&opts, os.args, .Unix, context.temp_allocator)
|
||||
if opts.variant == .Web {
|
||||
log.warnf("tracy is not supported on Web")
|
||||
opts.tracy = false
|
||||
}
|
||||
|
||||
tracy_flag: []string = opts.tracy ? {"-define:TRACY_ENABLE=true"} : {}
|
||||
debug_flag: []string = opts.debug ? {"-debug"} : {}
|
||||
optimize_flag: []string = opts.optimize ? {"-o:speed"} : {}
|
||||
|
||||
build_deps(opts)
|
||||
|
||||
#partial switch opts.variant {
|
||||
case .Hot_Reload:
|
||||
cmd := slice.concatenate(
|
||||
[][]string {
|
||||
[]string {
|
||||
"odin",
|
||||
"build",
|
||||
"game",
|
||||
"-define:RAYLIB_SHARED=true",
|
||||
"-define:PHYSFS_SHARED=true",
|
||||
"-build-mode:dll",
|
||||
"-out:game_tmp.so",
|
||||
},
|
||||
tracy_flag,
|
||||
debug_flag,
|
||||
optimize_flag,
|
||||
COMMON_FLAGS,
|
||||
},
|
||||
context.temp_allocator,
|
||||
)
|
||||
handle_error(run_cmd(cmd, "."))
|
||||
handle_error(os.rename("game_tmp.so", "game.so"))
|
||||
case .Desktop:
|
||||
cmd := slice.concatenate(
|
||||
[][]string {
|
||||
[]string{"odin", "build", "main_release", "-out:game.bin"},
|
||||
tracy_flag,
|
||||
debug_flag,
|
||||
optimize_flag,
|
||||
COMMON_FLAGS,
|
||||
},
|
||||
context.temp_allocator,
|
||||
)
|
||||
handle_error(run_cmd(cmd, "."))
|
||||
case:
|
||||
cmd := slice.concatenate(
|
||||
[][]string {
|
||||
[]string{"odin", "build", "main_web", "-build-mode:obj", "-out:game_web/game"},
|
||||
COMMON_FLAGS,
|
||||
debug_flag,
|
||||
optimize_flag,
|
||||
},
|
||||
)
|
||||
|
||||
handle_error(run_cmd(cmd, "."))
|
||||
}
|
||||
}
|
80
builder/helpers.odin
Normal file
80
builder/helpers.odin
Normal file
@ -0,0 +1,80 @@
|
||||
package builder
|
||||
|
||||
import "base:intrinsics"
|
||||
import "core:fmt"
|
||||
import "core:log"
|
||||
import os "core:os/os2"
|
||||
import "core:path/filepath"
|
||||
import "core:strings"
|
||||
|
||||
Process_Error :: enum {
|
||||
OK,
|
||||
Invalid_Exit_Code,
|
||||
Crash,
|
||||
}
|
||||
|
||||
Run_Error :: union #shared_nil {
|
||||
Process_Error,
|
||||
os.Error,
|
||||
}
|
||||
|
||||
@(require_results)
|
||||
run_cmd :: proc(cmd: []string, cwd: string, loc := #caller_location) -> Run_Error {
|
||||
log.infof(
|
||||
"running [%s]: %s",
|
||||
cwd,
|
||||
strings.join(cmd, " ", context.temp_allocator),
|
||||
location = loc,
|
||||
)
|
||||
desc := os.Process_Desc {
|
||||
command = cmd,
|
||||
working_dir = cwd,
|
||||
stderr = os.stderr,
|
||||
stdout = os.stdout,
|
||||
}
|
||||
process := os.process_start(desc) or_return
|
||||
state := os.process_wait(process) or_return
|
||||
|
||||
if !state.success {
|
||||
return .Crash
|
||||
}
|
||||
|
||||
if state.exit_code != 0 {
|
||||
return .Invalid_Exit_Code
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
Copy_Error :: union #shared_nil {
|
||||
os.Error,
|
||||
filepath.Match_Error,
|
||||
}
|
||||
|
||||
handle_error :: proc(
|
||||
err: $E,
|
||||
msg: string = "",
|
||||
expr := #caller_expression,
|
||||
loc := #caller_location,
|
||||
) where intrinsics.type_is_enum(E) ||
|
||||
intrinsics.type_is_union(E) {
|
||||
if err != nil {
|
||||
log.panicf("%v %s error: %v", expr, msg, err, location = loc)
|
||||
}
|
||||
}
|
||||
|
||||
remove_file :: proc(path: string, expr := #caller_expression, loc := #caller_location) {
|
||||
log.infof("remove(%s)", path, location = loc)
|
||||
err := os.remove(path)
|
||||
if err != .Not_Exist {
|
||||
handle_error(err, fmt.tprintf("failed to remove %s", path), expr = expr, loc = loc)
|
||||
}
|
||||
}
|
||||
|
||||
remove_all :: proc(path: string, expr := #caller_expression, loc := #caller_location) {
|
||||
log.infof("remove_all(%s)", path, location = loc)
|
||||
err := os.remove_all(path)
|
||||
if err != .Not_Exist {
|
||||
handle_error(err, fmt.tprintf("failed to remove %s", path), expr = expr, loc = loc)
|
||||
}
|
||||
}
|
@ -6,3 +6,5 @@ libphysfs.a: build_physfs
|
||||
cp ./build/libphysfs.a .
|
||||
libphysfs.so: build_physfs
|
||||
cp ./build/libphysfs.so* .
|
||||
clean:
|
||||
rm -r build; rm libphysfs.*
|
||||
|
3
libs/raylib/.gitignore
vendored
3
libs/raylib/.gitignore
vendored
@ -113,3 +113,6 @@ docgen_tmp/
|
||||
|
||||
# Parser stuff
|
||||
parser/raylib_parser
|
||||
|
||||
zig-out-static
|
||||
zig-out-shared
|
||||
|
@ -103,13 +103,13 @@ RAYLIB_SHARED :: #config(RAYLIB_SHARED, false)
|
||||
|
||||
when ODIN_OS == .Windows {
|
||||
@(extra_linker_flags = "/NODEFAULTLIB:" + ("msvcrt" when RAYLIB_SHARED else "libcmt"))
|
||||
foreign import lib {"windows/raylibdll.lib" when RAYLIB_SHARED else "windows/raylib.lib", "system:Winmm.lib", "system:Gdi32.lib", "system:User32.lib", "system:Shell32.lib"}
|
||||
foreign import lib {"zig-out-shared/lib/raylib.lib" when RAYLIB_SHARED else "zig-out-static/lib/raylib.lib", "system:Winmm.lib", "system:Gdi32.lib", "system:User32.lib", "system:Shell32.lib"}
|
||||
} else when ODIN_OS == .Linux {
|
||||
foreign import lib {// Note(bumbread): I'm not sure why in `linux/` folder there are
|
||||
// multiple copies of raylib.so, but since these bindings are for
|
||||
"src/libraylib.so.550" when RAYLIB_SHARED else "src/libraylib.a", "system:dl", "system:pthread"} // particular version of the library, I better specify it. Ideally,// though, it's best specified in terms of major (.so.4)
|
||||
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 {"src/libraylib.550.dylib" when RAYLIB_SHARED else "src/libraylib.a", "system:Cocoa.framework", "system:OpenGL.framework", "system:IOKit.framework"}
|
||||
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"
|
||||
} else {
|
||||
foreign import lib "system:raylib"
|
||||
}
|
||||
|
@ -121,14 +121,11 @@ RAYLIB_SHARED :: #config(RAYLIB_SHARED, false)
|
||||
|
||||
when ODIN_OS == .Windows {
|
||||
@(extra_linker_flags = "/NODEFAULTLIB:" + ("msvcrt" when RAYLIB_SHARED else "libcmt"))
|
||||
foreign import lib {"../windows/raylibdll.lib" when RAYLIB_SHARED else "../windows/raylib.lib", "system:Winmm.lib", "system:Gdi32.lib", "system:User32.lib", "system:Shell32.lib"}
|
||||
foreign import lib {"../zig-out-shared/lib/raylib.lib" when RAYLIB_SHARED else "../zig-out-static/lib/raylib.lib", "system:Winmm.lib", "system:Gdi32.lib", "system:User32.lib", "system:Shell32.lib"}
|
||||
} else when ODIN_OS == .Linux {
|
||||
foreign import lib {// Note(bumbread): I'm not sure why in `linux/` folder there are
|
||||
// multiple copies of raylib.so, but since these bindings are for
|
||||
"../src/libraylib.so.550" when RAYLIB_SHARED else "../src/libraylib.a", "system:dl", "system:pthread"} // particular version of the library, I better specify it. Ideally,// though, it's best specified in terms of major (.so.4)
|
||||
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 {"../macos" + ("-arm64" when ODIN_ARCH ==
|
||||
.arm64 else "") + "/libraylib" + (".500.dylib" when RAYLIB_SHARED else ".a"), "system:Cocoa.framework", "system:OpenGL.framework", "system:IOKit.framework"}
|
||||
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 {
|
||||
foreign import lib "system:raylib"
|
||||
}
|
||||
|
5
libs/tracy/.gitignore
vendored
Normal file
5
libs/tracy/.gitignore
vendored
Normal file
@ -0,0 +1,5 @@
|
||||
tracy.o
|
||||
tracy.so
|
||||
tracy.a
|
||||
tracy.lib
|
||||
tracy.dll
|
144
main_web/emscripten_allocator.odin
Normal file
144
main_web/emscripten_allocator.odin
Normal file
@ -0,0 +1,144 @@
|
||||
/*
|
||||
This allocator uses the malloc, calloc, free and realloc procs that emscripten
|
||||
exposes in order to allocate memory. Just like Odin's default heap allocator
|
||||
this uses proper alignment, so that maps and simd works.
|
||||
*/
|
||||
|
||||
package main_web
|
||||
|
||||
import "base:intrinsics"
|
||||
import "core:c"
|
||||
import "core:mem"
|
||||
|
||||
// This will create bindings to emscripten's implementation of libc
|
||||
// memory allocation features.
|
||||
@(default_calling_convention = "c")
|
||||
foreign _ {
|
||||
calloc :: proc(num, size: c.size_t) -> rawptr ---
|
||||
free :: proc(ptr: rawptr) ---
|
||||
malloc :: proc(size: c.size_t) -> rawptr ---
|
||||
realloc :: proc(ptr: rawptr, size: c.size_t) -> rawptr ---
|
||||
}
|
||||
|
||||
emscripten_allocator :: proc "contextless" () -> mem.Allocator {
|
||||
return mem.Allocator{emscripten_allocator_proc, nil}
|
||||
}
|
||||
|
||||
emscripten_allocator_proc :: proc(
|
||||
allocator_data: rawptr,
|
||||
mode: mem.Allocator_Mode,
|
||||
size, alignment: int,
|
||||
old_memory: rawptr,
|
||||
old_size: int,
|
||||
location := #caller_location,
|
||||
) -> (
|
||||
data: []byte,
|
||||
err: mem.Allocator_Error,
|
||||
) {
|
||||
// These aligned alloc procs are almost indentical those in
|
||||
// `_heap_allocator_proc` in `core:os`. Without the proper alignment you
|
||||
// cannot use maps and simd features.
|
||||
|
||||
aligned_alloc :: proc(
|
||||
size, alignment: int,
|
||||
zero_memory: bool,
|
||||
old_ptr: rawptr = nil,
|
||||
) -> (
|
||||
[]byte,
|
||||
mem.Allocator_Error,
|
||||
) {
|
||||
a := max(alignment, align_of(rawptr))
|
||||
space := size + a - 1
|
||||
|
||||
allocated_mem: rawptr
|
||||
if old_ptr != nil {
|
||||
original_old_ptr := mem.ptr_offset((^rawptr)(old_ptr), -1)^
|
||||
allocated_mem = realloc(original_old_ptr, c.size_t(space + size_of(rawptr)))
|
||||
} else if zero_memory {
|
||||
// calloc automatically zeros memory, but it takes a number + size
|
||||
// instead of just size.
|
||||
allocated_mem = calloc(c.size_t(space + size_of(rawptr)), 1)
|
||||
} else {
|
||||
allocated_mem = malloc(c.size_t(space + size_of(rawptr)))
|
||||
}
|
||||
aligned_mem := rawptr(mem.ptr_offset((^u8)(allocated_mem), size_of(rawptr)))
|
||||
|
||||
ptr := uintptr(aligned_mem)
|
||||
aligned_ptr := (ptr - 1 + uintptr(a)) & -uintptr(a)
|
||||
diff := int(aligned_ptr - ptr)
|
||||
if (size + diff) > space || allocated_mem == nil {
|
||||
return nil, .Out_Of_Memory
|
||||
}
|
||||
|
||||
aligned_mem = rawptr(aligned_ptr)
|
||||
mem.ptr_offset((^rawptr)(aligned_mem), -1)^ = allocated_mem
|
||||
|
||||
return mem.byte_slice(aligned_mem, size), nil
|
||||
}
|
||||
|
||||
aligned_free :: proc(p: rawptr) {
|
||||
if p != nil {
|
||||
free(mem.ptr_offset((^rawptr)(p), -1)^)
|
||||
}
|
||||
}
|
||||
|
||||
aligned_resize :: proc(
|
||||
p: rawptr,
|
||||
old_size: int,
|
||||
new_size: int,
|
||||
new_alignment: int,
|
||||
) -> (
|
||||
[]byte,
|
||||
mem.Allocator_Error,
|
||||
) {
|
||||
if p == nil {
|
||||
return nil, nil
|
||||
}
|
||||
return aligned_alloc(new_size, new_alignment, true, p)
|
||||
}
|
||||
|
||||
switch mode {
|
||||
case .Alloc:
|
||||
return aligned_alloc(size, alignment, true)
|
||||
|
||||
case .Alloc_Non_Zeroed:
|
||||
return aligned_alloc(size, alignment, false)
|
||||
|
||||
case .Free:
|
||||
aligned_free(old_memory)
|
||||
return nil, nil
|
||||
|
||||
case .Resize:
|
||||
if old_memory == nil {
|
||||
return aligned_alloc(size, alignment, true)
|
||||
}
|
||||
|
||||
bytes := aligned_resize(old_memory, old_size, size, alignment) or_return
|
||||
|
||||
// realloc doesn't zero the new bytes, so we do it manually.
|
||||
if size > old_size {
|
||||
new_region := raw_data(bytes[old_size:])
|
||||
intrinsics.mem_zero(new_region, size - old_size)
|
||||
}
|
||||
|
||||
return bytes, nil
|
||||
|
||||
case .Resize_Non_Zeroed:
|
||||
if old_memory == nil {
|
||||
return aligned_alloc(size, alignment, false)
|
||||
}
|
||||
|
||||
return aligned_resize(old_memory, old_size, size, alignment)
|
||||
|
||||
case .Query_Features:
|
||||
set := (^mem.Allocator_Mode_Set)(old_memory)
|
||||
if set != nil {
|
||||
set^ = {.Alloc, .Free, .Resize, .Query_Features}
|
||||
}
|
||||
return nil, nil
|
||||
|
||||
case .Free_All, .Query_Info:
|
||||
return nil, .Mode_Not_Implemented
|
||||
}
|
||||
return nil, .Mode_Not_Implemented
|
||||
}
|
99
main_web/emscripten_logger.odin
Normal file
99
main_web/emscripten_logger.odin
Normal file
@ -0,0 +1,99 @@
|
||||
/*
|
||||
This logger is largely a copy of the console logger in `core:log`, but it uses
|
||||
emscripten's `puts` proc to write into he console of the web browser.
|
||||
|
||||
This is more or less identical to the logger in Aronicu's repository:
|
||||
https://github.com/Aronicu/Raylib-WASM/tree/main
|
||||
*/
|
||||
|
||||
package main_web
|
||||
|
||||
import "core:c"
|
||||
import "core:fmt"
|
||||
import "core:log"
|
||||
import "core:strings"
|
||||
|
||||
Emscripten_Logger_Opts :: log.Options{.Level, .Short_File_Path, .Line}
|
||||
|
||||
create_emscripten_logger :: proc(
|
||||
lowest := log.Level.Debug,
|
||||
opt := Emscripten_Logger_Opts,
|
||||
) -> log.Logger {
|
||||
return log.Logger{data = nil, procedure = logger_proc, lowest_level = lowest, options = opt}
|
||||
}
|
||||
|
||||
// This create's a binding to `puts` which will be linked in as part of the
|
||||
// emscripten runtime.
|
||||
@(default_calling_convention = "c")
|
||||
foreign _ {
|
||||
puts :: proc(buffer: cstring) -> c.int ---
|
||||
}
|
||||
|
||||
@(private = "file")
|
||||
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, Level_Headers[level])
|
||||
do_location_header(options, &b, location)
|
||||
fmt.sbprint(&b, text)
|
||||
|
||||
if bc, bc_err := strings.to_cstring(&b); bc_err == nil {
|
||||
puts(bc)
|
||||
}
|
||||
}
|
||||
|
||||
@(private = "file")
|
||||
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, "] ")
|
||||
}
|
||||
|
@ -2,45 +2,52 @@
|
||||
These procs are the ones that will be called from `main_wasm.c`.
|
||||
*/
|
||||
|
||||
#+build wasm32, wasm64p32
|
||||
|
||||
package main_web
|
||||
|
||||
import game "../game"
|
||||
import "base:runtime"
|
||||
import "core:c"
|
||||
import "core:mem"
|
||||
import rl "libs:raylib"
|
||||
import "../game"
|
||||
|
||||
@(private="file")
|
||||
wasm_context: runtime.Context
|
||||
@(private = "file")
|
||||
web_context: runtime.Context
|
||||
|
||||
// I'm not sure @thread_local works with WASM. We'll see if anyone makes a
|
||||
// multi-threaded WASM game!
|
||||
@(private="file")
|
||||
@thread_local temp_allocator: WASM_Temp_Allocator
|
||||
|
||||
@export
|
||||
web_init :: proc "c" () {
|
||||
@(export)
|
||||
main_start :: proc "c" () {
|
||||
context = runtime.default_context()
|
||||
context.allocator = rl.MemAllocator()
|
||||
|
||||
wasm_temp_allocator_init(&temp_allocator, 1*mem.Megabyte)
|
||||
context.temp_allocator = wasm_temp_allocator(&temp_allocator)
|
||||
context.logger = create_wasm_logger()
|
||||
wasm_context = context
|
||||
// The WASM allocator doesn't seem to work properly in combination with
|
||||
// emscripten. There is some kind of conflict with how the manage memory.
|
||||
// So this sets up an allocator that uses emscripten's malloc.
|
||||
context.allocator = emscripten_allocator()
|
||||
runtime.init_global_temporary_allocator(1 * mem.Megabyte)
|
||||
|
||||
game.game_init_window()
|
||||
// Since we now use js_wasm32 we should be able to remove this and use
|
||||
// context.logger = log.create_console_logger(). However, that one produces
|
||||
// extra newlines on web. So it's a bug in that core lib.
|
||||
context.logger = create_emscripten_logger()
|
||||
|
||||
web_context = context
|
||||
|
||||
game.game_init_window({})
|
||||
game.game_init()
|
||||
}
|
||||
|
||||
@export
|
||||
web_update :: proc "c" () {
|
||||
context = wasm_context
|
||||
game.game_update()
|
||||
@(export)
|
||||
main_update :: proc "c" () -> bool {
|
||||
context = web_context
|
||||
return game.game_update()
|
||||
}
|
||||
|
||||
@export
|
||||
web_window_size_changed :: proc "c" (w: c.int, h: c.int) {
|
||||
rl.SetWindowSize(w, h)
|
||||
@(export)
|
||||
main_end :: proc "c" () {
|
||||
context = web_context
|
||||
game.game_shutdown()
|
||||
game.game_shutdown_window()
|
||||
}
|
||||
|
||||
@(export)
|
||||
web_window_size_changed :: proc "c" (w: c.int, h: c.int) {
|
||||
context = web_context
|
||||
// game.game_parent_window_size_changed(int(w), int(h))
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user