From b9530f6c7acf23696c00e80ece679672fa0545b0 Mon Sep 17 00:00:00 2001 From: jacob Date: Thu, 27 Feb 2025 09:17:21 -0600 Subject: [PATCH] use rand_state for rng --- src/app.c | 1 - src/rand.c | 60 ++++++++++++++++++++++++++++++++++++++++++++++++++ src/rand.h | 15 +++++++++++++ src/rng.c | 26 ---------------------- src/rng.h | 10 --------- src/sim_ent.c | 2 +- src/sim_step.c | 10 ++++----- src/sim_step.h | 3 +++ src/uid.c | 9 ++++---- src/uid.h | 2 +- src/user.c | 6 ++--- src/util.h | 17 -------------- 12 files changed, 92 insertions(+), 69 deletions(-) create mode 100644 src/rand.c create mode 100644 src/rand.h delete mode 100644 src/rng.c delete mode 100644 src/rng.h diff --git a/src/app.c b/src/app.c index b874aaaa..7d60ea3f 100644 --- a/src/app.c +++ b/src/app.c @@ -22,7 +22,6 @@ #include "math.h" #include "renderer.h" #include "phys.h" -#include "rng.h" #include "sock.h" #include "host.h" #include "bitbuff.h" diff --git a/src/rand.c b/src/rand.c new file mode 100644 index 00000000..5c6e9374 --- /dev/null +++ b/src/rand.c @@ -0,0 +1,60 @@ +#include "rand.h" +#include "sys.h" +#include "memory.h" +#include "thread_local.h" + +/* Based on Jon Maiga's "mx3" + * (https://jonkagstrom.com/mx3/mx3_rev2.html) + */ +INTERNAL u64 mix64(u64 x) +{ + x = (x ^ (x >> 32)) * 0xbea225f9eb34556d; + x = (x ^ (x >> 29)) * 0xbea225f9eb34556d; + x = (x ^ (x >> 32)) * 0xbea225f9eb34556d; + x = (x ^ (x >> 29)); + return x; +} + +/* ========================== * + * Stateful prng + * ========================== */ + +u64 rand_u64_from_state(struct rand_state *state) +{ + u64 res = state->seed; + while (res == 0) { + sys_true_rand(STRING_FROM_STRUCT(&res)); + } + res = mix64(res); + state->seed = res; + return res; +} + +f64 rand_f64_from_state(struct rand_state *state, f64 range_start, f64 range_end) +{ + if (range_start > range_end) { + f64 swp = range_start; + range_start = range_end; + range_end = swp; + } + return range_start + ((f64)rand_u64_from_state(state) / (f64)U64_MAX) * (range_end - range_start); +} + +/* ========================== * + * Seeded prng + * ========================== */ + +u64 rand_u64_from_seed(u64 seed) +{ + return mix64(seed); +} + +f64 rand_f64_from_seed(u64 seed, f64 range_start, f64 range_end) +{ + if (range_start > range_end) { + f64 swp = range_start; + range_start = range_end; + range_end = swp; + } + return range_start + ((f64)rand_u64_from_seed(seed) / (f64)U64_MAX) * (range_end - range_start); +} diff --git a/src/rand.h b/src/rand.h new file mode 100644 index 00000000..bdb97c1c --- /dev/null +++ b/src/rand.h @@ -0,0 +1,15 @@ +#ifndef RAND_H +#define RAND_H + +struct rand_state { + /* If a state's seed = 0 upon a to a related function, it will be initialized using platform's true rng source */ + u64 seed; +}; + +u64 rand_u64_from_state(struct rand_state *state); +f64 rand_f64_from_state(struct rand_state *state, f64 range_start, f64 range_end); + +u64 rand_u64_from_seed(u64 seed); +f64 rand_f64_from_seed(u64 seed, f64 range_start, f64 range_end); + +#endif diff --git a/src/rng.c b/src/rng.c deleted file mode 100644 index e3723c3d..00000000 --- a/src/rng.c +++ /dev/null @@ -1,26 +0,0 @@ -#include "rng.h" -#include "sys.h" - -u32 rng_true_u32(void) -{ - u32 v = 0; - sys_true_rand(STRING_FROM_STRUCT(&v)); - return v; -} - -u64 rng_true_u64(void) -{ - u64 v = 0; - sys_true_rand(STRING_FROM_STRUCT(&v)); - return v; -} - -f32 rng_true_f32(f32 range_start, f32 range_end) -{ - return ((f32)rng_true_u32() / (f32)U32_MAX) * (range_end - range_start) + range_start; -} - -f64 rng_true_f64(f64 range_start, f64 range_end) -{ - return ((f64)rng_true_u64() / (f64)U64_MAX) * (range_end - range_start) + range_start; -} diff --git a/src/rng.h b/src/rng.h deleted file mode 100644 index 2a68a7b4..00000000 --- a/src/rng.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef RNG_H -#define RNG_H - -/* Rand */ -u32 rng_true_u32(void); -u64 rng_true_u64(void); -f32 rng_true_f32(f32 range_start, f32 range_end); -f64 rng_true_f64(f64 range_start, f64 range_end); - -#endif diff --git a/src/sim_ent.c b/src/sim_ent.c index ae60809d..58183a34 100644 --- a/src/sim_ent.c +++ b/src/sim_ent.c @@ -269,7 +269,7 @@ struct sim_ent *sim_ent_from_id(struct sim_snapshot *ss, struct sim_ent_id id) struct sim_ent_id sim_ent_random_id(void) { struct sim_ent_id res = ZI; - res.uid = uid_rand(); + res.uid = uid_true_rand(); return res; } diff --git a/src/sim_step.c b/src/sim_step.c index 2fd201b5..7d6354da 100644 --- a/src/sim_step.c +++ b/src/sim_step.c @@ -11,7 +11,7 @@ #include "log.h" #include "phys.h" #include "collider.h" -#include "rng.h" +#include "rand.h" #include "space.h" #include "bitbuff.h" #include "host.h" @@ -74,7 +74,7 @@ INTERNAL void spawn_test_entities(struct sim_step_ctx *ctx, struct v2 offset) e->layer = SIM_LAYER_SHOULDERS; sim_ent_enable_prop(e, SIM_ENT_PROP_PHYSICAL_DYNAMIC); - e->mass_unscaled = 1; + e->mass_unscaled = 10; e->inertia_unscaled = 10; e->linear_ground_friction = 250; e->angular_ground_friction = 200; @@ -299,7 +299,7 @@ INTERNAL PHYS_COLLISION_CALLBACK_FUNC_DEF(on_collision, collision_data_array, st /* Create test blood */ /* TODO: Remove this */ { - struct xform xf = XFORM_TRS(.t = point, .r = rng_true_f32(0, TAU)); + struct xform xf = XFORM_TRS(.t = point, .r = rand_f64_from_state(&step_ctx->rand, 0, TAU)); struct sim_ent *decal = sim_ent_alloc_sync_src(root); decal->sprite = sprite_tag_from_path(LIT("res/graphics/blood.ase")); decal->sprite_tint = RGBA_32_F(1, 1, 1, 0.25f); @@ -308,10 +308,10 @@ INTERNAL PHYS_COLLISION_CALLBACK_FUNC_DEF(on_collision, collision_data_array, st 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), rng_true_f32(-perp_range, perp_range))); + linear_velocity = v2_add(linear_velocity, v2_mul(v2_perp(normal), rand_f64_from_state(&step_ctx->rand, -perp_range, perp_range))); f32 angular_velocity_range = 5; - f32 angular_velocity = rng_true_f32(-angular_velocity_range, angular_velocity_range); + f32 angular_velocity = rand_f64_from_seed(&step_ctx->rand, -angular_velocity_range, angular_velocity_range); sim_ent_enable_prop(decal, SIM_ENT_PROP_PHYSICAL_KINEMATIC); sim_ent_set_linear_velocity(decal, linear_velocity); diff --git a/src/sim_step.h b/src/sim_step.h index 48dac031..adabef81 100644 --- a/src/sim_step.h +++ b/src/sim_step.h @@ -1,6 +1,8 @@ #ifndef SIM_STEP_H #define SIM_STEP_H +#include "rand.h" + struct space; struct sim_snapshot; struct sim_snapshot_list; @@ -27,6 +29,7 @@ void sim_accel_reset(struct sim_snapshot *ss, struct sim_accel *accel); struct sim_step_ctx { b32 is_master; struct sim_accel *accel; + struct rand_state rand; /* TODO: Replace with per-sim rand for deterministic rng */ struct sim_snapshot *world; /* The world to simulate */ i64 sim_dt_ns; /* How much sim time should progress */ diff --git a/src/uid.c b/src/uid.c index 749df386..439a46eb 100644 --- a/src/uid.c +++ b/src/uid.c @@ -1,9 +1,9 @@ #include "uid.h" +#include "rand.h" #include "sys.h" -#include "util.h" /* Returns a uid generated from the system's random number generator */ -struct uid uid_rand(void) +struct uid uid_true_rand(void) { struct uid res = ZI; sys_true_rand(STRING_FROM_STRUCT(&res)); @@ -14,8 +14,7 @@ struct uid uid_rand(void) struct uid uid_combine(struct uid a, struct uid b) { struct uid res; - /* Add bits of a+b to an arbitrary random constant (to prevent (a=0 + b=0) from returning a uid=0) */ - res.hi = 0x958d53b0e2fd8e3f + a.hi + b.hi; - res.lo = 0x7038ffd46e0868c7 + a.lo + b.lo; + res.hi = rand_u64_from_seed(a.hi + b.hi); + res.lo = rand_u64_from_seed(a.lo + b.lo); return res; } diff --git a/src/uid.h b/src/uid.h index 1dd5e2b7..b2c8e4bc 100644 --- a/src/uid.h +++ b/src/uid.h @@ -1,7 +1,7 @@ #ifndef UID_H #define UID_H -struct uid uid_rand(void); +struct uid uid_true_rand(void); struct uid uid_combine(struct uid a, struct uid b); #endif diff --git a/src/user.c b/src/user.c index 0605aed7..9b0b7acf 100644 --- a/src/user.c +++ b/src/user.c @@ -15,7 +15,7 @@ #include "mixer.h" #include "atomic.h" #include "collider.h" -#include "rng.h" +#include "rand.h" #include "log.h" #include "sock.h" #include "host.h" @@ -752,8 +752,8 @@ INTERNAL void user_update(void) if (shake > 0) { u64 angle_seed0 = ent->id.uid.lo + (u64)(G.ss_blended->sim_time_ns / frequency_ns); u64 angle_seed1 = angle_seed0 + 1; - f32 angle0 = ((f32)mix64(angle_seed0) / (f32)U64_MAX) * TAU; - f32 angle1 = ((f32)mix64(angle_seed1) / (f32)U64_MAX) * TAU; + f32 angle0 = rand_f64_from_seed(angle_seed0, 0, TAU); + f32 angle1 = rand_f64_from_seed(angle_seed1, 0, TAU); 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 */ diff --git a/src/util.h b/src/util.h index 6a9b9419..2f45ea8f 100644 --- a/src/util.h +++ b/src/util.h @@ -30,23 +30,6 @@ INLINE u64 hash_fnv64(u64 seed, struct string s) return hash; } -/* ========================== * - * Bit mixing - * ========================== */ - -/* Based on Jon Maiga's "mx3" - * (https://jonkagstrom.com/mx3/mx3_rev2.html) - */ - -INLINE u64 mix64(u64 x) -{ - x = (x ^ (x >> 32)) * 0xbea225f9eb34556d; - x = (x ^ (x >> 29)) * 0xbea225f9eb34556d; - x = (x ^ (x >> 32)) * 0xbea225f9eb34556d; - x = (x ^ (x >> 29)); - return x; -} - /* ========================== * * Merge sort * ========================== */