diff --git a/voxygen/anim/src/arthropod/mod.rs b/voxygen/anim/src/arthropod/mod.rs index 9bbba91d39..ae7de05669 100644 --- a/voxygen/anim/src/arthropod/mod.rs +++ b/voxygen/anim/src/arthropod/mod.rs @@ -113,7 +113,8 @@ impl Skeleton for ArthropodSkeleton { orientation: mount_orientation, scale: Vec3::one(), }, - weapon_trail_mat: None, + main_weapon_trail_mat: None, + off_weapon_trail_mat: None, } } } diff --git a/voxygen/anim/src/biped_large/mod.rs b/voxygen/anim/src/biped_large/mod.rs index eb805eeafe..f06af4c2b3 100644 --- a/voxygen/anim/src/biped_large/mod.rs +++ b/voxygen/anim/src/biped_large/mod.rs @@ -137,7 +137,8 @@ impl Skeleton for BipedLargeSkeleton { .into(), ..Default::default() }, - weapon_trail_mat: None, + main_weapon_trail_mat: None, + off_weapon_trail_mat: None, } } } diff --git a/voxygen/anim/src/biped_small/mod.rs b/voxygen/anim/src/biped_small/mod.rs index 13ece9d2e4..b9592900a3 100644 --- a/voxygen/anim/src/biped_small/mod.rs +++ b/voxygen/anim/src/biped_small/mod.rs @@ -83,7 +83,8 @@ impl Skeleton for BipedSmallSkeleton { .into(), ..Default::default() }, - weapon_trail_mat: None, + main_weapon_trail_mat: None, + off_weapon_trail_mat: None, } } } diff --git a/voxygen/anim/src/bird_large/mod.rs b/voxygen/anim/src/bird_large/mod.rs index 30fc73bf2a..8fa4c3b4c2 100644 --- a/voxygen/anim/src/bird_large/mod.rs +++ b/voxygen/anim/src/bird_large/mod.rs @@ -106,7 +106,8 @@ impl Skeleton for BirdLargeSkeleton { .into(), ..Default::default() }, - weapon_trail_mat: None, + main_weapon_trail_mat: None, + off_weapon_trail_mat: None, } } } diff --git a/voxygen/anim/src/bird_medium/mod.rs b/voxygen/anim/src/bird_medium/mod.rs index ed37962f06..1953518634 100644 --- a/voxygen/anim/src/bird_medium/mod.rs +++ b/voxygen/anim/src/bird_medium/mod.rs @@ -60,7 +60,8 @@ impl Skeleton for BirdMediumSkeleton { .into(), ..Default::default() }, - weapon_trail_mat: None, + main_weapon_trail_mat: None, + off_weapon_trail_mat: None, } } } diff --git a/voxygen/anim/src/character/mod.rs b/voxygen/anim/src/character/mod.rs index 6496126b51..ba20e9bd9a 100644 --- a/voxygen/anim/src/character/mod.rs +++ b/voxygen/anim/src/character/mod.rs @@ -79,6 +79,7 @@ skeleton_impls!(struct CharacterSkeleton { :: // Begin non-bone fields holding_lantern: bool, main_weapon_trail: bool, + off_weapon_trail: bool, }); impl CharacterSkeleton { @@ -127,6 +128,7 @@ impl Skeleton for CharacterSkeleton { shorts_mat } * Mat4::::from(self.lantern); let main_mat = control_l_mat * Mat4::::from(self.main); + let second_mat = control_r_mat * Mat4::::from(self.second); *(<&mut [_; Self::BONE_COUNT]>::try_from(&mut buf[0..Self::BONE_COUNT]).unwrap()) = [ make_bone(head_mat), @@ -142,7 +144,7 @@ impl Skeleton for CharacterSkeleton { make_bone(chest_mat * Mat4::::from(self.shoulder_r)), make_bone(chest_mat * Mat4::::from(self.glider)), make_bone(main_mat), - make_bone(control_r_mat * Mat4::::from(self.second)), + make_bone(second_mat), make_bone(lantern_mat), // FIXME: Should this be control_l_mat? make_bone(control_mat * hand_l_mat * Mat4::::from(self.hold)), @@ -157,7 +159,8 @@ impl Skeleton for CharacterSkeleton { .into(), ..Default::default() }, - weapon_trail_mat: self.main_weapon_trail.then_some(main_mat), + main_weapon_trail_mat: self.main_weapon_trail.then_some(main_mat), + off_weapon_trail_mat: self.off_weapon_trail.then_some(second_mat), } } } diff --git a/voxygen/anim/src/dragon/mod.rs b/voxygen/anim/src/dragon/mod.rs index ffd993ccde..ebaa54d108 100644 --- a/voxygen/anim/src/dragon/mod.rs +++ b/voxygen/anim/src/dragon/mod.rs @@ -81,7 +81,8 @@ impl Skeleton for DragonSkeleton { .into(), ..Default::default() }, - weapon_trail_mat: None, + main_weapon_trail_mat: None, + off_weapon_trail_mat: None, } } } diff --git a/voxygen/anim/src/fish_medium/mod.rs b/voxygen/anim/src/fish_medium/mod.rs index ef062488bf..5b3211940d 100644 --- a/voxygen/anim/src/fish_medium/mod.rs +++ b/voxygen/anim/src/fish_medium/mod.rs @@ -60,7 +60,8 @@ impl Skeleton for FishMediumSkeleton { .into(), ..Default::default() }, - weapon_trail_mat: None, + main_weapon_trail_mat: None, + off_weapon_trail_mat: None, } } } diff --git a/voxygen/anim/src/fish_small/mod.rs b/voxygen/anim/src/fish_small/mod.rs index 338980b1ba..6fde7c2615 100644 --- a/voxygen/anim/src/fish_small/mod.rs +++ b/voxygen/anim/src/fish_small/mod.rs @@ -51,7 +51,8 @@ impl Skeleton for FishSmallSkeleton { .into(), ..Default::default() }, - weapon_trail_mat: None, + main_weapon_trail_mat: None, + off_weapon_trail_mat: None, } } } diff --git a/voxygen/anim/src/fixture/mod.rs b/voxygen/anim/src/fixture/mod.rs index f72daab767..f5c3c71511 100644 --- a/voxygen/anim/src/fixture/mod.rs +++ b/voxygen/anim/src/fixture/mod.rs @@ -37,7 +37,8 @@ impl Skeleton for FixtureSkeleton { Offsets { lantern: None, mount_bone: Transform::default(), - weapon_trail_mat: None, + main_weapon_trail_mat: None, + off_weapon_trail_mat: None, } } } diff --git a/voxygen/anim/src/golem/mod.rs b/voxygen/anim/src/golem/mod.rs index 6a81fa6fbe..a08addda6f 100644 --- a/voxygen/anim/src/golem/mod.rs +++ b/voxygen/anim/src/golem/mod.rs @@ -83,7 +83,8 @@ impl Skeleton for GolemSkeleton { .into(), ..Default::default() }, - weapon_trail_mat: None, + main_weapon_trail_mat: None, + off_weapon_trail_mat: None, } } } diff --git a/voxygen/anim/src/item_drop/mod.rs b/voxygen/anim/src/item_drop/mod.rs index dd7c8e63b4..74838b7520 100644 --- a/voxygen/anim/src/item_drop/mod.rs +++ b/voxygen/anim/src/item_drop/mod.rs @@ -43,7 +43,8 @@ impl Skeleton for ItemDropSkeleton { .into(), ..Default::default() }, - weapon_trail_mat: None, + main_weapon_trail_mat: None, + off_weapon_trail_mat: None, } } } diff --git a/voxygen/anim/src/lib.rs b/voxygen/anim/src/lib.rs index 009bc080e0..c7d286edd7 100644 --- a/voxygen/anim/src/lib.rs +++ b/voxygen/anim/src/lib.rs @@ -1,7 +1,4 @@ -#![feature( - generic_associated_types, - bool_to_option, -)] +#![feature(generic_associated_types, bool_to_option)] #![allow(incomplete_features)] #[cfg(all(feature = "be-dyn-lib", feature = "use-dyn-lib"))] compile_error!("Can't use both \"be-dyn-lib\" and \"use-dyn-lib\" features at once"); @@ -106,7 +103,8 @@ pub fn init() { lazy_static::initialize(&LIB); } pub struct Offsets { pub lantern: Option>, pub mount_bone: Transform, - pub weapon_trail_mat: Option>, + pub main_weapon_trail_mat: Option>, + pub off_weapon_trail_mat: Option>, } pub trait Skeleton: Send + Sync + 'static { diff --git a/voxygen/anim/src/object/mod.rs b/voxygen/anim/src/object/mod.rs index 45ee48831c..c222bfe898 100644 --- a/voxygen/anim/src/object/mod.rs +++ b/voxygen/anim/src/object/mod.rs @@ -49,7 +49,8 @@ impl Skeleton for ObjectSkeleton { .into(), ..Default::default() }, - weapon_trail_mat: None, + main_weapon_trail_mat: None, + off_weapon_trail_mat: None, } } } diff --git a/voxygen/anim/src/quadruped_low/mod.rs b/voxygen/anim/src/quadruped_low/mod.rs index 74876acf6b..642ad3f925 100644 --- a/voxygen/anim/src/quadruped_low/mod.rs +++ b/voxygen/anim/src/quadruped_low/mod.rs @@ -97,7 +97,8 @@ impl Skeleton for QuadrupedLowSkeleton { orientation: mount_orientation, scale: Vec3::one(), }, - weapon_trail_mat: None, + main_weapon_trail_mat: None, + off_weapon_trail_mat: None, } } } diff --git a/voxygen/anim/src/quadruped_medium/mod.rs b/voxygen/anim/src/quadruped_medium/mod.rs index 08c1f20d47..1f8a862752 100644 --- a/voxygen/anim/src/quadruped_medium/mod.rs +++ b/voxygen/anim/src/quadruped_medium/mod.rs @@ -109,7 +109,8 @@ impl Skeleton for QuadrupedMediumSkeleton { orientation: mount_orientation, scale: Vec3::one(), }, - weapon_trail_mat: None, + main_weapon_trail_mat: None, + off_weapon_trail_mat: None, } } } diff --git a/voxygen/anim/src/quadruped_small/mod.rs b/voxygen/anim/src/quadruped_small/mod.rs index b67c7ddbdc..15896b8491 100644 --- a/voxygen/anim/src/quadruped_small/mod.rs +++ b/voxygen/anim/src/quadruped_small/mod.rs @@ -74,7 +74,8 @@ impl Skeleton for QuadrupedSmallSkeleton { orientation: mount_orientation, scale: Vec3::one(), }, - weapon_trail_mat: None, + main_weapon_trail_mat: None, + off_weapon_trail_mat: None, } } } diff --git a/voxygen/anim/src/ship/mod.rs b/voxygen/anim/src/ship/mod.rs index fd7c8463ee..aa675c6c79 100644 --- a/voxygen/anim/src/ship/mod.rs +++ b/voxygen/anim/src/ship/mod.rs @@ -53,7 +53,8 @@ impl Skeleton for ShipSkeleton { ), ..Default::default() }, - weapon_trail_mat: None, + main_weapon_trail_mat: None, + off_weapon_trail_mat: None, } } } diff --git a/voxygen/anim/src/theropod/mod.rs b/voxygen/anim/src/theropod/mod.rs index 51755985bc..bf7f30dfab 100644 --- a/voxygen/anim/src/theropod/mod.rs +++ b/voxygen/anim/src/theropod/mod.rs @@ -84,7 +84,8 @@ impl Skeleton for TheropodSkeleton { .into(), ..Default::default() }, - weapon_trail_mat: None, + main_weapon_trail_mat: None, + off_weapon_trail_mat: None, } } } diff --git a/voxygen/src/scene/figure/mod.rs b/voxygen/src/scene/figure/mod.rs index 480b354c81..a3af96cb2d 100644 --- a/voxygen/src/scene/figure/mod.rs +++ b/voxygen/src/scene/figure/mod.rs @@ -33,9 +33,8 @@ use common::{ comp::{ inventory::slot::EquipSlot, item::{Hands, ItemKind, ToolKind}, - Body, CharacterState, Collider, Controller, Health, Inventory, Item, - ItemKey, Last, LightAnimation, LightEmitter, Ori, PhysicsState, PoiseState, Pos, Scale, - Vel, + Body, CharacterState, Collider, Controller, Health, Inventory, Item, ItemKey, Last, + LightAnimation, LightEmitter, Ori, PhysicsState, PoiseState, Pos, Scale, Vel, }, link::Is, mounting::Rider, @@ -6192,7 +6191,8 @@ impl FigureColLights { pub struct FigureStateMeta { lantern_offset: Option>, - abs_trail_points: Option<(anim::vek::Vec3, anim::vek::Vec3)>, + main_abs_trail_points: Option<(anim::vek::Vec3, anim::vek::Vec3)>, + off_abs_trail_points: Option<(anim::vek::Vec3, anim::vek::Vec3)>, // Animation to be applied to rider of this entity mount_transform: anim::vek::Transform, // Contains the position of this figure or if it is a rider it will contain the mount's @@ -6270,7 +6270,8 @@ impl FigureState { Self { meta: FigureStateMeta { lantern_offset: offsets.lantern, - abs_trail_points: None, + main_abs_trail_points: None, + off_abs_trail_points: None, mount_transform: offsets.mount_bone, mount_world_pos: anim::vek::Vec3::zero(), state_time: 0.0, @@ -6440,37 +6441,62 @@ impl FigureState { renderer.update_consts(&mut self.meta.bound.1, &new_bone_consts[0..S::BONE_COUNT]); self.lantern_offset = offsets.lantern; // Handle weapon trails - let weapon_offsets = offsets.weapon_trail_mat.map(|mat| { - let (trail_start, trail_end) = match tools.0 { - Some(ToolKind::Sword) => (20.25, 29.25), - // TODO: Make sure these are good positions, only did tweaking on sword - Some(ToolKind::Axe) => (10.0, 19.25), - Some(ToolKind::Hammer) => (10.0, 19.25), - _ => (0.0, 0.0), - }; - ( - (mat * anim::vek::Vec4::new(0.0, 0.0, trail_start, 1.0)).xyz(), - (mat * anim::vek::Vec4::new(0.0, 0.0, trail_end, 1.0)).xyz(), - ) - }); - let offsets_abs_trail_points = weapon_offsets.map(|(a, b)| (a + pos, b + pos)); - if let Some(trail_mgr) = trail_mgr { - if let Some(quad_mesh) = entity - .as_ref() - .and_then(|e| trail_mgr.entity_meshes.get_mut(e)) + fn handle_weapon_trails( + trail_mgr: &mut TrailMgr, + new_weapon_trail_mat: Option>, + old_abs_trail_points: &mut Option<(anim::vek::Vec3, anim::vek::Vec3)>, + entity: EcsEntity, + is_main_weapon: bool, + pos: anim::vek::Vec3, + tools: (Option, Option), + ) { + let weapon_offsets = new_weapon_trail_mat.map(|mat| { + let (trail_start, trail_end) = match tools.0 { + Some(ToolKind::Sword) => (20.25, 29.25), + // TODO: Make sure these are good positions, only did tweaking on sword + Some(ToolKind::Axe) => (10.0, 19.25), + Some(ToolKind::Hammer) => (10.0, 19.25), + _ => (0.0, 0.0), + }; + ( + (mat * anim::vek::Vec4::new(0.0, 0.0, trail_start, 1.0)).xyz(), + (mat * anim::vek::Vec4::new(0.0, 0.0, trail_end, 1.0)).xyz(), + ) + }); + let new_abs_trail_points = weapon_offsets.map(|(a, b)| (a + pos, b + pos)); + let trail_mgr_offset = trail_mgr.offset; + let quad_mesh = trail_mgr.entity_mesh_or_insert(entity, is_main_weapon); + if let (Some((p1, p2)), Some((p4, p3))) = (&old_abs_trail_points, new_abs_trail_points) { - if let (Some((p1, p2)), Some((p4, p3))) = - (self.abs_trail_points, offsets_abs_trail_points) - { - let vertex = |p: anim::vek::Vec3| trail::Vertex { - pos: p.into_array(), - }; - let quad = Quad::new(vertex(p1), vertex(p2), vertex(p3), vertex(p4)); - quad_mesh.replace_quad(trail_mgr.offset * 4, quad); - } + let vertex = |p: anim::vek::Vec3| trail::Vertex { + pos: p.into_array(), + }; + let quad = Quad::new(vertex(*p1), vertex(*p2), vertex(p3), vertex(p4)); + quad_mesh.replace_quad(trail_mgr_offset * 4, quad); } + *old_abs_trail_points = new_abs_trail_points; + } + + if let (Some(trail_mgr), Some(entity)) = (trail_mgr, entity) { + handle_weapon_trails( + trail_mgr, + offsets.main_weapon_trail_mat, + &mut self.main_abs_trail_points, + *entity, + true, + *pos, + *tools, + ); + handle_weapon_trails( + trail_mgr, + offsets.off_weapon_trail_mat, + &mut self.off_abs_trail_points, + *entity, + false, + *pos, + *tools, + ); } - self.abs_trail_points = offsets_abs_trail_points; // TODO: compute the mount bone only when it is needed self.mount_transform = offsets.mount_bone; diff --git a/voxygen/src/scene/figure/volume.rs b/voxygen/src/scene/figure/volume.rs index 6f07d76579..968c76e840 100644 --- a/voxygen/src/scene/figure/volume.rs +++ b/voxygen/src/scene/figure/volume.rs @@ -49,7 +49,8 @@ impl anim::Skeleton for VolumeKey { anim::Offsets { lantern: None, mount_bone: anim::vek::Transform::default(), - weapon_trail_mat: None, + main_weapon_trail_mat: None, + off_weapon_trail_mat: None, } } diff --git a/voxygen/src/scene/trail.rs b/voxygen/src/scene/trail.rs index 91fb7abb46..c148bf9e77 100644 --- a/voxygen/src/scene/trail.rs +++ b/voxygen/src/scene/trail.rs @@ -1,14 +1,19 @@ use super::SceneData; use crate::render::{DynamicModel, Mesh, Quad, Renderer, TrailDrawer, TrailVertex}; -use common::comp::CharacterState; use common_base::span; -use specs::{Entity as EcsEntity, Join, WorldExt}; +use specs::Entity as EcsEntity; use std::collections::HashMap; // use vek::*; +#[derive(Clone, Copy, Eq, PartialEq, Hash)] +struct MeshKey { + entity: EcsEntity, + is_main_weapon: bool, +} + pub struct TrailMgr { /// Meshes for each entity - pub entity_meshes: HashMap>, + entity_meshes: HashMap>, /// Offset pub offset: usize, @@ -47,7 +52,8 @@ impl TrailMgr { // Verts per quad are in b, c, a, d order vertices[i * 4 + 2] = vertices[i * 4 + 2] * TRAIL_SHRINKAGE + vertices[i * 4] * (1.0 - TRAIL_SHRINKAGE); - if i != (self.offset + TRAIL_DYNAMIC_MODEL_SIZE - 1) % TRAIL_DYNAMIC_MODEL_SIZE { + if i != (self.offset + TRAIL_DYNAMIC_MODEL_SIZE - 1) % TRAIL_DYNAMIC_MODEL_SIZE + { // 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); @@ -59,26 +65,9 @@ impl TrailMgr { mesh.replace_quad(self.offset * 4, Quad::new(zero, zero, zero, zero)); }); - // Create a mesh for each entity that doesn't already have one - let ecs = scene_data.state.ecs(); - for (entity, _char_state) in - (&ecs.entities(), &ecs.read_storage::()).join() - { - // Result returned doesn't matter, it just needs to only insert if entry didn't - // already exist - if let Ok(mesh) = self.entity_meshes.try_insert(entity, Mesh::new()) { - // Allocate up to necessary length so repalce_quad works as expected elsewhere - let zero = TrailVertex::zero(); - for _ in 0..TRAIL_DYNAMIC_MODEL_SIZE { - mesh.push_quad(Quad::new(zero, zero, zero, zero)); - } - } - } - - // Clear meshes for entities that no longer exist (is this even - // necessary? not sure if this growing too big is a concern) + // Clear meshes for entities that only have zero quads in mesh self.entity_meshes - .retain(|entity, _| ecs.entities().is_alive(*entity)); + .retain(|_, mesh| mesh.iter().any(|vert| *vert != TrailVertex::zero())); // Create dynamic model from currently existing meshes let mut big_mesh = Mesh::new(); @@ -111,4 +100,27 @@ impl TrailMgr { drawer.draw(&self.dynamic_model, self.model_len); } } + + pub fn entity_mesh_or_insert( + &mut self, + entity: EcsEntity, + is_main_weapon: bool, + ) -> &mut Mesh { + let key = MeshKey { + entity, + is_main_weapon, + }; + self.entity_meshes + .entry(key) + .or_insert_with(Self::default_trail_mesh) + } + + fn default_trail_mesh() -> Mesh { + 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 + } }