Skip to main content

benchmark/scenes/
rain.rs

1// The Rain benchmark scene: rows of ragdoll "humans" that spawn and recycle
2// over time. Ported from benchmarks.c. The C global g_rainData becomes
3// thread-local state here.
4
5use std::cell::RefCell;
6
7use box2d_rust::body::create_body;
8use box2d_rust::geometry::make_offset_box;
9use box2d_rust::math_functions::{offset_pos, to_pos, Vec2, ROT_IDENTITY};
10use box2d_rust::shape::create_polygon_shape;
11use box2d_rust::types::{default_body_def, default_shape_def};
12use box2d_rust::world::World;
13
14use crate::human::{create_human, destroy_human, Human};
15
16use super::BENCHMARK_DEBUG;
17
18// (RainConstants)
19const RAIN_ROW_COUNT: i32 = if BENCHMARK_DEBUG { 3 } else { 5 };
20const RAIN_COLUMN_COUNT: i32 = if BENCHMARK_DEBUG { 10 } else { 40 };
21const RAIN_GROUP_SIZE: i32 = if BENCHMARK_DEBUG { 2 } else { 5 };
22
23// (RainData) — groups[row * column] each holding RAIN_GROUP_SIZE humans.
24struct RainData {
25    groups: Vec<Vec<Human>>,
26    grid_size: f32,
27    grid_count: i32,
28    column_count: i32,
29    column_index: i32,
30}
31
32impl RainData {
33    fn new() -> Self {
34        RainData {
35            groups: Vec::new(),
36            grid_size: 0.0,
37            grid_count: 0,
38            column_count: 0,
39            column_index: 0,
40        }
41    }
42
43    // memset( &g_rainData, 0, sizeof( g_rainData ) )
44    fn reset(&mut self) {
45        let group_count = (RAIN_ROW_COUNT * RAIN_COLUMN_COUNT) as usize;
46        self.groups = (0..group_count)
47            .map(|_| vec![Human::default(); RAIN_GROUP_SIZE as usize])
48            .collect();
49        self.grid_size = 0.0;
50        self.grid_count = 0;
51        self.column_count = 0;
52        self.column_index = 0;
53    }
54}
55
56thread_local! {
57    static RAIN_DATA: RefCell<RainData> = RefCell::new(RainData::new());
58}
59
60// (CreateRain)
61pub fn create_rain(world: &mut World) {
62    RAIN_DATA.with(|rd| rd.borrow_mut().reset());
63
64    let grid_size = 0.5;
65    let grid_count = if BENCHMARK_DEBUG { 200 } else { 500 };
66    RAIN_DATA.with(|rd| {
67        let mut rd = rd.borrow_mut();
68        rd.grid_size = grid_size;
69        rd.grid_count = grid_count;
70    });
71
72    {
73        let body_def = default_body_def();
74        let ground_id = create_body(world, &body_def);
75
76        let shape_def = default_shape_def();
77        let mut y = 0.0;
78        let width = grid_size;
79        let height = grid_size;
80
81        for _ in 0..RAIN_ROW_COUNT {
82            let mut x = -0.5 * grid_count as f32 * grid_size;
83            for _ in 0..=grid_count {
84                let box_shape =
85                    make_offset_box(0.5 * width, 0.5 * height, Vec2 { x, y }, ROT_IDENTITY);
86                create_polygon_shape(world, ground_id, &shape_def, &box_shape);
87
88                x += grid_size;
89            }
90
91            y += 45.0;
92        }
93    }
94
95    RAIN_DATA.with(|rd| {
96        let mut rd = rd.borrow_mut();
97        rd.column_count = 0;
98        rd.column_index = 0;
99    });
100}
101
102// (CreateGroup)
103fn create_group(world: &mut World, row_index: i32, column_index: i32) {
104    debug_assert!(row_index < RAIN_ROW_COUNT && column_index < RAIN_COLUMN_COUNT);
105
106    RAIN_DATA.with(|rd| {
107        let mut rd = rd.borrow_mut();
108
109        let group_index = (row_index * RAIN_COLUMN_COUNT + column_index) as usize;
110
111        let span = rd.grid_count as f32 * rd.grid_size;
112        let group_distance = 1.0 * span / RAIN_COLUMN_COUNT as f32;
113
114        let mut position = to_pos(Vec2 {
115            x: -0.5 * span + group_distance * (column_index as f32 + 0.5),
116            y: 40.0 + 45.0 * row_index as f32,
117        });
118
119        let scale = 1.0;
120        let joint_friction = 0.05;
121        let joint_hertz = 5.0;
122        let joint_damping = 0.5;
123
124        for i in 0..RAIN_GROUP_SIZE {
125            create_human(
126                &mut rd.groups[group_index][i as usize],
127                world,
128                position,
129                scale,
130                joint_friction,
131                joint_hertz,
132                joint_damping,
133                i + 1,
134                0,
135                false,
136            );
137            position = offset_pos(position, Vec2 { x: 0.5, y: 0.0 });
138        }
139    });
140}
141
142// (DestroyGroup)
143fn destroy_group(world: &mut World, row_index: i32, column_index: i32) {
144    debug_assert!(row_index < RAIN_ROW_COUNT && column_index < RAIN_COLUMN_COUNT);
145
146    RAIN_DATA.with(|rd| {
147        let mut rd = rd.borrow_mut();
148        let group_index = (row_index * RAIN_COLUMN_COUNT + column_index) as usize;
149
150        for i in 0..RAIN_GROUP_SIZE {
151            destroy_human(world, &mut rd.groups[group_index][i as usize]);
152        }
153    });
154}
155
156// (StepRain)
157pub fn step_rain(world: &mut World, step_count: i32) -> f32 {
158    let delay: i32 = if BENCHMARK_DEBUG { 0x1F } else { 0x7 };
159
160    if (step_count & delay) == 0 {
161        let column_count = RAIN_DATA.with(|rd| rd.borrow().column_count);
162
163        if column_count < RAIN_COLUMN_COUNT {
164            for i in 0..RAIN_ROW_COUNT {
165                create_group(world, i, column_count);
166            }
167
168            RAIN_DATA.with(|rd| rd.borrow_mut().column_count += 1);
169        } else {
170            let column_index = RAIN_DATA.with(|rd| rd.borrow().column_index);
171
172            for i in 0..RAIN_ROW_COUNT {
173                destroy_group(world, i, column_index);
174                create_group(world, i, column_index);
175            }
176
177            RAIN_DATA.with(|rd| {
178                let mut rd = rd.borrow_mut();
179                rd.column_index = (rd.column_index + 1) % RAIN_COLUMN_COUNT;
180            });
181        }
182    }
183
184    0.0
185}