//! Cyborg is a high-performance, modern, experimental rendering engine written //! in Rust. use std::collections::HashMap; use std::sync::{Arc, RwLock}; use strum::IntoEnumIterator; #[derive(Copy, Clone, Debug, Hash, Eq, Ord, PartialEq, PartialOrd, strum::EnumIter)] pub enum PrePhase {} #[derive(Copy, Clone, Debug, Hash, Eq, Ord, PartialEq, PartialOrd, strum::EnumIter)] pub enum ViewportPhase {} #[derive(Debug, Default)] pub struct PhaseList { pub pre: Vec, pub viewport: Vec, } impl PhaseList { pub fn clear(&mut self) { self.pre.clear(); self.viewport.clear(); } } #[derive(Debug, Default)] pub struct PhaseMultiMap { pub pre: HashMap>, pub viewport: HashMap>, } impl PhaseMultiMap { pub fn insert_multi(&mut self, keys: &PhaseList, val: T) { for pre in keys.pre.iter() { Self::insert(&mut self.pre, pre, val); } for viewport in keys.viewport.iter() { Self::insert(&mut self.viewport, viewport, val); } } pub fn iter_pre<'a>(&'a self, phase: &'a PrePhase) -> std::slice::Iter<'a, T> { Self::iter(&self.pre, phase) } pub fn iter_viewport<'a>(&'a self, phase: &'a ViewportPhase) -> std::slice::Iter<'a, T> { Self::iter(&self.viewport, phase) } fn insert(map: &mut HashMap>, key: &K, val: T) where K: std::hash::Hash + Eq + Copy, { if let Some(existing) = map.get_mut(key) { if !existing.contains(&val) { existing.push(val); } } else { map.insert(*key, vec![val]); } } fn iter<'a, K>(map: &'a HashMap>, key: &'a K) -> std::slice::Iter<'a, T> where K: std::hash::Hash + Eq + Copy, { if let Some(vals) = map.get(key) { vals.iter() } else { [].iter() } } } pub struct ViewportData; pub trait FrameData {} pub trait RenderPass { type FrameData: FrameData; fn create_frame_data(&mut self) -> Self::FrameData; fn begin_frame(&mut self, data: &mut Self::FrameData, phases: &mut PhaseList); fn render_pre( &self, phase: PrePhase, data: &Self::FrameData, cmds: &mut gpu::RenderBundleEncoder, ); fn render_viewport( &self, phase: ViewportPhase, data: &Self::FrameData, viewport: &ViewportData, cmds: &mut gpu::RenderBundleEncoder, ); } pub struct Renderer { pub render_passes: Vec>, } impl Renderer { pub fn render(&mut self) { let frame_index = 0; let mut phase_passes = PhaseMultiMap::::default(); let mut phases_buf = PhaseList::default(); for (pass_index, rp) in self.render_passes.iter_mut().enumerate() { phases_buf.clear(); rp.begin_frame(frame_index, &mut phases_buf); phase_passes.insert_multi(&phases_buf, pass_index); } for phase in PrePhase::iter() { for pass_index in phase_passes.iter_pre(&phase) { let pass = &self.render_passes[*pass_index]; let mut encoder = gpu::RenderBundleEncoder; pass.render_pre(phase, frame_index, &mut encoder); } } let viewport = ViewportData; for phase in ViewportPhase::iter() { for pass_index in phase_passes.iter_viewport(&phase) { let pass = &self.render_passes[*pass_index]; let mut encoder = gpu::RenderBundleEncoder; pass.render_viewport(phase, frame_index, &viewport, &mut encoder); } } } } pub trait RenderPassBoxTrait { fn begin_frame(&mut self, data_index: usize, phases: &mut PhaseList); fn render_pre(&self, phase: PrePhase, data_index: usize, cmds: &mut gpu::RenderBundleEncoder); fn render_viewport( &self, phase: ViewportPhase, data_index: usize, viewport: &ViewportData, cmds: &mut gpu::RenderBundleEncoder, ); } pub struct RenderPassBox { render_pass: Arc>, frame_data: Vec, } impl RenderPassBox { pub fn new(render_pass: Arc>, frame_num: usize) -> Self { let frame_data = { let mut lock = render_pass.write().unwrap(); (0..frame_num).map(|_| lock.create_frame_data()).collect() }; Self { render_pass, frame_data, } } } impl RenderPassBoxTrait for RenderPassBox { fn begin_frame(&mut self, data_index: usize, phases: &mut PhaseList) { let frame_data = &mut self.frame_data[data_index]; let mut render_pass = self.render_pass.write().unwrap(); render_pass.begin_frame(frame_data, phases) } fn render_pre(&self, phase: PrePhase, data_index: usize, cmds: &mut gpu::RenderBundleEncoder) { let frame_data = &self.frame_data[data_index]; let render_pass = self.render_pass.read().unwrap(); render_pass.render_pre(phase, frame_data, cmds) } fn render_viewport( &self, phase: ViewportPhase, data_index: usize, viewport: &ViewportData, cmds: &mut gpu::RenderBundleEncoder, ) { let frame_data = &self.frame_data[data_index]; let render_pass = self.render_pass.read().unwrap(); render_pass.render_viewport(phase, frame_data, viewport, cmds) } } /// Mock GPU API (like Vulkan, WebGPU, or OpenGL) types for prototyping. pub mod gpu { /// Thread-safe GPU command recorder that's later executed in a command buffer. /// /// Also known as a: /// - RenderBundleEncoder in WebGPU /// - secondary command buffer in Vulkan pub struct RenderBundleEncoder; }