mirror of
https://github.com/penpot/penpot.git
synced 2026-04-29 21:28:20 +00:00
WIP
This commit is contained in:
parent
3af70a965d
commit
446fc53f00
@ -99,7 +99,7 @@
|
||||
;; This should never be called from the outside.
|
||||
(defn- render
|
||||
([timestamp]
|
||||
(render timestamp false))
|
||||
(render timestamp true))
|
||||
|
||||
([timestamp full]
|
||||
(h/call wasm/internal-module "_render" timestamp full)
|
||||
|
||||
@ -672,6 +672,15 @@ impl RenderState {
|
||||
self.current_tile = None;
|
||||
self.render_in_progress = true;
|
||||
self.render_is_full = full;
|
||||
if self.render_is_full {
|
||||
self.pending_nodes.push(NodeRenderState {
|
||||
id: Uuid::nil(),
|
||||
visited_children: false,
|
||||
clip_bounds: None,
|
||||
visited_mask: false,
|
||||
mask: false,
|
||||
});
|
||||
}
|
||||
self.apply_drawing_to_render_canvas(None);
|
||||
self.process_animation_frame(tree, modifiers, structure, scale_content, timestamp)?;
|
||||
performance::end_measure!("start_render_loop");
|
||||
@ -886,7 +895,172 @@ impl RenderState {
|
||||
scale_content: &HashMap<Uuid, f32>,
|
||||
timestamp: i32,
|
||||
) -> Result<(bool, bool), String> {
|
||||
self.render_shape_tree_partial_uncached(tree, modifiers, structure, scale_content, timestamp)
|
||||
let result = self.render_shape_tree_full_uncached(tree, modifiers, structure, scale_content, timestamp);
|
||||
|
||||
let (is_empty, should_stop_rendering) = result?;
|
||||
if should_stop_rendering {
|
||||
self.render_in_progress = false;
|
||||
self.render_is_full = false;
|
||||
}
|
||||
|
||||
if self.options.is_debug_visible() {
|
||||
debug::render(self);
|
||||
}
|
||||
|
||||
debug::render_wasm_label(self);
|
||||
Ok((is_empty, should_stop_rendering))
|
||||
}
|
||||
|
||||
pub fn render_shape_tree_full_uncached(
|
||||
&mut self,
|
||||
tree: &mut HashMap<Uuid, &mut Shape>,
|
||||
modifiers: &HashMap<Uuid, Matrix>,
|
||||
structure: &HashMap<Uuid, Vec<StructureEntry>>,
|
||||
scale_content: &HashMap<Uuid, f32>,
|
||||
timestamp: i32,
|
||||
) -> Result<(bool, bool), String> {
|
||||
let mut iteration = 0;
|
||||
let mut is_empty = true;
|
||||
let scale = self.get_scale();
|
||||
let tile_hashmap = &self.tiles;
|
||||
println!("render_shape_tree_full_uncached::while::start");
|
||||
while let Some(node_render_state) = self.pending_nodes.pop() {
|
||||
println!("render_shape_tree_full_uncached::while::pop {}", self.pending_nodes.len());
|
||||
let NodeRenderState {
|
||||
id: node_id,
|
||||
visited_children,
|
||||
clip_bounds,
|
||||
visited_mask,
|
||||
mask,
|
||||
} = node_render_state;
|
||||
|
||||
is_empty = false;
|
||||
let element = tree.get_mut(&node_id).ok_or(
|
||||
"Error: Element with root_id {node_render_state.id} not found in the tree."
|
||||
.to_string(),
|
||||
)?;
|
||||
|
||||
let tiles = tile_hashmap.get_tiles_of(node_id);
|
||||
// If the shape is not in the tile set, then we update
|
||||
// it.
|
||||
if tiles.is_none() {
|
||||
self.update_tile_for(element);
|
||||
}
|
||||
|
||||
// We need to iterate over every tile of the element.
|
||||
for tile in tiles.unwrap() {
|
||||
println!("render_shape_tree_full_uncached::while::start {} {}", tile.0, tile.1);
|
||||
self.current_tile = Some(*tile);
|
||||
self.render_area = tiles::get_tile_rect(*tile, scale);
|
||||
|
||||
if visited_children {
|
||||
if !visited_mask {
|
||||
if let Type::Group(group) = element.shape_type {
|
||||
// When we're dealing with masked groups we need to
|
||||
// do a separate extra step to draw the mask (the last
|
||||
// element of a masked group) and blend (using
|
||||
// the blend mode 'destination-in') the content
|
||||
// of the group and the mask.
|
||||
if group.masked {
|
||||
self.pending_nodes.push(NodeRenderState {
|
||||
id: node_id,
|
||||
visited_children: true,
|
||||
clip_bounds: None,
|
||||
visited_mask: true,
|
||||
mask: false,
|
||||
});
|
||||
if let Some(&mask_id) = element.mask_id() {
|
||||
self.pending_nodes.push(NodeRenderState {
|
||||
id: mask_id,
|
||||
visited_children: false,
|
||||
clip_bounds: None,
|
||||
visited_mask: false,
|
||||
mask: true,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
self.render_shape_exit(element, visited_mask);
|
||||
continue;
|
||||
}
|
||||
|
||||
if !node_render_state.id.is_nil() {
|
||||
let mut transformed_element: Cow<Shape> = Cow::Borrowed(element);
|
||||
|
||||
if let Some(modifier) = modifiers.get(&node_id) {
|
||||
transformed_element.to_mut().apply_transform(modifier);
|
||||
}
|
||||
|
||||
let is_visible = transformed_element.extrect().intersects(self.render_area)
|
||||
&& !transformed_element.hidden
|
||||
&& !transformed_element.visually_insignificant(scale);
|
||||
|
||||
if self.options.is_debug_visible() {
|
||||
debug::render_debug_shape(self, &transformed_element, is_visible);
|
||||
}
|
||||
|
||||
if !is_visible {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
self.render_shape_enter(element, mask);
|
||||
if !node_render_state.id.is_nil() {
|
||||
self.render_shape(
|
||||
element,
|
||||
modifiers.get(&element.id),
|
||||
scale_content.get(&element.id),
|
||||
clip_bounds,
|
||||
);
|
||||
} else {
|
||||
self.apply_drawing_to_render_canvas(Some(element));
|
||||
}
|
||||
}
|
||||
|
||||
// Set the node as visited_children before processing children
|
||||
self.pending_nodes.push(NodeRenderState {
|
||||
id: node_id,
|
||||
visited_children: true,
|
||||
clip_bounds: None,
|
||||
visited_mask: false,
|
||||
mask,
|
||||
});
|
||||
|
||||
if element.is_recursive() {
|
||||
let children_clip_bounds =
|
||||
node_render_state.get_children_clip_bounds(element, modifiers.get(&element.id));
|
||||
|
||||
let mut children_ids = modified_children_ids(element, structure.get(&element.id));
|
||||
|
||||
// Z-index ordering on Layouts
|
||||
if element.has_layout() {
|
||||
children_ids.sort_by(|id1, id2| {
|
||||
let z1 = tree.get(id1).map_or_else(|| 0, |s| s.z_index());
|
||||
let z2 = tree.get(id2).map_or_else(|| 0, |s| s.z_index());
|
||||
z1.cmp(&z2)
|
||||
});
|
||||
}
|
||||
|
||||
for child_id in children_ids.iter() {
|
||||
self.pending_nodes.push(NodeRenderState {
|
||||
id: *child_id,
|
||||
visited_children: false,
|
||||
clip_bounds: children_clip_bounds,
|
||||
visited_mask: false,
|
||||
mask: false,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// We try to avoid doing too many calls to get_time
|
||||
if self.should_stop_rendering(iteration, timestamp) {
|
||||
return Ok((is_empty, true));
|
||||
}
|
||||
iteration += 1;
|
||||
}
|
||||
println!("render_shape_tree_full_uncached::while::end");
|
||||
Ok((is_empty, self.pending_nodes.is_empty()))
|
||||
}
|
||||
|
||||
pub fn render_shape_tree_partial_uncached(
|
||||
@ -899,6 +1073,7 @@ impl RenderState {
|
||||
) -> Result<(bool, bool), String> {
|
||||
let mut iteration = 0;
|
||||
let mut is_empty = true;
|
||||
let scale = self.get_scale();
|
||||
while let Some(node_render_state) = self.pending_nodes.pop() {
|
||||
let NodeRenderState {
|
||||
id: node_id,
|
||||
@ -939,7 +1114,7 @@ impl RenderState {
|
||||
|
||||
let is_visible = transformed_element.extrect().intersects(self.render_area)
|
||||
&& !transformed_element.hidden
|
||||
&& !transformed_element.visually_insignificant(self.get_scale());
|
||||
&& !transformed_element.visually_insignificant(scale);
|
||||
|
||||
if self.options.is_debug_visible() {
|
||||
debug::render_debug_shape(self, &transformed_element, is_visible);
|
||||
@ -1003,7 +1178,7 @@ impl RenderState {
|
||||
}
|
||||
iteration += 1;
|
||||
}
|
||||
Ok((is_empty, false))
|
||||
Ok((is_empty, self.pending_nodes.is_empty()))
|
||||
}
|
||||
|
||||
pub fn render_shape_tree_partial(
|
||||
@ -1221,6 +1396,10 @@ impl RenderState {
|
||||
self.viewbox.zoom() * self.options.dpr()
|
||||
}
|
||||
|
||||
pub fn get_scale_mut(&mut self) -> f32 {
|
||||
self.viewbox.zoom() * self.options.dpr()
|
||||
}
|
||||
|
||||
pub fn get_cached_scale(&self) -> f32 {
|
||||
self.cached_viewbox.zoom() * self.options.dpr()
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user