From c4adbb78ae2d77b35f186282e55753ae012a3087 Mon Sep 17 00:00:00 2001 From: Jon Mease Date: Thu, 4 Jan 2024 07:48:45 -0500 Subject: [PATCH 1/4] Move *Instance structs to renderers, store encoding Values in EncodingValue enum --- vega-wgpu-renderer/Cargo.toml | 1 + vega-wgpu-renderer/src/renderers/canvas.rs | 35 ++- vega-wgpu-renderer/src/renderers/rect.rs | 31 ++- vega-wgpu-renderer/src/renderers/rule.rs | 36 ++- vega-wgpu-renderer/src/renderers/symbol.rs | 28 +- vega-wgpu-renderer/src/renderers/text.rs | 63 ++++- vega-wgpu-renderer/src/scene/group.rs | 73 +++++ vega-wgpu-renderer/src/scene/mod.rs | 6 +- vega-wgpu-renderer/src/scene/rect.rs | 142 +++++++--- vega-wgpu-renderer/src/scene/rule.rs | 165 +++++++---- vega-wgpu-renderer/src/scene/scene_graph.rs | 141 ++-------- vega-wgpu-renderer/src/scene/symbol.rs | 131 ++++++--- vega-wgpu-renderer/src/scene/text.rs | 294 +++++++++++++++----- vega-wgpu-renderer/src/scene/value.rs | 24 ++ vega-wgpu-renderer/src/specs/mark.rs | 4 +- vega-wgpu-renderer/src/specs/rule.rs | 2 + 16 files changed, 832 insertions(+), 344 deletions(-) create mode 100644 vega-wgpu-renderer/src/scene/group.rs create mode 100644 vega-wgpu-renderer/src/scene/value.rs diff --git a/vega-wgpu-renderer/Cargo.toml b/vega-wgpu-renderer/Cargo.toml index 716026b..571b44a 100644 --- a/vega-wgpu-renderer/Cargo.toml +++ b/vega-wgpu-renderer/Cargo.toml @@ -22,6 +22,7 @@ csscolorparser = "0.6.2" image = "0.24.7" futures-intrusive = "^0.5" glyphon = { git = "https://github.com/grovesNL/glyphon.git", rev="941309aed230d7110bfec0d4af502ecb4648cf90" } +itertools = "0.12.0" [dev-dependencies] dssim = "3.2.4" diff --git a/vega-wgpu-renderer/src/renderers/canvas.rs b/vega-wgpu-renderer/src/renderers/canvas.rs index 9a4733d..afeb082 100644 --- a/vega-wgpu-renderer/src/renderers/canvas.rs +++ b/vega-wgpu-renderer/src/renderers/canvas.rs @@ -1,14 +1,9 @@ use crate::error::VegaWgpuError; use crate::renderers::mark::GeomMarkRenderer; -use crate::renderers::rect::RectShader; -use crate::renderers::rule::RuleShader; -use crate::renderers::symbol::SymbolShader; -use crate::renderers::text::TextMarkRenderer; -use crate::scene::rect::RectMark; -use crate::scene::rule::RuleMark; -use crate::scene::scene_graph::{SceneGraph, SceneGroup, SceneMark}; -use crate::scene::symbol::SymbolMark; -use crate::scene::text::TextMark; +use crate::renderers::rect::{RectInstance, RectShader}; +use crate::renderers::rule::{RuleInstance, RuleShader}; +use crate::renderers::symbol::{SymbolInstance, SymbolShader}; +use crate::renderers::text::{TextInstance, TextMarkRenderer}; use image::imageops::crop_imm; use wgpu::{ Adapter, Buffer, BufferAddress, BufferDescriptor, BufferUsages, CommandBuffer, @@ -22,6 +17,16 @@ use wgpu::{ use winit::event::WindowEvent; use winit::window::Window; +use crate::scene::{ + group::SceneGroup, + rect::RectMark, + rule::RuleMark, + scene_graph::{SceneGraph, SceneMark}, + symbol::SymbolMark, + text::TextMark, +}; + + #[repr(C)] #[derive(Copy, Clone, Debug, bytemuck::Pod, bytemuck::Zeroable)] pub struct CanvasUniform { @@ -48,46 +53,50 @@ pub trait Canvas { fn sample_count(&self) -> u32; fn add_symbol_mark(&mut self, mark: &SymbolMark) { + let instances = SymbolInstance::iter_from_spec(mark).collect::>(); self.add_mark_renderer(MarkRenderer::Geom(GeomMarkRenderer::new( self.device(), *self.uniform(), self.texture_format(), self.sample_count(), Box::new(SymbolShader::new(mark.shape)), - mark.instances.as_slice(), + instances.as_slice(), ))); } fn add_rect_mark(&mut self, mark: &RectMark) { + let instances = RectInstance::iter_from_spec(mark).collect::>(); self.add_mark_renderer(MarkRenderer::Geom(GeomMarkRenderer::new( self.device(), *self.uniform(), self.texture_format(), self.sample_count(), Box::new(RectShader::new()), - mark.instances.as_slice(), + instances.as_slice(), ))); } fn add_rule_mark(&mut self, mark: &RuleMark) { + let instances = RuleInstance::iter_from_spec(mark).collect::>(); self.add_mark_renderer(MarkRenderer::Geom(GeomMarkRenderer::new( self.device(), *self.uniform(), self.texture_format(), self.sample_count(), Box::new(RuleShader::new()), - mark.instances.as_slice(), + instances.as_slice(), ))); } fn add_text_mark(&mut self, mark: &TextMark) { + let instances = TextInstance::iter_from_spec(mark).collect::>(); self.add_mark_renderer(MarkRenderer::Text(TextMarkRenderer::new( self.device(), self.queue(), *self.uniform(), self.texture_format(), self.sample_count(), - mark.instances.clone(), + instances, ))); } diff --git a/vega-wgpu-renderer/src/renderers/rect.rs b/vega-wgpu-renderer/src/renderers/rect.rs index 3cdf22f..1bf601f 100644 --- a/vega-wgpu-renderer/src/renderers/rect.rs +++ b/vega-wgpu-renderer/src/renderers/rect.rs @@ -1,6 +1,35 @@ +use itertools::izip; use crate::renderers::mark::MarkShader; use crate::renderers::vertex::Vertex; -use crate::scene::rect::RectInstance; +use crate::scene::rect::RectMark; + +#[repr(C)] +#[derive(Copy, Clone, Debug, bytemuck::Pod, bytemuck::Zeroable)] +pub struct RectInstance { + pub position: [f32; 2], + pub color: [f32; 3], + pub width: f32, + pub height: f32, +} + +impl RectInstance { + pub fn iter_from_spec(mark: &RectMark) -> impl Iterator + '_{ + izip!( + mark.x_iter(), + mark.y_iter(), + mark.width_iter(), + mark.height_iter(), + mark.fill_iter(), + ).map(|(x, y, width, height, fill)| { + RectInstance { + position: [*x, *y], + width: *width, + height: *height, + color: *fill, + } + }) + } +} pub struct RectShader { verts: Vec, diff --git a/vega-wgpu-renderer/src/renderers/rule.rs b/vega-wgpu-renderer/src/renderers/rule.rs index 5fb5690..7d965a1 100644 --- a/vega-wgpu-renderer/src/renderers/rule.rs +++ b/vega-wgpu-renderer/src/renderers/rule.rs @@ -1,6 +1,40 @@ +use itertools::izip; use crate::renderers::mark::MarkShader; use crate::renderers::vertex::Vertex; -use crate::scene::rule::RuleInstance; +use crate::scene::rule::RuleMark; + +#[repr(C)] +#[derive(Copy, Clone, Debug, bytemuck::Pod, bytemuck::Zeroable)] +pub struct RuleInstance { + pub x0: f32, + pub y0: f32, + pub x1: f32, + pub y1: f32, + pub stroke: [f32; 3], + pub stroke_width: f32, +} + +impl RuleInstance { + pub fn iter_from_spec(mark: &RuleMark) -> impl Iterator + '_ { + izip!( + mark.x0_iter(), + mark.y0_iter(), + mark.x1_iter(), + mark.y1_iter(), + mark.stroke_iter(), + mark.stroke_width_iter(), + ).map(|(x0, y0, x1, y1, stroke, stroke_width)| { + RuleInstance { + x0: *x0, + y0: *y0, + x1: *x1, + y1: *y1, + stroke: *stroke, + stroke_width: *stroke_width, + } + }) + } +} pub struct RuleShader { verts: Vec, diff --git a/vega-wgpu-renderer/src/renderers/symbol.rs b/vega-wgpu-renderer/src/renderers/symbol.rs index a3dafab..15172ea 100644 --- a/vega-wgpu-renderer/src/renderers/symbol.rs +++ b/vega-wgpu-renderer/src/renderers/symbol.rs @@ -1,7 +1,33 @@ use crate::renderers::mark::MarkShader; use crate::renderers::vertex::Vertex; -use crate::scene::symbol::SymbolInstance; +use crate::scene::symbol::SymbolMark; use crate::specs::symbol::SymbolShape; +use itertools::izip; + +#[repr(C)] +#[derive(Copy, Clone, Debug, bytemuck::Pod, bytemuck::Zeroable)] +pub struct SymbolInstance { + pub position: [f32; 2], + pub color: [f32; 3], + pub size: f32, +} + +impl SymbolInstance { + pub fn iter_from_spec(mark: &SymbolMark) -> impl Iterator + '_ { + izip!( + mark.x_iter(), + mark.y_iter(), + mark.fill_iter(), + mark.size_iter(), + ).map(|(x, y, fill, size)| { + SymbolInstance { + position: [*x, *y], + color: *fill, + size: *size, + } + }) + } +} pub struct SymbolShader { verts: Vec, diff --git a/vega-wgpu-renderer/src/renderers/text.rs b/vega-wgpu-renderer/src/renderers/text.rs index 976c369..e97f1bb 100644 --- a/vega-wgpu-renderer/src/renderers/text.rs +++ b/vega-wgpu-renderer/src/renderers/text.rs @@ -1,14 +1,73 @@ use crate::renderers::canvas::CanvasUniform; -use crate::scene::text::TextInstance; -use crate::specs::text::{FontWeightNameSpec, FontWeightSpec, TextAlignSpec, TextBaselineSpec}; +use crate::specs::text::{FontStyleSpec, FontWeightNameSpec, FontWeightSpec, TextAlignSpec, TextBaselineSpec}; use glyphon::{ Attrs, Buffer, Color, Family, FontSystem, Metrics, Resolution, Shaping, SwashCache, TextArea, TextAtlas, TextBounds, TextRenderer, Weight, }; +use itertools::izip; use wgpu::{ CommandBuffer, CommandEncoderDescriptor, Device, MultisampleState, Operations, Queue, RenderPassColorAttachment, RenderPassDescriptor, TextureFormat, TextureView, }; +use crate::scene::text::TextMark; + +#[derive(Clone, Debug)] +pub struct TextInstance { + pub text: String, + pub position: [f32; 2], + pub color: [f32; 3], + pub opacity: f32, + pub align: TextAlignSpec, + pub angle: f32, + pub baseline: TextBaselineSpec, + pub dx: f32, + pub dy: f32, + pub font: String, + pub font_size: f32, + pub font_weight: FontWeightSpec, + pub font_style: FontStyleSpec, + pub limit: f32, +} + +impl TextInstance { + pub fn iter_from_spec(mark: &TextMark) -> impl Iterator + '_ { + izip!( + mark.text_iter(), + mark.x_iter(), + mark.y_iter(), + mark.color_iter(), + mark.opacity_iter(), + mark.align_iter(), + mark.angle_iter(), + mark.baseline_iter(), + mark.dx_iter(), + mark.dy_iter(), + mark.font_iter(), + mark.font_size_iter(), + mark.font_weight_iter(), + mark.font_style_iter(), + mark.limit_iter(), + ).map(|(text, x, y, color, opacity, align, angle, baseline, dx, dy, font, font_size, font_weight, font_style, limit)| { + TextInstance { + text: text.clone(), + position: [*x, *y], + color: *color, + opacity: *opacity, + align: *align, + angle: *angle, + baseline: *baseline, + dx: *dx, + dy: *dy, + font: font.clone(), + font_size: *font_size, + font_weight: *font_weight, + font_style: *font_style, + limit: *limit, + } + }) + } +} + pub struct TextMarkRenderer { pub font_system: FontSystem, diff --git a/vega-wgpu-renderer/src/scene/group.rs b/vega-wgpu-renderer/src/scene/group.rs new file mode 100644 index 0000000..a407e9e --- /dev/null +++ b/vega-wgpu-renderer/src/scene/group.rs @@ -0,0 +1,73 @@ +use crate::error::VegaWgpuError; +use crate::scene::{ + rect::RectMark, + rule::RuleMark, + scene_graph::SceneMark, + symbol::SymbolMark, + text::TextMark, +}; +use crate::specs::group::GroupItemSpec; +use crate::specs::mark::{MarkContainerSpec, MarkSpec}; + +#[derive(Debug, Clone, Copy)] +pub struct GroupBounds { + pub x: f32, + pub y: f32, + pub width: f32, + pub height: f32, +} + +#[derive(Debug, Clone)] +pub struct SceneGroup { + pub bounds: GroupBounds, + pub marks: Vec, +} + +impl SceneGroup { + pub fn from_spec( + spec: &MarkContainerSpec, + origin: [f32; 2], + ) -> Result, VegaWgpuError> { + let mut scene_groups: Vec = Vec::new(); + for group_item_spec in &spec.items { + let new_origin = [group_item_spec.x + origin[0], group_item_spec.y + origin[1]]; + + let mut group_marks: Vec = Vec::new(); + for item in &group_item_spec.items { + let item_marks: Vec<_> = match item { + MarkSpec::Group(group) => SceneGroup::from_spec(group, new_origin)? + .into_iter() + .map(SceneMark::Group) + .collect(), + MarkSpec::Rect(mark) => { + vec![SceneMark::Rect(RectMark::from_spec(mark, new_origin)?)] + } + MarkSpec::Rule(mark) => { + vec![SceneMark::Rule(RuleMark::from_spec(mark, new_origin)?)] + } + MarkSpec::Symbol(mark) => { + vec![SceneMark::Symbol(SymbolMark::from_spec(mark, new_origin)?)] + } + MarkSpec::Text(mark) => { + vec![SceneMark::Text(TextMark::from_spec(mark, new_origin)?)] + } + _ => { + println!("Mark type not yet supported: {:?}", item); + continue; + } + }; + group_marks.extend(item_marks); + } + scene_groups.push(Self { + bounds: GroupBounds { + x: group_item_spec.x, + y: group_item_spec.y, + width: group_item_spec.width.unwrap_or(0.0), // What should happen here? + height: group_item_spec.height.unwrap_or(0.0), // What should happen here? + }, + marks: group_marks, + }) + } + Ok(scene_groups) + } +} diff --git a/vega-wgpu-renderer/src/scene/mod.rs b/vega-wgpu-renderer/src/scene/mod.rs index e031364..2e550f2 100644 --- a/vega-wgpu-renderer/src/scene/mod.rs +++ b/vega-wgpu-renderer/src/scene/mod.rs @@ -1,5 +1,7 @@ -pub mod rect; pub mod rule; -pub mod scene_graph; +pub mod value; pub mod symbol; +pub mod rect; pub mod text; +pub mod scene_graph; +pub mod group; \ No newline at end of file diff --git a/vega-wgpu-renderer/src/scene/rect.rs b/vega-wgpu-renderer/src/scene/rect.rs index 6415e98..0784c5f 100644 --- a/vega-wgpu-renderer/src/scene/rect.rs +++ b/vega-wgpu-renderer/src/scene/rect.rs @@ -1,61 +1,119 @@ use crate::error::VegaWgpuError; +use crate::scene::value::EncodingValue; use crate::specs::mark::MarkContainerSpec; use crate::specs::rect::RectItemSpec; -#[derive(Debug, Clone)] +use serde::{Serialize, Deserialize}; + +#[derive(Debug, Clone, Serialize, Deserialize)] +#[serde(rename_all="kebab-case")] pub struct RectMark { - pub instances: Vec, + pub name: String, pub clip: bool, + pub len: u32, + pub x: EncodingValue, + pub y: EncodingValue, + pub width: EncodingValue, + pub height: EncodingValue, + pub fill: EncodingValue<[f32; 3]>, } impl RectMark { - pub fn from_spec( - spec: &MarkContainerSpec, - origin: [f32; 2], - ) -> Result { - let instances = RectInstance::from_specs(spec.items.as_slice(), origin)?; + pub fn x_iter(&self) -> Box + '_> { + self.x.as_iter(self.len as usize) + } - Ok(Self { - instances, - clip: spec.clip, - }) + pub fn y_iter(&self) -> Box + '_> { + self.y.as_iter(self.len as usize) } -} -#[repr(C)] -#[derive(Copy, Clone, Debug, bytemuck::Pod, bytemuck::Zeroable)] -pub struct RectInstance { - pub position: [f32; 2], - pub color: [f32; 3], - pub width: f32, - pub height: f32, + pub fn width_iter(&self) -> Box + '_> { + self.width.as_iter(self.len as usize) + } + + pub fn height_iter(&self) -> Box + '_> { + self.height.as_iter(self.len as usize) + } + + pub fn fill_iter(&self) -> Box + '_> { + self.fill.as_iter(self.len as usize) + } } -impl RectInstance { - pub fn from_spec(item_spec: &RectItemSpec, origin: [f32; 2]) -> Result { - // TODO: x2, y2 - let color = if let Some(fill) = &item_spec.fill { - let c = csscolorparser::parse(fill)?; - [c.r as f32, c.g as f32, c.b as f32] - } else { - [0.5f32, 0.5, 0.5] - }; - - Ok(Self { - position: [item_spec.x + origin[0], item_spec.y + origin[1]], - color, - width: item_spec.width.unwrap(), - height: item_spec.height.unwrap(), - }) +impl Default for RectMark { + fn default() -> Self { + Self { + name: "rule_mark".to_string(), + clip: true, + len: 1, + x: EncodingValue::Scalar { value: 0.0 }, + y: EncodingValue::Scalar { value: 0.0 }, + width: EncodingValue::Scalar { value: 0.0 }, + height: EncodingValue::Scalar { value: 0.0 }, + fill: EncodingValue::Scalar { value: [0.0, 0.0, 0.0] }, + } } +} - pub fn from_specs( - item_specs: &[RectItemSpec], + +impl RectMark { + pub fn from_spec( + spec: &MarkContainerSpec, origin: [f32; 2], - ) -> Result, VegaWgpuError> { - item_specs - .iter() - .map(|item| Self::from_spec(item, origin)) - .collect::, VegaWgpuError>>() + ) -> Result { + + // Init mark with scalar defaults + let mut mark = RectMark::default(); + if let Some(name) = &spec.name { + mark.name = name.clone(); + } + + // propagate clip + mark.clip = spec.clip; + + // Init vector for each encoding channel + let mut x = Vec::::new(); + let mut y = Vec::::new(); + let mut width = Vec::::new(); + let mut height = Vec::::new(); + let mut fill = Vec::<[f32; 3]>::new(); + + // For each item, append explicit values to corresponding vector + for item in &spec.items { + x.push(item.x + origin[0]); + y.push(item.y + origin[1]); + if let Some(v) = item.width { + width.push(v); + } + if let Some(v) = item.height { + height.push(v); + } + if let Some(v) = &item.fill { + let c = csscolorparser::parse(v)?; + fill.push([c.r as f32, c.g as f32, c.b as f32]) + } + } + + // Override values with vectors + let len = spec.items.len(); + mark.len = len as u32; + + if x.len() == len { + mark.x = EncodingValue::Array {values: x }; + } + if y.len() == len { + mark.y = EncodingValue::Array {values: y }; + } + if width.len() == len { + mark.width = EncodingValue::Array {values: width }; + } + if height.len() == len { + mark.height = EncodingValue::Array {values: height }; + } + if fill.len() == len { + mark.fill = EncodingValue::Array {values: fill }; + } + + Ok(mark) } } diff --git a/vega-wgpu-renderer/src/scene/rule.rs b/vega-wgpu-renderer/src/scene/rule.rs index 5a6ecd5..c366d89 100644 --- a/vega-wgpu-renderer/src/scene/rule.rs +++ b/vega-wgpu-renderer/src/scene/rule.rs @@ -1,70 +1,137 @@ use crate::error::VegaWgpuError; +use crate::scene::value::{EncodingValue, StrokeCap}; use crate::specs::mark::MarkContainerSpec; use crate::specs::rule::RuleItemSpec; +use serde::{Serialize, Deserialize}; -#[derive(Debug, Clone)] +#[derive(Debug, Clone, Serialize, Deserialize)] +#[serde(rename_all="kebab-case")] pub struct RuleMark { - pub instances: Vec, + pub name: String, pub clip: bool, + pub len: u32, + pub x0: EncodingValue, + pub y0: EncodingValue, + pub x1: EncodingValue, + pub y1: EncodingValue, + pub stroke: EncodingValue<[f32; 3]>, + pub stroke_width: EncodingValue, + pub stroke_cap: EncodingValue, } +impl RuleMark { + pub fn x0_iter(&self) -> Box + '_> { + self.x0.as_iter(self.len as usize) + } + pub fn y0_iter(&self) -> Box + '_> { + self.y0.as_iter(self.len as usize) + } + pub fn x1_iter(&self) -> Box + '_> { + self.x1.as_iter(self.len as usize) + } + pub fn y1_iter(&self) -> Box + '_> { + self.y1.as_iter(self.len as usize) + } + pub fn stroke_iter(&self) -> Box + '_> { + self.stroke.as_iter(self.len as usize) + } + pub fn stroke_width_iter(&self) -> Box + '_> { + self.stroke_width.as_iter(self.len as usize) + } + pub fn stroke_cap_iter(&self) -> Box + '_> { + self.stroke_cap.as_iter(self.len as usize) + } +} + +impl Default for RuleMark { + fn default() -> Self { + Self { + name: "rule_mark".to_string(), + clip: true, + len: 1, + x0: EncodingValue::Scalar { value: 0.0 }, + y0: EncodingValue::Scalar { value: 0.0 }, + x1: EncodingValue::Scalar { value: 0.0 }, + y1: EncodingValue::Scalar { value: 0.0 }, + stroke: EncodingValue::Scalar { value: [0.0, 0.0, 0.0] }, + stroke_width: EncodingValue::Scalar { value: 1.0 }, + stroke_cap: EncodingValue::Scalar { value: StrokeCap::Butt }, + } + } +} + + impl RuleMark { pub fn from_spec( spec: &MarkContainerSpec, origin: [f32; 2], ) -> Result { - let instances = RuleInstance::from_specs(spec.items.as_slice(), origin)?; - Ok(Self { - instances, - clip: spec.clip, - }) - } -} + // Init mark with scalar defaults + let mut mark = RuleMark::default(); + if let Some(name) = &spec.name { + mark.name = name.clone(); + } -#[repr(C)] -#[derive(Copy, Clone, Debug, bytemuck::Pod, bytemuck::Zeroable)] -pub struct RuleInstance { - pub x0: f32, - pub y0: f32, - pub x1: f32, - pub y1: f32, - pub stroke: [f32; 3], - pub stroke_width: f32, -} + // propagate clip + mark.clip = spec.clip; -impl RuleInstance { - pub fn from_spec(item_spec: &RuleItemSpec, origin: [f32; 2]) -> Result { - let stroke = if let Some(stroke) = &item_spec.stroke { - let c = csscolorparser::parse(stroke)?; - [c.r as f32, c.g as f32, c.b as f32] - } else { - [0.5f32, 0.5, 0.5] - }; + // Init vector for each encoding channel + let mut x0 = Vec::::new(); + let mut y0 = Vec::::new(); + let mut x1 = Vec::::new(); + let mut y1 = Vec::::new(); + let mut stroke = Vec::<[f32; 3]>::new(); + let mut stroke_width = Vec::::new(); + let mut stroke_cap = Vec::::new(); - let x0 = item_spec.x + origin[0]; - let y0 = item_spec.y + origin[1]; - let x1 = item_spec.x2.unwrap_or(item_spec.x) + origin[0]; - let y1 = item_spec.y2.unwrap_or(item_spec.y) + origin[1]; - let stroke_width = item_spec.stroke_width.unwrap_or(1.0); + // For each item, append explicit values to corresponding vector + for item in &spec.items { + x0.push(item.x + origin[0]); + y0.push(item.y + origin[1]); + x1.push(item.x2.unwrap_or(item.x) + origin[0]); + y1.push(item.y2.unwrap_or(item.y) + origin[1]); - Ok(Self { - x0, - y0, - x1, - y1, - stroke, - stroke_width, - }) - } + if let Some(s) = &item.stroke { + let c = csscolorparser::parse(s)?; + stroke.push([c.r as f32, c.g as f32, c.b as f32]) + } - pub fn from_specs( - item_specs: &[RuleItemSpec], - origin: [f32; 2], - ) -> Result, VegaWgpuError> { - item_specs - .iter() - .map(|item| Self::from_spec(item, origin)) - .collect::, VegaWgpuError>>() + if let Some(s) = item.stroke_width { + stroke_width.push(s); + } + + if let Some(s) = item.stroke_cap { + stroke_cap.push(s); + } + } + + // Override values with vectors + let len = spec.items.len(); + mark.len = len as u32; + + if x0.len() == len { + mark.x0 = EncodingValue::Array {values: x0}; + } + if y0.len() == len { + mark.y0 = EncodingValue::Array {values: y0}; + } + if x1.len() == len { + mark.x1 = EncodingValue::Array {values: x1}; + } + if y1.len() == len { + mark.y1 = EncodingValue::Array {values: y1}; + } + if stroke.len() == len { + mark.stroke = EncodingValue::Array {values: stroke}; + } + if stroke_width.len() == len { + mark.stroke_width = EncodingValue::Array {values: stroke_width}; + } + if stroke_cap.len() == len { + mark.stroke_cap = EncodingValue::Array {values: stroke_cap}; + } + + Ok(mark) } } diff --git a/vega-wgpu-renderer/src/scene/scene_graph.rs b/vega-wgpu-renderer/src/scene/scene_graph.rs index 871a571..448a68c 100644 --- a/vega-wgpu-renderer/src/scene/scene_graph.rs +++ b/vega-wgpu-renderer/src/scene/scene_graph.rs @@ -1,51 +1,31 @@ use crate::error::VegaWgpuError; -use crate::scene::rect::RectMark; -use crate::scene::rule::RuleMark; -use crate::scene::symbol::SymbolMark; -use crate::scene::text::TextMark; +use crate::scene::{ + group::SceneGroup, + rect::RectMark, + rule::RuleMark, + symbol::SymbolMark, + text::TextMark +}; use crate::specs::group::GroupItemSpec; -use crate::specs::mark::{MarkContainerSpec, MarkSpec}; +use crate::specs::mark::MarkContainerSpec; -pub trait SceneVisitor { - type Error; - fn visit_group(&mut self, group: &SceneGroup, bounds: GroupBounds) -> Result<(), Self::Error>; - - fn visit_symbol_mark( - &mut self, - mark: &SymbolMark, - bounds: GroupBounds, - ) -> Result<(), Self::Error>; - - fn visit_rect_mark(&mut self, mark: &RectMark, bounds: GroupBounds) -> Result<(), Self::Error>; - - fn visit_rule_mark(&mut self, mark: &RuleMark, bounds: GroupBounds) -> Result<(), Self::Error>; - - fn visit_text_mark(&mut self, mark: &TextMark, bounds: GroupBounds) -> Result<(), Self::Error>; +#[derive(Debug, Clone)] +pub enum SceneMark { + Symbol(SymbolMark), + Rect(RectMark), + Rule(RuleMark), + Text(TextMark), + Group(SceneGroup), } #[derive(Debug, Clone)] pub struct SceneGraph { - pub(crate) groups: Vec, - pub(crate) width: f32, - pub(crate) height: f32, + pub groups: Vec, + pub width: f32, + pub height: f32, } impl SceneGraph { - pub fn walk(&self, visitor: &mut dyn SceneVisitor) -> Result<(), E> { - for group in &self.groups { - visitor.visit_group( - group, - GroupBounds { - x: 0.0, - y: 0.0, - width: self.width, - height: self.height, - }, - )? - } - Ok(()) - } - pub fn from_spec( spec: &MarkContainerSpec, origin: [f32; 2], @@ -59,88 +39,3 @@ impl SceneGraph { }) } } - -#[derive(Debug, Clone)] -pub struct SceneGroup { - pub bounds: GroupBounds, - pub marks: Vec, -} - -impl SceneGroup { - pub fn walk(&self, visitor: &mut dyn SceneVisitor) -> Result<(), E> { - for mark in &self.marks { - match mark { - SceneMark::Symbol(mark) => visitor.visit_symbol_mark(mark, self.bounds)?, - SceneMark::Rect(mark) => visitor.visit_rect_mark(mark, self.bounds)?, - SceneMark::Rule(mark) => visitor.visit_rule_mark(mark, self.bounds)?, - SceneMark::Text(mark) => visitor.visit_text_mark(mark, self.bounds)?, - SceneMark::Group(group) => visitor.visit_group(group, self.bounds)?, - } - } - Ok(()) - } - - pub fn from_spec( - spec: &MarkContainerSpec, - origin: [f32; 2], - ) -> Result, VegaWgpuError> { - let mut scene_groups: Vec = Vec::new(); - for group_item_spec in &spec.items { - let new_origin = [group_item_spec.x + origin[0], group_item_spec.y + origin[1]]; - - let mut group_marks: Vec = Vec::new(); - for item in &group_item_spec.items { - let item_marks: Vec<_> = match item { - MarkSpec::Group(group) => SceneGroup::from_spec(group, new_origin)? - .into_iter() - .map(SceneMark::Group) - .collect(), - MarkSpec::Rect(mark) => { - vec![SceneMark::Rect(RectMark::from_spec(mark, new_origin)?)] - } - MarkSpec::Rule(mark) => { - vec![SceneMark::Rule(RuleMark::from_spec(mark, new_origin)?)] - } - MarkSpec::Symbol(mark) => { - vec![SceneMark::Symbol(SymbolMark::from_spec(mark, new_origin)?)] - } - MarkSpec::Text(mark) => { - vec![SceneMark::Text(TextMark::from_spec(mark, new_origin)?)] - } - _ => { - println!("Mark type not yet supported: {:?}", item); - continue; - } - }; - group_marks.extend(item_marks); - } - scene_groups.push(Self { - bounds: GroupBounds { - x: group_item_spec.x, - y: group_item_spec.y, - width: group_item_spec.width.unwrap_or(0.0), // What should happen here? - height: group_item_spec.height.unwrap_or(0.0), // What should happen here? - }, - marks: group_marks, - }) - } - Ok(scene_groups) - } -} - -#[derive(Debug, Clone)] -pub enum SceneMark { - Symbol(SymbolMark), - Rect(RectMark), - Rule(RuleMark), - Text(TextMark), - Group(SceneGroup), -} - -#[derive(Debug, Clone, Copy)] -pub struct GroupBounds { - pub x: f32, - pub y: f32, - pub width: f32, - pub height: f32, -} diff --git a/vega-wgpu-renderer/src/scene/symbol.rs b/vega-wgpu-renderer/src/scene/symbol.rs index 6415465..038f53b 100644 --- a/vega-wgpu-renderer/src/scene/symbol.rs +++ b/vega-wgpu-renderer/src/scene/symbol.rs @@ -1,12 +1,52 @@ use crate::error::VegaWgpuError; +use crate::scene::value::EncodingValue; use crate::specs::mark::MarkContainerSpec; use crate::specs::symbol::{SymbolItemSpec, SymbolShape}; +use serde::{Serialize, Deserialize}; -#[derive(Debug, Clone)] +#[derive(Debug, Clone, Serialize, Deserialize)] +#[serde(rename_all="kebab-case")] pub struct SymbolMark { - pub instances: Vec, - pub shape: SymbolShape, + pub name: String, pub clip: bool, + pub shape: SymbolShape, + pub len: u32, + pub x: EncodingValue, + pub y: EncodingValue, + pub fill: EncodingValue<[f32; 3]>, + pub size: EncodingValue, +} + +impl SymbolMark { + pub fn x_iter(&self) -> Box + '_> { + self.x.as_iter(self.len as usize) + } + + pub fn y_iter(&self) -> Box + '_> { + self.y.as_iter(self.len as usize) + } + + pub fn fill_iter(&self) -> Box + '_> { + self.fill.as_iter(self.len as usize) + } + + pub fn size_iter(&self) -> Box + '_> { + self.size.as_iter(self.len as usize) + } +} +impl Default for SymbolMark { + fn default() -> Self { + Self { + name: "".to_string(), + clip: true, + shape: Default::default(), + len: 1, + x: EncodingValue::Scalar { value: 0.0 }, + y: EncodingValue::Scalar { value: 0.0 }, + fill: EncodingValue::Scalar { value: [0.0, 0.0, 0.0] }, + size: EncodingValue::Scalar { value: 20.0 }, + } + } } impl SymbolMark { @@ -14,53 +54,62 @@ impl SymbolMark { spec: &MarkContainerSpec, origin: [f32; 2], ) -> Result { - let instances = SymbolInstance::from_specs(spec.items.as_slice(), origin)?; - // For now, grab the shape of the first item and use this for all items. - // Eventually we'll need to handle marks with mixed symbols + // Get shape of first item and use that for all items for now let first_shape = spec .items .get(0) .and_then(|item| item.shape) .unwrap_or_default(); - Ok(Self { - instances, + // Init mark with scalar defaults + let mut mark = SymbolMark { shape: first_shape, clip: spec.clip, - }) - } -} + ..Default::default() + }; -#[repr(C)] -#[derive(Copy, Clone, Debug, bytemuck::Pod, bytemuck::Zeroable)] -pub struct SymbolInstance { - pub position: [f32; 2], - pub color: [f32; 3], - pub size: f32, -} + if let Some(name) = &spec.name { + mark.name = name.clone(); + } -impl SymbolInstance { - pub fn from_spec(item_spec: &SymbolItemSpec, origin: [f32; 2]) -> Result { - let color = if let Some(fill) = &item_spec.fill { - let c = csscolorparser::parse(fill)?; - [c.r as f32, c.g as f32, c.b as f32] - } else { - [0.5f32, 0.5, 0.5] - }; - Ok(Self { - position: [item_spec.x + origin[0], item_spec.y + origin[1]], - color, - size: item_spec.size.unwrap_or(20.0), - }) - } + // Init vector for each encoding channel + let mut x = Vec::::new(); + let mut y = Vec::::new(); + let mut fill = Vec::<[f32; 3]>::new(); + let mut size = Vec::::new(); - pub fn from_specs( - item_specs: &[SymbolItemSpec], - origin: [f32; 2], - ) -> Result, VegaWgpuError> { - item_specs - .iter() - .map(|item| Self::from_spec(item, origin)) - .collect() + // For each item, append explicit values to corresponding vector + for item in &spec.items { + x.push(item.x + origin[0]); + y.push(item.y + origin[1]); + + if let Some(c) = &item.fill { + let c = csscolorparser::parse(c)?; + fill.push([c.r as f32, c.g as f32, c.b as f32]) + } + + if let Some(s) = item.size { + size.push(s); + } + } + + // Override values with vectors + let len = spec.items.len(); + mark.len = len as u32; + + if x.len() == len { + mark.x = EncodingValue::Array {values: x}; + } + if y.len() == len { + mark.y = EncodingValue::Array {values: y}; + } + if fill.len() == len { + mark.fill = EncodingValue::Array {values: fill}; + } + if size.len() == len { + mark.size = EncodingValue::Array {values: size}; + } + + Ok(mark) } -} +} \ No newline at end of file diff --git a/vega-wgpu-renderer/src/scene/text.rs b/vega-wgpu-renderer/src/scene/text.rs index 4900010..59e8114 100644 --- a/vega-wgpu-renderer/src/scene/text.rs +++ b/vega-wgpu-renderer/src/scene/text.rs @@ -1,82 +1,242 @@ use crate::error::VegaWgpuError; +use crate::scene::value::EncodingValue; use crate::specs::mark::MarkContainerSpec; -use crate::specs::text::{ - FontStyleSpec, FontWeightSpec, TextAlignSpec, TextBaselineSpec, TextItemSpec, -}; +use crate::specs::text::{FontStyleSpec, FontWeightNameSpec, FontWeightSpec, TextAlignSpec, TextBaselineSpec, TextItemSpec}; -#[derive(Debug, Clone)] +use serde::{Serialize, Deserialize}; + +#[derive(Debug, Clone, Serialize, Deserialize)] +#[serde(rename_all="kebab-case")] pub struct TextMark { - pub instances: Vec, + pub name: String, pub clip: bool, + pub len: u32, + pub text: EncodingValue, + pub x: EncodingValue, + pub y: EncodingValue, + pub align: EncodingValue, + pub baseline: EncodingValue, + pub opacity: EncodingValue, + pub angle: EncodingValue, + pub color: EncodingValue<[f32; 3]>, + pub dx: EncodingValue, + pub dy: EncodingValue, + pub font: EncodingValue, + pub font_size: EncodingValue, + pub font_weight: EncodingValue, + pub font_style: EncodingValue, + pub limit: EncodingValue, } impl TextMark { - pub fn from_spec( - spec: &MarkContainerSpec, - origin: [f32; 2], - ) -> Result { - let instances = TextInstance::from_specs(spec.items.as_slice(), origin)?; - Ok(Self { - instances, - clip: spec.clip, - }) + pub fn text_iter(&self) -> Box + '_> { + self.text.as_iter(self.len as usize) + } + pub fn x_iter(&self) -> Box + '_> { + self.x.as_iter(self.len as usize) + } + pub fn y_iter(&self) -> Box + '_> { + self.y.as_iter(self.len as usize) + } + pub fn align_iter(&self) -> Box + '_> { + self.align.as_iter(self.len as usize) + } + pub fn baseline_iter(&self) -> Box + '_> { + self.baseline.as_iter(self.len as usize) + } + pub fn opacity_iter(&self) -> Box + '_> { + self.opacity.as_iter(self.len as usize) + } + pub fn angle_iter(&self) -> Box + '_> { + self.angle.as_iter(self.len as usize) + } + pub fn color_iter(&self) -> Box + '_> { + self.color.as_iter(self.len as usize) + } + pub fn dx_iter(&self) -> Box + '_> { + self.dx.as_iter(self.len as usize) + } + pub fn dy_iter(&self) -> Box + '_> { + self.dx.as_iter(self.len as usize) + } + pub fn font_iter(&self) -> Box + '_> { + self.font.as_iter(self.len as usize) + } + pub fn font_size_iter(&self) -> Box + '_> { + self.font_size.as_iter(self.len as usize) + } + pub fn font_weight_iter(&self) -> Box + '_> { + self.font_weight.as_iter(self.len as usize) + } + pub fn font_style_iter(&self) -> Box + '_> { + self.font_style.as_iter(self.len as usize) + } + pub fn limit_iter(&self) -> Box + '_> { + self.limit.as_iter(self.len as usize) } } -#[derive(Clone, Debug)] -pub struct TextInstance { - pub text: String, - pub position: [f32; 2], - pub color: [f32; 3], - pub opacity: f32, - pub align: TextAlignSpec, - pub angle: f32, - pub baseline: TextBaselineSpec, - pub dx: f32, - pub dy: f32, - pub font: String, - pub font_size: f32, - pub font_weight: FontWeightSpec, - pub font_style: FontStyleSpec, - pub limit: f32, +impl Default for TextMark { + fn default() -> Self { + Self { + name: "text_mark".to_string(), + clip: true, + len: 1, + text: EncodingValue::Scalar { value: String::new() }, + x: EncodingValue::Scalar { value: 0.0 }, + y: EncodingValue::Scalar { value: 0.0 }, + align: EncodingValue::Scalar { value: TextAlignSpec::Left }, + baseline: EncodingValue::Scalar { value: TextBaselineSpec::Bottom }, + opacity: EncodingValue::Scalar { value: 1.0 }, + angle: EncodingValue::Scalar { value: 0.0 }, + color: EncodingValue::Scalar { value: [0.0, 0.0, 0.0] }, + dx: EncodingValue::Scalar { value: 0.0 }, + dy: EncodingValue::Scalar { value: 0.0 }, + font: EncodingValue::Scalar { value: "sans serif".to_string() }, + font_size: EncodingValue::Scalar { value: 10.0 }, + font_weight: EncodingValue::Scalar { value: FontWeightSpec::Name(FontWeightNameSpec::Normal) }, + font_style: EncodingValue::Scalar { value: FontStyleSpec::Normal }, + limit: EncodingValue::Scalar { value: 0.0 }, + } + } } -impl TextInstance { - pub fn from_spec(item_spec: &TextItemSpec, origin: [f32; 2]) -> Result { - let color = if let Some(fill) = &item_spec.fill { - let c = csscolorparser::parse(fill)?; - [c.r as f32, c.g as f32, c.b as f32] - } else { - [0.0, 0.0, 0.0] - }; - Ok(Self { - text: item_spec.text.clone(), - position: [item_spec.x + origin[0], item_spec.y + origin[1]], - color, - align: item_spec.align.unwrap_or_default(), - angle: item_spec.angle.unwrap_or(0.0), - baseline: item_spec.baseline.unwrap_or_default(), - dx: item_spec.dx.unwrap_or(0.0), - dy: item_spec.dy.unwrap_or(0.0), - opacity: item_spec.fill_opacity.unwrap_or(1.0), - font: item_spec - .font - .clone() - .unwrap_or_else(|| "Sans Serif".to_string()), - font_size: item_spec.font_size.unwrap_or(10.0), - font_weight: item_spec.font_weight.unwrap_or_default(), - font_style: item_spec.font_style.unwrap_or_default(), - limit: item_spec.limit.unwrap_or(0.0), - }) - } - - pub fn from_specs( - item_specs: &[TextItemSpec], +impl TextMark { + pub fn from_spec( + spec: &MarkContainerSpec, origin: [f32; 2], - ) -> Result, VegaWgpuError> { - item_specs - .iter() - .map(|item| Self::from_spec(item, origin)) - .collect() + ) -> Result { + + // Init mark with scalar defaults + let mut mark = TextMark::default(); + if let Some(name) = &spec.name { + mark.name = name.clone(); + } + + // propagate clip + mark.clip = spec.clip; + + // Init vector for each encoding channel + let mut text = Vec::::new(); + let mut x = Vec::::new(); + let mut y = Vec::::new(); + let mut align = Vec::::new(); + let mut baseline = Vec::::new(); + let mut opacity = Vec::::new(); + let mut angle = Vec::::new(); + let mut color = Vec::<[f32; 3]>::new(); + let mut dx = Vec::::new(); + let mut dy = Vec::::new(); + let mut font = Vec::::new(); + let mut font_size = Vec::::new(); + let mut font_weight = Vec::::new(); + let mut font_style = Vec::::new(); + let mut limit = Vec::::new(); + + for item in &spec.items { + x.push(item.x + origin[0]); + y.push(item.y + origin[1]); + text.push(item.text.clone()); + + if let Some(v) = item.align { + align.push(v); + } + + if let Some(v) = item.baseline { + baseline.push(v); + } + + if let Some(v) = item.fill_opacity { + opacity.push(v); + } + + if let Some(v) = item.angle { + angle.push(v); + } + + if let Some(v) = &item.fill { + let c = csscolorparser::parse(v)?; + color.push([c.r as f32, c.g as f32, c.b as f32]) + } + + if let Some(v) = item.dx { + dx.push(v); + } + + if let Some(v) = item.dy { + dy.push(v); + } + + if let Some(v) = &item.font { + font.push(v.clone()); + } + + if let Some(v) = item.font_size { + font_size.push(v); + } + + if let Some(v) = item.font_weight { + font_weight.push(v); + } + + if let Some(v) = item.font_style { + font_style.push(v); + } + + if let Some(v) = item.limit { + limit.push(v); + } + } + + // Override values with vectors + let len = spec.items.len(); + mark.len = len as u32; + + if x.len() == len { + mark.x = EncodingValue::Array {values: x }; + } + if y.len() == len { + mark.y = EncodingValue::Array {values: y }; + } + if text.len() == len { + mark.text = EncodingValue::Array {values: text }; + } + if align.len() == len { + mark.align = EncodingValue::Array {values: align }; + } + if baseline.len() == len { + mark.baseline = EncodingValue::Array {values: baseline }; + } + if opacity.len() == len { + mark.opacity = EncodingValue::Array {values: opacity }; + } + if angle.len() == len { + mark.angle = EncodingValue::Array {values: angle }; + } + if color.len() == len { + mark.color = EncodingValue::Array {values: color }; + } + if dx.len() == len { + mark.dx = EncodingValue::Array {values: dx }; + } + if dy.len() == len { + mark.dy = EncodingValue::Array {values: dy }; + } + if font.len() == len { + mark.font = EncodingValue::Array {values: font }; + } + if font_size.len() == len { + mark.font_size = EncodingValue::Array {values: font_size }; + } + if font_weight.len() == len { + mark.font_weight = EncodingValue::Array {values: font_weight }; + } + if font_style.len() == len { + mark.font_style = EncodingValue::Array {values: font_style }; + } + if limit.len() == len { + mark.limit = EncodingValue::Array {values: limit }; + } + Ok(mark) } -} +} \ No newline at end of file diff --git a/vega-wgpu-renderer/src/scene/value.rs b/vega-wgpu-renderer/src/scene/value.rs new file mode 100644 index 0000000..1dfaf5c --- /dev/null +++ b/vega-wgpu-renderer/src/scene/value.rs @@ -0,0 +1,24 @@ +use serde::{Serialize, Deserialize}; + +#[derive(Debug, Clone, Serialize, Deserialize)] +#[serde(tag = "type", rename_all="kebab-case")] +pub enum EncodingValue { + Scalar {value: T}, + Array {values: Vec} +} + +impl EncodingValue { + pub fn as_iter(&self, scalar_len: usize) -> Box + '_> { + match self { + EncodingValue::Scalar { value } => Box::new(std::iter::repeat(value).take(scalar_len)), + EncodingValue::Array { values } => Box::new(values.iter()) + } + } +} + +#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)] +pub enum StrokeCap { + Butt, + Round, + Square, +} diff --git a/vega-wgpu-renderer/src/specs/mark.rs b/vega-wgpu-renderer/src/specs/mark.rs index ffa3857..903e41e 100644 --- a/vega-wgpu-renderer/src/specs/mark.rs +++ b/vega-wgpu-renderer/src/specs/mark.rs @@ -30,10 +30,10 @@ pub enum MarkSpec { pub struct MarkContainerSpec { #[serde(default)] pub clip: bool, - interactive: bool, + pub interactive: bool, #[serde(default)] pub items: Vec, - name: Option, + pub name: Option, role: Option, zindex: Option, } diff --git a/vega-wgpu-renderer/src/specs/rule.rs b/vega-wgpu-renderer/src/specs/rule.rs index 7f9045f..1ad6f49 100644 --- a/vega-wgpu-renderer/src/specs/rule.rs +++ b/vega-wgpu-renderer/src/specs/rule.rs @@ -1,5 +1,6 @@ use crate::specs::mark::MarkItemSpec; use serde::{Deserialize, Serialize}; +use crate::scene::value::StrokeCap; #[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] @@ -10,6 +11,7 @@ pub struct RuleItemSpec { pub y2: Option, pub stroke: Option, pub stroke_width: Option, + pub stroke_cap: Option, } impl MarkItemSpec for RuleItemSpec {} From 30a8ccfb7310f4a74583b7c0ce4a8133d5d9438e Mon Sep 17 00:00:00 2001 From: Jon Mease Date: Thu, 4 Jan 2024 10:10:03 -0500 Subject: [PATCH 2/4] Refactor into multiple sg2d crates --- .gitignore | 2 +- Cargo.lock | 170 ++++++------ Cargo.toml | 11 +- README.md | 9 +- .../Cargo.toml | 0 .../README.md | 12 +- .../src/main.rs | 6 +- .../vega-scenegraphs}/rect/heatmap.dims.json | 0 .../vega-scenegraphs}/rect/heatmap.png | Bin .../vega-scenegraphs}/rect/heatmap.sg.json | 0 .../rect/stacked_bar.dims.json | 0 .../vega-scenegraphs}/rect/stacked_bar.png | Bin .../rect/stacked_bar.sg.json | 0 .../rule/wide_rule_axes.dims.json | 0 .../vega-scenegraphs}/rule/wide_rule_axes.png | Bin .../rule/wide_rule_axes.sg.json | 0 .../symbol/binned_scatter_arrow.dims.json | 0 .../symbol/binned_scatter_arrow.png | Bin .../symbol/binned_scatter_arrow.sg.json | 0 .../symbol/binned_scatter_circle.dims.json | 0 .../symbol/binned_scatter_circle.png | Bin .../symbol/binned_scatter_circle.sg.json | 0 .../symbol/binned_scatter_cross.dims.json | 0 .../symbol/binned_scatter_cross.png | Bin .../symbol/binned_scatter_cross.sg.json | 0 .../symbol/binned_scatter_diamonds.dims.json | 0 .../symbol/binned_scatter_diamonds.png | Bin .../symbol/binned_scatter_diamonds.sg.json | 0 .../symbol/binned_scatter_square.dims.json | 0 .../symbol/binned_scatter_square.png | Bin .../symbol/binned_scatter_square.sg.json | 0 .../binned_scatter_triangle-down.dims.json | 0 .../symbol/binned_scatter_triangle-down.png | Bin .../binned_scatter_triangle-down.sg.json | 0 .../binned_scatter_triangle-left.dims.json | 0 .../symbol/binned_scatter_triangle-left.png | Bin .../binned_scatter_triangle-left.sg.json | 0 .../binned_scatter_triangle-right.dims.json | 0 .../symbol/binned_scatter_triangle-right.png | Bin .../binned_scatter_triangle-right.sg.json | 0 .../binned_scatter_triangle-up.dims.json | 0 .../symbol/binned_scatter_triangle-up.png | Bin .../symbol/binned_scatter_triangle-up.sg.json | 0 .../symbol/binned_scatter_triangle.dims.json | 0 .../symbol/binned_scatter_triangle.png | Bin .../symbol/binned_scatter_triangle.sg.json | 0 .../symbol/binned_scatter_wedge.dims.json | 0 .../symbol/binned_scatter_wedge.png | Bin .../symbol/binned_scatter_wedge.sg.json | 0 .../text/bar_axis_labels.dims.json | 0 .../text/bar_axis_labels.png | Bin .../text/bar_axis_labels.sg.json | 0 .../vega-specs/rect/heatmap.vg.json | 0 .../vega-specs/rect/stacked_bar.vg.json | 0 .../vega-specs/rule/wide_rule_axes.vg.json | 0 .../symbol/binned_scatter_arrow.vg.json | 0 .../symbol/binned_scatter_circle.vg.json | 0 .../symbol/binned_scatter_cross.vg.json | 0 .../symbol/binned_scatter_diamonds.vg.json | 0 .../symbol/binned_scatter_square.vg.json | 0 .../binned_scatter_triangle-down.vg.json | 0 .../binned_scatter_triangle-left.vg.json | 0 .../binned_scatter_triangle-right.vg.json | 0 .../symbol/binned_scatter_triangle-up.vg.json | 0 .../symbol/binned_scatter_triangle.vg.json | 0 .../symbol/binned_scatter_wedge.vg.json | 0 .../vega-specs/text/bar_axis_labels.vg.json | 0 sg2d-vega/Cargo.toml | 13 + .../src/specs => sg2d-vega/src}/dims.rs | 2 +- sg2d-vega/src/error.rs | 10 + sg2d-vega/src/lib.rs | 4 + sg2d-vega/src/marks/group.rs | 60 +++++ sg2d-vega/src/marks/mark.rs | 38 +++ .../renderers => sg2d-vega/src/marks}/mod.rs | 5 +- sg2d-vega/src/marks/rect.rs | 79 ++++++ sg2d-vega/src/marks/rule.rs | 93 +++++++ sg2d-vega/src/marks/symbol.rs | 81 ++++++ sg2d-vega/src/marks/text.rs | 169 ++++++++++++ sg2d-vega/src/scene_graph.rs | 27 ++ sg2d-vega/tests/test_parsing.rs | 27 ++ {vega-wgpu-renderer => sg2d-wgpu}/Cargo.toml | 21 +- {vega-wgpu-renderer => sg2d-wgpu}/index.html | 2 +- .../src/renderers => sg2d-wgpu/src}/canvas.rs | 33 +-- .../src/error.rs | 6 +- {vega-wgpu-renderer => sg2d-wgpu}/src/lib.rs | 33 ++- {vega-wgpu-renderer => sg2d-wgpu}/src/main.rs | 2 +- .../src/marks}/circle.wgsl | 0 .../renderers => sg2d-wgpu/src/marks}/mark.rs | 4 +- .../src/scene => sg2d-wgpu/src/marks}/mod.rs | 6 +- .../src/marks}/polygon_symbol.wgsl | 0 .../renderers => sg2d-wgpu/src/marks}/rect.rs | 21 +- .../src/marks}/rect.wgsl | 0 .../renderers => sg2d-wgpu/src/marks}/rule.rs | 25 +- .../src/marks}/rule.wgsl | 0 .../src/marks}/symbol.rs | 20 +- .../renderers => sg2d-wgpu/src/marks}/text.rs | 65 +++-- .../src/renderers => sg2d-wgpu/src}/vertex.rs | 0 .../tests/test_image_baselines.rs | 20 +- sg2d/Cargo.toml | 11 + sg2d/src/error.rs | 7 + sg2d/src/lib.rs | 4 + sg2d/src/marks/group.rs | 16 ++ sg2d/src/marks/mark.rs | 15 ++ sg2d/src/marks/mod.rs | 6 + sg2d/src/marks/rect.rs | 54 ++++ sg2d/src/marks/rule.rs | 62 +++++ sg2d/src/marks/symbol.rs | 66 +++++ sg2d/src/marks/text.rs | 162 ++++++++++++ sg2d/src/scene_graph.rs | 9 + .../src/scene => sg2d/src}/value.rs | 16 +- sg2d/tests/test_scene_graph.rs | 7 + vega-wgpu-renderer/src/scene/group.rs | 73 ------ vega-wgpu-renderer/src/scene/rect.rs | 119 --------- vega-wgpu-renderer/src/scene/rule.rs | 137 ---------- vega-wgpu-renderer/src/scene/scene_graph.rs | 41 --- vega-wgpu-renderer/src/scene/symbol.rs | 115 --------- vega-wgpu-renderer/src/scene/text.rs | 242 ------------------ vega-wgpu-renderer/src/specs/group.rs | 15 -- vega-wgpu-renderer/src/specs/mark.rs | 39 --- vega-wgpu-renderer/src/specs/mod.rs | 12 - vega-wgpu-renderer/src/specs/rect.rs | 17 -- vega-wgpu-renderer/src/specs/rule.rs | 17 -- vega-wgpu-renderer/src/specs/symbol.rs | 32 --- vega-wgpu-renderer/src/specs/text.rs | 77 ------ 124 files changed, 1286 insertions(+), 1161 deletions(-) rename {gen-test-data => sg2d-vega-test-data}/Cargo.toml (100%) rename {gen-test-data => sg2d-vega-test-data}/README.md (73%) rename {gen-test-data => sg2d-vega-test-data}/src/main.rs (94%) rename {vega-wgpu-renderer/tests/specs => sg2d-vega-test-data/vega-scenegraphs}/rect/heatmap.dims.json (100%) rename {vega-wgpu-renderer/tests/specs => sg2d-vega-test-data/vega-scenegraphs}/rect/heatmap.png (100%) rename {vega-wgpu-renderer/tests/specs => sg2d-vega-test-data/vega-scenegraphs}/rect/heatmap.sg.json (100%) rename {vega-wgpu-renderer/tests/specs => sg2d-vega-test-data/vega-scenegraphs}/rect/stacked_bar.dims.json (100%) rename {vega-wgpu-renderer/tests/specs => sg2d-vega-test-data/vega-scenegraphs}/rect/stacked_bar.png (100%) rename {vega-wgpu-renderer/tests/specs => sg2d-vega-test-data/vega-scenegraphs}/rect/stacked_bar.sg.json (100%) rename {vega-wgpu-renderer/tests/specs => sg2d-vega-test-data/vega-scenegraphs}/rule/wide_rule_axes.dims.json (100%) rename {vega-wgpu-renderer/tests/specs => sg2d-vega-test-data/vega-scenegraphs}/rule/wide_rule_axes.png (100%) rename {vega-wgpu-renderer/tests/specs => sg2d-vega-test-data/vega-scenegraphs}/rule/wide_rule_axes.sg.json (100%) rename {vega-wgpu-renderer/tests/specs => sg2d-vega-test-data/vega-scenegraphs}/symbol/binned_scatter_arrow.dims.json (100%) rename {vega-wgpu-renderer/tests/specs => sg2d-vega-test-data/vega-scenegraphs}/symbol/binned_scatter_arrow.png (100%) rename {vega-wgpu-renderer/tests/specs => sg2d-vega-test-data/vega-scenegraphs}/symbol/binned_scatter_arrow.sg.json (100%) rename {vega-wgpu-renderer/tests/specs => sg2d-vega-test-data/vega-scenegraphs}/symbol/binned_scatter_circle.dims.json (100%) rename {vega-wgpu-renderer/tests/specs => sg2d-vega-test-data/vega-scenegraphs}/symbol/binned_scatter_circle.png (100%) rename {vega-wgpu-renderer/tests/specs => sg2d-vega-test-data/vega-scenegraphs}/symbol/binned_scatter_circle.sg.json (100%) rename {vega-wgpu-renderer/tests/specs => sg2d-vega-test-data/vega-scenegraphs}/symbol/binned_scatter_cross.dims.json (100%) rename {vega-wgpu-renderer/tests/specs => sg2d-vega-test-data/vega-scenegraphs}/symbol/binned_scatter_cross.png (100%) rename {vega-wgpu-renderer/tests/specs => sg2d-vega-test-data/vega-scenegraphs}/symbol/binned_scatter_cross.sg.json (100%) rename {vega-wgpu-renderer/tests/specs => sg2d-vega-test-data/vega-scenegraphs}/symbol/binned_scatter_diamonds.dims.json (100%) rename {vega-wgpu-renderer/tests/specs => sg2d-vega-test-data/vega-scenegraphs}/symbol/binned_scatter_diamonds.png (100%) rename {vega-wgpu-renderer/tests/specs => sg2d-vega-test-data/vega-scenegraphs}/symbol/binned_scatter_diamonds.sg.json (100%) rename {vega-wgpu-renderer/tests/specs => sg2d-vega-test-data/vega-scenegraphs}/symbol/binned_scatter_square.dims.json (100%) rename {vega-wgpu-renderer/tests/specs => sg2d-vega-test-data/vega-scenegraphs}/symbol/binned_scatter_square.png (100%) rename {vega-wgpu-renderer/tests/specs => sg2d-vega-test-data/vega-scenegraphs}/symbol/binned_scatter_square.sg.json (100%) rename {vega-wgpu-renderer/tests/specs => sg2d-vega-test-data/vega-scenegraphs}/symbol/binned_scatter_triangle-down.dims.json (100%) rename {vega-wgpu-renderer/tests/specs => sg2d-vega-test-data/vega-scenegraphs}/symbol/binned_scatter_triangle-down.png (100%) rename {vega-wgpu-renderer/tests/specs => sg2d-vega-test-data/vega-scenegraphs}/symbol/binned_scatter_triangle-down.sg.json (100%) rename {vega-wgpu-renderer/tests/specs => sg2d-vega-test-data/vega-scenegraphs}/symbol/binned_scatter_triangle-left.dims.json (100%) rename {vega-wgpu-renderer/tests/specs => sg2d-vega-test-data/vega-scenegraphs}/symbol/binned_scatter_triangle-left.png (100%) rename {vega-wgpu-renderer/tests/specs => sg2d-vega-test-data/vega-scenegraphs}/symbol/binned_scatter_triangle-left.sg.json (100%) rename {vega-wgpu-renderer/tests/specs => sg2d-vega-test-data/vega-scenegraphs}/symbol/binned_scatter_triangle-right.dims.json (100%) rename {vega-wgpu-renderer/tests/specs => sg2d-vega-test-data/vega-scenegraphs}/symbol/binned_scatter_triangle-right.png (100%) rename {vega-wgpu-renderer/tests/specs => sg2d-vega-test-data/vega-scenegraphs}/symbol/binned_scatter_triangle-right.sg.json (100%) rename {vega-wgpu-renderer/tests/specs => sg2d-vega-test-data/vega-scenegraphs}/symbol/binned_scatter_triangle-up.dims.json (100%) rename {vega-wgpu-renderer/tests/specs => sg2d-vega-test-data/vega-scenegraphs}/symbol/binned_scatter_triangle-up.png (100%) rename {vega-wgpu-renderer/tests/specs => sg2d-vega-test-data/vega-scenegraphs}/symbol/binned_scatter_triangle-up.sg.json (100%) rename {vega-wgpu-renderer/tests/specs => sg2d-vega-test-data/vega-scenegraphs}/symbol/binned_scatter_triangle.dims.json (100%) rename {vega-wgpu-renderer/tests/specs => sg2d-vega-test-data/vega-scenegraphs}/symbol/binned_scatter_triangle.png (100%) rename {vega-wgpu-renderer/tests/specs => sg2d-vega-test-data/vega-scenegraphs}/symbol/binned_scatter_triangle.sg.json (100%) rename {vega-wgpu-renderer/tests/specs => sg2d-vega-test-data/vega-scenegraphs}/symbol/binned_scatter_wedge.dims.json (100%) rename {vega-wgpu-renderer/tests/specs => sg2d-vega-test-data/vega-scenegraphs}/symbol/binned_scatter_wedge.png (100%) rename {vega-wgpu-renderer/tests/specs => sg2d-vega-test-data/vega-scenegraphs}/symbol/binned_scatter_wedge.sg.json (100%) rename {vega-wgpu-renderer/tests/specs => sg2d-vega-test-data/vega-scenegraphs}/text/bar_axis_labels.dims.json (100%) rename {vega-wgpu-renderer/tests/specs => sg2d-vega-test-data/vega-scenegraphs}/text/bar_axis_labels.png (100%) rename {vega-wgpu-renderer/tests/specs => sg2d-vega-test-data/vega-scenegraphs}/text/bar_axis_labels.sg.json (100%) rename {gen-test-data => sg2d-vega-test-data}/vega-specs/rect/heatmap.vg.json (100%) rename {gen-test-data => sg2d-vega-test-data}/vega-specs/rect/stacked_bar.vg.json (100%) rename {gen-test-data => sg2d-vega-test-data}/vega-specs/rule/wide_rule_axes.vg.json (100%) rename {gen-test-data => sg2d-vega-test-data}/vega-specs/symbol/binned_scatter_arrow.vg.json (100%) rename {gen-test-data => sg2d-vega-test-data}/vega-specs/symbol/binned_scatter_circle.vg.json (100%) rename {gen-test-data => sg2d-vega-test-data}/vega-specs/symbol/binned_scatter_cross.vg.json (100%) rename {gen-test-data => sg2d-vega-test-data}/vega-specs/symbol/binned_scatter_diamonds.vg.json (100%) rename {gen-test-data => sg2d-vega-test-data}/vega-specs/symbol/binned_scatter_square.vg.json (100%) rename {gen-test-data => sg2d-vega-test-data}/vega-specs/symbol/binned_scatter_triangle-down.vg.json (100%) rename {gen-test-data => sg2d-vega-test-data}/vega-specs/symbol/binned_scatter_triangle-left.vg.json (100%) rename {gen-test-data => sg2d-vega-test-data}/vega-specs/symbol/binned_scatter_triangle-right.vg.json (100%) rename {gen-test-data => sg2d-vega-test-data}/vega-specs/symbol/binned_scatter_triangle-up.vg.json (100%) rename {gen-test-data => sg2d-vega-test-data}/vega-specs/symbol/binned_scatter_triangle.vg.json (100%) rename {gen-test-data => sg2d-vega-test-data}/vega-specs/symbol/binned_scatter_wedge.vg.json (100%) rename {gen-test-data => sg2d-vega-test-data}/vega-specs/text/bar_axis_labels.vg.json (100%) create mode 100644 sg2d-vega/Cargo.toml rename {vega-wgpu-renderer/src/specs => sg2d-vega/src}/dims.rs (90%) create mode 100644 sg2d-vega/src/error.rs create mode 100644 sg2d-vega/src/lib.rs create mode 100644 sg2d-vega/src/marks/group.rs create mode 100644 sg2d-vega/src/marks/mark.rs rename {vega-wgpu-renderer/src/renderers => sg2d-vega/src/marks}/mod.rs (58%) create mode 100644 sg2d-vega/src/marks/rect.rs create mode 100644 sg2d-vega/src/marks/rule.rs create mode 100644 sg2d-vega/src/marks/symbol.rs create mode 100644 sg2d-vega/src/marks/text.rs create mode 100644 sg2d-vega/src/scene_graph.rs create mode 100644 sg2d-vega/tests/test_parsing.rs rename {vega-wgpu-renderer => sg2d-wgpu}/Cargo.toml (77%) rename {vega-wgpu-renderer => sg2d-wgpu}/index.html (90%) rename {vega-wgpu-renderer/src/renderers => sg2d-wgpu/src}/canvas.rs (96%) rename {vega-wgpu-renderer => sg2d-wgpu}/src/error.rs (72%) rename {vega-wgpu-renderer => sg2d-wgpu}/src/lib.rs (83%) rename {vega-wgpu-renderer => sg2d-wgpu}/src/main.rs (61%) rename {vega-wgpu-renderer/src/renderers => sg2d-wgpu/src/marks}/circle.wgsl (100%) rename {vega-wgpu-renderer/src/renderers => sg2d-wgpu/src/marks}/mark.rs (98%) rename {vega-wgpu-renderer/src/scene => sg2d-wgpu/src/marks}/mod.rs (53%) rename {vega-wgpu-renderer/src/renderers => sg2d-wgpu/src/marks}/polygon_symbol.wgsl (100%) rename {vega-wgpu-renderer/src/renderers => sg2d-wgpu/src/marks}/rect.rs (89%) rename {vega-wgpu-renderer/src/renderers => sg2d-wgpu/src/marks}/rect.wgsl (100%) rename {vega-wgpu-renderer/src/renderers => sg2d-wgpu/src/marks}/rule.rs (90%) rename {vega-wgpu-renderer/src/renderers => sg2d-wgpu/src/marks}/rule.wgsl (100%) rename {vega-wgpu-renderer/src/renderers => sg2d-wgpu/src/marks}/symbol.rs (97%) rename {vega-wgpu-renderer/src/renderers => sg2d-wgpu/src/marks}/text.rs (86%) rename {vega-wgpu-renderer/src/renderers => sg2d-wgpu/src}/vertex.rs (100%) rename {vega-wgpu-renderer => sg2d-wgpu}/tests/test_image_baselines.rs (82%) create mode 100644 sg2d/Cargo.toml create mode 100644 sg2d/src/error.rs create mode 100644 sg2d/src/lib.rs create mode 100644 sg2d/src/marks/group.rs create mode 100644 sg2d/src/marks/mark.rs create mode 100644 sg2d/src/marks/mod.rs create mode 100644 sg2d/src/marks/rect.rs create mode 100644 sg2d/src/marks/rule.rs create mode 100644 sg2d/src/marks/symbol.rs create mode 100644 sg2d/src/marks/text.rs create mode 100644 sg2d/src/scene_graph.rs rename {vega-wgpu-renderer/src/scene => sg2d/src}/value.rs (66%) create mode 100644 sg2d/tests/test_scene_graph.rs delete mode 100644 vega-wgpu-renderer/src/scene/group.rs delete mode 100644 vega-wgpu-renderer/src/scene/rect.rs delete mode 100644 vega-wgpu-renderer/src/scene/rule.rs delete mode 100644 vega-wgpu-renderer/src/scene/scene_graph.rs delete mode 100644 vega-wgpu-renderer/src/scene/symbol.rs delete mode 100644 vega-wgpu-renderer/src/scene/text.rs delete mode 100644 vega-wgpu-renderer/src/specs/group.rs delete mode 100644 vega-wgpu-renderer/src/specs/mark.rs delete mode 100644 vega-wgpu-renderer/src/specs/mod.rs delete mode 100644 vega-wgpu-renderer/src/specs/rect.rs delete mode 100644 vega-wgpu-renderer/src/specs/rule.rs delete mode 100644 vega-wgpu-renderer/src/specs/symbol.rs delete mode 100644 vega-wgpu-renderer/src/specs/text.rs diff --git a/.gitignore b/.gitignore index 310fdc0..f47511c 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,4 @@ /target /.idea -/vega-wgpu-renderer/tests/output/ +/sg2d-wgpu/tests/output/ .DS_Store \ No newline at end of file diff --git a/Cargo.lock b/Cargo.lock index 2329c28..8aebea7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -261,7 +261,7 @@ dependencies = [ "proc-macro2", "quote", "swc_macros_common", - "syn 2.0.42", + "syn 2.0.47", ] [[package]] @@ -286,7 +286,7 @@ checksum = "fdf6721fb0140e4f897002dd086c06f6c27775df19cfe1fccb21181a48fd2c98" dependencies = [ "proc-macro2", "quote", - "syn 2.0.42", + "syn 2.0.47", ] [[package]] @@ -485,7 +485,7 @@ checksum = "965ab7eb5f8f97d2a083c799f3a1b994fc397b2fe2da5d1da1626ce15a39f2b1" dependencies = [ "proc-macro2", "quote", - "syn 2.0.42", + "syn 2.0.47", ] [[package]] @@ -851,7 +851,7 @@ checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.42", + "syn 2.0.47", ] [[package]] @@ -1361,7 +1361,7 @@ dependencies = [ "quote", "strum", "strum_macros", - "syn 2.0.42", + "syn 2.0.47", "thiserror", ] @@ -1682,7 +1682,7 @@ checksum = "487585f4d0c6655fe74905e2504d8ad6908e4db67f744eb140876906c2f3175d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.42", + "syn 2.0.47", ] [[package]] @@ -1714,7 +1714,7 @@ checksum = "f2b99bf03862d7f545ebc28ddd33a665b50865f4dfd84031a393823879bd4c54" dependencies = [ "proc-macro2", "quote", - "syn 2.0.42", + "syn 2.0.47", ] [[package]] @@ -2167,7 +2167,7 @@ checksum = "1a5c6c585bc94aaf2c7b51dd4c2ba22680844aba4c687be581871a6f518c5742" dependencies = [ "proc-macro2", "quote", - "syn 2.0.42", + "syn 2.0.47", ] [[package]] @@ -2200,7 +2200,7 @@ dependencies = [ "pmutil", "proc-macro2", "swc_macros_common", - "syn 2.0.42", + "syn 2.0.47", ] [[package]] @@ -2300,7 +2300,7 @@ checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" dependencies = [ "proc-macro2", "quote", - "syn 2.0.42", + "syn 2.0.47", ] [[package]] @@ -2964,7 +2964,7 @@ dependencies = [ "Inflector", "proc-macro2", "quote", - "syn 2.0.42", + "syn 2.0.47", ] [[package]] @@ -3115,7 +3115,7 @@ dependencies = [ "proc-macro2", "quote", "regex", - "syn 2.0.42", + "syn 2.0.47", ] [[package]] @@ -3776,7 +3776,7 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.42", + "syn 2.0.47", ] [[package]] @@ -4083,7 +4083,7 @@ dependencies = [ "phf_shared", "proc-macro2", "quote", - "syn 2.0.42", + "syn 2.0.47", ] [[package]] @@ -4118,7 +4118,7 @@ checksum = "4359fd9c9171ec6e8c62926d6faaf553a8dc3f64e1507e76da7911b4f6a04405" dependencies = [ "proc-macro2", "quote", - "syn 2.0.42", + "syn 2.0.47", ] [[package]] @@ -4174,7 +4174,7 @@ checksum = "52a40bc70c2c58040d2d8b167ba9a5ff59fc9dab7ad44771cfde3dcfde7a09c6" dependencies = [ "proc-macro2", "quote", - "syn 2.0.42", + "syn 2.0.47", ] [[package]] @@ -4287,7 +4287,7 @@ checksum = "07c277e4e643ef00c1233393c673f655e3672cf7eb3ba08a00bdd0ea59139b5f" dependencies = [ "proc-macro-rules-macros", "proc-macro2", - "syn 2.0.42", + "syn 2.0.47", ] [[package]] @@ -4299,14 +4299,14 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn 2.0.42", + "syn 2.0.47", ] [[package]] name = "proc-macro2" -version = "1.0.71" +version = "1.0.75" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75cb1540fadbd5b8fbccc4dddad2734eba435053f725621c070711a14bb5f4b8" +checksum = "907a61bd0f64c2f29cd1cf1dc34d05176426a3f504a78010f08416ddb7b13708" dependencies = [ "unicode-ident", ] @@ -4403,9 +4403,9 @@ checksum = "a993555f31e5a609f617c12db6250dedcac1b0a85076912c436e6fc9b2c8e6a3" [[package]] name = "quote" -version = "1.0.33" +version = "1.0.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae" +checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef" dependencies = [ "proc-macro2", ] @@ -4734,7 +4734,7 @@ dependencies = [ "regex", "relative-path", "rustc_version 0.4.0", - "syn 2.0.42", + "syn 2.0.47", "unicode-ident", ] @@ -5059,9 +5059,9 @@ checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" [[package]] name = "serde" -version = "1.0.193" +version = "1.0.194" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25dd9975e68d0cb5aa1120c288333fc98731bd1dd12f561e468ea4728c042b89" +checksum = "0b114498256798c94a0689e1a15fec6005dee8ac1f41de56404b67afc2a4b773" dependencies = [ "serde_derive", ] @@ -5087,20 +5087,20 @@ dependencies = [ [[package]] name = "serde_derive" -version = "1.0.193" +version = "1.0.194" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43576ca501357b9b071ac53cdc7da8ef0cbd9493d8df094cd821777ea6e894d3" +checksum = "a3385e45322e8f9931410f01b3031ec534c3947d0e94c18049af4d9f9907d4e0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.42", + "syn 2.0.47", ] [[package]] name = "serde_json" -version = "1.0.108" +version = "1.0.111" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d1c7e3eac408d115102c4c24ad393e0821bb3a5df4d506a80f85f7a742a526b" +checksum = "176e46fa42316f18edd598015a5166857fc835ec732f5215eac6b7bdbf0a84f4" dependencies = [ "indexmap 2.1.0", "itoa", @@ -5135,6 +5135,54 @@ dependencies = [ "v8", ] +[[package]] +name = "sg2d" +version = "0.1.0" +dependencies = [ + "serde", + "thiserror", +] + +[[package]] +name = "sg2d-vega" +version = "0.1.0" +dependencies = [ + "csscolorparser", + "serde", + "serde_json", + "sg2d", + "thiserror", +] + +[[package]] +name = "sg2d-wgpu" +version = "0.1.0" +dependencies = [ + "bytemuck", + "cfg-if", + "cgmath", + "console_error_panic_hook", + "console_log", + "dssim", + "env_logger", + "futures-intrusive", + "glyphon", + "image", + "itertools 0.12.0", + "log", + "pollster", + "rstest", + "serde_json", + "sg2d", + "sg2d-vega", + "thiserror", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", + "wgpu", + "winit", +] + [[package]] name = "sha-1" version = "0.10.0" @@ -5389,7 +5437,7 @@ dependencies = [ "proc-macro2", "quote", "swc_macros_common", - "syn 2.0.42", + "syn 2.0.47", ] [[package]] @@ -5411,7 +5459,7 @@ dependencies = [ "proc-macro2", "quote", "rustversion", - "syn 2.0.42", + "syn 2.0.47", ] [[package]] @@ -5555,7 +5603,7 @@ dependencies = [ "proc-macro2", "quote", "swc_macros_common", - "syn 2.0.42", + "syn 2.0.47", ] [[package]] @@ -5605,7 +5653,7 @@ dependencies = [ "proc-macro2", "quote", "swc_macros_common", - "syn 2.0.42", + "syn 2.0.47", ] [[package]] @@ -5690,7 +5738,7 @@ dependencies = [ "proc-macro2", "quote", "swc_macros_common", - "syn 2.0.42", + "syn 2.0.47", ] [[package]] @@ -5819,7 +5867,7 @@ dependencies = [ "pmutil", "proc-macro2", "quote", - "syn 2.0.42", + "syn 2.0.47", ] [[package]] @@ -5856,7 +5904,7 @@ dependencies = [ "pmutil", "proc-macro2", "quote", - "syn 2.0.42", + "syn 2.0.47", ] [[package]] @@ -5880,7 +5928,7 @@ dependencies = [ "proc-macro2", "quote", "swc_macros_common", - "syn 2.0.42", + "syn 2.0.47", ] [[package]] @@ -5896,9 +5944,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.42" +version = "2.0.47" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b7d0a2c048d661a1a59fcd7355baa232f7ed34e0ee4df2eef3c1c1c0d3852d8" +checksum = "1726efe18f42ae774cc644f330953a5e7b3c3003d3edcecf18850fe9d4dd9afb" dependencies = [ "proc-macro2", "quote", @@ -5995,7 +6043,7 @@ checksum = "e7fbe9b594d6568a6a1443250a7e67d80b74e1e96f6d1715e1e21cc1888291d3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.42", + "syn 2.0.47", ] [[package]] @@ -6131,7 +6179,7 @@ checksum = "5b8a1e28f2deaa14e508979454cb3a223b10b938b45af148bc0986de36f1923b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.42", + "syn 2.0.47", ] [[package]] @@ -6244,7 +6292,7 @@ checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.42", + "syn 2.0.47", ] [[package]] @@ -6603,34 +6651,6 @@ version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191" -[[package]] -name = "vega-wgpu-renderer" -version = "0.1.0" -dependencies = [ - "bytemuck", - "cfg-if", - "cgmath", - "console_error_panic_hook", - "console_log", - "csscolorparser", - "dssim", - "env_logger", - "futures-intrusive", - "glyphon", - "image", - "log", - "pollster", - "rstest", - "serde", - "serde_json", - "thiserror", - "wasm-bindgen", - "wasm-bindgen-futures", - "web-sys", - "wgpu", - "winit", -] - [[package]] name = "version_check" version = "0.9.4" @@ -6760,7 +6780,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn 2.0.42", + "syn 2.0.47", "wasm-bindgen-shared", ] @@ -6794,7 +6814,7 @@ checksum = "54681b18a46765f095758388f2d0cf16eb8d4169b639ab575a8f5693af210c7b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.42", + "syn 2.0.47", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -7447,7 +7467,7 @@ checksum = "9ce1b18ccd8e73a9321186f97e46f9f04b778851177567b1975109d26a08d2a6" dependencies = [ "proc-macro2", "quote", - "syn 2.0.42", + "syn 2.0.47", ] [[package]] @@ -7467,7 +7487,7 @@ checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" dependencies = [ "proc-macro2", "quote", - "syn 2.0.42", + "syn 2.0.47", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index 592bb35..ba21a49 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,10 +1,13 @@ [workspace] members = [ - "vega-wgpu-renderer", - "gen-test-data", + "sg2d", + "sg2d-vega", + "sg2d-wgpu", + "sg2d-vega-test-data", ] resolver = "2" [workspace.dependencies] -serde = { version = "1.0", features = ["derive"] } -serde_json = "1.0" +serde = { version = "^1.0", features = ["derive"] } +serde_json = "^1.0" +thiserror = "^1.0" diff --git a/README.md b/README.md index 47e6caa..a22a4c2 100644 --- a/README.md +++ b/README.md @@ -1,19 +1,24 @@ -# vega-wgpu-renderer +# Vega wgpu renderer This repo holds an early stage prototype of what it could look like to build an alternative [Vega](https://vega.github.io/vega/) visualization renderer in Rust using [wgpu](https://github.com/gfx-rs/wgpu). This is not useful yet (and may never be). +We're exploring how general the various components are, and so the names and structures of +crates are still changing. If you're interested in collaborating on a visualization renderer for +a non-Vega application, please open an issue. + # Try it out ## Run native To launch a wgpu rendered visualization in a native window, run the following: ``` +cd sg2d-wgpu cargo run ``` ## Build wasm To build the example above to WASM + WebGL2, run the following: ``` -cd vega-wgpu-renderer +cd sg2d-wgpu wasm-pack build --target web ``` diff --git a/gen-test-data/Cargo.toml b/sg2d-vega-test-data/Cargo.toml similarity index 100% rename from gen-test-data/Cargo.toml rename to sg2d-vega-test-data/Cargo.toml diff --git a/gen-test-data/README.md b/sg2d-vega-test-data/README.md similarity index 73% rename from gen-test-data/README.md rename to sg2d-vega-test-data/README.md index e8cdcf5..b4ae657 100644 --- a/gen-test-data/README.md +++ b/sg2d-vega-test-data/README.md @@ -1,18 +1,18 @@ ## Generate Test Data -This is a binary crate responsible for generating image baseline test data for the vega-wgpu-renderer. +This is a binary crate responsible for generating image baseline vega test data for the sg2d-wgpu renderer. From the project root ``` -cargo run -p gen-test-data +cargo run -p sg2d-vega-test-data ``` ## How it works -A collection of Vega specs are located under `gen-test-data/vega-specs` inside category directories. -For example: `gen-test-data/vega-specs/rect/stacked_bar.vg.json`. +A collection of Vega specs are located under `sg2d-vega-test-data/vega-specs` inside category directories. +For example: `sg2d-vega-test-data/vega-specs/rect/stacked_bar.vg.json`. The main binary entry point scans this directory and for each Vega spec it uses [`vl-convert-rs`](https://github.com/vega/vl-convert) to -output the following three files in matching category directory under `vega-wgpu-renderer/tests/specs` +output the following three files in matching category directory under `sg2d-vega-test-data/vega-scenegraphs` 1. `{spec_name}.sg.json`: This is the JSON representation of the scenegraph that Vega generates for this Vega spec. This is used as the input for the wgpu renderer. 2. `{spec_name}.dims.json`: This JSON file contains the final chart width, height, and origin values. @@ -21,5 +21,5 @@ output the following three files in matching category directory under `vega-wgpu chart to SVG and then renders the SVG to PNG using [resvg](https://github.com/RazrFalcon/resvg). This PNG image serves as the baseline that wgpu rendered PNGs are compared to. -Image baselines are tested in `vega-wgpu-renderer/tests/test_image_baselines.rs`. Image similarity is measured +Image baselines are tested in `sg2d-wgpu/tests/test_image_baselines.rs`. Image similarity is measured using [DSSIM](https://github.com/kornelski/dssim). diff --git a/gen-test-data/src/main.rs b/sg2d-vega-test-data/src/main.rs similarity index 94% rename from gen-test-data/src/main.rs rename to sg2d-vega-test-data/src/main.rs index dd15697..79ca98c 100644 --- a/gen-test-data/src/main.rs +++ b/sg2d-vega-test-data/src/main.rs @@ -5,8 +5,8 @@ use std::path::Path; use std::{fs, io}; use vl_convert_rs::VlConverter; -/// Generate test data for each Vega spec located in `gen-test-data/vega-specs` -/// For each spec, the following three files are saved to `vega-wgpu-renderer/tests/specs` +/// Generate test data for each Vega spec located in `sg2d-vega-test-data/vega-specs` +/// For each spec, the following three files are saved to `sg2d-vega-test-data/vega-scenegraphs` /// 1. spec_name.dims.json: This is a JSON file containing the chart's width, height, and origin /// 2. spec_name.sg.json: This is a JSON file containing the chart's scene graph /// 3. spec_name.png: This is a PNG rendering of the chart using vl-convert with resvg @@ -33,7 +33,7 @@ fn main() { env!("CARGO_MANIFEST_DIR") ); let output_dir = format!( - "{}/../vega-wgpu-renderer/tests/specs/{spec_category}/", + "{}/vega-scenegraphs/{spec_category}/", env!("CARGO_MANIFEST_DIR") ); fs::create_dir_all(Path::new(&output_dir)).unwrap(); diff --git a/vega-wgpu-renderer/tests/specs/rect/heatmap.dims.json b/sg2d-vega-test-data/vega-scenegraphs/rect/heatmap.dims.json similarity index 100% rename from vega-wgpu-renderer/tests/specs/rect/heatmap.dims.json rename to sg2d-vega-test-data/vega-scenegraphs/rect/heatmap.dims.json diff --git a/vega-wgpu-renderer/tests/specs/rect/heatmap.png b/sg2d-vega-test-data/vega-scenegraphs/rect/heatmap.png similarity index 100% rename from vega-wgpu-renderer/tests/specs/rect/heatmap.png rename to sg2d-vega-test-data/vega-scenegraphs/rect/heatmap.png diff --git a/vega-wgpu-renderer/tests/specs/rect/heatmap.sg.json b/sg2d-vega-test-data/vega-scenegraphs/rect/heatmap.sg.json similarity index 100% rename from vega-wgpu-renderer/tests/specs/rect/heatmap.sg.json rename to sg2d-vega-test-data/vega-scenegraphs/rect/heatmap.sg.json diff --git a/vega-wgpu-renderer/tests/specs/rect/stacked_bar.dims.json b/sg2d-vega-test-data/vega-scenegraphs/rect/stacked_bar.dims.json similarity index 100% rename from vega-wgpu-renderer/tests/specs/rect/stacked_bar.dims.json rename to sg2d-vega-test-data/vega-scenegraphs/rect/stacked_bar.dims.json diff --git a/vega-wgpu-renderer/tests/specs/rect/stacked_bar.png b/sg2d-vega-test-data/vega-scenegraphs/rect/stacked_bar.png similarity index 100% rename from vega-wgpu-renderer/tests/specs/rect/stacked_bar.png rename to sg2d-vega-test-data/vega-scenegraphs/rect/stacked_bar.png diff --git a/vega-wgpu-renderer/tests/specs/rect/stacked_bar.sg.json b/sg2d-vega-test-data/vega-scenegraphs/rect/stacked_bar.sg.json similarity index 100% rename from vega-wgpu-renderer/tests/specs/rect/stacked_bar.sg.json rename to sg2d-vega-test-data/vega-scenegraphs/rect/stacked_bar.sg.json diff --git a/vega-wgpu-renderer/tests/specs/rule/wide_rule_axes.dims.json b/sg2d-vega-test-data/vega-scenegraphs/rule/wide_rule_axes.dims.json similarity index 100% rename from vega-wgpu-renderer/tests/specs/rule/wide_rule_axes.dims.json rename to sg2d-vega-test-data/vega-scenegraphs/rule/wide_rule_axes.dims.json diff --git a/vega-wgpu-renderer/tests/specs/rule/wide_rule_axes.png b/sg2d-vega-test-data/vega-scenegraphs/rule/wide_rule_axes.png similarity index 100% rename from vega-wgpu-renderer/tests/specs/rule/wide_rule_axes.png rename to sg2d-vega-test-data/vega-scenegraphs/rule/wide_rule_axes.png diff --git a/vega-wgpu-renderer/tests/specs/rule/wide_rule_axes.sg.json b/sg2d-vega-test-data/vega-scenegraphs/rule/wide_rule_axes.sg.json similarity index 100% rename from vega-wgpu-renderer/tests/specs/rule/wide_rule_axes.sg.json rename to sg2d-vega-test-data/vega-scenegraphs/rule/wide_rule_axes.sg.json diff --git a/vega-wgpu-renderer/tests/specs/symbol/binned_scatter_arrow.dims.json b/sg2d-vega-test-data/vega-scenegraphs/symbol/binned_scatter_arrow.dims.json similarity index 100% rename from vega-wgpu-renderer/tests/specs/symbol/binned_scatter_arrow.dims.json rename to sg2d-vega-test-data/vega-scenegraphs/symbol/binned_scatter_arrow.dims.json diff --git a/vega-wgpu-renderer/tests/specs/symbol/binned_scatter_arrow.png b/sg2d-vega-test-data/vega-scenegraphs/symbol/binned_scatter_arrow.png similarity index 100% rename from vega-wgpu-renderer/tests/specs/symbol/binned_scatter_arrow.png rename to sg2d-vega-test-data/vega-scenegraphs/symbol/binned_scatter_arrow.png diff --git a/vega-wgpu-renderer/tests/specs/symbol/binned_scatter_arrow.sg.json b/sg2d-vega-test-data/vega-scenegraphs/symbol/binned_scatter_arrow.sg.json similarity index 100% rename from vega-wgpu-renderer/tests/specs/symbol/binned_scatter_arrow.sg.json rename to sg2d-vega-test-data/vega-scenegraphs/symbol/binned_scatter_arrow.sg.json diff --git a/vega-wgpu-renderer/tests/specs/symbol/binned_scatter_circle.dims.json b/sg2d-vega-test-data/vega-scenegraphs/symbol/binned_scatter_circle.dims.json similarity index 100% rename from vega-wgpu-renderer/tests/specs/symbol/binned_scatter_circle.dims.json rename to sg2d-vega-test-data/vega-scenegraphs/symbol/binned_scatter_circle.dims.json diff --git a/vega-wgpu-renderer/tests/specs/symbol/binned_scatter_circle.png b/sg2d-vega-test-data/vega-scenegraphs/symbol/binned_scatter_circle.png similarity index 100% rename from vega-wgpu-renderer/tests/specs/symbol/binned_scatter_circle.png rename to sg2d-vega-test-data/vega-scenegraphs/symbol/binned_scatter_circle.png diff --git a/vega-wgpu-renderer/tests/specs/symbol/binned_scatter_circle.sg.json b/sg2d-vega-test-data/vega-scenegraphs/symbol/binned_scatter_circle.sg.json similarity index 100% rename from vega-wgpu-renderer/tests/specs/symbol/binned_scatter_circle.sg.json rename to sg2d-vega-test-data/vega-scenegraphs/symbol/binned_scatter_circle.sg.json diff --git a/vega-wgpu-renderer/tests/specs/symbol/binned_scatter_cross.dims.json b/sg2d-vega-test-data/vega-scenegraphs/symbol/binned_scatter_cross.dims.json similarity index 100% rename from vega-wgpu-renderer/tests/specs/symbol/binned_scatter_cross.dims.json rename to sg2d-vega-test-data/vega-scenegraphs/symbol/binned_scatter_cross.dims.json diff --git a/vega-wgpu-renderer/tests/specs/symbol/binned_scatter_cross.png b/sg2d-vega-test-data/vega-scenegraphs/symbol/binned_scatter_cross.png similarity index 100% rename from vega-wgpu-renderer/tests/specs/symbol/binned_scatter_cross.png rename to sg2d-vega-test-data/vega-scenegraphs/symbol/binned_scatter_cross.png diff --git a/vega-wgpu-renderer/tests/specs/symbol/binned_scatter_cross.sg.json b/sg2d-vega-test-data/vega-scenegraphs/symbol/binned_scatter_cross.sg.json similarity index 100% rename from vega-wgpu-renderer/tests/specs/symbol/binned_scatter_cross.sg.json rename to sg2d-vega-test-data/vega-scenegraphs/symbol/binned_scatter_cross.sg.json diff --git a/vega-wgpu-renderer/tests/specs/symbol/binned_scatter_diamonds.dims.json b/sg2d-vega-test-data/vega-scenegraphs/symbol/binned_scatter_diamonds.dims.json similarity index 100% rename from vega-wgpu-renderer/tests/specs/symbol/binned_scatter_diamonds.dims.json rename to sg2d-vega-test-data/vega-scenegraphs/symbol/binned_scatter_diamonds.dims.json diff --git a/vega-wgpu-renderer/tests/specs/symbol/binned_scatter_diamonds.png b/sg2d-vega-test-data/vega-scenegraphs/symbol/binned_scatter_diamonds.png similarity index 100% rename from vega-wgpu-renderer/tests/specs/symbol/binned_scatter_diamonds.png rename to sg2d-vega-test-data/vega-scenegraphs/symbol/binned_scatter_diamonds.png diff --git a/vega-wgpu-renderer/tests/specs/symbol/binned_scatter_diamonds.sg.json b/sg2d-vega-test-data/vega-scenegraphs/symbol/binned_scatter_diamonds.sg.json similarity index 100% rename from vega-wgpu-renderer/tests/specs/symbol/binned_scatter_diamonds.sg.json rename to sg2d-vega-test-data/vega-scenegraphs/symbol/binned_scatter_diamonds.sg.json diff --git a/vega-wgpu-renderer/tests/specs/symbol/binned_scatter_square.dims.json b/sg2d-vega-test-data/vega-scenegraphs/symbol/binned_scatter_square.dims.json similarity index 100% rename from vega-wgpu-renderer/tests/specs/symbol/binned_scatter_square.dims.json rename to sg2d-vega-test-data/vega-scenegraphs/symbol/binned_scatter_square.dims.json diff --git a/vega-wgpu-renderer/tests/specs/symbol/binned_scatter_square.png b/sg2d-vega-test-data/vega-scenegraphs/symbol/binned_scatter_square.png similarity index 100% rename from vega-wgpu-renderer/tests/specs/symbol/binned_scatter_square.png rename to sg2d-vega-test-data/vega-scenegraphs/symbol/binned_scatter_square.png diff --git a/vega-wgpu-renderer/tests/specs/symbol/binned_scatter_square.sg.json b/sg2d-vega-test-data/vega-scenegraphs/symbol/binned_scatter_square.sg.json similarity index 100% rename from vega-wgpu-renderer/tests/specs/symbol/binned_scatter_square.sg.json rename to sg2d-vega-test-data/vega-scenegraphs/symbol/binned_scatter_square.sg.json diff --git a/vega-wgpu-renderer/tests/specs/symbol/binned_scatter_triangle-down.dims.json b/sg2d-vega-test-data/vega-scenegraphs/symbol/binned_scatter_triangle-down.dims.json similarity index 100% rename from vega-wgpu-renderer/tests/specs/symbol/binned_scatter_triangle-down.dims.json rename to sg2d-vega-test-data/vega-scenegraphs/symbol/binned_scatter_triangle-down.dims.json diff --git a/vega-wgpu-renderer/tests/specs/symbol/binned_scatter_triangle-down.png b/sg2d-vega-test-data/vega-scenegraphs/symbol/binned_scatter_triangle-down.png similarity index 100% rename from vega-wgpu-renderer/tests/specs/symbol/binned_scatter_triangle-down.png rename to sg2d-vega-test-data/vega-scenegraphs/symbol/binned_scatter_triangle-down.png diff --git a/vega-wgpu-renderer/tests/specs/symbol/binned_scatter_triangle-down.sg.json b/sg2d-vega-test-data/vega-scenegraphs/symbol/binned_scatter_triangle-down.sg.json similarity index 100% rename from vega-wgpu-renderer/tests/specs/symbol/binned_scatter_triangle-down.sg.json rename to sg2d-vega-test-data/vega-scenegraphs/symbol/binned_scatter_triangle-down.sg.json diff --git a/vega-wgpu-renderer/tests/specs/symbol/binned_scatter_triangle-left.dims.json b/sg2d-vega-test-data/vega-scenegraphs/symbol/binned_scatter_triangle-left.dims.json similarity index 100% rename from vega-wgpu-renderer/tests/specs/symbol/binned_scatter_triangle-left.dims.json rename to sg2d-vega-test-data/vega-scenegraphs/symbol/binned_scatter_triangle-left.dims.json diff --git a/vega-wgpu-renderer/tests/specs/symbol/binned_scatter_triangle-left.png b/sg2d-vega-test-data/vega-scenegraphs/symbol/binned_scatter_triangle-left.png similarity index 100% rename from vega-wgpu-renderer/tests/specs/symbol/binned_scatter_triangle-left.png rename to sg2d-vega-test-data/vega-scenegraphs/symbol/binned_scatter_triangle-left.png diff --git a/vega-wgpu-renderer/tests/specs/symbol/binned_scatter_triangle-left.sg.json b/sg2d-vega-test-data/vega-scenegraphs/symbol/binned_scatter_triangle-left.sg.json similarity index 100% rename from vega-wgpu-renderer/tests/specs/symbol/binned_scatter_triangle-left.sg.json rename to sg2d-vega-test-data/vega-scenegraphs/symbol/binned_scatter_triangle-left.sg.json diff --git a/vega-wgpu-renderer/tests/specs/symbol/binned_scatter_triangle-right.dims.json b/sg2d-vega-test-data/vega-scenegraphs/symbol/binned_scatter_triangle-right.dims.json similarity index 100% rename from vega-wgpu-renderer/tests/specs/symbol/binned_scatter_triangle-right.dims.json rename to sg2d-vega-test-data/vega-scenegraphs/symbol/binned_scatter_triangle-right.dims.json diff --git a/vega-wgpu-renderer/tests/specs/symbol/binned_scatter_triangle-right.png b/sg2d-vega-test-data/vega-scenegraphs/symbol/binned_scatter_triangle-right.png similarity index 100% rename from vega-wgpu-renderer/tests/specs/symbol/binned_scatter_triangle-right.png rename to sg2d-vega-test-data/vega-scenegraphs/symbol/binned_scatter_triangle-right.png diff --git a/vega-wgpu-renderer/tests/specs/symbol/binned_scatter_triangle-right.sg.json b/sg2d-vega-test-data/vega-scenegraphs/symbol/binned_scatter_triangle-right.sg.json similarity index 100% rename from vega-wgpu-renderer/tests/specs/symbol/binned_scatter_triangle-right.sg.json rename to sg2d-vega-test-data/vega-scenegraphs/symbol/binned_scatter_triangle-right.sg.json diff --git a/vega-wgpu-renderer/tests/specs/symbol/binned_scatter_triangle-up.dims.json b/sg2d-vega-test-data/vega-scenegraphs/symbol/binned_scatter_triangle-up.dims.json similarity index 100% rename from vega-wgpu-renderer/tests/specs/symbol/binned_scatter_triangle-up.dims.json rename to sg2d-vega-test-data/vega-scenegraphs/symbol/binned_scatter_triangle-up.dims.json diff --git a/vega-wgpu-renderer/tests/specs/symbol/binned_scatter_triangle-up.png b/sg2d-vega-test-data/vega-scenegraphs/symbol/binned_scatter_triangle-up.png similarity index 100% rename from vega-wgpu-renderer/tests/specs/symbol/binned_scatter_triangle-up.png rename to sg2d-vega-test-data/vega-scenegraphs/symbol/binned_scatter_triangle-up.png diff --git a/vega-wgpu-renderer/tests/specs/symbol/binned_scatter_triangle-up.sg.json b/sg2d-vega-test-data/vega-scenegraphs/symbol/binned_scatter_triangle-up.sg.json similarity index 100% rename from vega-wgpu-renderer/tests/specs/symbol/binned_scatter_triangle-up.sg.json rename to sg2d-vega-test-data/vega-scenegraphs/symbol/binned_scatter_triangle-up.sg.json diff --git a/vega-wgpu-renderer/tests/specs/symbol/binned_scatter_triangle.dims.json b/sg2d-vega-test-data/vega-scenegraphs/symbol/binned_scatter_triangle.dims.json similarity index 100% rename from vega-wgpu-renderer/tests/specs/symbol/binned_scatter_triangle.dims.json rename to sg2d-vega-test-data/vega-scenegraphs/symbol/binned_scatter_triangle.dims.json diff --git a/vega-wgpu-renderer/tests/specs/symbol/binned_scatter_triangle.png b/sg2d-vega-test-data/vega-scenegraphs/symbol/binned_scatter_triangle.png similarity index 100% rename from vega-wgpu-renderer/tests/specs/symbol/binned_scatter_triangle.png rename to sg2d-vega-test-data/vega-scenegraphs/symbol/binned_scatter_triangle.png diff --git a/vega-wgpu-renderer/tests/specs/symbol/binned_scatter_triangle.sg.json b/sg2d-vega-test-data/vega-scenegraphs/symbol/binned_scatter_triangle.sg.json similarity index 100% rename from vega-wgpu-renderer/tests/specs/symbol/binned_scatter_triangle.sg.json rename to sg2d-vega-test-data/vega-scenegraphs/symbol/binned_scatter_triangle.sg.json diff --git a/vega-wgpu-renderer/tests/specs/symbol/binned_scatter_wedge.dims.json b/sg2d-vega-test-data/vega-scenegraphs/symbol/binned_scatter_wedge.dims.json similarity index 100% rename from vega-wgpu-renderer/tests/specs/symbol/binned_scatter_wedge.dims.json rename to sg2d-vega-test-data/vega-scenegraphs/symbol/binned_scatter_wedge.dims.json diff --git a/vega-wgpu-renderer/tests/specs/symbol/binned_scatter_wedge.png b/sg2d-vega-test-data/vega-scenegraphs/symbol/binned_scatter_wedge.png similarity index 100% rename from vega-wgpu-renderer/tests/specs/symbol/binned_scatter_wedge.png rename to sg2d-vega-test-data/vega-scenegraphs/symbol/binned_scatter_wedge.png diff --git a/vega-wgpu-renderer/tests/specs/symbol/binned_scatter_wedge.sg.json b/sg2d-vega-test-data/vega-scenegraphs/symbol/binned_scatter_wedge.sg.json similarity index 100% rename from vega-wgpu-renderer/tests/specs/symbol/binned_scatter_wedge.sg.json rename to sg2d-vega-test-data/vega-scenegraphs/symbol/binned_scatter_wedge.sg.json diff --git a/vega-wgpu-renderer/tests/specs/text/bar_axis_labels.dims.json b/sg2d-vega-test-data/vega-scenegraphs/text/bar_axis_labels.dims.json similarity index 100% rename from vega-wgpu-renderer/tests/specs/text/bar_axis_labels.dims.json rename to sg2d-vega-test-data/vega-scenegraphs/text/bar_axis_labels.dims.json diff --git a/vega-wgpu-renderer/tests/specs/text/bar_axis_labels.png b/sg2d-vega-test-data/vega-scenegraphs/text/bar_axis_labels.png similarity index 100% rename from vega-wgpu-renderer/tests/specs/text/bar_axis_labels.png rename to sg2d-vega-test-data/vega-scenegraphs/text/bar_axis_labels.png diff --git a/vega-wgpu-renderer/tests/specs/text/bar_axis_labels.sg.json b/sg2d-vega-test-data/vega-scenegraphs/text/bar_axis_labels.sg.json similarity index 100% rename from vega-wgpu-renderer/tests/specs/text/bar_axis_labels.sg.json rename to sg2d-vega-test-data/vega-scenegraphs/text/bar_axis_labels.sg.json diff --git a/gen-test-data/vega-specs/rect/heatmap.vg.json b/sg2d-vega-test-data/vega-specs/rect/heatmap.vg.json similarity index 100% rename from gen-test-data/vega-specs/rect/heatmap.vg.json rename to sg2d-vega-test-data/vega-specs/rect/heatmap.vg.json diff --git a/gen-test-data/vega-specs/rect/stacked_bar.vg.json b/sg2d-vega-test-data/vega-specs/rect/stacked_bar.vg.json similarity index 100% rename from gen-test-data/vega-specs/rect/stacked_bar.vg.json rename to sg2d-vega-test-data/vega-specs/rect/stacked_bar.vg.json diff --git a/gen-test-data/vega-specs/rule/wide_rule_axes.vg.json b/sg2d-vega-test-data/vega-specs/rule/wide_rule_axes.vg.json similarity index 100% rename from gen-test-data/vega-specs/rule/wide_rule_axes.vg.json rename to sg2d-vega-test-data/vega-specs/rule/wide_rule_axes.vg.json diff --git a/gen-test-data/vega-specs/symbol/binned_scatter_arrow.vg.json b/sg2d-vega-test-data/vega-specs/symbol/binned_scatter_arrow.vg.json similarity index 100% rename from gen-test-data/vega-specs/symbol/binned_scatter_arrow.vg.json rename to sg2d-vega-test-data/vega-specs/symbol/binned_scatter_arrow.vg.json diff --git a/gen-test-data/vega-specs/symbol/binned_scatter_circle.vg.json b/sg2d-vega-test-data/vega-specs/symbol/binned_scatter_circle.vg.json similarity index 100% rename from gen-test-data/vega-specs/symbol/binned_scatter_circle.vg.json rename to sg2d-vega-test-data/vega-specs/symbol/binned_scatter_circle.vg.json diff --git a/gen-test-data/vega-specs/symbol/binned_scatter_cross.vg.json b/sg2d-vega-test-data/vega-specs/symbol/binned_scatter_cross.vg.json similarity index 100% rename from gen-test-data/vega-specs/symbol/binned_scatter_cross.vg.json rename to sg2d-vega-test-data/vega-specs/symbol/binned_scatter_cross.vg.json diff --git a/gen-test-data/vega-specs/symbol/binned_scatter_diamonds.vg.json b/sg2d-vega-test-data/vega-specs/symbol/binned_scatter_diamonds.vg.json similarity index 100% rename from gen-test-data/vega-specs/symbol/binned_scatter_diamonds.vg.json rename to sg2d-vega-test-data/vega-specs/symbol/binned_scatter_diamonds.vg.json diff --git a/gen-test-data/vega-specs/symbol/binned_scatter_square.vg.json b/sg2d-vega-test-data/vega-specs/symbol/binned_scatter_square.vg.json similarity index 100% rename from gen-test-data/vega-specs/symbol/binned_scatter_square.vg.json rename to sg2d-vega-test-data/vega-specs/symbol/binned_scatter_square.vg.json diff --git a/gen-test-data/vega-specs/symbol/binned_scatter_triangle-down.vg.json b/sg2d-vega-test-data/vega-specs/symbol/binned_scatter_triangle-down.vg.json similarity index 100% rename from gen-test-data/vega-specs/symbol/binned_scatter_triangle-down.vg.json rename to sg2d-vega-test-data/vega-specs/symbol/binned_scatter_triangle-down.vg.json diff --git a/gen-test-data/vega-specs/symbol/binned_scatter_triangle-left.vg.json b/sg2d-vega-test-data/vega-specs/symbol/binned_scatter_triangle-left.vg.json similarity index 100% rename from gen-test-data/vega-specs/symbol/binned_scatter_triangle-left.vg.json rename to sg2d-vega-test-data/vega-specs/symbol/binned_scatter_triangle-left.vg.json diff --git a/gen-test-data/vega-specs/symbol/binned_scatter_triangle-right.vg.json b/sg2d-vega-test-data/vega-specs/symbol/binned_scatter_triangle-right.vg.json similarity index 100% rename from gen-test-data/vega-specs/symbol/binned_scatter_triangle-right.vg.json rename to sg2d-vega-test-data/vega-specs/symbol/binned_scatter_triangle-right.vg.json diff --git a/gen-test-data/vega-specs/symbol/binned_scatter_triangle-up.vg.json b/sg2d-vega-test-data/vega-specs/symbol/binned_scatter_triangle-up.vg.json similarity index 100% rename from gen-test-data/vega-specs/symbol/binned_scatter_triangle-up.vg.json rename to sg2d-vega-test-data/vega-specs/symbol/binned_scatter_triangle-up.vg.json diff --git a/gen-test-data/vega-specs/symbol/binned_scatter_triangle.vg.json b/sg2d-vega-test-data/vega-specs/symbol/binned_scatter_triangle.vg.json similarity index 100% rename from gen-test-data/vega-specs/symbol/binned_scatter_triangle.vg.json rename to sg2d-vega-test-data/vega-specs/symbol/binned_scatter_triangle.vg.json diff --git a/gen-test-data/vega-specs/symbol/binned_scatter_wedge.vg.json b/sg2d-vega-test-data/vega-specs/symbol/binned_scatter_wedge.vg.json similarity index 100% rename from gen-test-data/vega-specs/symbol/binned_scatter_wedge.vg.json rename to sg2d-vega-test-data/vega-specs/symbol/binned_scatter_wedge.vg.json diff --git a/gen-test-data/vega-specs/text/bar_axis_labels.vg.json b/sg2d-vega-test-data/vega-specs/text/bar_axis_labels.vg.json similarity index 100% rename from gen-test-data/vega-specs/text/bar_axis_labels.vg.json rename to sg2d-vega-test-data/vega-specs/text/bar_axis_labels.vg.json diff --git a/sg2d-vega/Cargo.toml b/sg2d-vega/Cargo.toml new file mode 100644 index 0000000..2a57e95 --- /dev/null +++ b/sg2d-vega/Cargo.toml @@ -0,0 +1,13 @@ +[package] +name = "sg2d-vega" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +sg2d = { path = "../sg2d" } +thiserror = { workspace = true } +serde = { workspace = true } +csscolorparser = "0.6.2" +serde_json = { version = "1.0.111" } \ No newline at end of file diff --git a/vega-wgpu-renderer/src/specs/dims.rs b/sg2d-vega/src/dims.rs similarity index 90% rename from vega-wgpu-renderer/src/specs/dims.rs rename to sg2d-vega/src/dims.rs index c182699..b9f4c97 100644 --- a/vega-wgpu-renderer/src/specs/dims.rs +++ b/sg2d-vega/src/dims.rs @@ -3,7 +3,7 @@ use serde::{Deserialize, Serialize}; /// This struct is not part of the scene graph definition. This is the format /// written by the gen-test-data crate #[derive(Debug, Clone, Serialize, Deserialize)] -pub struct SceneGraphDims { +pub struct VegaSceneGraphDims { pub width: f32, pub height: f32, pub origin_x: f32, diff --git a/sg2d-vega/src/error.rs b/sg2d-vega/src/error.rs new file mode 100644 index 0000000..51e6434 --- /dev/null +++ b/sg2d-vega/src/error.rs @@ -0,0 +1,10 @@ +use thiserror::Error; + +#[derive(Error, Debug)] +pub enum VegaSceneGraphError { + #[error("SceneGraph error")] + SceneGraphError(#[from] sg2d::error::SceneGraphError), + + #[error("css color parse error")] + InvalidColor(#[from] csscolorparser::ParseColorError), +} diff --git a/sg2d-vega/src/lib.rs b/sg2d-vega/src/lib.rs new file mode 100644 index 0000000..4085dbe --- /dev/null +++ b/sg2d-vega/src/lib.rs @@ -0,0 +1,4 @@ +pub mod dims; +pub mod error; +pub mod marks; +pub mod scene_graph; diff --git a/sg2d-vega/src/marks/group.rs b/sg2d-vega/src/marks/group.rs new file mode 100644 index 0000000..e3584c6 --- /dev/null +++ b/sg2d-vega/src/marks/group.rs @@ -0,0 +1,60 @@ +use crate::error::VegaSceneGraphError; +use crate::marks::mark::{VegaMark, VegaMarkItem}; +use serde::{Deserialize, Serialize}; +use sg2d::marks::group::{GroupBounds, SceneGroup}; +use sg2d::marks::mark::SceneMark; + +#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct VegaGroupItem { + pub items: Vec, + #[serde(default)] + pub(crate) x: f32, + #[serde(default)] + pub(crate) y: f32, + pub width: Option, + pub height: Option, +} + +impl VegaMarkItem for VegaGroupItem {} + +impl VegaGroupItem { + pub fn to_scene_graph(&self, origin: [f32; 2]) -> Result { + let new_origin = [self.x + origin[0], self.y + origin[1]]; + let mut marks: Vec = Vec::new(); + for item in &self.items { + let item_marks: Vec<_> = match item { + VegaMark::Group(group) => group + .items + .iter() + .map(|item| Ok(SceneMark::Group(item.to_scene_graph(new_origin)?))) + .collect::, VegaSceneGraphError>>()?, + VegaMark::Rect(mark) => { + vec![mark.to_scene_graph(new_origin)?] + } + VegaMark::Rule(mark) => { + vec![mark.to_scene_graph(new_origin)?] + } + VegaMark::Symbol(mark) => { + vec![mark.to_scene_graph(new_origin)?] + } + VegaMark::Text(mark) => { + vec![mark.to_scene_graph(new_origin)?] + } + _ => { + println!("Mark type not yet supported: {:?}", item); + continue; + } + }; + marks.extend(item_marks); + } + Ok(SceneGroup { + bounds: GroupBounds { + x: self.x, + y: self.y, + width: self.width, + height: self.height, + }, + marks, + }) + } +} diff --git a/sg2d-vega/src/marks/mark.rs b/sg2d-vega/src/marks/mark.rs new file mode 100644 index 0000000..4996fd0 --- /dev/null +++ b/sg2d-vega/src/marks/mark.rs @@ -0,0 +1,38 @@ +use crate::marks::group::VegaGroupItem; +use crate::marks::rect::VegaRectItem; +use crate::marks::rule::VegaRuleItem; +use crate::marks::symbol::VegaSymbolItem; +use crate::marks::text::VegaTextItem; +use serde::{Deserialize, Serialize}; + +pub trait VegaMarkItem {} + +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +#[serde(tag = "marktype")] +pub enum VegaMark { + Arc, + Area, + Image, + Group(VegaMarkContainer), + Line, + Path, + Rect(VegaMarkContainer), + Rule(VegaMarkContainer), + Shape, + Symbol(VegaMarkContainer), + Text(VegaMarkContainer), + Trail, +} + +#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct VegaMarkContainer { + #[serde(default)] + pub clip: bool, + pub interactive: bool, + #[serde(default)] + pub items: Vec, + pub name: Option, + role: Option, + zindex: Option, +} diff --git a/vega-wgpu-renderer/src/renderers/mod.rs b/sg2d-vega/src/marks/mod.rs similarity index 58% rename from vega-wgpu-renderer/src/renderers/mod.rs rename to sg2d-vega/src/marks/mod.rs index 649cdfe..f7213d9 100644 --- a/vega-wgpu-renderer/src/renderers/mod.rs +++ b/sg2d-vega/src/marks/mod.rs @@ -1,7 +1,6 @@ -pub mod canvas; +pub mod group; pub mod mark; pub mod rect; pub mod rule; pub mod symbol; -mod text; -pub mod vertex; +pub mod text; diff --git a/sg2d-vega/src/marks/rect.rs b/sg2d-vega/src/marks/rect.rs new file mode 100644 index 0000000..be9940a --- /dev/null +++ b/sg2d-vega/src/marks/rect.rs @@ -0,0 +1,79 @@ +use crate::error::VegaSceneGraphError; +use crate::marks::mark::{VegaMarkContainer, VegaMarkItem}; +use serde::{Deserialize, Serialize}; +use sg2d::marks::mark::SceneMark; +use sg2d::marks::rect::RectMark; +use sg2d::value::EncodingValue; + +#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct VegaRectItem { + pub x: f32, + pub y: f32, + pub width: Option, + pub height: Option, + pub x2: Option, + pub y2: Option, + pub fill: Option, + pub fill_opacity: Option, +} + +impl VegaMarkItem for VegaRectItem {} + +impl VegaMarkContainer { + pub fn to_scene_graph(&self, origin: [f32; 2]) -> Result { + let mut mark = RectMark { + clip: self.clip, + ..Default::default() + }; + + if let Some(name) = &self.name { + mark.name = name.clone(); + } + + // Init vector for each encoding channel + let mut x = Vec::::new(); + let mut y = Vec::::new(); + let mut width = Vec::::new(); + let mut height = Vec::::new(); + let mut fill = Vec::<[f32; 3]>::new(); + + // For each item, append explicit values to corresponding vector + for item in &self.items { + x.push(item.x + origin[0]); + y.push(item.y + origin[1]); + if let Some(v) = item.width { + width.push(v); + } + if let Some(v) = item.height { + height.push(v); + } + if let Some(v) = &item.fill { + let c = csscolorparser::parse(v)?; + fill.push([c.r as f32, c.g as f32, c.b as f32]) + } + } + + // Override values with vectors + let len = self.items.len(); + mark.len = len as u32; + + if x.len() == len { + mark.x = EncodingValue::Array { values: x }; + } + if y.len() == len { + mark.y = EncodingValue::Array { values: y }; + } + if width.len() == len { + mark.width = EncodingValue::Array { values: width }; + } + if height.len() == len { + mark.height = EncodingValue::Array { values: height }; + } + if fill.len() == len { + mark.fill = EncodingValue::Array { values: fill }; + } + + Ok(SceneMark::Rect(mark)) + } +} diff --git a/sg2d-vega/src/marks/rule.rs b/sg2d-vega/src/marks/rule.rs new file mode 100644 index 0000000..fa21362 --- /dev/null +++ b/sg2d-vega/src/marks/rule.rs @@ -0,0 +1,93 @@ +use crate::error::VegaSceneGraphError; +use crate::marks::mark::{VegaMarkContainer, VegaMarkItem}; +use serde::{Deserialize, Serialize}; +use sg2d::marks::mark::SceneMark; +use sg2d::marks::rule::RuleMark; +use sg2d::value::{EncodingValue, StrokeCap}; + +#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct VegaRuleItem { + pub x: f32, + pub y: f32, + pub x2: Option, + pub y2: Option, + pub stroke: Option, + pub stroke_width: Option, + pub stroke_cap: Option, +} + +impl VegaMarkItem for VegaRuleItem {} + +impl VegaMarkContainer { + pub fn to_scene_graph(&self, origin: [f32; 2]) -> Result { + // Init mark with scalar defaults + let mut mark = RuleMark { + clip: self.clip, + ..Default::default() + }; + if let Some(name) = &self.name { + mark.name = name.clone(); + } + + // Init vector for each encoding channel + let mut x0 = Vec::::new(); + let mut y0 = Vec::::new(); + let mut x1 = Vec::::new(); + let mut y1 = Vec::::new(); + let mut stroke = Vec::<[f32; 3]>::new(); + let mut stroke_width = Vec::::new(); + let mut stroke_cap = Vec::::new(); + + // For each item, append explicit values to corresponding vector + for item in &self.items { + x0.push(item.x + origin[0]); + y0.push(item.y + origin[1]); + x1.push(item.x2.unwrap_or(item.x) + origin[0]); + y1.push(item.y2.unwrap_or(item.y) + origin[1]); + + if let Some(s) = &item.stroke { + let c = csscolorparser::parse(s)?; + stroke.push([c.r as f32, c.g as f32, c.b as f32]) + } + + if let Some(s) = item.stroke_width { + stroke_width.push(s); + } + + if let Some(s) = item.stroke_cap { + stroke_cap.push(s); + } + } + + // Override values with vectors + let len = self.items.len(); + mark.len = len as u32; + + if x0.len() == len { + mark.x0 = EncodingValue::Array { values: x0 }; + } + if y0.len() == len { + mark.y0 = EncodingValue::Array { values: y0 }; + } + if x1.len() == len { + mark.x1 = EncodingValue::Array { values: x1 }; + } + if y1.len() == len { + mark.y1 = EncodingValue::Array { values: y1 }; + } + if stroke.len() == len { + mark.stroke = EncodingValue::Array { values: stroke }; + } + if stroke_width.len() == len { + mark.stroke_width = EncodingValue::Array { + values: stroke_width, + }; + } + if stroke_cap.len() == len { + mark.stroke_cap = EncodingValue::Array { values: stroke_cap }; + } + + Ok(SceneMark::Rule(mark)) + } +} diff --git a/sg2d-vega/src/marks/symbol.rs b/sg2d-vega/src/marks/symbol.rs new file mode 100644 index 0000000..30854d8 --- /dev/null +++ b/sg2d-vega/src/marks/symbol.rs @@ -0,0 +1,81 @@ +use crate::error::VegaSceneGraphError; +use crate::marks::mark::{VegaMarkContainer, VegaMarkItem}; +use serde::{Deserialize, Serialize}; +use sg2d::marks::mark::SceneMark; +use sg2d::marks::symbol::{SymbolMark, SymbolShape}; +use sg2d::value::EncodingValue; + +#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct VegaSymbolItem { + pub x: f32, + pub y: f32, + pub fill: Option, + pub fill_opacity: Option, + pub size: Option, + pub shape: Option, +} + +impl VegaMarkItem for VegaSymbolItem {} + +impl VegaMarkContainer { + pub fn to_scene_graph(&self, origin: [f32; 2]) -> Result { + // Get shape of first item and use that for all items for now + let first_shape = self + .items + .get(0) + .and_then(|item| item.shape) + .unwrap_or_default(); + + // Init mark with scalar defaults + let mut mark = SymbolMark { + shape: first_shape, + clip: self.clip, + ..Default::default() + }; + + if let Some(name) = &self.name { + mark.name = name.clone(); + } + + // Init vector for each encoding channel + let mut x = Vec::::new(); + let mut y = Vec::::new(); + let mut fill = Vec::<[f32; 3]>::new(); + let mut size = Vec::::new(); + + // For each item, append explicit values to corresponding vector + for item in &self.items { + x.push(item.x + origin[0]); + y.push(item.y + origin[1]); + + if let Some(c) = &item.fill { + let c = csscolorparser::parse(c)?; + fill.push([c.r as f32, c.g as f32, c.b as f32]) + } + + if let Some(s) = item.size { + size.push(s); + } + } + + // Override values with vectors + let len = self.items.len(); + mark.len = len as u32; + + if x.len() == len { + mark.x = EncodingValue::Array { values: x }; + } + if y.len() == len { + mark.y = EncodingValue::Array { values: y }; + } + if fill.len() == len { + mark.fill = EncodingValue::Array { values: fill }; + } + if size.len() == len { + mark.size = EncodingValue::Array { values: size }; + } + + Ok(SceneMark::Symbol(mark)) + } +} diff --git a/sg2d-vega/src/marks/text.rs b/sg2d-vega/src/marks/text.rs new file mode 100644 index 0000000..ccb3005 --- /dev/null +++ b/sg2d-vega/src/marks/text.rs @@ -0,0 +1,169 @@ +use crate::error::VegaSceneGraphError; +use crate::marks::mark::{VegaMarkContainer, VegaMarkItem}; +use serde::{Deserialize, Serialize}; +use sg2d::marks::mark::SceneMark; +use sg2d::marks::text::{FontStyleSpec, FontWeightSpec, TextAlignSpec, TextBaselineSpec, TextMark}; +use sg2d::value::EncodingValue; + +#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct VegaTextItem { + // Required + pub x: f32, + pub y: f32, + pub text: String, + + // Optional + pub align: Option, + pub angle: Option, + pub baseline: Option, + pub dx: Option, + pub dy: Option, + pub fill: Option, + pub fill_opacity: Option, + pub font: Option, + pub font_size: Option, + pub font_weight: Option, + pub font_style: Option, + pub limit: Option, +} + +impl VegaMarkItem for VegaTextItem {} + +impl VegaMarkContainer { + pub fn to_scene_graph(&self, origin: [f32; 2]) -> Result { + // Init mark with scalar defaults + let mut mark = TextMark { + clip: self.clip, + ..Default::default() + }; + if let Some(name) = &self.name { + mark.name = name.clone(); + } + + // Init vector for each encoding channel + let mut text = Vec::::new(); + let mut x = Vec::::new(); + let mut y = Vec::::new(); + let mut align = Vec::::new(); + let mut baseline = Vec::::new(); + let mut opacity = Vec::::new(); + let mut angle = Vec::::new(); + let mut color = Vec::<[f32; 3]>::new(); + let mut dx = Vec::::new(); + let mut dy = Vec::::new(); + let mut font = Vec::::new(); + let mut font_size = Vec::::new(); + let mut font_weight = Vec::::new(); + let mut font_style = Vec::::new(); + let mut limit = Vec::::new(); + + for item in &self.items { + x.push(item.x + origin[0]); + y.push(item.y + origin[1]); + text.push(item.text.clone()); + + if let Some(v) = item.align { + align.push(v); + } + + if let Some(v) = item.baseline { + baseline.push(v); + } + + if let Some(v) = item.fill_opacity { + opacity.push(v); + } + + if let Some(v) = item.angle { + angle.push(v); + } + + if let Some(v) = &item.fill { + let c = csscolorparser::parse(v)?; + color.push([c.r as f32, c.g as f32, c.b as f32]) + } + + if let Some(v) = item.dx { + dx.push(v); + } + + if let Some(v) = item.dy { + dy.push(v); + } + + if let Some(v) = &item.font { + font.push(v.clone()); + } + + if let Some(v) = item.font_size { + font_size.push(v); + } + + if let Some(v) = item.font_weight { + font_weight.push(v); + } + + if let Some(v) = item.font_style { + font_style.push(v); + } + + if let Some(v) = item.limit { + limit.push(v); + } + } + + // Override values with vectors + let len = self.items.len(); + mark.len = len as u32; + + if x.len() == len { + mark.x = EncodingValue::Array { values: x }; + } + if y.len() == len { + mark.y = EncodingValue::Array { values: y }; + } + if text.len() == len { + mark.text = EncodingValue::Array { values: text }; + } + if align.len() == len { + mark.align = EncodingValue::Array { values: align }; + } + if baseline.len() == len { + mark.baseline = EncodingValue::Array { values: baseline }; + } + if opacity.len() == len { + mark.opacity = EncodingValue::Array { values: opacity }; + } + if angle.len() == len { + mark.angle = EncodingValue::Array { values: angle }; + } + if color.len() == len { + mark.color = EncodingValue::Array { values: color }; + } + if dx.len() == len { + mark.dx = EncodingValue::Array { values: dx }; + } + if dy.len() == len { + mark.dy = EncodingValue::Array { values: dy }; + } + if font.len() == len { + mark.font = EncodingValue::Array { values: font }; + } + if font_size.len() == len { + mark.font_size = EncodingValue::Array { values: font_size }; + } + if font_weight.len() == len { + mark.font_weight = EncodingValue::Array { + values: font_weight, + }; + } + if font_style.len() == len { + mark.font_style = EncodingValue::Array { values: font_style }; + } + if limit.len() == len { + mark.limit = EncodingValue::Array { values: limit }; + } + Ok(SceneMark::Text(mark)) + } +} diff --git a/sg2d-vega/src/scene_graph.rs b/sg2d-vega/src/scene_graph.rs new file mode 100644 index 0000000..a305726 --- /dev/null +++ b/sg2d-vega/src/scene_graph.rs @@ -0,0 +1,27 @@ +use crate::error::VegaSceneGraphError; +use crate::marks::group::VegaGroupItem; +use crate::marks::mark::VegaMarkContainer; +use sg2d::scene_graph::SceneGraph; + +pub type VegaSceneGraph = VegaMarkContainer; + +impl VegaSceneGraph { + pub fn to_scene_graph( + &self, + origin: [f32; 2], + width: f32, + height: f32, + ) -> Result { + let groups = self + .items + .iter() + .map(|group| group.to_scene_graph(origin)) + .collect::, VegaSceneGraphError>>()?; + + Ok(SceneGraph { + groups, + width, + height, + }) + } +} diff --git a/sg2d-vega/tests/test_parsing.rs b/sg2d-vega/tests/test_parsing.rs new file mode 100644 index 0000000..cec1866 --- /dev/null +++ b/sg2d-vega/tests/test_parsing.rs @@ -0,0 +1,27 @@ +#[cfg(test)] +mod tests { + use sg2d_vega::scene_graph::VegaSceneGraph; + use std::fs; + + #[test] + fn try_it() { + let category = "rule"; + let spec_name = "wide_rule_axes"; + let specs_dir = format!( + "{}/../vega-wgpu-renderer/tests/specs/{category}", + env!("CARGO_MANIFEST_DIR") + ); + + // Read scene graph spec + let scene_spec_str = + fs::read_to_string(format!("{specs_dir}/{spec_name}.sg.json")).unwrap(); + let scene_spec: VegaSceneGraph = serde_json::from_str(&scene_spec_str).unwrap(); + + println!("{:#?}", scene_spec); + + // Convert to scene graph + + let sg = scene_spec.to_scene_graph([0.0, 0.0], 200.0, 300.0).unwrap(); + println!("{sg:#?}"); + } +} diff --git a/vega-wgpu-renderer/Cargo.toml b/sg2d-wgpu/Cargo.toml similarity index 77% rename from vega-wgpu-renderer/Cargo.toml rename to sg2d-wgpu/Cargo.toml index 571b44a..150eef6 100644 --- a/vega-wgpu-renderer/Cargo.toml +++ b/sg2d-wgpu/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "vega-wgpu-renderer" +name = "sg2d-wgpu" version = "0.1.0" edition = "2021" @@ -7,6 +7,9 @@ edition = "2021" crate-type = ["cdylib", "rlib"] [dependencies] +sg2d = { path = "../sg2d" } + +thiserror = { workspace = true } cfg-if = "1" winit = "0.28" env_logger = "0.10" @@ -15,18 +18,14 @@ wgpu = "0.18" pollster = "0.3" bytemuck = { version = "1.14", features = [ "derive" ] } cgmath = "0.18.0" -serde = { version = "1.0", features = ["derive"] } -serde_json = "1.0" -thiserror = "1.0.52" -csscolorparser = "0.6.2" +itertools = "0.12.0" image = "0.24.7" futures-intrusive = "^0.5" glyphon = { git = "https://github.com/grovesNL/glyphon.git", rev="941309aed230d7110bfec0d4af502ecb4648cf90" } -itertools = "0.12.0" -[dev-dependencies] -dssim = "3.2.4" -rstest = "0.18.2" +# Only used for lib.rs example. Move this to example +sg2d-vega = { path = "../sg2d-vega" } +serde_json = { version = "1.0.111" } [target.'cfg(target_arch = "wasm32")'.dependencies] console_error_panic_hook = "0.1.6" @@ -39,3 +38,7 @@ web-sys = { version = "0.3.53", features = [ "Window", "Element", ]} + +[dev-dependencies] +dssim = "3.2.4" +rstest = "0.18.2" \ No newline at end of file diff --git a/vega-wgpu-renderer/index.html b/sg2d-wgpu/index.html similarity index 90% rename from vega-wgpu-renderer/index.html rename to sg2d-wgpu/index.html index 0f35d34..f3f36ea 100644 --- a/vega-wgpu-renderer/index.html +++ b/sg2d-wgpu/index.html @@ -15,7 +15,7 @@