Skip to main content

benchmark/scenes/
pyramids.rs

1// Pyramid-family benchmark scenes: joint grid, large pyramid, many pyramids,
2// and the compound-shape barrel. Ported from benchmarks.c.
3
4use box2d_rust::body::create_body;
5use box2d_rust::collision::{Circle, Segment};
6use box2d_rust::geometry::{make_box, make_offset_box, make_polygon, make_square};
7use box2d_rust::hull::compute_hull;
8use box2d_rust::id::BodyId;
9use box2d_rust::joint::create_revolute_joint;
10use box2d_rust::math_functions::{to_pos, Vec2, ROT_IDENTITY};
11use box2d_rust::shape::{create_circle_shape, create_polygon_shape, create_segment_shape};
12use box2d_rust::types::{
13    default_body_def, default_revolute_joint_def, default_shape_def, BodyType,
14};
15use box2d_rust::world::{world_enable_sleeping, World};
16
17use super::BENCHMARK_DEBUG;
18
19// (CreateJointGrid)
20pub fn create_joint_grid(world: &mut World) {
21    world_enable_sleeping(world, false);
22
23    let n: i32 = if BENCHMARK_DEBUG { 20 } else { 100 };
24
25    let mut bodies: Vec<BodyId> = Vec::with_capacity((n * n) as usize);
26
27    let mut shape_def = default_shape_def();
28    shape_def.density = 1.0;
29    shape_def.filter.category_bits = 2;
30    shape_def.filter.mask_bits = (!2u32) as u64;
31
32    let circle = Circle {
33        center: Vec2 { x: 0.0, y: 0.0 },
34        radius: 0.4,
35    };
36
37    let mut joint_def = default_revolute_joint_def();
38    joint_def.base.draw_scale = 0.4;
39
40    let mut body_def = default_body_def();
41
42    for k in 0..n {
43        for i in 0..n {
44            let fk = k as f32;
45            let fi = i as f32;
46
47            if k >= n / 2 - 3 && k <= n / 2 + 3 && i == 0 {
48                body_def.type_ = BodyType::Static;
49            } else {
50                body_def.type_ = BodyType::Dynamic;
51            }
52
53            body_def.position = to_pos(Vec2 { x: fk, y: -fi });
54
55            let body = create_body(world, &body_def);
56            create_circle_shape(world, body, &shape_def, &circle);
57
58            let index = bodies.len();
59
60            if i > 0 {
61                joint_def.base.body_id_a = bodies[index - 1];
62                joint_def.base.body_id_b = body;
63                joint_def.base.local_frame_a.p = Vec2 { x: 0.0, y: -0.5 };
64                joint_def.base.local_frame_b.p = Vec2 { x: 0.0, y: 0.5 };
65                create_revolute_joint(world, &joint_def);
66            }
67
68            if k > 0 {
69                joint_def.base.body_id_a = bodies[index - n as usize];
70                joint_def.base.body_id_b = body;
71                joint_def.base.local_frame_a.p = Vec2 { x: 0.5, y: 0.0 };
72                joint_def.base.local_frame_b.p = Vec2 { x: -0.5, y: 0.0 };
73                create_revolute_joint(world, &joint_def);
74            }
75
76            bodies.push(body);
77        }
78    }
79}
80
81// (CreateLargePyramid)
82pub fn create_large_pyramid(world: &mut World) {
83    world_enable_sleeping(world, false);
84
85    let base_count: i32 = if BENCHMARK_DEBUG { 20 } else { 100 };
86
87    {
88        let mut body_def = default_body_def();
89        body_def.position = to_pos(Vec2 { x: 0.0, y: -1.0 });
90        let ground_id = create_body(world, &body_def);
91
92        let box_shape = make_box(100.0, 1.0);
93        let shape_def = default_shape_def();
94        create_polygon_shape(world, ground_id, &shape_def, &box_shape);
95    }
96
97    let mut body_def = default_body_def();
98    body_def.type_ = BodyType::Dynamic;
99
100    let mut shape_def = default_shape_def();
101    shape_def.density = 1.0;
102
103    let a = 0.5;
104    let box_shape = make_square(a);
105
106    let shift = 1.0 * a;
107
108    for i in 0..base_count {
109        let y = (2.0 * i as f32 + 1.0) * shift;
110
111        for j in i..base_count {
112            let x = (i as f32 + 1.0) * shift + 2.0 * (j - i) as f32 * shift - a * base_count as f32;
113
114            body_def.position = to_pos(Vec2 { x, y });
115
116            let body_id = create_body(world, &body_def);
117            create_polygon_shape(world, body_id, &shape_def, &box_shape);
118        }
119    }
120}
121
122// (static CreateSmallPyramid)
123fn create_small_pyramid(
124    world: &mut World,
125    base_count: i32,
126    extent: f32,
127    center_x: f32,
128    base_y: f32,
129) {
130    let mut body_def = default_body_def();
131    body_def.type_ = BodyType::Dynamic;
132
133    let shape_def = default_shape_def();
134
135    let box_shape = make_square(extent);
136
137    for i in 0..base_count {
138        let y = (2.0 * i as f32 + 1.0) * extent + base_y;
139
140        for j in i..base_count {
141            let x = (i as f32 + 1.0) * extent + 2.0 * (j - i) as f32 * extent + center_x - 0.5;
142            body_def.position = to_pos(Vec2 { x, y });
143
144            let body_id = create_body(world, &body_def);
145            create_polygon_shape(world, body_id, &shape_def, &box_shape);
146        }
147    }
148}
149
150// (CreateManyPyramids)
151pub fn create_many_pyramids(world: &mut World) {
152    world_enable_sleeping(world, false);
153
154    let base_count = 10;
155    let extent = 0.5;
156    let row_count: i32 = if BENCHMARK_DEBUG { 5 } else { 20 };
157    let column_count: i32 = if BENCHMARK_DEBUG { 5 } else { 20 };
158
159    let body_def = default_body_def();
160    let ground_id = create_body(world, &body_def);
161
162    let ground_delta_y = 2.0 * extent * (base_count as f32 + 1.0);
163    let ground_width = 2.0 * extent * column_count as f32 * (base_count as f32 + 1.0);
164    let shape_def = default_shape_def();
165
166    let mut ground_y = 0.0;
167
168    for _ in 0..row_count {
169        let segment = Segment {
170            point1: Vec2 {
171                x: -0.5 * ground_width,
172                y: ground_y,
173            },
174            point2: Vec2 {
175                x: 0.5 * ground_width,
176                y: ground_y,
177            },
178        };
179        create_segment_shape(world, ground_id, &shape_def, &segment);
180        ground_y += ground_delta_y;
181    }
182
183    let base_width = 2.0 * extent * base_count as f32;
184    let mut base_y = 0.0;
185
186    for _ in 0..row_count {
187        for j in 0..column_count {
188            let center_x =
189                -0.5 * ground_width + j as f32 * (base_width + 2.0 * extent) + 2.0 * extent;
190            create_small_pyramid(world, base_count, extent, center_x, base_y);
191        }
192
193        base_y += ground_delta_y;
194    }
195}
196
197// (CreateCompounds)
198// Lifted from samples/sample_benchmark.cpp BenchmarkBarrel (e_compoundShape
199// branch). Each dynamic body is a compound of two triangular polygon shapes.
200pub fn create_compounds(world: &mut World) {
201    {
202        let grid_size = 1.0;
203
204        let body_def = default_body_def();
205        let ground_id = create_body(world, &body_def);
206
207        let shape_def = default_shape_def();
208
209        let y = 0.0;
210        let mut x = -40.0 * grid_size;
211        for _ in 0..81 {
212            let box_shape = make_offset_box(
213                0.55 * grid_size,
214                0.5 * grid_size,
215                Vec2 { x, y },
216                ROT_IDENTITY,
217            );
218            create_polygon_shape(world, ground_id, &shape_def, &box_shape);
219            x += grid_size;
220        }
221
222        let mut y = grid_size;
223        let x = -40.0 * grid_size;
224        for _ in 0..100 {
225            let box_shape = make_offset_box(
226                0.5 * grid_size,
227                0.55 * grid_size,
228                Vec2 { x, y },
229                ROT_IDENTITY,
230            );
231            create_polygon_shape(world, ground_id, &shape_def, &box_shape);
232            y += grid_size;
233        }
234
235        let mut y = grid_size;
236        let x = 40.0 * grid_size;
237        for _ in 0..100 {
238            let box_shape = make_offset_box(
239                0.5 * grid_size,
240                0.55 * grid_size,
241                Vec2 { x, y },
242                ROT_IDENTITY,
243            );
244            create_polygon_shape(world, ground_id, &shape_def, &box_shape);
245            y += grid_size;
246        }
247
248        let segment = Segment {
249            point1: Vec2 {
250                x: -800.0,
251                y: -80.0,
252            },
253            point2: Vec2 { x: 800.0, y: -80.0 },
254        };
255        create_segment_shape(world, ground_id, &shape_def, &segment);
256    }
257
258    let column_count: i32 = if BENCHMARK_DEBUG { 10 } else { 20 };
259    let row_count: i32 = if BENCHMARK_DEBUG { 40 } else { 150 };
260
261    let left_points = [
262        Vec2 { x: -1.0, y: 0.0 },
263        Vec2 { x: 0.5, y: 1.0 },
264        Vec2 { x: 0.0, y: 2.0 },
265    ];
266    let left_hull = compute_hull(&left_points);
267    let left = make_polygon(&left_hull, 0.0);
268
269    let right_points = [
270        Vec2 { x: 1.0, y: 0.0 },
271        Vec2 { x: -0.5, y: 1.0 },
272        Vec2 { x: 0.0, y: 2.0 },
273    ];
274    let right_hull = compute_hull(&right_points);
275    let right = make_polygon(&right_hull, 0.0);
276
277    let mut body_def = default_body_def();
278    body_def.type_ = BodyType::Dynamic;
279
280    let mut shape_def = default_shape_def();
281    shape_def.density = 1.0;
282    shape_def.material.friction = 0.5;
283
284    // Match the sample exactly: centery is computed before shift is reset for
285    // the compound branch.
286    let shift = 2.0;
287    let extray = 0.25;
288    let mut side = 0.25;
289    let centerx = shift * column_count as f32 / 2.0 - 1.0;
290    let centery = 1.15 / 2.0;
291    let y_start = 5.0;
292
293    for i in 0..column_count {
294        let x = i as f32 * shift - centerx;
295
296        for j in 0..row_count {
297            let y = j as f32 * (shift + extray) + centery + y_start;
298
299            body_def.position = to_pos(Vec2 { x: x + side, y });
300            side = -side;
301
302            let body_id = create_body(world, &body_def);
303            create_polygon_shape(world, body_id, &shape_def, &left);
304            create_polygon_shape(world, body_id, &shape_def, &right);
305        }
306    }
307}