diff --git a/crates/bevy_material/src/lib.rs b/crates/bevy_material/src/lib.rs index d1d54eb0e0..6ddf61b5f8 100644 --- a/crates/bevy_material/src/lib.rs +++ b/crates/bevy_material/src/lib.rs @@ -2,6 +2,8 @@ pub mod component; pub mod material; pub mod material_data; pub mod material_pipeline; +pub mod shaders; +pub mod specialize; pub mod prelude { pub use super::material::{Material, MaterialPlugin}; @@ -21,14 +23,4 @@ mod tests { pub struct TestPipeline; type TestMaterial = MaterialComponent; - - impl MaterialPipeline for TestPipeline { - type MaterialProperties = (); - type ShaderKey = (); - type PipelineContext<'a, M: Material> = (); - - fn material_plugin>() -> impl Plugin { - |_: &mut App| {} - } - } } diff --git a/crates/bevy_material/src/material.rs b/crates/bevy_material/src/material.rs index adc21cf48e..4fbf4ae0d1 100644 --- a/crates/bevy_material/src/material.rs +++ b/crates/bevy_material/src/material.rs @@ -3,24 +3,26 @@ use bevy_ecs::{ system::{lifetimeless::SRes, SystemParamItem}, world::{FromWorld, World}, }; -use bevy_utils::HashMap; use core::marker::PhantomData; use bevy_app::{App, Plugin}; -use bevy_asset::{Asset, AssetApp, AssetId, AssetPath, AssetServer, Handle}; +use bevy_asset::{Asset, AssetApp, AssetId, AssetServer}; use bevy_derive::{Deref, DerefMut}; use bevy_ecs::system::{Query, ResMut, Resource}; use bevy_render::{ render_asset::{PrepareAssetError, RenderAsset, RenderAssetPlugin}, - render_resource::{AsBindGroup, AsBindGroupError, BindGroupLayout, PreparedBindGroup, Shader}, + render_resource::{AsBindGroup, AsBindGroupError, BindGroupLayout, PreparedBindGroup}, renderer::RenderDevice, sync_world::{MainEntity, MainEntityHashMap}, view::ViewVisibility, Extract, ExtractSchedule, RenderApp, }; -use crate::component::MaterialComponent; use crate::material_pipeline::MaterialPipeline; +use crate::{ + component::MaterialComponent, + shaders::{LoadedShaders, Shaders}, +}; pub enum SpecializeMaterialError {} @@ -34,24 +36,6 @@ pub trait Material: BaseMaterial { fn specialize(ctx: P::PipelineContext<'_, Self>) -> Result<(), SpecializeMaterialError>; } -#[derive(Deref)] -pub struct Shaders { - shaders: HashMap>, -} - -impl>> FromIterator<(P::ShaderKey, A)> - for Shaders

-{ - fn from_iter>(iter: T) -> Self { - Self { - shaders: iter - .into_iter() - .map(|(key, path)| (key, path.into())) - .collect(), - } - } -} - pub struct MaterialPlugin, P: MaterialPipeline>(PhantomData); impl, P: MaterialPipeline> Default for MaterialPlugin { @@ -146,7 +130,7 @@ impl RenderAsset for MaterialBindGroup { pub struct MaterialProperties, R: MaterialPipeline> { #[deref] properties: R::MaterialProperties, - _data: PhantomData, + _data: PhantomData, } impl, R: MaterialPipeline> MaterialProperties { @@ -191,19 +175,18 @@ impl FromWorld for MaterialLayout { #[derive(Deref, Resource)] pub struct MaterialShaders, P: MaterialPipeline> { #[deref] - shaders: HashMap>, + shaders: LoadedShaders

, _data: PhantomData, } impl, P: MaterialPipeline> FromWorld for MaterialShaders { fn from_world(world: &mut World) -> Self { let asset_server = world.resource::(); + let mut shaders = P::default_shaders(); + shaders.extend(M::shaders()); + Self { - shaders: M::shaders() - .shaders - .into_iter() - .map(|(key, path)| (key, asset_server.load(path))) - .collect(), + shaders: shaders.load(asset_server), _data: PhantomData, } } diff --git a/crates/bevy_material/src/material_data.rs b/crates/bevy_material/src/material_data.rs index e123670ab8..68cc3c1fbc 100644 --- a/crates/bevy_material/src/material_data.rs +++ b/crates/bevy_material/src/material_data.rs @@ -23,14 +23,10 @@ pub struct MaterialData<'w, M: Material

, P: MaterialPipeline> { } impl<'w, M: Material

, P: MaterialPipeline> MaterialData<'w, M, P> { - pub fn get( - &self, - main_entity: MainEntity, - id: AssetId, - ) -> Option> { + pub fn get(&self, main_entity: MainEntity, id: AssetId) -> Option> { let bind_group = self.bind_groups.get(id)?; let properties = self.properties.get(id)?; - Some(PreparedMaterialInstance { + Some(MaterialInstance { main_entity, layout: &self.layout, shaders: &self.shaders, @@ -42,14 +38,14 @@ impl<'w, M: Material

, P: MaterialPipeline> MaterialData<'w, M, P> { pub fn iter<'a>( &'a self, instances: &'a MaterialInstances, - ) -> impl Iterator> + 'a { + ) -> impl Iterator> { instances .iter() .filter_map(|(main_entity, material_id)| self.get(*main_entity, *material_id)) } } -pub struct PreparedMaterialInstance<'a, M: Material

, P: MaterialPipeline> { +pub struct MaterialInstance<'a, M: Material

, P: MaterialPipeline> { pub main_entity: MainEntity, pub properties: &'a P::MaterialProperties, pub shaders: &'a MaterialShaders, diff --git a/crates/bevy_material/src/material_pipeline.rs b/crates/bevy_material/src/material_pipeline.rs index e69a0cc524..0bea4e63e4 100644 --- a/crates/bevy_material/src/material_pipeline.rs +++ b/crates/bevy_material/src/material_pipeline.rs @@ -1,13 +1,16 @@ use bevy_app::Plugin; +use bevy_ecs::system::{ReadOnlySystemParam, SystemParamItem}; use bevy_reflect::TypePath; use core::hash::Hash; -use crate::material::Material; +use crate::{material::Material, shaders::Shaders}; pub trait MaterialPipeline: TypePath + Sized + 'static { - type MaterialProperties: Send + Sync + 'static; - type ShaderKey: Hash + Eq + Send + Sync + 'static; + type MaterialProperties: Send + Sync; + type ShaderKey: Hash + Eq + Send + Sync; type PipelineContext<'a, M: Material>; + fn default_shaders() -> Shaders; + fn material_plugin>() -> impl Plugin; } diff --git a/crates/bevy_material/src/shaders.rs b/crates/bevy_material/src/shaders.rs new file mode 100644 index 0000000000..0b9759bdff --- /dev/null +++ b/crates/bevy_material/src/shaders.rs @@ -0,0 +1,75 @@ +use bevy_asset::{AssetPath, AssetServer, Handle}; +use bevy_derive::{Deref, DerefMut}; +use bevy_render::render_resource::Shader; +use bevy_utils::HashMap; + +use crate::material_pipeline::MaterialPipeline; + +#[derive(Deref, DerefMut, Clone)] +pub struct Shaders { + shaders: HashMap>, +} + +impl Default for Shaders

{ + fn default() -> Self { + Self { + shaders: Default::default(), + } + } +} + +impl>> FromIterator<(P::ShaderKey, A)> + for Shaders

+{ + fn from_iter>(iter: T) -> Self { + Self { + shaders: iter + .into_iter() + .map(|(key, path)| (key, path.into())) + .collect(), + } + } +} + +impl Shaders

{ + pub fn new(iter: impl IntoIterator)>) -> Self { + Self::from_iter(iter) + } + + pub fn extend(&mut self, other: Shaders

) { + self.shaders.extend(other.shaders.into_iter()); + } + + pub fn load(self, asset_server: &AssetServer) -> LoadedShaders

{ + self.shaders + .into_iter() + .map(|(key, path)| (key, asset_server.load(path))) + .collect() + } +} + +#[derive(Deref)] +pub struct LoadedShaders { + shaders: HashMap>, +} + +impl FromIterator<(P::ShaderKey, Handle)> for LoadedShaders

{ + fn from_iter)>>(iter: T) -> Self { + Self { + shaders: iter + .into_iter() + .map(|(key, path)| (key, path.into())) + .collect(), + } + } +} + +impl LoadedShaders

{ + pub fn new(iter: impl IntoIterator)>) -> Self { + Self::from_iter(iter) + } + + pub fn extend(&mut self, other: LoadedShaders

) { + self.shaders.extend(other.shaders.into_iter()); + } +} diff --git a/crates/bevy_material/src/specialize.rs b/crates/bevy_material/src/specialize.rs new file mode 100644 index 0000000000..a38a80edbd --- /dev/null +++ b/crates/bevy_material/src/specialize.rs @@ -0,0 +1,21 @@ +use bevy_ecs::system::ReadOnlySystemParam; +use bevy_utils::HashMap; +use core::{hash::Hash, marker::PhantomData}; + +use crate::{material::Material, material_pipeline::MaterialPipeline}; + +pub trait Specialize { + type Key: Clone + Hash + Eq + Send + Sync; + type Item: Send + Sync; +} + +pub type SpecializeMaterialContext<'a, M, P> = + <

::Specializer as SpecializeMaterial>::Context<'a>; + +pub struct Specializer { + items: HashMap, +} + +impl Specializer {} + +pub struct SpecializedMaterial, P: MaterialPipeline>(PhantomData);