rustial-engine 0.0.1

Framework-agnostic 2.5D map engine for rustial
Documentation
//! Layer system for the map engine.

mod background_layer;
mod dynamic_image_overlay_layer;
mod hillshade_layer;
mod image_overlay_layer;
mod model_layer;
mod tile_layer;
mod vector_layer;

pub use background_layer::BackgroundLayer;
pub use dynamic_image_overlay_layer::{
    CallbackFrameProvider, DynamicImageOverlayLayer, FrameData, FrameProvider, FrameProviderFactory,
};
pub use hillshade_layer::{HillshadeLayer, HillshadeParams};
pub use image_overlay_layer::{ImageOverlayData, ImageOverlayLayer};
pub use model_layer::ModelLayer;
pub use tile_layer::TileLayer;
pub use vector_layer::{
    CircleInstanceData, FeatureProvenance, LineCap, LineJoin, PatternImage, VectorLayer,
    VectorMeshData, VectorRenderMode, VectorStyle,
};

/// An ordered stack of map layers, rendered bottom-to-top.
pub struct LayerStack {
    layers: Vec<Box<dyn crate::layer::Layer>>,
}

impl LayerStack {
    /// Create an empty layer stack.
    pub fn new() -> Self {
        Self { layers: Vec::new() }
    }

    /// Create a layer stack from an existing vector of layers.
    pub fn from_vec(layers: Vec<Box<dyn crate::layer::Layer>>) -> Self {
        Self { layers }
    }

    /// Add a layer on top of the stack.
    pub fn push(&mut self, layer: Box<dyn crate::layer::Layer>) {
        self.layers.push(layer);
    }

    /// Insert a layer at a specific index (0 = bottom).
    pub fn insert(&mut self, index: usize, layer: Box<dyn crate::layer::Layer>) {
        let idx = index.min(self.layers.len());
        self.layers.insert(idx, layer);
    }

    /// Remove a layer by index. Returns it if valid.
    pub fn remove(&mut self, index: usize) -> Option<Box<dyn crate::layer::Layer>> {
        if index < self.layers.len() {
            Some(self.layers.remove(index))
        } else {
            None
        }
    }

    /// Remove a layer by name. Returns it if found.
    pub fn remove_by_name(&mut self, name: &str) -> Option<Box<dyn crate::layer::Layer>> {
        if let Some(idx) = self.layers.iter().position(|l| l.name() == name) {
            Some(self.layers.remove(idx))
        } else {
            None
        }
    }

    /// Move a layer up (toward the top of the stack / rendered last).
    ///
    /// Returns `true` if the layer was moved.
    pub fn move_up(&mut self, index: usize) -> bool {
        if index + 1 < self.layers.len() {
            self.layers.swap(index, index + 1);
            true
        } else {
            false
        }
    }

    /// Move a layer down (toward the bottom of the stack / rendered first).
    ///
    /// Returns `true` if the layer was moved.
    pub fn move_down(&mut self, index: usize) -> bool {
        if index > 0 && index < self.layers.len() {
            self.layers.swap(index, index - 1);
            true
        } else {
            false
        }
    }

    /// Find a layer by name and return its index.
    pub fn index_of(&self, name: &str) -> Option<usize> {
        self.layers.iter().position(|l| l.name() == name)
    }

    /// Get a layer by index.
    pub fn get(&self, index: usize) -> Option<&dyn crate::layer::Layer> {
        self.layers.get(index).map(|l| l.as_ref())
    }

    /// Get a layer mutably by index.
    pub fn get_mut(&mut self, index: usize) -> Option<&mut Box<dyn crate::layer::Layer>> {
        self.layers.get_mut(index)
    }

    /// Number of layers.
    pub fn len(&self) -> usize {
        self.layers.len()
    }

    /// Whether there are no layers.
    pub fn is_empty(&self) -> bool {
        self.layers.is_empty()
    }

    /// Iterate layers bottom-to-top.
    pub fn iter(&self) -> impl Iterator<Item = &dyn crate::layer::Layer> + '_ {
        self.layers.iter().map(|l| l.as_ref())
    }

    /// Iterate layers mutably.
    pub fn iter_mut(&mut self) -> std::slice::IterMut<'_, Box<dyn crate::layer::Layer>> {
        self.layers.iter_mut()
    }
}

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