veloren_voxygen/scene/
trail.rs1use super::SceneData;
2use crate::render::{DynamicModel, Mesh, Quad, Renderer, TrailDrawer, TrailVertex};
3use common::comp::{Body, Pos, Vel, object};
4use common_base::span;
5use specs::{Entity as EcsEntity, Join, WorldExt};
6use std::collections::HashMap;
7use vek::*;
8
9#[derive(Clone, Copy, Eq, PartialEq, Hash)]
10struct MeshKey {
11 entity: EcsEntity,
12 is_main_weapon: bool,
13}
14
15#[derive(Default)]
16pub struct TrailMgr {
17 entity_meshes: HashMap<MeshKey, (Mesh<TrailVertex>, usize)>,
19
20 pos_cache: HashMap<EcsEntity, Pos>,
22
23 offset: usize,
25
26 dynamic_model: Option<DynamicModel<TrailVertex>>,
28
29 model_len: u32,
31}
32
33const TRAIL_DYNAMIC_MODEL_SIZE: usize = 15;
34const TRAIL_SHRINKAGE: f32 = 0.8;
35
36impl TrailMgr {
37 pub fn maintain(&mut self, renderer: &mut Renderer, scene_data: &SceneData) {
38 span!(_guard, "maintain", "TrailMgr::maintain");
39
40 if scene_data.weapon_trails_enabled {
41 let ecs = scene_data.state.ecs();
43 for (entity, body, vel, pos) in (
44 &ecs.entities(),
45 &ecs.read_storage::<Body>(),
46 &ecs.read_storage::<Vel>(),
47 &ecs.read_storage::<Pos>(),
48 )
49 .join()
50 {
51 const MIN_SPEED: f32 = 15.0;
52 if vel.0.magnitude_squared() > MIN_SPEED.powi(2)
53 && matches!(
54 body,
55 Body::Object(
56 object::Body::Arrow
57 | object::Body::MultiArrow
58 | object::Body::ArrowSnake
59 | object::Body::ArrowTurret
60 | object::Body::ArrowClay
61 | object::Body::BoltBesieger,
62 )
63 )
64 {
65 let last_pos = *self.pos_cache.entry(entity).or_insert(*pos);
66 let offset = self.offset;
67 let quad_mesh = self.entity_mesh_or_insert(entity, true);
68 const THICKNESS: f32 = 0.05;
69 let p1 = pos.0;
70 let p2 = p1 + Vec3::unit_z() * THICKNESS;
71 let p4 = last_pos.0;
72 let p3 = p4 + Vec3::unit_z() * THICKNESS;
73 let vertex = |p: Vec3<f32>| TrailVertex {
74 pos: p.into_array(),
75 };
76 let quad = Quad::new(vertex(p1), vertex(p2), vertex(p3), vertex(p4));
77 quad_mesh.replace_quad(offset * 4, quad);
78 self.pos_cache.insert(entity, *pos);
79 }
80 }
81
82 self.offset = (self.offset + 1) % TRAIL_DYNAMIC_MODEL_SIZE;
84
85 self.entity_meshes.values_mut().for_each(|(mesh, _)| {
86 let vertices = mesh.vertices_mut_vec();
89 let last_offset =
90 (self.offset + TRAIL_DYNAMIC_MODEL_SIZE - 1) % TRAIL_DYNAMIC_MODEL_SIZE;
91 let next_offset = (self.offset + 1) % TRAIL_DYNAMIC_MODEL_SIZE;
92 for i in 0..TRAIL_DYNAMIC_MODEL_SIZE {
93 let [b, c, a, d] = [0, 1, 2, 3].map(|offset| i * 4 + offset);
95 vertices[a] = if i == next_offset {
96 vertices[b]
97 } else {
98 vertices[a] * TRAIL_SHRINKAGE + vertices[b] * (1.0 - TRAIL_SHRINKAGE)
99 };
100 if i != last_offset {
101 vertices[d] =
103 vertices[d] * TRAIL_SHRINKAGE + vertices[c] * (1.0 - TRAIL_SHRINKAGE);
104 }
105 }
106
107 let zero = TrailVertex::zero();
109 mesh.replace_quad(self.offset * 4, Quad::new(zero, zero, zero, zero));
110 });
111
112 self.entity_meshes
114 .retain(|_, (_mesh, last_updated)| *last_updated != self.offset);
115
116 let mut big_mesh = Mesh::new();
121 self.entity_meshes
122 .values()
123 .filter(|(mesh, _)| mesh.iter().any(|vert| *vert != TrailVertex::zero()))
125 .for_each(|(mesh, _)| big_mesh.push_mesh(mesh));
126
127 if big_mesh.is_empty() {
129 let zero = TrailVertex::zero();
130 big_mesh.push_quad(Quad::new(zero, zero, zero, zero));
131 }
132
133 if self.dynamic_model.as_ref().map_or(0, |model| model.len()) < big_mesh.len() {
136 self.dynamic_model = Some(
137 renderer
138 .create_dynamic_model(big_mesh.len() + TRAIL_DYNAMIC_MODEL_SIZE * 4 * 10),
139 );
140 }
141 if let Some(dynamic_model) = &self.dynamic_model {
142 renderer.update_model(dynamic_model, &big_mesh, 0);
143 }
144 self.model_len = big_mesh.len() as u32;
145 } else {
146 self.entity_meshes.clear();
147 self.dynamic_model = None;
149 }
150 }
151
152 pub fn render<'a>(&'a self, drawer: &mut TrailDrawer<'_, 'a>, scene_data: &SceneData) {
153 span!(_guard, "render", "TrailMgr::render");
154 if scene_data.weapon_trails_enabled {
155 if let Some(dynamic_model) = &self.dynamic_model {
156 drawer.draw(dynamic_model.submodel(0..self.model_len))
157 }
158 }
159 }
160
161 pub fn entity_mesh_or_insert(
162 &mut self,
163 entity: EcsEntity,
164 is_main_weapon: bool,
165 ) -> &mut Mesh<TrailVertex> {
166 let key = MeshKey {
167 entity,
168 is_main_weapon,
169 };
170 &mut self
171 .entity_meshes
172 .entry(key)
173 .and_modify(|(_mesh, offset)| *offset = self.offset)
174 .or_insert((Self::default_trail_mesh(), self.offset))
175 .0
176 }
177
178 fn default_trail_mesh() -> Mesh<TrailVertex> {
179 let mut mesh = Mesh::new();
180 let zero = TrailVertex::zero();
181 for _ in 0..TRAIL_DYNAMIC_MODEL_SIZE {
182 mesh.push_quad(Quad::new(zero, zero, zero, zero));
183 }
184 mesh
185 }
186
187 pub fn offset(&self) -> usize { self.offset }
188}