Skip to main content

cvkg_render_gpu/api/
shapes.rs

1use 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    /// Inherent method: stroke a lyon path using wgpu.
10    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                panel_id: self.current_panel_id,
90                texture_id: tid,
91                scissor_rect: self.clip_stack.last().copied(),
92                index_start: base_index_idx,
93                index_count: idx_count as u32,
94                instance_count: 1,
95                material,
96                instance_start: (self.instance_data.len() - 1) as u32,
97                draw_order: 0,
98            });
99        } else {
100            if let Some(last) = self.draw_calls.last_mut() {
101                last.index_count += idx_count as u32;
102            }
103        }
104    }
105}