cvkg_render_gpu/api/
shapes.rs1use crate::renderer::GpuRenderer;
2use crate::types::DrawCall;
3use crate::vertex::{CustomStrokeVertexConstructor, InstanceData, Vertex};
4use cvkg_core::Renderer;
5use lyon::tessellation::{BuffersBuilder, StrokeOptions, StrokeTessellator, VertexBuffers};
6use std::hash::Hasher;
7
8impl GpuRenderer {
9 pub fn stroke_path_impl(
11 &mut self,
12 path: &lyon::path::Path,
13 color: [f32; 4],
14 stroke_width: f32,
15 ) {
16 let c = self.apply_opacity(color);
17 let base_vertex_idx = self.vertices.len() as u32;
18 let base_index_idx = self.indices.len() as u32;
19
20 let path_hash = {
21 let mut h = std::collections::hash_map::DefaultHasher::new();
22 let num_elements = path.iter().count();
23 std::hash::Hash::hash(&num_elements, &mut h);
24 std::hash::Hash::hash(&stroke_width.to_bits(), &mut h);
25 h.finish()
26 };
27
28 let (vert_count, idx_count) = match self.path_geometry_cache.get(&path_hash) {
29 Some((cached_verts, cached_indices)) => {
30 self.vertices.extend_from_slice(cached_verts);
31 for idx in cached_indices {
32 self.indices.push(base_vertex_idx + *idx);
33 }
34 (cached_verts.len(), cached_indices.len())
35 }
36 None => {
37 let mut tessellator = StrokeTessellator::new();
38 let mut buffers: VertexBuffers<Vertex, u32> = VertexBuffers::new();
39 let result = tessellator.tessellate_path(
40 path,
41 &StrokeOptions::default().with_line_width(stroke_width),
42 &mut BuffersBuilder::new(
43 &mut buffers,
44 CustomStrokeVertexConstructor {
45 color: c,
46 clip: [0.0, 0.0, 0.0, 0.0],
47 path_length: 1.0,
48 },
49 ),
50 );
51 if let Err(e) = result {
52 tracing::warn!("Failed to tessellate stroke path: {:?}", e);
53 return;
54 }
55 let vert_count = buffers.vertices.len();
56 let idx_count = buffers.indices.len();
57 let cached_verts = buffers.vertices.clone();
58 let cached_indices = buffers.indices.clone();
59 self.path_geometry_cache
60 .put(path_hash, (cached_verts, cached_indices));
61 self.vertices.extend(buffers.vertices);
62 for idx in &buffers.indices {
63 self.indices.push(base_vertex_idx + *idx);
64 }
65 (vert_count, idx_count)
66 }
67 };
68
69 let material = self.current_material();
70 let tid = self.get_texture_id("__mega_heim");
71
72 if self.draw_calls.last().is_none()
73 || self.current_texture_id != tid
74 || self.draw_calls.last().unwrap().scissor_rect != self.clip_stack.last().copied()
75 || self.draw_calls.last().unwrap().material != material
76 {
77 self.current_texture_id = tid;
78 let (translation, scale, rotation, _, _) = self.current_transform();
79 self.instance_data.push(InstanceData {
80 translation,
81 scale,
82 rotation,
83 blur_radius: 0.0,
84 ior_override: 0.0,
85 glass_intensity: 1.0,
86 });
87 self.draw_calls.push(DrawCall {
88 target_id: None,
89 texture_id: tid,
90 scissor_rect: self.clip_stack.last().copied(),
91 index_start: base_index_idx,
92 index_count: idx_count as u32,
93 instance_count: 1,
94 material,
95 instance_start: (self.instance_data.len() - 1) as u32,
96 draw_order: 0,
97 });
98 } else {
99 if let Some(last) = self.draw_calls.last_mut() {
100 last.index_count += idx_count as u32;
101 }
102 }
103 }
104}