proof-engine 0.2.1

Real-time graphics from math: glyphs and particles moved by ODEs, strange attractors and force fields, drawn with HDR bloom on OpenGL.
Documentation

// ── Render Feature Flags ──────────────────────────────────────────────────────

#[derive(Clone, Debug)]
pub struct RenderFeatureFlags {
    pub pbr: bool,
    pub shadows: bool,
    pub ssao: bool,
    pub ssr: bool,
    pub bloom: bool,
    pub fxaa: bool,
    pub taa: bool,
    pub dof: bool,
    pub motion_blur: bool,
    pub volumetric_fog: bool,
    pub lens_flare: bool,
    pub chromatic_aberration: bool,
    pub vignette: bool,
    pub color_grading: bool,
    pub debug_mode: bool,
}

impl RenderFeatureFlags {
    pub fn all_off() -> Self { Self { pbr: false, shadows: false, ssao: false, ssr: false, bloom: false, fxaa: false, taa: false, dof: false, motion_blur: false, volumetric_fog: false, lens_flare: false, chromatic_aberration: false, vignette: false, color_grading: false, debug_mode: false } }
    pub fn default_high_quality() -> Self { Self { pbr: true, shadows: true, ssao: true, ssr: false, bloom: true, fxaa: true, taa: true, dof: false, motion_blur: false, volumetric_fog: false, lens_flare: false, chromatic_aberration: false, vignette: true, color_grading: true, debug_mode: false } }
    pub fn default_medium_quality() -> Self { Self { pbr: true, shadows: true, ssao: false, ssr: false, bloom: true, fxaa: true, taa: false, ..Self::all_off() } }
    pub fn default_low_quality() -> Self { Self { fxaa: true, ..Self::all_off() } }
    pub fn active_count(&self) -> usize {
        [self.pbr, self.shadows, self.ssao, self.ssr, self.bloom, self.fxaa, self.taa, self.dof, self.motion_blur, self.volumetric_fog, self.lens_flare, self.chromatic_aberration, self.vignette, self.color_grading].iter().filter(|&&b| b).count()
    }
    pub fn generate_defines(&self) -> Vec<(String, String)> {
        let mut defines = Vec::new();
        if self.pbr { defines.push(("USE_PBR".into(), "1".into())); }
        if self.shadows { defines.push(("USE_SHADOWS".into(), "1".into())); }
        if self.ssao { defines.push(("USE_SSAO".into(), "1".into())); }
        if self.bloom { defines.push(("USE_BLOOM".into(), "1".into())); }
        if self.fxaa { defines.push(("USE_FXAA".into(), "1".into())); }
        if self.taa { defines.push(("USE_TAA".into(), "1".into())); }
        defines
    }
}

impl Default for RenderFeatureFlags {
    fn default() -> Self { Self::default_high_quality() }
}

// ── Shader compilation context ────────────────────────────────────────────────

#[derive(Clone, Debug)]
pub struct ShaderCompilationContext {
    pub source_path: String,
    pub stage: ShaderStage,
    pub target: CodeGenTarget,
    pub defines: HashMap<String, String>,
    pub include_paths: Vec<String>,
    pub optimization: OptimizationLevel,
    pub version: String,
    pub entry_point: String,
    pub features: RenderFeatureFlags,
}

impl ShaderCompilationContext {
    pub fn new(path: impl Into<String>, stage: ShaderStage, target: CodeGenTarget) -> Self {
        Self { source_path: path.into(), stage, target, defines: HashMap::new(), include_paths: Vec::new(), optimization: OptimizationLevel::Medium, version: "450".into(), entry_point: "main".into(), features: RenderFeatureFlags::default() }
    }
    pub fn add_define(&mut self, k: impl Into<String>, v: impl Into<String>) { self.defines.insert(k.into(), v.into()); }
    pub fn apply_features(&mut self) {
        for (k, v) in self.features.generate_defines() { self.defines.insert(k, v); }
    }
    pub fn is_vertex(&self) -> bool { self.stage == ShaderStage::Vertex }
    pub fn is_fragment(&self) -> bool { self.stage == ShaderStage::Fragment }
    pub fn is_compute(&self) -> bool { self.stage == ShaderStage::Compute }
}

// ── Shader bundle ─────────────────────────────────────────────────────────────

#[derive(Clone, Debug)]
pub struct ShaderBundle {
    pub id: u32,
    pub name: String,
    pub programs: Vec<ShaderProgram>,
    pub materials: Vec<Material>,
    pub templates: Vec<ShaderTemplate>,
    pub version: u32,
    pub description: String,
    pub author: String,
    pub created_at: u64,
}

impl ShaderBundle {
    pub fn new(id: u32, name: impl Into<String>) -> Self {
        Self { id, name: name.into(), programs: Vec::new(), materials: Vec::new(), templates: Vec::new(), version: 1, description: String::new(), author: String::new(), created_at: 0 }
    }
    pub fn add_program(&mut self, p: ShaderProgram) { self.programs.push(p); }
    pub fn add_material(&mut self, m: Material) { self.materials.push(m); }
    pub fn add_template(&mut self, t: ShaderTemplate) { self.templates.push(t); }
    pub fn program_count(&self) -> usize { self.programs.len() }
    pub fn material_count(&self) -> usize { self.materials.len() }
    pub fn find_program(&self, name: &str) -> Option<&ShaderProgram> { self.programs.iter().find(|p| p.name == name) }
    pub fn is_empty(&self) -> bool { self.programs.is_empty() && self.materials.is_empty() }
}

#[derive(Clone, Debug)]
pub struct ShaderBundleRegistry {
    pub bundles: HashMap<u32, ShaderBundle>,
    pub next_id: u32,
}

impl ShaderBundleRegistry {
    pub fn new() -> Self { Self { bundles: HashMap::new(), next_id: 1 } }
    pub fn register(&mut self, mut b: ShaderBundle) -> u32 {
        let id = self.next_id; self.next_id += 1;
        b.id = id;
        self.bundles.insert(id, b);
        id
    }
    pub fn get(&self, id: u32) -> Option<&ShaderBundle> { self.bundles.get(&id) }
    pub fn find_by_name(&self, name: &str) -> Option<&ShaderBundle> { self.bundles.values().find(|b| b.name == name) }
    pub fn total_programs(&self) -> usize { self.bundles.values().map(|b| b.program_count()).sum() }
    pub fn count(&self) -> usize { self.bundles.len() }
}

impl Default for ShaderBundleRegistry {
    fn default() -> Self { Self::new() }
}

// ── Shader Workspace ──────────────────────────────────────────────────────────

#[derive(Clone, Debug)]
pub struct ShaderWorkspace {
    pub registry: ShaderProgramRegistry,
    pub cache: ShaderCache,
    pub library: ShaderLibrary,
    pub material_lib: MaterialLibrary,
    pub texture_reg: TextureRegistry,
    pub buffer_reg: BufferRegistry,
    pub pipeline: RenderPipeline,
    pub post_process: PostProcessStack,
    pub template_lib: ShaderTemplateLibrary,
    pub linter: ShaderLinter,
    pub formatter: ShaderFormatter,
    pub debugger: ShaderDebugger,
    pub profiler: ShaderProfiler,
    pub hot_reload: HotReloadManager,
    pub editor_state: ShaderEditorState,
    pub autocomplete: AutoCompleteProvider,
    pub linker: ShaderLinker,
    pub bundle_reg: ShaderBundleRegistry,
    pub feature_flags: RenderFeatureFlags,
    pub memory_budget: GpuMemoryBudget,
    pub render_stats: RenderStatistics,
}

impl ShaderWorkspace {
    pub fn new() -> Self {
        Self {
            registry: ShaderProgramRegistry::new(),
            cache: ShaderCache::new(SHADER_CACHE_SIZE),
            library: ShaderLibrary::build_standard(),
            material_lib: MaterialLibrary::new(),
            texture_reg: TextureRegistry::new(),
            buffer_reg: BufferRegistry::new(),
            pipeline: RenderPipeline::new(),
            post_process: PostProcessStack::new(),
            template_lib: ShaderTemplateLibrary::new(),
            linter: ShaderLinter::new(),
            formatter: ShaderFormatter::new(),
            debugger: ShaderDebugger::build_defaults(),
            profiler: ShaderProfiler::new(),
            hot_reload: HotReloadManager::new(),
            editor_state: ShaderEditorState::new(),
            autocomplete: AutoCompleteProvider::new(),
            linker: ShaderLinker::new(),
            bundle_reg: ShaderBundleRegistry::new(),
            feature_flags: RenderFeatureFlags::default(),
            memory_budget: GpuMemoryBudget::new(GPU_MEMORY_BUDGET_DEFAULT_MB * 1024 * 1024),
            render_stats: RenderStatistics::new(),
        }
    }
    pub fn program_count(&self) -> usize { self.registry.count() }
    pub fn material_count(&self) -> usize { self.material_lib.count() }
    pub fn texture_count(&self) -> usize { self.texture_reg.count() }
    pub fn buffer_count(&self) -> usize { self.buffer_reg.count() }
    pub fn begin_frame(&mut self) { self.render_stats.begin_frame(); self.profiler.begin_frame(); }
    pub fn has_program(&self, name: &str) -> bool { self.registry.find_by_name(name).is_some() }
    pub fn tick(&mut self, dt: f32) { let _ = self.hot_reload.tick(dt); }
}

impl Default for ShaderWorkspace {
    fn default() -> Self { Self::new() }
}

// ── Final constants ───────────────────────────────────────────────────────────

pub const SHADER_BUNDLE_MAX: usize = 64;
pub const SHADER_WORKSPACE_MAX_PROGRAMS: usize = SHADER_MAX_PROGRAMS;
pub const RENDER_FEATURE_COUNT: usize = 15;
pub const SHADER_VERSION_DEFAULT: &str = "450";
pub const SHADER_ES_VERSION_DEFAULT: &str = "300 es";
pub const SHADER_ENTRY_POINT_DEFAULT: &str = "main";
pub const GLSL_BUILTIN_TYPE_COUNT: usize = 40;
pub const GLSL_KEYWORD_COUNT: usize = 31;
pub const GLSL_MAX_FRAGMENT_OUTPUTS: u32 = 8;
pub const GLSL_MAX_VERTEX_ATTRIBS: u32 = 32;

pub fn build_standard_shader_workspace() -> ShaderWorkspace { ShaderWorkspace::new() }
pub fn shader_workspace_summary(ws: &ShaderWorkspace) -> String {
    format!("ShaderWorkspace: {} programs, {} materials, {} textures, {} buffers, {} render passes", ws.program_count(), ws.material_count(), ws.texture_count(), ws.buffer_count(), ws.pipeline.pass_count())
}
pub fn shader_system_version() -> &'static str { "1.0.0" }
pub fn is_shader_system_ready() -> bool { true }