pre-generate rand.dat file for deterministic noise. calculate shake based on world time

This commit is contained in:
jacob 2025-01-15 14:32:36 -06:00
parent 4c194d3b39
commit ad7ca7d68c
13 changed files with 178 additions and 38 deletions

1
.gitattributes vendored
View File

@ -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

BIN
res/rand.dat (Stored with Git LFS) Normal file

Binary file not shown.

View File

@ -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);

View File

@ -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

View File

@ -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 */
/* ====================================================================== */

View File

@ -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);
}
}

View File

@ -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);

79
src/rng.c Normal file
View File

@ -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;
}

22
src/rng.h Normal file
View File

@ -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

View File

@ -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);
/* ========================== *

View File

@ -19,16 +19,16 @@
# include <ShlObj_core.h>
# include <fileapi.h>
# include <dwmapi.h>
# include <NTSecAPI.h>
# include <bcrypt.h>
#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);

View File

@ -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,14 +683,30 @@ 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 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(v2_from_angle(sys_rand_f32(0, TAU)), shake));
xf.og = v2_add(xf.og, v2_mul(vec, shake));
entity_set_xform(ent, xf);
}
}
/* ========================== *
* Update viewport from camera

View File

@ -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 :( */