nightshade 0.32.0

A cross-platform data-oriented game engine.
Documentation
//! Built-in render passes for the default pipeline.
//!
//! These passes implement [`PassNode`](super::rendergraph::PassNode) and can be used
//! directly or as references for custom pass implementations.
//!
//! # Geometry Passes
//!
//! | Pass | Description |
//! |------|-------------|
//! | [`MeshPass`] | Static mesh rendering with lighting |
//! | [`SkinnedMeshPass`] | Animated skeletal mesh rendering |
//! | [`DecalPass`] | Projected decal rendering |
//! | [`ParticlePass`] | GPU particle billboard rendering |
//! | [`ClothPass`] | GPU cloth simulation and rendering |
//! | [`TextPass`] | 3D text rendering |
//! | [`LinesPass`] | Debug line rendering |
//! | [`GridPass`] | Infinite ground grid |
//! | [`SkyPass`] | Procedural sky/atmosphere |
//! | [`UiPass`] | UI rectangle + text rendering (batched) |
//!
//! # Shadow Passes
//!
//! | Pass | Description |
//! |------|-------------|
//! | [`ShadowDepthPass`] | Cascaded shadow map generation |
//!
//! Shadow mapping uses 4 cascades (`NUM_SHADOW_CASCADES`) for directional lights.
//!
//! # Post-Processing Passes
//!
//! | Pass | Description |
//! |------|-------------|
//! | [`PostProcessPass`] | Final compositing with tonemapping |
//! | [`BloomPass`] | HDR bloom effect |
//! | [`SsaoPass`] | Screen-space ambient occlusion |
//! | [`SsaoBlurPass`] | SSAO blur for soft shadows |
//! | [`SsgiPass`] | Screen-space global illumination |
//! | [`SsgiBlurPass`] | SSGI bilateral blur |
//! | [`DepthOfFieldPass`] | Bokeh depth of field |
//! | [`OutlinePass`] | Selection outline rendering |
//! | [`SelectionMaskPass`] | Selection mask generation |
//! | [`BlitPass`] | Simple texture copy |
//!
//! # Using Built-in Passes
//!
//! ```ignore
//! fn configure_render_graph(
//!     &mut self,
//!     graph: &mut RenderGraph<World>,
//!     device: &wgpu::Device,
//!     surface_format: wgpu::TextureFormat,
//!     resources: RenderResources,
//! ) {
//!     // Add bloom post-processing
//!     let bloom = BloomPass::new(device, width, height);
//!     render_graph_pass(graph, Box::new(bloom))
//!         .read("hdr", resources.scene_color)
//!         .write("bloom", bloom_texture);
//!
//!     // Add SSAO
//!     let ssao = SsaoPass::new(device);
//!     render_graph_pass(graph, Box::new(ssao))
//!         .read("depth", resources.depth)
//!         .read("view_normals", resources.view_normals)
//!         .write("ssao_raw", ssao_raw);
//!
//!     let ssao_blur = SsaoBlurPass::new(device);
//!     render_graph_pass(graph, Box::new(ssao_blur))
//!         .read("ssao_raw", ssao_raw)
//!         .read("depth", resources.depth)
//!         .read("view_normals", resources.view_normals)
//!         .write("ssao", ssao_final);
//!
//!     // Final post-process with tonemapping
//!     let postprocess = PostProcessPass::new(device, surface_format, bloom_intensity);
//!     render_graph_pass(graph, Box::new(postprocess))
//!         .read("hdr", resources.scene_color)
//!         .read("bloom", bloom_texture)
//!         .read("ssao", ssao_final)
//!         .write("output", resources.swapchain);
//! }
//! ```
//!
//! # Pass Configuration
//!
//! Most passes accept configuration in their constructors:
//!
//! ```ignore
//! // Bloom with custom mip levels
//! let bloom = BloomPass::new(device, width, height);
//!
//! // SSAO (tuned at runtime via world.resources.render_settings.ssao_*)
//! let ssao = SsaoPass::new(device);
//!
//! // Post-process with bloom intensity
//! let postprocess = PostProcessPass::new(device, format, 0.3);  // 30% bloom
//! ```

pub mod setup;
pub use setup::{ClearPass, PickKeepalivePass};

pub mod geometry;
pub use geometry::{
    ClothPass, DecalPass, GridPass, LinesPass, MeshPass, ParticlePass, SkinnedMeshPass, SkyPass,
    TextPass, UiImage, UiImagePass, UiPass, UiRect, sync_bounding_volume_data, sync_lines_data,
    sync_normal_data,
};

pub mod shadow_depth;
pub use shadow_depth::{
    CASCADE_ATLAS_SIZE, CASCADE_SLOT_RESOLUTION, NUM_SHADOW_CASCADES, ShadowDepthPass,
    SpotlightShadowData, SpotlightShadowSlot,
};

pub mod postprocess;
pub use postprocess::{
    BlitPass, BloomPass, DepthOfFieldPass, EffectsPass, FxaaPass, PostProcessPass, SsaoBlurPass,
    SsaoPass, SsgiBlurPass, SsgiPass, SsrBlurPass, SsrPass, ViewportComposePass,
};
#[cfg(feature = "debug_render")]
pub use postprocess::{OutlinePass, SelectionMaskPass};

/// Grows a storage buffer to hold at least `required` elements of `T`, doubling
/// the capacity so reallocation amortizes. Returns `true` when the buffer was
/// recreated, so the caller can rebuild any bind groups that referenced the old
/// buffer. No-op (returns `false`) while the current capacity already fits.
pub(crate) fn grow_storage_buffer<T>(
    device: &wgpu::Device,
    buffer: &mut wgpu::Buffer,
    capacity: &mut usize,
    required: usize,
    usage: wgpu::BufferUsages,
    label: &str,
) -> bool {
    if required <= *capacity {
        return false;
    }
    let new_capacity = (required as f32 * 2.0).ceil() as usize;
    *buffer = device.create_buffer(&wgpu::BufferDescriptor {
        label: Some(label),
        size: (std::mem::size_of::<T>() * new_capacity) as u64,
        usage,
        mapped_at_creation: false,
    });
    *capacity = new_capacity;
    true
}