# A particles generator in rust for laser shows ## Philosophy This library should allow users to define their own particle behaviours - how many particles at start? min/max at any time? how many to add at any time? - how do particles behave? Are there different types? Different shapes? - how do particles react with real world? To audio? To a controller? ## Constraints - Render as lists of points in the form [x,y,color] with color encoded as 12 bits (r,g,b) - i.e. it doesn't speak to the laser directly, we use a middleware for that part (see. xxx) - it can output to STDOUT or send to redis - Obviously be as fast as possible - Use a physics engine as a tool for collision detection, velocity and more - Be easy to use: good defaults for everything - Handle bounding and drawing boxes - Handle user custom particle properties (ex: decay, frequency, personality, etc.) - Handle additional drawings for the current frame due to custom events (ex: random edge between two particles) ## Questions ### Working with the Physics engine - Q: how do we enable custom behaviours (ex: reacting to audio) - Q: how do we map physics engine object (ex: ball, square) for users as concept - Q: how do we convert the physics engine objets to 2D points - Q: how do we handle 3D? On by default? ## How to use in a project 1. Clone lj_rust_template and edit draw.rs 2. add lj_particle library crate 3. edit the draw function 4. compile ## Fundamental Features - [ ] Use a 3D physics engine - [ ] Provide hooks to create and update the simulation (onInit, onTick, onCollide, etc.) - [ ] Render using box clipping for out of bound particles points - [ ] Use an out-of-simulation list of additional points - [ ] Render to STDOUT or Redis ## Future Features - [ ] Use a 2D physics engine - [ ] Use attractors/repulsors objects - [ ] Use OSC to update configuration ## Library struct/objects ``` Particle - PhysicsBody - Shape : Square, Triangle, Circle, 3DSphere - UserData // custom ex: life decay, seed, created_at, frequency - Group PhysicsEngine PhysicsEngineConfig RenderEngine RenderEngineConfig Config - ParticlesGroups: vec< - RedisConfig - PhysicsEngineConfig - RenderEngineConfig // future feature OSCConfig - OSCCache - OSCServer ```` ## API example ```rust /*** An idea of the crate API ***/ use LJParticleSystem as ParticleSystem; use LJRedilysis as Redilysis; use Rapier as PhysicsEngine; // Configure let boundingbox = BoundingBox(); let clipping_box = ClippingBox(); let particle_system = ParticleSystem( ParticleSystemConfig, PhysicsEngine, ClippingBox, BoundingBox ); let redilysis = Redilysis ( RedilysisConfig( file_path ) ); // by default, equiprobability to generate a particle from any group particle_system.new_particle( lambda() => { ... }) // some way to init the particles world.init(); particle_system.tick = lambda(){ // Configuration update if read via OSC current_config = self->getConfig(); // Retrieve bandwidth/bpm/rms info (with caching) analysis = redilysis.update(); // Manage self.boundingBox(); self.physicsEngine(); for( particle in self.getParticles() ) { } n_particles = current_config.particles_amount; return self.clippingBox(); } pub fn draw() -> Result, Box> { let mut v: Vec = vec![]; v.push( particle_system.tick() ); Ok(v) } ``` ## OSC CONFIG ### Actors and notations ``` - [S] Server / (LJ) OSC Server and client eventual config channel 1 : IP channel X : IP - [R] Rust = (LJ Particle) OSC Server and Client - [U] User Interface = (Tablet) HTML Interface - [c] Program Channel = configurable, uint ex: 1 - [n] Programe name = configurable, string ex: particle_foo_square ``` ### Sequence Diagram ``` # Prerequisite : [S] is running and available and U is connected to [S] # [R] starts # [R]: Do you have my config already ? [R] -> [S] "/program/${c}/${n}/configure" # [S] needs to stock which program is currently used for ${n} channel and its parameters # If no, [S] manifests the need to init the configuration [S] -> [R] "/program/${c}/${n}/no-config" # If no-config, [R] sends its default config for [S] to store [R] -> [S] "/program/${c}/${n}/var1 default_value1" # etc. # In any case, [S] sends to [R] the current config [S] -> [R] "/program/${c}/${n}/var1 value1" # etc. # [S] creates an event for the User to change [S] -> U "/program/${c}/${n}" # U can change the program configuration U -> [S] "/program/${c}/${n}" ```