2020-07-05 12:10:58 +00:00
|
|
|
use super::SceneData;
|
|
|
|
use crate::{
|
|
|
|
mesh::Meshable,
|
|
|
|
render::{
|
|
|
|
mesh::Quad, Consts, Globals, Instances, Light, Mesh, Model, ParticleInstance,
|
|
|
|
ParticlePipeline, Renderer, Shadow,
|
|
|
|
},
|
|
|
|
};
|
|
|
|
use common::{
|
|
|
|
assets,
|
|
|
|
comp::{visual::ParticleEmitterMode, Ori, ParticleEmitter, Pos, Vel},
|
|
|
|
figure::Segment,
|
|
|
|
vol::BaseVol,
|
|
|
|
};
|
|
|
|
use dot_vox::DotVoxData;
|
|
|
|
use hashbrown::HashMap;
|
|
|
|
use rand::Rng;
|
|
|
|
use specs::{Entity as EcsEntity, Join, WorldExt};
|
2020-07-11 10:37:19 +00:00
|
|
|
use std::time::{Duration, Instant};
|
2020-07-05 12:10:58 +00:00
|
|
|
use tracing::{debug, error, warn};
|
|
|
|
use vek::{Mat4, Rgb, Vec3};
|
2020-07-11 10:37:19 +00:00
|
|
|
|
2020-07-05 12:10:58 +00:00
|
|
|
struct Particles {
|
|
|
|
// this is probably nieve,
|
|
|
|
// could cache and re-use between particles,
|
|
|
|
// should be a cache key?
|
|
|
|
// model: Model<ParticlePipeline>,
|
2020-07-11 10:37:19 +00:00
|
|
|
// created_at: Instant,
|
|
|
|
// lifespan: Duration,
|
|
|
|
alive_until: Instant, // created_at + lifespan
|
|
|
|
|
2020-07-05 12:10:58 +00:00
|
|
|
instances: Instances<ParticleInstance>,
|
|
|
|
}
|
|
|
|
|
2020-07-11 10:37:19 +00:00
|
|
|
struct Emitter {
|
|
|
|
last_emit: Instant,
|
|
|
|
}
|
|
|
|
|
2020-07-05 12:10:58 +00:00
|
|
|
pub struct ParticleMgr {
|
2020-07-11 10:37:19 +00:00
|
|
|
// to keep track of spawn intervals
|
|
|
|
emitters: HashMap<EcsEntity, Emitter>,
|
|
|
|
|
|
|
|
// to keep track of lifespans
|
|
|
|
particles: Vec<Particles>,
|
|
|
|
|
|
|
|
model_cache: HashMap<&'static str, Model<ParticlePipeline>>,
|
|
|
|
|
|
|
|
beginning_of_time: Instant,
|
2020-07-05 12:10:58 +00:00
|
|
|
}
|
|
|
|
|
2020-07-11 10:37:19 +00:00
|
|
|
const MODEL_KEY: &str = "voxygen.voxel.not_found";
|
|
|
|
|
2020-07-05 12:10:58 +00:00
|
|
|
impl ParticleMgr {
|
|
|
|
pub fn new(renderer: &mut Renderer) -> Self {
|
2020-07-11 10:37:19 +00:00
|
|
|
let mut model_cache = HashMap::new();
|
2020-07-05 12:10:58 +00:00
|
|
|
|
2020-07-11 10:37:19 +00:00
|
|
|
let model = model_cache.entry(MODEL_KEY).or_insert_with(|| {
|
|
|
|
let offset = Vec3::zero();
|
|
|
|
let lod_scale = Vec3::one();
|
2020-07-05 12:10:58 +00:00
|
|
|
|
2020-07-11 10:37:19 +00:00
|
|
|
// TODO: from cache
|
|
|
|
let vox = assets::load_expect::<DotVoxData>(MODEL_KEY);
|
|
|
|
|
|
|
|
// TODO: from cache
|
|
|
|
let mesh = &Meshable::<ParticlePipeline, ParticlePipeline>::generate_mesh(
|
|
|
|
&Segment::from(vox.as_ref()),
|
|
|
|
(offset * lod_scale, Vec3::one() / lod_scale),
|
|
|
|
)
|
|
|
|
.0;
|
|
|
|
|
|
|
|
// TODO: from cache
|
|
|
|
let model = renderer
|
|
|
|
.create_model(mesh)
|
|
|
|
.expect("Failed to create particle model");
|
2020-07-05 12:10:58 +00:00
|
|
|
|
2020-07-11 10:37:19 +00:00
|
|
|
model
|
|
|
|
});
|
2020-07-05 12:10:58 +00:00
|
|
|
|
|
|
|
Self {
|
2020-07-11 10:37:19 +00:00
|
|
|
emitters: HashMap::new(),
|
|
|
|
particles: Vec::new(),
|
|
|
|
model_cache,
|
|
|
|
beginning_of_time: Instant::now(),
|
2020-07-05 12:10:58 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn maintain(
|
|
|
|
&mut self,
|
|
|
|
renderer: &mut Renderer,
|
|
|
|
scene_data: &SceneData,
|
|
|
|
focus_pos: Vec3<f32>,
|
|
|
|
loaded_distance: f32,
|
|
|
|
view_mat: Mat4<f32>,
|
|
|
|
proj_mat: Mat4<f32>,
|
|
|
|
) {
|
|
|
|
let state = scene_data.state;
|
|
|
|
let ecs = state.ecs();
|
|
|
|
|
|
|
|
let tick = scene_data.tick;
|
|
|
|
|
2020-07-11 10:37:19 +00:00
|
|
|
let now = Instant::now();
|
|
|
|
let beginning_of_time1 = self.beginning_of_time.clone();
|
|
|
|
|
|
|
|
// remove dead emitters
|
|
|
|
self.emitters.retain(|k, _v| ecs.is_alive(*k));
|
2020-07-05 12:10:58 +00:00
|
|
|
|
2020-07-11 10:37:19 +00:00
|
|
|
// remove dead particles
|
|
|
|
self.particles.retain(|p| p.alive_until > now);
|
2020-07-05 12:10:58 +00:00
|
|
|
|
|
|
|
// add living entities particles
|
|
|
|
for (_i, (entity, particle_emitter, pos, ori, vel)) in (
|
|
|
|
&ecs.entities(),
|
|
|
|
&ecs.read_storage::<ParticleEmitter>(),
|
|
|
|
&ecs.read_storage::<Pos>(),
|
|
|
|
ecs.read_storage::<Ori>().maybe(),
|
|
|
|
ecs.read_storage::<Vel>().maybe(),
|
|
|
|
)
|
|
|
|
.join()
|
|
|
|
.enumerate()
|
|
|
|
{
|
2020-07-11 10:37:19 +00:00
|
|
|
let emitter = self.emitters.entry(entity).or_insert_with(|| Emitter {
|
|
|
|
last_emit: beginning_of_time1, // self.beginning_of_time.clone()
|
|
|
|
});
|
|
|
|
|
|
|
|
if emitter.last_emit + particle_emitter.frequency < now {
|
|
|
|
emitter.last_emit = Instant::now();
|
|
|
|
|
|
|
|
let cpu_insts =
|
|
|
|
into_particle_instances(particle_emitter, renderer, tick, pos, ori, vel);
|
|
|
|
|
|
|
|
let gpu_insts = renderer
|
|
|
|
.create_instances(&cpu_insts)
|
|
|
|
.expect("Failed to upload particle instances to the GPU!");
|
|
|
|
|
|
|
|
let entry = self.particles.push(Particles {
|
|
|
|
alive_until: now + particle_emitter.initial_lifespan,
|
|
|
|
instances: gpu_insts,
|
|
|
|
});
|
|
|
|
}
|
2020-07-05 12:10:58 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn render(
|
|
|
|
&self,
|
|
|
|
renderer: &mut Renderer,
|
|
|
|
globals: &Consts<Globals>,
|
|
|
|
lights: &Consts<Light>,
|
|
|
|
shadows: &Consts<Shadow>,
|
|
|
|
focus_pos: Vec3<f32>,
|
|
|
|
) {
|
2020-07-11 10:37:19 +00:00
|
|
|
for particle in &self.particles {
|
|
|
|
renderer.render_particles(
|
|
|
|
&self
|
|
|
|
.model_cache
|
|
|
|
.get(MODEL_KEY)
|
|
|
|
.expect("Expected particle model in cache"),
|
|
|
|
globals,
|
|
|
|
&particle.instances,
|
|
|
|
lights,
|
|
|
|
shadows,
|
|
|
|
);
|
2020-07-05 12:10:58 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-07-11 10:37:19 +00:00
|
|
|
fn into_particle_instances(
|
|
|
|
particle_emitter: &ParticleEmitter,
|
2020-07-05 12:10:58 +00:00
|
|
|
renderer: &mut Renderer,
|
|
|
|
tick: u64,
|
|
|
|
pos: &Pos,
|
|
|
|
ori: Option<&Ori>,
|
|
|
|
vel: Option<&Vel>,
|
2020-07-11 10:37:19 +00:00
|
|
|
) -> Vec<ParticleInstance> {
|
2020-07-05 12:10:58 +00:00
|
|
|
let mut rng = rand::thread_rng();
|
|
|
|
let vel_default = Vel::default();
|
|
|
|
let vel2 = vel.unwrap_or_else(|| &vel_default).0;
|
2020-07-11 10:37:19 +00:00
|
|
|
|
2020-07-05 12:10:58 +00:00
|
|
|
let mut instances_vec = Vec::new();
|
|
|
|
|
2020-07-11 10:37:19 +00:00
|
|
|
for x in 0..rng.gen_range(particle_emitter.count.0, particle_emitter.count.1) {
|
2020-07-05 12:10:58 +00:00
|
|
|
// how does ParticleEmitterMode fit in here?
|
|
|
|
// can we have a ParticleInstance type per ParticleEmitterMode?
|
|
|
|
// can we mix and match instance types in the same instances_vec?
|
|
|
|
instances_vec.push(ParticleInstance::new(
|
|
|
|
Mat4::identity()
|
|
|
|
// initial rotation
|
2020-07-11 10:37:19 +00:00
|
|
|
.rotated_x(rng.gen_range(particle_emitter.initial_orientation.0.x * std::f32::consts::PI * 2.0, particle_emitter.initial_orientation.1.x * std::f32::consts::PI * 2.0))
|
|
|
|
.rotated_y(rng.gen_range(particle_emitter.initial_orientation.0.y * std::f32::consts::PI * 2.0, particle_emitter.initial_orientation.1.y * std::f32::consts::PI * 2.0))
|
|
|
|
.rotated_z(rng.gen_range(particle_emitter.initial_orientation.0.z * std::f32::consts::PI * 2.0, particle_emitter.initial_orientation.1.z * std::f32::consts::PI * 2.0))
|
|
|
|
// initial scale
|
|
|
|
.scaled_3d(rng.gen_range(particle_emitter.initial_scale.0, particle_emitter.initial_scale.1))
|
2020-07-05 12:10:58 +00:00
|
|
|
// inition position
|
|
|
|
.translated_3d(
|
2020-07-11 10:37:19 +00:00
|
|
|
pos.0 // relative
|
2020-07-05 12:10:58 +00:00
|
|
|
+ Vec3::new(
|
2020-07-11 10:37:19 +00:00
|
|
|
rng.gen_range(particle_emitter.initial_offset.0.x, particle_emitter.initial_offset.1.x),
|
|
|
|
rng.gen_range(particle_emitter.initial_offset.0.y, particle_emitter.initial_offset.1.y),
|
|
|
|
rng.gen_range(particle_emitter.initial_offset.0.z, particle_emitter.initial_offset.1.z),
|
2020-07-05 12:10:58 +00:00
|
|
|
),
|
|
|
|
),
|
|
|
|
Rgb::broadcast(1.0), // instance color
|
|
|
|
vel2 + Vec3::broadcast(rng.gen_range(-5.0, 5.0)),
|
|
|
|
tick,
|
|
|
|
rng.gen_range(0.0, 20.0), // wind sway
|
|
|
|
ParticleEmitterMode::Sprinkler, // particle_emitter.mode */
|
|
|
|
));
|
|
|
|
}
|
|
|
|
|
2020-07-11 10:37:19 +00:00
|
|
|
instances_vec
|
2020-07-05 12:10:58 +00:00
|
|
|
}
|