From ad7ca7d68cce95f442d5564f1f68140c53adea6f Mon Sep 17 00:00:00 2001 From: jacob Date: Wed, 15 Jan 2025 14:32:36 -0600 Subject: [PATCH] pre-generate rand.dat file for deterministic noise. calculate shake based on world time --- .gitattributes | 1 + res/rand.dat | 3 ++ src/app.c | 29 +++++++++++++++++- src/config.h | 6 ++-- src/entity.h | 1 + src/game.c | 11 +++---- src/math.h | 2 +- src/rng.c | 79 +++++++++++++++++++++++++++++++++++++++++++++++++ src/rng.h | 22 ++++++++++++++ src/sys.h | 7 +---- src/sys_win32.c | 29 +++++++----------- src/user.c | 25 +++++++++++++--- src/util.h | 1 + 13 files changed, 178 insertions(+), 38 deletions(-) create mode 100644 res/rand.dat create mode 100644 src/rng.c create mode 100644 src/rng.h diff --git a/.gitattributes b/.gitattributes index 3aeaddc0..8bf090de 100644 --- a/.gitattributes +++ b/.gitattributes @@ -25,3 +25,4 @@ Makefile text eol=lf *.ase filter=lfs diff=lfs merge=lfs -text *.ttf filter=lfs diff=lfs merge=lfs -text *.mp3 filter=lfs diff=lfs merge=lfs -text +*.dat filter=lfs diff=lfs merge=lfs -text diff --git a/res/rand.dat b/res/rand.dat new file mode 100644 index 00000000..0c12536b --- /dev/null +++ b/res/rand.dat @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:d8f10e80c507131bb7db1aba60dd4fd294e6eefb293072809ddc90e5aa23bdb9 +size 8388608 diff --git a/src/app.c b/src/app.c index 27ff367a..7d3306fb 100644 --- a/src/app.c +++ b/src/app.c @@ -21,6 +21,7 @@ #include "math.h" #include "renderer.h" #include "phys.h" +#include "rng.h" struct exit_callback { app_exit_callback_func *func; @@ -117,6 +118,30 @@ void app_register_exit_callback(app_exit_callback_func *func) sys_mutex_unlock(&lock); } +/* ========================== * + * Generate random number file + * (unused function) + * ========================== */ + +#if 0 +#include "rng.h" +INTERNAL void gen_random_file(struct string path, u32 count) +{ + { + /* Clear file */ + struct sys_file f = sys_file_open_write(path); + sys_file_write(f, BUFFER(0, 0)); + sys_file_close(f); + } + struct sys_file f = sys_file_open_append(path); + for (u32 i = 0; i < count; ++i) { + u64 rand = rng_rand_u64(); + sys_file_write(f, BUFFER_FROM_STRUCT(&rand)); + } + sys_file_close(f); +} +#endif + /* ========================== * * Entry point * ========================== */ @@ -204,9 +229,10 @@ void app_entry_point(void) } /* Startup systems */ + struct resource_startup_receipt resource_sr = resource_startup(); + struct rng_startup_receipt rng_sr = rng_startup(&resource_sr); struct renderer_startup_receipt renderer_sr = renderer_startup(&window); struct work_startup_receipt work_sr = work_startup(worker_count); - struct resource_startup_receipt resource_sr = resource_startup(); struct asset_cache_startup_receipt asset_cache_sr = asset_cache_startup(&work_sr); struct ttf_startup_receipt ttf_sr = ttf_startup(); struct font_startup_receipt font_sr = font_startup(&work_sr, &renderer_sr, &asset_cache_sr, &ttf_sr, &resource_sr); @@ -221,6 +247,7 @@ void app_entry_point(void) (UNUSED)user_sr; (UNUSED)playback_sr; + (UNUSED)rng_sr; /* Show window */ sys_window_show(&window); diff --git a/src/config.h b/src/config.h index 628ae832..7546209b 100644 --- a/src/config.h +++ b/src/config.h @@ -29,8 +29,8 @@ #define PIXELS_PER_UNIT 256.0 -#define GAME_FPS 50.0 -#define GAME_TIMESCALE 1.0 +#define GAME_FPS 100.0 +#define GAME_TIMESCALE 1 #define GAME_PHYSICS_SUBSTEPS 4 #define GAME_PHYSICS_ENABLE_WARM_STARTING 1 @@ -65,4 +65,4 @@ #define AUDIO_ENABLED 0 #define VSYNC_ENABLED 0 -#define USER_FRAME_LIMIT 300.0 +#define USER_FRAME_LIMIT 300 diff --git a/src/entity.h b/src/entity.h index ee21dbde..fce590e8 100644 --- a/src/entity.h +++ b/src/entity.h @@ -254,6 +254,7 @@ struct entity { /* ENTITY_PROP_QUAKE */ f32 quake_intensity; + f32 quake_frequency; f32 quake_fade; /* How much intensity to lose per second */ /* ====================================================================== */ diff --git a/src/game.c b/src/game.c index 0c27da2f..f8a3c859 100644 --- a/src/game.c +++ b/src/game.c @@ -12,6 +12,7 @@ #include "log.h" #include "phys.h" #include "collider.h" +#include "rng.h" GLOBAL struct { struct atomic_i32 game_thread_shutdown; @@ -413,7 +414,7 @@ INTERNAL PHYS_COLLISION_CALLBACK_FUNC_DEF(on_collision, array) /* Create test blood */ /* TODO: Remove this */ { - struct xform xf = XFORM_TRS(.t = point, .r = sys_rand_f32(0, TAU)); + struct xform xf = XFORM_TRS(.t = point, .r = rng_rand_f32(0, TAU)); struct entity *decal = entity_alloc(root); decal->sprite = sprite_tag_from_path(STR("res/graphics/blood.ase")); decal->sprite_tint = RGBA_32_F(1, 1, 1, 0.25f); @@ -421,10 +422,10 @@ INTERNAL PHYS_COLLISION_CALLBACK_FUNC_DEF(on_collision, array) f32 perp_range = 0.5; struct v2 linear_velocity = v2_mul(normal, 0.5); - linear_velocity = v2_add(linear_velocity, v2_mul(v2_perp(normal), sys_rand_f32(-perp_range, perp_range))); + linear_velocity = v2_add(linear_velocity, v2_mul(v2_perp(normal), rng_rand_f32(-perp_range, perp_range))); f32 angular_velocity_range = 5; - f32 angular_velocity = sys_rand_f32(-angular_velocity_range, angular_velocity_range); + f32 angular_velocity = rng_rand_f32(-angular_velocity_range, angular_velocity_range); entity_enable_prop(decal, ENTITY_PROP_PHYSICAL_KINEMATIC); entity_set_linear_velocity(decal, linear_velocity); @@ -1149,8 +1150,8 @@ INTERNAL void game_update(struct game_cmd_array game_cmds) { struct entity *quake = entity_alloc(root); entity_set_xform(quake, XFORM_POS(pos)); - quake->quake_intensity = 0.02f; - quake->quake_fade = quake->quake_intensity / 0.01f; + quake->quake_intensity = 0.2f; + quake->quake_fade = quake->quake_intensity / 0.1f; entity_enable_prop(quake, ENTITY_PROP_QUAKE); } } diff --git a/src/math.h b/src/math.h index 0648e936..546cd3a7 100644 --- a/src/math.h +++ b/src/math.h @@ -819,7 +819,7 @@ INLINE struct mat4x4 mat4x4_from_xform(struct xform xf) INLINE struct mat4x4 mat4x4_from_ortho(f32 left, f32 right, f32 bottom, f32 top, f32 near_z, f32 far_z) { - struct mat4x4 m = {0}; + struct mat4x4 m = ZI; f32 rl = 1.0f / (right - left); f32 tb = 1.0f / (top - bottom); diff --git a/src/rng.c b/src/rng.c new file mode 100644 index 00000000..4c421021 --- /dev/null +++ b/src/rng.c @@ -0,0 +1,79 @@ +#include "rng.h" +#include "sys.h" +#include "resource.h" + +GLOBAL struct { + u64 *noise; + u64 noise_count; +} G = ZI, DEBUG_ALIAS(G, G_rng); + +/* ========================== * + * Startup + * ========================== */ + +struct rng_startup_receipt rng_startup(struct resource_startup_receipt *resource_sr) +{ + (UNUSED)resource_sr; + struct string rand_path = STR("res/rand.dat"); + if (resource_exists(rand_path)) { + struct resource r = resource_open(rand_path); + G.noise = (u64 *)r.bytes.data; + G.noise_count = r.bytes.size / sizeof(*G.noise); + } else { + sys_panic(STR("Failed to locate pre-computed noise resource")); + } + return (struct rng_startup_receipt) { 0 }; +} + +/* ========================== * + * Rand + * ========================== */ + +u32 rng_rand_u32(void) +{ + u32 v = 0; + sys_rand(BUFFER_FROM_STRUCT(&v)); + return v; +} + +u64 rng_rand_u64(void) +{ + u64 v = 0; + sys_rand(BUFFER_FROM_STRUCT(&v)); + return v; +} + +f32 rng_rand_f32(f32 range_start, f32 range_end) +{ + return ((f32)rng_rand_u32() / (f32)U32_MAX) * (range_end - range_start) + range_start; +} + +f64 rng_rand_f64(f64 range_start, f64 range_end) +{ + return ((f64)rng_rand_u64() / (f64)U64_MAX) * (range_end - range_start) + range_start; +} + +/* ========================== * + * Noise + * Functions that return a deterministic pre-computed random number based on the provided seed + * ========================== */ + +u32 rng_noise_u32(u32 seed) +{ + return (u32)G.noise[seed % G.noise_count]; +} + +u64 rng_noise_u64(u64 seed) +{ + return G.noise[seed % G.noise_count]; +} + +f32 rng_noise_f32(u64 seed, f32 range_start, f32 range_end) +{ + return ((f32)rng_noise_u32(seed) / (f32)U32_MAX) * (range_end - range_start) + range_start; +} + +f32 rng_noise_f64(u64 seed, f64 range_start, f64 range_end) +{ + return ((f64)rng_noise_u64(seed) / (f64)U64_MAX) * (range_end - range_start) + range_start; +} diff --git a/src/rng.h b/src/rng.h new file mode 100644 index 00000000..2177b421 --- /dev/null +++ b/src/rng.h @@ -0,0 +1,22 @@ +#ifndef RNG_H +#define RNG_H + +struct resource_startup_receipt; + +/* Startup */ +struct rng_startup_receipt { i32 _; }; +struct rng_startup_receipt rng_startup(struct resource_startup_receipt *resource_sr); + +/* Rand */ +u32 rng_rand_u32(void); +u64 rng_rand_u64(void); +f32 rng_rand_f32(f32 range_start, f32 range_end); +f64 rng_rand_f64(f64 range_start, f64 range_end); + +/* Noise */ +u32 rng_noise_u32(u32 seed); +u64 rng_noise_u64(u64 seed); +f32 rng_noise_f32(u64 seed, f32 range_start, f32 range_end); +f32 rng_noise_f64(u64 seed, f64 range_start, f64 range_end); + +#endif diff --git a/src/sys.h b/src/sys.h index cd72d19b..c82ceec4 100644 --- a/src/sys.h +++ b/src/sys.h @@ -441,14 +441,9 @@ struct string sys_get_clipboard_text(struct arena *arena); /* ========================== * * Util * ========================== */ - +void sys_rand(struct buffer b); u32 sys_num_logical_processors(void); - void sys_exit(void); - -u32 sys_rand_u32(void); -f32 sys_rand_f32(f32 range_start, f32 range_end); - void sys_panic(struct string msg); /* ========================== * diff --git a/src/sys_win32.c b/src/sys_win32.c index 248f503e..14e088ef 100644 --- a/src/sys_win32.c +++ b/src/sys_win32.c @@ -19,16 +19,16 @@ # include # include # include -# include +# include #pragma warning(pop) #pragma comment(lib, "kernel32") #pragma comment(lib, "user32") #pragma comment(lib, "shell32") #pragma comment(lib, "ole32") -#pragma comment(lib, "advapi32") #pragma comment(lib, "winmm") #pragma comment(lib, "dwmapi") +#pragma comment(lib, "bcrypt") #define SYS_WINDOW_EVENT_LISTENERS_MAX 512 #define WINDOW_CLASS_NAME L"power_play_window_class" @@ -737,7 +737,7 @@ INTERNAL SYS_THREAD_ENTRY_POINT_FUNC_DEF(window_thread_entry_point, arg) sync_flag_set(&window->ready_sf); while (!window->event_thread_shutdown) { - MSG msg = {0}; + MSG msg = ZI; GetMessageW(&msg, 0, 0, 0); /* Update cursor */ @@ -859,10 +859,10 @@ INTERNAL void win32_update_window_from_system(struct win32_window *window) { HWND hwnd = window->hwnd; - RECT window_rect = {0}; + RECT window_rect = ZI; GetWindowRect(hwnd, &window_rect); - RECT client_rect = {0}; + RECT client_rect = ZI; GetClientRect(hwnd, (LPRECT)&client_rect); ClientToScreen(hwnd, (LPPOINT)&client_rect.left); ClientToScreen(hwnd, (LPPOINT)&client_rect.right); @@ -1852,9 +1852,14 @@ struct string sys_get_clipboard_text(struct arena *arena) } /* ========================== * - * Util + * RNG * ========================== */ +void sys_rand(struct buffer b) +{ + BCryptGenRandom(BCRYPT_RNG_ALG_HANDLE, (PUCHAR)b.data, b.size, 0); +} + u32 sys_num_logical_processors(void) { return GetActiveProcessorCount(ALL_PROCESSOR_GROUPS); @@ -1865,18 +1870,6 @@ void sys_exit(void) ExitProcess(1); } -u32 sys_rand_u32(void) -{ - u32 v; - RtlGenRandom(&v, sizeof(v)); - return v; -} - -f32 sys_rand_f32(f32 range_start, f32 range_end) -{ - return ((f32)sys_rand_u32() / (f32)U32_MAX) * (range_end - range_start) + range_start; -} - void sys_panic(struct string msg) { ASSERT(false); diff --git a/src/user.c b/src/user.c index 4bc95d68..18a6aa1e 100644 --- a/src/user.c +++ b/src/user.c @@ -17,6 +17,7 @@ #include "mixer.h" #include "atomic.h" #include "collider.h" +#include "rng.h" struct bind_state { b32 is_held; /* Is this bind held down this frame */ @@ -682,13 +683,29 @@ INTERNAL void user_update(void) for (u64 entity_index = 0; entity_index < store->reserved; ++entity_index) { struct entity *ent = &store->entities[entity_index]; if (!entity_is_valid_and_active(ent)) continue; - if (ent->shake <= 0) continue; + /* How much time between camera shakes */ + const f32 frequency = 0.01; f32 shake = ent->shake; + if (shake > 0) { + u64 basis = hash_fnv64(HASH_FNV64_BASIS, BUFFER_FROM_STRUCT(&ent->handle)); + u32 angle_seed0 = basis + (u64)(G.world.time / frequency); + u32 angle_seed1 = angle_seed0 + 1; + f32 angle0 = rng_noise_f32(angle_seed0, 0, TAU); + f32 angle1 = rng_noise_f32(angle_seed1, 0, TAU); - struct xform xf = entity_get_xform(ent); - xf.og = v2_add(xf.og, v2_mul(v2_from_angle(sys_rand_f32(0, TAU)), shake)); - entity_set_xform(ent, xf); + struct v2 vec0 = v2_with_len(v2_from_angle(angle0), shake); + /* NOTE: vec1 not completely accurate since shake can change between frames, just a prediction */ + struct v2 vec1 = v2_with_len(v2_from_angle(angle1), shake); + + /* TODO: Cubic interp? */ + f32 blend = math_fmod64(G.world.time, frequency) / frequency; + struct v2 vec = v2_lerp(vec0, vec1, blend); + + struct xform xf = entity_get_xform(ent); + xf.og = v2_add(xf.og, v2_mul(vec, shake)); + entity_set_xform(ent, xf); + } } /* ========================== * diff --git a/src/util.h b/src/util.h index 6369e47b..3547b1c3 100644 --- a/src/util.h +++ b/src/util.h @@ -6,6 +6,7 @@ #include "memory.h" #include "arena.h" #include "atomic.h" +#include "math.h" /* Utility functions and stuff that don't have a home :( */