diff --git a/Cargo.lock b/Cargo.lock index 164b1e0..f4c0fe2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -357,6 +357,7 @@ name = "avenger" version = "0.0.8" dependencies = [ "image 0.25.5", + "itertools 0.13.0", "lyon_extra", "lyon_path", "pyo3", diff --git a/Cargo.toml b/Cargo.toml index ac9943b..de3723d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -26,4 +26,5 @@ tracing-subscriber = "0.3.18" rayon = "1.8.1" winit = "0.30.5" wgpu = "23.0.1" - +arrow = "53.3.0" +itertools = "0.13.0" \ No newline at end of file diff --git a/avenger-wgpu/Cargo.toml b/avenger-wgpu/Cargo.toml index 4149dc8..59d9ee0 100644 --- a/avenger-wgpu/Cargo.toml +++ b/avenger-wgpu/Cargo.toml @@ -19,7 +19,7 @@ cfg-if = "1" winit = { workspace = true } wgpu = { workspace = true } pollster = "0.4.0" -itertools = "0.13.0" +itertools = { workspace = true } image = { workspace = true } futures-intrusive = "^0.5" etagere = "0.2.10" diff --git a/avenger-wgpu/src/marks/multi.rs b/avenger-wgpu/src/marks/multi.rs index dce242c..52ed8ae 100644 --- a/avenger-wgpu/src/marks/multi.rs +++ b/avenger-wgpu/src/marks/multi.rs @@ -6,15 +6,14 @@ use crate::marks::image::ImageAtlasBuilder; use avenger::marks::area::{AreaMark, AreaOrientation}; use avenger::marks::image::ImageMark; use avenger::marks::line::LineMark; -use avenger::marks::path::{PathMark, PathTransform}; -use avenger::marks::rect::RectMark; +use avenger::marks::path::{PathMark, PathMarkInstance, PathTransform}; +use avenger::marks::rect::{RectMark, RectMarkInstance}; use avenger::marks::rule::RuleMark; use avenger::marks::symbol::SymbolMark; use avenger::marks::trail::TrailMark; use avenger::marks::value::{ColorOrGradient, ImageAlign, ImageBaseline, StrokeCap, StrokeJoin}; use etagere::euclid::UnknownUnit; use image::DynamicImage; -use itertools::izip; use lyon::algorithms::aabb::bounding_box; use lyon::algorithms::measure::{PathMeasurements, PathSampler, SampleType}; use lyon::geom::euclid::{Point2D, Vector2D}; @@ -39,12 +38,12 @@ use wgpu::{ // Import rayon prelude as required by par_izip. use crate::marks::text::{TextAtlasBuilderTrait, TextInstance}; -use avenger::marks::arc::ArcMark; +use avenger::marks::arc::{ArcMark, ArcMarkInstance}; use avenger::marks::group::Clip; use avenger::marks::text::TextMark; #[cfg(feature = "rayon")] -use {crate::par_izip, rayon::prelude::*}; +use rayon::prelude::*; pub const GRADIENT_TEXTURE_CODE: f32 = -1.0; pub const IMAGE_TEXTURE_CODE: f32 = -2.0; @@ -196,139 +195,101 @@ impl MultiMarkRenderer { .gradient_atlas_builder .register_gradients(&mark.gradients); - let verts_inds = if let Some(stroke_dash_iter) = mark.stroke_dash_iter() { - izip!( - stroke_dash_iter, - mark.x0_iter(), - mark.y0_iter(), - mark.x1_iter(), - mark.y1_iter(), - mark.stroke_iter(), - mark.stroke_width_iter(), - mark.stroke_cap_iter(), - ).map(|(stroke_dash, x0, y0, x1, y1, stroke, stroke_width, cap)| -> Result<(Vec, Vec), AvengerWgpuError> { - // Next index into stroke_dash array - let mut dash_idx = 0; - - // Distance along line from (x0,y0) to (x1,y1) where the next dash will start - let mut start_dash_dist: f32 = 0.0; - - // Length of the line from (x0,y0) to (x1,y1) - let rule_len = ((x1 - x0).powi(2) + (y1 - y0).powi(2)).sqrt(); - - // Coponents of unit vector along (x0,y0) to (x1,y1) - let xhat = (x1 - x0) / rule_len; - let yhat = (y1 - y0) / rule_len; - - // Whether the next dash length represents a drawn dash (draw == true) - // or a gap (draw == false) - let mut draw = true; - - // Init path builder - let mut path_builder = lyon::path::Path::builder().with_svg(); - - while start_dash_dist < rule_len { - let end_dash_dist = if start_dash_dist + stroke_dash[dash_idx] >= rule_len { - // The final dash/gap should be truncated to the end of the rule - rule_len + let verts_inds = mark + .instances() + .map( + |instance| -> Result<(Vec, Vec), AvengerWgpuError> { + let mut path_builder = lyon::path::Path::builder().with_svg(); + + if let Some(stroke_dash) = &instance.stroke_dash { + // Next index into stroke_dash array + let mut dash_idx = 0; + + // Distance along line from (x0,y0) to (x1,y1) where the next dash will start + let mut start_dash_dist: f32 = 0.0; + + // Length of the line from (x0,y0) to (x1,y1) + let rule_len = ((instance.x1 - instance.x0).powi(2) + + (instance.y1 - instance.y0).powi(2)) + .sqrt(); + + // Components of unit vector along (x0,y0) to (x1,y1) + let xhat = (instance.x1 - instance.x0) / rule_len; + let yhat = (instance.y1 - instance.y0) / rule_len; + + // Whether the next dash length represents a drawn dash (draw == true) + // or a gap (draw == false) + let mut draw = true; + + while start_dash_dist < rule_len { + let end_dash_dist = + if start_dash_dist + stroke_dash[dash_idx] >= rule_len { + // The final dash/gap should be truncated to the end of the rule + rule_len + } else { + // The dash/gap fits entirely in the rule + start_dash_dist + stroke_dash[dash_idx] + }; + + if draw { + let dash_x0 = instance.x0 + xhat * start_dash_dist; + let dash_y0 = instance.y0 + yhat * start_dash_dist; + let dash_x1 = instance.x0 + xhat * end_dash_dist; + let dash_y1 = instance.y0 + yhat * end_dash_dist; + + path_builder + .move_to(Point::new(dash_x0 + origin[0], dash_y0 + origin[1])); + path_builder + .line_to(Point::new(dash_x1 + origin[0], dash_y1 + origin[1])); + } + + // update start dist for next dash/gap + start_dash_dist = end_dash_dist; + + // increment index and cycle back to start of start of dash array + dash_idx = (dash_idx + 1) % stroke_dash.len(); + + // Alternate between drawn dash and gap + draw = !draw; + } } else { - // The dash/gap fits entirely in the rule - start_dash_dist + stroke_dash[dash_idx] - }; - - if draw { - let dash_x0 = x0 + xhat * start_dash_dist; - let dash_y0 = y0 + yhat * start_dash_dist; - let dash_x1 = x0 + xhat * end_dash_dist; - let dash_y1 = y0 + yhat * end_dash_dist; - - path_builder.move_to(Point::new(dash_x0 + origin[0], dash_y0 + origin[1])); - path_builder.line_to(Point::new(dash_x1 + origin[0], dash_y1 + origin[1])); + path_builder + .move_to(Point::new(instance.x0 + origin[0], instance.y0 + origin[1])); + path_builder + .line_to(Point::new(instance.x1 + origin[0], instance.y1 + origin[1])); } - // update start dist for next dash/gap - start_dash_dist = end_dash_dist; - - // increment index and cycle back to start of start of dash array - dash_idx = (dash_idx + 1) % stroke_dash.len(); - - // Alternate between drawn dash and gap - draw = !draw; - } - - let path = path_builder.build(); - let bbox = bounding_box(&path); - - // Create vertex/index buffer builder - let mut buffers: VertexBuffers = VertexBuffers::new(); - let mut builder = BuffersBuilder::new( - &mut buffers, - VertexPositions { - fill: [0.0, 0.0, 0.0, 0.0], - stroke: to_color_or_gradient_coord(stroke, &grad_coords), - top_left: bbox.min.to_array(), - bottom_right: bbox.max.to_array(), - }, - ); - - // Tesselate stroke - let mut stroke_tessellator = StrokeTessellator::new(); - let stroke_options = StrokeOptions::default() - .with_tolerance(0.05) - .with_line_join(LineJoin::Miter) - .with_line_cap(match cap { - StrokeCap::Butt => LineCap::Butt, - StrokeCap::Round => LineCap::Round, - StrokeCap::Square => LineCap::Square, - }) - .with_line_width(*stroke_width); - stroke_tessellator.tessellate_path(&path, &stroke_options, &mut builder)?; - Ok((buffers.vertices, buffers.indices)) - }).collect::, AvengerWgpuError>>()? - } else { - izip!( - mark.x0_iter(), - mark.y0_iter(), - mark.x1_iter(), - mark.y1_iter(), - mark.stroke_iter(), - mark.stroke_width_iter(), - mark.stroke_cap_iter(), - ).map(|(x0, y0, x1, y1, stroke, stroke_width, cap)| -> Result<(Vec, Vec), AvengerWgpuError> { - let mut path_builder = lyon::path::Path::builder().with_svg(); - path_builder.move_to(Point::new(*x0 + origin[0], *y0 + origin[1])); - path_builder.line_to(Point::new(*x1 + origin[0], *y1 + origin[1])); - let path = path_builder.build(); - let bbox = bounding_box(&path); - - // Create vertex/index buffer builder - let mut buffers: VertexBuffers = VertexBuffers::new(); - let mut builder = BuffersBuilder::new( - &mut buffers, - VertexPositions { - fill: [0.0, 0.0, 0.0, 0.0], - stroke: to_color_or_gradient_coord(stroke, &grad_coords), - top_left: bbox.min.to_array(), - bottom_right: bbox.max.to_array(), - }, - ); + let path = path_builder.build(); + let bbox = bounding_box(&path); - // Tesselate stroke - let mut stroke_tessellator = StrokeTessellator::new(); - let stroke_options = StrokeOptions::default() - .with_tolerance(0.05) - .with_line_join(LineJoin::Miter) - .with_line_cap(match cap { - StrokeCap::Butt => LineCap::Butt, - StrokeCap::Round => LineCap::Round, - StrokeCap::Square => LineCap::Square, - }) - .with_line_width(*stroke_width); - stroke_tessellator.tessellate_path(&path, &stroke_options, &mut builder)?; - Ok((buffers.vertices, buffers.indices)) + // Create vertex/index buffer builder + let mut buffers: VertexBuffers = VertexBuffers::new(); + let mut builder = BuffersBuilder::new( + &mut buffers, + VertexPositions { + fill: [0.0, 0.0, 0.0, 0.0], + stroke: to_color_or_gradient_coord(&instance.stroke, &grad_coords), + top_left: bbox.min.to_array(), + bottom_right: bbox.max.to_array(), + }, + ); - }).collect::, AvengerWgpuError>>()? - }; + // Tesselate stroke + let mut stroke_tessellator = StrokeTessellator::new(); + let stroke_options = StrokeOptions::default() + .with_tolerance(0.05) + .with_line_join(LineJoin::Miter) + .with_line_cap(match instance.stroke_cap { + StrokeCap::Butt => LineCap::Butt, + StrokeCap::Round => LineCap::Round, + StrokeCap::Square => LineCap::Square, + }) + .with_line_width(instance.stroke_width); + stroke_tessellator.tessellate_path(&path, &stroke_options, &mut builder)?; + Ok((buffers.vertices, buffers.indices)) + }, + ) + .collect::, AvengerWgpuError>>()?; let start_ind = self.num_indices(); let inds_len: usize = verts_inds.iter().map(|(_, i)| i.len()).sum(); @@ -369,21 +330,14 @@ impl MultiMarkRenderer { let mut verts: Vec = Vec::with_capacity((mark.len * 4) as usize); let mut indicies: Vec = Vec::with_capacity((mark.len * 6) as usize); - for (i, x, y, width, height, fill) in izip!( - 0..mark.len, - mark.x_iter(), - mark.y_iter(), - mark.width_iter(), - mark.height_iter(), - mark.fill_iter() - ) { - let x0 = *x + origin[0]; - let y0 = *y + origin[1]; - let x1 = x0 + width; - let y1 = y0 + height; + for (i, instance) in (0..mark.len).zip(mark.instances()) { + let x0 = instance.x + origin[0]; + let y0 = instance.y + origin[1]; + let x1 = x0 + instance.width; + let y1 = y0 + instance.height; let top_left = [x0, y0]; let bottom_right = [x1, y1]; - let color = fill.color_or_transparent(); + let color = instance.fill.color_or_transparent(); verts.push(MultiVertex { position: [x0, y0], color, @@ -410,113 +364,86 @@ impl MultiMarkRenderer { }); let offset = i * 4; indicies.extend([ - offset, - offset + 1, - offset + 2, - offset, - offset + 2, - offset + 3, + offset as u32, + offset as u32 + 1, + offset as u32 + 2, + offset as u32, + offset as u32 + 2, + offset as u32 + 3, ]) } vec![(verts, indicies)] } else { // General rects - let build_verts_inds = - |x: &f32, - y: &f32, - width: &f32, - height: &f32, - fill: &ColorOrGradient, - stroke: &ColorOrGradient, - stroke_width: &f32, - corner_radius: &f32| - -> Result<(Vec, Vec), AvengerWgpuError> { - // Create rect path - let mut path_builder = lyon::path::Path::builder(); - let x0 = *x + origin[0]; - let y0 = *y + origin[1]; - let x1 = x0 + width; - let y1 = y0 + height; - if *corner_radius > 0.0 { - path_builder.add_rounded_rectangle( - &Box2D::new(Point2D::new(x0, y0), Point2D::new(x1, y1)), - &BorderRadii { - top_left: *corner_radius, - top_right: *corner_radius, - bottom_left: *corner_radius, - bottom_right: *corner_radius, - }, - Winding::Positive, - ); - } else { - path_builder.add_rectangle( - &Box2D::new(Point2D::new(x0, y0), Point2D::new(x1, y1)), - Winding::Positive, - ); - } - - // Apply transform to path - let path = path_builder.build(); - let bbox = bounding_box(&path); - - // Create vertex/index buffer builder - let mut buffers: VertexBuffers = VertexBuffers::new(); - let mut builder = BuffersBuilder::new( - &mut buffers, - VertexPositions { - fill: to_color_or_gradient_coord(fill, &grad_coords), - stroke: to_color_or_gradient_coord(stroke, &grad_coords), - top_left: bbox.min.to_array(), - bottom_right: bbox.max.to_array(), + let build_verts_inds = |instance: &RectMarkInstance| -> Result<(Vec, Vec), AvengerWgpuError> { + // Create rect path + let mut path_builder = lyon::path::Path::builder(); + let x0 = instance.x + origin[0]; + let y0 = instance.y + origin[1]; + let x1 = x0 + instance.width; + let y1 = y0 + instance.height; + if instance.corner_radius > 0.0 { + path_builder.add_rounded_rectangle( + &Box2D::new(Point2D::new(x0, y0), Point2D::new(x1, y1)), + &BorderRadii { + top_left: instance.corner_radius, + top_right: instance.corner_radius, + bottom_left: instance.corner_radius, + bottom_right: instance.corner_radius, }, + Winding::Positive, + ); + } else { + path_builder.add_rectangle( + &Box2D::new(Point2D::new(x0, y0), Point2D::new(x1, y1)), + Winding::Positive, ); + } - // Tesselate fill - let mut fill_tessellator = FillTessellator::new(); - let fill_options = FillOptions::default().with_tolerance(0.05); + // Apply transform to path + let path = path_builder.build(); + let bbox = bounding_box(&path); - fill_tessellator.tessellate_path(&path, &fill_options, &mut builder)?; + // Create vertex/index buffer builder + let mut buffers: VertexBuffers = VertexBuffers::new(); + let mut builder = BuffersBuilder::new( + &mut buffers, + VertexPositions { + fill: to_color_or_gradient_coord(&instance.fill, &grad_coords), + stroke: to_color_or_gradient_coord(&instance.stroke, &grad_coords), + top_left: bbox.min.to_array(), + bottom_right: bbox.max.to_array(), + }, + ); - // Tesselate stroke - if *stroke_width > 0.0 { - let mut stroke_tessellator = StrokeTessellator::new(); - let stroke_options = StrokeOptions::default() - .with_tolerance(0.05) - .with_line_width(*stroke_width); - stroke_tessellator.tessellate_path(&path, &stroke_options, &mut builder)?; - } + // Tesselate fill + let mut fill_tessellator = FillTessellator::new(); + let fill_options = FillOptions::default().with_tolerance(0.05); - Ok((buffers.vertices, buffers.indices)) - }; + fill_tessellator.tessellate_path(&path, &fill_options, &mut builder)?; + + // Tesselate stroke + if instance.stroke_width > 0.0 { + let mut stroke_tessellator = StrokeTessellator::new(); + let stroke_options = StrokeOptions::default() + .with_tolerance(0.05) + .with_line_width(instance.stroke_width); + stroke_tessellator.tessellate_path(&path, &stroke_options, &mut builder)?; + } + + Ok((buffers.vertices, buffers.indices)) + }; cfg_if::cfg_if! { if #[cfg(feature = "rayon")] { - par_izip!( - mark.x_vec(), - mark.y_vec(), - mark.width_vec(), - mark.height_vec(), - mark.fill_vec(), - mark.stroke_vec(), - mark.stroke_width_vec(), - mark.corner_radius_vec(), - ).map(|(x, y, width, height, fill, stroke, stroke_width, corner_radius)| -> Result<(Vec, Vec), AvengerWgpuError> { - build_verts_inds(x, &y, &width, &height, &fill, &stroke, &stroke_width, &corner_radius) - }).collect::, AvengerWgpuError>>()? + mark.instances().collect::>().into_par_iter() + .map(|instance| build_verts_inds(&instance)) + .collect::, AvengerWgpuError>>()? } else { - izip!( - mark.x_iter(), - mark.y_iter(), - mark.width_iter(), - mark.height_iter(), - mark.fill_iter(), - mark.stroke_iter(), - mark.stroke_width_iter(), - mark.corner_radius_iter(), - ).map(|(x, y, width, height, fill, stroke, stroke_width, corner_radius)| -> Result<(Vec, Vec), AvengerWgpuError> { - build_verts_inds(x, y, width, height, fill, stroke, stroke_width, corner_radius) - }).collect::, AvengerWgpuError>>()? + mark.instances() + .map(|instance| build_verts_inds(&instance)) + .collect::, AvengerWgpuError>>()? } } }; @@ -550,15 +477,12 @@ impl MultiMarkRenderer { .gradient_atlas_builder .register_gradients(&mark.gradients); - let build_verts_inds = |path: &lyon::path::Path, - fill: &ColorOrGradient, - stroke: &ColorOrGradient, - transform: &PathTransform| + let build_verts_inds = |instance: &PathMarkInstance| -> Result<(Vec, Vec), AvengerWgpuError> { // Apply transform to path - let path = path + let path = instance.path .clone() - .transformed(&transform.then_translate(Vector2D::new(origin[0], origin[1]))); + .transformed(&instance.transform.then_translate(Vector2D::new(origin[0], origin[1]))); let bbox = bounding_box(&path); // Create vertex/index buffer builder @@ -566,8 +490,8 @@ impl MultiMarkRenderer { let mut builder = BuffersBuilder::new( &mut buffers, crate::marks::multi::VertexPositions { - fill: to_color_or_gradient_coord(fill, &grad_coords), - stroke: to_color_or_gradient_coord(stroke, &grad_coords), + fill: to_color_or_gradient_coord(&instance.fill, &grad_coords), + stroke: to_color_or_gradient_coord(&instance.stroke, &grad_coords), top_left: bbox.min.to_array(), bottom_right: bbox.max.to_array(), }, @@ -603,23 +527,13 @@ impl MultiMarkRenderer { cfg_if::cfg_if! { if #[cfg(feature = "rayon")] { - let verts_inds = par_izip!( - mark.path_vec(), - mark.fill_vec(), - mark.stroke_vec(), - mark.transform_vec(), - ).map(|(path, fill, stroke, transform)| -> Result<(Vec, Vec), AvengerWgpuError> { - build_verts_inds(path, &fill, &stroke, &transform) - }).collect::, AvengerWgpuError>>()?; + let verts_inds = mark.instances().collect::>().into_par_iter() + .map(|instance| build_verts_inds(&instance)) + .collect::, AvengerWgpuError>>()?; } else { - let verts_inds = izip!( - mark.path_iter(), - mark.fill_iter(), - mark.stroke_iter(), - mark.transform_iter(), - ).map(|(path, fill, stroke, transform)| -> Result<(Vec, Vec), AvengerWgpuError> { - build_verts_inds(path, fill, stroke, transform) - }).collect::, AvengerWgpuError>>()?; + let verts_inds = mark.instances() + .map(|instance| build_verts_inds(&instance)) + .collect::, AvengerWgpuError>>()?; } } @@ -727,28 +641,13 @@ impl MultiMarkRenderer { cfg_if::cfg_if! { if #[cfg(feature = "rayon")] { - let verts_inds = par_izip!( - mark.x_vec(), - mark.y_vec(), - mark.fill_vec(), - mark.size_vec(), - mark.stroke_vec(), - mark.angle_vec(), - mark.shape_index_vec(), - ).map(|(x, y, fill, size, stroke, angle, shape_index)| -> Result<(Vec, Vec), AvengerWgpuError> { - build_verts_inds(x, &y, &fill, &size, &stroke, &angle, &shape_index) + let verts_inds = mark.instances().collect::>().into_par_iter() + .map(|instance| { + build_verts_inds(&instance.x, &instance.y, &instance.fill, &instance.size, &instance.stroke, &instance.angle, &instance.shape_index) }).collect::, AvengerWgpuError>>()?; } else { - let verts_inds = izip!( - mark.x_iter(), - mark.y_iter(), - mark.fill_iter(), - mark.size_iter(), - mark.stroke_iter(), - mark.angle_iter(), - mark.shape_index_iter(), - ).map(|(x, y, fill, size, stroke, angle, shape_index)| -> Result<(Vec, Vec), AvengerWgpuError> { - build_verts_inds(x, y, fill, size, stroke, angle, shape_index) + let verts_inds = mark.instances().map(|instance| { + build_verts_inds(&instance.x, &instance.y, &instance.fill, &instance.size, &instance.stroke, &instance.angle, &instance.shape_index) }).collect::, AvengerWgpuError>>()?; } }; @@ -787,14 +686,20 @@ impl MultiMarkRenderer { // Build path for each defined line segment let mut path_builder = lyon::path::Path::builder().with_svg(); let mut path_len = 0; - for (x, y, defined) in izip!(mark.x_iter(), mark.y_iter(), mark.defined_iter()) { - if *defined { + for instance in mark.instances() { + if instance.defined { if path_len > 0 { // Continue path - path_builder.line_to(lyon::geom::point(*x + origin[0], *y + origin[1])); + path_builder.line_to(lyon::geom::point( + instance.x + origin[0], + instance.y + origin[1], + )); } else { // New path - path_builder.move_to(lyon::geom::point(*x + origin[0], *y + origin[1])); + path_builder.move_to(lyon::geom::point( + instance.x + origin[0], + instance.y + origin[1], + )); } path_len += 1; } else { @@ -943,45 +848,41 @@ impl MultiMarkRenderer { b.close(); } - if mark.orientation == AreaOrientation::Vertical { - for (x, y, y2, defined) in izip!( - mark.x_iter(), - mark.y_iter(), - mark.y2_iter(), - mark.defined_iter(), - ) { - if *defined { + for instance in mark.instances() { + if instance.defined { + if mark.orientation == AreaOrientation::Vertical { if !tail.is_empty() { // Continue path - path_builder.line_to(lyon::geom::point(*x + origin[0], *y + origin[1])); + path_builder.line_to(lyon::geom::point( + instance.x + origin[0], + instance.y + origin[1], + )); } else { // New path - path_builder.move_to(lyon::geom::point(*x + origin[0], *y + origin[1])); + path_builder.move_to(lyon::geom::point( + instance.x + origin[0], + instance.y + origin[1], + )); } - tail.push((*x + origin[0], *y2 + origin[1])); + tail.push((instance.x + origin[0], instance.y2 + origin[1])); } else { - close_area(&mut path_builder, &mut tail); - } - } - } else { - for (y, x, x2, defined) in izip!( - mark.y_iter(), - mark.x_iter(), - mark.x2_iter(), - mark.defined_iter(), - ) { - if *defined { if !tail.is_empty() { // Continue path - path_builder.line_to(lyon::geom::point(*x + origin[0], *y + origin[1])); + path_builder.line_to(lyon::geom::point( + instance.x + origin[0], + instance.y + origin[1], + )); } else { // New path - path_builder.move_to(lyon::geom::point(*x + origin[0], *y + origin[1])); + path_builder.move_to(lyon::geom::point( + instance.x + origin[0], + instance.y + origin[1], + )); } - tail.push((*x2 + origin[0], *y + origin[1])); - } else { - close_area(&mut path_builder, &mut tail); + tail.push((instance.x2 + origin[0], instance.y + origin[1])); } + } else { + close_area(&mut path_builder, &mut tail); } } @@ -1056,20 +957,20 @@ impl MultiMarkRenderer { let size_idx: AttributeIndex = 0; let mut path_builder = lyon::path::Path::builder_with_attributes(1); let mut path_len = 0; - for (x, y, size, defined) in izip!( - mark.x_iter(), - mark.y_iter(), - mark.size_iter(), - mark.defined_iter() - ) { - if *defined { + for instance in mark.instances() { + if instance.defined { if path_len > 0 { // Continue path - path_builder - .line_to(lyon::geom::point(*x + origin[0], *y + origin[1]), &[*size]); + path_builder.line_to( + lyon::geom::point(instance.x + origin[0], instance.y + origin[1]), + &[instance.size], + ); } else { // New path - path_builder.begin(lyon::geom::point(*x + origin[0], *y + origin[1]), &[*size]); + path_builder.begin( + lyon::geom::point(instance.x + origin[0], instance.y + origin[1]), + &[instance.size], + ); } path_len += 1; } else { @@ -1085,8 +986,6 @@ impl MultiMarkRenderer { } path_builder.end(false); - // let bbox = bounding_box(&path); - let path = path_builder.build(); let bbox = bounding_box(&path); @@ -1139,120 +1038,112 @@ impl MultiMarkRenderer { .gradient_atlas_builder .register_gradients(&mark.gradients); - let verts_inds = izip!( - mark.x_iter(), - mark.y_iter(), - mark.start_angle_iter(), - mark.end_angle_iter(), - mark.outer_radius_iter(), - mark.inner_radius_iter(), - mark.fill_iter(), - mark.stroke_iter(), - mark.stroke_width_iter(), - ) - .map( - |( - x, - y, - start_angle, - end_angle, - outer_radius, - inner_radius, - fill, - stroke, - stroke_width, - )| - -> Result<(Vec, Vec), AvengerWgpuError> { - // Compute angle - let total_angle = end_angle - start_angle; - - // Normalize inner/outer radius - let (inner_radius, outer_radius) = if *inner_radius > *outer_radius { - (*outer_radius, *inner_radius) - } else { - (*inner_radius, *outer_radius) - }; + let verts_inds = mark + .instances() + .map( + |ArcMarkInstance { + x, + y, + start_angle, + end_angle, + outer_radius, + inner_radius, + fill_color, + stroke_color, + stroke_width, + .. + }| + -> Result<(Vec, Vec), AvengerWgpuError> { + // Compute angle + let total_angle = end_angle - start_angle; - let mut path_builder = lyon::path::Path::builder().with_svg(); + // Normalize inner/outer radius + let (inner_radius, outer_radius) = if inner_radius > outer_radius { + (outer_radius, inner_radius) + } else { + (inner_radius, outer_radius) + }; - // Orient arc starting along vertical y-axis - path_builder.move_to(lyon::geom::Point::new(0.0, -inner_radius)); - path_builder.line_to(lyon::geom::Point::new(0.0, -outer_radius)); + let mut path_builder = lyon::path::Path::builder().with_svg(); - // Draw outer arc - path_builder.arc( - lyon::geom::Point::new(0.0, 0.0), - lyon::math::Vector::new(outer_radius, outer_radius), - lyon::geom::Angle::radians(total_angle), - lyon::geom::Angle::radians(0.0), - ); + // Orient arc starting along vertical y-axis + path_builder.move_to(lyon::geom::Point::new(0.0, -inner_radius)); + path_builder.line_to(lyon::geom::Point::new(0.0, -outer_radius)); - if inner_radius != 0.0 { - // Compute vector from outer arc corner to arc corner - let inner_radius_vec = path_builder - .current_position() - .to_vector() - .neg() - .normalize() - .mul(outer_radius - inner_radius); - path_builder.relative_line_to(inner_radius_vec); - - // Draw inner + // Draw outer arc path_builder.arc( lyon::geom::Point::new(0.0, 0.0), - lyon::math::Vector::new(inner_radius, inner_radius), - lyon::geom::Angle::radians(-total_angle), + lyon::math::Vector::new(outer_radius, outer_radius), + lyon::geom::Angle::radians(total_angle), lyon::geom::Angle::radians(0.0), ); - } else { - // Draw line back to origin - path_builder.line_to(lyon::geom::Point::new(0.0, 0.0)); - } - path_builder.close(); - let path = path_builder.build(); + if inner_radius != 0.0 { + // Compute vector from outer arc corner to arc corner + let inner_radius_vec = path_builder + .current_position() + .to_vector() + .neg() + .normalize() + .mul(outer_radius - inner_radius); + path_builder.relative_line_to(inner_radius_vec); + + // Draw inner + path_builder.arc( + lyon::geom::Point::new(0.0, 0.0), + lyon::math::Vector::new(inner_radius, inner_radius), + lyon::geom::Angle::radians(-total_angle), + lyon::geom::Angle::radians(0.0), + ); + } else { + // Draw line back to origin + path_builder.line_to(lyon::geom::Point::new(0.0, 0.0)); + } - // Transform path to account for start angle and position - let path = path.transformed( - &PathTransform::rotation(lyon::geom::Angle::radians(*start_angle)) - .then_translate(Vector2D::new(*x + origin[0], *y + origin[1])), - ); + path_builder.close(); + let path = path_builder.build(); - // Compute bounding box - let bbox = bounding_box(&path); + // Transform path to account for start angle and position + let path = path.transformed( + &PathTransform::rotation(lyon::geom::Angle::radians(start_angle)) + .then_translate(Vector2D::new(x + origin[0], y + origin[1])), + ); - // Create vertex/index buffer builder - let mut buffers: VertexBuffers = VertexBuffers::new(); - let mut builder = BuffersBuilder::new( - &mut buffers, - VertexPositions { - fill: to_color_or_gradient_coord(fill, &grad_coords), - stroke: to_color_or_gradient_coord(stroke, &grad_coords), - top_left: bbox.min.to_array(), - bottom_right: bbox.max.to_array(), - }, - ); + // Compute bounding box + let bbox = bounding_box(&path); - // Tesselate fill - let mut fill_tessellator = FillTessellator::new(); - let fill_options = FillOptions::default().with_tolerance(0.05); - fill_tessellator.tessellate_path(&path, &fill_options, &mut builder)?; + // Create vertex/index buffer builder + let mut buffers: VertexBuffers = VertexBuffers::new(); + let mut builder = BuffersBuilder::new( + &mut buffers, + VertexPositions { + fill: to_color_or_gradient_coord(&fill_color, &grad_coords), + stroke: to_color_or_gradient_coord(&stroke_color, &grad_coords), + top_left: bbox.min.to_array(), + bottom_right: bbox.max.to_array(), + }, + ); - // Tesselate stroke - if *stroke_width > 0.0 { - let mut stroke_tessellator = StrokeTessellator::new(); - let stroke_options = StrokeOptions::default() - .with_tolerance(0.05) - .with_line_join(LineJoin::Miter) - .with_line_cap(LineCap::Butt) - .with_line_width(*stroke_width); - stroke_tessellator.tessellate_path(&path, &stroke_options, &mut builder)?; - } + // Tessellate fill + let mut fill_tessellator = FillTessellator::new(); + let fill_options = FillOptions::default().with_tolerance(0.05); + fill_tessellator.tessellate_path(&path, &fill_options, &mut builder)?; - Ok((buffers.vertices, buffers.indices)) - }, - ) - .collect::, AvengerWgpuError>>()?; + // Tessellate stroke + if stroke_width > 0.0 { + let mut stroke_tessellator = StrokeTessellator::new(); + let stroke_options = StrokeOptions::default() + .with_tolerance(0.05) + .with_line_join(LineJoin::Miter) + .with_line_cap(LineCap::Butt) + .with_line_width(stroke_width); + stroke_tessellator.tessellate_path(&path, &stroke_options, &mut builder)?; + } + + Ok((buffers.vertices, buffers.indices)) + }, + ) + .collect::, AvengerWgpuError>>()?; let start_ind = self.num_indices(); let inds_len: usize = verts_inds.iter().map(|(_, i)| i.len()).sum(); @@ -1279,96 +1170,96 @@ impl MultiMarkRenderer { origin: [f32; 2], clip: &Clip, ) -> Result<(), AvengerWgpuError> { - let verts_inds = izip!( - mark.image_iter(), - mark.x_iter(), - mark.y_iter(), - mark.width_iter(), - mark.height_iter(), - mark.baseline_iter(), - mark.align_iter(), - ).map(|(img, x, y, width, height, baseline, align)| -> Result<(usize, Vec, Vec), AvengerWgpuError> { - let x = *x + origin[0]; - let y = *y + origin[1]; - - let Some(rgba_image) = img.to_image() else { - return Err(AvengerWgpuError::ConversionError("Failed to convert raw image to rgba image".to_string())) - }; + let verts_inds = mark + .instances() + .map( + |instance| -> Result<(usize, Vec, Vec), AvengerWgpuError> { + let x = instance.x + origin[0]; + let y = instance.y + origin[1]; + + let Some(rgba_image) = instance.image.to_image() else { + return Err(AvengerWgpuError::ConversionError( + "Failed to convert raw image to rgba image".to_string(), + )); + }; - let (atlas_index, tex_coords) = self.image_atlas_builder.register_image(&rgba_image)?; + let (atlas_index, tex_coords) = + self.image_atlas_builder.register_image(&rgba_image)?; - // Compute image left - let left = match *align { - ImageAlign::Left => x, - ImageAlign::Center => x - *width / 2.0, - ImageAlign::Right => x - *width, - }; + // Compute image left + let left = match instance.align { + ImageAlign::Left => x, + ImageAlign::Center => x - instance.width / 2.0, + ImageAlign::Right => x - instance.width, + }; - // Compute image top - let top = match *baseline { - ImageBaseline::Top => y, - ImageBaseline::Middle => y - *height / 2.0, - ImageBaseline::Bottom => y - *height, - }; + // Compute image top + let top = match instance.baseline { + ImageBaseline::Top => y, + ImageBaseline::Middle => y - instance.height / 2.0, + ImageBaseline::Bottom => y - instance.height, + }; - // Adjust position and dimensions if aspect ratio should be preserved - let (left, top, width, height) = if mark.aspect { - let img_aspect = img.width as f32 / img.height as f32; - let outline_aspect = *width / *height; - if img_aspect > outline_aspect { - // image is wider than the box, so we scale - // image to box width and center vertically - let aspect_height = *width / img_aspect; - let aspect_top = top + (*height - aspect_height) / 2.0; - (left, aspect_top, *width, aspect_height) - } else if img_aspect < outline_aspect { - // image is taller than the box, so we scale - // image to box height an center horizontally - let aspect_width = *height * img_aspect; - let aspect_left = left + (*width - aspect_width) / 2.0; - (aspect_left, top, aspect_width, *height) - } else { - (left, top, *width, *height) - } - } else { - (left, top, *width, *height) - }; + // Adjust position and dimensions if aspect ratio should be preserved + let (left, top, width, height) = if mark.aspect { + let img_aspect = instance.image.width as f32 / instance.image.height as f32; + let outline_aspect = instance.width / instance.height; + if img_aspect > outline_aspect { + // image is wider than the box, so we scale + // image to box width and center vertically + let aspect_height = instance.width / img_aspect; + let aspect_top = top + (instance.height - aspect_height) / 2.0; + (left, aspect_top, instance.width, aspect_height) + } else if img_aspect < outline_aspect { + // image is taller than the box, so we scale + // image to box height an center horizontally + let aspect_width = instance.height * img_aspect; + let aspect_left = left + (instance.width - aspect_width) / 2.0; + (aspect_left, top, aspect_width, instance.height) + } else { + (left, top, instance.width, instance.height) + } + } else { + (left, top, instance.width, instance.height) + }; - let top_left = [top, left]; - let bottom_right = [top + height, left + width]; - let verts = vec![ - // Upper left - MultiVertex { - color: [IMAGE_TEXTURE_CODE, tex_coords.x0, tex_coords.y0, 0.0], - position: [left, top], - top_left, - bottom_right, - }, - // Lower left - MultiVertex { - color: [IMAGE_TEXTURE_CODE, tex_coords.x0, tex_coords.y1, 0.0], - position: [left, top + height], - top_left, - bottom_right, - }, - // Lower right - MultiVertex { - color: [IMAGE_TEXTURE_CODE, tex_coords.x1, tex_coords.y1, 0.0], - position: [left + width, top + height], - top_left, - bottom_right, - }, - // Upper right - MultiVertex { - color: [IMAGE_TEXTURE_CODE, tex_coords.x1, tex_coords.y0, 0.0], - position: [left + width, top], - top_left, - bottom_right, + let top_left = [top, left]; + let bottom_right = [top + height, left + width]; + let verts = vec![ + // Upper left + MultiVertex { + color: [IMAGE_TEXTURE_CODE, tex_coords.x0, tex_coords.y0, 0.0], + position: [left, top], + top_left, + bottom_right, + }, + // Lower left + MultiVertex { + color: [IMAGE_TEXTURE_CODE, tex_coords.x0, tex_coords.y1, 0.0], + position: [left, top + height], + top_left, + bottom_right, + }, + // Lower right + MultiVertex { + color: [IMAGE_TEXTURE_CODE, tex_coords.x1, tex_coords.y1, 0.0], + position: [left + width, top + height], + top_left, + bottom_right, + }, + // Upper right + MultiVertex { + color: [IMAGE_TEXTURE_CODE, tex_coords.x1, tex_coords.y0, 0.0], + position: [left + width, top], + top_left, + bottom_right, + }, + ]; + let indices: Vec = vec![0, 1, 2, 0, 2, 3]; + Ok((atlas_index, verts, indices)) }, - ]; - let indices: Vec = vec![0, 1, 2, 0, 2, 3]; - Ok((atlas_index, verts, indices)) - }).collect::, AvengerWgpuError>>()?; + ) + .collect::, AvengerWgpuError>>()?; // Construct batches, one batch per image atlas index let start_ind = self.num_indices() as u32; @@ -1418,63 +1309,37 @@ impl MultiMarkRenderer { origin: [f32; 2], clip: &Clip, ) -> Result<(), AvengerWgpuError> { - let registrations = izip!( - mark.text_iter(), - mark.x_iter(), - mark.y_iter(), - mark.color_iter(), - mark.align_iter(), - mark.angle_iter(), - mark.baseline_iter(), - mark.font_iter(), - mark.font_size_iter(), - mark.font_weight_iter(), - mark.font_style_iter(), - mark.limit_iter(), - ) - .map( - |( - text, - x, - y, - color, - align, - angle, - baseline, - font, - font_size, - font_weight, - font_style, - limit, - )| { - let instance = TextInstance { - text, - position: [*x + origin[0], *y + origin[1]], - color, - align, - angle: *angle, - baseline, - font, - font_size: *font_size, - font_weight, - font_style, - limit: *limit, - }; - self.text_atlas_builder - .register_text(instance, self.dimensions) - }, - ) - .collect::, AvengerWgpuError>>()? - .into_iter() - .flatten() - .collect::>(); + let clip_indices_range = self.add_clip_path(clip, mark.clip)?; + let clipped = if mark.clip { clip.clone() } else { Clip::None }; + + let mut registrations = Vec::new(); + for instance in mark.instances() { + let text_instance = TextInstance { + text: &instance.text, + position: [instance.x + origin[0], instance.y + origin[1]], + color: &instance.color, + align: &instance.align, + angle: instance.angle, + baseline: &instance.baseline, + font: &instance.font, + font_size: instance.font_size, + font_weight: &instance.font_weight, + font_style: &instance.font_style, + limit: instance.limit, + }; + + let registration = self + .text_atlas_builder + .register_text(text_instance, self.dimensions)?; + registrations.extend(registration); + } // Construct batches, one batch per text atlas index let start_ind = self.num_indices() as u32; let mut next_batch = MultiMarkBatch { indices_range: start_ind..start_ind, - clip: clip.maybe_clip(mark.clip), - clip_indices_range: self.add_clip_path(clip, mark.clip)?, + clip: clipped.clone(), + clip_indices_range: clip_indices_range.clone(), image_atlas_index: None, gradient_atlas_index: None, text_atlas_index: None, @@ -1485,7 +1350,6 @@ impl MultiMarkRenderer { let verts = registration.verts; let inds = registration.indices; - // (atlas_index, verts, inds) if next_batch.text_atlas_index.unwrap_or(atlas_index) == atlas_index { // update next batch with atlas index and inds range next_batch.text_atlas_index = Some(atlas_index); @@ -1497,8 +1361,8 @@ impl MultiMarkRenderer { // Initialize new next_batch and swap to avoid extra mem copy let mut full_batch = MultiMarkBatch { indices_range: start_ind..(start_ind + inds.len() as u32), - clip: clip.maybe_clip(mark.clip), - clip_indices_range: self.add_clip_path(clip, mark.clip)?, + clip: clipped.clone(), + clip_indices_range: clip_indices_range.clone(), image_atlas_index: None, gradient_atlas_index: None, text_atlas_index: Some(atlas_index), @@ -1511,7 +1375,10 @@ impl MultiMarkRenderer { self.verts_inds.push((verts, inds)) } - self.batches.push(next_batch); + // Only push the last batch if it contains any indices + if next_batch.indices_range.start < next_batch.indices_range.end { + self.batches.push(next_batch); + } Ok(()) } diff --git a/avenger-wgpu/src/marks/symbol.rs b/avenger-wgpu/src/marks/symbol.rs index f929dff..e3b4b12 100644 --- a/avenger-wgpu/src/marks/symbol.rs +++ b/avenger-wgpu/src/marks/symbol.rs @@ -3,7 +3,6 @@ use crate::error::AvengerWgpuError; use crate::marks::instanced_mark::{InstancedMarkBatch, InstancedMarkShader}; use avenger::marks::path::PathTransform; use avenger::marks::symbol::SymbolMark; -use itertools::izip; use lyon::lyon_tessellation::{ BuffersBuilder, FillVertex, FillVertexConstructor, StrokeVertex, StrokeVertexConstructor, }; @@ -62,7 +61,7 @@ impl SymbolVertex { #[repr(C)] #[derive(Copy, Clone, Debug, bytemuck::Pod, bytemuck::Zeroable)] -pub struct SymbolInstance { +pub struct SymbolShaderInstance { pub position: [f32; 2], pub fill_color: [f32; 4], pub stroke_color: [f32; 4], @@ -84,31 +83,28 @@ const INSTANCE_ATTRIBUTES: [wgpu::VertexAttribute; 7] = wgpu::vertex_attr_array! 10 => Uint32, // shape_index ]; -impl SymbolInstance { +impl SymbolShaderInstance { pub fn from_spec( mark: &SymbolMark, max_size: f32, - ) -> (Vec, Option, Extent3d) { + ) -> ( + Vec, + Option, + Extent3d, + ) { let max_scale = max_size.sqrt(); let stroke_width = mark.stroke_width.unwrap_or(0.0); - let mut instances: Vec = Vec::new(); - for (x, y, fill, size, stroke, angle, shape_index) in izip!( - mark.x_iter(), - mark.y_iter(), - mark.fill_iter(), - mark.size_iter(), - mark.stroke_iter(), - mark.angle_iter(), - mark.shape_index_iter(), - ) { - instances.push(SymbolInstance { - position: [*x, *y], - fill_color: fill.color_or_transparent(), - stroke_color: stroke.color_or_transparent(), - stroke_width, - relative_scale: (*size).sqrt() / max_scale, - angle: *angle, - shape_index: (*shape_index) as u32, + let mut instances: Vec = Vec::new(); + + for instance in mark.instances() { + instances.push(SymbolShaderInstance { + position: [instance.x, instance.y], + fill_color: instance.fill.color_or_transparent(), + stroke_color: instance.stroke.color_or_transparent(), + stroke_width: stroke_width, + relative_scale: (instance.size).sqrt() / max_scale, + angle: instance.angle, + shape_index: (instance.shape_index) as u32, }); } @@ -119,7 +115,7 @@ impl SymbolInstance { pub struct SymbolShader { verts: Vec, indices: Vec, - instances: Vec, + instances: Vec, uniform: SymbolUniform, batches: Vec, texture_size: Extent3d, @@ -170,7 +166,7 @@ impl SymbolShader { verts.extend(buffers.vertices); indices.extend(buffers.indices.into_iter().map(|i| i + index_offset)); } - let (instances, img, texture_size) = SymbolInstance::from_spec(mark, max_size); + let (instances, img, texture_size) = SymbolShaderInstance::from_spec(mark, max_size); let batches = vec![InstancedMarkBatch { instances_range: 0..instances.len() as u32, image: img, @@ -190,7 +186,7 @@ impl SymbolShader { } impl InstancedMarkShader for SymbolShader { - type Instance = SymbolInstance; + type Instance = SymbolShaderInstance; type Vertex = SymbolVertex; type Uniform = SymbolUniform; @@ -232,7 +228,7 @@ impl InstancedMarkShader for SymbolShader { fn instance_desc(&self) -> wgpu::VertexBufferLayout<'static> { wgpu::VertexBufferLayout { - array_stride: std::mem::size_of::() as wgpu::BufferAddress, + array_stride: std::mem::size_of::() as wgpu::BufferAddress, step_mode: wgpu::VertexStepMode::Instance, attributes: &INSTANCE_ATTRIBUTES, } diff --git a/avenger/Cargo.toml b/avenger/Cargo.toml index 8fae475..338eed6 100644 --- a/avenger/Cargo.toml +++ b/avenger/Cargo.toml @@ -18,6 +18,9 @@ workspace = true workspace = true features = [ "serialization",] +[dependencies.itertools] +workspace = true + [dependencies.image] workspace = true features = [ "png",] diff --git a/avenger/src/marks/arc.rs b/avenger/src/marks/arc.rs index a113351..851b76a 100644 --- a/avenger/src/marks/arc.rs +++ b/avenger/src/marks/arc.rs @@ -1,4 +1,5 @@ use crate::marks::value::{ColorOrGradient, EncodingValue, Gradient}; +use itertools::izip; use serde::{Deserialize, Serialize}; #[derive(Debug, Clone, Serialize, Deserialize)] @@ -8,6 +9,10 @@ pub struct ArcMark { pub clip: bool, pub len: u32, pub gradients: Vec, + pub indices: Option>, + pub zindex: Option, + + // Encodings pub x: EncodingValue, pub y: EncodingValue, pub start_angle: EncodingValue, @@ -19,78 +24,133 @@ pub struct ArcMark { pub fill: EncodingValue, pub stroke: EncodingValue, pub stroke_width: EncodingValue, - pub indices: Option>, - pub zindex: Option, } impl ArcMark { - pub fn x_iter(&self) -> Box + '_> { - self.x.as_iter(self.len as usize, self.indices.as_ref()) - } - pub fn y_iter(&self) -> Box + '_> { - self.y.as_iter(self.len as usize, self.indices.as_ref()) - } - pub fn start_angle_iter(&self) -> Box + '_> { - self.start_angle - .as_iter(self.len as usize, self.indices.as_ref()) - } - pub fn end_angle_iter(&self) -> Box + '_> { - self.end_angle - .as_iter(self.len as usize, self.indices.as_ref()) - } - pub fn outer_radius_iter(&self) -> Box + '_> { - self.outer_radius - .as_iter(self.len as usize, self.indices.as_ref()) - } - pub fn inner_radius_iter(&self) -> Box + '_> { - self.inner_radius - .as_iter(self.len as usize, self.indices.as_ref()) - } - pub fn pad_angle_iter(&self) -> Box + '_> { - self.pad_angle - .as_iter(self.len as usize, self.indices.as_ref()) - } - pub fn corner_radius_iter(&self) -> Box + '_> { - self.corner_radius - .as_iter(self.len as usize, self.indices.as_ref()) - } - pub fn fill_iter(&self) -> Box + '_> { - self.fill.as_iter(self.len as usize, self.indices.as_ref()) - } - pub fn stroke_iter(&self) -> Box + '_> { - self.stroke - .as_iter(self.len as usize, self.indices.as_ref()) - } - pub fn stroke_width_iter(&self) -> Box + '_> { - self.stroke_width - .as_iter(self.len as usize, self.indices.as_ref()) + pub fn instances(&self) -> Box + '_> { + let n = self.len as usize; + let inds = self.indices.as_ref(); + Box::new( + izip!( + self.x.as_iter(n, inds), + self.y.as_iter(n, inds), + self.start_angle.as_iter(n, inds), + self.end_angle.as_iter(n, inds), + self.outer_radius.as_iter(n, inds), + self.inner_radius.as_iter(n, inds), + self.pad_angle.as_iter(n, inds), + self.corner_radius.as_iter(n, inds), + self.fill.as_iter(n, inds), + self.stroke.as_iter(n, inds), + self.stroke_width.as_iter(n, inds), + ) + .map( + |( + x, + y, + start_angle, + end_angle, + outer_radius, + inner_radius, + pad_angle, + corner_radius, + fill_color, + stroke_color, + stroke_width, + )| ArcMarkInstance { + x: *x, + y: *y, + start_angle: *start_angle, + end_angle: *end_angle, + outer_radius: *outer_radius, + inner_radius: *inner_radius, + pad_angle: *pad_angle, + corner_radius: *corner_radius, + fill_color: fill_color.clone(), + stroke_color: stroke_color.clone(), + stroke_width: *stroke_width, + }, + ), + ) } } impl Default for ArcMark { fn default() -> Self { + let default_instance = ArcMarkInstance::default(); Self { name: "arc_mark".to_string(), clip: true, len: 1, gradients: vec![], - x: EncodingValue::Scalar { value: 0.0 }, - y: EncodingValue::Scalar { value: 0.0 }, - start_angle: EncodingValue::Scalar { value: 0.0 }, - end_angle: EncodingValue::Scalar { value: 0.0 }, - outer_radius: EncodingValue::Scalar { value: 0.0 }, - inner_radius: EncodingValue::Scalar { value: 0.0 }, - pad_angle: EncodingValue::Scalar { value: 0.0 }, - corner_radius: EncodingValue::Scalar { value: 0.0 }, + x: EncodingValue::Scalar { + value: default_instance.x, + }, + y: EncodingValue::Scalar { + value: default_instance.y, + }, + start_angle: EncodingValue::Scalar { + value: default_instance.start_angle, + }, + end_angle: EncodingValue::Scalar { + value: default_instance.end_angle, + }, + outer_radius: EncodingValue::Scalar { + value: default_instance.outer_radius, + }, + inner_radius: EncodingValue::Scalar { + value: default_instance.inner_radius, + }, + pad_angle: EncodingValue::Scalar { + value: default_instance.pad_angle, + }, + corner_radius: EncodingValue::Scalar { + value: default_instance.corner_radius, + }, fill: EncodingValue::Scalar { - value: ColorOrGradient::Color([0.0, 0.0, 0.0, 1.0]), + value: default_instance.fill_color, }, stroke: EncodingValue::Scalar { - value: ColorOrGradient::Color([0.0, 0.0, 0.0, 0.0]), + value: default_instance.stroke_color, + }, + stroke_width: EncodingValue::Scalar { + value: default_instance.stroke_width, }, - stroke_width: EncodingValue::Scalar { value: 0.0 }, indices: None, zindex: None, } } } + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct ArcMarkInstance { + pub x: f32, + pub y: f32, + pub start_angle: f32, + pub end_angle: f32, + pub outer_radius: f32, + pub inner_radius: f32, + pub pad_angle: f32, + pub corner_radius: f32, + pub fill_color: ColorOrGradient, + pub stroke_color: ColorOrGradient, + pub stroke_width: f32, +} + +impl Default for ArcMarkInstance { + fn default() -> Self { + Self { + x: 0.0, + y: 0.0, + start_angle: 0.0, + end_angle: 0.0, + outer_radius: 0.0, + inner_radius: 0.0, + pad_angle: 0.0, + corner_radius: 0.0, + fill_color: ColorOrGradient::Color([0.0, 0.0, 0.0, 1.0]), + stroke_color: ColorOrGradient::Color([0.0, 0.0, 0.0, 0.0]), + stroke_width: 0.0, + } + } +} diff --git a/avenger/src/marks/area.rs b/avenger/src/marks/area.rs index 2488daf..37f14b4 100644 --- a/avenger/src/marks/area.rs +++ b/avenger/src/marks/area.rs @@ -1,4 +1,5 @@ use crate::marks::value::{ColorOrGradient, EncodingValue, Gradient, StrokeCap, StrokeJoin}; +use itertools::izip; use serde::{Deserialize, Serialize}; #[derive(Debug, Clone, Serialize, Deserialize)] @@ -9,11 +10,6 @@ pub struct AreaMark { pub len: u32, pub orientation: AreaOrientation, pub gradients: Vec, - pub x: EncodingValue, - pub y: EncodingValue, - pub x2: EncodingValue, - pub y2: EncodingValue, - pub defined: EncodingValue, pub fill: ColorOrGradient, pub stroke: ColorOrGradient, pub stroke_width: f32, @@ -21,43 +17,61 @@ pub struct AreaMark { pub stroke_join: StrokeJoin, pub stroke_dash: Option>, pub zindex: Option, + + // Encodings + pub x: EncodingValue, + pub y: EncodingValue, + pub x2: EncodingValue, + pub y2: EncodingValue, + pub defined: EncodingValue, } impl AreaMark { - pub fn x_iter(&self) -> Box + '_> { - self.x.as_iter(self.len as usize, None) - } - - pub fn y_iter(&self) -> Box + '_> { - self.y.as_iter(self.len as usize, None) - } - - pub fn x2_iter(&self) -> Box + '_> { - self.x2.as_iter(self.len as usize, None) - } - - pub fn y2_iter(&self) -> Box + '_> { - self.y2.as_iter(self.len as usize, None) - } - - pub fn defined_iter(&self) -> Box + '_> { - self.defined.as_iter(self.len as usize, None) + pub fn instances(&self) -> Box + '_> { + let n = self.len as usize; + Box::new( + izip!( + self.x.as_iter(n, None), + self.y.as_iter(n, None), + self.x2.as_iter(n, None), + self.y2.as_iter(n, None), + self.defined.as_iter(n, None) + ) + .map(|(x, y, x2, y2, defined)| AreaMarkInstance { + x: *x, + y: *y, + x2: *x2, + y2: *y2, + defined: *defined, + }), + ) } } impl Default for AreaMark { fn default() -> Self { + let default_instance = AreaMarkInstance::default(); Self { name: "area_mark".to_string(), clip: true, len: 1, orientation: Default::default(), gradients: vec![], - x: EncodingValue::Scalar { value: 0.0 }, - y: EncodingValue::Scalar { value: 0.0 }, - x2: EncodingValue::Scalar { value: 0.0 }, - y2: EncodingValue::Scalar { value: 0.0 }, - defined: EncodingValue::Scalar { value: true }, + x: EncodingValue::Scalar { + value: default_instance.x, + }, + y: EncodingValue::Scalar { + value: default_instance.y, + }, + x2: EncodingValue::Scalar { + value: default_instance.x2, + }, + y2: EncodingValue::Scalar { + value: default_instance.y2, + }, + defined: EncodingValue::Scalar { + value: default_instance.defined, + }, fill: ColorOrGradient::Color([0.0, 0.0, 0.0, 0.0]), stroke: ColorOrGradient::Color([0.0, 0.0, 0.0, 0.0]), stroke_width: 1.0, @@ -76,3 +90,24 @@ pub enum AreaOrientation { Vertical, Horizontal, } + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct AreaMarkInstance { + pub x: f32, + pub y: f32, + pub x2: f32, + pub y2: f32, + pub defined: bool, +} + +impl Default for AreaMarkInstance { + fn default() -> Self { + Self { + x: 0.0, + y: 0.0, + x2: 0.0, + y2: 0.0, + defined: true, + } + } +} diff --git a/avenger/src/marks/image.rs b/avenger/src/marks/image.rs index 439d516..0cb1a6b 100644 --- a/avenger/src/marks/image.rs +++ b/avenger/src/marks/image.rs @@ -1,4 +1,5 @@ use crate::marks::value::{EncodingValue, ImageAlign, ImageBaseline}; +use itertools::izip; use serde::{Deserialize, Serialize}; #[derive(Debug, Clone, Serialize, Deserialize)] @@ -9,6 +10,10 @@ pub struct ImageMark { pub len: u32, pub aspect: bool, pub smooth: bool, + pub indices: Option>, + pub zindex: Option, + + // Encodings pub image: EncodingValue, pub x: EncodingValue, pub y: EncodingValue, @@ -16,38 +21,40 @@ pub struct ImageMark { pub height: EncodingValue, pub align: EncodingValue, pub baseline: EncodingValue, - pub indices: Option>, - pub zindex: Option, } impl ImageMark { - pub fn image_iter(&self) -> Box + '_> { - self.image.as_iter(self.len as usize, self.indices.as_ref()) - } - pub fn x_iter(&self) -> Box + '_> { - self.x.as_iter(self.len as usize, self.indices.as_ref()) - } - pub fn y_iter(&self) -> Box + '_> { - self.y.as_iter(self.len as usize, self.indices.as_ref()) - } - pub fn width_iter(&self) -> Box + '_> { - self.width.as_iter(self.len as usize, self.indices.as_ref()) - } - pub fn height_iter(&self) -> Box + '_> { - self.height - .as_iter(self.len as usize, self.indices.as_ref()) - } - pub fn align_iter(&self) -> Box + '_> { - self.align.as_iter(self.len as usize, self.indices.as_ref()) - } - pub fn baseline_iter(&self) -> Box + '_> { - self.baseline - .as_iter(self.len as usize, self.indices.as_ref()) + pub fn instances(&self) -> Box + '_> { + let n = self.len as usize; + let inds = self.indices.as_ref(); + Box::new( + izip!( + self.image.as_iter(n, inds), + self.x.as_iter(n, inds), + self.y.as_iter(n, inds), + self.width.as_iter(n, inds), + self.height.as_iter(n, inds), + self.align.as_iter(n, inds), + self.baseline.as_iter(n, inds) + ) + .map( + |(image, x, y, width, height, align, baseline)| ImageMarkInstance { + image: image.clone(), + x: *x, + y: *y, + width: *width, + height: *height, + align: *align, + baseline: *baseline, + }, + ), + ) } } impl Default for ImageMark { fn default() -> Self { + let default_instance = ImageMarkInstance::default(); Self { name: "image_mark".to_string(), clip: true, @@ -55,24 +62,57 @@ impl Default for ImageMark { aspect: true, indices: None, smooth: true, - x: EncodingValue::Scalar { value: 0.0 }, - y: EncodingValue::Scalar { value: 0.0 }, - width: EncodingValue::Scalar { value: 0.0 }, - height: EncodingValue::Scalar { value: 0.0 }, + x: EncodingValue::Scalar { + value: default_instance.x, + }, + y: EncodingValue::Scalar { + value: default_instance.y, + }, + width: EncodingValue::Scalar { + value: default_instance.width, + }, + height: EncodingValue::Scalar { + value: default_instance.height, + }, align: EncodingValue::Scalar { - value: Default::default(), + value: default_instance.align, }, baseline: EncodingValue::Scalar { - value: Default::default(), + value: default_instance.baseline, }, image: EncodingValue::Scalar { - value: Default::default(), + value: default_instance.image, }, zindex: None, } } } +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct ImageMarkInstance { + pub image: RgbaImage, + pub x: f32, + pub y: f32, + pub width: f32, + pub height: f32, + pub align: ImageAlign, + pub baseline: ImageBaseline, +} + +impl Default for ImageMarkInstance { + fn default() -> Self { + Self { + image: Default::default(), + x: 0.0, + y: 0.0, + width: 0.0, + height: 0.0, + align: Default::default(), + baseline: Default::default(), + } + } +} + #[derive(Debug, Clone, Default, Serialize, Deserialize)] pub struct RgbaImage { pub width: u32, diff --git a/avenger/src/marks/line.rs b/avenger/src/marks/line.rs index 5265114..96f575c 100644 --- a/avenger/src/marks/line.rs +++ b/avenger/src/marks/line.rs @@ -1,4 +1,5 @@ use crate::marks::value::{ColorOrGradient, EncodingValue, Gradient, StrokeCap, StrokeJoin}; +use itertools::izip; use serde::{Deserialize, Serialize}; #[derive(Debug, Clone, Serialize, Deserialize)] @@ -8,41 +9,54 @@ pub struct LineMark { pub clip: bool, pub len: u32, pub gradients: Vec, - pub x: EncodingValue, - pub y: EncodingValue, - pub defined: EncodingValue, pub stroke: ColorOrGradient, pub stroke_width: f32, pub stroke_cap: StrokeCap, pub stroke_join: StrokeJoin, pub stroke_dash: Option>, pub zindex: Option, + + // Encodings + pub x: EncodingValue, + pub y: EncodingValue, + pub defined: EncodingValue, } impl LineMark { - pub fn x_iter(&self) -> Box + '_> { - self.x.as_iter(self.len as usize, None) - } - - pub fn y_iter(&self) -> Box + '_> { - self.y.as_iter(self.len as usize, None) - } - - pub fn defined_iter(&self) -> Box + '_> { - self.defined.as_iter(self.len as usize, None) + pub fn instances(&self) -> Box + '_> { + let n = self.len as usize; + Box::new( + izip!( + self.x.as_iter(n, None), + self.y.as_iter(n, None), + self.defined.as_iter(n, None) + ) + .map(|(x, y, defined)| LineMarkInstance { + x: *x, + y: *y, + defined: *defined, + }), + ) } } impl Default for LineMark { fn default() -> Self { + let default_instance = LineMarkInstance::default(); Self { name: "line_mark".to_string(), clip: true, len: 1, gradients: vec![], - x: EncodingValue::Scalar { value: 0.0 }, - y: EncodingValue::Scalar { value: 0.0 }, - defined: EncodingValue::Scalar { value: true }, + x: EncodingValue::Scalar { + value: default_instance.x, + }, + y: EncodingValue::Scalar { + value: default_instance.y, + }, + defined: EncodingValue::Scalar { + value: default_instance.defined, + }, stroke: ColorOrGradient::Color([0.0, 0.0, 0.0, 1.0]), stroke_width: 1.0, stroke_cap: Default::default(), @@ -52,3 +66,20 @@ impl Default for LineMark { } } } + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct LineMarkInstance { + pub x: f32, + pub y: f32, + pub defined: bool, +} + +impl Default for LineMarkInstance { + fn default() -> Self { + Self { + x: 0.0, + y: 0.0, + defined: true, + } + } +} diff --git a/avenger/src/marks/path.rs b/avenger/src/marks/path.rs index 0c17ca1..a45a3b8 100644 --- a/avenger/src/marks/path.rs +++ b/avenger/src/marks/path.rs @@ -1,4 +1,5 @@ use crate::marks::value::{ColorOrGradient, EncodingValue, Gradient, StrokeCap, StrokeJoin}; +use itertools::izip; use lyon_path::geom::euclid::{Transform2D, UnknownUnit}; use serde::{Deserialize, Serialize}; @@ -14,55 +15,42 @@ pub struct PathMark { pub stroke_cap: StrokeCap, pub stroke_join: StrokeJoin, pub stroke_width: Option, + pub indices: Option>, + pub zindex: Option, + + // Encodings pub path: EncodingValue, pub fill: EncodingValue, pub stroke: EncodingValue, pub transform: EncodingValue, - pub indices: Option>, - pub zindex: Option, } impl PathMark { - pub fn path_iter(&self) -> Box + '_> { - self.path.as_iter(self.len as usize, self.indices.as_ref()) - } - - pub fn path_vec(&self) -> Vec { - self.path.as_vec(self.len as usize, self.indices.as_ref()) - } - - pub fn fill_iter(&self) -> Box + '_> { - self.fill.as_iter(self.len as usize, self.indices.as_ref()) - } - - pub fn fill_vec(&self) -> Vec { - self.fill.as_vec(self.len as usize, self.indices.as_ref()) - } - - pub fn stroke_iter(&self) -> Box + '_> { - self.stroke - .as_iter(self.len as usize, self.indices.as_ref()) - } - - pub fn stroke_vec(&self) -> Vec { - self.stroke.as_vec(self.len as usize, self.indices.as_ref()) - } - - pub fn transform_iter(&self) -> Box + '_> { - self.transform - .as_iter(self.len as usize, self.indices.as_ref()) - } - - pub fn transform_vec(&self) -> Vec { - self.transform - .as_vec(self.len as usize, self.indices.as_ref()) + pub fn instances(&self) -> Box + '_> { + let n = self.len as usize; + let inds = self.indices.as_ref(); + Box::new( + izip!( + self.path.as_iter(n, inds), + self.fill.as_iter(n, inds), + self.stroke.as_iter(n, inds), + self.transform.as_iter(n, inds) + ) + .map(|(path, fill, stroke, transform)| PathMarkInstance { + path: path.clone(), + fill: fill.clone(), + stroke: stroke.clone(), + transform: *transform, + }), + ) } } impl Default for PathMark { fn default() -> Self { + let default_instance = PathMarkInstance::default(); Self { - name: "rule_mark".to_string(), + name: "path_mark".to_string(), clip: true, len: 1, gradients: vec![], @@ -70,19 +58,38 @@ impl Default for PathMark { stroke_join: StrokeJoin::Miter, stroke_width: Some(0.0), path: EncodingValue::Scalar { - value: lyon_path::Path::default(), + value: default_instance.path, }, fill: EncodingValue::Scalar { - value: ColorOrGradient::Color([0.0, 0.0, 0.0, 0.0]), + value: default_instance.fill, }, stroke: EncodingValue::Scalar { - value: ColorOrGradient::Color([0.0, 0.0, 0.0, 0.0]), + value: default_instance.stroke, }, transform: EncodingValue::Scalar { - value: PathTransform::identity(), + value: default_instance.transform, }, indices: None, zindex: None, } } } + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct PathMarkInstance { + pub path: lyon_path::Path, + pub fill: ColorOrGradient, + pub stroke: ColorOrGradient, + pub transform: PathTransform, +} + +impl Default for PathMarkInstance { + fn default() -> Self { + Self { + path: lyon_path::Path::default(), + fill: ColorOrGradient::Color([0.0, 0.0, 0.0, 0.0]), + stroke: ColorOrGradient::Color([0.0, 0.0, 0.0, 0.0]), + transform: PathTransform::identity(), + } + } +} diff --git a/avenger/src/marks/rect.rs b/avenger/src/marks/rect.rs index f4462e5..285c270 100644 --- a/avenger/src/marks/rect.rs +++ b/avenger/src/marks/rect.rs @@ -1,4 +1,5 @@ use crate::marks::value::{ColorOrGradient, EncodingValue, Gradient}; +use itertools::izip; use serde::{Deserialize, Serialize}; #[derive(Debug, Clone, Serialize, Deserialize)] @@ -8,6 +9,10 @@ pub struct RectMark { pub clip: bool, pub len: u32, pub gradients: Vec, + pub indices: Option>, + pub zindex: Option, + + // Encodings pub x: EncodingValue, pub y: EncodingValue, pub width: EncodingValue, @@ -16,103 +21,102 @@ pub struct RectMark { pub stroke: EncodingValue, pub stroke_width: EncodingValue, pub corner_radius: EncodingValue, - pub indices: Option>, - pub zindex: Option, } impl RectMark { - pub fn x_iter(&self) -> Box + '_> { - self.x.as_iter(self.len as usize, self.indices.as_ref()) - } - - pub fn x_vec(&self) -> Vec { - self.x.as_vec(self.len as usize, self.indices.as_ref()) - } - - pub fn y_iter(&self) -> Box + '_> { - self.y.as_iter(self.len as usize, self.indices.as_ref()) - } - - pub fn y_vec(&self) -> Vec { - self.y.as_vec(self.len as usize, self.indices.as_ref()) - } - - pub fn width_iter(&self) -> Box + '_> { - self.width.as_iter(self.len as usize, self.indices.as_ref()) - } - - pub fn width_vec(&self) -> Vec { - self.width.as_vec(self.len as usize, self.indices.as_ref()) - } - - pub fn height_iter(&self) -> Box + '_> { - self.height - .as_iter(self.len as usize, self.indices.as_ref()) - } - - pub fn height_vec(&self) -> Vec { - self.height.as_vec(self.len as usize, self.indices.as_ref()) - } - - pub fn fill_iter(&self) -> Box + '_> { - self.fill.as_iter(self.len as usize, self.indices.as_ref()) - } - - pub fn fill_vec(&self) -> Vec { - self.fill.as_vec(self.len as usize, self.indices.as_ref()) - } - - pub fn stroke_iter(&self) -> Box + '_> { - self.stroke - .as_iter(self.len as usize, self.indices.as_ref()) - } - - pub fn stroke_vec(&self) -> Vec { - self.stroke.as_vec(self.len as usize, self.indices.as_ref()) - } - - pub fn stroke_width_iter(&self) -> Box + '_> { - self.stroke_width - .as_iter(self.len as usize, self.indices.as_ref()) - } - - pub fn stroke_width_vec(&self) -> Vec { - self.stroke_width - .as_vec(self.len as usize, self.indices.as_ref()) - } - - pub fn corner_radius_iter(&self) -> Box + '_> { - self.corner_radius - .as_iter(self.len as usize, self.indices.as_ref()) - } - - pub fn corner_radius_vec(&self) -> Vec { - self.corner_radius - .as_vec(self.len as usize, self.indices.as_ref()) + pub fn instances(&self) -> Box + '_> { + let n = self.len as usize; + let inds = self.indices.as_ref(); + Box::new( + izip!( + self.x.as_iter(n, inds), + self.y.as_iter(n, inds), + self.width.as_iter(n, inds), + self.height.as_iter(n, inds), + self.fill.as_iter(n, inds), + self.stroke.as_iter(n, inds), + self.stroke_width.as_iter(n, inds), + self.corner_radius.as_iter(n, inds) + ) + .map( + |(x, y, width, height, fill, stroke, stroke_width, corner_radius)| { + RectMarkInstance { + x: *x, + y: *y, + width: *width, + height: *height, + fill: fill.clone(), + stroke: stroke.clone(), + stroke_width: *stroke_width, + corner_radius: *corner_radius, + } + }, + ), + ) } } impl Default for RectMark { fn default() -> Self { + let default_instance = RectMarkInstance::default(); Self { - name: "rule_mark".to_string(), + name: "rect_mark".to_string(), clip: true, len: 1, gradients: vec![], - x: EncodingValue::Scalar { value: 0.0 }, - y: EncodingValue::Scalar { value: 0.0 }, - width: EncodingValue::Scalar { value: 0.0 }, - height: EncodingValue::Scalar { value: 0.0 }, + x: EncodingValue::Scalar { + value: default_instance.x, + }, + y: EncodingValue::Scalar { + value: default_instance.y, + }, + width: EncodingValue::Scalar { + value: default_instance.width, + }, + height: EncodingValue::Scalar { + value: default_instance.height, + }, fill: EncodingValue::Scalar { - value: ColorOrGradient::Color([0.0, 0.0, 0.0, 0.0]), + value: default_instance.fill, }, stroke: EncodingValue::Scalar { - value: ColorOrGradient::Color([0.0, 0.0, 0.0, 0.0]), + value: default_instance.stroke, + }, + stroke_width: EncodingValue::Scalar { + value: default_instance.stroke_width, + }, + corner_radius: EncodingValue::Scalar { + value: default_instance.corner_radius, }, - stroke_width: EncodingValue::Scalar { value: 0.0 }, - corner_radius: EncodingValue::Scalar { value: 0.0 }, indices: None, zindex: None, } } } + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct RectMarkInstance { + pub x: f32, + pub y: f32, + pub width: f32, + pub height: f32, + pub fill: ColorOrGradient, + pub stroke: ColorOrGradient, + pub stroke_width: f32, + pub corner_radius: f32, +} + +impl Default for RectMarkInstance { + fn default() -> Self { + Self { + x: 0.0, + y: 0.0, + width: 0.0, + height: 0.0, + fill: ColorOrGradient::Color([0.0, 0.0, 0.0, 0.0]), + stroke: ColorOrGradient::Color([0.0, 0.0, 0.0, 0.0]), + stroke_width: 0.0, + corner_radius: 0.0, + } + } +} diff --git a/avenger/src/marks/rule.rs b/avenger/src/marks/rule.rs index 0b384da..69fcafc 100644 --- a/avenger/src/marks/rule.rs +++ b/avenger/src/marks/rule.rs @@ -1,4 +1,5 @@ use crate::marks::value::{ColorOrGradient, EncodingValue, Gradient, StrokeCap}; +use itertools::izip; use serde::{Deserialize, Serialize}; #[derive(Debug, Clone, Serialize, Deserialize)] @@ -8,7 +9,10 @@ pub struct RuleMark { pub clip: bool, pub len: u32, pub gradients: Vec, - pub stroke_dash: Option>>, + pub indices: Option>, + pub zindex: Option, + + // Encodings pub x0: EncodingValue, pub y0: EncodingValue, pub x1: EncodingValue, @@ -16,65 +20,110 @@ pub struct RuleMark { pub stroke: EncodingValue, pub stroke_width: EncodingValue, pub stroke_cap: EncodingValue, - pub indices: Option>, - pub zindex: Option, + pub stroke_dash: Option>>, } impl RuleMark { - pub fn x0_iter(&self) -> Box + '_> { - self.x0.as_iter(self.len as usize, self.indices.as_ref()) - } - pub fn y0_iter(&self) -> Box + '_> { - self.y0.as_iter(self.len as usize, self.indices.as_ref()) - } - pub fn x1_iter(&self) -> Box + '_> { - self.x1.as_iter(self.len as usize, self.indices.as_ref()) - } - pub fn y1_iter(&self) -> Box + '_> { - self.y1.as_iter(self.len as usize, self.indices.as_ref()) - } - pub fn stroke_iter(&self) -> Box + '_> { - self.stroke - .as_iter(self.len as usize, self.indices.as_ref()) - } - pub fn stroke_width_iter(&self) -> Box + '_> { - self.stroke_width - .as_iter(self.len as usize, self.indices.as_ref()) - } - pub fn stroke_cap_iter(&self) -> Box + '_> { - self.stroke_cap - .as_iter(self.len as usize, self.indices.as_ref()) - } - pub fn stroke_dash_iter(&self) -> Option> + '_>> { - if let Some(stroke_dash) = &self.stroke_dash { - Some(stroke_dash.as_iter(self.len as usize, self.indices.as_ref())) - } else { - None - } + pub fn instances(&self) -> Box + '_> { + let n = self.len as usize; + let inds = self.indices.as_ref(); + + let stroke_dash_iter = self.stroke_dash.as_ref().map_or_else( + || { + Box::new(std::iter::repeat(None)) + as Box>> + '_> + }, + |dash| Box::new(dash.as_iter(n, inds).map(Some)), + ); + + Box::new( + izip!( + self.x0.as_iter(n, inds), + self.y0.as_iter(n, inds), + self.x1.as_iter(n, inds), + self.y1.as_iter(n, inds), + self.stroke.as_iter(n, inds), + self.stroke_width.as_iter(n, inds), + self.stroke_cap.as_iter(n, inds), + stroke_dash_iter, + ) + .map( + |(x0, y0, x1, y1, stroke, stroke_width, stroke_cap, stroke_dash)| { + RuleMarkInstance { + x0: *x0, + y0: *y0, + x1: *x1, + y1: *y1, + stroke: stroke.clone(), + stroke_width: *stroke_width, + stroke_cap: *stroke_cap, + stroke_dash: stroke_dash.cloned(), + } + }, + ), + ) } } impl Default for RuleMark { fn default() -> Self { + let default_instance = RuleMarkInstance::default(); Self { name: "rule_mark".to_string(), clip: true, len: 1, gradients: vec![], stroke_dash: None, - x0: EncodingValue::Scalar { value: 0.0 }, - y0: EncodingValue::Scalar { value: 0.0 }, - x1: EncodingValue::Scalar { value: 0.0 }, - y1: EncodingValue::Scalar { value: 0.0 }, + x0: EncodingValue::Scalar { + value: default_instance.x0, + }, + y0: EncodingValue::Scalar { + value: default_instance.y0, + }, + x1: EncodingValue::Scalar { + value: default_instance.x1, + }, + y1: EncodingValue::Scalar { + value: default_instance.y1, + }, stroke: EncodingValue::Scalar { - value: ColorOrGradient::Color([0.0, 0.0, 0.0, 1.0]), + value: default_instance.stroke, + }, + stroke_width: EncodingValue::Scalar { + value: default_instance.stroke_width, }, - stroke_width: EncodingValue::Scalar { value: 1.0 }, stroke_cap: EncodingValue::Scalar { - value: StrokeCap::Butt, + value: default_instance.stroke_cap, }, indices: None, zindex: None, } } } + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct RuleMarkInstance { + pub x0: f32, + pub y0: f32, + pub x1: f32, + pub y1: f32, + pub stroke: ColorOrGradient, + pub stroke_width: f32, + pub stroke_cap: StrokeCap, + pub stroke_dash: Option>, +} + +impl Default for RuleMarkInstance { + fn default() -> Self { + Self { + x0: 0.0, + y0: 0.0, + x1: 0.0, + y1: 0.0, + stroke: ColorOrGradient::Color([0.0, 0.0, 0.0, 1.0]), + stroke_width: 1.0, + stroke_cap: StrokeCap::Butt, + stroke_dash: None, + } + } +} diff --git a/avenger/src/marks/symbol.rs b/avenger/src/marks/symbol.rs index 786b3cf..93ea69a 100644 --- a/avenger/src/marks/symbol.rs +++ b/avenger/src/marks/symbol.rs @@ -1,5 +1,6 @@ use crate::error::AvengerError; use crate::marks::value::{ColorOrGradient, EncodingValue, Gradient}; +use itertools::izip; use lyon_extra::parser::{ParserOptions, Source}; use lyon_path::geom::euclid::Point2D; use lyon_path::geom::{Box2D, Point, Scale}; @@ -16,80 +17,50 @@ pub struct SymbolMark { pub gradients: Vec, pub shapes: Vec, pub stroke_width: Option, - pub shape_index: EncodingValue, + pub indices: Option>, + pub zindex: Option, + + // Encoding values pub x: EncodingValue, pub y: EncodingValue, - pub fill: EncodingValue, pub size: EncodingValue, + pub shape_index: EncodingValue, + pub fill: EncodingValue, pub stroke: EncodingValue, pub angle: EncodingValue, - pub indices: Option>, - pub zindex: Option, } impl SymbolMark { - pub fn x_iter(&self) -> Box + '_> { - self.x.as_iter(self.len as usize, self.indices.as_ref()) - } - - pub fn x_vec(&self) -> Vec { - self.x.as_vec(self.len as usize, self.indices.as_ref()) - } - - pub fn y_iter(&self) -> Box + '_> { - self.y.as_iter(self.len as usize, self.indices.as_ref()) - } - - pub fn y_vec(&self) -> Vec { - self.y.as_vec(self.len as usize, self.indices.as_ref()) - } - - pub fn fill_iter(&self) -> Box + '_> { - self.fill.as_iter(self.len as usize, self.indices.as_ref()) - } - - pub fn fill_vec(&self) -> Vec { - self.fill.as_vec(self.len as usize, self.indices.as_ref()) - } - - pub fn size_iter(&self) -> Box + '_> { - self.size.as_iter(self.len as usize, self.indices.as_ref()) - } - - pub fn size_vec(&self) -> Vec { - self.size.as_vec(self.len as usize, self.indices.as_ref()) - } - - pub fn stroke_iter(&self) -> Box + '_> { - self.stroke - .as_iter(self.len as usize, self.indices.as_ref()) - } - - pub fn stroke_vec(&self) -> Vec { - self.stroke.as_vec(self.len as usize, self.indices.as_ref()) - } - - pub fn angle_iter(&self) -> Box + '_> { - self.angle.as_iter(self.len as usize, self.indices.as_ref()) - } - - pub fn angle_vec(&self) -> Vec { - self.angle.as_vec(self.len as usize, self.indices.as_ref()) - } - - pub fn shape_index_iter(&self) -> Box + '_> { - self.shape_index - .as_iter(self.len as usize, self.indices.as_ref()) - } - - pub fn shape_index_vec(&self) -> Vec { - self.shape_index - .as_vec(self.len as usize, self.indices.as_ref()) + pub fn instances(&self) -> Box + '_> { + let n = self.len as usize; + let inds = self.indices.as_ref(); + Box::new( + izip!( + self.x.as_iter(n, inds), + self.y.as_iter(n, inds), + self.size.as_iter(n, inds), + self.shape_index.as_iter(n, inds), + self.fill.as_iter(n, inds), + self.stroke.as_iter(n, inds), + self.angle.as_iter(n, inds) + ) + .map( + |(x, y, size, shape_index, fill, stroke, angle)| SymbolMarkInstance { + x: *x, + y: *y, + size: *size, + shape_index: *shape_index, + fill: fill.clone(), + stroke: stroke.clone(), + angle: *angle, + }, + ), + ) } pub fn max_size(&self) -> f32 { match &self.size { - EncodingValue::Scalar { value: size } => *size, + EncodingValue::Scalar { value } => *value, EncodingValue::Array { values } => *values .iter() .max_by(|a, b| a.partial_cmp(b).unwrap()) @@ -100,30 +71,66 @@ impl SymbolMark { impl Default for SymbolMark { fn default() -> Self { + let default_instance = SymbolMarkInstance::default(); Self { - name: "".to_string(), + name: "symbol_mark".to_string(), clip: true, + len: 1, + gradients: vec![], shapes: vec![Default::default()], stroke_width: None, - len: 1, - x: EncodingValue::Scalar { value: 0.0 }, - y: EncodingValue::Scalar { value: 0.0 }, - shape_index: EncodingValue::Scalar { value: 0 }, + x: EncodingValue::Scalar { + value: default_instance.x, + }, + y: EncodingValue::Scalar { + value: default_instance.y, + }, + size: EncodingValue::Scalar { + value: default_instance.size, + }, + shape_index: EncodingValue::Scalar { + value: default_instance.shape_index, + }, fill: EncodingValue::Scalar { - value: ColorOrGradient::Color([0.0, 0.0, 0.0, 0.0]), + value: default_instance.fill, }, - size: EncodingValue::Scalar { value: 20.0 }, stroke: EncodingValue::Scalar { - value: ColorOrGradient::Color([0.0, 0.0, 0.0, 0.0]), + value: default_instance.stroke, + }, + angle: EncodingValue::Scalar { + value: default_instance.angle, }, - angle: EncodingValue::Scalar { value: 0.0 }, indices: None, - gradients: vec![], zindex: None, } } } +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct SymbolMarkInstance { + pub x: f32, + pub y: f32, + pub size: f32, + pub shape_index: usize, + pub fill: ColorOrGradient, + pub stroke: ColorOrGradient, + pub angle: f32, +} + +impl Default for SymbolMarkInstance { + fn default() -> Self { + Self { + x: 0.0, + y: 0.0, + size: 20.0, + shape_index: 0, + fill: ColorOrGradient::Color([0.0, 0.0, 0.0, 0.0]), + stroke: ColorOrGradient::Color([0.0, 0.0, 0.0, 0.0]), + angle: 0.0, + } + } +} + #[derive(Default, Debug, Clone, Serialize, Deserialize)] #[serde(rename_all = "kebab-case")] pub enum SymbolShape { diff --git a/avenger/src/marks/text.rs b/avenger/src/marks/text.rs index a9002a2..324fcf5 100644 --- a/avenger/src/marks/text.rs +++ b/avenger/src/marks/text.rs @@ -1,4 +1,5 @@ use crate::marks::value::EncodingValue; +use itertools::izip; use serde::{Deserialize, Serialize}; #[derive(Debug, Clone, Serialize, Deserialize)] @@ -7,6 +8,10 @@ pub struct TextMark { pub name: String, pub clip: bool, pub len: u32, + pub indices: Option>, + pub zindex: Option, + + // Encodings pub text: EncodingValue, pub x: EncodingValue, pub y: EncodingValue, @@ -19,91 +24,146 @@ pub struct TextMark { pub font_weight: EncodingValue, pub font_style: EncodingValue, pub limit: EncodingValue, - pub indices: Option>, - pub zindex: Option, } impl TextMark { - pub fn text_iter(&self) -> Box + '_> { - self.text.as_iter(self.len as usize, self.indices.as_ref()) - } - pub fn x_iter(&self) -> Box + '_> { - self.x.as_iter(self.len as usize, self.indices.as_ref()) - } - pub fn y_iter(&self) -> Box + '_> { - self.y.as_iter(self.len as usize, self.indices.as_ref()) - } - pub fn align_iter(&self) -> Box + '_> { - self.align.as_iter(self.len as usize, self.indices.as_ref()) - } - pub fn baseline_iter(&self) -> Box + '_> { - self.baseline - .as_iter(self.len as usize, self.indices.as_ref()) - } - pub fn angle_iter(&self) -> Box + '_> { - self.angle.as_iter(self.len as usize, self.indices.as_ref()) - } - pub fn color_iter(&self) -> Box + '_> { - self.color.as_iter(self.len as usize, self.indices.as_ref()) - } - pub fn font_iter(&self) -> Box + '_> { - self.font.as_iter(self.len as usize, self.indices.as_ref()) - } - pub fn font_size_iter(&self) -> Box + '_> { - self.font_size - .as_iter(self.len as usize, self.indices.as_ref()) - } - pub fn font_weight_iter(&self) -> Box + '_> { - self.font_weight - .as_iter(self.len as usize, self.indices.as_ref()) - } - pub fn font_style_iter(&self) -> Box + '_> { - self.font_style - .as_iter(self.len as usize, self.indices.as_ref()) - } - pub fn limit_iter(&self) -> Box + '_> { - self.limit.as_iter(self.len as usize, self.indices.as_ref()) + pub fn instances(&self) -> Box + '_> { + let n = self.len as usize; + let inds = self.indices.as_ref(); + Box::new( + izip!( + self.text.as_iter(n, inds), + self.x.as_iter(n, inds), + self.y.as_iter(n, inds), + self.align.as_iter(n, inds), + self.baseline.as_iter(n, inds), + self.angle.as_iter(n, inds), + self.color.as_iter(n, inds), + self.font.as_iter(n, inds), + self.font_size.as_iter(n, inds), + self.font_weight.as_iter(n, inds), + self.font_style.as_iter(n, inds), + self.limit.as_iter(n, inds) + ) + .map( + |( + text, + x, + y, + align, + baseline, + angle, + color, + font, + font_size, + font_weight, + font_style, + limit, + )| { + TextMarkInstance { + text: text.clone(), + x: *x, + y: *y, + align: *align, + baseline: *baseline, + angle: *angle, + color: *color, + font: font.clone(), + font_size: *font_size, + font_weight: *font_weight, + font_style: *font_style, + limit: *limit, + } + }, + ), + ) } } impl Default for TextMark { fn default() -> Self { + let default_instance = TextMarkInstance::default(); Self { name: "text_mark".to_string(), clip: true, len: 1, text: EncodingValue::Scalar { - value: String::new(), + value: default_instance.text, + }, + x: EncodingValue::Scalar { + value: default_instance.x, + }, + y: EncodingValue::Scalar { + value: default_instance.y, }, - x: EncodingValue::Scalar { value: 0.0 }, - y: EncodingValue::Scalar { value: 0.0 }, align: EncodingValue::Scalar { - value: TextAlignSpec::Left, + value: default_instance.align, }, baseline: EncodingValue::Scalar { - value: TextBaselineSpec::Alphabetic, + value: default_instance.baseline, + }, + angle: EncodingValue::Scalar { + value: default_instance.angle, }, - angle: EncodingValue::Scalar { value: 0.0 }, color: EncodingValue::Scalar { - value: [0.0, 0.0, 0.0, 1.0], + value: default_instance.color, }, font: EncodingValue::Scalar { - value: "sans serif".to_string(), + value: default_instance.font, + }, + font_size: EncodingValue::Scalar { + value: default_instance.font_size, }, - font_size: EncodingValue::Scalar { value: 10.0 }, font_weight: EncodingValue::Scalar { - value: FontWeightSpec::Name(FontWeightNameSpec::Normal), + value: default_instance.font_weight, }, font_style: EncodingValue::Scalar { - value: FontStyleSpec::Normal, + value: default_instance.font_style, + }, + limit: EncodingValue::Scalar { + value: default_instance.limit, }, - limit: EncodingValue::Scalar { value: 0.0 }, indices: None, zindex: None, } } } +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct TextMarkInstance { + pub text: String, + pub x: f32, + pub y: f32, + pub align: TextAlignSpec, + pub baseline: TextBaselineSpec, + pub angle: f32, + pub color: [f32; 4], + pub font: String, + pub font_size: f32, + pub font_weight: FontWeightSpec, + pub font_style: FontStyleSpec, + pub limit: f32, +} + +impl Default for TextMarkInstance { + fn default() -> Self { + Self { + text: String::new(), + x: 0.0, + y: 0.0, + align: TextAlignSpec::Left, + baseline: TextBaselineSpec::Alphabetic, + angle: 0.0, + color: [0.0, 0.0, 0.0, 1.0], + font: "sans serif".to_string(), + font_size: 10.0, + font_weight: FontWeightSpec::Name(FontWeightNameSpec::Normal), + font_style: FontStyleSpec::Normal, + limit: 0.0, + } + } +} + #[derive(Default, Debug, Clone, Copy, PartialEq, Serialize, Deserialize)] #[serde(rename_all = "lowercase")] pub enum TextAlignSpec { diff --git a/avenger/src/marks/trail.rs b/avenger/src/marks/trail.rs index f2238b4..fd29ecb 100644 --- a/avenger/src/marks/trail.rs +++ b/avenger/src/marks/trail.rs @@ -1,4 +1,5 @@ use crate::marks::value::{ColorOrGradient, EncodingValue, Gradient}; +use itertools::izip; use serde::{Deserialize, Serialize}; #[derive(Debug, Clone, Serialize, Deserialize)] @@ -9,44 +10,76 @@ pub struct TrailMark { pub len: u32, pub gradients: Vec, pub stroke: ColorOrGradient, + pub zindex: Option, + + // Encodings pub x: EncodingValue, pub y: EncodingValue, pub size: EncodingValue, pub defined: EncodingValue, - pub zindex: Option, } impl TrailMark { - pub fn x_iter(&self) -> Box + '_> { - self.x.as_iter(self.len as usize, None) - } - - pub fn y_iter(&self) -> Box + '_> { - self.y.as_iter(self.len as usize, None) - } - - pub fn size_iter(&self) -> Box + '_> { - self.size.as_iter(self.len as usize, None) - } - - pub fn defined_iter(&self) -> Box + '_> { - self.defined.as_iter(self.len as usize, None) + pub fn instances(&self) -> Box + '_> { + let n = self.len as usize; + Box::new( + izip!( + self.x.as_iter(n, None), + self.y.as_iter(n, None), + self.size.as_iter(n, None), + self.defined.as_iter(n, None) + ) + .map(|(x, y, size, defined)| TrailMarkInstance { + x: *x, + y: *y, + size: *size, + defined: *defined, + }), + ) } } impl Default for TrailMark { fn default() -> Self { + let default_instance = TrailMarkInstance::default(); Self { name: "trail_mark".to_string(), clip: true, len: 1, - x: EncodingValue::Scalar { value: 0.0 }, - y: EncodingValue::Scalar { value: 0.0 }, - size: EncodingValue::Scalar { value: 1.0 }, - defined: EncodingValue::Scalar { value: true }, + x: EncodingValue::Scalar { + value: default_instance.x, + }, + y: EncodingValue::Scalar { + value: default_instance.y, + }, + size: EncodingValue::Scalar { + value: default_instance.size, + }, + defined: EncodingValue::Scalar { + value: default_instance.defined, + }, stroke: ColorOrGradient::Color([0.0, 0.0, 0.0, 1.0]), gradients: vec![], zindex: None, } } } + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct TrailMarkInstance { + pub x: f32, + pub y: f32, + pub size: f32, + pub defined: bool, +} + +impl Default for TrailMarkInstance { + fn default() -> Self { + Self { + x: 0.0, + y: 0.0, + size: 1.0, + defined: true, + } + } +} diff --git a/examples/scatter-panning/Cargo.lock b/examples/scatter-panning/Cargo.lock index 3bc5c8b..9138c37 100644 --- a/examples/scatter-panning/Cargo.lock +++ b/examples/scatter-panning/Cargo.lock @@ -31,6 +31,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011" dependencies = [ "cfg-if", + "const-random", "getrandom", "once_cell", "version_check", @@ -79,6 +80,12 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fc7eb209b1518d6bb87b283c20095f5228ecda460da70b44f0802523dea6da04" +[[package]] +name = "android-tzdata" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0" + [[package]] name = "android_system_properties" version = "0.1.5" @@ -100,6 +107,220 @@ version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711" +[[package]] +name = "arrow" +version = "53.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c91839b07e474b3995035fd8ac33ee54f9c9ccbbb1ea33d9909c71bffdf1259d" +dependencies = [ + "arrow-arith", + "arrow-array", + "arrow-buffer", + "arrow-cast", + "arrow-csv", + "arrow-data", + "arrow-ipc", + "arrow-json", + "arrow-ord", + "arrow-row", + "arrow-schema", + "arrow-select", + "arrow-string", +] + +[[package]] +name = "arrow-arith" +version = "53.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "855c57c4efd26722b044dcd3e348252560e3e0333087fb9f6479dc0bf744054f" +dependencies = [ + "arrow-array", + "arrow-buffer", + "arrow-data", + "arrow-schema", + "chrono", + "half", + "num", +] + +[[package]] +name = "arrow-array" +version = "53.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd03279cea46569acf9295f6224fbc370c5df184b4d2ecfe97ccb131d5615a7f" +dependencies = [ + "ahash", + "arrow-buffer", + "arrow-data", + "arrow-schema", + "chrono", + "half", + "hashbrown 0.15.2", + "num", +] + +[[package]] +name = "arrow-buffer" +version = "53.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e4a9b9b1d6d7117f6138e13bc4dd5daa7f94e671b70e8c9c4dc37b4f5ecfc16" +dependencies = [ + "bytes", + "half", + "num", +] + +[[package]] +name = "arrow-cast" +version = "53.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc70e39916e60c5b7af7a8e2719e3ae589326039e1e863675a008bee5ffe90fd" +dependencies = [ + "arrow-array", + "arrow-buffer", + "arrow-data", + "arrow-schema", + "arrow-select", + "atoi", + "base64", + "chrono", + "half", + "lexical-core", + "num", + "ryu", +] + +[[package]] +name = "arrow-csv" +version = "53.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "789b2af43c1049b03a8d088ff6b2257cdcea1756cd76b174b1f2600356771b97" +dependencies = [ + "arrow-array", + "arrow-buffer", + "arrow-cast", + "arrow-data", + "arrow-schema", + "chrono", + "csv", + "csv-core", + "lazy_static", + "lexical-core", + "regex", +] + +[[package]] +name = "arrow-data" +version = "53.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e4e75edf21ffd53744a9b8e3ed11101f610e7ceb1a29860432824f1834a1f623" +dependencies = [ + "arrow-buffer", + "arrow-schema", + "half", + "num", +] + +[[package]] +name = "arrow-ipc" +version = "53.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d186a909dece9160bf8312f5124d797884f608ef5435a36d9d608e0b2a9bcbf8" +dependencies = [ + "arrow-array", + "arrow-buffer", + "arrow-cast", + "arrow-data", + "arrow-schema", + "flatbuffers", +] + +[[package]] +name = "arrow-json" +version = "53.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b66ff2fedc1222942d0bd2fd391cb14a85baa3857be95c9373179bd616753b85" +dependencies = [ + "arrow-array", + "arrow-buffer", + "arrow-cast", + "arrow-data", + "arrow-schema", + "chrono", + "half", + "indexmap", + "lexical-core", + "num", + "serde", + "serde_json", +] + +[[package]] +name = "arrow-ord" +version = "53.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ece7b5bc1180e6d82d1a60e1688c199829e8842e38497563c3ab6ea813e527fd" +dependencies = [ + "arrow-array", + "arrow-buffer", + "arrow-data", + "arrow-schema", + "arrow-select", + "half", + "num", +] + +[[package]] +name = "arrow-row" +version = "53.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "745c114c8f0e8ce211c83389270de6fbe96a9088a7b32c2a041258a443fe83ff" +dependencies = [ + "ahash", + "arrow-array", + "arrow-buffer", + "arrow-data", + "arrow-schema", + "half", +] + +[[package]] +name = "arrow-schema" +version = "53.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b95513080e728e4cec37f1ff5af4f12c9688d47795d17cda80b6ec2cf74d4678" + +[[package]] +name = "arrow-select" +version = "53.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e415279094ea70323c032c6e739c48ad8d80e78a09bef7117b8718ad5bf3722" +dependencies = [ + "ahash", + "arrow-array", + "arrow-buffer", + "arrow-data", + "arrow-schema", + "num", +] + +[[package]] +name = "arrow-string" +version = "53.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11d956cae7002eb8d83a27dbd34daaea1cf5b75852f0b84deb4d93a276e92bbf" +dependencies = [ + "arrow-array", + "arrow-buffer", + "arrow-data", + "arrow-schema", + "arrow-select", + "memchr", + "num", + "regex", + "regex-syntax 0.8.3", +] + [[package]] name = "as-raw-xcb-connection" version = "1.0.1" @@ -124,6 +345,15 @@ dependencies = [ "libloading 0.8.3", ] +[[package]] +name = "atoi" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f28d99ec8bfea296261ca1af174f24225171fea9664ba9003cbebee704810528" +dependencies = [ + "num-traits", +] + [[package]] name = "atomic-waker" version = "1.1.2" @@ -140,7 +370,9 @@ checksum = "f1fdabc7756949593fe60f30ec81974b613357de856987752631dea1e3394c80" name = "avenger" version = "0.0.8" dependencies = [ + "arrow", "image", + "itertools", "lyon_extra", "lyon_path", "serde", @@ -185,6 +417,12 @@ dependencies = [ "winit", ] +[[package]] +name = "base64" +version = "0.22.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" + [[package]] name = "bit-set" version = "0.5.3" @@ -340,6 +578,18 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" +[[package]] +name = "chrono" +version = "0.4.38" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a21f936df1771bf62b77f047b726c4625ff2e8aa607c01ec06e5a05bd8463401" +dependencies = [ + "android-tzdata", + "iana-time-zone", + "num-traits", + "windows-targets 0.52.6", +] + [[package]] name = "codespan-reporting" version = "0.11.1" @@ -429,6 +679,26 @@ dependencies = [ "web-sys", ] +[[package]] +name = "const-random" +version = "0.1.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87e00182fe74b066627d63b85fd550ac2998d4b0bd86bfed477a0ae4c7c71359" +dependencies = [ + "const-random-macro", +] + +[[package]] +name = "const-random-macro" +version = "0.1.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f9d839f2a20b0aee515dc581a6172f2321f96cab76c1a38a4c584a194955390e" +dependencies = [ + "getrandom", + "once_cell", + "tiny-keccak", +] + [[package]] name = "core-foundation" version = "0.9.4" @@ -484,6 +754,12 @@ version = "0.8.19" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "248e3bacc7dc6baa3b21e405ee045c3047101a49145e7e9eca583ab4c2ca5345" +[[package]] +name = "crunchy" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" + [[package]] name = "csscolorparser" version = "0.7.0" @@ -493,6 +769,27 @@ dependencies = [ "phf", ] +[[package]] +name = "csv" +version = "1.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "acdc4883a9c96732e4733212c01447ebd805833b7275a73ca3ee080fd77afdaf" +dependencies = [ + "csv-core", + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "csv-core" +version = "0.1.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5efa2b3d7902f4b634a20cae3c9c4e6209dc4779feb6863329607560143efa70" +dependencies = [ + "memchr", +] + [[package]] name = "cursor-icon" version = "1.1.0" @@ -599,6 +896,16 @@ dependencies = [ "simd-adler32", ] +[[package]] +name = "flatbuffers" +version = "24.3.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8add37afff2d4ffa83bc748a70b4b1370984f6980768554182424ef71447c35f" +dependencies = [ + "bitflags 1.3.2", + "rustc_version", +] + [[package]] name = "flate2" version = "1.0.28" @@ -787,7 +1094,7 @@ checksum = "cc11df1ace8e7e564511f53af41f3e42ddc95b56fd07b3f4445d2a6048bc682c" dependencies = [ "bitflags 2.6.0", "gpu-descriptor-types 0.1.2", - "hashbrown", + "hashbrown 0.14.3", ] [[package]] @@ -798,7 +1105,7 @@ checksum = "9c08c1f623a8d0b722b8b99f821eb0ba672a1618f0d3b16ddbee1cedd2dd8557" dependencies = [ "bitflags 2.6.0", "gpu-descriptor-types 0.2.0", - "hashbrown", + "hashbrown 0.14.3", ] [[package]] @@ -819,6 +1126,17 @@ dependencies = [ "bitflags 2.6.0", ] +[[package]] +name = "half" +version = "2.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6dd08c532ae367adf81c312a4580bc67f1d0fe8bc9c460520283f4c0ff277888" +dependencies = [ + "cfg-if", + "crunchy", + "num-traits", +] + [[package]] name = "hashbrown" version = "0.14.3" @@ -829,6 +1147,12 @@ dependencies = [ "allocator-api2", ] +[[package]] +name = "hashbrown" +version = "0.15.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289" + [[package]] name = "hassle-rs" version = "0.11.0" @@ -862,6 +1186,29 @@ version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" +[[package]] +name = "iana-time-zone" +version = "0.1.61" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "235e081f3925a06703c2d0117ea8b91f042756fd6e7a6e5d901e8ca1a996b220" +dependencies = [ + "android_system_properties", + "core-foundation-sys", + "iana-time-zone-haiku", + "js-sys", + "wasm-bindgen", + "windows-core 0.52.0", +] + +[[package]] +name = "iana-time-zone-haiku" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" +dependencies = [ + "cc", +] + [[package]] name = "image" version = "0.25.5" @@ -881,7 +1228,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "168fb715dda47215e360912c096649d23d58bf392ac62f73919e831745e40f26" dependencies = [ "equivalent", - "hashbrown", + "hashbrown 0.14.3", ] [[package]] @@ -973,6 +1320,70 @@ version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" +[[package]] +name = "lexical-core" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0431c65b318a590c1de6b8fd6e72798c92291d27762d94c9e6c37ed7a73d8458" +dependencies = [ + "lexical-parse-float", + "lexical-parse-integer", + "lexical-util", + "lexical-write-float", + "lexical-write-integer", +] + +[[package]] +name = "lexical-parse-float" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eb17a4bdb9b418051aa59d41d65b1c9be5affab314a872e5ad7f06231fb3b4e0" +dependencies = [ + "lexical-parse-integer", + "lexical-util", + "static_assertions", +] + +[[package]] +name = "lexical-parse-integer" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5df98f4a4ab53bf8b175b363a34c7af608fe31f93cc1fb1bf07130622ca4ef61" +dependencies = [ + "lexical-util", + "static_assertions", +] + +[[package]] +name = "lexical-util" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85314db53332e5c192b6bca611fb10c114a80d1b831ddac0af1e9be1b9232ca0" +dependencies = [ + "static_assertions", +] + +[[package]] +name = "lexical-write-float" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e7c3ad4e37db81c1cbe7cf34610340adc09c322871972f74877a712abc6c809" +dependencies = [ + "lexical-util", + "lexical-write-integer", + "static_assertions", +] + +[[package]] +name = "lexical-write-integer" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eb89e9f6958b83258afa3deed90b5de9ef68eef090ad5086c791cd2345610162" +dependencies = [ + "lexical-util", + "static_assertions", +] + [[package]] name = "libc" version = "0.2.153" @@ -1127,9 +1538,9 @@ dependencies = [ [[package]] name = "memchr" -version = "2.7.2" +version = "2.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c8640c5d730cb13ebd907d8d04b52f55ac9a2eec55b440c8892f40d56c76c1d" +checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" [[package]] name = "memmap2" @@ -1268,11 +1679,75 @@ dependencies = [ "winapi", ] +[[package]] +name = "num" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "35bd024e8b2ff75562e5f34e7f4905839deb4b22955ef5e73d2fea1b9813cb23" +dependencies = [ + "num-bigint", + "num-complex", + "num-integer", + "num-iter", + "num-rational", + "num-traits", +] + +[[package]] +name = "num-bigint" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9" +dependencies = [ + "num-integer", + "num-traits", +] + +[[package]] +name = "num-complex" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73f88a1307638156682bada9d7604135552957b7818057dcef22705b4d509495" +dependencies = [ + "num-traits", +] + +[[package]] +name = "num-integer" +version = "0.1.46" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" +dependencies = [ + "num-traits", +] + +[[package]] +name = "num-iter" +version = "0.1.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1429034a0490724d0075ebb2bc9e875d6503c3cf69e235a8941aa757d83ef5bf" +dependencies = [ + "autocfg", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-rational" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f83d14da390562dca69fc84082e73e548e1ad308d24accdedd2720017cb37824" +dependencies = [ + "num-bigint", + "num-integer", + "num-traits", +] + [[package]] name = "num-traits" -version = "0.2.18" +version = "0.2.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da0df0e5185db44f69b44f26786fe401b6c293d1907744beaa7fa62b2e5a517a" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" dependencies = [ "autocfg", "libm", @@ -1861,6 +2336,15 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" +[[package]] +name = "rustc_version" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" +dependencies = [ + "semver", +] + [[package]] name = "rustix" version = "0.38.32" @@ -1939,6 +2423,12 @@ dependencies = [ "tiny-skia", ] +[[package]] +name = "semver" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61697e0a1c7e512e84a621326239844a24d8207b4669b41bc18b32ea5cbf988b" + [[package]] name = "serde" version = "1.0.197" @@ -2157,6 +2647,15 @@ dependencies = [ "once_cell", ] +[[package]] +name = "tiny-keccak" +version = "2.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c9d3793400a45f954c52e73d068316d76b6f4e36977e3fcebb13a2721e80237" +dependencies = [ + "crunchy", +] + [[package]] name = "tiny-skia" version = "0.11.4" diff --git a/examples/wgpu-winit/Cargo.lock b/examples/wgpu-winit/Cargo.lock index c8520d3..8b06fe7 100644 --- a/examples/wgpu-winit/Cargo.lock +++ b/examples/wgpu-winit/Cargo.lock @@ -31,6 +31,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011" dependencies = [ "cfg-if", + "const-random", "getrandom", "once_cell", "version_check", @@ -79,6 +80,12 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fc7eb209b1518d6bb87b283c20095f5228ecda460da70b44f0802523dea6da04" +[[package]] +name = "android-tzdata" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0" + [[package]] name = "android_system_properties" version = "0.1.5" @@ -100,6 +107,220 @@ version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711" +[[package]] +name = "arrow" +version = "53.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c91839b07e474b3995035fd8ac33ee54f9c9ccbbb1ea33d9909c71bffdf1259d" +dependencies = [ + "arrow-arith", + "arrow-array", + "arrow-buffer", + "arrow-cast", + "arrow-csv", + "arrow-data", + "arrow-ipc", + "arrow-json", + "arrow-ord", + "arrow-row", + "arrow-schema", + "arrow-select", + "arrow-string", +] + +[[package]] +name = "arrow-arith" +version = "53.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "855c57c4efd26722b044dcd3e348252560e3e0333087fb9f6479dc0bf744054f" +dependencies = [ + "arrow-array", + "arrow-buffer", + "arrow-data", + "arrow-schema", + "chrono", + "half", + "num", +] + +[[package]] +name = "arrow-array" +version = "53.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd03279cea46569acf9295f6224fbc370c5df184b4d2ecfe97ccb131d5615a7f" +dependencies = [ + "ahash", + "arrow-buffer", + "arrow-data", + "arrow-schema", + "chrono", + "half", + "hashbrown 0.15.2", + "num", +] + +[[package]] +name = "arrow-buffer" +version = "53.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e4a9b9b1d6d7117f6138e13bc4dd5daa7f94e671b70e8c9c4dc37b4f5ecfc16" +dependencies = [ + "bytes", + "half", + "num", +] + +[[package]] +name = "arrow-cast" +version = "53.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc70e39916e60c5b7af7a8e2719e3ae589326039e1e863675a008bee5ffe90fd" +dependencies = [ + "arrow-array", + "arrow-buffer", + "arrow-data", + "arrow-schema", + "arrow-select", + "atoi", + "base64", + "chrono", + "half", + "lexical-core", + "num", + "ryu", +] + +[[package]] +name = "arrow-csv" +version = "53.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "789b2af43c1049b03a8d088ff6b2257cdcea1756cd76b174b1f2600356771b97" +dependencies = [ + "arrow-array", + "arrow-buffer", + "arrow-cast", + "arrow-data", + "arrow-schema", + "chrono", + "csv", + "csv-core", + "lazy_static", + "lexical-core", + "regex", +] + +[[package]] +name = "arrow-data" +version = "53.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e4e75edf21ffd53744a9b8e3ed11101f610e7ceb1a29860432824f1834a1f623" +dependencies = [ + "arrow-buffer", + "arrow-schema", + "half", + "num", +] + +[[package]] +name = "arrow-ipc" +version = "53.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d186a909dece9160bf8312f5124d797884f608ef5435a36d9d608e0b2a9bcbf8" +dependencies = [ + "arrow-array", + "arrow-buffer", + "arrow-cast", + "arrow-data", + "arrow-schema", + "flatbuffers", +] + +[[package]] +name = "arrow-json" +version = "53.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b66ff2fedc1222942d0bd2fd391cb14a85baa3857be95c9373179bd616753b85" +dependencies = [ + "arrow-array", + "arrow-buffer", + "arrow-cast", + "arrow-data", + "arrow-schema", + "chrono", + "half", + "indexmap", + "lexical-core", + "num", + "serde", + "serde_json", +] + +[[package]] +name = "arrow-ord" +version = "53.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ece7b5bc1180e6d82d1a60e1688c199829e8842e38497563c3ab6ea813e527fd" +dependencies = [ + "arrow-array", + "arrow-buffer", + "arrow-data", + "arrow-schema", + "arrow-select", + "half", + "num", +] + +[[package]] +name = "arrow-row" +version = "53.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "745c114c8f0e8ce211c83389270de6fbe96a9088a7b32c2a041258a443fe83ff" +dependencies = [ + "ahash", + "arrow-array", + "arrow-buffer", + "arrow-data", + "arrow-schema", + "half", +] + +[[package]] +name = "arrow-schema" +version = "53.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b95513080e728e4cec37f1ff5af4f12c9688d47795d17cda80b6ec2cf74d4678" + +[[package]] +name = "arrow-select" +version = "53.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e415279094ea70323c032c6e739c48ad8d80e78a09bef7117b8718ad5bf3722" +dependencies = [ + "ahash", + "arrow-array", + "arrow-buffer", + "arrow-data", + "arrow-schema", + "num", +] + +[[package]] +name = "arrow-string" +version = "53.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11d956cae7002eb8d83a27dbd34daaea1cf5b75852f0b84deb4d93a276e92bbf" +dependencies = [ + "arrow-array", + "arrow-buffer", + "arrow-data", + "arrow-schema", + "arrow-select", + "memchr", + "num", + "regex", + "regex-syntax", +] + [[package]] name = "as-raw-xcb-connection" version = "1.0.1" @@ -124,6 +345,15 @@ dependencies = [ "libloading 0.8.3", ] +[[package]] +name = "atoi" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f28d99ec8bfea296261ca1af174f24225171fea9664ba9003cbebee704810528" +dependencies = [ + "num-traits", +] + [[package]] name = "atomic-waker" version = "1.1.2" @@ -140,7 +370,9 @@ checksum = "f1fdabc7756949593fe60f30ec81974b613357de856987752631dea1e3394c80" name = "avenger" version = "0.0.8" dependencies = [ + "arrow", "image", + "itertools", "lyon_extra", "lyon_path", "serde", @@ -185,6 +417,12 @@ dependencies = [ "winit", ] +[[package]] +name = "base64" +version = "0.22.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" + [[package]] name = "bit-set" version = "0.5.3" @@ -340,6 +578,18 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" +[[package]] +name = "chrono" +version = "0.4.38" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a21f936df1771bf62b77f047b726c4625ff2e8aa607c01ec06e5a05bd8463401" +dependencies = [ + "android-tzdata", + "iana-time-zone", + "num-traits", + "windows-targets 0.52.6", +] + [[package]] name = "codespan-reporting" version = "0.11.1" @@ -429,6 +679,26 @@ dependencies = [ "web-sys", ] +[[package]] +name = "const-random" +version = "0.1.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87e00182fe74b066627d63b85fd550ac2998d4b0bd86bfed477a0ae4c7c71359" +dependencies = [ + "const-random-macro", +] + +[[package]] +name = "const-random-macro" +version = "0.1.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f9d839f2a20b0aee515dc581a6172f2321f96cab76c1a38a4c584a194955390e" +dependencies = [ + "getrandom", + "once_cell", + "tiny-keccak", +] + [[package]] name = "core-foundation" version = "0.9.4" @@ -484,6 +754,12 @@ version = "0.8.19" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "248e3bacc7dc6baa3b21e405ee045c3047101a49145e7e9eca583ab4c2ca5345" +[[package]] +name = "crunchy" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" + [[package]] name = "csscolorparser" version = "0.7.0" @@ -493,6 +769,27 @@ dependencies = [ "phf", ] +[[package]] +name = "csv" +version = "1.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "acdc4883a9c96732e4733212c01447ebd805833b7275a73ca3ee080fd77afdaf" +dependencies = [ + "csv-core", + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "csv-core" +version = "0.1.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5efa2b3d7902f4b634a20cae3c9c4e6209dc4779feb6863329607560143efa70" +dependencies = [ + "memchr", +] + [[package]] name = "cursor-icon" version = "1.1.0" @@ -610,6 +907,16 @@ dependencies = [ "simd-adler32", ] +[[package]] +name = "flatbuffers" +version = "24.3.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8add37afff2d4ffa83bc748a70b4b1370984f6980768554182424ef71447c35f" +dependencies = [ + "bitflags 1.3.2", + "rustc_version", +] + [[package]] name = "flate2" version = "1.0.28" @@ -796,7 +1103,7 @@ checksum = "cc11df1ace8e7e564511f53af41f3e42ddc95b56fd07b3f4445d2a6048bc682c" dependencies = [ "bitflags 2.6.0", "gpu-descriptor-types 0.1.2", - "hashbrown", + "hashbrown 0.14.3", ] [[package]] @@ -807,7 +1114,7 @@ checksum = "9c08c1f623a8d0b722b8b99f821eb0ba672a1618f0d3b16ddbee1cedd2dd8557" dependencies = [ "bitflags 2.6.0", "gpu-descriptor-types 0.2.0", - "hashbrown", + "hashbrown 0.14.3", ] [[package]] @@ -828,6 +1135,17 @@ dependencies = [ "bitflags 2.6.0", ] +[[package]] +name = "half" +version = "2.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6dd08c532ae367adf81c312a4580bc67f1d0fe8bc9c460520283f4c0ff277888" +dependencies = [ + "cfg-if", + "crunchy", + "num-traits", +] + [[package]] name = "hashbrown" version = "0.14.3" @@ -838,6 +1156,12 @@ dependencies = [ "allocator-api2", ] +[[package]] +name = "hashbrown" +version = "0.15.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289" + [[package]] name = "hassle-rs" version = "0.11.0" @@ -871,6 +1195,29 @@ version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" +[[package]] +name = "iana-time-zone" +version = "0.1.61" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "235e081f3925a06703c2d0117ea8b91f042756fd6e7a6e5d901e8ca1a996b220" +dependencies = [ + "android_system_properties", + "core-foundation-sys", + "iana-time-zone-haiku", + "js-sys", + "wasm-bindgen", + "windows-core 0.52.0", +] + +[[package]] +name = "iana-time-zone-haiku" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" +dependencies = [ + "cc", +] + [[package]] name = "image" version = "0.25.5" @@ -890,7 +1237,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "168fb715dda47215e360912c096649d23d58bf392ac62f73919e831745e40f26" dependencies = [ "equivalent", - "hashbrown", + "hashbrown 0.14.3", ] [[package]] @@ -982,6 +1329,70 @@ version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" +[[package]] +name = "lexical-core" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0431c65b318a590c1de6b8fd6e72798c92291d27762d94c9e6c37ed7a73d8458" +dependencies = [ + "lexical-parse-float", + "lexical-parse-integer", + "lexical-util", + "lexical-write-float", + "lexical-write-integer", +] + +[[package]] +name = "lexical-parse-float" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eb17a4bdb9b418051aa59d41d65b1c9be5affab314a872e5ad7f06231fb3b4e0" +dependencies = [ + "lexical-parse-integer", + "lexical-util", + "static_assertions", +] + +[[package]] +name = "lexical-parse-integer" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5df98f4a4ab53bf8b175b363a34c7af608fe31f93cc1fb1bf07130622ca4ef61" +dependencies = [ + "lexical-util", + "static_assertions", +] + +[[package]] +name = "lexical-util" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85314db53332e5c192b6bca611fb10c114a80d1b831ddac0af1e9be1b9232ca0" +dependencies = [ + "static_assertions", +] + +[[package]] +name = "lexical-write-float" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e7c3ad4e37db81c1cbe7cf34610340adc09c322871972f74877a712abc6c809" +dependencies = [ + "lexical-util", + "lexical-write-integer", + "static_assertions", +] + +[[package]] +name = "lexical-write-integer" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eb89e9f6958b83258afa3deed90b5de9ef68eef090ad5086c791cd2345610162" +dependencies = [ + "lexical-util", + "static_assertions", +] + [[package]] name = "libc" version = "0.2.153" @@ -1127,9 +1538,9 @@ dependencies = [ [[package]] name = "memchr" -version = "2.7.2" +version = "2.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c8640c5d730cb13ebd907d8d04b52f55ac9a2eec55b440c8892f40d56c76c1d" +checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" [[package]] name = "memmap2" @@ -1260,11 +1671,75 @@ dependencies = [ "jni-sys", ] +[[package]] +name = "num" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "35bd024e8b2ff75562e5f34e7f4905839deb4b22955ef5e73d2fea1b9813cb23" +dependencies = [ + "num-bigint", + "num-complex", + "num-integer", + "num-iter", + "num-rational", + "num-traits", +] + +[[package]] +name = "num-bigint" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9" +dependencies = [ + "num-integer", + "num-traits", +] + +[[package]] +name = "num-complex" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73f88a1307638156682bada9d7604135552957b7818057dcef22705b4d509495" +dependencies = [ + "num-traits", +] + +[[package]] +name = "num-integer" +version = "0.1.46" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" +dependencies = [ + "num-traits", +] + +[[package]] +name = "num-iter" +version = "0.1.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1429034a0490724d0075ebb2bc9e875d6503c3cf69e235a8941aa757d83ef5bf" +dependencies = [ + "autocfg", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-rational" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f83d14da390562dca69fc84082e73e548e1ad308d24accdedd2720017cb37824" +dependencies = [ + "num-bigint", + "num-integer", + "num-traits", +] + [[package]] name = "num-traits" -version = "0.2.18" +version = "0.2.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da0df0e5185db44f69b44f26786fe401b6c293d1907744beaa7fa62b2e5a517a" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" dependencies = [ "autocfg", "libm", @@ -1812,6 +2287,15 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" +[[package]] +name = "rustc_version" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" +dependencies = [ + "semver", +] + [[package]] name = "rustix" version = "0.38.32" @@ -1865,6 +2349,12 @@ dependencies = [ "tiny-skia", ] +[[package]] +name = "semver" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61697e0a1c7e512e84a621326239844a24d8207b4669b41bc18b32ea5cbf988b" + [[package]] name = "serde" version = "1.0.197" @@ -2064,6 +2554,15 @@ dependencies = [ "syn 2.0.89", ] +[[package]] +name = "tiny-keccak" +version = "2.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c9d3793400a45f954c52e73d068316d76b6f4e36977e3fcebb13a2721e80237" +dependencies = [ + "crunchy", +] + [[package]] name = "tiny-skia" version = "0.11.4"