Skip to main content

benchmark/
utils.rs

1// Port of box2d-cpp-reference/shared/utils.c + utils.h: the XorShift32 random
2// number generator used for cross-platform determinism.
3//
4// GetNumberOfCores is intentionally not ported: the Rust benchmark harness is
5// serial and always reports a single worker.
6//
7// None of the ported benchmark scenes currently call the RNG (RandomPolygon and
8// friends are used by other shared helpers/samples), so the whole module is
9// allowed dead code. It is kept as a faithful companion to the C shared library.
10#![allow(dead_code)]
11
12use std::cell::Cell;
13
14use box2d_rust::collision::Polygon;
15use box2d_rust::geometry::{make_polygon, make_square};
16use box2d_rust::hull::compute_hull;
17use box2d_rust::math_functions::{make_rot, Rot, Vec2, PI};
18
19pub const RAND_LIMIT: i32 = 32767;
20pub const RAND_SEED: u32 = 12345;
21
22thread_local! {
23    /// Global seed for the simple random number generator. (g_randomSeed)
24    static G_RANDOM_SEED: Cell<u32> = const { Cell::new(RAND_SEED) };
25}
26
27/// Reset the RNG seed. (assign g_randomSeed = RAND_SEED)
28pub fn reset_random_seed() {
29    G_RANDOM_SEED.with(|seed| seed.set(RAND_SEED));
30}
31
32/// Simple random number generator. Using this instead of rand() for
33/// cross-platform determinism. (RandomInt)
34pub fn random_int() -> i32 {
35    G_RANDOM_SEED.with(|seed| {
36        // XorShift32 algorithm
37        let mut x = seed.get();
38        x ^= x << 13;
39        x ^= x >> 17;
40        x ^= x << 5;
41        seed.set(x);
42
43        // Map the 32-bit value to the range 0 to RAND_LIMIT
44        (x % (RAND_LIMIT as u32 + 1)) as i32
45    })
46}
47
48/// Random integer in range [lo, hi]. (RandomIntRange)
49pub fn random_int_range(lo: i32, hi: i32) -> i32 {
50    lo + random_int() % (hi - lo + 1)
51}
52
53/// Random number in range [-1,1]. (RandomFloat)
54pub fn random_float() -> f32 {
55    let mut r = (random_int() & RAND_LIMIT) as f32;
56    r /= RAND_LIMIT as f32;
57    r = 2.0 * r - 1.0;
58    r
59}
60
61/// Random floating point number in range [lo, hi]. (RandomFloatRange)
62pub fn random_float_range(lo: f32, hi: f32) -> f32 {
63    let mut r = (random_int() & RAND_LIMIT) as f32;
64    r /= RAND_LIMIT as f32;
65    r = (hi - lo) * r + lo;
66    r
67}
68
69/// Random vector with coordinates in range [lo, hi]. (RandomVec2)
70pub fn random_vec2(lo: f32, hi: f32) -> Vec2 {
71    Vec2 {
72        x: random_float_range(lo, hi),
73        y: random_float_range(lo, hi),
74    }
75}
76
77/// Random rotation with angle in range [-pi, pi]. (RandomRot)
78pub fn random_rot() -> Rot {
79    let angle = random_float_range(-PI, PI);
80    make_rot(angle)
81}
82
83/// (RandomPolygon)
84pub fn random_polygon(extent: f32) -> Polygon {
85    let count = 3 + random_int() % 6;
86    let mut points = Vec::with_capacity(count as usize);
87    for _ in 0..count {
88        points.push(random_vec2(-extent, extent));
89    }
90
91    let hull = compute_hull(&points);
92    if hull.count > 0 {
93        return make_polygon(&hull, 0.0);
94    }
95
96    make_square(extent)
97}