use crate::draw2d::Color;
use crate::effect_pass::EffectPass;
use crate::gpu::GpuContext;
use crate::hot_shader::{HotEffectPass, HotPostProcessPass, HotWorldPostProcessPass};
use crate::post_process::{PostProcessPass, WorldPostProcessPass};
use crate::render_graph::{
EffectNode, HotEffectNode, HotPostProcessNode, HotWorldPostProcessNode, MeshNode, MeshQueue,
PostProcessNode, RenderGraph, WorldPostProcessNode,
};
use std::cell::RefCell;
use std::rc::Rc;
pub struct SceneSetupContext<'a> {
pub gpu: &'a GpuContext,
graph_builder: &'a mut Option<RenderGraph>,
mesh_queue: &'a Rc<RefCell<MeshQueue>>,
}
impl<'a> SceneSetupContext<'a> {
pub(crate) fn new(
gpu: &'a GpuContext,
graph_builder: &'a mut Option<RenderGraph>,
mesh_queue: &'a Rc<RefCell<MeshQueue>>,
) -> Self {
Self {
gpu,
graph_builder,
mesh_queue,
}
}
pub fn background_color(&mut self, color: Color) -> &mut Self {
let shader = format!(
r#"
@group(0) @binding(0) var<uniform> u: Uniforms;
struct Uniforms {{
resolution: vec2f,
time: f32,
}}
@vertex
fn vs(@builtin(vertex_index) vertex_index: u32) -> @builtin(position) vec4f {{
var pos = array<vec2f, 3>(
vec2f(-1.0, -1.0),
vec2f(3.0, -1.0),
vec2f(-1.0, 3.0)
);
return vec4f(pos[vertex_index], 0.0, 1.0);
}}
@fragment
fn fs() -> @location(0) vec4f {{
return vec4f({:.6}, {:.6}, {:.6}, {:.6});
}}
"#,
color.r, color.g, color.b, color.a
);
let effect = EffectPass::new(self.gpu, &shader);
self.add_node(EffectNode::new(effect));
self
}
pub fn effect(&mut self, shader: &str) -> &mut Self {
let effect = EffectPass::new(self.gpu, shader);
self.add_node(EffectNode::new(effect));
self
}
pub fn effect_world(&mut self, shader: &str) -> &mut Self {
let effect = EffectPass::new_world(self.gpu, shader);
self.add_node(EffectNode::new(effect));
self
}
pub fn post_process(&mut self, shader: &str) -> &mut Self {
let pass = PostProcessPass::new(self.gpu, shader);
self.add_node(PostProcessNode::new(pass));
self
}
pub fn post_process_world(&mut self, shader: &str) -> &mut Self {
let pass = WorldPostProcessPass::new(self.gpu, shader);
self.add_node(WorldPostProcessNode::new(pass));
self
}
pub fn hot_effect(&mut self, path: &str) -> &mut Self {
match HotEffectPass::new(self.gpu, path) {
Ok(effect) => self.add_node(HotEffectNode::new(effect)),
Err(e) => eprintln!("[hot-reload] Failed to load shader '{}': {}", path, e),
}
self
}
pub fn hot_effect_world(&mut self, path: &str) -> &mut Self {
match HotEffectPass::new_world(self.gpu, path) {
Ok(effect) => self.add_node(HotEffectNode::new(effect)),
Err(e) => eprintln!("[hot-reload] Failed to load shader '{}': {}", path, e),
}
self
}
pub fn hot_post_process(&mut self, path: &str) -> &mut Self {
match HotPostProcessPass::new(self.gpu, path) {
Ok(pass) => self.add_node(HotPostProcessNode::new(pass)),
Err(e) => eprintln!("[hot-reload] Failed to load shader '{}': {}", path, e),
}
self
}
pub fn hot_post_process_world(&mut self, path: &str) -> &mut Self {
match HotWorldPostProcessPass::new(self.gpu, path) {
Ok(pass) => self.add_node(HotWorldPostProcessNode::new(pass)),
Err(e) => eprintln!("[hot-reload] Failed to load shader '{}': {}", path, e),
}
self
}
pub fn enable_mesh_rendering(&mut self) -> &mut Self {
let mesh_node = MeshNode::new(self.gpu, Rc::clone(self.mesh_queue));
self.add_node(mesh_node);
self
}
fn add_node<N: crate::render_graph::RenderNode + 'static>(&mut self, node: N) {
if self.graph_builder.is_none() {
*self.graph_builder = Some(RenderGraph::builder().node(node).build(self.gpu));
} else {
let old = self.graph_builder.take().unwrap();
*self.graph_builder = Some(old.with_node(node, self.gpu));
}
}
}