diff --git a/api.json b/api.json index 213d3528..e36e887f 100644 --- a/api.json +++ b/api.json @@ -12729,7 +12729,7 @@ "fn_args": [ {"nodes": "TessellatedColoredSvgNodeVecRef"} ], - "fn_body": "azul_impl::svg::join_tessellated_nodes(nodes.as_slice())" + "fn_body": "azul_impl::svg::join_tessellated_colored_nodes(nodes.as_slice())" } } }, diff --git a/azul-dll/src/lib.rs b/azul-dll/src/lib.rs index df6f716e..3d5b5d96 100644 --- a/azul-dll/src/lib.rs +++ b/azul-dll/src/lib.rs @@ -3701,7 +3701,7 @@ pub use AzTessellatedColoredSvgNodeTT as AzTessellatedColoredSvgNode; /// Returns an empty buffer vertices / indices #[no_mangle] pub extern "C" fn AzTessellatedColoredSvgNode_empty() -> AzTessellatedColoredSvgNode { AzTessellatedColoredSvgNode::empty() } /// Creates a new TessellatedColoredSvgNode by joining all the given nodes together into one array and inserting a `GL_RESTART_INDEX` (`u32::MAX`) into the indices (so that the resulting buffer can be drawn in one draw call). -#[no_mangle] pub extern "C" fn AzTessellatedColoredSvgNode_fromNodes(nodes: AzTessellatedColoredSvgNodeVecRef) -> AzTessellatedColoredSvgNode { azul_impl::svg::join_tessellated_nodes(nodes.as_slice()) } +#[no_mangle] pub extern "C" fn AzTessellatedColoredSvgNode_fromNodes(nodes: AzTessellatedColoredSvgNodeVecRef) -> AzTessellatedColoredSvgNode { azul_impl::svg::join_tessellated_colored_nodes(nodes.as_slice()) } /// Destructor: Takes ownership of the `TessellatedColoredSvgNode` pointer and deletes it. #[no_mangle] pub extern "C" fn AzTessellatedColoredSvgNode_delete(object: &mut AzTessellatedColoredSvgNode) { unsafe { core::ptr::drop_in_place(object); } } diff --git a/azulc/src/svg.rs b/azulc/src/svg.rs index 51ae6af3..1073019c 100644 --- a/azulc/src/svg.rs +++ b/azulc/src/svg.rs @@ -1293,11 +1293,77 @@ pub fn join_tessellated_nodes(nodes: &[TessellatedSvgNode]) -> TessellatedSvgNod } } +#[cfg(feature = "svg")] +pub fn join_tessellated_colored_nodes(nodes: &[TessellatedColoredSvgNode]) -> TessellatedColoredSvgNode { + + use rayon::iter::IntoParallelRefIterator; + use rayon::iter::ParallelIterator; + use rayon::iter::IndexedParallelIterator; + use rayon::iter::IntoParallelRefMutIterator; + + let mut index_offset = 0; + + // note: can not be parallelized! + let all_index_offsets = nodes + .as_ref() + .iter() + .map(|t| { + let i = index_offset; + index_offset += t.vertices.len(); + i + }) + .collect::>(); + + let all_vertices = nodes + .as_ref() + .par_iter() + .flat_map(|t| t.vertices.clone().into_library_owned_vec()) + .collect::>(); + + let all_indices = nodes + .as_ref() + .par_iter() + .enumerate() + .flat_map(|(buffer_index, t)| { + + // since the vertex buffers are now joined, + // offset the indices by the vertex buffers lengths + // encountered so far + let vertex_buffer_offset: u32 = all_index_offsets + .get(buffer_index) + .copied() + .unwrap_or(0) + .min(core::u32::MAX as usize) as u32; + + let mut indices = t.indices.clone().into_library_owned_vec(); + if vertex_buffer_offset != 0 { + indices + .par_iter_mut() + .for_each(|i| { *i += vertex_buffer_offset; }); + } + + indices.push(GL_RESTART_INDEX); + + indices + }) + .collect::>(); + + TessellatedSvgNode { + vertices: all_vertices.into(), + indices: all_indices.into(), + } +} + #[cfg(not(feature = "svg"))] pub fn join_tessellated_nodes(nodes: &[TessellatedSvgNode]) -> TessellatedSvgNode { TessellatedSvgNode::default() } +#[cfg(not(feature = "svg"))] +pub fn join_tessellated_colored_nodes(nodes: &[TessellatedColoredSvgNode]) -> TessellatedColoredSvgNode { + TessellatedColoredSvgNode::default() +} + #[cfg(feature = "svg")] pub fn tessellate_node_fill(node: &SvgNode, fs: SvgFillStyle) -> TessellatedSvgNode { use rayon::prelude::*;