cvkg_render_gpu/passes/
pre_world_panel.rs1use crate::kvasir::node::{ExecutionContext, KvasirNode};
2use crate::kvasir::resource::ResourceId;
3
4pub struct PreWorldPanelNode {
8 pub panel_textures: Vec<ResourceId>,
9 pub panel_ids: Vec<u64>,
10 pub inputs: Vec<ResourceId>,
11 pub outputs: Vec<ResourceId>,
12}
13
14impl PreWorldPanelNode {
15 pub fn new(panel_textures: Vec<ResourceId>, panel_ids: Vec<u64>) -> Self {
16 Self {
17 panel_textures: panel_textures.clone(),
18 panel_ids,
19 inputs: vec![],
20 outputs: panel_textures,
21 }
22 }
23}
24
25impl KvasirNode for PreWorldPanelNode {
26 fn label(&self) -> &'static str {
27 "PreWorldPanel"
28 }
29 fn inputs(&self) -> &[ResourceId] {
30 &self.inputs
31 }
32 fn outputs(&self) -> &[ResourceId] {
33 &self.outputs
34 }
35 fn pass_id(&self) -> crate::kvasir::nodes::PassId {
36 crate::kvasir::nodes::PassId::PreWorldPanel
37 }
38
39 fn execute(&self, ctx: &mut ExecutionContext) {
40 for (i, &panel_tex) in self.panel_textures.iter().enumerate() {
47 let panel_id = self.panel_ids[i];
48 let view = match ctx.registry.get_texture_view(panel_tex) {
49 Some(v) => v,
50 None => {
51 tracing::error!(
52 "PreWorldPanel: missing texture view for panel {} ({})",
53 i,
54 panel_tex.0
55 );
56 continue;
57 }
58 };
59
60 let mut pass = ctx.encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
62 label: Some(&format!("Surtr PreWorldPanel {}", i)),
63 color_attachments: &[Some(wgpu::RenderPassColorAttachment {
64 view: &view,
65 resolve_target: None,
66 ops: wgpu::Operations {
67 load: wgpu::LoadOp::Clear(wgpu::Color::TRANSPARENT),
68 store: wgpu::StoreOp::Store,
69 },
70 depth_slice: None,
71 })],
72 depth_stencil_attachment: None,
73 timestamp_writes: None,
74 occlusion_query_set: None,
75 multiview_mask: None,
76 });
77
78 pass.set_bind_group(1, &ctx.renderer.dummy_env_bind_group, &[]);
80 pass.set_bind_group(2, &ctx.renderer.berserker_bind_group, &[]);
81 pass.set_bind_group(3, &ctx.renderer.gradient_bind_group, &[]);
82
83 if !ctx.renderer.draw_calls.is_empty() {
85 pass.set_vertex_buffer(0, ctx.renderer.geometry_buffers.vertex_buffer.slice(..));
86 pass.set_vertex_buffer(1, ctx.renderer.geometry_buffers.instance_buffer.slice(..));
87 pass.set_index_buffer(
88 ctx.renderer.geometry_buffers.index_buffer.slice(..),
89 wgpu::IndexFormat::Uint32,
90 );
91
92 for call in &ctx.renderer.draw_calls {
93 if call.panel_id == Some(panel_id) {
94 pass.draw_indexed(
95 call.index_start..call.index_start + call.index_count,
96 0,
97 call.instance_start..call.instance_start + call.instance_count,
98 );
99 }
100 }
101 }
102 }
103 }
104}
105
106#[cfg(test)]
107mod pre_world_panel_tests {
108 use super::*;
109
110 #[test]
111 fn test_pre_world_panel_node_label() {
112 let node = PreWorldPanelNode::new(vec![], vec![]);
113 assert_eq!(node.label(), "PreWorldPanel");
114 }
115
116 #[test]
117 fn test_pre_world_panel_node_empty() {
118 let node = PreWorldPanelNode::new(vec![], vec![]);
119 assert!(node.inputs().is_empty());
120 assert!(node.outputs().is_empty());
121 assert!(node.panel_textures.is_empty());
122 }
123
124 #[test]
125 fn test_pre_world_panel_node_single_panel() {
126 let tex = ResourceId(2000);
127 let node = PreWorldPanelNode::new(vec![tex], vec![123]);
128 assert_eq!(node.inputs().len(), 0);
129 assert_eq!(node.outputs().len(), 1);
130 assert_eq!(node.outputs()[0], tex);
131 assert_eq!(node.panel_textures.len(), 1);
132 }
133
134 #[test]
135 fn test_pre_world_panel_node_multiple_panels() {
136 let texes = vec![ResourceId(2000), ResourceId(2001), ResourceId(2002)];
137 let node = PreWorldPanelNode::new(texes.clone(), vec![1, 2, 3]);
138 assert_eq!(node.outputs().len(), 3);
139 assert_eq!(node.panel_textures.len(), 3);
140 for (i, tex) in texes.iter().enumerate() {
141 assert_eq!(node.panel_textures[i], *tex);
142 }
143 }
144
145 #[test]
146 fn test_pre_world_panel_node_pass_id() {
147 let node = PreWorldPanelNode::new(vec![], vec![]);
148 assert!(matches!(
149 node.pass_id(),
150 crate::kvasir::nodes::PassId::PreWorldPanel
151 ));
152 }
153}