1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
//! The shared material registry as data: list the named materials, read one,
//! and update one in place so every entity referencing it changes at once. The
//! per-entity [`set_color`](crate::prelude::set_color) family edits an entity's
//! own material; these edit the registry the scene shares.
use nightshade::ecs::material::components::Material;
use nightshade::ecs::material::resources::material_registry_iter;
use nightshade::prelude::*;
use serde::{Deserialize, Serialize};
/// One named entry in the material registry.
#[derive(Clone, Serialize, Deserialize)]
pub struct MaterialEntry {
pub name: String,
pub material: Material,
}
/// Every material in the registry, sorted by name.
pub fn list_materials(world: &World) -> Vec<MaterialEntry> {
let mut entries: Vec<MaterialEntry> =
material_registry_iter(&world.resources.assets.material_registry)
.map(|(name, material)| MaterialEntry {
name: name.clone(),
material: material.clone(),
})
.collect();
entries.sort_by(|a, b| a.name.cmp(&b.name));
entries
}
/// The material registered under `name`, if any.
pub fn get_material(world: &World, name: &str) -> Option<Material> {
registry_entry_by_name(&world.resources.assets.material_registry.registry, name).cloned()
}
/// Replaces the material registered under `name`, reuploading it so every
/// entity that references it updates. The change runs through the ECS command
/// queue, so it applies on the next frame setup.
pub fn update_material(world: &mut World, name: &str, material: Material) {
queue_ecs_command(
world,
nightshade::ecs::world::commands::EcsCommand::ReloadMaterial {
name: name.to_string(),
material: Box::new(material),
},
);
}
/// Registers a named material in the shared registry so instanced meshes and
/// models can reference it by name, returning the name it was stored under. Build
/// the [`Material`] with the fields you need (base color, metallic, roughness,
/// emissive, textures). If a material with this name already exists it is kept
/// and its name returned, so calling this once at setup is idempotent.
pub fn register_material(world: &mut World, name: &str, material: Material) -> String {
nightshade::ecs::material::resources::material_registry_find_or_insert(
&mut world.resources.assets.material_registry,
name.to_string(),
material,
)
}
/// Activates a material variant by name across the scene, or the base materials
/// with `None`. Returns the number of entities affected.
pub fn set_material_variant(world: &mut World, variant: Option<&str>) -> usize {
nightshade::ecs::material::commands::material_variant_apply(world, variant)
}