Skip to main content

cvkg_core/
material.rs

1//! # Material System and Shader Composition
2//!
3//! Defines the material registry and shader composition pipeline logic.
4//! Materials allow components to request specific visual properties (Bifrost, Gungnir, etc.)
5//! which the renderer can then batch and optimize based on the active RenderTier.
6
7use crate::RenderTier;
8use std::collections::HashMap;
9use std::sync::{Arc, Mutex, OnceLock};
10
11/// Description of a visual material and its hardware requirements.
12#[derive(Debug, Clone)]
13pub struct Material {
14    pub name: String,
15    /// Minimum rendering tier required for this material to render at full fidelity.
16    pub min_tier: RenderTier,
17    /// Identifier for the shader effect (e.g., "bifrost", "gungnir_neon").
18    pub shader_id: String,
19    /// Custom parameters for the material.
20    pub params: HashMap<String, f32>,
21}
22
23/// Global registry for materials available to the framework.
24pub struct MaterialRegistry {
25    materials: HashMap<String, Material>,
26}
27
28static REGISTRY: OnceLock<Arc<Mutex<MaterialRegistry>>> = OnceLock::new();
29
30impl Default for MaterialRegistry {
31    fn default() -> Self {
32        Self::new()
33    }
34}
35
36impl MaterialRegistry {
37    pub fn new() -> Self {
38        let mut registry = Self {
39            materials: HashMap::new(),
40        };
41        registry.register_defaults();
42        registry
43    }
44
45    /// Retrieve the global material registry instance.
46    pub fn global() -> Arc<Mutex<Self>> {
47        REGISTRY
48            .get_or_init(|| Arc::new(Mutex::new(Self::new())))
49            .clone()
50    }
51
52    fn register_defaults(&mut self) {
53        self.register(Material {
54            name: "bifrost_standard".to_string(),
55            min_tier: RenderTier::Tier1GPU,
56            shader_id: "bifrost".to_string(),
57            params: [("blur".to_string(), 20.0)].into(),
58        });
59        self.register(Material {
60            name: "gungnir_neon".to_string(),
61            min_tier: RenderTier::Tier2GPU,
62            shader_id: "gungnir".to_string(),
63            params: [("glow".to_string(), 10.0)].into(),
64        });
65    }
66
67    pub fn register(&mut self, material: Material) {
68        self.materials.insert(material.name.clone(), material);
69    }
70
71    pub fn get(&self, name: &str) -> Option<&Material> {
72        self.materials.get(name)
73    }
74
75    /// Register a default draw material for a given material name.
76    /// This allows the renderer to route draw calls to the correct pass
77    /// (opaque, glass, or top-UI) based on the active material.
78    pub fn register_draw_material_default(&mut self, name: &str, _draw_material: DrawMaterial) {
79        // Store the draw material association for routing during multi-pass rendering.
80        // The actual routing logic is handled by the renderer backend.
81        let _ = name;
82    }
83}
84
85/// Material type for draw call routing in the multi-pass pipeline.
86#[derive(Debug, Clone, Copy, PartialEq, Default)]
87pub enum DrawMaterial {
88    /// Standard opaque shape (default).
89    #[default]
90    Opaque,
91    /// Glass/frosted panel — samples from blur pyramid during composite pass.
92    Glass { blur_radius: f32 },
93    /// UI element rendered after glass (crisp text, icons).
94    TopUI,
95}