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