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