unlit3dx_examples/scene/
floor.rs1use glam::Vec3;
11use unlit_ecs::World;
12use unlit3d::components::Transform;
13use unlit3dx::prelude::*;
14
15use super::Scene;
16use crate::render::{
17 allocate_mesh, allocate_rgba_material, cuboid_mesh, instance_of, linear_sampler,
18};
19
20pub const GROUND_HALF: Vec3 = Vec3::new(12.0, 0.5, 12.0);
22
23pub const GROUND_POSITION: Vec3 = Vec3::new(0.0, -0.5, 0.0);
25
26pub const GROUND_COLOR: [u8; 4] = [126, 130, 138, 255];
28
29pub const GROUND_CHECKER_DARK: [u8; 4] = [88, 92, 100, 255];
31
32pub const GROUND_CHECKER_SIZE: u32 = 256;
36
37const GROUND_CHECKER_SQUARES: u32 = 8;
39
40const GROUND_FRICTION: f32 = 0.9;
42
43#[must_use]
47pub fn checker_ground() -> Vec<[u8; 4]> {
48 let block = GROUND_CHECKER_SIZE / GROUND_CHECKER_SQUARES;
49 let mut pixels = Vec::with_capacity((GROUND_CHECKER_SIZE * GROUND_CHECKER_SIZE) as usize);
50 for y in 0..GROUND_CHECKER_SIZE {
51 for x in 0..GROUND_CHECKER_SIZE {
52 let square = (x / block + y / block).is_multiple_of(2);
53 pixels.push(if square {
54 GROUND_COLOR
55 } else {
56 GROUND_CHECKER_DARK
57 });
58 }
59 }
60 pixels
61}
62
63pub fn spawn_floor(scene: &Scene) {
69 if let Err(error) = scene.physics.send(Box::new(|world: &mut World| {
70 spawn_fixed_cuboid(world, GROUND_POSITION, GROUND_HALF, GROUND_FRICTION);
71 })) {
72 log::error!("the physics world refused the ground ({error:?})");
73 }
74 if let Err(error) = scene.render.send(ground_job()) {
75 log::error!("the render world refused the ground ({error:?})");
76 }
77}
78
79fn ground_job() -> Job {
81 Box::new(|world: &mut World| {
82 let mesh = allocate_mesh(world, &cuboid_mesh(GROUND_HALF));
83 let material = allocate_rgba_material(
84 world,
85 (GROUND_CHECKER_SIZE, GROUND_CHECKER_SIZE),
86 &checker_ground(),
87 linear_sampler(),
88 );
89 instance_of(
90 world,
91 mesh,
92 material,
93 Transform {
94 translation: GROUND_POSITION,
95 ..Default::default()
96 },
97 );
98 })
99}
100
101#[cfg(test)]
102mod tests {
103 use super::*;
104 use crate::render::cuboid_mesh;
105 use crate::scene::shapes::tests::assert_faces_outward;
106
107 #[test]
111 fn the_ground_mesh_faces_outward() {
112 assert_faces_outward("cuboid", &cuboid_mesh(GROUND_HALF));
113 }
114
115 #[test]
118 fn the_checker_alternates_both_ways() {
119 let block = GROUND_CHECKER_SIZE / GROUND_CHECKER_SQUARES;
120 let pixels = checker_ground();
121 let at = |x: u32, y: u32| pixels[(y * GROUND_CHECKER_SIZE + x) as usize];
122 assert_ne!(at(0, 0), at(block, 0));
123 assert_ne!(at(0, 0), at(0, block));
124 assert_eq!(at(0, 0), at(block, block));
125 }
126}