2022-01-25 19:17:21 +00:00
|
|
|
use super::SceneData;
|
2022-02-15 18:47:25 +00:00
|
|
|
use crate::render::{DynamicModel, Mesh, Quad, Renderer, TrailDrawer, TrailVertex};
|
2022-02-22 17:38:08 +00:00
|
|
|
use common::comp::{object, Body, Pos, Vel};
|
2022-01-25 17:34:33 +00:00
|
|
|
use common_base::span;
|
2022-02-22 17:38:08 +00:00
|
|
|
use specs::{Entity as EcsEntity, Join, WorldExt};
|
2022-01-25 20:49:06 +00:00
|
|
|
use std::collections::HashMap;
|
2022-02-22 17:38:08 +00:00
|
|
|
use vek::*;
|
2022-01-25 17:34:33 +00:00
|
|
|
|
2022-02-16 17:37:52 +00:00
|
|
|
#[derive(Clone, Copy, Eq, PartialEq, Hash)]
|
|
|
|
struct MeshKey {
|
|
|
|
entity: EcsEntity,
|
|
|
|
is_main_weapon: bool,
|
|
|
|
}
|
|
|
|
|
2022-01-25 17:34:33 +00:00
|
|
|
pub struct TrailMgr {
|
2022-02-15 18:47:25 +00:00
|
|
|
/// Meshes for each entity
|
2022-02-16 17:37:52 +00:00
|
|
|
entity_meshes: HashMap<MeshKey, Mesh<TrailVertex>>,
|
2022-01-26 01:37:56 +00:00
|
|
|
|
2022-02-22 17:38:08 +00:00
|
|
|
/// Position cache for things like projectiles
|
|
|
|
pos_cache: HashMap<EcsEntity, Pos>,
|
|
|
|
|
2022-01-26 01:37:56 +00:00
|
|
|
/// Offset
|
|
|
|
pub offset: usize,
|
2022-02-15 18:47:25 +00:00
|
|
|
|
|
|
|
/// Dynamic model to upload to GPU
|
|
|
|
dynamic_model: DynamicModel<TrailVertex>,
|
2022-02-15 20:15:35 +00:00
|
|
|
|
|
|
|
/// Used to create sub model from dynamic model
|
|
|
|
model_len: u32,
|
2022-01-25 17:34:33 +00:00
|
|
|
}
|
|
|
|
|
2022-01-27 20:04:53 +00:00
|
|
|
const TRAIL_DYNAMIC_MODEL_SIZE: usize = 15;
|
2022-02-15 21:54:41 +00:00
|
|
|
const TRAIL_SHRINKAGE: f32 = 0.8;
|
2022-01-26 01:37:56 +00:00
|
|
|
|
2022-01-25 17:34:33 +00:00
|
|
|
impl TrailMgr {
|
2022-02-15 18:47:25 +00:00
|
|
|
pub fn new(renderer: &mut Renderer) -> Self {
|
2022-01-25 17:34:33 +00:00
|
|
|
Self {
|
2022-02-15 18:47:25 +00:00
|
|
|
entity_meshes: HashMap::new(),
|
2022-02-22 17:38:08 +00:00
|
|
|
pos_cache: HashMap::new(),
|
2022-01-26 01:37:56 +00:00
|
|
|
offset: 0,
|
2022-02-15 18:47:25 +00:00
|
|
|
dynamic_model: renderer.create_dynamic_model(0),
|
2022-02-15 20:15:35 +00:00
|
|
|
model_len: 0,
|
2022-01-25 17:34:33 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-01-26 01:37:56 +00:00
|
|
|
pub fn maintain(&mut self, renderer: &mut Renderer, scene_data: &SceneData) {
|
2022-01-25 17:34:33 +00:00
|
|
|
span!(_guard, "maintain", "TrailMgr::maintain");
|
2022-01-26 01:37:56 +00:00
|
|
|
|
2022-01-28 05:06:11 +00:00
|
|
|
if scene_data.weapon_trails_enabled {
|
2022-01-26 01:37:56 +00:00
|
|
|
// Update offset
|
|
|
|
self.offset = (self.offset + 1) % TRAIL_DYNAMIC_MODEL_SIZE;
|
|
|
|
|
2022-02-15 20:25:57 +00:00
|
|
|
self.entity_meshes.values_mut().for_each(|mesh| {
|
2022-02-15 21:54:41 +00:00
|
|
|
// Shrink size of each quad over time
|
|
|
|
let vertices = mesh.vertices_mut_vec();
|
2022-02-16 23:33:24 +00:00
|
|
|
let last_offset =
|
|
|
|
(self.offset + TRAIL_DYNAMIC_MODEL_SIZE - 1) % TRAIL_DYNAMIC_MODEL_SIZE;
|
|
|
|
let next_offset = (self.offset + 1) % TRAIL_DYNAMIC_MODEL_SIZE;
|
2022-02-15 21:54:41 +00:00
|
|
|
for i in 0..TRAIL_DYNAMIC_MODEL_SIZE {
|
|
|
|
// Verts per quad are in b, c, a, d order
|
2022-02-16 23:33:24 +00:00
|
|
|
vertices[i * 4 + 2] = if i == next_offset {
|
|
|
|
vertices[i * 4]
|
|
|
|
} else {
|
|
|
|
vertices[i * 4 + 2] * TRAIL_SHRINKAGE
|
|
|
|
+ vertices[i * 4] * (1.0 - TRAIL_SHRINKAGE)
|
|
|
|
};
|
|
|
|
if i != last_offset {
|
2022-02-16 16:06:21 +00:00
|
|
|
// Avoid shrinking edge of most recent quad so that edges of quads align
|
|
|
|
vertices[i * 4 + 3] = vertices[i * 4 + 3] * TRAIL_SHRINKAGE
|
|
|
|
+ vertices[i * 4 + 1] * (1.0 - TRAIL_SHRINKAGE);
|
|
|
|
}
|
2022-02-15 21:54:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Reset quad for each entity mesh at new offset
|
2022-02-15 20:25:57 +00:00
|
|
|
let zero = TrailVertex::zero();
|
|
|
|
mesh.replace_quad(self.offset * 4, Quad::new(zero, zero, zero, zero));
|
|
|
|
});
|
2022-02-15 18:47:25 +00:00
|
|
|
|
2022-02-22 17:38:08 +00:00
|
|
|
// Hack to shove trails in for projectiles
|
|
|
|
let ecs = scene_data.state.ecs();
|
|
|
|
for (entity, body, vel, pos) in (
|
|
|
|
&ecs.entities(),
|
|
|
|
&ecs.read_storage::<Body>(),
|
|
|
|
&ecs.read_storage::<Vel>(),
|
|
|
|
&ecs.read_storage::<Pos>(),
|
|
|
|
)
|
|
|
|
.join()
|
|
|
|
{
|
|
|
|
if !vel.0.is_approx_zero()
|
|
|
|
&& matches!(
|
|
|
|
body,
|
|
|
|
Body::Object(
|
|
|
|
object::Body::Arrow
|
|
|
|
| object::Body::MultiArrow
|
|
|
|
| object::Body::ArrowSnake
|
|
|
|
| object::Body::ArrowTurret,
|
|
|
|
)
|
|
|
|
)
|
|
|
|
{
|
|
|
|
let last_pos = *self.pos_cache.entry(entity).or_insert(*pos);
|
|
|
|
let offset = self.offset;
|
|
|
|
let quad_mesh = self.entity_mesh_or_insert(entity, true);
|
|
|
|
const THICKNESS: f32 = 0.05;
|
|
|
|
let p1 = pos.0;
|
|
|
|
let p2 = p1 + Vec3::unit_z() * THICKNESS;
|
|
|
|
let p4 = last_pos.0;
|
|
|
|
let p3 = p4 + Vec3::unit_z() * THICKNESS;
|
|
|
|
let vertex = |p: Vec3<f32>| TrailVertex {
|
|
|
|
pos: p.into_array(),
|
|
|
|
};
|
|
|
|
let quad = Quad::new(vertex(p1), vertex(p2), vertex(p3), vertex(p4));
|
|
|
|
quad_mesh.replace_quad(offset * 4, quad);
|
|
|
|
self.pos_cache.insert(entity, *pos);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-02-16 17:37:52 +00:00
|
|
|
// Clear meshes for entities that only have zero quads in mesh
|
2022-02-15 18:47:25 +00:00
|
|
|
self.entity_meshes
|
2022-02-16 17:37:52 +00:00
|
|
|
.retain(|_, mesh| mesh.iter().any(|vert| *vert != TrailVertex::zero()));
|
2022-02-15 18:47:25 +00:00
|
|
|
|
|
|
|
// Create dynamic model from currently existing meshes
|
2022-02-15 20:15:35 +00:00
|
|
|
let mut big_mesh = Mesh::new();
|
|
|
|
self.entity_meshes
|
|
|
|
.values()
|
|
|
|
// If any of the vertices in a mesh are non-zero, upload the entire mesh for the entity
|
|
|
|
.filter(|mesh| mesh.iter().any(|vert| *vert != TrailVertex::zero()))
|
|
|
|
.for_each(|mesh| big_mesh.push_mesh(mesh));
|
|
|
|
|
|
|
|
// To avoid empty mesh
|
|
|
|
if big_mesh.is_empty() {
|
|
|
|
let zero = TrailVertex::zero();
|
|
|
|
big_mesh.push_quad(Quad::new(zero, zero, zero, zero));
|
|
|
|
}
|
|
|
|
|
|
|
|
// If dynamic model too small, resize
|
|
|
|
if self.dynamic_model.len() < big_mesh.len() {
|
|
|
|
self.dynamic_model = renderer.create_dynamic_model(big_mesh.len());
|
2022-02-15 18:47:25 +00:00
|
|
|
};
|
2022-02-15 20:15:35 +00:00
|
|
|
renderer.update_model(&self.dynamic_model, &big_mesh, 0);
|
|
|
|
self.model_len = big_mesh.len() as u32;
|
2022-01-26 01:37:56 +00:00
|
|
|
} else {
|
2022-02-15 18:47:25 +00:00
|
|
|
self.entity_meshes.clear();
|
2022-01-26 01:37:56 +00:00
|
|
|
}
|
2022-01-25 17:34:33 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
pub fn render<'a>(&'a self, drawer: &mut TrailDrawer<'_, 'a>, scene_data: &SceneData) {
|
|
|
|
span!(_guard, "render", "TrailMgr::render");
|
2022-01-28 05:06:11 +00:00
|
|
|
if scene_data.weapon_trails_enabled {
|
2022-02-15 20:15:35 +00:00
|
|
|
drawer.draw(&self.dynamic_model, self.model_len);
|
2022-01-25 17:34:33 +00:00
|
|
|
}
|
|
|
|
}
|
2022-02-16 17:37:52 +00:00
|
|
|
|
|
|
|
pub fn entity_mesh_or_insert(
|
|
|
|
&mut self,
|
|
|
|
entity: EcsEntity,
|
|
|
|
is_main_weapon: bool,
|
|
|
|
) -> &mut Mesh<TrailVertex> {
|
|
|
|
let key = MeshKey {
|
|
|
|
entity,
|
|
|
|
is_main_weapon,
|
|
|
|
};
|
|
|
|
self.entity_meshes
|
|
|
|
.entry(key)
|
|
|
|
.or_insert_with(Self::default_trail_mesh)
|
|
|
|
}
|
|
|
|
|
|
|
|
fn default_trail_mesh() -> Mesh<TrailVertex> {
|
|
|
|
let mut mesh = Mesh::new();
|
|
|
|
let zero = TrailVertex::zero();
|
|
|
|
for _ in 0..TRAIL_DYNAMIC_MODEL_SIZE {
|
|
|
|
mesh.push_quad(Quad::new(zero, zero, zero, zero));
|
|
|
|
}
|
|
|
|
mesh
|
|
|
|
}
|
2022-01-25 17:34:33 +00:00
|
|
|
}
|