### move_to Source: https://docs.rs/femtovg/latest/src/femtovg/path.rs.html Starts a new sub-path with the specified point as the first point. ```APIDOC ## move_to ### Description Starts a new sub-path with the specified point as the first point. ### Method move_to ### Parameters - **x** (f32) - Required - The x coordinate of the first point. - **y** (f32) - Required - The y coordinate of the first point. ### Returns void ``` -------------------------------- ### Paint::line_cap_start Source: https://docs.rs/femtovg/latest/femtovg/struct.Paint.html Returns the current start line cap. ```APIDOC ## Paint::line_cap_start ### Description Returns the current start line cap. ### Method Function ### Signature pub fn line_cap_start(&self) -> LineCap ### Returns - **LineCap** - The current start line cap. ``` -------------------------------- ### with_line_cap_start Source: https://docs.rs/femtovg/latest/femtovg/struct.Paint.html Returns a new Paint with the start line cap set to the specified value. ```APIDOC ## with_line_cap_start ### Description Returns the paint with the start line cap set to the specified value. ### Method pub fn with_line_cap_start(self, cap: LineCap) -> Self ### Parameters - **cap** (LineCap) - Required - The line cap value to set. ### Returns Self - A new Paint with the start line cap set. ``` -------------------------------- ### Paint::image example: fill a rectangle with an image pattern Source: https://docs.rs/femtovg/latest/femtovg/struct.Paint.html Creates an image pattern paint from a loaded image and fills a rectangle with it. Requires an image ID from load_image_file; the paint parameters specify the pattern's top-left, size, rotation, and alpha. ```rust use femtovg::{Paint, Path, Color, Canvas, ImageFlags, renderer::Void}; let mut canvas = Canvas::new(Void).expect("Cannot create canvas"); let image_id = canvas.load_image_file("examples/assets/rust-logo.png", ImageFlags::GENERATE_MIPMAPS).expect("Cannot create image"); let fill_paint = Paint::image(image_id, 10.0, 10.0, 85.0, 85.0, 0.0, 1.0); let mut path = Path::new(); path.rect(10.0, 10.0, 85.0, 85.0); canvas.fill_path(&path, &fill_paint); ``` -------------------------------- ### Get main program based on glyph texture need Source: https://docs.rs/femtovg/latest/src/femtovg/renderer/opengl.rs.html Returns the currently selected main shader program, choosing between glyph-texture and non-glyph-texture program lists based on the current state. Panics with an internal error if the program index is invalid. ```rust let programs = if self.current_program_needs_glyph_texture { &self.main_programs_with_glyph_texture } else { &self.main_programs_without_glyph_texture }; programs[self.current_program as usize] .as_ref() .expect("internal error: invalid shader program selected for given paint") ``` -------------------------------- ### conic_gradient_non_finite_start_angle_is_treated_as_zero Source: https://docs.rs/femtovg/latest/src/femtovg/paint.rs.html Verifies that non-finite start angles (NaN, infinity, negative infinity) are treated as 0.0 for conic gradients, while finite angles are preserved. Tests both two-stop and multi-stop constructors. ```rust let start_angle_of = |paint: Paint| match paint.flavor { PaintFlavor::ConicGradient { start_angle, .. } => start_angle, other => panic!("expected ConicGradient, got {other:?}"), }; for bad_angle in [f32::NAN, f32::INFINITY, f32::NEG_INFINITY] { let two_stop = Paint::conic_gradient_with_angle(10.0, 20.0, bad_angle, Color::black(), Color::white()); assert_eq!(start_angle_of(two_stop), 0.0); let multi_stop = Paint::conic_gradient_stops_with_angle( 10.0, 20.0, bad_angle, [(0.0, Color::black()), (1.0, Color::white())], ); assert_eq!(start_angle_of(multi_stop), 0.0); } // Finite angles must pass through untouched. let finite = Paint::conic_gradient_with_angle(10.0, 20.0, -1.25, Color::black(), Color::white()); assert_eq!(start_angle_of(finite), -1.25); ``` -------------------------------- ### butt_cap_start: Generate butt cap vertices Source: https://docs.rs/femtovg/latest/src/femtovg/path/cache.rs.html Generates the vertices for a butt cap at the start of a path segment. It places two vertices at the cap position and two more offset by the anti-aliasing distance along the direction. The function is used when the line cap is butt. ```rust fn butt_cap_start(verts: &mut Vec, p0: &Point, p1: &Point, w: f32, d: f32, aa: f32, u0: f32, u1: f32) { let ppos = p0.pos + p1.dpos * d; let dlpos = p1.dpos.orthogonal(); verts.push(Vertex::pos(ppos + dlpos * w, u0, 1.0)); verts.push(Vertex::pos(ppos - dlpos * w, u1, 1.0)); verts.push(Vertex::pos(ppos + dlpos * w + p1.dpos * aa, u0, 0.0)); verts.push(Vertex::pos(ppos - dlpos * w + p1.dpos * aa, u1, 0.0)); } ``` -------------------------------- ### Gaussian blur filter setup in wgpu renderer Source: https://docs.rs/femtovg/latest/src/femtovg/renderer/wgpu.rs.html Sets up a Gaussian blur filter for an image in the wgpu renderer. Computes Gaussian coefficients, clamps sigma to 8.0 for GLES 2.0 compatibility, and creates a horizontal blur texture. The blur direction is set to horizontal (1.0, 0.0). ```rust fn gaussian_blur_filter( device: &wgpu::Device, current_render_target: &mut RenderTarget, images: &mut ImageStore, command: super::Command, sigma: f32, render_pass_builder: &mut RenderPassBuilder<'_>, pipeline_and_bindgroup_mapper: &mut CommandToPipelineAndBindGroupMapper, target_image: ImageId, ) { let blend_state = blend_state(&command).into(); let previous_render_target = *current_render_target; let source_image = images.get(command.image.unwrap()).unwrap(); let image_paint = crate::Paint::image( command.image.unwrap(), 0., 0., source_image.info.width() as _, source_image.info.height() as _, 0., 1., ); let mut blur_params = Params::new( images, &Default::default(), &image_paint.flavor, &Default::default(), &Scissor::default(), 0., 0., 0., ); blur_params.shader_type = ShaderType::FilterImage; let gauss_coeff_x = 1. / ((2. * std::f32::consts::PI).sqrt() * sigma); let gauss_coeff_y = f32::exp(-0.5 / (sigma * sigma)); let gauss_coeff_z = gauss_coeff_y * gauss_coeff_y; blur_params.image_blur_filter_coeff[0] = gauss_coeff_x; blur_params.image_blur_filter_coeff[1] = gauss_coeff_y; blur_params.image_blur_filter_coeff[2] = gauss_coeff_z; blur_params.image_blur_filter_direction = [1.0, 0.0]; // GLES 2.0 does not allow non-constant loop indices, so limit the standard devitation to allow for a upper fixed limit // on the number of iterations in the fragment shader. blur_params.image_blur_filter_sigma = sigma.min(8.); let horizontal_blur_buffer = device.create_texture(&wgpu::TextureDescriptor { label: Some("blur horizontal"), size: wgpu::Extent3d { width: source_image.info.width() as _, height: source_image.info.height() as _, ``` -------------------------------- ### femtovg path.rs: Path, Verb, and Solidity definitions Source: https://docs.rs/femtovg/latest/src/femtovg/path.rs.html The main source file for the femtovg Path type. It defines the Solidity and Verb enums, the Path struct with its cache, and the Path::new, size, is_empty, set_distance_tolerance, and verbs methods. The compile_fail doc example shows that sharing a &Path across threads is rejected because Path is not Sync. ```rust use std::{ cell::{RefCell, RefMut}, f32::consts::PI, slice, }; use crate::geometry::{Position, Transform2D, Vector}; #[cfg(feature = "textlayout")] use rustybuzz::ttf_parser; mod cache; pub use cache::{Convexity, PathCache}; // Length proportional to radius of a cubic bezier handle for 90deg arcs. const KAPPA90: f32 = 0.552_284_8; // 0.552_284_749_3; /// Specifies whether a shape is solid or a hole when adding it to a path. /// /// The default value is `Solid`. #[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Default)] pub enum Solidity { /// The shape is solid (filled). #[default] Solid = 1, /// The shape is a hole (not filled). Hole = 2, } #[derive(Copy, Clone, Debug, Eq, PartialEq)] #[repr(u8)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] pub enum PackedVerb { MoveTo, LineTo, BezierTo, Solid, Hole, Close, } /// A verb describes how to interpret one or more points to continue the countour /// of a [`Path`]. #[derive(Copy, Clone, Debug)] pub enum Verb { /// Terminates the current sub-path and defines the new current point by the /// given x/y f32 coordinates. MoveTo(f32, f32), /// Describes that the contour of the path should continue as a line from the /// current point to the given x/y f32 coordinates. LineTo(f32, f32), /// Describes that the contour of the path should continue as a cubie bezier segment from the /// current point via two control points (as f32 pairs) to the point in the last f32 pair. BezierTo(f32, f32, f32, f32, f32, f32), /// Sets the current sub-path winding to be solid. Solid, /// Sets the current sub-path winding to be hole. Hole, /// Closes the current sub-path. Close, } impl Verb { fn num_coordinates(&self) -> usize { match *self { Self::MoveTo(..) => 1, Self::LineTo(..) => 1, Self::BezierTo(..) => 3, Self::Solid => 0, Self::Hole => 0, Self::Close => 0, } } fn from_packed(packed: &PackedVerb, coords: &[Position]) -> Self { match *packed { PackedVerb::MoveTo => Self::MoveTo(coords[0].x, coords[0].y), PackedVerb::LineTo => Self::LineTo(coords[0].x, coords[0].y), PackedVerb::BezierTo => Self::BezierTo( coords[0].x, coords[0].y, coords[1].x, coords[1].y, coords[2].x, coords[2].y, ), PackedVerb::Solid => Self::Solid, PackedVerb::Hole => Self::Hole, PackedVerb::Close => Self::Close, } } } /// A collection of verbs (`move_to()`, `line_to()`, `bezier_to()`, etc.) /// describing one or more contours. /// /// A `Path` is `Send` but intentionally not `Sync`: the interior tessellation /// cache uses a [`RefCell`], so sharing a `&Path` between threads is rejected /// at compile time. Move (or clone) a `Path` into each thread instead. /// /// ```compile_fail /// let path = femtovg::Path::new(); /// std::thread::scope(|scope| { /// // ERROR: `&Path` is not `Send` because `Path` is not `Sync`. /// scope.spawn(|| path.is_empty()); /// }); /// ``` #[derive(Default, Clone, Debug)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] pub struct Path { verbs: Vec, coords: Vec, last_pos: Position, dist_tol: f32, #[cfg_attr(feature = "serde", serde(skip))] pub(crate) cache: RefCell>, } impl Path { /// Creates a new empty path with a distance tolerance of 0.01. pub fn new() -> Self { Self { dist_tol: 0.01, ..Default::default() } } /// Returns the memory size in bytes used by the path. pub fn size(&self) -> usize { std::mem::size_of::() * self.verbs.len() + std::mem::size_of::() * self.coords.len() } /// Checks if the path is empty (contains no verbs). pub fn is_empty(&self) -> bool { self.verbs.is_empty() } /// Sets the distance tolerance used for path operations. pub fn set_distance_tolerance(&mut self, value: f32) { self.dist_tol = value; } /// Returns an iterator over the path's verbs. pub fn verbs(&self) -> PathIter<'_> { PathIter { verbs: self.verbs.iter(), coords: &self.coords, } } ``` -------------------------------- ### Materialize BindGroupState into wgpu BindGroup Source: https://docs.rs/femtovg/latest/src/femtovg/renderer/wgpu.rs.html Creates a wgpu bind group with five entries: a uniform buffer, main texture view, main sampler, glyph texture view, and glyph sampler. External texture views trigger an unimplemented panic. Requires a device, image store, bind group layout, empty texture view, sampler cache, and uniform buffer. ```rust impl BindGroupState { fn materialize( &self, device: &wgpu::Device, images: &ImageStore, bind_group_layout: &wgpu::BindGroupLayout, empty_texture_view: &wgpu::TextureView, sampler_cache: &RefCell>, uniform_buffer: &wgpu::Buffer, ) -> wgpu::BindGroup { let (main_texture_view, main_sampler) = RenderPassBuilder::create_binding_resource_and_sampler( device, images, self.image.as_ref(), empty_texture_view, sampler_cache, ); let (glyph_texture_view, glyph_sampler) = RenderPassBuilder::create_binding_resource_and_sampler( device, images, self.glyph_texture.image_id().map(ImageOrTexture::Image).as_ref(), empty_texture_view, sampler_cache, ); if main_texture_view.is_external() || glyph_texture_view.is_external() { unimplemented!("External texture shaders and bind groups are not implemented yet"); } device.create_bind_group(&wgpu::BindGroupDescriptor { layout: bind_group_layout, entries: &[ wgpu::BindGroupEntry { binding: 0, resource: wgpu::BindingResource::Buffer(wgpu::BufferBinding { buffer: uniform_buffer, offset: 0, size: wgpu::BufferSize::new(UNIFORM_BYTES), }), }, wgpu::BindGroupEntry { binding: 1, resource: (&main_texture_view).into(), }, wgpu::BindGroupEntry { binding: 2, resource: wgpu::BindingResource::Sampler(&main_sampler), }, wgpu::BindGroupEntry { binding: 3, resource: (&glyph_texture_view).into(), }, wgpu::BindGroupEntry { binding: 4, resource: wgpu::BindingResource::Sampler(&glyph_sampler), }, ], label: None, }) } } ``` -------------------------------- ### Paint::conic_gradient_stops_with_angle Source: https://docs.rs/femtovg/latest/femtovg/struct.Paint.html Creates a multi-stop conic gradient with a start angle. Non-finite start angles are treated as 0.0. ```APIDOC ## Paint::conic_gradient_stops_with_angle ### Description Creates and returns a multi-stop conic gradient with a start angle. The start_angle is in radians, measured clockwise from the positive x axis. Non-finite start_angle values are ignored and treated as 0.0. ### Method Function ### Signature pub fn conic_gradient_stops_with_angle(cx: f32, cy: f32, start_angle: f32, stops: impl IntoIterator) -> Self ### Parameters - **cx** (f32) - Required - Center x coordinate. - **cy** (f32) - Required - Center y coordinate. - **start_angle** (f32) - Required - Start angle in radians, measured clockwise from the positive x axis. - **stops** (impl IntoIterator) - Required - List of color stops with offsets. ### Returns - **Self** - A Paint configured with the conic gradient. ``` -------------------------------- ### WGPURenderer::new Source: https://docs.rs/femtovg/latest/femtovg/renderer/struct.WGPURenderer.html Creates a new WGPU renderer for the given device and queue. ```APIDOC ## WGPURenderer::new ### Description Creates a new WGPU renderer for the given device and queue. ### Method new ### Parameters - **device** (wgpu::Device) - Required - The WGPU device to use for rendering. - **queue** (wgpu::Queue) - Required - The WGPU queue to use for rendering. ### Returns - **Self** - A new WGPURenderer instance. ``` -------------------------------- ### Paint::conic_gradient_with_angle Source: https://docs.rs/femtovg/latest/femtovg/struct.Paint.html Creates a two-color conic gradient with a start angle. Non-finite start angles are treated as 0.0. ```APIDOC ## Paint::conic_gradient_with_angle ### Description Creates and returns a two-color conic gradient with a start angle. The start_angle is in radians, measured clockwise from the positive x axis. Non-finite start_angle values are ignored and treated as 0.0. ### Method Function ### Signature pub fn conic_gradient_with_angle(cx: f32, cy: f32, start_angle: f32, start_color: Color, end_color: Color) -> Self ### Parameters - **cx** (f32) - Required - Center x coordinate. - **cy** (f32) - Required - Center y coordinate. - **start_angle** (f32) - Required - Start angle in radians, measured clockwise from the positive x axis. - **start_color** (Color) - Required - Color at the start of the gradient. - **end_color** (Color) - Required - Color at the end of the gradient. ### Returns - **Self** - A Paint configured with the conic gradient. ``` -------------------------------- ### Test svg_arc_to on empty path starts at origin Source: https://docs.rs/femtovg/latest/src/femtovg/path.rs.html Checks that svg_arc_to on an empty path starts at the origin (0,0) with an implicit move_to, and the arc endpoint is correct. ```rust let mut path = Path::new(); path.svg_arc_to(50.0, 50.0, 0.0, false, true, 100.0, 0.0); let verbs: Vec<_> = path.verbs().collect(); // An implicit move_to(0, 0) is inserted before the bezier segments. assert!(matches!(verbs[0], Verb::MoveTo(0.0, 0.0))); assert!(verbs.len() > 1); let (_, endpoint) = sample_path(&path); assert!((endpoint.0 - 100.0).abs() < 1e-3); assert!((endpoint.1).abs() < 1e-3); ``` -------------------------------- ### Test svg_arc_to large flag selects longer sweep (start) Source: https://docs.rs/femtovg/latest/src/femtovg/path.rs.html Starts a test that verifies the large_arc flag selects the longer sweep. It defines a closure that samples the path and sums segment lengths, then computes the length for large_arc=false. ```rust #[test] fn svg_arc_large_flag_selects_longer_sweep() { let start = (100.0, 100.0); let end = (160.0, 100.0); let rx = 50.0; let ry = 50.0; let arc_length = |large: bool| -> f32 { let mut path = Path::new(); path.move_to(start.0, start.1); path.svg_arc_to(rx, ry, 0.0, large, true, end.0, end.1); let (points, _) = sample_path(&path); points .windows(2) .map(|w| (w[1].0 - w[0].0).hypot(w[1].1 - w[0].1)) .sum() }; let small = arc_length(false); ``` -------------------------------- ### WGPU bind group layout and render method Source: https://docs.rs/femtovg/latest/src/femtovg/renderer/wgpu.rs.html Defines the WGPU bind group layout with a dynamic uniform buffer and two texture/sampler pairs, then creates the pipeline layout and stores renderer state. The render method grows the uniform and vertex buffers, writes vertex data, and returns None when commands are empty. ```rust label: None, entries: &[ wgpu::BindGroupLayoutEntry { binding: 0, visibility: wgpu::ShaderStages::FRAGMENT, ty: wgpu::BindingType::Buffer { ty: wgpu::BufferBindingType::Uniform, has_dynamic_offset: true, min_binding_size: wgpu::BufferSize::new(UNIFORM_BYTES), }, count: None, }, wgpu::BindGroupLayoutEntry { binding: 1, visibility: wgpu::ShaderStages::FRAGMENT, ty: wgpu::BindingType::Texture { sample_type: wgpu::TextureSampleType::Float { filterable: true }, view_dimension: wgpu::TextureViewDimension::D2, multisampled: false, }, count: None, }, wgpu::BindGroupLayoutEntry { binding: 2, visibility: wgpu::ShaderStages::FRAGMENT, ty: wgpu::BindingType::Sampler(wgpu::SamplerBindingType::Filtering), count: None, }, wgpu::BindGroupLayoutEntry { binding: 3, visibility: wgpu::ShaderStages::FRAGMENT, ty: wgpu::BindingType::Texture { sample_type: wgpu::TextureSampleType::Float { filterable: true }, view_dimension: wgpu::TextureViewDimension::D2, multisampled: false, }, count: None, }, wgpu::BindGroupLayoutEntry { binding: 4, visibility: wgpu::ShaderStages::FRAGMENT, ty: wgpu::BindingType::Sampler(wgpu::SamplerBindingType::Filtering), count: None, }, ], }); let pipeline_layout = device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor { label: None, bind_group_layouts: &[Some(&viewport_bind_group_layout), Some(&bind_group_layout)], immediate_size: 0, }); Self { device, queue, shader_module, screen_view: [0.0, 0.0], empty_texture_view: empty_texture.create_view(&Default::default()), sampler_cache: Rc::new(RefCell::new(HashMap::new())), uniform_buffer, uniform_stride, vertex_buffer, stencil_buffer: None, stencil_buffer_for_textures: HashMap::new(), bind_group_layout, viewport_bind_group_layout, pipeline_layout, pipeline_cache: Default::default(), } } ``` ```rust impl Renderer for WGPURenderer { type Image = Image; type NativeTexture = wgpu::Texture; type ExternalTexture = wgpu::ExternalTexture; type RenderOutput = WGPURenderOutput; type CommandBuffer = Option; fn set_size(&mut self, _width: u32, _height: u32, _dpi: f32) {} fn render( &mut self, output: impl Into, images: &mut crate::image::ImageStore, verts: &[super::Vertex], commands: Vec, ) -> Self::CommandBuffer { if commands.is_empty() { return None; } // The bind groups recorded below hold this buffer, so it cannot grow mid-frame. let needed_slots = commands.len() as u64 * UNIFORM_SLOTS_PER_COMMAND; grow_buffer( &self.device, &mut self.uniform_buffer, needed_slots * self.uniform_stride, UNIFORM_BUFFER_LABEL, UNIFORM_BUFFER_USAGE, ); let output = output.into(); self.screen_view[0] = output.width as f32; self.screen_view[1] = output.height as f32; let texture_view = output.view.clone(); let vertex_bytes: &[u8] = bytemuck::cast_slice(verts); let vertex_needed = (vertex_bytes.len() as u64).div_ceil(wgpu::COPY_BUFFER_ALIGNMENT) * wgpu::COPY_BUFFER_ALIGNMENT; grow_buffer( &self.device, &mut self.vertex_buffer, vertex_needed, VERTEX_BUFFER_LABEL, VERTEX_BUFFER_USAGE, ); if !vertex_bytes.is_empty() { self.queue.write_buffer(&self.vertex_buffer, 0, vertex_bytes); } ``` -------------------------------- ### set_line_cap_start Source: https://docs.rs/femtovg/latest/femtovg/struct.Paint.html Sets the line cap for the start of the line. ```APIDOC ## set_line_cap_start ### Description Sets the line cap for the start of the line. ### Method pub fn set_line_cap_start(&mut self, cap: LineCap) ### Parameters - **cap** (LineCap) - Required - The line cap value to set. ``` -------------------------------- ### MainProgram struct and constructor in program.rs Source: https://docs.rs/femtovg/latest/src/femtovg/renderer/opengl/program.rs.html Defines MainProgram with uniform locations for view size, textures, and fragment shader selection. Its constructor builds shader source strings with preprocessor defines for antialiasing, shader type, and glyph texture support, then includes external GLSL files via include_str!. ```rust #[derive(Debug)] pub struct MainProgram { context: Rc, program: Program, loc_viewsize: ::UniformLocation, loc_tex: Option<::UniformLocation>, loc_glyphtex: Option<::UniformLocation>, loc_frag: Option<::UniformLocation>, } impl MainProgram { pub(crate) fn new( context: &Rc, antialias: bool, shader_type: ShaderType, with_glyph_texture: bool, ) -> Result { let shader_defs = if antialias { "#define EDGE_AA 1" } else { "" }; let select_shader_type = format!( "#define SELECT_SHADER {}\n{}", shader_type.to_u8(), if with_glyph_texture { "#define ENABLE_GLYPH_TEXTURE" } else { "" } ); let vert_shader_src = format!("{}\n{}\n{}", GLSL_VERSION, shader_defs, include_str!("main-vs.glsl")); let frag_shader_src = format!( "{}\n{}\n{}\n{}", GLSL_VERSION, shader_defs, select_shader_type, ``` -------------------------------- ### WGPURenderer::get_native_texture Source: https://docs.rs/femtovg/latest/femtovg/renderer/struct.WGPURenderer.html Gets the native texture associated with an image. ```APIDOC ## WGPURenderer::get_native_texture ### Description Gets the native texture associated with an image. ### Method get_native_texture ### Parameters - **image** (&Self::Image) - Required - The image to get the native texture for. ### Returns - **Result** - The native texture, or an error. ``` -------------------------------- ### Allocate image texture in wgpu renderer Source: https://docs.rs/femtovg/latest/src/femtovg/renderer/wgpu.rs.html Creates a wgpu texture for an image, mapping PixelFormat to TextureFormat (Rgb8 and Rgba8 both become Rgba8Unorm, Gray8 becomes R8Unorm). The texture is 2D, single mip, single sample, with TEXTURE_BINDING, COPY_DST, and RENDER_ATTACHMENT usage. ```rust fn alloc_image(&mut self, info: crate::ImageInfo) -> Result { Ok(Image { texture: Texture::Internal(self.device.create_texture(&wgpu::TextureDescriptor { label: None, size: wgpu::Extent3d { width: info.width() as u32, height: info.height() as u32, depth_or_array_layers: 1, }, mip_level_count: 1, sample_count: 1, dimension: wgpu::TextureDimension::D2, format: match info.format() { crate::PixelFormat::Rgb8 => wgpu::TextureFormat::Rgba8Unorm, crate::PixelFormat::Rgba8 => wgpu::TextureFormat::Rgba8Unorm, crate::PixelFormat::Gray8 => wgpu::TextureFormat::R8Unorm, }, usage: wgpu::TextureUsages::TEXTURE_BINDING | wgpu::TextureUsages::COPY_DST | wgpu::TextureUsages::RENDER_ATTACHMENT, view_formats: &[], })), info, }) } ``` -------------------------------- ### Create WGPURenderer with shader and buffers Source: https://docs.rs/femtovg/latest/src/femtovg/renderer/wgpu.rs.html Creates a new WGPURenderer for the device: loads the WGSL shader, creates a texture descriptor, computes uniform buffer alignment, creates uniform and vertex buffers, writes a red pixel to an empty texture, and creates a bind group layout for the viewport uniform. ```rust let module = wgpu::include_wgsl!("wgpu/shader.wgsl"); let shader_module = Rc::new(device.create_shader_module(module)); let texture_descriptor = wgpu::TextureDescriptor { size: wgpu::Extent3d::default(), mip_level_count: 1, sample_count: 1, dimension: wgpu::TextureDimension::D2, format: wgpu::TextureFormat::Rgba8Unorm, usage: wgpu::TextureUsages::TEXTURE_BINDING | wgpu::TextureUsages::COPY_DST, label: None, view_formats: &[], }; // A dynamic offset must be a multiple of this, usually 256. let alignment = u64::from(device.limits().min_uniform_buffer_offset_alignment).max(1); let uniform_stride = UNIFORM_BYTES.div_ceil(alignment) * alignment; let uniform_buffer = device.create_buffer(&wgpu::BufferDescriptor { label: Some(UNIFORM_BUFFER_LABEL), size: MIN_UNIFORM_SLOTS * uniform_stride, usage: UNIFORM_BUFFER_USAGE, mapped_at_creation: false, }); let vertex_buffer = device.create_buffer(&wgpu::BufferDescriptor { label: Some(VERTEX_BUFFER_LABEL), size: MIN_VERTEX_BYTES, usage: VERTEX_BUFFER_USAGE, mapped_at_creation: false, }); let empty_texture = device.create_texture(&wgpu::TextureDescriptor { label: Some("empty"), view_formats: &[], ..texture_descriptor }); queue.write_texture( empty_texture.as_image_copy(), &[255, 0, 0, 255], wgpu::TexelCopyBufferLayout { offset: 0, bytes_per_row: Some(4), rows_per_image: None, }, wgpu::Extent3d::default(), ); let viewport_bind_group_layout = device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor { label: Some("Bind Group Layout for Viewport uniform"), entries: &[wgpu::BindGroupLayoutEntry { binding: 0, visibility: wgpu::ShaderStages::VERTEX, ty: wgpu::BindingType::Buffer { ty: wgpu::BufferBindingType::Uniform, has_dynamic_offset: false, min_binding_size: None, }, count: None, }], }); ``` -------------------------------- ### Paint::set_line_cap Source: https://docs.rs/femtovg/latest/femtovg/struct.Paint.html Sets the line cap for both start and end of the line. ```APIDOC ## Paint::set_line_cap ### Description Sets the line cap for both start and end of the line. ### Method Function ### Signature pub fn set_line_cap(&mut self, cap: LineCap) ### Parameters - **cap** (LineCap) - Required - The line cap to set. ``` -------------------------------- ### round_cap_start: Generate round cap vertices Source: https://docs.rs/femtovg/latest/src/femtovg/path/cache.rs.html Generates the vertices for a round cap at the start of a path segment. It uses the orthogonal of the direction vector and a basis to place vertices along a semicircle, then adds the two end vertices. The function is called when the line join is round and the cap is at the start. ```rust fn round_cap_start(verts: &mut Vec, p0: &Point, p1: &Point, w: f32, ncap: usize, u0: f32, u1: f32) { let ppos = p0.pos; let dlpos = p1.dpos.orthogonal(); for i in 0..ncap { let a = i as f32 / (ncap as f32 - 1.0) * PI; let offset = Vector::from_angle(a).with_basis(-dlpos, -p1.dpos) * w; verts.push(Vertex::pos(ppos + offset, u0, 1.0)); verts.push(Vertex::pos(ppos, 0.5, 1.0)); } verts.push(Vertex::pos(ppos + dlpos * w, u0, 1.0)); verts.push(Vertex::pos(ppos - dlpos * w, u1, 1.0)); } ``` -------------------------------- ### Thread safety constraint Source: https://docs.rs/femtovg/latest/femtovg/struct.Path.html Example demonstrating that Path is not Sync and cannot be shared between threads. ```rust let path = femtovg::Path::new(); std::thread::scope(|scope| { // ERROR: `&Path` is not `Send` because `Path` is not `Sync`. scope.spawn(|| path.is_empty()); }); ``` -------------------------------- ### Execute render commands and finish command buffer in wgpu renderer Source: https://docs.rs/femtovg/latest/src/femtovg/renderer/wgpu.rs.html Handles command execution for triangles and filtered image rendering, then flushes uniform staging and finishes the command buffer. The debug_assert enforces the UNIFORM_SLOTS_PER_COMMAND limit; write_buffer is ordered ahead of the caller's submit. ```rust &mut render_pass_builder, params2, images, params1, ); } super::CommandType::Triangles { ref params } => { triangles( &command, &mut pipeline_and_bindgroup_mapper, &mut render_pass_builder, params, images, ); } super::CommandType::RenderFilteredImage { target_image, filter } => match filter { crate::ImageFilter::GaussianBlur { sigma } => { gaussian_blur_filter( &self.device, &mut current_render_target, images, command, sigma, &mut render_pass_builder, &mut pipeline_and_bindgroup_mapper, target_image, ); } crate::ImageFilter::ColorMatrix { matrix } => { color_matrix_filter( &mut current_render_target, images, command, matrix, &mut render_pass_builder, &mut pipeline_and_bindgroup_mapper, target_image, ); } }, } } drop(render_pass_builder); // write_buffer is ordered ahead of the caller's submit. let uniform_staging = &pipeline_and_bindgroup_mapper.uniform_staging; debug_assert!( uniform_staging.len() as u64 <= self.uniform_buffer.size(), "a command recorded more than UNIFORM_SLOTS_PER_COMMAND uniform slots" ); if !uniform_staging.is_empty() { self.queue.write_buffer(&self.uniform_buffer, 0, uniform_staging); } let command_buffer = encoder.finish(); self.pipeline_cache .borrow_mut() .retain(|_, cached_pipeline| std::mem::replace(&mut cached_pipeline.accessed, false)); Some(command_buffer) } ``` -------------------------------- ### Get FontFaceRef without textlayout Source: https://docs.rs/femtovg/latest/src/femtovg/text/font.rs.html Returns a FontFaceRef containing PhantomData when textlayout is disabled. ```rust #[cfg(not(feature = "textlayout"))] pub(crate) fn face_ref(&self) -> FontFaceRef<'_> { FontFaceRef(std::marker::PhantomData) } ``` -------------------------------- ### Create CommandToPipelineAndBindGroupMapper::new Source: https://docs.rs/femtovg/latest/src/femtovg/renderer/wgpu.rs.html Constructs a CommandToPipelineAndBindGroupMapper with the given device, texture view, sampler cache, uniform buffer and stride, shader module, bind group layout, pipeline layout, and pipeline cache. Initializes staging and current state fields to empty or None. ```rust fn new( device: wgpu::Device, empty_texture_view: wgpu::TextureView, sampler_cache: SamplerCache, uniform_buffer: wgpu::Buffer, uniform_stride: u64, shader_module: Rc, bind_group_layout: wgpu::BindGroupLayout, pipeline_layout: wgpu::PipelineLayout, pipeline_cache: Rc>>, ) -> Self { Self { device: device.clone(), empty_texture_view, sampler_cache, uniform_buffer, uniform_stride, uniform_staging: Vec::new(), current_uniforms: None, shader_module, current_bind_group_state: None, current_bind_group: None, bind_group_layout, pipeline_cache, pipeline_layout, } } ``` -------------------------------- ### WGPURenderer::render Source: https://docs.rs/femtovg/latest/femtovg/renderer/struct.WGPURenderer.html Renders the specified commands to the given output. ```APIDOC ## WGPURenderer::render ### Description Renders the specified commands to the given output. ### Method render ### Parameters - **output** (impl Into) - Required - The render output target. - **images** (&mut ImageStore) - Required - The image store containing images to use. - **verts** (&[Vertex]) - Required - The vertex data to render. - **commands** (Vec) - Required - The list of render commands. ### Returns - **Self::CommandBuffer** - The command buffer containing the rendered commands. ``` -------------------------------- ### Test svg_arc_to half-turn arcs return to start and stay on circle Source: https://docs.rs/femtovg/latest/src/femtovg/path.rs.html Tests that two consecutive half-turn arcs (each 180 degrees) return to the starting point and that every sampled point lies on the radius-80 circle centered at (100, 100). The endpoint assertion uses a tolerance of 1e-3 and the residual check uses ELLIPSE_RESIDUAL_TOL. ```rust path.svg_arc_to(80.0, 80.0, 0.0, false, true, 180.0, 100.0); path.svg_arc_to(80.0, 80.0, 0.0, false, true, 20.0, 100.0); let (points, endpoint) = sample_path(&path); assert!( (endpoint.0 - 20.0).abs() < 1e-3 && (endpoint.1 - 100.0).abs() < 1e-3, "the second half turn must return to the start, got {endpoint:?}" ); for (px, py) in points { let resid = ellipse_residual(px, py, 100.0, 100.0, 80.0, 80.0, 0.0); assert!( resid.abs() < ELLIPSE_RESIDUAL_TOL, "point ({px}, {py}) off the radius-80 circle, residual {resid}" ); } ``` -------------------------------- ### solidity Source: https://docs.rs/femtovg/latest/src/femtovg/path.rs.html Sets the current sub-path winding, see Solidity. ```APIDOC ## solidity ### Description Sets the current sub-path winding, see Solidity. ### Method solidity ### Parameters - **solidity** (Solidity) - Required - The winding to set for the current sub-path. ### Returns void ``` -------------------------------- ### debug_inspector_get_font_textures Source: https://docs.rs/femtovg/latest/femtovg/struct.Canvas.html Gets a list of all font textures. This method is only available when the crate feature 'debug_inspector' is enabled. ```APIDOC ## debug_inspector_get_font_textures ### Description Get a list of all font textures. This method is only available when the crate feature `debug_inspector` is enabled. ### Method pub fn debug_inspector_get_font_textures ### Signature pub fn debug_inspector_get_font_textures(&self) -> Vec ### Returns Vec - A list of all font texture image identifiers. ``` -------------------------------- ### Configure wgpu render pass and draw Source: https://docs.rs/femtovg/latest/src/femtovg/renderer/wgpu.rs.html Configures a wgpu render pass with no timestamp writes, occlusion query, or multiview mask, then sets the vertex buffer, viewport, and bind group before storing the render pass. The draw method issues a draw call using the stored render pass. ```rust timestamp_writes: None, occlusion_query_set: None, multiview_mask: None, }); rpass.set_vertex_buffer(0, self.vertex_buffer.slice(..)); rpass.set_viewport(0., 0., self.viewport[0], self.viewport[1], 0., 0.); rpass.set_bind_group(0, &self.viewport_bind_group, &[]); self.rpass = Some(rpass.forget_lifetime()); } fn draw(&mut self, vertices: std::ops::Range) { self.rpass.as_mut().unwrap().draw(vertices, 0..1); } } ``` -------------------------------- ### Paint::conic_gradient_stops Source: https://docs.rs/femtovg/latest/src/femtovg/paint.rs.html Creates a multi-stop conic gradient paint with a default start angle of 0 radians. ```APIDOC ## Paint::conic_gradient_stops ### Description Creates and returns a multi-stop conic gradient. Parameters (`cx`,`cy`) specify the center. The gradient begins at the positive x axis (the 3 o'clock direction) and proceeds clockwise, matching the Canvas 2D `createConicGradient(0, cx, cy)` semantics. ### Method Constructor ### Signature ```rust pub fn conic_gradient_stops(cx: f32, cy: f32, stops: impl IntoIterator) -> Self ``` ### Parameters - **cx** (f32) - Required - The x-coordinate of the center. - **cy** (f32) - Required - The y-coordinate of the center. - **stops** (impl IntoIterator) - Required - A list of color stops with offsets. ### Returns - **Self** - A new `Paint` instance representing the conic gradient. ``` -------------------------------- ### Get FontFaceRef with textlayout Source: https://docs.rs/femtovg/latest/src/femtovg/text/font.rs.html Returns a FontFaceRef by parsing the font data with ttf-parser, panicking on parse failure. Only available with the textlayout feature. ```rust #[cfg(feature = "textlayout")] pub(crate) fn face_ref(&self) -> FontFaceRef<'_> { FontFaceRef(ttf_parser::Face::parse(self.data.as_ref().as_ref(), self.face_index).unwrap()) } ```