├── assets ├── readme │ ├── twinkle.png │ ├── two_colors.png │ └── complex_one_color.png ├── fonts │ ├── FiraSans-Bold.ttf │ └── FiraMono-Medium.ttf ├── box.svg ├── neutron_star.svg └── twinkle.svg ├── src ├── resources.rs ├── render │ ├── mod.rs │ ├── svg3d │ │ ├── svg_3d.wgsl │ │ ├── mod.rs │ │ └── plugin.rs │ ├── svg2d │ │ ├── svg_2d.wgsl │ │ ├── plugin.rs │ │ └── mod.rs │ ├── plugin.rs │ ├── tessellation.rs │ └── vertex_buffer.rs ├── util.rs ├── lib.rs ├── loader.rs ├── origin.rs ├── plugin.rs └── svg.rs ├── examples ├── 2d │ ├── twinkle.rs │ ├── two_colors.rs │ ├── origin_check.rs │ ├── complex_one_color.rs │ ├── preloading.rs │ └── multiple_translation.rs ├── 3d │ ├── two_colors.rs │ ├── complex_one_color.rs │ ├── twinkle.rs │ ├── origin_check.rs │ ├── multiple_perspective.rs │ └── multiple_translation.rs └── common │ └── lib.rs ├── .gitignore ├── LICENSE-MIT ├── Cargo.toml ├── CHANGELOG.md ├── README.md └── LICENSE-APACHE /assets/readme/twinkle.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Weasy666/bevy_svg/HEAD/assets/readme/twinkle.png -------------------------------------------------------------------------------- /assets/fonts/FiraSans-Bold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Weasy666/bevy_svg/HEAD/assets/fonts/FiraSans-Bold.ttf -------------------------------------------------------------------------------- /assets/readme/two_colors.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Weasy666/bevy_svg/HEAD/assets/readme/two_colors.png -------------------------------------------------------------------------------- /assets/fonts/FiraMono-Medium.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Weasy666/bevy_svg/HEAD/assets/fonts/FiraMono-Medium.ttf -------------------------------------------------------------------------------- /assets/readme/complex_one_color.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Weasy666/bevy_svg/HEAD/assets/readme/complex_one_color.png -------------------------------------------------------------------------------- /src/resources.rs: -------------------------------------------------------------------------------- 1 | use bevy::prelude::{Deref, DerefMut, Resource}; 2 | 3 | #[derive(Resource, Deref, DerefMut, Default)] 4 | pub struct FillTessellator(lyon_tessellation::FillTessellator); 5 | 6 | #[derive(Resource, Deref, DerefMut, Default)] 7 | pub struct StrokeTessellator(lyon_tessellation::StrokeTessellator); 8 | -------------------------------------------------------------------------------- /src/render/mod.rs: -------------------------------------------------------------------------------- 1 | mod plugin; 2 | pub mod tessellation; 3 | mod vertex_buffer; 4 | 5 | #[cfg(feature = "2d")] 6 | mod svg2d; 7 | #[cfg(feature = "3d")] 8 | mod svg3d; 9 | 10 | #[cfg(feature = "2d")] 11 | pub use svg2d::Svg2d; 12 | #[cfg(feature = "3d")] 13 | pub use svg3d::Svg3d; 14 | 15 | pub use plugin::SvgPlugin; 16 | -------------------------------------------------------------------------------- /src/render/svg3d/svg_3d.wgsl: -------------------------------------------------------------------------------- 1 | #import bevy_pbr::{ 2 | forward_io::{VertexOutput, FragmentOutput} 3 | mesh_types::Mesh, 4 | mesh_view_bindings, 5 | } 6 | 7 | @group(2) @binding(0) 8 | var mesh: Mesh; 9 | 10 | @fragment 11 | fn fragment( 12 | in: VertexOutput, 13 | @builtin(front_facing) is_front: bool, 14 | ) -> FragmentOutput { 15 | var out: FragmentOutput; 16 | out.color = in.color; 17 | return out; 18 | } 19 | -------------------------------------------------------------------------------- /assets/box.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /src/render/svg2d/svg_2d.wgsl: -------------------------------------------------------------------------------- 1 | #import bevy_sprite::{ 2 | mesh2d_types::Mesh2d, 3 | mesh2d_view_bindings::view, 4 | mesh2d_vertex_output::VertexOutput, 5 | } 6 | 7 | #ifdef TONEMAP_IN_SHADER 8 | #import bevy_core_pipeline::tonemapping 9 | #endif 10 | 11 | 12 | @group(2) @binding(0) 13 | var mesh: Mesh2d; 14 | 15 | @fragment 16 | fn fragment(in: VertexOutput) -> @location(0) vec4 { 17 | #ifdef VERTEX_COLORS 18 | var color = in.color; 19 | #ifdef TONEMAP_IN_SHADER 20 | color = tonemapping::tone_mapping(color, view.color_grading); 21 | #endif 22 | return color; 23 | #else 24 | return vec4(1.0, 0.0, 1.0, 1.0); 25 | #endif 26 | } 27 | -------------------------------------------------------------------------------- /src/render/plugin.rs: -------------------------------------------------------------------------------- 1 | use crate::resources::{FillTessellator, StrokeTessellator}; 2 | use bevy::app::{App, Plugin}; 3 | 4 | #[cfg(feature = "2d")] 5 | use crate::render::svg2d; 6 | #[cfg(feature = "3d")] 7 | use crate::render::svg3d; 8 | 9 | /// Plugin that renders [`Svg`](crate::svg::Svg)s in 2D 10 | pub struct SvgPlugin; 11 | 12 | impl Plugin for SvgPlugin { 13 | fn build(&self, app: &mut App) { 14 | let fill_tess = FillTessellator::default(); 15 | let stroke_tess = StrokeTessellator::default(); 16 | app.insert_resource(fill_tess).insert_resource(stroke_tess); 17 | 18 | #[cfg(feature = "2d")] 19 | app.add_plugins(svg2d::RenderPlugin); 20 | 21 | #[cfg(feature = "3d")] 22 | app.add_plugins(svg3d::RenderPlugin); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/render/svg2d/plugin.rs: -------------------------------------------------------------------------------- 1 | use crate::{render::svg2d::SVG_2D_SHADER_HANDLE, svg::Svg}; 2 | use bevy::{ 3 | app::{App, Plugin}, 4 | asset::{AssetApp, load_internal_asset}, 5 | shader::{Shader, ShaderRef}, 6 | sprite_render::{Material2d, Material2dPlugin}, 7 | }; 8 | 9 | /// Plugin that renders [`Svg`](crate::svg::Svg)s in 2D 10 | pub struct RenderPlugin; 11 | 12 | impl Plugin for RenderPlugin { 13 | fn build(&self, app: &mut App) { 14 | load_internal_asset!(app, SVG_2D_SHADER_HANDLE, "svg_2d.wgsl", Shader::from_wgsl); 15 | 16 | app.add_plugins(Material2dPlugin::::default()) 17 | .register_asset_reflect::(); 18 | } 19 | } 20 | 21 | impl Material2d for Svg { 22 | fn fragment_shader() -> ShaderRef { 23 | SVG_2D_SHADER_HANDLE.into() 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /examples/2d/twinkle.rs: -------------------------------------------------------------------------------- 1 | use bevy::prelude::*; 2 | use bevy_svg::prelude::*; 3 | 4 | #[path = "../common/lib.rs"] 5 | mod common; 6 | 7 | fn main() { 8 | App::new() 9 | .add_plugins(DefaultPlugins.set(WindowPlugin { 10 | primary_window: Some(Window { 11 | title: "2d_twinkle".to_string(), 12 | resolution: (600, 600).into(), 13 | ..Default::default() 14 | }), 15 | ..Default::default() 16 | })) 17 | .add_plugins((common::CommonPlugin, bevy_svg::prelude::SvgPlugin)) 18 | .add_systems(Startup, setup) 19 | .run(); 20 | } 21 | 22 | fn setup(mut commands: Commands, asset_server: Res) { 23 | let svg = asset_server.load("twinkle.svg"); 24 | commands.spawn(Camera2d); 25 | commands.spawn((Svg2d(svg), Origin::Center)); 26 | } 27 | -------------------------------------------------------------------------------- /examples/2d/two_colors.rs: -------------------------------------------------------------------------------- 1 | use bevy::prelude::*; 2 | use bevy_svg::prelude::*; 3 | 4 | #[path = "../common/lib.rs"] 5 | mod common; 6 | 7 | fn main() { 8 | App::new() 9 | .add_plugins(DefaultPlugins.set(WindowPlugin { 10 | primary_window: Some(Window { 11 | title: "2d_two_colors".to_string(), 12 | resolution: (600, 600).into(), 13 | ..Default::default() 14 | }), 15 | ..Default::default() 16 | })) 17 | .add_plugins((common::CommonPlugin, bevy_svg::prelude::SvgPlugin)) 18 | .add_systems(Startup, setup) 19 | .run(); 20 | } 21 | 22 | fn setup(mut commands: Commands, asset_server: Res) { 23 | let svg = asset_server.load("neutron_star.svg"); 24 | commands.spawn(Camera2d); 25 | commands.spawn((Svg2d(svg), Origin::Center)); 26 | } 27 | -------------------------------------------------------------------------------- /examples/2d/origin_check.rs: -------------------------------------------------------------------------------- 1 | use bevy::prelude::*; 2 | use bevy_svg::prelude::*; 3 | 4 | #[path = "../common/lib.rs"] 5 | mod common; 6 | 7 | fn main() { 8 | App::new() 9 | .add_plugins(DefaultPlugins.set(WindowPlugin { 10 | primary_window: Some(Window { 11 | title: "origin_check".to_string(), 12 | resolution: (600, 600).into(), 13 | ..Default::default() 14 | }), 15 | ..Default::default() 16 | })) 17 | .add_plugins((common::CommonPlugin, bevy_svg::prelude::SvgPlugin)) 18 | .add_systems(Startup, setup) 19 | .run(); 20 | } 21 | 22 | fn setup(mut commands: Commands, asset_server: Res) { 23 | let svg = asset_server.load("box.svg"); 24 | commands.spawn(Camera2d); 25 | commands.spawn((Svg2d(svg.clone()), Origin::Center)); 26 | commands.spawn((Svg2d(svg), Origin::TopLeft, common::DontChange)); 27 | } 28 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Created by https://www.toptal.com/developers/gitignore/api/vscode,rust,dotenv 2 | # Edit at https://www.toptal.com/developers/gitignore?templates=vscode,rust,dotenv 3 | 4 | ### dotenv ### 5 | # This normally contains sensitive information, like DB passwords, so we don't want 6 | # this commited in a source code repository. 7 | .env 8 | 9 | ### Rust ### 10 | # Generated by Cargo 11 | # will have compiled files and executables 12 | /target/ 13 | 14 | # Remove Cargo.lock from gitignore if creating an executable, leave it inside for libraries 15 | # More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html 16 | Cargo.lock 17 | 18 | ### vscode ### 19 | .vscode/* 20 | !.vscode/settings.json 21 | !.vscode/tasks.json 22 | !.vscode/launch.json 23 | !.vscode/extensions.json 24 | *.code-workspace 25 | 26 | ### Bevy ### 27 | wgpu_trace 28 | 29 | # End of https://www.toptal.com/developers/gitignore/api/vscode,rust,dotenv 30 | -------------------------------------------------------------------------------- /src/util.rs: -------------------------------------------------------------------------------- 1 | pub mod paint { 2 | use bevy::color::{Color, ColorToComponents, Srgba}; 3 | use usvg::BaseGradient; 4 | 5 | use crate::Convert; 6 | 7 | trait ToF32Array { 8 | fn to_f32_array(&self) -> [f32; 4]; 9 | } 10 | 11 | impl ToF32Array for Option<&usvg::Stop> { 12 | fn to_f32_array(&self) -> [f32; 4] { 13 | self.map(Convert::convert) 14 | .unwrap_or(Color::NONE) 15 | .to_srgba() 16 | .to_f32_array() 17 | } 18 | } 19 | 20 | pub fn avg_gradient(gradient: &BaseGradient) -> Color { 21 | let first = gradient.stops().first().to_f32_array(); 22 | let last = gradient.stops().last().to_f32_array(); 23 | let avg = [ 24 | first[0] + last[0], 25 | first[1] + last[1], 26 | first[2] + last[2], 27 | first[3] + last[3], 28 | ] 29 | .map(|x| x / 2.0); 30 | Color::Srgba(Srgba::from_f32_array(avg)) 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /examples/3d/two_colors.rs: -------------------------------------------------------------------------------- 1 | use bevy::prelude::*; 2 | use bevy_svg::prelude::*; 3 | 4 | #[path = "../common/lib.rs"] 5 | mod common; 6 | 7 | fn main() { 8 | App::new() 9 | .add_plugins(DefaultPlugins.set(WindowPlugin { 10 | primary_window: Some(Window { 11 | title: "3d_two_colors".to_string(), 12 | resolution: (600, 600).into(), 13 | ..Default::default() 14 | }), 15 | ..Default::default() 16 | })) 17 | .add_plugins((common::CommonPlugin, bevy_svg::prelude::SvgPlugin)) 18 | .add_systems(Startup, setup) 19 | .run(); 20 | } 21 | 22 | fn setup(mut commands: Commands, asset_server: Res) { 23 | let svg = asset_server.load("neutron_star.svg"); 24 | commands.spawn(Camera3d::default()); 25 | commands.spawn(( 26 | Svg3d(svg.clone()), 27 | Origin::Center, 28 | Transform { 29 | translation: Vec3::new(0.0, 0.0, -600.0), 30 | ..Default::default() 31 | }, 32 | )); 33 | } 34 | -------------------------------------------------------------------------------- /examples/2d/complex_one_color.rs: -------------------------------------------------------------------------------- 1 | use bevy::prelude::*; 2 | use bevy_svg::prelude::*; 3 | 4 | #[path = "../common/lib.rs"] 5 | mod common; 6 | 7 | fn main() { 8 | App::new() 9 | .add_plugins(DefaultPlugins.set(WindowPlugin { 10 | primary_window: Some(Window { 11 | title: "2d_complex_one_color".to_string(), 12 | resolution: (600, 600).into(), 13 | ..Default::default() 14 | }), 15 | ..Default::default() 16 | })) 17 | .add_plugins((common::CommonPlugin, bevy_svg::prelude::SvgPlugin)) 18 | .add_systems(Startup, setup) 19 | .run(); 20 | } 21 | 22 | fn setup(mut commands: Commands, asset_server: Res) { 23 | let svg = asset_server.load("asteroid_field.svg"); 24 | commands.spawn((Camera2d, Msaa::Sample4)); 25 | commands.spawn(( 26 | Svg2d(svg), 27 | Origin::Center, 28 | Transform { 29 | scale: Vec3::new(2.0, 2.0, 1.0), 30 | ..Default::default() 31 | }, 32 | )); 33 | } 34 | -------------------------------------------------------------------------------- /src/render/svg2d/mod.rs: -------------------------------------------------------------------------------- 1 | use crate::{origin::Origin, svg::Svg}; 2 | use bevy::{ 3 | asset::{Handle, uuid_handle}, 4 | ecs::{component::Component, lifecycle::HookContext, world::DeferredWorld}, 5 | mesh::Mesh2d, 6 | shader::Shader, 7 | sprite_render::MeshMaterial2d, 8 | }; 9 | 10 | mod plugin; 11 | 12 | /// Handle to the custom shader with a unique random ID 13 | pub const SVG_2D_SHADER_HANDLE: Handle = 14 | uuid_handle!("00000000-0000-0000-762a-bdb29826d266"); 15 | 16 | pub use plugin::RenderPlugin; 17 | 18 | /// A component for 2D SVGs. 19 | #[derive(Component, Default)] 20 | #[require(Mesh2d, Origin)] 21 | #[component(on_insert = svg_2d_on_insert)] 22 | pub struct Svg2d(pub Handle); 23 | 24 | fn svg_2d_on_insert(mut world: DeferredWorld, ctx: HookContext) { 25 | let component = world.entity(ctx.entity).get_components::<&Svg2d>().unwrap(); 26 | let handle = component.0.clone(); 27 | let entity = world.entity(ctx.entity).id(); 28 | let mut commands = world.commands(); 29 | commands.entity(entity).insert(MeshMaterial2d(handle)); 30 | } 31 | -------------------------------------------------------------------------------- /src/render/svg3d/mod.rs: -------------------------------------------------------------------------------- 1 | use bevy::{ 2 | asset::{Handle, uuid_handle}, 3 | ecs::{component::Component, lifecycle::HookContext, world::DeferredWorld}, 4 | mesh::Mesh3d, 5 | pbr::MeshMaterial3d, 6 | shader::Shader, 7 | }; 8 | 9 | mod plugin; 10 | 11 | /// Handle to the custom shader with a unique random ID 12 | pub const SVG_3D_SHADER_HANDLE: Handle = 13 | uuid_handle!("00000000-0000-0000-762a-bdb74c2a5c66"); 14 | 15 | pub use plugin::RenderPlugin; 16 | 17 | use crate::{origin::Origin, svg::Svg}; 18 | 19 | /// A component for 3D SVGs. 20 | #[derive(Component, Default)] 21 | #[require(Mesh3d, Origin, MeshMaterial3d)] 22 | #[component(on_insert = svg_3d_on_insert)] 23 | pub struct Svg3d(pub Handle); 24 | 25 | fn svg_3d_on_insert(mut world: DeferredWorld, ctx: HookContext) { 26 | let component = world.entity(ctx.entity).get_components::<&Svg3d>().unwrap(); 27 | let handle = component.0.clone(); 28 | let entity = world.entity(ctx.entity).id(); 29 | let mut commands = world.commands(); 30 | commands.entity(entity).insert(MeshMaterial3d(handle)); 31 | } 32 | -------------------------------------------------------------------------------- /examples/3d/complex_one_color.rs: -------------------------------------------------------------------------------- 1 | use bevy::prelude::*; 2 | use bevy_svg::prelude::*; 3 | 4 | #[path = "../common/lib.rs"] 5 | mod common; 6 | 7 | fn main() { 8 | App::new() 9 | .add_plugins(DefaultPlugins.set(WindowPlugin { 10 | primary_window: Some(Window { 11 | title: "3d_complex_one_color".to_string(), 12 | resolution: (600, 600).into(), 13 | ..Default::default() 14 | }), 15 | ..Default::default() 16 | })) 17 | .add_plugins((common::CommonPlugin, bevy_svg::prelude::SvgPlugin)) 18 | .add_systems(Startup, setup) 19 | .run(); 20 | } 21 | 22 | fn setup(mut commands: Commands, asset_server: Res) { 23 | let svg = asset_server.load("asteroid_field.svg"); 24 | commands.spawn(Camera3d::default()); 25 | commands.spawn(( 26 | Svg3d(svg), 27 | Origin::Center, 28 | Transform { 29 | translation: Vec3::new(0.0, 0.0, -600.0), 30 | scale: Vec3::new(2.0, 2.0, 1.0), 31 | ..Default::default() 32 | }, 33 | )); 34 | } 35 | -------------------------------------------------------------------------------- /LICENSE-MIT: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 Daniel Wiesenberg 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /examples/3d/twinkle.rs: -------------------------------------------------------------------------------- 1 | use bevy::prelude::*; 2 | use bevy_svg::prelude::*; 3 | 4 | #[path = "../common/lib.rs"] 5 | mod common; 6 | 7 | fn main() { 8 | App::new() 9 | .add_plugins(DefaultPlugins.set(WindowPlugin { 10 | primary_window: Some(Window { 11 | title: "3d_twinkle".to_string(), 12 | resolution: (600, 600).into(), 13 | ..Default::default() 14 | }), 15 | ..Default::default() 16 | })) 17 | .add_plugins((common::CommonPlugin, bevy_svg::prelude::SvgPlugin)) 18 | .add_systems(Startup, setup) 19 | .run(); 20 | } 21 | 22 | fn setup(mut commands: Commands, asset_server: Res) { 23 | let svg = asset_server.load("twinkle.svg"); 24 | commands.spawn(( 25 | Camera3d::default(), 26 | Transform::from_xyz(5.0, 8.0, 8.0).looking_at(Vec3::ZERO, Vec3::Y), 27 | )); 28 | commands.spawn(( 29 | Svg3d(svg.clone()), 30 | Origin::Center, 31 | Transform { 32 | translation: Vec3::new(0.0, 0.0, -1.0), 33 | scale: Vec3::new(0.01, 0.01, 1.0), 34 | rotation: Quat::from_rotation_x(-std::f32::consts::PI / 5.0), 35 | }, 36 | )); 37 | } 38 | -------------------------------------------------------------------------------- /examples/3d/origin_check.rs: -------------------------------------------------------------------------------- 1 | use bevy::prelude::*; 2 | use bevy_svg::prelude::*; 3 | 4 | #[path = "../common/lib.rs"] 5 | mod common; 6 | 7 | fn main() { 8 | App::new() 9 | .add_plugins(DefaultPlugins.set(WindowPlugin { 10 | primary_window: Some(Window { 11 | title: "origin_check".to_string(), 12 | resolution: (600, 600).into(), 13 | ..Default::default() 14 | }), 15 | ..Default::default() 16 | })) 17 | .add_plugins((common::CommonPlugin, bevy_svg::prelude::SvgPlugin)) 18 | .add_systems(Startup, setup) 19 | .run(); 20 | } 21 | 22 | fn setup(mut commands: Commands, asset_server: Res) { 23 | let svg = asset_server.load("box.svg"); 24 | commands.spawn(Camera3d::default()); 25 | commands.spawn(( 26 | Svg3d(svg.clone()), 27 | Origin::Center, 28 | Transform { 29 | translation: Vec3::new(0.0, 0.0, -600.0), 30 | ..Default::default() 31 | }, 32 | )); 33 | commands.spawn(( 34 | Svg3d(svg.clone()), 35 | Origin::TopLeft, 36 | Transform { 37 | translation: Vec3::new(0.0, 0.0, -600.0), 38 | ..Default::default() 39 | }, 40 | common::DontChange, 41 | )); 42 | } 43 | -------------------------------------------------------------------------------- /src/render/svg3d/plugin.rs: -------------------------------------------------------------------------------- 1 | use super::SVG_3D_SHADER_HANDLE; 2 | use crate::svg::Svg; 3 | use bevy::{ 4 | app::{App, Plugin}, 5 | asset::{AssetApp, load_internal_asset}, 6 | mesh::MeshVertexBufferLayoutRef, 7 | pbr::{Material, MaterialPipeline, MaterialPipelineKey, MaterialPlugin}, 8 | render::render_resource::{RenderPipelineDescriptor, SpecializedMeshPipelineError}, 9 | shader::{Shader, ShaderRef}, 10 | }; 11 | 12 | /// Plugin that renders [`Svg`](crate::svg::Svg)s in 2D 13 | pub struct RenderPlugin; 14 | 15 | impl Plugin for RenderPlugin { 16 | fn build(&self, app: &mut App) { 17 | load_internal_asset!(app, SVG_3D_SHADER_HANDLE, "svg_3d.wgsl", Shader::from_wgsl); 18 | 19 | app.add_plugins(MaterialPlugin::::default()) 20 | .register_asset_reflect::(); 21 | } 22 | } 23 | 24 | impl Material for Svg { 25 | fn fragment_shader() -> ShaderRef { 26 | SVG_3D_SHADER_HANDLE.into() 27 | } 28 | 29 | fn specialize( 30 | _pipeline: &MaterialPipeline, 31 | descriptor: &mut RenderPipelineDescriptor, 32 | _layout: &MeshVertexBufferLayoutRef, 33 | _key: MaterialPipelineKey, 34 | ) -> bevy::prelude::Result<(), SpecializedMeshPipelineError> { 35 | descriptor.primitive.cull_mode = None; 36 | 37 | Ok(()) 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /examples/3d/multiple_perspective.rs: -------------------------------------------------------------------------------- 1 | use bevy::prelude::*; 2 | use bevy_svg::prelude::*; 3 | 4 | #[path = "../common/lib.rs"] 5 | mod common; 6 | 7 | fn main() { 8 | App::new() 9 | .add_plugins(DefaultPlugins.set(WindowPlugin { 10 | primary_window: Some(Window { 11 | title: "3d_multiple_perspective".to_string(), 12 | resolution: (600, 600).into(), 13 | ..Default::default() 14 | }), 15 | ..Default::default() 16 | })) 17 | .add_plugins((common::CommonPlugin, bevy_svg::prelude::SvgPlugin)) 18 | .add_systems(Startup, setup) 19 | .run(); 20 | } 21 | 22 | fn setup(mut commands: Commands, asset_server: Res) { 23 | let svg = asset_server.load("neutron_star.svg"); 24 | commands.spawn(( 25 | Camera3d::default(), 26 | Transform::from_xyz(100.0, 175.0, 0.0).looking_at(Vec3::new(0.0, 0.0, -600.0), Vec3::Y), 27 | )); 28 | commands.spawn(( 29 | Svg3d(svg.clone()), 30 | Origin::Center, 31 | Transform { 32 | translation: Vec3::new(0.0, 0.0, -600.0), 33 | rotation: Quat::from_rotation_x(-std::f32::consts::PI * 3.0), 34 | ..Default::default() 35 | }, 36 | )); 37 | commands.spawn(( 38 | Svg3d(svg.clone()), 39 | Origin::Center, 40 | Transform { 41 | translation: Vec3::new(0.0, 0.0, -700.0), 42 | rotation: Quat::from_rotation_x(-std::f32::consts::PI * 3.0), 43 | ..Default::default() 44 | }, 45 | )); 46 | commands.spawn(( 47 | Svg3d(svg), 48 | Origin::Center, 49 | Transform { 50 | translation: Vec3::new(0.0, 0.0, -800.0), 51 | rotation: Quat::from_rotation_x(-std::f32::consts::PI * 3.0), 52 | ..Default::default() 53 | }, 54 | )); 55 | } 56 | -------------------------------------------------------------------------------- /examples/2d/preloading.rs: -------------------------------------------------------------------------------- 1 | use bevy::asset::LoadState; 2 | use bevy::prelude::*; 3 | use bevy_svg::prelude::*; 4 | 5 | #[path = "../common/lib.rs"] 6 | mod common; 7 | 8 | fn main() { 9 | App::new() 10 | .add_plugins(DefaultPlugins.set(WindowPlugin { 11 | primary_window: Some(Window { 12 | title: "preloading".to_string(), 13 | resolution: (600, 600).into(), 14 | ..Default::default() 15 | }), 16 | ..Default::default() 17 | })) 18 | .add_plugins((common::CommonPlugin, bevy_svg::prelude::SvgPlugin)) 19 | .add_systems(Startup, setup) 20 | .add_systems(Update, run) 21 | .run(); 22 | } 23 | 24 | fn setup(mut commands: Commands) { 25 | commands.spawn(Camera2d); 26 | } 27 | 28 | #[derive(Default, Eq, PartialEq)] 29 | enum TutorialFsm { 30 | #[default] 31 | Ready, 32 | StartedLoad(Handle), 33 | Wait(Handle, u8), 34 | Loaded, 35 | } 36 | 37 | fn run(mut commands: Commands, asset_server: Res, mut fsm: Local) { 38 | match &*fsm { 39 | TutorialFsm::Ready => { 40 | let handle = asset_server.load("neutron_star.svg"); 41 | *fsm = TutorialFsm::StartedLoad(handle); 42 | } 43 | TutorialFsm::StartedLoad(handle) => { 44 | if let Some(LoadState::Loaded) = asset_server.get_load_state(handle) { 45 | *fsm = TutorialFsm::Wait(handle.clone(), 60); 46 | } 47 | } 48 | TutorialFsm::Wait(handle, frames) => { 49 | if *frames > 0 { 50 | *fsm = TutorialFsm::Wait(handle.clone(), *frames - 1); 51 | } else if let Some(svg) = asset_server.get_handle("neutron_star.svg") { 52 | commands.spawn((Svg2d(svg), Origin::Center)); 53 | 54 | *fsm = TutorialFsm::Loaded; 55 | dbg!("We loaded"); 56 | } 57 | } 58 | TutorialFsm::Loaded => {} 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /examples/2d/multiple_translation.rs: -------------------------------------------------------------------------------- 1 | use bevy::prelude::*; 2 | use bevy_svg::prelude::*; 3 | 4 | #[path = "../common/lib.rs"] 5 | mod common; 6 | 7 | fn main() { 8 | App::new() 9 | .add_plugins(DefaultPlugins.set(WindowPlugin { 10 | primary_window: Some(Window { 11 | title: "2d_multiple_translation".to_string(), 12 | resolution: (600, 600).into(), 13 | ..Default::default() 14 | }), 15 | ..Default::default() 16 | })) 17 | .add_plugins((common::CommonPlugin, bevy_svg::prelude::SvgPlugin)) 18 | .add_systems(Startup, setup) 19 | .add_systems(Update, svg_movement) 20 | .run(); 21 | } 22 | 23 | fn setup(mut commands: Commands, asset_server: Res) { 24 | let svg = asset_server.load("asteroid_field.svg"); 25 | commands.spawn(Camera2d); 26 | commands.spawn(( 27 | Svg2d(svg), 28 | Origin::Center, 29 | Transform { 30 | translation: Vec3::new(100.0, 0.0, 0.0), 31 | scale: Vec3::new(2.0, 2.0, 1.0), 32 | ..Default::default() 33 | }, 34 | Direction::Up, 35 | )); 36 | 37 | let svg = asset_server.load("neutron_star.svg"); 38 | commands.spawn((Svg2d(svg), Origin::Center, Direction::Up)); 39 | } 40 | 41 | #[derive(Component)] 42 | enum Direction { 43 | Up, 44 | Down, 45 | } 46 | 47 | fn svg_movement( 48 | time: Res