Skip to main content

appcore_render/
scene_storage.rs

1// =============================================================================
2//        #######
3//     ###       ###     F: scene_storage.rs
4//    ##   ## ##   ##    P: AppCore-Runtime
5//         ## ##
6//                       C: 2026/10/14 16:59:22 by dnettoRaw
7//    ##   ## ##   ##    U: 2026/10/15 10:24:40 by dnettoRaw
8//      ###########      S: 0.1.0-alpha.1
9// =============================================================================
10
11use crate::{RenderBinding, RenderError, Transform, Velocity};
12use std::sync::{
13    atomic::{AtomicU32, Ordering},
14    Arc,
15};
16/// Scene-scoped generational identity, stable when a row moves between archetypes.
17#[derive(Debug, Clone, Copy, PartialEq, Eq)]
18pub struct EntityId {
19    pub(crate) owner: u64,
20    pub(crate) index: u32,
21    pub(crate) generation: u64,
22}
23#[derive(Clone, Copy)]
24pub(crate) struct Location {
25    pub(crate) archetype: usize,
26    pub(crate) row: usize,
27}
28pub(crate) struct Slot {
29    pub(crate) generation: u64,
30    pub(crate) location: Option<Location>,
31}
32pub(crate) struct Archetype {
33    pub(crate) entities: Vec<EntityId>,
34    pub(crate) transforms: Vec<Transform>,
35    pub(crate) bindings: Vec<RenderBinding>,
36    pub(crate) velocities: Option<Vec<Velocity>>,
37}
38impl Archetype {
39    pub(crate) fn new(capacity: usize, moving: bool) -> Result<Self, RenderError> {
40        Ok(Self {
41            entities: reserved(capacity)?,
42            transforms: reserved(capacity)?,
43            bindings: reserved(capacity)?,
44            velocities: if moving {
45                Some(reserved(capacity)?)
46            } else {
47                None
48            },
49        })
50    }
51    pub(crate) fn push(
52        &mut self,
53        id: EntityId,
54        transform: Transform,
55        binding: RenderBinding,
56        velocity: Option<Velocity>,
57    ) -> usize {
58        let row = self.entities.len();
59        self.entities.push(id);
60        self.transforms.push(transform);
61        self.bindings.push(binding);
62        if let (Some(column), Some(value)) = (&mut self.velocities, velocity) {
63            column.push(value);
64        }
65        row
66    }
67    pub(crate) fn remove(&mut self, row: usize) -> (Transform, RenderBinding, Option<Velocity>) {
68        self.entities.swap_remove(row);
69        (
70            self.transforms.swap_remove(row),
71            self.bindings.swap_remove(row),
72            self.velocities.as_mut().map(|v| v.swap_remove(row)),
73        )
74    }
75}
76/// Disjoint mutable columns borrowed from the moving archetype; structural changes
77/// cannot occur while this value is borrowed. Component types preserve numeric validity.
78pub struct MovingColumns<'a> {
79    /// Row-aligned stable identities.
80    pub entities: &'a [EntityId],
81    /// Aligned contiguous transforms.
82    pub transforms: &'a mut [Transform],
83    /// Aligned contiguous velocities.
84    pub velocities: &'a mut [Velocity],
85}
86/// Immutable extracted instance; does not borrow the world or resolve its assets.
87#[derive(Debug, Clone, Copy)]
88pub struct SceneInstance {
89    /// Identity at extraction time, not a mutable entity reference.
90    pub entity: EntityId,
91    /// Validated local transform.
92    pub transform: Transform,
93    /// Declared asset/appearance binding.
94    pub binding: RenderBinding,
95}
96/// Owned bounded frame snapshot; world mutations cannot invalidate its storage.
97pub(crate) struct SnapshotPermit(pub(crate) Arc<AtomicU32>);
98impl Drop for SnapshotPermit {
99    fn drop(&mut self) {
100        self.0.fetch_sub(1, Ordering::AcqRel);
101    }
102}
103
104pub struct SceneSnapshot {
105    pub(crate) _permit: SnapshotPermit,
106    pub(crate) instances: Vec<SceneInstance>,
107}
108impl SceneSnapshot {
109    /// Contiguous immutable instances, in archetype order rather than spawn order.
110    pub fn instances(&self) -> &[SceneInstance] {
111        &self.instances
112    }
113}
114
115pub(crate) fn reserved<T>(capacity: usize) -> Result<Vec<T>, RenderError> {
116    let mut values = Vec::new();
117    values
118        .try_reserve_exact(capacity)
119        .map_err(|_| RenderError::CpuAllocationFailed)?;
120    Ok(values)
121}