use std::sync::{Arc, Mutex};
use bevy::{
asset::uuid_handle,
camera::visibility::RenderLayers,
mesh::{MeshVertexBufferLayoutRef, VertexBufferLayout},
prelude::*,
render::{
extract_component::ExtractComponent,
render_resource::{
AsBindGroup, RenderPipelineDescriptor, SpecializedMeshPipelineError, VertexFormat,
VertexStepMode,
},
renderer::RenderDevice,
},
shader::ShaderRef,
sprite_render::{Material2d, Material2dKey},
};
use vello::{AaConfig, AaSupport, kurbo::Affine};
mod plugin;
mod systems;
pub(crate) mod extract;
pub(crate) mod prepare;
pub(crate) use plugin::VelloRenderPlugin;
pub mod diagnostics;
pub const RT_SHADER_HANDLE: Handle<Shader> = uuid_handle!("e7235b72-1181-4e18-a9f2-93b32026a820");
#[derive(Component, Debug, Clone, Copy, ExtractComponent)]
#[require(Camera2d)]
pub struct VelloView;
#[derive(AsBindGroup, TypePath, Asset, Clone)]
pub struct VelloCanvasMaterial {
#[texture(0)]
#[sampler(1)]
pub texture: Handle<Image>,
}
impl Material2d for VelloCanvasMaterial {
fn vertex_shader() -> ShaderRef {
RT_SHADER_HANDLE.into()
}
fn fragment_shader() -> ShaderRef {
RT_SHADER_HANDLE.into()
}
fn specialize(
descriptor: &mut RenderPipelineDescriptor,
_layout: &MeshVertexBufferLayoutRef,
_key: Material2dKey<Self>,
) -> Result<(), SpecializedMeshPipelineError> {
if let Some(target) = descriptor.fragment.as_mut() {
let mut_targets = &mut target.targets;
if let Some(Some(target)) = mut_targets.get_mut(0) {
target.blend = Some(vello::wgpu::BlendState::ALPHA_BLENDING);
}
}
let formats = vec![
VertexFormat::Float32x3,
VertexFormat::Float32x2,
];
let vertex_layout =
VertexBufferLayout::from_vertex_formats(VertexStepMode::Vertex, formats);
descriptor.vertex.buffers = vec![vertex_layout];
Ok(())
}
}
#[derive(Resource, Deref, DerefMut)]
pub struct VelloRenderer(Arc<Mutex<vello::Renderer>>);
impl VelloRenderer {
pub fn try_new(
device: &vello::wgpu::Device,
settings: &VelloRenderSettings,
) -> Result<Self, vello::Error> {
vello::Renderer::new(
device,
vello::RendererOptions {
use_cpu: settings.use_cpu,
antialiasing_support: AaSupport::all(),
num_init_threads: None,
pipeline_cache: None,
},
)
.map(Mutex::new)
.map(Arc::new)
.map(VelloRenderer)
}
}
impl FromWorld for VelloRenderer {
fn from_world(world: &mut World) -> Self {
match VelloRenderer::try_new(
world.get_resource::<RenderDevice>().unwrap().wgpu_device(),
world.get_resource::<VelloRenderSettings>().unwrap(),
) {
Ok(r) => r,
Err(e) => {
tracing::error!(
"Attempting safe-mode fallback, failed to initialize renderer: {e:}"
);
{
let mut settings = world.get_resource_mut::<VelloRenderSettings>().unwrap();
settings.use_cpu = true;
settings.antialiasing = AaConfig::Area;
}
match VelloRenderer::try_new(
world.get_resource::<RenderDevice>().unwrap().wgpu_device(),
world.get_resource::<VelloRenderSettings>().unwrap(),
) {
Ok(r) => r,
Err(e) => panic!("Failed to start vello: {e}"),
}
}
}
}
}
#[derive(Resource, Deref, DerefMut, Default)]
#[cfg(feature = "lottie")]
pub struct VelatoRenderer(velato::Renderer);
#[derive(Resource, Clone)]
pub struct VelloRenderSettings {
pub use_cpu: bool,
pub antialiasing: AaConfig,
}
impl Default for VelloRenderSettings {
fn default() -> Self {
Self {
use_cpu: false,
antialiasing: AaConfig::Area,
}
}
}
#[derive(Resource, Clone, Debug, Default, PartialEq)]
pub(crate) struct VelloCanvasSettings {
pub render_layers: RenderLayers,
}
#[derive(Clone)]
#[allow(clippy::large_enum_variant, reason = "Many feature gates")]
pub(crate) enum VelloWorldRenderItem {
Scene {
affine: Affine,
item: crate::integrations::scene::render::ExtractedVelloScene2d,
},
#[cfg(feature = "svg")]
Svg {
affine: Affine,
item: crate::integrations::svg::render::ExtractedVelloSvg2d,
},
#[cfg(feature = "lottie")]
Lottie {
affine: Affine,
item: crate::integrations::lottie::render::ExtractedVelloLottie2d,
},
#[cfg(feature = "text")]
Text {
affine: Affine,
item: crate::integrations::text::render::ExtractedVelloText2d,
},
}
#[derive(Clone)]
#[allow(clippy::large_enum_variant, reason = "Many feature gates")]
pub(crate) enum VelloUiRenderItem {
Scene {
affine: Affine,
item: crate::integrations::scene::render::ExtractedUiVelloScene,
},
#[cfg(feature = "svg")]
Svg {
affine: Affine,
item: crate::integrations::svg::render::ExtractedUiVelloSvg,
},
#[cfg(feature = "lottie")]
Lottie {
affine: Affine,
item: crate::integrations::lottie::render::ExtractedUiVelloLottie,
},
#[cfg(feature = "text")]
Text {
affine: Affine,
item: crate::integrations::text::render::ExtractedUiVelloText,
},
}
#[derive(Resource, Default)]
pub(crate) struct VelloRenderQueue {
world: Vec<VelloWorldRenderItem>,
ui: Vec<VelloUiRenderItem>,
}
#[derive(Resource, Default, Debug, Clone, Reflect)]
pub(crate) struct VelloEntityCountData {
pub n_world_scenes: u32,
pub n_ui_scenes: u32,
#[cfg(feature = "text")]
pub n_world_texts: u32,
#[cfg(feature = "text")]
pub n_ui_texts: u32,
#[cfg(feature = "svg")]
pub n_world_svgs: u32,
#[cfg(feature = "svg")]
pub n_ui_svgs: u32,
#[cfg(feature = "lottie")]
pub n_world_lotties: u32,
#[cfg(feature = "lottie")]
pub n_ui_lotties: u32,
}
#[derive(Resource, Default, Debug, Clone, Reflect)]
pub(crate) struct VelloFrameProfileData {
pub n_paths: u32,
pub n_path_segs: u32,
pub n_clips: u32,
pub n_open_clips: u32,
}