use super::types::{ClipRectDrawData, DrawCommandError};
use super::*;
use crate::ShapeDrawCommandOptions;
use crate::ShapeTextureFitMode;
fn clip_rect_supports_transform(transform: InstanceTransform) -> bool {
rect_utils::extract_axis_aligned_rect_transform(Some(transform)).is_some()
}
impl<'a> Renderer<'a> {
pub fn load_shape(
&mut self,
shape: impl AsRef<Shape>,
cache_key: u64,
geometry_id: Option<u64>,
) {
let cached_shape = CachedShapeHandle::new(
shape.as_ref(),
&mut self.tessellator,
&mut self.buffers_pool_manager,
geometry_id,
);
self.shape_cache.insert(cache_key, cached_shape);
}
pub fn remove_shape(&mut self, cache_key: u64) {
self.shape_cache.remove(&cache_key);
}
pub fn add_cached_shape_to_the_render_queue(
&mut self,
cache_key: u64,
parent_shape_id: Option<usize>,
options: ShapeDrawCommandOptions,
) -> Result<usize, DrawCommandError> {
let mut draw_data = if let Some(cached_shape_handle) = self.shape_cache.get(&cache_key) {
CachedShapeDrawData::new(cached_shape_handle.clone(), &options)
} else {
return Err(DrawCommandError::ShapeNotLoaded(cache_key));
};
self.append_buffers_for_shape(&mut draw_data, &options);
self.add_draw_command(DrawCommand::CachedShape(draw_data), parent_shape_id)
}
pub fn add_shape(
&mut self,
shape: impl AsRef<Shape>,
parent_shape_id: Option<usize>,
geometry_id: Option<u64>,
options: ShapeDrawCommandOptions,
) -> Result<usize, DrawCommandError> {
let cached_shape = CachedShapeHandle::new(
shape.as_ref(),
&mut self.tessellator,
&mut self.buffers_pool_manager,
geometry_id,
);
let mut draw_data = CachedShapeDrawData::new(cached_shape, &options);
self.append_buffers_for_shape(&mut draw_data, &options);
self.add_draw_command(DrawCommand::CachedShape(draw_data), parent_shape_id)
}
pub fn add_clipping_rect(
&mut self,
rect_bounds: [(f32, f32); 2],
parent_shape_id: Option<usize>,
transform: Option<impl Into<InstanceTransform>>,
clips_children: bool,
) -> Result<usize, DrawCommandError> {
let transform = transform.map(Into::into);
if let Some(transform) = transform {
if !clip_rect_supports_transform(transform) {
return Err(DrawCommandError::UnsupportedClipRectTransform);
}
}
self.add_draw_command(
DrawCommand::ClipRect(ClipRectDrawData::new(
rect_bounds,
transform,
clips_children,
)),
parent_shape_id,
)
}
fn append_buffers_for_shape(
&mut self,
cached_shape_data: &mut CachedShapeDrawData,
draw_options: &ShapeDrawCommandOptions,
) {
self.refresh_geometry_cache(cached_shape_data);
cached_shape_data.refresh_gradient_bind_group(
&mut self.buffers_pool_manager.gradient_cache,
&self.device,
&self.queue,
&self.gradient_bind_group_layout,
&self.gradient_ramp_sampler,
self.gradient_bind_group_layout_epoch,
);
let index_range = preparation::append_aggregated_geometry_for_shape(
cached_shape_data,
&mut self.temp_vertices,
&mut self.temp_indices,
&mut self.geometry_dedup_map,
);
if let Some((index_start, index_count)) = index_range {
cached_shape_data.index_buffer_range = Some((index_start, index_count));
cached_shape_data.is_empty = false;
let texture_uv_scales = self.compute_texture_uv_scales(
cached_shape_data.cached_shape.texture_mapping_size(),
draw_options,
);
let instance_index = preparation::append_instance_data(
&mut self.temp_instance_transforms,
&mut self.temp_instance_colors,
&mut self.temp_instance_metadata,
draw_options.transform,
match &draw_options.fill {
None => None,
Some(fill) => fill.to_normalized_solid(),
},
preparation::InstanceTextureData {
texture_ids: cached_shape_data.texture_ids,
texture_uv_scales,
},
);
*cached_shape_data.instance_index_mut() = Some(instance_index);
} else {
cached_shape_data.is_empty = true;
}
}
fn add_draw_command(
&mut self,
draw_command: DrawCommand,
parent_shape_id: Option<usize>,
) -> Result<usize, DrawCommandError> {
if self.draw_tree.is_empty() {
let node_id = self.draw_tree.add_node(draw_command);
Ok(node_id)
} else if let Some(parent_shape_id) = parent_shape_id {
if let Some(parent) = self.draw_tree.get_mut(parent_shape_id) {
parent.set_not_leaf();
let node_id = self.draw_tree.add_child(parent_shape_id, draw_command);
Ok(node_id)
} else {
Err(DrawCommandError::InvalidShapeId(parent_shape_id))
}
} else {
if let Some(root) = self.draw_tree.get_mut(0) {
root.set_not_leaf();
}
let node_id = self.draw_tree.add_child_to_root(draw_command);
Ok(node_id)
}
}
fn refresh_geometry_cache(&mut self, cached_shape_data: &CachedShapeDrawData) {
if let Some(geometry_id) = cached_shape_data.cached_shape.geometry_id {
self.buffers_pool_manager
.tessellation_cache
.refresh_vertex_buffers(geometry_id, &cached_shape_data.cached_shape.tessellation);
}
}
pub fn texture_manager(&self) -> &TextureManager {
&self.texture_manager
}
pub fn clear_draw_queue(&mut self) {
self.draw_tree.clear();
self.metadata_to_clips.clear();
self.group_effects.clear();
self.backdrop_effects.clear();
self.trim_scratch_on_resize_or_policy();
self.clear_buffers();
}
fn compute_texture_uv_scales(
&self,
texture_mapping_size: [f32; 2],
draw_options: &ShapeDrawCommandOptions,
) -> [[f32; 2]; 2] {
[
self.compute_texture_uv_scale_for_layer(
draw_options.background_texture.texture_id,
draw_options.background_texture.fit_mode,
texture_mapping_size,
),
self.compute_texture_uv_scale_for_layer(
draw_options.foreground_texture.texture_id,
draw_options.foreground_texture.fit_mode,
texture_mapping_size,
),
]
}
fn compute_texture_uv_scale_for_layer(
&self,
texture_id: Option<u64>,
texture_fit_mode: ShapeTextureFitMode,
texture_mapping_size: [f32; 2],
) -> [f32; 2] {
if texture_fit_mode != ShapeTextureFitMode::OriginalSize {
return [1.0, 1.0];
}
let Some(texture_id) = texture_id else {
return [1.0, 1.0];
};
let Some((texture_width, texture_height)) =
self.texture_manager.texture_dimensions(texture_id)
else {
return [1.0, 1.0];
};
self.compute_texture_uv_scale_from_dimensions(
texture_mapping_size,
(texture_width, texture_height),
)
}
pub(super) fn compute_texture_uv_scale_from_dimensions(
&self,
texture_mapping_size: [f32; 2],
texture_dimensions: (u32, u32),
) -> [f32; 2] {
[
texture_mapping_size[0] * self.scale_factor as f32 / texture_dimensions.0.max(1) as f32,
texture_mapping_size[1] * self.scale_factor as f32 / texture_dimensions.1.max(1) as f32,
]
}
}