Compare commits

3 Commits
Author SHA1 Message Date
Riyyi be516d39a3 Add Windows build script 2026-09-15 18:41:04 +02:00
Riyyi e7cc935035 lol 2026-09-14 23:00:24 +02:00
Riyyi 416b42c27e . 2026-09-14 19:25:33 +02:00
6 changed files with 117 additions and 6 deletions
+52
View File
@@ -0,0 +1,52 @@
$ErrorActionPreference = "Stop"
$PROJECT = "sindri"
$COMMIT = git rev-parse --short HEAD
$VERSION = "dev-$(Get-Date -Format 'yyyy-MM-dd')-$COMMIT"
$OPTION = $args[0]
if ($args) { $args = $args[1..($args.Length - 1)] } else { $args = @() }
# ------------------------------------------
# Game compile
New-Item -ItemType Directory -Force -Path build | Out-Null
# Game.dll
odin build game/ -show-timings `
-collection:sindri=src `
-build-mode:dynamic `
-out:build/game_tmp -microarch:native "-define:VERSION=$VERSION-debug" -debug @args
# Need to use a temp file on Windows because it first writes an empty file,
# which the engine will load before it is actually fully written.
if (-not (Test-Path "build/game_tmp.dll")) {
Write-Error "error: build produced no game lib.dll"
exit 1
}
Move-Item -Force "build/game_tmp.dll" "build/game.dll"
# ------------------------------------------
# Engine compile
# If the executable is already running, then don't try to build and start it.
$proc = Get-Process -Name $PROJECT -ErrorAction SilentlyContinue
if ($proc) {
Write-Output "Hot reloading..."
exit 0
}
if ($OPTION -eq "debug") {
odin build src/ -show-timings `
-collection:sindri=src `
-collection:gram=vendor/gram/src `
-collection:wgpu=vendor `
-out:build/$PROJECT -microarch:native -use-separate-modules "-define:VERSION=$VERSION-debug" -debug @args
exit 0
}
odin build src/ -show-timings `
-collection:sindri=src `
-collection:gram=vendor/gram/src `
-collection:wgpu=vendor `
-out:build/$PROJECT -microarch:native -o:speed "-define:VERSION=$VERSION" @args
+22
View File
@@ -0,0 +1,22 @@
# Odin
This document contains specifics about the workings of the Odin programming
language, dynamic linking and state management design patterns. These are
tested and validated findings, for continued reference by me.
## Dynamic Library Memory
When a program loads in a dynamic library, what happens with package globals?
Findings (macOS):
- The package globals are shared between the host and the lib
- After hot reloading the lib, the memory of the packge is not refreshed,
it keeps pointing to the package global of the host
The clanker states this is due to "flat-namespace symbol interposition".
Linux "ELF has symbol preemption: when resolving references, ld.so searches
globals scope in order — executable first, then loaded shared objects".
Windows PE has no interposition at all, every module (exe and each DLL) has its
own symbol table.
+14 -6
View File
@@ -5,11 +5,12 @@ import "core:time"
import "core:fmt" import "core:fmt"
import "sindri:core" import "sindri:core"
import "sindri:test"
// ----------------------------------------- // -----------------------------------------
Game_Memory :: struct { Game_Memory :: struct {
should_close: bool should_close: bool,
} }
g: ^Game_Memory g: ^Game_Memory
@@ -54,6 +55,8 @@ settings :: proc() -> core.Settings {
@(export) @(export)
init_once :: proc() { init_once :: proc() {
fmt.println("init once") fmt.println("init once")
test.test_proc = proc() {}
} }
@(export) @(export)
@@ -61,6 +64,9 @@ init :: proc() {
fmt.println("hello from .dll!") fmt.println("hello from .dll!")
g = new(Game_Memory) g = new(Game_Memory)
memory_set(g)
test.test_proc = proc() { asd := 2 }
} }
@(export) @(export)
@@ -70,6 +76,10 @@ update :: proc(dt: f32) {
if input.key_state(.Key_Escape) == .Press { if input.key_state(.Key_Escape) == .Press {
g.should_close = true g.should_close = true
} }
fmt.println("GAME:", test.test)
fmt.printf("pointer: %p | %p\n", &test.test, &test.test_proc)
test.test += 1
} }
@(export) @(export)
@@ -83,19 +93,17 @@ start := time.tick_now()
should_close :: proc() -> bool { should_close :: proc() -> bool {
elapsed := time.tick_since(start) elapsed := time.tick_since(start)
seconds := time.duration_seconds(elapsed) seconds := time.duration_seconds(elapsed)
if seconds > 4 do return true // if seconds > 4 do return true
return g.should_close return g.should_close
} }
@(export) @(export)
force_reload :: proc() -> bool { force_reload :: proc() -> bool {
// TODO: read keypress return input.key_state(.Key_F5) == .Press
return false
} }
@(export) @(export)
force_restart :: proc() -> bool { force_restart :: proc() -> bool {
// TODO: read keypress return input.key_state(.Key_F6) == .Press
return false
} }
+20
View File
@@ -5,9 +5,11 @@ import "core:fmt"
import "sindri:input" import "sindri:input"
// ----------------------------------------- // -----------------------------------------
// Types
// event category, bitfield (?) // event category, bitfield (?)
// Event_Data :: union {
Event :: union { Event :: union {
Window_Close_Event, Window_Close_Event,
Window_Resize_Event, Window_Resize_Event,
@@ -22,6 +24,11 @@ Event :: union {
Mouse_Scroll_Event, Mouse_Scroll_Event,
} }
// Event :: struct {
// data: Event_Data,
// handled: bool,
// }
Window_Close_Event :: struct { Window_Close_Event :: struct {
handled: bool, handled: bool,
} }
@@ -85,6 +92,13 @@ Mouse_Scroll_Event :: struct {
} }
// ----------------------------------------- // -----------------------------------------
// Variables
// I want to have a list of Listeners per Event type, but this is state
// listeners: map[typeid][dynamic]Listener
// -----------------------------------------
// Public functions
// Dispatcher(Event) -> forwards to the right function // Dispatcher(Event) -> forwards to the right function
on_event :: proc(event: Event) { on_event :: proc(event: Event) {
@@ -116,3 +130,9 @@ on_event :: proc(event: Event) {
fmt.println("Joy dis:", e.id) fmt.println("Joy dis:", e.id)
} }
} }
/*
Notes:
Have the events queued up into a frame buffer that gets drained at a specific time.
*/
+4
View File
@@ -2,6 +2,7 @@ package sindri
import "core:fmt" import "core:fmt"
import "core:time" import "core:time"
import "sindri:test"
import "sindri:hot_reload" import "sindri:hot_reload"
import "sindri:platform" import "sindri:platform"
@@ -41,6 +42,9 @@ main :: proc() {
platform.os_poll_events() platform.os_poll_events()
api.update(dt) api.update(dt)
fmt.println("MAIN:", test.test)
fmt.printf("pointer: %p | %p\n", &test.test, &test.test_proc)
platform.frame(dt) platform.frame(dt)
dt = f32(time.duration_seconds(time.tick_since(start))) dt = f32(time.duration_seconds(time.tick_since(start)))
+5
View File
@@ -0,0 +1,5 @@
package test
test: int = 0
test_proc: proc()