scena 1.7.1

A Rust-native scene-graph renderer with typed scene state, glTF assets, and explicit prepare/render lifecycles.
Documentation
use crate::assets::Assets;
use crate::diagnostics::{
    CapabilityReport, Diagnostic, DiagnosticCode, PostProcessingDepthSourceV1,
    PostProcessingPassV1, PostProcessingReportV1, RendererStats,
};
use crate::scene::Scene;

use super::{Renderer, prepare};

impl Renderer {
    pub fn capability_report(&self) -> CapabilityReport {
        CapabilityReport::new_with_post_processing(
            self.capabilities,
            self.gpu_adapter_report(),
            self.post_processing_report(),
        )
    }

    pub fn diagnose_scene(&self, scene: &Scene) -> Vec<Diagnostic> {
        let mut diagnostics = Vec::new();
        if scene.active_camera().is_none() {
            diagnostics.push(Diagnostic::error(
                DiagnosticCode::MissingActiveCamera,
                "scene has no active camera",
                "call Scene::add_default_camera or Scene::set_active_camera before rendering",
            ));
        }
        diagnostics.extend(prepare::collect_camera_projection_diagnostics(scene));
        diagnostics.extend(prepare::collect_camera_visibility_diagnostics(
            scene,
            self.target,
        ));

        if scene.visible_drawable_count() == 0 {
            diagnostics.push(Diagnostic::warning(
                DiagnosticCode::InvisibleScene,
                "scene has no visible drawables for the active camera",
                "check node visibility, parent visibility, camera layer masks, or add a mesh/renderable node",
            ));
        }

        if scene.light_nodes().count() == 0 && self.environment.is_none() {
            diagnostics.push(Diagnostic::warning(
                DiagnosticCode::MissingLightingOrEnvironment,
                "scene has no active light nodes and no renderer environment",
                "call renderer.set_environment for image-based lighting or add a scene light for lit materials",
            ));
        }

        diagnostics
    }

    pub fn diagnose_scene_with_assets<F>(
        &self,
        scene: &Scene,
        assets: &Assets<F>,
    ) -> Vec<Diagnostic> {
        let mut diagnostics = self.diagnose_scene(scene);
        diagnostics.extend(prepare::collect_asset_camera_visibility_diagnostics(
            scene,
            self.target,
            assets,
        ));
        diagnostics.extend(prepare::collect_material_texture_diagnostics(scene, assets));
        diagnostics
    }

    pub fn stats(&self) -> RendererStats {
        self.stats
    }

    pub fn diagnostics(&self) -> &[Diagnostic] {
        &self.diagnostics
    }

    fn post_processing_report(&self) -> PostProcessingReportV1 {
        let anti_aliasing = matches!(self.anti_aliasing, super::AntiAliasing::Fxaa);
        let bloom = self.bloom.is_some();
        let screen_space_ambient_occlusion = self.screen_space_ambient_occlusion.is_some();
        let mut active_passes = Vec::new();
        if screen_space_ambient_occlusion {
            active_passes.push(PostProcessingPassV1::ScreenSpaceAmbientOcclusion);
        }
        if bloom {
            active_passes.push(PostProcessingPassV1::Bloom);
        }
        if anti_aliasing {
            active_passes.push(PostProcessingPassV1::Fxaa);
        }
        PostProcessingReportV1 {
            active_passes,
            anti_aliasing,
            bloom,
            screen_space_ambient_occlusion,
            ssao_depth_source: screen_space_ambient_occlusion.then(|| {
                if self.gpu.is_some() {
                    PostProcessingDepthSourceV1::DepthColorTarget
                } else {
                    PostProcessingDepthSourceV1::CpuDepthFrame
                }
            }),
        }
    }
}