base_rand refactor

This commit is contained in:
jacob 2025-07-30 15:03:15 -05:00
parent d2e1be0df9
commit 380f63cacf
8 changed files with 66 additions and 57 deletions

View File

@ -1,44 +1,42 @@
/* TODO: Use a value that gives good precision when dividing into range 0 -> 1 */
#define F64_RAND_MAX U64Max
////////////////////////////////
//~ True randomness
#if PlatformIsWindows
# define BCRYPT_RNG_ALG_HANDLE ((void *)0x00000081)
u32 BCryptGenRandom(void *algorithm, u8 *buffer, u32 buffer_size, u32 flags);
void rand_true(String buffer)
void TrueRand(String buffer)
{
BCryptGenRandom(BCRYPT_RNG_ALG_HANDLE, (u8 *)buffer.text, buffer.len, 0);
}
#else
# error rand_true not implemented for this platform
# error TrueRand not implemented for this platform
#endif
/* ========================== *
* Stateful prng
* ========================== */
////////////////////////////////
//~ Stateful randomness
u64 rand_u64_from_state(RandState *state)
u64 RandU64FromState(RandState *state)
{
u64 seed = state->seed;
if (seed == 0) {
rand_true(STRING_FROM_STRUCT(&seed));
TrueRand(STRING_FROM_STRUCT(&seed));
state->seed = seed;
}
return seed ^ rand_u64_from_seed(++state->counter);
return seed ^ RandU64FromSeed(++state->counter);
}
f64 rand_f64_from_state(RandState *state, f64 range_start, f64 range_end)
f64 RandF64FromState(RandState *state, f64 range_start, f64 range_end)
{
return range_start + (range_end - range_start) * ((f64)(rand_u64_from_state(state) % F64_RAND_MAX) / (f64)F64_RAND_MAX);
return range_start + (range_end - range_start) * ((f64)(RandU64FromState(state) % RandMaxF64) / (f64)RandMaxF64);
}
/* ========================== *
* Seeded prng
* ========================== */
////////////////////////////////
//~ Seeded randomness
/* Based on Jon Maiga's "mx3"
* https://jonkagstrom.com/mx3/mx3_rev2.html
*/
u64 rand_u64_from_seed(u64 seed)
u64 RandU64FromSeed(u64 seed)
{
seed = (seed ^ (seed >> 32)) * 0xbea225f9eb34556d;
seed = (seed ^ (seed >> 29)) * 0xbea225f9eb34556d;
@ -47,12 +45,12 @@ u64 rand_u64_from_seed(u64 seed)
return seed;
}
u64 rand_u64_from_seeds(u64 seed_a, u64 seed_b)
u64 RandU64FromSeeds(u64 seed_a, u64 seed_b)
{
return rand_u64_from_seed((seed_a * 3) + seed_b);
return RandU64FromSeed((seed_a * 3) + seed_b);
}
f64 rand_f64_from_seed(u64 seed, f64 range_start, f64 range_end)
f64 RandF64FromSeed(u64 seed, f64 range_start, f64 range_end)
{
return range_start + (range_end - range_start) * ((f64)(rand_u64_from_seed(seed) % F64_RAND_MAX) / (f64)F64_RAND_MAX);
return range_start + (range_end - range_start) * ((f64)(RandU64FromSeed(seed) % RandMaxF64) / (f64)RandMaxF64);
}

View File

@ -1,14 +1,25 @@
////////////////////////////////
//~ Rand types
Struct(RandState) {
/* If a state's seed == 0 upon a call to a related function, it will be initialized using platform's true rng source */
u64 seed;
u64 seed; /* If a state's seed == 0 upon a call to a related function, it will be initialized using platform's true rng source */
u64 counter;
};
void rand_true(String buffer);
/* TODO: Use a value that gives good precision when dividing into range 0 -> 1 */
#define RandMaxF64 U64Max
u64 rand_u64_from_state(RandState *state);
f64 rand_f64_from_state(RandState *state, f64 range_start, f64 range_end);
////////////////////////////////
//~ Rand operations
u64 rand_u64_from_seed(u64 seed);
u64 rand_u64_from_seeds(u64 seed_a, u64 seed_b);
f64 rand_f64_from_seed(u64 seed, f64 range_start, f64 range_end);
//- True randomness
void TrueRand(String buffer);
//- Stateful randomness
u64 RandU64FromState(RandState *state);
f64 RandF64FromState(RandState *state, f64 range_start, f64 range_end);
//- Seeded randomness
u64 RandU64FromSeed(u64 seed);
u64 RandU64FromSeeds(u64 seed_a, u64 seed_b);
f64 RandF64FromSeed(u64 seed, f64 range_start, f64 range_end);

View File

@ -2,7 +2,7 @@
UID uid_true_rand(void)
{
UID res = ZI;
rand_true(STRING_FROM_STRUCT(&res));
TrueRand(STRING_FROM_STRUCT(&res));
return res;
}
@ -14,8 +14,8 @@ UID uid_combine(UID a, UID b)
res.lo = (a.lo * 3) + b.lo;
res.hi += res.lo;
res.lo += res.hi;
res.hi = rand_u64_from_seed(res.hi);
res.lo = rand_u64_from_seed(res.lo);
res.hi = RandU64FromSeed(res.hi);
res.lo = RandU64FromSeed(res.lo);
res.hi += res.lo;
res.lo += res.hi;
return res;

View File

@ -2035,7 +2035,7 @@ internal struct command_descriptor_heap *command_list_push_descriptor_heap(struc
internal u64 command_buffer_hash_from_size(u64 size)
{
u64 hash = rand_u64_from_seed(size);
u64 hash = RandU64FromSeed(size);
return hash;
}
@ -3003,10 +3003,10 @@ G_Resource *gp_run_render(G_RenderSig *gp_render_sig, G_RenderParams params)
sig.flags = K_UintFromU32(shade_flags);
sig.tex_width = K_UintFromU32(render_size.x);
sig.tex_height = K_UintFromU32(render_size.y);
sig.frame_seed = K_Uint4FromU32((u32)(rand_u64_from_state(&rsig->rand) & 0xFFFFFFFF),
(u32)(rand_u64_from_state(&rsig->rand) & 0xFFFFFFFF),
(u32)(rand_u64_from_state(&rsig->rand) & 0xFFFFFFFF),
(u32)(rand_u64_from_state(&rsig->rand) & 0xFFFFFFFF));
sig.frame_seed = K_Uint4FromU32((u32)(RandU64FromState(&rsig->rand) & 0xFFFFFFFF),
(u32)(RandU64FromState(&rsig->rand) & 0xFFFFFFFF),
(u32)(RandU64FromState(&rsig->rand) & 0xFFFFFFFF),
(u32)(RandU64FromState(&rsig->rand) & 0xFFFFFFFF));
sig.frame_index = K_UintFromU32(rsig->frame_index);
sig.camera_offset = K_Float2FromV2(world_to_render_xf.og);
sig.albedo_tex_urid = K_UintFromU32(rsig->albedo->srv_descriptor->index);

View File

@ -293,7 +293,7 @@ EntId sim_ent_tile_chunk_id_from_tile_chunk_index(Vec2I32 chunk_index)
{
EntId res = ZI;
res.uid = SIM_ENT_TILE_CHUNK_BASIS_UID;
res.uid = uid_combine(res.uid, MakeUID(rand_u64_from_seed(chunk_index.x), rand_u64_from_seed(chunk_index.y)));
res.uid = uid_combine(res.uid, MakeUID(RandU64FromSeed(chunk_index.x), RandU64FromSeed(chunk_index.y)));
return res;
}

View File

@ -270,9 +270,9 @@ internal void test_spawn_entities2(Ent *parent, Vec2 pos)
/* FIXME: Remove this */
{
static RandState rand = ZI;
f32 r = rand_f64_from_state(&rand, 1, 5);
f32 g = rand_f64_from_state(&rand, 1, 5);
f32 b = rand_f64_from_state(&rand, 1, 5);
f32 r = RandF64FromState(&rand, 1, 5);
f32 g = RandF64FromState(&rand, 1, 5);
f32 b = RandF64FromState(&rand, 1, 5);
e->sprite_emittance = VEC3(r, g, b);
e->sprite_tint = Rgba32F(r / 5, g / 5, b / 5, 1);
}
@ -528,8 +528,8 @@ internal void test_generate_walls(Snapshot *world)
Vec2I32 end = sim_world_tile_index_from_local_tile_index(chunk_index, VEC2I32(wall_end, tile_y));
struct wall_node *node = 0;
if (wall_start == 0) {
u64 start_hash = rand_u64_from_seed(*(u64 *)&start);
start_hash = rand_u64_from_seeds(start_hash, wall_dir);
u64 start_hash = RandU64FromSeed(*(u64 *)&start);
start_hash = RandU64FromSeeds(start_hash, wall_dir);
DictEntry *entry = dict_get_entry(horizontal_ends_dict, start_hash);
if (entry) {
/* Existing wall exists accross chunk boundary */
@ -546,8 +546,8 @@ internal void test_generate_walls(Snapshot *world)
}
node->end = end;
if (wall_end == SIM_TILES_PER_CHUNK_SQRT) {
u64 end_hash = rand_u64_from_seed(*(u64 *)&end);
end_hash = rand_u64_from_seeds(end_hash, wall_dir);
u64 end_hash = RandU64FromSeed(*(u64 *)&end);
end_hash = RandU64FromSeeds(end_hash, wall_dir);
dict_set(scratch.arena, horizontal_ends_dict, end_hash, (u64)node);
}
wall_start = -1;
@ -618,8 +618,8 @@ internal void test_generate_walls(Snapshot *world)
Vec2I32 end = sim_world_tile_index_from_local_tile_index(chunk_index, VEC2I32(tile_x, wall_end));
struct wall_node *node = 0;
if (wall_start == 0) {
u64 start_hash = rand_u64_from_seed(*(u64 *)&start);
start_hash = rand_u64_from_seeds(start_hash, wall_dir);
u64 start_hash = RandU64FromSeed(*(u64 *)&start);
start_hash = RandU64FromSeeds(start_hash, wall_dir);
DictEntry *entry = dict_get_entry(vertical_ends_dict, start_hash);
if (entry) {
/* Existing wall exists accross chunk boundary */
@ -636,8 +636,8 @@ internal void test_generate_walls(Snapshot *world)
}
node->end = end;
if (wall_end == SIM_TILES_PER_CHUNK_SQRT) {
u64 end_hash = rand_u64_from_seed(*(u64 *)&end);
end_hash = rand_u64_from_seeds(end_hash, wall_dir);
u64 end_hash = RandU64FromSeed(*(u64 *)&end);
end_hash = RandU64FromSeeds(end_hash, wall_dir);
dict_set(scratch.arena, vertical_ends_dict, end_hash, (u64)node);
}
wall_start = -1;
@ -748,7 +748,7 @@ internal PHYS_COLLISION_CALLBACK_FUNC_DEF(on_collision, data, step_ctx)
/* Create test blood */
/* TODO: Remove this */
{
Xform xf = XformFromTrs(TRS(.t = point, .r = rand_f64_from_state(&step_ctx->rand, 0, Tau)));
Xform xf = XformFromTrs(TRS(.t = point, .r = RandF64FromState(&step_ctx->rand, 0, Tau)));
Ent *decal = sim_ent_alloc_sync_src(root);
decal->sprite = sprite_tag_from_path(LIT("sprite/blood.ase"));
decal->sprite_tint = Rgba32F(1, 1, 1, 0.25f);
@ -757,10 +757,10 @@ internal PHYS_COLLISION_CALLBACK_FUNC_DEF(on_collision, data, step_ctx)
f32 perp_range = 0.5;
Vec2 linear_velocity = MulVec2(normal, 0.5);
linear_velocity = AddVec2(linear_velocity, MulVec2(PerpVec2(normal), rand_f64_from_state(&step_ctx->rand, -perp_range, perp_range)));
linear_velocity = AddVec2(linear_velocity, MulVec2(PerpVec2(normal), RandF64FromState(&step_ctx->rand, -perp_range, perp_range)));
f32 angular_velocity_range = 5;
f32 angular_velocity = rand_f64_from_state(&step_ctx->rand, -angular_velocity_range, angular_velocity_range);
f32 angular_velocity = RandF64FromState(&step_ctx->rand, -angular_velocity_range, angular_velocity_range);
sim_ent_enable_prop(decal, SEPROP_KINEMATIC);
sim_ent_set_linear_velocity(decal, linear_velocity);

View File

@ -276,7 +276,7 @@ b32 sprite_tag_eq(S_Tag t1, S_Tag t2)
internal struct cache_entry_hash cache_entry_hash_from_tag_hash(u64 tag_hash, enum cache_entry_kind kind)
{
return (struct cache_entry_hash) { .v = rand_u64_from_seed(tag_hash + kind) };
return (struct cache_entry_hash) { .v = RandU64FromSeed(tag_hash + kind) };
}
/* ========================== *

View File

@ -846,8 +846,8 @@ internal void user_update(P_Window *window)
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 = rand_f64_from_seed(angle_seed0, 0, Tau);
f32 angle1 = rand_f64_from_seed(angle_seed1, 0, Tau);
f32 angle0 = RandF64FromSeed(angle_seed0, 0, Tau);
f32 angle1 = RandF64FromSeed(angle_seed1, 0, Tau);
Vec2 vec0 = Vec2WithLen(Vec2FromAngle(angle0), shake);
/* NOTE: vec1 not completely accurate since shake can change between frames, it's just a prediction */