rdpe/
lib.rs

1//! # RDPE - Reaction Diffusion Particle Engine
2//!
3//! GPU-accelerated particle simulations with a simple, declarative API.
4//!
5//! RDPE handles all the GPU complexity (buffers, shaders, spatial hashing) so you can
6//! focus on defining particle behavior through composable rules.
7//!
8//! ## Quick Start
9//!
10//! ```ignore
11//! use rdpe::prelude::*;
12//!
13//! #[derive(Particle, Clone)]
14//! struct Ball {
15//!     position: Vec3,
16//!     velocity: Vec3,
17//! }
18//!
19//! fn main() {
20//!     Simulation::<Ball>::new()
21//!         .with_particle_count(10_000)
22//!         .with_bounds(1.0)
23//!         .with_spawner(|i, _| Ball {
24//!             position: Vec3::new(0.0, 0.5, 0.0),
25//!             velocity: Vec3::ZERO,
26//!         })
27//!         .with_rule(Rule::Gravity(9.8))
28//!         .with_rule(Rule::BounceWalls { restitution: 1.0 })
29//!         .run();
30//! }
31//! ```
32//!
33//! ## Core Concepts
34//!
35//! ### Particles
36//!
37//! Define your particle struct with `#[derive(Particle)]`. Required fields:
38//! - `position: Vec3` - particle position in 3D space
39//! - `velocity: Vec3` - particle velocity
40//!
41//! Optional fields:
42//! - `#[color] color: Vec3` - custom particle color (RGB, 0.0-1.0)
43//! - `particle_type: u32` - for typed interactions (auto-added if not present)
44//! - Any other `f32`, `u32`, `i32`, `Vec2`, `Vec3`, `Vec4` fields
45//!
46//! ### Rules
47//!
48//! Rules define particle behavior. They execute every frame in order:
49//!
50//! ```ignore
51//! .with_rule(Rule::Gravity(9.8))        // Apply forces
52//! .with_rule(Rule::Separate { ... })    // Neighbor interactions
53//! .with_rule(Rule::SpeedLimit { ... })  // Constrain velocity
54//! .with_rule(Rule::Drag(1.0))           // Apply friction
55//! .with_rule(Rule::BounceWalls { restitution: 1.0 })         // Boundary conditions
56//! ```
57//!
58//! ### Typed Interactions
59//!
60//! Use [`ParticleType`] derive for type-safe particle categories:
61//!
62//! ```ignore
63//! #[derive(ParticleType, Clone, Copy, PartialEq)]
64//! enum Species {
65//!     Prey,
66//!     Predator,
67//! }
68//!
69//! // Predators chase prey
70//! Rule::Chase {
71//!     self_type: Species::Predator.into(),
72//!     target_type: Species::Prey.into(),
73//!     radius: 0.3,
74//!     strength: 2.0,
75//! }
76//! ```
77//!
78//! ## Spatial Hashing
79//!
80//! Neighbor-based rules (Separate, Cohere, Align, etc.) use spatial hashing
81//! for efficient neighbor queries. Configure with:
82//!
83//! ```ignore
84//! .with_spatial_config(cell_size, grid_resolution)
85//! ```
86//!
87//! - `cell_size` should be >= your largest interaction radius
88//! - `grid_resolution` must be a power of 2 (16, 32, 64)
89//!
90//! ## Feature Overview
91//!
92//! | Category | Rules |
93//! |----------|-------|
94//! | Physics | [`Rule::Gravity`], [`Rule::Drag`], [`Rule::Acceleration`] |
95//! | Boundaries | [`Rule::BounceWalls`], [`Rule::WrapWalls`] |
96//! | Forces | [`Rule::AttractTo`], [`Rule::RepelFrom`] |
97//! | Movement | [`Rule::Wander`], [`Rule::SpeedLimit`] |
98//! | Flocking | [`Rule::Separate`], [`Rule::Cohere`], [`Rule::Align`] |
99//! | Collision | [`Rule::Collide`] |
100//! | Types | [`Rule::Typed`], [`Rule::Convert`], [`Rule::Chase`], [`Rule::Evade`] |
101//! | Custom | [`Rule::Custom`] for raw WGSL |
102
103mod emitter;
104pub mod error;
105pub mod field;
106mod gpu;
107pub mod input;
108mod interactions;
109pub mod lifecycle;
110pub mod rules;
111pub mod shader_utils;
112mod simulation;
113mod spawn;
114mod spatial;
115pub mod sub_emitter;
116pub mod textures;
117pub mod time;
118mod uniforms;
119pub mod visuals;
120pub mod selection;
121
122pub use bytemuck;
123pub use emitter::Emitter;
124pub use error::{GpuError, SimulationError, TextureError};
125pub use field::{FieldConfig, FieldRegistry, FieldType};
126pub use glam::{Vec2, Vec3, Vec4};
127pub use gpu::GlyphRenderer;
128pub use gpu::VolumeConfig;
129pub use gpu::VolumeRenderState;
130pub use gpu::{FieldSystemGpu, create_particle_field_bind_group_layout};
131pub use interactions::InteractionMatrix;
132pub use lifecycle::Lifecycle;
133pub use rdpe_derive::{MultiParticle, Particle, ParticleType};
134pub use rules::{AgentState, CustomRuleBuilder, Falloff, Rule, Transition};
135pub use simulation::Simulation;
136pub use spawn::SpawnContext;
137pub use sub_emitter::{SpawnTrigger, SubEmitter};
138pub use textures::{AddressMode, FilterMode, TextureConfig, TextureRegistry};
139pub use uniforms::{CustomUniforms, UniformValue, UpdateContext};
140pub use visuals::{BlendMode, ColorMapping, ConfigDiff, GlyphColorMode, GlyphConfig, GlyphMode, HotSwapChange, Palette, ParticleShape, VertexEffect, VisualConfig, WireframeMesh};
141pub use gpu::{AdjacencyGpu, SpatialGpu, SpatialGridViz};
142pub use spatial::{AdjacencyConfig, SpatialConfig};
143
144/// Trait automatically implemented by `#[derive(Particle)]`.
145///
146/// This trait bridges your Rust particle struct to GPU-compatible memory layout.
147/// The derive macro generates:
148/// - A companion `{Name}Gpu` struct with proper alignment/padding
149/// - WGSL struct definition for compute shaders
150/// - Conversion between Rust and GPU representations
151///
152/// # Do Not Implement Manually
153///
154/// This trait should only be derived, never implemented by hand.
155/// The derive macro handles complex GPU memory layout requirements.
156///
157/// # Example
158///
159/// ```ignore
160/// #[derive(Particle, Clone)]
161/// struct MyParticle {
162///     position: Vec3,           // Required
163///     velocity: Vec3,           // Required
164///     #[color]
165///     color: Vec3,              // Optional: custom color
166///     particle_type: u32,       // Optional: for typed rules
167///     energy: f32,              // Optional: custom data
168/// }
169/// ```
170pub trait ParticleTrait: Clone + Send + Sync {
171    /// GPU-compatible representation with proper memory alignment.
172    ///
173    /// Generated automatically by the derive macro. Includes padding
174    /// fields to satisfy WGSL alignment requirements (vec3 → 16-byte aligned).
175    type Gpu: Copy + Clone + bytemuck::Pod + bytemuck::Zeroable + Send + Sync;
176
177    /// WGSL struct definition for use in compute shaders.
178    ///
179    /// Generated to match the GPU struct layout exactly.
180    const WGSL_STRUCT: &'static str;
181
182    /// Name of the field marked with `#[color]`, if any.
183    ///
184    /// Used by the renderer to determine which field contains particle color.
185    /// If `None`, particles are colored based on position.
186    const COLOR_FIELD: Option<&'static str>;
187
188    /// Byte offset of the color field within the GPU struct.
189    ///
190    /// Used to configure vertex attributes for rendering.
191    const COLOR_OFFSET: Option<u32>;
192
193    /// Byte offset of the `alive` field within the GPU struct.
194    ///
195    /// Used to configure vertex attributes for culling dead particles.
196    /// Always present since lifecycle fields are auto-injected.
197    const ALIVE_OFFSET: u32;
198
199    /// Byte offset of the `scale` field within the GPU struct.
200    ///
201    /// Used to configure vertex attributes for particle sizing.
202    /// Always present since lifecycle fields are auto-injected.
203    const SCALE_OFFSET: u32;
204
205    /// Additional WGSL code prepended to shaders.
206    ///
207    /// Used by `MultiParticle` enums to inject type constants and helper functions.
208    /// Regular particle structs leave this empty.
209    ///
210    /// Example for a multi-particle enum:
211    /// ```wgsl
212    /// const BOID: u32 = 0u;
213    /// const PREDATOR: u32 = 1u;
214    /// fn is_boid(p: Particle) -> bool { return p.particle_type == BOID; }
215    /// ```
216    const EXTRA_WGSL: &'static str = "";
217
218    /// Convert this particle to its GPU representation.
219    ///
220    /// Called once per particle during initialization.
221    fn to_gpu(&self) -> Self::Gpu;
222
223    /// Convert from GPU representation back to this particle type.
224    ///
225    /// Used for CPU readback of particle data (e.g., for inspection).
226    fn from_gpu(gpu: &Self::Gpu) -> Self;
227
228    /// Get field names and their display values for inspection.
229    ///
230    /// Returns a vector of (field_name, formatted_value) pairs for all
231    /// user-defined fields in the particle struct. Used by the built-in
232    /// particle inspector panel.
233    ///
234    /// This is automatically generated by the derive macro and should not
235    /// be implemented manually.
236    fn inspect_fields(&self) -> Vec<(&'static str, String)>;
237
238    /// Render editable UI widgets for all particle fields.
239    ///
240    /// Returns `true` if any field was modified. Used by the built-in
241    /// particle inspector to allow live editing of particle values.
242    ///
243    /// This is automatically generated by the derive macro and should not
244    /// be implemented manually.
245    #[cfg(feature = "egui")]
246    fn render_editable_fields(&mut self, ui: &mut egui::Ui) -> bool;
247}
248
249/// Convenient re-exports for common usage.
250///
251/// # Usage
252///
253/// ```ignore
254/// use rdpe::prelude::*;
255/// ```
256///
257/// This imports:
258/// - [`Simulation`] - the simulation builder
259/// - [`Rule`] - all available rules
260/// - [`Emitter`] - particle emitters
261/// - [`Particle`] - derive macro for particle structs
262/// - [`ParticleType`] - derive macro for type enums
263/// - [`Vec2`], [`Vec3`], [`Vec4`] - glam vector types
264/// - [`ParticleTrait`] - the particle trait (rarely needed directly)
265pub mod prelude {
266    pub use crate::emitter::Emitter;
267    pub use crate::field::{FieldConfig, FieldRegistry, FieldType};
268    pub use crate::gpu::VolumeConfig;
269    pub use crate::input::{Input, KeyCode, MouseButton};
270    pub use crate::interactions::InteractionMatrix;
271    pub use crate::lifecycle::Lifecycle;
272    pub use crate::rules::{AgentState, CustomRuleBuilder, Falloff, Rule, Transition};
273    pub use crate::simulation::Simulation;
274    pub use crate::spawn::SpawnContext;
275    pub use crate::sub_emitter::{SpawnTrigger, SubEmitter};
276    pub use crate::textures::{AddressMode, FilterMode, TextureConfig, TextureRegistry};
277    pub use crate::time::Time;
278    pub use crate::uniforms::{CustomUniforms, UpdateContext};
279    pub use crate::visuals::{BlendMode, ColorMapping, ConfigDiff, HotSwapChange, Palette, ParticleShape, VertexEffect, VisualConfig, WireframeMesh};
280    pub use crate::ParticleTrait;
281    pub use crate::{Vec2, Vec3, Vec4};
282    pub use rdpe_derive::{MultiParticle, Particle, ParticleType};
283    #[cfg(feature = "egui")]
284    pub use crate::selection::{selected_particle, selected_particle_data};
285    #[cfg(feature = "egui")]
286    pub use egui;
287}