use bevy::app::App;
use bevy::asset::{Asset, Handle};
use bevy::color::LinearRgba;
use bevy::image::Image;
use bevy::material::AlphaMode;
use bevy::math::Vec4;
use bevy::mesh::MeshVertexBufferLayoutRef;
use bevy::pbr::{Material, MaterialPipeline, MaterialPipelineKey};
use bevy::reflect::TypePath;
use bevy::render::render_resource::{
AsBindGroup, RenderPipelineDescriptor, SpecializedMeshPipelineError,
};
use bevy::shader::ShaderRef;
use bevy::render::storage::ShaderBuffer;
use crate::params::RenderStyle;
use crate::shading::{FloraUniform, FloraWindBuffer};
#[derive(Asset, AsBindGroup, TypePath, Debug, Clone)]
#[bind_group_data(ImpostorKey)]
pub struct ImpostorMaterial {
#[texture(0)]
#[sampler(1)]
pub albedo: Handle<Image>,
#[texture(2)]
pub surface: Handle<Image>,
#[uniform(3)]
pub params: Vec4,
#[uniform(101)]
pub flora: FloraUniform,
#[storage(102, read_only)]
pub wind: Handle<ShaderBuffer>,
pub see_through: bool,
pub fire: bool,
}
impl ImpostorMaterial {
pub fn new(
albedo: Handle<Image>,
surface: Handle<Image>,
views: u32,
style: RenderStyle,
flora: FloraUniform,
wind: &FloraWindBuffer,
) -> Self {
Self {
albedo,
surface,
params: Vec4::new(views as f32, style as u32 as f32, 0.0, 0.0),
flora,
wind: wind.0.clone(),
see_through: false,
fire: false,
}
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub struct ImpostorKey {
pub see_through: bool,
pub fire: bool,
}
impl From<&ImpostorMaterial> for ImpostorKey {
fn from(material: &ImpostorMaterial) -> Self {
Self { see_through: material.see_through, fire: material.fire }
}
}
impl Material for ImpostorMaterial {
fn vertex_shader() -> ShaderRef {
"embedded://bevy_flora/impostor/impostor.wesl".into()
}
fn fragment_shader() -> ShaderRef {
"embedded://bevy_flora/impostor/impostor.wesl".into()
}
fn alpha_mode(&self) -> AlphaMode {
AlphaMode::AlphaToCoverage
}
fn enable_prepass() -> bool {
false
}
fn enable_shadows() -> bool {
false
}
fn specialize(
_pipeline: &MaterialPipeline,
descriptor: &mut RenderPipelineDescriptor,
_layout: &MeshVertexBufferLayoutRef,
key: MaterialPipelineKey<Self>,
) -> Result<(), SpecializedMeshPipelineError> {
descriptor.primitive.cull_mode = None;
let defs = [(key.bind_group_data.see_through, "FLORA_SEE_THROUGH"), (key.bind_group_data.fire, "FLORA_FIRE")];
for (on, def) in defs {
if on && let Some(fragment) = descriptor.fragment.as_mut() {
fragment.shader_defs.push(def.into());
}
}
Ok(())
}
}
#[derive(Asset, AsBindGroup, TypePath, Debug, Clone)]
pub(crate) struct ImpostorBakeMaterial {
#[uniform(0)]
pub color: LinearRgba,
#[uniform(1)]
pub params: Vec4,
}
impl ImpostorBakeMaterial {
pub(crate) fn colour(color: LinearRgba) -> Self {
Self { color, params: Vec4::new(0.0, 0.0, 1.0, 0.0) }
}
pub(crate) fn surface(color: LinearRgba, translucency: f32) -> Self {
Self { color, params: Vec4::new(1.0, translucency, 1.0, 0.0) }
}
}
impl Material for ImpostorBakeMaterial {
fn vertex_shader() -> ShaderRef {
"embedded://bevy_flora/impostor/impostor_bake.wesl".into()
}
fn fragment_shader() -> ShaderRef {
"embedded://bevy_flora/impostor/impostor_bake.wesl".into()
}
fn enable_prepass() -> bool {
false
}
fn enable_shadows() -> bool {
false
}
}
pub(crate) fn add_shaders(app: &mut App) {
bevy::asset::embedded_asset!(app, "impostor.wesl");
bevy::asset::embedded_asset!(app, "impostor_bake.wesl");
}