119 lines
3.6 KiB
Rust
119 lines
3.6 KiB
Rust
use bevy::{
|
|
ecs::system::{lifetimeless::SRes, SystemParamItem},
|
|
prelude::*,
|
|
reflect::TypeUuid,
|
|
render::{
|
|
render_asset::{PrepareAssetError, RenderAsset},
|
|
render_resource::{
|
|
std140::{AsStd140, Std140},
|
|
*,
|
|
},
|
|
renderer::RenderDevice,
|
|
},
|
|
sprite::{Material2d, Material2dPipeline, Material2dPlugin, MaterialMesh2dBundle},
|
|
};
|
|
|
|
#[derive(Debug, Clone, TypeUuid, Component)]
|
|
#[uuid = "d29793f4-c24d-43f0-97c7-4d417a99188a"]
|
|
pub struct MandelbrotMaterial {
|
|
pub center: Vec2,
|
|
pub start: Vec2,
|
|
pub scale: f32,
|
|
pub aspect: f32,
|
|
pub iters: i32,
|
|
}
|
|
|
|
#[derive(Clone, Default, AsStd140)]
|
|
pub struct MandelbrotFSUniformData {
|
|
pub center: Vec2,
|
|
pub start: Vec2,
|
|
pub scale: f32,
|
|
pub aspect: f32,
|
|
pub iters: i32,
|
|
}
|
|
|
|
#[derive(Debug, Clone)]
|
|
pub struct GpuMandelbrotMaterial {
|
|
pub fs_buffer: Buffer,
|
|
pub bind_group: BindGroup,
|
|
}
|
|
|
|
impl RenderAsset for MandelbrotMaterial {
|
|
type ExtractedAsset = MandelbrotMaterial;
|
|
type PreparedAsset = GpuMandelbrotMaterial;
|
|
type Param = (
|
|
SRes<RenderDevice>,
|
|
SRes<Material2dPipeline<MandelbrotMaterial>>,
|
|
);
|
|
|
|
fn extract_asset(&self) -> Self::ExtractedAsset {
|
|
self.clone()
|
|
}
|
|
|
|
fn prepare_asset(
|
|
material: Self::ExtractedAsset,
|
|
(render_device, mandelbrot_pipeline): &mut SystemParamItem<Self::Param>,
|
|
) -> Result<Self::PreparedAsset, PrepareAssetError<Self::ExtractedAsset>> {
|
|
let fs_value = MandelbrotFSUniformData {
|
|
center: material.center,
|
|
start: material.start,
|
|
scale: material.scale,
|
|
aspect: material.aspect,
|
|
iters: material.iters,
|
|
};
|
|
let fs_value_std140 = fs_value.as_std140();
|
|
|
|
let fs_buffer = render_device.create_buffer_with_data(&BufferInitDescriptor {
|
|
label: Some("mandelbrot_material_uniform_fs_buffer"),
|
|
usage: BufferUsages::UNIFORM | BufferUsages::COPY_DST,
|
|
contents: fs_value_std140.as_bytes(),
|
|
});
|
|
|
|
let bind_group = render_device.create_bind_group(&BindGroupDescriptor {
|
|
entries: &[BindGroupEntry {
|
|
binding: 0,
|
|
resource: fs_buffer.as_entire_binding(),
|
|
}],
|
|
label: Some("mandelbrot_material_bind_group"),
|
|
layout: &mandelbrot_pipeline.material2d_layout,
|
|
});
|
|
|
|
Ok(GpuMandelbrotMaterial {
|
|
fs_buffer,
|
|
bind_group,
|
|
})
|
|
}
|
|
}
|
|
|
|
impl Material2d for MandelbrotMaterial {
|
|
fn fragment_shader(asset_server: &AssetServer) -> Option<Handle<Shader>> {
|
|
Some(asset_server.load("shaders/mandelbrot.wgsl"))
|
|
}
|
|
|
|
#[inline]
|
|
fn bind_group(render_asset: &<Self as RenderAsset>::PreparedAsset) -> &BindGroup {
|
|
&render_asset.bind_group
|
|
}
|
|
|
|
fn bind_group_layout(render_device: &RenderDevice) -> BindGroupLayout {
|
|
render_device.create_bind_group_layout(&BindGroupLayoutDescriptor {
|
|
entries: &[BindGroupLayoutEntry {
|
|
binding: 0,
|
|
visibility: ShaderStages::FRAGMENT,
|
|
ty: BindingType::Buffer {
|
|
ty: BufferBindingType::Uniform,
|
|
has_dynamic_offset: false,
|
|
min_binding_size: BufferSize::new(
|
|
MandelbrotFSUniformData::std140_size_static() as u64,
|
|
),
|
|
},
|
|
count: None,
|
|
}],
|
|
label: Some("mandelbrot_material_layout"),
|
|
})
|
|
}
|
|
}
|
|
|
|
pub type MandelbrotMesh2dBundle = MaterialMesh2dBundle<MandelbrotMaterial>;
|
|
pub type MandelbrotPlugin = Material2dPlugin<MandelbrotMaterial>;
|