cvkg_render_gpu/passes/
ui.rs1use crate::kvasir::node::{ExecutionContext, KvasirNode};
2use crate::kvasir::nodes::{PassId, RES_SCENE};
3use crate::kvasir::resource::ResourceId;
4
5pub struct UINode {
10 pub inputs: Vec<ResourceId>,
11 pub outputs: Vec<ResourceId>,
12}
13
14impl UINode {
15 pub fn new() -> Self {
19 Self {
20 inputs: vec![RES_SCENE],
21 outputs: vec![RES_SCENE],
22 }
23 }
24}
25
26impl Default for UINode {
27 fn default() -> Self {
28 Self::new()
29 }
30}
31
32impl KvasirNode for UINode {
33 fn label(&self) -> &'static str {
34 "UI"
35 }
36
37 fn inputs(&self) -> &[ResourceId] {
38 &self.inputs
39 }
40
41 fn outputs(&self) -> &[ResourceId] {
42 &self.outputs
43 }
44
45 fn pass_id(&self) -> PassId {
46 PassId::UI
47 }
48
49 fn execute(&self, ctx: &mut ExecutionContext) {
50 let rt_w = ctx.renderer.current_width() as i32;
51 let rt_h = ctx.renderer.current_height() as i32;
52 let scale = ctx.renderer.current_scale_factor();
53
54 let scene_view = match ctx.registry.get_texture_view(RES_SCENE) {
55 Some(v) => v,
56 None => {
57 log::error!("Missing texture view for {}", stringify!(RES_SCENE));
58 return;
59 }
60 };
61
62 let mut p = ctx.encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
63 label: Some("Surtr P4 UI Layer"),
64 color_attachments: &[Some(wgpu::RenderPassColorAttachment {
65 view: &scene_view,
66 resolve_target: None,
67 ops: wgpu::Operations {
68 load: wgpu::LoadOp::Load,
69 store: wgpu::StoreOp::Store,
70 },
71 depth_slice: None,
72 })],
73 depth_stencil_attachment: None,
74 ..Default::default()
75 });
76
77 p.set_pipeline(&ctx.renderer.ui_pipeline);
78 p.set_vertex_buffer(0, ctx.renderer.geometry_buffers.vertex_buffer.slice(..));
79 p.set_vertex_buffer(1, ctx.renderer.geometry_buffers.instance_buffer.slice(..));
80 p.set_index_buffer(
81 ctx.renderer.geometry_buffers.index_buffer.slice(..),
82 wgpu::IndexFormat::Uint32,
83 );
84 p.set_bind_group(1, &ctx.renderer.dummy_env_bind_group, &[]);
85 p.set_bind_group(2, &ctx.renderer.berserker_bind_group, &[]);
86 p.set_bind_group(3, &ctx.renderer.gradient_bind_group, &[]);
87
88 for call in ctx
89 .renderer
90 .draw_calls
91 .iter()
92 .filter(|c| matches!(c.material, cvkg_core::DrawMaterial::TopUI))
93 {
94 let bg = if let Some(id) = call.texture_id {
95 if id == 0 {
96 &ctx.renderer.mega_heim_bind_group
97 } else {
98 ctx.renderer
99 .texture_bind_groups
100 .get(id as usize)
101 .unwrap_or(&ctx.renderer.dummy_texture_bind_group)
102 }
103 } else {
104 &ctx.renderer.dummy_texture_bind_group
105 };
106
107 p.set_bind_group(0, bg, &[]);
108
109 if let Some(rect) = call.scissor_rect
110 && rt_w > 0
111 && rt_h > 0
112 {
113 let x1 = (rect.x * scale).round() as i32;
114 let y1 = (rect.y * scale).round() as i32;
115 let x2 = ((rect.x + rect.width) * scale).round() as i32;
116 let y2 = ((rect.y + rect.height) * scale).round() as i32;
117 let w = (x2 - x1).clamp(0, rt_w);
118 let h = (y2 - y1).clamp(0, rt_h);
119 if w > 0 && h > 0 {
120 p.set_scissor_rect(x1 as u32, y1 as u32, w as u32, h as u32);
121 } else {
122 p.set_scissor_rect(0, 0, 0, 0);
123 }
124 } else {
125 p.set_scissor_rect(0, 0, rt_w as u32, rt_h as u32);
126 }
127 p.draw_indexed(
128 call.index_start..call.index_start + call.index_count,
129 0,
130 call.instance_start..call.instance_start + call.instance_count,
131 );
132 }
133 }
134}