diff --git a/README.md b/README.md index 1a06b48..80a25bd 100644 --- a/README.md +++ b/README.md @@ -36,3 +36,15 @@ vendor - microui (temp) - box3d? - build.sh -> build.odin + +## Hot Reload + +build.sh -> hot reload enabled, debug mode enabled +build_release.sh -> hot reload disabled, debug mode disabled +build_debug.sh -> hot reload disabled, debug mode enabled + +hot reload builds engine as .exe, then game as dynamic lib. +skips building the engine if its already running (pgrep). + +no hot reload does not use game.dll, instead it imports the game source +as a normal Odin package during build. diff --git a/build.sh b/build.sh index 91f29d6..5305c91 100755 --- a/build.sh +++ b/build.sh @@ -1,6 +1,6 @@ #!/bin/sh -set -e +set -eu PROJECT="sindri" VERSION="dev-$(date -u '+%Y-%m-%d')-$(git rev-parse --short HEAD)" @@ -14,6 +14,12 @@ VERSION="dev-$(date -u '+%Y-%m-%d')-$(git rev-parse --short HEAD)" mkdir -p build +# Game.dll +odin build game/ -show-timings \ + -collection:sindri=src \ + -build-mode:dynamic \ + -out:build/game -microarch:native -define:VERSION="$VERSION-debug" -debug "$@" + if [ "$1" = "debug" ]; then shift diff --git a/game/game.odin b/game/game.odin new file mode 100644 index 0000000..0f973a1 --- /dev/null +++ b/game/game.odin @@ -0,0 +1,20 @@ +package game + +import "core:time" +import "core:fmt" + +@(export) +hello :: proc() { + fmt.println("hello from .dll!") +} + +start := time.tick_now() + +@(export) +should_close :: proc() -> bool { + elapsed := time.tick_since(start) + seconds := time.duration_seconds(elapsed) + if seconds > 4 do return true + + return false +} diff --git a/src/glfw.odin b/src/glfw.odin index 151c3d4..1c5a7c8 100644 --- a/src/glfw.odin +++ b/src/glfw.odin @@ -1,6 +1,5 @@ package sindri -import "core:time" import "vendor:glfw" import "wgpu:wgpu" @@ -27,20 +26,19 @@ os_init :: proc() { glfw.SetFramebufferSizeCallback(state.os.window, size_callback) } -os_run :: proc() { - dt: f32 +os_should_close :: proc() -> bool { + return bool(glfw.WindowShouldClose(state.os.window)) +} - for !glfw.WindowShouldClose(state.os.window) { - start := time.tick_now() +os_set_should_close :: proc(val: bool) { + glfw.SetWindowShouldClose(state.os.window, b32(val)) +} - glfw.PollEvents() - frame(dt) - - dt = f32(time.duration_seconds(time.tick_since(start))) - } - - instance_destroy() +os_poll_events :: proc() { + glfw.PollEvents() +} +os_destroy :: proc() { glfw.DestroyWindow(state.os.window) glfw.Terminate() } diff --git a/src/main.odin b/src/main.odin index 834382c..dcffb2e 100644 --- a/src/main.odin +++ b/src/main.odin @@ -1,13 +1,56 @@ package sindri +import "core:dynlib" import "core:fmt" +import "core:time" VERSION :: #config(VERSION, "dev") // ----------------------------------------- +instance_ready: bool + +Game_API :: struct { + __handle: dynlib.Library, + hello: proc(), + should_close: proc() -> bool, +} + main :: proc() { fmt.println("hello world!") + api: Game_API + load_game_api(&api) + api.hello() + + // Initialize window + os_init() + + // Initialize GPU resources instance_init() + + gt: f32 + + for !os_should_close() && !api.should_close() { + start := time.tick_now() + + os_poll_events() + frame(gt) + + gt = f32(time.duration_seconds(time.tick_since(start))) + } + + // Cleanup GPU resources + instance_destroy() + + // Cleanup window + os_destroy() +} + +load_game_api :: proc(api: ^Game_API) { + // Match the names of the fields in Game_API to symbols in the game DLL + _, ok := dynlib.initialize_symbols(api, "build/game.dylib") + if !ok { + fmt.printfln("Failed initializing symbols: {0}", dynlib.last_error()) + } } diff --git a/src/wgpu.odin b/src/wgpu.odin index 27924b7..2870a42 100644 --- a/src/wgpu.odin +++ b/src/wgpu.odin @@ -27,8 +27,6 @@ state: struct { instance_init :: proc() { state.ctx = context - os_init() - state.instance = wgpu.CreateInstance(nil) if state.instance == nil { panic("WebGPU is not supported") @@ -130,8 +128,6 @@ instance_init :: proc() { multisample = {count = 1, mask = 0xFFFFFFFF}, }, ) - - os_run() } }