use crate::scene::api_material_name;
use nightshade::prelude::*;
use nightshade::render::wgpu::texture_cache::{
SamplerSettings, TextureUsage, texture_cache_remove_reference,
};
pub fn set_color(world: &mut World, entity: Entity, color: [f32; 4]) {
mutate_material(world, entity, |material| {
material.base_color = color;
});
}
pub fn set_metallic_roughness(world: &mut World, entity: Entity, metallic: f32, roughness: f32) {
mutate_material(world, entity, |material| {
material.metallic = metallic;
material.roughness = roughness;
});
}
pub fn set_emissive(world: &mut World, entity: Entity, color: [f32; 3], strength: f32) {
mutate_material(world, entity, |material| {
material.emissive_factor = color;
material.emissive_strength = strength;
});
}
pub fn set_unlit(world: &mut World, entity: Entity, unlit: bool) {
mutate_material(world, entity, |material| {
material.unlit = unlit;
});
}
pub fn set_texture(world: &mut World, entity: Entity, texture_name: &str) {
let name = texture_name.to_string();
mutate_material(world, entity, move |material| {
material.base_texture = Some(name);
});
}
pub fn load_texture(world: &mut World, name: &str, image_bytes: &[u8]) {
nightshade::ecs::loading::queue_encoded_texture(
world,
name.to_string(),
image_bytes.to_vec(),
TextureUsage::Color,
SamplerSettings::DEFAULT,
);
texture_cache_add_reference(&mut world.resources.texture_cache, name);
}
fn mutate_material(world: &mut World, entity: Entity, apply: impl FnOnce(&mut Material)) {
let Some(material_ref) = world.core.get_material_ref(entity).cloned() else {
return;
};
let api_name = api_material_name(entity);
if material_ref.name == api_name {
let Some(mut material) = registry_entry_by_name(
&world.resources.assets.material_registry.registry,
&api_name,
)
.cloned() else {
return;
};
let old_textures: Vec<String> = material.texture_names().map(str::to_string).collect();
apply(&mut material);
let new_textures: Vec<String> = material.texture_names().map(str::to_string).collect();
swap_texture_references(world, &old_textures, &new_textures);
if let Some(existing) = registry_entry_by_name_mut(
&mut world.resources.assets.material_registry.registry,
&api_name,
) {
*existing = material;
}
world
.resources
.mesh_render_state
.mark_material_dirty(entity);
} else {
let mut material = registry_entry_by_name(
&world.resources.assets.material_registry.registry,
&material_ref.name,
)
.cloned()
.unwrap_or_default();
apply(&mut material);
let textures: Vec<String> = material.texture_names().map(str::to_string).collect();
for texture in &textures {
texture_cache_add_reference(&mut world.resources.texture_cache, texture);
}
if let Some((index, _)) = registry_lookup_index(
&world.resources.assets.material_registry.registry,
&material_ref.name,
) {
registry_remove_reference(
&mut world.resources.assets.material_registry.registry,
index,
);
}
register_material(world, entity, api_name, material);
}
}
fn swap_texture_references(world: &mut World, old_textures: &[String], new_textures: &[String]) {
for texture in old_textures {
if !new_textures.contains(texture) {
texture_cache_remove_reference(&mut world.resources.texture_cache, texture);
}
}
for texture in new_textures {
if !old_textures.contains(texture) {
texture_cache_add_reference(&mut world.resources.texture_cache, texture);
}
}
}