Skip to main content

parity/
parity.rs

1use nightshade_api::prelude::*;
2use std::time::{Duration, Instant};
3
4const CUBE_COUNT: usize = 500;
5const PHASE_FRAMES: u32 = 300;
6
7fn main() {
8    let mut app = open();
9    show_grid(&mut app.world, false);
10    orbit_camera(&mut app.world, vec3(0.0, 0.5, 0.0), 45.0);
11
12    let positions = grid_positions();
13    let mut entities = spawn_objects(
14        &mut app.world,
15        Object {
16            color: TEAL,
17            ..Object::default()
18        },
19        &positions,
20    );
21
22    let label = spawn_text(
23        &mut app.world,
24        "phase 1: api spelling",
25        ScreenAnchor::TopLeft,
26    );
27
28    let mut frame_index = 0u32;
29    let mut api_total = Duration::ZERO;
30    let mut api_frames = 0u32;
31    let mut longhand_total = Duration::ZERO;
32    let mut longhand_frames = 0u32;
33
34    while frame(&mut app) {
35        let step = delta_time(&app.world);
36        if frame_index < PHASE_FRAMES {
37            let start = Instant::now();
38            for &entity in &entities {
39                rotate(&mut app.world, entity, Vec3::y(), step);
40            }
41            api_total += start.elapsed();
42            api_frames += 1;
43            if frame_index + 1 == PHASE_FRAMES {
44                for &entity in &entities {
45                    despawn(&mut app.world, entity);
46                }
47                entities = longhand::spawn_grid(&mut app.world, &positions, ORANGE);
48                app.world.resources.mesh_render_state.request_full_rebuild();
49                set_text(&mut app.world, label, "phase 2: longhand spelling");
50            }
51        } else {
52            let start = Instant::now();
53            for &entity in &entities {
54                longhand::rotate(&mut app.world, entity, Vec3::y(), step);
55            }
56            longhand_total += start.elapsed();
57            longhand_frames += 1;
58            if frame_index + 1 == PHASE_FRAMES * 2 {
59                break;
60            }
61        }
62        frame_index += 1;
63    }
64
65    report("api", api_total, api_frames);
66    report("longhand", longhand_total, longhand_frames);
67}
68
69fn report(name: &str, total: Duration, frames: u32) {
70    if frames == 0 {
71        println!("{name}: no frames measured");
72        return;
73    }
74    let milliseconds = total.as_secs_f64() * 1000.0 / frames as f64;
75    println!(
76        "{name}: {CUBE_COUNT} cubes rotated in {milliseconds:.4} ms per frame average over {frames} frames"
77    );
78}
79
80fn grid_positions() -> Vec<Vec3> {
81    let mut positions = Vec::with_capacity(CUBE_COUNT);
82    for row in 0..20 {
83        for column in 0..25 {
84            positions.push(vec3(
85                column as f32 * 2.0 - 24.0,
86                0.5,
87                row as f32 * 2.0 - 19.0,
88            ));
89        }
90    }
91    positions
92}
93
94mod longhand {
95    use nightshade_api::nightshade;
96    use nightshade_api::nightshade::prelude::*;
97
98    pub fn spawn_grid(world: &mut World, positions: &[Vec3], color: [f32; 4]) -> Vec<Entity> {
99        let material_name = nightshade::ecs::material::resources::material_registry_find_or_insert(
100            &mut world.resources.assets.material_registry,
101            "parity::longhand".to_string(),
102            Material {
103                base_color: color,
104                ..Default::default()
105            },
106        );
107        let mut entities = Vec::with_capacity(positions.len());
108        for &position in positions {
109            let entity = spawn_mesh_at(world, "Cube", position, Vec3::new(1.0, 1.0, 1.0));
110            let previous = world
111                .core
112                .get_material_ref(entity)
113                .map(|material_ref| material_ref.name.clone());
114            if let Some(previous_name) = previous
115                && let Some((index, _)) = registry_lookup_index(
116                    &world.resources.assets.material_registry.registry,
117                    &previous_name,
118                )
119            {
120                registry_remove_reference(
121                    &mut world.resources.assets.material_registry.registry,
122                    index,
123                );
124            }
125            if let Some((index, _)) = registry_lookup_index(
126                &world.resources.assets.material_registry.registry,
127                &material_name,
128            ) {
129                registry_add_reference(
130                    &mut world.resources.assets.material_registry.registry,
131                    index,
132                );
133            }
134            world
135                .core
136                .set_material_ref(entity, MaterialRef::new(material_name.clone()));
137            world.resources.mesh_render_state.mark_entity_added(entity);
138            entities.push(entity);
139        }
140        entities
141    }
142
143    pub fn rotate(world: &mut World, entity: Entity, axis: Vec3, radians: f32) {
144        if let Some(transform) = mutate_local_transform(world, entity) {
145            transform.rotation =
146                nalgebra_glm::quat_angle_axis(radians, &axis.normalize()) * transform.rotation;
147        }
148    }
149}