nightshade 0.13.1

A cross-platform data-oriented game engine.
Documentation
use super::super::types::MaterialTextures;
use super::{MaterialBindGroupContext, MeshPass};

impl MeshPass {
    pub(in super::super) fn create_material_bind_group(
        device: &wgpu::Device,
        material_id: u32,
        cache_key: &MaterialTextures,
        ctx: &MaterialBindGroupContext,
    ) -> (wgpu::BindGroup, MaterialTextures) {
        let mut found_textures = MaterialTextures::default();

        let (base_texture_view, base_sampler) = if let Some(ref name) = cache_key.base_texture
            && let Some((view, sampler)) = ctx.registered_textures.get(name)
        {
            found_textures.base_texture = Some(name.clone());
            (view, sampler)
        } else {
            (ctx.dummy_white_view, ctx.dummy_sampler)
        };

        let (emissive_texture_view, emissive_sampler) = if let Some(ref name) =
            cache_key.emissive_texture
            && let Some((view, sampler)) = ctx.registered_textures.get(name)
        {
            found_textures.emissive_texture = Some(name.clone());
            (view, sampler)
        } else {
            (ctx.dummy_black_view, ctx.dummy_sampler)
        };

        let (normal_texture_view, normal_sampler) = if let Some(ref name) = cache_key.normal_texture
            && let Some((view, sampler)) = ctx.registered_textures.get(name)
        {
            found_textures.normal_texture = Some(name.clone());
            (view, sampler)
        } else {
            (ctx.dummy_normal_view, ctx.dummy_sampler)
        };

        let (metallic_roughness_texture_view, metallic_roughness_sampler) = if let Some(ref name) =
            cache_key.metallic_roughness_texture
            && let Some((view, sampler)) = ctx.registered_textures.get(name)
        {
            found_textures.metallic_roughness_texture = Some(name.clone());
            (view, sampler)
        } else {
            (ctx.dummy_white_view, ctx.dummy_sampler)
        };

        let (occlusion_texture_view, occlusion_sampler) = if let Some(ref name) =
            cache_key.occlusion_texture
            && let Some((view, sampler)) = ctx.registered_textures.get(name)
        {
            found_textures.occlusion_texture = Some(name.clone());
            (view, sampler)
        } else {
            (ctx.dummy_white_view, ctx.dummy_sampler)
        };

        let (transmission_texture_view, transmission_sampler) = if let Some(ref name) =
            cache_key.transmission_texture
            && let Some((view, sampler)) = ctx.registered_textures.get(name)
        {
            found_textures.transmission_texture = Some(name.clone());
            (view, sampler)
        } else {
            (ctx.dummy_white_view, ctx.dummy_sampler)
        };

        let (thickness_texture_view, thickness_sampler) = if let Some(ref name) =
            cache_key.thickness_texture
            && let Some((view, sampler)) = ctx.registered_textures.get(name)
        {
            found_textures.thickness_texture = Some(name.clone());
            (view, sampler)
        } else {
            (ctx.dummy_white_view, ctx.dummy_sampler)
        };

        let (specular_texture_view, specular_sampler) = if let Some(ref name) =
            cache_key.specular_texture
            && let Some((view, sampler)) = ctx.registered_textures.get(name)
        {
            found_textures.specular_texture = Some(name.clone());
            (view, sampler)
        } else {
            (ctx.dummy_white_view, ctx.dummy_sampler)
        };

        let bind_group_entries = vec![
            wgpu::BindGroupEntry {
                binding: 0,
                resource: wgpu::BindingResource::TextureView(base_texture_view),
            },
            wgpu::BindGroupEntry {
                binding: 1,
                resource: wgpu::BindingResource::Sampler(base_sampler),
            },
            wgpu::BindGroupEntry {
                binding: 2,
                resource: wgpu::BindingResource::TextureView(emissive_texture_view),
            },
            wgpu::BindGroupEntry {
                binding: 3,
                resource: wgpu::BindingResource::Sampler(emissive_sampler),
            },
            wgpu::BindGroupEntry {
                binding: 4,
                resource: wgpu::BindingResource::TextureView(normal_texture_view),
            },
            wgpu::BindGroupEntry {
                binding: 5,
                resource: wgpu::BindingResource::Sampler(normal_sampler),
            },
            wgpu::BindGroupEntry {
                binding: 6,
                resource: wgpu::BindingResource::TextureView(metallic_roughness_texture_view),
            },
            wgpu::BindGroupEntry {
                binding: 7,
                resource: wgpu::BindingResource::Sampler(metallic_roughness_sampler),
            },
            wgpu::BindGroupEntry {
                binding: 8,
                resource: wgpu::BindingResource::TextureView(occlusion_texture_view),
            },
            wgpu::BindGroupEntry {
                binding: 9,
                resource: wgpu::BindingResource::Sampler(occlusion_sampler),
            },
            wgpu::BindGroupEntry {
                binding: 10,
                resource: wgpu::BindingResource::TextureView(transmission_texture_view),
            },
            wgpu::BindGroupEntry {
                binding: 11,
                resource: wgpu::BindingResource::Sampler(transmission_sampler),
            },
            wgpu::BindGroupEntry {
                binding: 12,
                resource: wgpu::BindingResource::TextureView(thickness_texture_view),
            },
            wgpu::BindGroupEntry {
                binding: 13,
                resource: wgpu::BindingResource::Sampler(thickness_sampler),
            },
            wgpu::BindGroupEntry {
                binding: 14,
                resource: wgpu::BindingResource::TextureView(specular_texture_view),
            },
            wgpu::BindGroupEntry {
                binding: 15,
                resource: wgpu::BindingResource::Sampler(specular_sampler),
            },
        ];
        let bind_group = device.create_bind_group(&wgpu::BindGroupDescriptor {
            label: Some(&format!("Material {} Texture Bind Group", material_id)),
            layout: ctx.texture_bind_group_layout,
            entries: &bind_group_entries,
        });

        (bind_group, found_textures)
    }

    pub(in super::super) fn refresh_material_bind_groups_for_world(
        &mut self,
        device: &wgpu::Device,
    ) {
        let world_state = match self.world_states.get(&self.current_world_id) {
            Some(state) => state,
            None => return,
        };

        if world_state.material_bind_group_cache_key.is_empty() {
            return;
        }

        let material_ids_to_refresh: Vec<u32> = world_state
            .material_bind_group_cache_key
            .iter()
            .filter(|&(&material_id, cache_key)| {
                let prev_found = world_state
                    .material_bind_group_found_textures
                    .get(&material_id)
                    .cloned()
                    .unwrap_or_default();
                cache_key.has_newly_available_textures(&prev_found, &self.registered_textures)
            })
            .map(|(&id, _)| id)
            .collect();

        if material_ids_to_refresh.is_empty() {
            return;
        }

        let ctx = MaterialBindGroupContext {
            registered_textures: &self.registered_textures,
            dummy_white_view: &self.dummy_white_view,
            dummy_black_view: &self.dummy_black_view,
            dummy_normal_view: &self.dummy_normal_view,
            dummy_sampler: &self.dummy_sampler,
            texture_bind_group_layout: &self.texture_bind_group_layout,
        };
        let world_state = self.world_states.get_mut(&self.current_world_id).unwrap();
        for material_id in material_ids_to_refresh {
            let cache_key = world_state
                .material_bind_group_cache_key
                .get(&material_id)
                .cloned()
                .unwrap();

            let (bind_group, found_textures) =
                Self::create_material_bind_group(device, material_id, &cache_key, &ctx);

            world_state
                .material_bind_groups
                .insert(material_id, bind_group);
            world_state
                .material_bind_group_found_textures
                .insert(material_id, found_textures);
        }
    }
}