use std::collections::HashSet;
use awsm_renderer_core::renderer::AwsmRendererWebGpu;
use strum::{EnumIter, IntoEnumIterator};
use thiserror::Error;
use crate::{
anti_alias::AntiAliasing, bind_group_layout::BindGroupLayouts, camera::CameraBuffer,
environment::Environment, lights::Lights, materials::Materials, meshes::Meshes, picker::Picker,
render_passes::RenderPasses, render_textures::RenderTextureViews, textures::Textures,
transforms::Transforms,
};
pub struct BindGroupRecreateContext<'a> {
pub gpu: &'a AwsmRendererWebGpu,
pub render_texture_views: &'a RenderTextureViews,
pub textures: &'a Textures,
pub materials: &'a Materials,
pub bind_group_layouts: &'a BindGroupLayouts,
pub meshes: &'a Meshes,
pub camera: &'a CameraBuffer,
pub environment: &'a Environment,
pub lights: &'a Lights,
pub transforms: &'a Transforms,
pub anti_aliasing: &'a AntiAliasing,
}
#[derive(Hash, Debug, Clone, PartialEq, Eq, EnumIter)]
pub enum BindGroupCreate {
CameraInitOnly,
LightsResize,
LightsInfoCreate,
BrdfLutTextures,
IblTextures,
EnvironmentSkyboxCreate,
TransformsResize,
TransformNormalsResize,
GeometryMorphTargetWeightsResize,
GeometryMorphTargetValuesResize,
MaterialMorphTargetWeightsResize,
MaterialMorphTargetValuesResize,
SkinJointMatricesResize,
SkinJointIndexAndWeightsResize,
GeometryMeshMetaResize,
MaterialMeshMetaResize,
MeshAttributeDataResize,
MeshAttributeIndexResize,
MaterialResize,
TextureViewRecreate,
TexturePool,
TextureTransformsResize,
AntiAliasingChange,
}
pub struct BindGroups {
create_list: HashSet<BindGroupCreate>,
}
impl Default for BindGroups {
fn default() -> Self {
Self::new()
}
}
impl BindGroups {
pub fn new() -> Self {
Self {
create_list: BindGroupCreate::iter().collect::<HashSet<_>>(),
}
}
pub fn mark_create(&mut self, create: BindGroupCreate) {
self.create_list.insert(create);
}
pub fn recreate(
&mut self,
ctx: BindGroupRecreateContext<'_>,
render_passes: &mut RenderPasses,
picker: &mut Picker,
) -> crate::error::Result<()> {
if self.create_list.is_empty() {
return Ok(());
}
#[derive(Hash, Debug, Clone, Copy, PartialEq, Eq)]
enum FunctionToCall {
GeometryCamera,
GeometryTransformMaterials,
GeometryMeta,
GeometryAnimation,
OpaqueMain,
OpaqueLights,
OpaqueTextures,
TransparentMain,
TransparentMeshMaterial,
TransparentLights,
TransparentTextures,
LightCulling,
Effects,
Display,
Picker,
}
let mut functions_to_call = HashSet::new();
for create in self.create_list.drain() {
match create {
BindGroupCreate::CameraInitOnly => {
functions_to_call.insert(FunctionToCall::GeometryCamera);
functions_to_call.insert(FunctionToCall::TransparentMain);
}
BindGroupCreate::LightsInfoCreate => {
functions_to_call.insert(FunctionToCall::OpaqueLights);
functions_to_call.insert(FunctionToCall::TransparentLights);
}
BindGroupCreate::LightsResize => {
functions_to_call.insert(FunctionToCall::OpaqueLights);
functions_to_call.insert(FunctionToCall::TransparentLights);
}
BindGroupCreate::TransformsResize => {
functions_to_call.insert(FunctionToCall::GeometryTransformMaterials);
functions_to_call.insert(FunctionToCall::TransparentMain);
functions_to_call.insert(FunctionToCall::TransparentMeshMaterial);
}
BindGroupCreate::MaterialResize => {
functions_to_call.insert(FunctionToCall::GeometryTransformMaterials);
functions_to_call.insert(FunctionToCall::OpaqueMain);
functions_to_call.insert(FunctionToCall::TransparentMeshMaterial);
}
BindGroupCreate::GeometryMeshMetaResize => {
functions_to_call.insert(FunctionToCall::GeometryMeta);
functions_to_call.insert(FunctionToCall::TransparentMeshMaterial);
}
BindGroupCreate::GeometryMorphTargetWeightsResize
| BindGroupCreate::GeometryMorphTargetValuesResize
| BindGroupCreate::SkinJointMatricesResize
| BindGroupCreate::SkinJointIndexAndWeightsResize => {
functions_to_call.insert(FunctionToCall::GeometryAnimation);
functions_to_call.insert(FunctionToCall::TransparentMain);
}
BindGroupCreate::TextureViewRecreate => {
functions_to_call.insert(FunctionToCall::LightCulling);
functions_to_call.insert(FunctionToCall::Display);
functions_to_call.insert(FunctionToCall::Effects);
functions_to_call.insert(FunctionToCall::OpaqueMain);
functions_to_call.insert(FunctionToCall::TransparentMain);
functions_to_call.insert(FunctionToCall::Picker);
}
BindGroupCreate::TexturePool => {
functions_to_call.insert(FunctionToCall::OpaqueTextures);
functions_to_call.insert(FunctionToCall::TransparentTextures);
}
BindGroupCreate::TextureTransformsResize => {
functions_to_call.insert(FunctionToCall::OpaqueTextures);
functions_to_call.insert(FunctionToCall::TransparentTextures);
}
BindGroupCreate::BrdfLutTextures => {
functions_to_call.insert(FunctionToCall::OpaqueMain);
functions_to_call.insert(FunctionToCall::TransparentLights);
}
BindGroupCreate::IblTextures => {
functions_to_call.insert(FunctionToCall::OpaqueMain);
functions_to_call.insert(FunctionToCall::TransparentLights);
}
BindGroupCreate::EnvironmentSkyboxCreate => {
functions_to_call.insert(FunctionToCall::OpaqueMain);
functions_to_call.insert(FunctionToCall::TransparentLights);
}
BindGroupCreate::TransformNormalsResize => {
functions_to_call.insert(FunctionToCall::OpaqueMain);
functions_to_call.insert(FunctionToCall::TransparentMain);
}
BindGroupCreate::MaterialMorphTargetWeightsResize => {
functions_to_call.insert(FunctionToCall::OpaqueMain);
functions_to_call.insert(FunctionToCall::TransparentMain);
}
BindGroupCreate::MaterialMorphTargetValuesResize => {
functions_to_call.insert(FunctionToCall::OpaqueMain);
functions_to_call.insert(FunctionToCall::TransparentMain);
}
BindGroupCreate::MaterialMeshMetaResize => {
functions_to_call.insert(FunctionToCall::OpaqueMain);
functions_to_call.insert(FunctionToCall::TransparentMain);
functions_to_call.insert(FunctionToCall::Picker);
}
BindGroupCreate::MeshAttributeDataResize => {
functions_to_call.insert(FunctionToCall::OpaqueMain);
functions_to_call.insert(FunctionToCall::TransparentMain);
}
BindGroupCreate::MeshAttributeIndexResize => {
functions_to_call.insert(FunctionToCall::OpaqueMain);
functions_to_call.insert(FunctionToCall::TransparentMain);
}
BindGroupCreate::AntiAliasingChange => {
functions_to_call.insert(FunctionToCall::OpaqueMain);
functions_to_call.insert(FunctionToCall::TransparentMain);
}
}
}
for f in functions_to_call {
match f {
FunctionToCall::GeometryCamera => {
render_passes.geometry.bind_groups.camera.recreate(&ctx)?;
}
FunctionToCall::GeometryTransformMaterials => {
render_passes
.geometry
.bind_groups
.transforms
.recreate(&ctx)?;
}
FunctionToCall::GeometryMeta => {
render_passes.geometry.bind_groups.meta.recreate(&ctx)?;
}
FunctionToCall::GeometryAnimation => {
render_passes
.geometry
.bind_groups
.animation
.recreate(&ctx)?;
}
FunctionToCall::OpaqueMain => {
render_passes
.material_opaque
.bind_groups
.recreate_main(&ctx)?;
}
FunctionToCall::OpaqueLights => {
render_passes
.material_opaque
.bind_groups
.recreate_lights(&ctx)?;
}
FunctionToCall::OpaqueTextures => {
render_passes
.material_opaque
.bind_groups
.recreate_texture_pool(&ctx)?;
}
FunctionToCall::TransparentMain => {
render_passes
.material_transparent
.bind_groups
.recreate_main(&ctx)?;
}
FunctionToCall::TransparentMeshMaterial => {
render_passes
.material_transparent
.bind_groups
.recreate_mesh_material(&ctx)?;
}
FunctionToCall::TransparentLights => {
render_passes
.material_transparent
.bind_groups
.recreate_lights(&ctx)?;
}
FunctionToCall::TransparentTextures => {
render_passes
.material_transparent
.bind_groups
.recreate_texture_pool(&ctx)?;
}
FunctionToCall::LightCulling => {
render_passes.light_culling.bind_groups.recreate(&ctx)?;
}
FunctionToCall::Effects => {
render_passes.effects.bind_groups.recreate(&ctx)?;
}
FunctionToCall::Display => {
render_passes.display.bind_groups.recreate(&ctx)?;
}
FunctionToCall::Picker => {
picker.recreate_bind_group(&ctx)?;
}
}
}
Ok(())
}
}
#[derive(Error, Debug)]
pub enum AwsmBindGroupError {
#[error("[bind group] bind group not found for {0}")]
NotFound(String),
}