use crate::geom::graph::{edge, node};
use crate::geom::{self, Vector3};
use crate::math::BaseFloat;
use crate::text;
use lyon::path::PathEvent;
use lyon::tessellation::FillTessellator;
use std::cell::{Ref, RefCell};
use std::collections::HashMap;
use std::{fmt, mem, ops};
pub use self::backend::wgpu::Renderer;
pub use self::background::Background;
pub use self::drawing::{Drawing, DrawingContext};
pub use self::mesh::intermediary::{
IntermediaryMesh, IntermediaryMeshBuilder, IntermediaryVertexData, IntermediaryVertexDataRanges,
};
pub use self::mesh::Mesh;
use self::primitive::Primitive;
use self::properties::spatial::orientation::{self, Orientation};
use self::properties::spatial::position::{self, Position};
use self::properties::IntoDrawn;
pub use self::theme::Theme;
pub mod backend;
pub mod background;
mod drawing;
pub mod mesh;
pub mod primitive;
pub mod properties;
pub mod theme;
#[derive(Clone, Debug)]
pub struct Draw<S = geom::scalar::Default>
where
S: BaseFloat,
{
state: RefCell<State<S>>,
}
#[derive(Clone, Debug)]
pub struct State<S = geom::scalar::Default>
where
S: BaseFloat,
{
geom_graph: geom::Graph<S>,
geom_graph_dfs: RefCell<geom::graph::node::Dfs<S>>,
intermediary_state: RefCell<IntermediaryState<S>>,
mesh: Mesh<S>,
ranges: HashMap<node::Index, Ranges>,
drawing: HashMap<node::Index, Primitive<S>>,
last_node_drawn: Option<node::Index>,
theme: Theme,
background_color: Option<properties::LinSrgba>,
}
#[derive(Clone, Debug)]
pub struct GlyphCache {
cache: GlyphCacheWrapper,
pixel_buffer: Vec<u8>,
has_updated: bool,
}
#[derive(Clone, Debug)]
pub struct IntermediaryState<S> {
intermediary_mesh: IntermediaryMesh<S>,
fill_tessellator: FillTessellatorWrapper,
path_event_buffer: Vec<PathEvent>,
text_buffer: String,
glyph_cache: GlyphCache,
}
#[derive(Default)]
pub(crate) struct FillTessellatorWrapper(pub(crate) FillTessellator);
pub(crate) struct GlyphCacheWrapper(pub(crate) text::GlyphCache<'static>);
#[derive(Clone, Debug)]
struct Ranges {
vertices: ops::Range<usize>,
indices: ops::Range<usize>,
}
const WOULD_CYCLE: &'static str =
"drawing the given primitive with the given relative positioning would have caused a cycle \
within the geometry graph";
pub type NodeVertices<'a, S = geom::scalar::Default> =
node::TransformedVertices<crate::mesh::Vertices<Ref<'a, Mesh<S>>>, S>;
pub type RawNodeVertices<'a, S = geom::scalar::Default> =
node::TransformedVertices<crate::mesh::RawVertices<Ref<'a, Mesh<S>>>, S>;
pub type NodeTriangles<'a, S = geom::scalar::Default> =
geom::tri::IterFromVertices<NodeVertices<'a, S>>;
#[derive(Debug)]
pub struct Vertices<'a, S = geom::scalar::Default>
where
S: 'a + BaseFloat,
{
draw: &'a Draw<S>,
node_vertices: Option<NodeVertices<'a, S>>,
}
pub type Triangles<'a, S = geom::scalar::Default> = geom::tri::IterFromVertices<Vertices<'a, S>>;
#[derive(Debug)]
pub struct RawVertices<'a, S = geom::scalar::Default>
where
S: 'a + BaseFloat,
{
draw: &'a Draw<S>,
node_vertices: Option<RawNodeVertices<'a, S>>,
}
impl GlyphCache {
pub const DEFAULT_W: u32 = 256;
pub const DEFAULT_H: u32 = 256;
pub const DEFAULT_DIMENSIONS: (u32, u32) = (Self::DEFAULT_W, Self::DEFAULT_H);
}
impl<S> IntermediaryVertexData<S> {
pub fn reset(&mut self) {
self.points.clear();
self.colors.clear();
self.tex_coords.clear();
}
}
impl<S> IntermediaryMesh<S> {
pub fn reset(&mut self) {
self.vertex_data.reset();
self.indices.clear();
}
}
impl<S> IntermediaryState<S> {
pub fn reset(&mut self) {
self.intermediary_mesh.reset();
self.path_event_buffer.clear();
self.text_buffer.clear();
}
}
impl<S> State<S>
where
S: BaseFloat,
{
fn reset(&mut self) {
self.geom_graph.clear();
self.geom_graph_dfs.borrow_mut().reset(&self.geom_graph);
self.drawing.clear();
self.ranges.clear();
self.intermediary_state.borrow_mut().reset();
self.mesh.clear();
self.background_color = None;
self.last_node_drawn = None;
}
fn finish_remaining_drawings(&mut self) -> Result<(), geom::graph::WouldCycle<S>> {
let mut drawing = mem::replace(&mut self.drawing, Default::default());
for (node_index, primitive) in drawing.drain() {
draw_primitive(self, node_index, primitive)?;
}
mem::replace(&mut self.drawing, drawing);
Ok(())
}
fn finish_drawing(&mut self, n: &node::Index) -> Result<(), geom::graph::WouldCycle<S>> {
if let Some(primitive) = self.drawing.remove(n) {
draw_primitive(self, *n, primitive)?;
}
Ok(())
}
fn untransformed_dimension_of<F>(&mut self, n: &node::Index, point_axis: &F) -> Option<S>
where
F: Fn(&mesh::vertex::Point<S>) -> S,
{
self.finish_drawing(n).expect(WOULD_CYCLE);
self.ranges.get(n).and_then(|ranges| {
let points = self.mesh.points()[ranges.vertices.clone()].iter().cloned();
min_max_dimension(points, point_axis).map(|(min, max)| max - min)
})
}
fn untransformed_x_dimension_of(&mut self, n: &node::Index) -> Option<S> {
self.untransformed_dimension_of(n, &point_x)
}
fn untransformed_y_dimension_of(&mut self, n: &node::Index) -> Option<S> {
self.untransformed_dimension_of(n, &point_y)
}
fn untransformed_z_dimension_of(&mut self, n: &node::Index) -> Option<S> {
self.untransformed_dimension_of(n, &point_z)
}
fn dimension_of<F>(&mut self, n: &node::Index, point_axis: &F) -> Option<S>
where
F: Fn(&mesh::vertex::Point<S>) -> S,
{
self.finish_drawing(n).expect(WOULD_CYCLE);
self.ranges.get(n).and_then(|ranges| {
let points = self.mesh.points()[ranges.vertices.clone()].iter().cloned();
let points = self
.geom_graph
.node_vertices(*n, points)
.expect("no node at index");
min_max_dimension(points, point_axis).map(|(min, max)| max - min)
})
}
fn x_dimension_of(&mut self, n: &node::Index) -> Option<S> {
self.dimension_of(n, &point_x)
}
fn y_dimension_of(&mut self, n: &node::Index) -> Option<S> {
self.dimension_of(n, &point_y)
}
fn z_dimension_of(&mut self, n: &node::Index) -> Option<S> {
self.dimension_of(n, &point_z)
}
}
impl<S> Draw<S>
where
S: BaseFloat,
{
pub fn new() -> Self {
Self::default()
}
pub fn reset(&self) {
self.state.borrow_mut().reset();
}
pub fn background(&self) -> Background<S> {
background::new(self)
}
pub fn a<T>(&self, primitive: T) -> Drawing<T, S>
where
T: Into<Primitive<S>>,
Primitive<S>: Into<Option<T>>,
{
let index = self
.state
.borrow_mut()
.geom_graph
.add_node(geom::graph::Node::Point);
let primitive: Primitive<S> = primitive.into();
self.state.borrow_mut().drawing.insert(index, primitive);
drawing::new(self, index)
}
pub fn path(&self) -> Drawing<primitive::PathInit<S>, S> {
self.a(Default::default())
}
pub fn ellipse(&self) -> Drawing<primitive::Ellipse<S>, S> {
self.a(Default::default())
}
pub fn line(&self) -> Drawing<primitive::Line<S>, S> {
self.a(Default::default())
}
pub fn quad(&self) -> Drawing<primitive::Quad<S>, S> {
self.a(Default::default())
}
pub fn rect(&self) -> Drawing<primitive::Rect<S>, S> {
self.a(Default::default())
}
pub fn tri(&self) -> Drawing<primitive::Tri<S>, S> {
self.a(Default::default())
}
pub fn polygon(&self) -> Drawing<primitive::PolygonInit<S>, S> {
self.a(Default::default())
}
pub fn mesh(&self) -> Drawing<primitive::mesh::Vertexless, S> {
self.a(Default::default())
}
pub fn polyline(&self) -> Drawing<primitive::PathStroke<S>, S> {
self.path().stroke()
}
pub fn text(&self, s: &str) -> Drawing<primitive::Text<S>, S> {
let text = {
let state = self.state.borrow();
let mut intermediary_state = state.intermediary_state.borrow_mut();
let ctxt = DrawingContext::from_intermediary_state(&mut *intermediary_state);
primitive::text::Text::new(ctxt, s)
};
self.a(text)
}
pub fn node_vertices(&self, n: node::Index) -> Option<NodeVertices<S>> {
self.state
.borrow_mut()
.finish_drawing(&n)
.expect(WOULD_CYCLE);
let index_range = match self.state.borrow().ranges.get(&n) {
None => return None,
Some(ranges) => ranges.indices.clone(),
};
let vertices = crate::mesh::vertices(self.inner_mesh()).index_range(index_range);
self.state.borrow().geom_graph.node_vertices(n, vertices)
}
pub fn node_triangles(&self, n: node::Index) -> Option<NodeTriangles<S>> {
self.node_vertices(n).map(geom::tri::iter_from_vertices)
}
pub fn raw_vertices(&self) -> RawVertices<S> {
self.finish_remaining_drawings().expect(WOULD_CYCLE);
let state = self.state.borrow();
state.geom_graph_dfs.borrow_mut().reset(&state.geom_graph);
let draw = self;
let node_vertices = None;
RawVertices {
draw,
node_vertices,
}
}
pub fn vertices(&self) -> Vertices<S> {
self.finish_remaining_drawings().expect(WOULD_CYCLE);
let state = self.state.borrow();
state.geom_graph_dfs.borrow_mut().reset(&state.geom_graph);
let draw = self;
let node_vertices = None;
Vertices {
draw,
node_vertices,
}
}
pub fn triangles(&self) -> Triangles<S> {
geom::tri::iter_from_vertices(self.vertices())
}
pub fn inner_mesh(&self) -> Ref<Mesh<S>> {
Ref::map(self.state.borrow(), |s| &s.mesh)
}
pub fn untransformed_dimension_of<F>(&self, n: &node::Index, point_axis: &F) -> Option<S>
where
F: Fn(&mesh::vertex::Point<S>) -> S,
{
self.state
.borrow_mut()
.untransformed_dimension_of(n, point_axis)
}
pub fn untransformed_x_dimension_of(&self, n: &node::Index) -> Option<S> {
self.state.borrow_mut().untransformed_x_dimension_of(n)
}
pub fn untransformed_y_dimension_of(&self, n: &node::Index) -> Option<S> {
self.state.borrow_mut().untransformed_y_dimension_of(n)
}
pub fn untransformed_z_dimension_of(&self, n: &node::Index) -> Option<S> {
self.state.borrow_mut().untransformed_z_dimension_of(n)
}
pub fn untransformed_dimensions_of(&self, n: &node::Index) -> Option<Vector3<S>> {
if self.state.borrow().geom_graph.node(*n).is_none()
|| !self.state.borrow().ranges.contains_key(n)
{
return None;
}
let dimensions = Vector3 {
x: self.untransformed_x_dimension_of(n).unwrap_or_else(S::zero),
y: self.untransformed_y_dimension_of(n).unwrap_or_else(S::zero),
z: self.untransformed_z_dimension_of(n).unwrap_or_else(S::zero),
};
Some(dimensions)
}
pub fn dimension_of<F>(&self, n: &node::Index, point_axis: &F) -> Option<S>
where
F: Fn(&mesh::vertex::Point<S>) -> S,
{
self.state.borrow_mut().dimension_of(n, point_axis)
}
pub fn x_dimension_of(&self, n: &node::Index) -> Option<S> {
self.state.borrow_mut().x_dimension_of(n)
}
pub fn y_dimension_of(&self, n: &node::Index) -> Option<S> {
self.state.borrow_mut().y_dimension_of(n)
}
pub fn z_dimension_of(&self, n: &node::Index) -> Option<S> {
self.state.borrow_mut().z_dimension_of(n)
}
pub fn finish_remaining_drawings(&self) -> Result<(), geom::graph::WouldCycle<S>> {
self.state.borrow_mut().finish_remaining_drawings()
}
}
impl<S> Default for IntermediaryState<S> {
fn default() -> Self {
let intermediary_mesh = Default::default();
let fill_tessellator = Default::default();
let path_event_buffer = Default::default();
let text_buffer = Default::default();
let glyph_cache = Default::default();
IntermediaryState {
intermediary_mesh,
fill_tessellator,
path_event_buffer,
text_buffer,
glyph_cache,
}
}
}
impl<S> Default for State<S>
where
S: BaseFloat,
{
fn default() -> Self {
let geom_graph = Default::default();
let geom_graph_dfs = RefCell::new(geom::graph::node::Dfs::new(&geom_graph));
let drawing = Default::default();
let intermediary_state = RefCell::new(Default::default());
let mesh = Default::default();
let ranges = Default::default();
let theme = Default::default();
let last_node_drawn = Default::default();
let background_color = Default::default();
State {
geom_graph,
geom_graph_dfs,
intermediary_state,
mesh,
drawing,
ranges,
theme,
last_node_drawn,
background_color,
}
}
}
impl<S> Default for Draw<S>
where
S: BaseFloat,
{
fn default() -> Self {
let state = RefCell::new(Default::default());
Draw { state }
}
}
impl<'a, S> Iterator for Vertices<'a, S>
where
S: BaseFloat,
{
type Item = mesh::Vertex<S>;
fn next(&mut self) -> Option<Self::Item> {
let Vertices {
ref draw,
ref mut node_vertices,
} = *self;
loop {
if let Some(v) = node_vertices.as_mut().and_then(|n| n.next()) {
return Some(v);
}
let next_transform = {
let state = draw.state.borrow();
let mut dfs = state.geom_graph_dfs.borrow_mut();
dfs.next_transform(&state.geom_graph)
};
match next_transform {
None => return None,
Some((n, transform)) => {
let index_range = match draw.state.borrow().ranges.get(&n) {
None => continue,
Some(ranges) => ranges.indices.clone(),
};
let vertices =
crate::mesh::vertices(draw.inner_mesh()).index_range(index_range);
let transformed_vertices = transform.vertices(vertices);
*node_vertices = Some(transformed_vertices);
}
}
}
}
}
impl<'a, S> Iterator for RawVertices<'a, S>
where
S: BaseFloat,
{
type Item = mesh::Vertex<S>;
fn next(&mut self) -> Option<Self::Item> {
let RawVertices {
ref draw,
ref mut node_vertices,
} = *self;
loop {
if let Some(v) = node_vertices.as_mut().and_then(|n| n.next()) {
return Some(v);
}
let next_transform = {
let state = draw.state.borrow();
let mut dfs = state.geom_graph_dfs.borrow_mut();
dfs.next_transform(&state.geom_graph)
};
match next_transform {
None => return None,
Some((n, transform)) => {
let vertex_range = match draw.state.borrow().ranges.get(&n) {
None => continue,
Some(ranges) => ranges.vertices.clone(),
};
let vertices = crate::mesh::raw_vertices(draw.inner_mesh()).range(vertex_range);
let transformed_vertices = transform.vertices(vertices);
*node_vertices = Some(transformed_vertices);
}
}
}
}
}
impl Clone for FillTessellatorWrapper {
fn clone(&self) -> Self {
Default::default()
}
}
impl Clone for GlyphCacheWrapper {
fn clone(&self) -> Self {
GlyphCacheWrapper(self.0.to_builder().build())
}
}
impl fmt::Debug for FillTessellatorWrapper {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "FillTessellator")
}
}
impl fmt::Debug for GlyphCacheWrapper {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "GlyphCache")
}
}
impl ops::Deref for GlyphCacheWrapper {
type Target = text::GlyphCache<'static>;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl Default for GlyphCache {
fn default() -> Self {
let (w, h) = GlyphCache::DEFAULT_DIMENSIONS;
let cache = text::GlyphCache::builder().dimensions(w, h).build().into();
let pixel_buffer = vec![0u8; w as usize * h as usize];
let has_updated = false;
GlyphCache {
cache,
pixel_buffer,
has_updated,
}
}
}
impl From<text::GlyphCache<'static>> for GlyphCacheWrapper {
fn from(g: text::GlyphCache<'static>) -> Self {
GlyphCacheWrapper(g)
}
}
fn position_to_edge<S, F>(
node_index: node::Index,
position: &Position<S>,
draw: &mut State<S>,
axis: edge::Axis,
point_axis: &F,
) -> (geom::graph::Edge<S>, node::Index)
where
S: BaseFloat,
F: Fn(&mesh::vertex::Point<S>) -> S,
{
match *position {
Position::Absolute(s) => {
let edge = geom::graph::Edge::position(axis, s);
let origin = draw.geom_graph.origin();
(edge, origin)
}
Position::Relative(relative, maybe_parent) => {
let parent = maybe_parent
.or(draw.last_node_drawn)
.unwrap_or(draw.geom_graph.origin());
let edge = match relative {
position::Relative::Scalar(s) => geom::graph::Edge::position(axis, s),
position::Relative::Align(align) => match align {
position::Align::Middle => {
let zero = S::zero();
geom::graph::Edge::position(axis, zero)
}
align => {
let one = S::one();
let (direction, margin) = match align {
position::Align::Start(mgn) => (-one, mgn.unwrap_or(S::zero())),
position::Align::End(mgn) => (one, mgn.unwrap_or(S::zero())),
_ => unreachable!(),
};
let node_dimension = draw
.untransformed_dimension_of(&node_index, point_axis)
.unwrap();
let parent_dimension = draw
.dimension_of(&parent, point_axis)
.expect("no node for relative position");
let half = S::from(0.5).unwrap();
let node_half_dim = node_dimension * half;
let parent_half_dim = parent_dimension * half;
let weight = direction * (parent_half_dim - node_half_dim - margin);
geom::graph::Edge::position(axis, weight)
}
},
position::Relative::Direction(direction, amt) => {
let one = S::one();
let direction = match direction {
position::Direction::Backwards => -one,
position::Direction::Forwards => one,
};
let node_dimension = draw
.untransformed_dimension_of(&node_index, point_axis)
.unwrap();
let parent_dimension = draw
.dimension_of(&parent, point_axis)
.expect("no node for relative position");
let half = S::from(0.5).unwrap();
let node_half_dim = node_dimension * half;
let parent_half_dim = parent_dimension * half;
let weight = direction * (parent_half_dim + node_half_dim + amt);
geom::graph::Edge::position(axis, weight)
}
};
(edge, parent)
}
}
}
fn orientation_to_edge<S>(
orientation: &Orientation<S>,
draw: &mut State<S>,
axis: edge::Axis,
) -> (geom::graph::Edge<S>, node::Index)
where
S: BaseFloat,
{
match *orientation {
Orientation::Absolute(s) => {
let edge = geom::graph::Edge::orientation(axis, s);
let origin = draw.geom_graph.origin();
(edge, origin)
}
Orientation::Relative(s, maybe_parent) => {
let parent = maybe_parent
.or(draw.last_node_drawn)
.unwrap_or(draw.geom_graph.origin());
let edge = geom::graph::Edge::orientation(axis, s);
(edge, parent)
}
}
}
fn point_x<S: Clone>(p: &mesh::vertex::Point<S>) -> S {
p.x.clone()
}
fn point_y<S: Clone>(p: &mesh::vertex::Point<S>) -> S {
p.y.clone()
}
fn point_z<S: Clone>(p: &mesh::vertex::Point<S>) -> S {
p.z.clone()
}
fn into_drawn<T, S>(
draw: &mut State<S>,
node_index: node::Index,
drawing: T,
) -> Result<(), geom::graph::WouldCycle<S>>
where
T: IntoDrawn<S>,
S: BaseFloat,
{
let (spatial, vertices, indices) = drawing.into_drawn(properties::Draw::new(draw));
let vertices_start_index = draw.mesh.raw_vertex_count();
let indices_start_index = draw.mesh.indices().len();
{
let State {
ref mut mesh,
ref intermediary_state,
..
} = *draw;
let intermediary_state = intermediary_state.borrow();
let intermediary_mesh = &intermediary_state.intermediary_mesh;
let min_intermediary_index = properties::Indices::min_index(&indices);
let vertices = properties::Vertices::into_iter(vertices, intermediary_mesh);
let indices = properties::Indices::into_iter(indices, &intermediary_mesh.indices)
.map(|i| vertices_start_index + i - min_intermediary_index);
mesh.extend(vertices, indices);
}
let vertices_end_index = draw.mesh.raw_vertex_count();
let indices_end_index = draw.mesh.indices().len();
let vertices = vertices_start_index..vertices_end_index;
let indices = indices_start_index..indices_end_index;
let ranges = Ranges { vertices, indices };
draw.ranges.insert(node_index, ranges);
let p = &spatial.position;
let x = p.x.map(|pos| {
(
pos,
edge::Axis::X,
point_x as fn(&mesh::vertex::Point<S>) -> S,
)
});
let y = p.y.map(|pos| (pos, edge::Axis::Y, point_y as _));
let z = p.z.map(|pos| (pos, edge::Axis::Z, point_z as _));
let positions = x.into_iter().chain(y).chain(z);
for (position, axis, point_axis) in positions {
let (edge, parent) = position_to_edge(node_index, &position, draw, axis, &point_axis);
draw.geom_graph.set_edge(parent, node_index, edge)?;
}
match spatial.orientation {
orientation::Properties::LookAt(look_at) => {
let _p = match look_at {
orientation::LookAt::Node(_node) => unimplemented!(),
orientation::LookAt::Point(point) => point,
};
unimplemented!();
}
orientation::Properties::Axes(axes) => {
let x = axes.x.map(|axis| (axis, edge::Axis::X));
let y = axes.y.map(|axis| (axis, edge::Axis::Y));
let z = axes.z.map(|axis| (axis, edge::Axis::Z));
let axes = x.into_iter().chain(y).chain(z);
for (orientation, axis) in axes {
let (edge, parent) = orientation_to_edge(&orientation, draw, axis);
draw.geom_graph.set_edge(parent, node_index, edge)?;
}
}
}
draw.last_node_drawn = Some(node_index);
Ok(())
}
fn draw_primitive<S>(
draw: &mut State<S>,
node_index: node::Index,
primitive: Primitive<S>,
) -> Result<(), geom::graph::WouldCycle<S>>
where
S: BaseFloat,
{
match primitive {
Primitive::Ellipse(prim) => into_drawn(draw, node_index, prim),
Primitive::Line(prim) => into_drawn(draw, node_index, prim),
Primitive::Mesh(prim) => into_drawn(draw, node_index, prim),
Primitive::Path(prim) => into_drawn(draw, node_index, prim),
Primitive::Polygon(prim) => into_drawn(draw, node_index, prim),
Primitive::Quad(prim) => into_drawn(draw, node_index, prim),
Primitive::Rect(prim) => into_drawn(draw, node_index, prim),
Primitive::Text(prim) => into_drawn(draw, node_index, prim),
Primitive::Tri(prim) => into_drawn(draw, node_index, prim),
Primitive::MeshVertexless(_)
| Primitive::PathInit(_)
| Primitive::PathFill(_)
| Primitive::PathStroke(_)
| Primitive::PolygonInit(_) => Ok(()),
}
}
fn min_max_dimension<I, F, S>(points: I, point_axis: &F) -> Option<(S, S)>
where
I: IntoIterator<Item = mesh::vertex::Point<S>>,
F: Fn(&mesh::vertex::Point<S>) -> S,
S: BaseFloat,
{
let mut points = points.into_iter();
points.next().map(|first| {
let s = point_axis(&first);
let init = (s, s);
points.fold(init, |(min, max), p| {
let s = point_axis(&p);
(s.min(min), s.max(max))
})
})
}