From f67bf2a539062681c6cceffc2ef1df82f6fa6075 Mon Sep 17 00:00:00 2001 From: Snowram Date: Sun, 25 Jul 2021 17:16:57 +0200 Subject: [PATCH] Adds arthropod skeleton --- assets/common/npc_names.ron | 16 +- .../voxel/arthropod_central_manifest.ron | 22 + .../voxel/arthropod_lateral_manifest.ron | 118 ++++++ common/src/cmd.rs | 1 + common/src/comp/agent.rs | 1 + common/src/comp/body.rs | 8 + common/src/comp/body/arthropod.rs | 66 +++ common/src/comp/fluid_dynamics.rs | 3 +- common/src/comp/inventory/loadout_builder.rs | 8 +- common/src/comp/mod.rs | 6 +- common/src/generation.rs | 1 + common/src/npc.rs | 13 +- common/src/states/utils.rs | 6 +- server/src/sys/agent.rs | 4 + voxygen/anim/src/arthropod/alpha.rs | 70 ++++ voxygen/anim/src/arthropod/idle.rs | 54 +++ voxygen/anim/src/arthropod/jump.rs | 53 +++ voxygen/anim/src/arthropod/mod.rs | 232 +++++++++++ voxygen/anim/src/arthropod/run.rs | 94 +++++ voxygen/anim/src/lib.rs | 1 + voxygen/egui/src/lib.rs | 1 + voxygen/src/scene/figure/load.rs | 379 ++++++++++++++++++ voxygen/src/scene/figure/mod.rs | 189 ++++++++- 23 files changed, 1337 insertions(+), 9 deletions(-) create mode 100644 assets/voxygen/voxel/arthropod_central_manifest.ron create mode 100644 assets/voxygen/voxel/arthropod_lateral_manifest.ron create mode 100644 common/src/comp/body/arthropod.rs create mode 100644 voxygen/anim/src/arthropod/alpha.rs create mode 100644 voxygen/anim/src/arthropod/idle.rs create mode 100644 voxygen/anim/src/arthropod/jump.rs create mode 100644 voxygen/anim/src/arthropod/mod.rs create mode 100644 voxygen/anim/src/arthropod/run.rs diff --git a/assets/common/npc_names.ron b/assets/common/npc_names.ron index a68091e6b1..ff318bed99 100644 --- a/assets/common/npc_names.ron +++ b/assets/common/npc_names.ron @@ -1207,5 +1207,19 @@ generic: "Deadwood" ), ) - ) + ), + arthropod: ( + body: ( + keyword: "arthropod", + names_0: [ + "Shelob" + ] + ), + species: ( + tarantula: ( + keyword: "tarantula", + generic: "Tarantula" + ) + ) + ), ) diff --git a/assets/voxygen/voxel/arthropod_central_manifest.ron b/assets/voxygen/voxel/arthropod_central_manifest.ron new file mode 100644 index 0000000000..f12fcedd2e --- /dev/null +++ b/assets/voxygen/voxel/arthropod_central_manifest.ron @@ -0,0 +1,22 @@ +({ + (Tarantula, Male): ( + head: ( + offset: (-4.5, 0.0, -5.0), + central: ("npc.tarantula.male.head"), + ), + chest: ( + offset: (-5.5, -2.0, -3.0), + central: ("npc.tarantula.male.chest"), + ), + ), + (Tarantula, Female): ( + head: ( + offset: (-4.5, 0.0, -5.0), + central: ("npc.tarantula.male.head"), + ), + chest: ( + offset: (-5.5, -2.0, -3.0), + central: ("npc.tarantula.male.chest"), + ), + ), +}) diff --git a/assets/voxygen/voxel/arthropod_lateral_manifest.ron b/assets/voxygen/voxel/arthropod_lateral_manifest.ron new file mode 100644 index 0000000000..382868e439 --- /dev/null +++ b/assets/voxygen/voxel/arthropod_lateral_manifest.ron @@ -0,0 +1,118 @@ +({ + (Tarantula, Male): ( + mandible_l: ( + offset: (-4.0, -2.0, -9.0), + lateral: ("npc.tarantula.male.mandible_l"), + ), + mandible_r: ( + offset: (0.0, -2.0, -9.0), + lateral: ("npc.tarantula.male.mandible_r"), + ), + wing_fl: ( + offset: (-6.0, -4.5, -8.0), + lateral: ("npc.tarantula.male.wing_fl"), + ), + wing_fr: ( + offset: (0.0, -4.5, -8.0), + lateral: ("npc.tarantula.male.wing_fr"), + ), + wing_bl: ( + offset: (-11.0, -1.0, -8.0), + lateral: ("npc.tarantula.male.wing_bl"), + ), + wing_br: ( + offset: (-11.0, -1.0, -8.0), + lateral: ("npc.tarantula.male.wing_br"), + ), + leg_fl: ( + offset: (0.0, -1.0, -8.0), + lateral: ("npc.tarantula.male.leg_fl"), + ), + leg_fr: ( + offset: (0.0, -1.0, -8.0), + lateral: ("npc.tarantula.male.leg_fr"), + ), + leg_fcl: ( + offset: (0.0, -1.0, -8.0), + lateral: ("npc.tarantula.male.leg_fbl"), + ), + leg_fcr: ( + offset: (0.0, -1.0, -8.0), + lateral: ("npc.tarantula.male.leg_fbr"), + ), + leg_bcl: ( + offset: (0.0, -1.0, -8.0), + lateral: ("npc.tarantula.male.leg_bcl"), + ), + leg_bcr: ( + offset: (0.0, -1.0, -8.0), + lateral: ("npc.tarantula.male.leg_bcr"), + ), + leg_bl: ( + offset: (0.0, -1.0, -8.0), + lateral: ("npc.tarantula.male.leg_bl"), + ), + leg_br: ( + offset: (0.0, -1.0, -8.0), + lateral: ("npc.tarantula.male.leg_br"), + ), + ), + (Tarantula, Female): ( + mandible_l: ( + offset: (-4.0, -2.0, -9.0), + lateral: ("npc.tarantula.male.mandible_l"), + ), + mandible_r: ( + offset: (0.0, -2.0, -9.0), + lateral: ("npc.tarantula.male.mandible_r"), + ), + wing_fl: ( + offset: (-6.0, -4.5, -8.0), + lateral: ("npc.tarantula.male.wing_fl"), + ), + wing_fr: ( + offset: (0.0, -4.5, -8.0), + lateral: ("npc.tarantula.male.wing_fr"), + ), + wing_bl: ( + offset: (-11.0, -1.0, -8.0), + lateral: ("npc.tarantula.male.wing_bl"), + ), + wing_br: ( + offset: (-11.0, -1.0, -8.0), + lateral: ("npc.tarantula.male.wing_br"), + ), + leg_fl: ( + offset: (0.0, -1.0, -8.0), + lateral: ("npc.tarantula.male.leg_fl"), + ), + leg_fr: ( + offset: (0.0, -1.0, -8.0), + lateral: ("npc.tarantula.male.leg_fr"), + ), + leg_fcl: ( + offset: (0.0, -1.0, -8.0), + lateral: ("npc.tarantula.male.leg_fbl"), + ), + leg_fcr: ( + offset: (0.0, -1.0, -8.0), + lateral: ("npc.tarantula.male.leg_fbr"), + ), + leg_bcl: ( + offset: (0.0, -1.0, -8.0), + lateral: ("npc.tarantula.male.leg_bcl"), + ), + leg_bcr: ( + offset: (0.0, -1.0, -8.0), + lateral: ("npc.tarantula.male.leg_bcr"), + ), + leg_bl: ( + offset: (0.0, -1.0, -8.0), + lateral: ("npc.tarantula.male.leg_bl"), + ), + leg_br: ( + offset: (0.0, -1.0, -8.0), + lateral: ("npc.tarantula.male.leg_br"), + ), + ), +}) diff --git a/common/src/cmd.rs b/common/src/cmd.rs index 02c78b683c..363aee8df0 100644 --- a/common/src/cmd.rs +++ b/common/src/cmd.rs @@ -172,6 +172,7 @@ lazy_static! { theropod, dragon, golem, + arthropod, ); souls diff --git a/common/src/comp/agent.rs b/common/src/comp/agent.rs index f092092a17..4cfcc39206 100644 --- a/common/src/comp/agent.rs +++ b/common/src/comp/agent.rs @@ -267,6 +267,7 @@ impl<'a> From<&'a Body> for Psyche { Body::Theropod(_) => 0.0, Body::Ship(_) => 0.0, Body::Dragon(_) => 0.0, + Body::Arthropod(_) => 1.0, }, sight_dist: 40.0, listen_dist: 30.0, diff --git a/common/src/comp/body.rs b/common/src/comp/body.rs index 33b7cb5b89..ae1f64590b 100644 --- a/common/src/comp/body.rs +++ b/common/src/comp/body.rs @@ -1,3 +1,4 @@ +pub mod arthropod; pub mod biped_large; pub mod biped_small; pub mod bird_large; @@ -48,6 +49,7 @@ make_case_elim!( Theropod(body: theropod::Body) = 12, QuadrupedLow(body: quadruped_low::Body) = 13, Ship(body: ship::Body) = 14, + Arthropod(body: arthropod::Body) = 15, } ); @@ -85,6 +87,7 @@ pub struct AllBodies { pub theropod: BodyData>, pub quadruped_low: BodyData>, pub ship: BodyData, + pub arthropod: BodyData>, } /// Can only retrieve body metadata by direct index. @@ -107,6 +110,7 @@ impl core::ops::Index for AllBodies &self.theropod.body, NpcKind::Reddragon => &self.dragon.body, NpcKind::Crocodile => &self.quadruped_low.body, + NpcKind::Tarantula => &self.arthropod.body, } } } @@ -132,6 +136,7 @@ impl<'a, BodyMeta, SpeciesMeta> core::ops::Index<&'a Body> for AllBodies &self.golem.body, Body::Theropod(_) => &self.theropod.body, Body::QuadrupedLow(_) => &self.quadruped_low.body, + Body::Arthropod(_) => &self.arthropod.body, Body::Ship(_) => &self.ship.body, } } @@ -290,6 +295,7 @@ impl Body { theropod::Species::Yale => 1_000.0, }, Body::Ship(ship) => ship.mass().0, + Body::Arthropod(body) => 500.0, }; Mass(m) } @@ -396,6 +402,7 @@ impl Body { theropod::Species::Woodraptor => Vec3::new(2.0, 3.0, 2.6), theropod::Species::Yale => Vec3::new(1.5, 3.2, 4.0), }, + Body::Arthropod(body) => Vec3::new(1.0, 1.0, 1.0), } } @@ -640,6 +647,7 @@ impl Body { quadruped_low::Species::Deadwood => 120, _ => 70, }, + Body::Arthropod(_) => 100, Body::Ship(_) => 1000, } } diff --git a/common/src/comp/body/arthropod.rs b/common/src/comp/body/arthropod.rs new file mode 100644 index 0000000000..682067bd71 --- /dev/null +++ b/common/src/comp/body/arthropod.rs @@ -0,0 +1,66 @@ +use rand::{seq::SliceRandom, thread_rng}; +use serde::{Deserialize, Serialize}; + +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] +pub struct Body { + pub species: Species, + pub body_type: BodyType, +} + +impl Body { + pub fn random() -> Self { + let mut rng = thread_rng(); + let species = *(&ALL_SPECIES).choose(&mut rng).unwrap(); + Self::random_with(&mut rng, &species) + } + + #[inline] + pub fn random_with(rng: &mut impl rand::Rng, &species: &Species) -> Self { + let body_type = *(&ALL_BODY_TYPES).choose(rng).unwrap(); + Self { species, body_type } + } +} + +impl From for super::Body { + fn from(body: Body) -> Self { super::Body::Arthropod(body) } +} + +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] +#[repr(u32)] +pub enum Species { + Tarantula = 0, +} + +/// Data representing per-species generic data. +#[derive(Clone, Debug, Serialize, Deserialize)] +pub struct AllSpecies { + pub tarantula: SpeciesMeta, +} + +impl<'a, SpeciesMeta> core::ops::Index<&'a Species> for AllSpecies { + type Output = SpeciesMeta; + + #[inline] + fn index(&self, &index: &'a Species) -> &Self::Output { + match index { + Species::Tarantula => &self.tarantula, + } + } +} + +pub const ALL_SPECIES: [Species; 1] = [Species::Tarantula]; + +impl<'a, SpeciesMeta: 'a> IntoIterator for &'a AllSpecies { + type IntoIter = std::iter::Copied>; + type Item = Species; + + fn into_iter(self) -> Self::IntoIter { ALL_SPECIES.iter().copied() } +} + +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] +#[repr(u32)] +pub enum BodyType { + Female = 0, + Male = 1, +} +pub const ALL_BODY_TYPES: [BodyType; 2] = [BodyType::Female, BodyType::Male]; diff --git a/common/src/comp/fluid_dynamics.rs b/common/src/comp/fluid_dynamics.rs index 1f6e2960ba..212e4ae198 100644 --- a/common/src/comp/fluid_dynamics.rs +++ b/common/src/comp/fluid_dynamics.rs @@ -229,7 +229,8 @@ impl Body { Body::Theropod(_) | Body::QuadrupedMedium(_) | Body::QuadrupedSmall(_) - | Body::QuadrupedLow(_) => { + | Body::QuadrupedLow(_) + | Body::Arthropod(_) => { let dim = self.dimensions().map(|a| a * 0.5); let cd: f32 = if matches!(self, Body::QuadrupedLow(_)) { 0.7 diff --git a/common/src/comp/inventory/loadout_builder.rs b/common/src/comp/inventory/loadout_builder.rs index 39110bb48c..4f8f60a1c9 100644 --- a/common/src/comp/inventory/loadout_builder.rs +++ b/common/src/comp/inventory/loadout_builder.rs @@ -3,7 +3,7 @@ use crate::{ assets::{self, AssetExt}, comp::{ - biped_large, biped_small, bird_large, golem, + arthropod, biped_large, biped_small, bird_large, golem, inventory::{ loadout::Loadout, slot::{ArmorSlot, EquipSlot}, @@ -265,6 +265,11 @@ fn default_main_tool(body: &Body) -> Item { "common.items.npc_weapons.unique.theropodbasic", )), }, + Body::Arthropod(arthropod) => match arthropod.species { + _ => Some(Item::new_from_asset_expect( + "common.items.npc_weapons.unique.theropodbasic", + )), + }, Body::BipedLarge(biped_large) => match (biped_large.species, biped_large.body_type) { (biped_large::Species::Occultsaurok, _) => Some(Item::new_from_asset_expect( "common.items.npc_weapons.staff.saurok_staff", @@ -752,6 +757,7 @@ mod tests { theropod: Theropod, dragon: Dragon, golem: Golem, + arthropod: Arthropod, ); } diff --git a/common/src/comp/mod.rs b/common/src/comp/mod.rs index eccf554684..5d45365138 100644 --- a/common/src/comp/mod.rs +++ b/common/src/comp/mod.rs @@ -59,9 +59,9 @@ pub use self::{ aura::{Aura, AuraChange, AuraKind, Auras}, beam::{Beam, BeamSegment}, body::{ - biped_large, biped_small, bird_large, bird_medium, dragon, fish_medium, fish_small, golem, - humanoid, object, quadruped_low, quadruped_medium, quadruped_small, ship, theropod, - AllBodies, Body, BodyData, + arthropod, biped_large, biped_small, bird_large, bird_medium, dragon, fish_medium, + fish_small, golem, humanoid, object, quadruped_low, quadruped_medium, quadruped_small, + ship, theropod, AllBodies, Body, BodyData, }, buff::{ Buff, BuffCategory, BuffChange, BuffData, BuffEffect, BuffId, BuffKind, BuffSource, Buffs, diff --git a/common/src/generation.rs b/common/src/generation.rs index 4837baa7a1..757eaf720f 100644 --- a/common/src/generation.rs +++ b/common/src/generation.rs @@ -406,6 +406,7 @@ impl EntityInfo { Body::QuadrupedLow(body) => Some(get_npc_name(&npc_names.quadruped_low, body.species)), Body::Golem(body) => Some(get_npc_name(&npc_names.golem, body.species)), Body::BipedLarge(body) => Some(get_npc_name(&npc_names.biped_large, body.species)), + Body::Arthropod(body) => Some(get_npc_name(&npc_names.arthropod, body.species)), _ => None, }; self.name = name.map(str::to_owned); diff --git a/common/src/npc.rs b/common/src/npc.rs index 5712c33696..1985d7f113 100644 --- a/common/src/npc.rs +++ b/common/src/npc.rs @@ -22,9 +22,10 @@ pub enum NpcKind { StoneGolem, Reddragon, Crocodile, + Tarantula, } -pub const ALL_NPCS: [NpcKind; 13] = [ +pub const ALL_NPCS: [NpcKind; 14] = [ NpcKind::Humanoid, NpcKind::Wolf, NpcKind::Pig, @@ -38,6 +39,7 @@ pub const ALL_NPCS: [NpcKind; 13] = [ NpcKind::StoneGolem, NpcKind::Reddragon, NpcKind::Crocodile, + NpcKind::Tarantula, ]; /// Body-specific NPC name metadata. @@ -133,6 +135,7 @@ pub fn kind_to_body(kind: NpcKind) -> Body { NpcKind::StoneGolem => comp::golem::Body::random().into(), NpcKind::Reddragon => comp::dragon::Body::random().into(), NpcKind::Crocodile => comp::quadruped_low::Body::random().into(), + NpcKind::Tarantula => comp::arthropod::Body::random().into(), } } @@ -303,6 +306,14 @@ impl NpcBody { comp::quadruped_low::Body::random_with, ) }) + .or_else(|| { + parse( + s, + NpcKind::Tarantula, + &npc_names.arthropod, + comp::arthropod::Body::random_with, + ) + }) .ok_or(()) } } diff --git a/common/src/states/utils.rs b/common/src/states/utils.rs index 9d0612290a..c9969989ff 100644 --- a/common/src/states/utils.rs +++ b/common/src/states/utils.rs @@ -2,7 +2,7 @@ use crate::{ astar::Astar, combat, comp::{ - biped_large, biped_small, + arthropod, biped_large, biped_small, character_state::OutputEvents, inventory::slot::{EquipSlot, Slot}, item::{Hands, ItemKind, Tool, ToolKind}, @@ -129,6 +129,7 @@ impl Body { quadruped_low::Species::Deadwood => 140.0, }, Body::Ship(_) => 0.0, + Body::Arthropod(_) => 135.0, } } @@ -186,6 +187,7 @@ impl Body { }, Body::Ship(ship) if ship.has_water_thrust() => 0.1, Body::Ship(_) => 0.035, + Body::Arthropod(_) => 3.5, } } @@ -214,6 +216,7 @@ impl Body { Body::QuadrupedSmall(_) => Some(300.0 * self.mass().0), Body::Ship(ship) if ship.has_water_thrust() => Some(3500.0 * self.mass().0), Body::Ship(_) => None, + Body::Arthropod(_) => Some(300.0 * self.mass().0), } } @@ -242,6 +245,7 @@ impl Body { | theropod::Species::Woodraptor => Some(0.4 * self.mass().0), _ => None, }, + Body::QuadrupedMedium(_) => Some(3.0 * self.mass().0), _ => Some(0.4 * self.mass().0), } .map(|f| f * GRAVITY) diff --git a/server/src/sys/agent.rs b/server/src/sys/agent.rs index 418287de3f..3fb63cd1ac 100644 --- a/server/src/sys/agent.rs +++ b/server/src/sys/agent.rs @@ -1692,6 +1692,7 @@ impl<'a> AgentData<'a> { "Quad Low Quick" => Tactic::QuadLowQuick, "Quad Low Basic" => Tactic::QuadLowBasic, "Theropod Basic" | "Theropod Bird" => Tactic::Theropod, + "Arthropod Basic" => Tactic::Arthropod, "Theropod Charge" => Tactic::CircleCharge { radius: 6, circle_time: 1, @@ -1968,6 +1969,9 @@ impl<'a> AgentData<'a> { Tactic::Theropod => { self.handle_theropod_attack(agent, controller, &attack_data, tgt_data, read_data) }, + Tactic::Arthropod => { + self.handle_arthropod_attack(agent, controller, &attack_data, tgt_data, read_data) + }, Tactic::Turret => { self.handle_turret_attack(agent, controller, &attack_data, tgt_data, read_data) }, diff --git a/voxygen/anim/src/arthropod/alpha.rs b/voxygen/anim/src/arthropod/alpha.rs new file mode 100644 index 0000000000..23ffab743a --- /dev/null +++ b/voxygen/anim/src/arthropod/alpha.rs @@ -0,0 +1,70 @@ +use super::{ + super::{vek::*, Animation}, + ArthropodSkeleton, SkeletonAttr, +}; +use common::states::utils::StageSection; + +pub struct AlphaAnimation; + +impl Animation for AlphaAnimation { + type Dependency<'a> = (f32, f32, Option, f32); + type Skeleton = ArthropodSkeleton; + + #[cfg(feature = "use-dyn-lib")] + const UPDATE_FN: &'static [u8] = b"arthropod_alpha\0"; + + #[cfg_attr(feature = "be-dyn-lib", export_name = "arthropod_alpha")] + fn update_skeleton_inner<'a>( + skeleton: &Self::Skeleton, + (_velocity, global_time, stage_section, timer): Self::Dependency<'a>, + anim_time: f32, + _rate: &mut f32, + s_a: &SkeletonAttr, + ) -> Self::Skeleton { + let mut next = (*skeleton).clone(); + + let (movement1base, movement2base, movement3) = match stage_section { + Some(StageSection::Buildup) => (anim_time.powi(2), 0.0, 0.0), + Some(StageSection::Swing) => (1.0, anim_time.powi(4), 0.0), + Some(StageSection::Recover) => (1.0, 1.0, anim_time), + _ => (0.0, 0.0, 0.0), + }; + let pullback = 1.0 - movement3; + let subtract = global_time - timer; + let check = subtract - subtract.trunc(); + let mirror = (check - 0.5).signum(); + let movement1 = mirror * movement1base * pullback; + let movement2 = mirror * movement2base * pullback; + let movement1abs = movement1base * pullback; + let movement2abs = movement2base * pullback; + + next.chest.scale = Vec3::one() / s_a.scaler; + + next.head.position = Vec3::new(0.0, s_a.head.0, s_a.head.1); + + next.chest.position = Vec3::new(0.0, s_a.chest.0, s_a.chest.1); + + next.mandible_l.position = Vec3::new(-s_a.mandible_l.0, s_a.mandible_l.1, s_a.mandible_l.2); + next.mandible_r.position = Vec3::new(s_a.mandible_r.0, s_a.mandible_r.1, s_a.mandible_r.2); + + next.wing_fl.position = Vec3::new(-s_a.wing_fl.0, s_a.wing_fl.1, s_a.wing_fl.2); + next.wing_fr.position = Vec3::new(s_a.wing_fr.0, s_a.wing_fr.1, s_a.wing_fr.2); + + next.wing_bl.position = Vec3::new(-s_a.wing_bl.0, s_a.wing_bl.1, s_a.wing_bl.2); + next.wing_br.position = Vec3::new(s_a.wing_br.0, s_a.wing_br.1, s_a.wing_br.2); + + next.leg_fl.position = Vec3::new(-s_a.leg_fl.0, s_a.leg_fl.1, s_a.leg_fl.2); + next.leg_fr.position = Vec3::new(s_a.leg_fr.0, s_a.leg_fr.1, s_a.leg_fr.2); + + next.leg_fcl.position = Vec3::new(-s_a.leg_fcl.0, s_a.leg_fcl.1, s_a.leg_fcl.2); + next.leg_fcr.position = Vec3::new(s_a.leg_fcr.0, s_a.leg_fcr.1, s_a.leg_fcr.2); + + next.leg_bcl.position = Vec3::new(-s_a.leg_bcl.0, s_a.leg_bcl.1, s_a.leg_bcl.2); + next.leg_bcr.position = Vec3::new(s_a.leg_bcr.0, s_a.leg_bcr.1, s_a.leg_bcr.2); + + next.leg_bl.position = Vec3::new(-s_a.leg_bl.0, s_a.leg_bl.1, s_a.leg_bl.2); + next.leg_br.position = Vec3::new(s_a.leg_br.0, s_a.leg_br.1, s_a.leg_br.2); + + next + } +} diff --git a/voxygen/anim/src/arthropod/idle.rs b/voxygen/anim/src/arthropod/idle.rs new file mode 100644 index 0000000000..057ea079b9 --- /dev/null +++ b/voxygen/anim/src/arthropod/idle.rs @@ -0,0 +1,54 @@ +use super::{super::Animation, ArthropodSkeleton, SkeletonAttr}; +//use std::{f32::consts::PI, ops::Mul}; +use super::super::vek::*; +use std::ops::Mul; + +pub struct IdleAnimation; + +impl Animation for IdleAnimation { + type Dependency<'a> = f32; + type Skeleton = ArthropodSkeleton; + + #[cfg(feature = "use-dyn-lib")] + const UPDATE_FN: &'static [u8] = b"arthropod_idle\0"; + + #[cfg_attr(feature = "be-dyn-lib", export_name = "arthropod_idle")] + fn update_skeleton_inner<'a>( + skeleton: &Self::Skeleton, + global_time: Self::Dependency<'a>, + anim_time: f32, + _rate: &mut f32, + s_a: &SkeletonAttr, + ) -> Self::Skeleton { + let mut next = (*skeleton).clone(); + + next.chest.scale = Vec3::one() / s_a.scaler; + + next.head.position = Vec3::new(0.0, s_a.head.0, s_a.head.1); + + next.chest.position = Vec3::new(0.0, s_a.chest.0, s_a.chest.1); + + next.mandible_l.position = Vec3::new(-s_a.mandible_l.0, s_a.mandible_l.1, s_a.mandible_l.2); + next.mandible_r.position = Vec3::new(s_a.mandible_r.0, s_a.mandible_r.1, s_a.mandible_r.2); + + next.wing_fl.position = Vec3::new(-s_a.wing_fl.0, s_a.wing_fl.1, s_a.wing_fl.2); + next.wing_fr.position = Vec3::new(s_a.wing_fr.0, s_a.wing_fr.1, s_a.wing_fr.2); + + next.wing_bl.position = Vec3::new(-s_a.wing_bl.0, s_a.wing_bl.1, s_a.wing_bl.2); + next.wing_br.position = Vec3::new(s_a.wing_br.0, s_a.wing_br.1, s_a.wing_br.2); + + next.leg_fl.position = Vec3::new(-s_a.leg_fl.0, s_a.leg_fl.1, s_a.leg_fl.2); + next.leg_fr.position = Vec3::new(s_a.leg_fr.0, s_a.leg_fr.1, s_a.leg_fr.2); + + next.leg_fcl.position = Vec3::new(-s_a.leg_fcl.0, s_a.leg_fcl.1, s_a.leg_fcl.2); + next.leg_fcr.position = Vec3::new(s_a.leg_fcr.0, s_a.leg_fcr.1, s_a.leg_fcr.2); + + next.leg_bcl.position = Vec3::new(-s_a.leg_bcl.0, s_a.leg_bcl.1, s_a.leg_bcl.2); + next.leg_bcr.position = Vec3::new(s_a.leg_bcr.0, s_a.leg_bcr.1, s_a.leg_bcr.2); + + next.leg_bl.position = Vec3::new(-s_a.leg_bl.0, s_a.leg_bl.1, s_a.leg_bl.2); + next.leg_br.position = Vec3::new(s_a.leg_br.0, s_a.leg_br.1, s_a.leg_br.2); + + next + } +} diff --git a/voxygen/anim/src/arthropod/jump.rs b/voxygen/anim/src/arthropod/jump.rs new file mode 100644 index 0000000000..a873962f29 --- /dev/null +++ b/voxygen/anim/src/arthropod/jump.rs @@ -0,0 +1,53 @@ +use super::{super::Animation, ArthropodSkeleton, SkeletonAttr}; +//use std::f32::consts::PI; +use super::super::vek::*; + +pub struct JumpAnimation; + +impl Animation for JumpAnimation { + type Dependency<'a> = (f32, Vec3, Vec3, f32, Vec3); + type Skeleton = ArthropodSkeleton; + + #[cfg(feature = "use-dyn-lib")] + const UPDATE_FN: &'static [u8] = b"arthropod_jump\0"; + + #[cfg_attr(feature = "be-dyn-lib", export_name = "arthropod_jump")] + fn update_skeleton_inner<'a>( + skeleton: &Self::Skeleton, + (_velocity, _orientation, _last_ori, _global_time, _avg_vel): Self::Dependency<'a>, + _anim_time: f32, + _rate: &mut f32, + s_a: &SkeletonAttr, + ) -> Self::Skeleton { + let mut next = (*skeleton).clone(); + + next.chest.scale = Vec3::one() / s_a.scaler; + + next.head.position = Vec3::new(0.0, s_a.head.0, s_a.head.1); + + next.chest.position = Vec3::new(0.0, s_a.chest.0, s_a.chest.1); + + next.mandible_l.position = Vec3::new(-s_a.mandible_l.0, s_a.mandible_l.1, s_a.mandible_l.2); + next.mandible_r.position = Vec3::new(s_a.mandible_r.0, s_a.mandible_r.1, s_a.mandible_r.2); + + next.wing_fl.position = Vec3::new(-s_a.wing_fl.0, s_a.wing_fl.1, s_a.wing_fl.2); + next.wing_fr.position = Vec3::new(s_a.wing_fr.0, s_a.wing_fr.1, s_a.wing_fr.2); + + next.wing_bl.position = Vec3::new(-s_a.wing_bl.0, s_a.wing_bl.1, s_a.wing_bl.2); + next.wing_br.position = Vec3::new(s_a.wing_br.0, s_a.wing_br.1, s_a.wing_br.2); + + next.leg_fl.position = Vec3::new(-s_a.leg_fl.0, s_a.leg_fl.1, s_a.leg_fl.2); + next.leg_fr.position = Vec3::new(s_a.leg_fr.0, s_a.leg_fr.1, s_a.leg_fr.2); + + next.leg_fcl.position = Vec3::new(-s_a.leg_fcl.0, s_a.leg_fcl.1, s_a.leg_fcl.2); + next.leg_fcr.position = Vec3::new(s_a.leg_fcr.0, s_a.leg_fcr.1, s_a.leg_fcr.2); + + next.leg_bcl.position = Vec3::new(-s_a.leg_bcl.0, s_a.leg_bcl.1, s_a.leg_bcl.2); + next.leg_bcr.position = Vec3::new(s_a.leg_bcr.0, s_a.leg_bcr.1, s_a.leg_bcr.2); + + next.leg_bl.position = Vec3::new(-s_a.leg_bl.0, s_a.leg_bl.1, s_a.leg_bl.2); + next.leg_br.position = Vec3::new(s_a.leg_br.0, s_a.leg_br.1, s_a.leg_br.2); + + next + } +} diff --git a/voxygen/anim/src/arthropod/mod.rs b/voxygen/anim/src/arthropod/mod.rs new file mode 100644 index 0000000000..587ff46871 --- /dev/null +++ b/voxygen/anim/src/arthropod/mod.rs @@ -0,0 +1,232 @@ +pub mod alpha; +pub mod idle; +pub mod jump; +pub mod run; + +// Reexports +pub use self::{ + alpha::AlphaAnimation, idle::IdleAnimation, jump::JumpAnimation, run::RunAnimation, +}; + +use super::{make_bone, vek::*, FigureBoneData, Offsets, Skeleton}; +use common::comp::{self}; +use core::convert::TryFrom; + +pub type Body = comp::arthropod::Body; + +skeleton_impls!(struct ArthropodSkeleton { + + head, + + chest, + + mandible_l, + + mandible_r, + + wing_fl, + + wing_fr, + + wing_bl, + + wing_br, + + leg_fl, + + leg_fr, + + leg_fcl, + + leg_fcr, + + leg_bcl, + + leg_bcr, + + leg_bl, + + leg_br, +}); + +impl Skeleton for ArthropodSkeleton { + type Attr = SkeletonAttr; + type Body = Body; + + const BONE_COUNT: usize = 16; + #[cfg(feature = "use-dyn-lib")] + const COMPUTE_FN: &'static [u8] = b"arthropod_compute_s\0"; + + #[cfg_attr(feature = "be-dyn-lib", export_name = "arthropod_compute_s")] + + fn compute_matrices_inner( + &self, + base_mat: Mat4, + buf: &mut [FigureBoneData; super::MAX_BONE_COUNT], + body: Self::Body, + ) -> Offsets { + let chest_mat = base_mat * Mat4::::from(self.chest); + let head_mat = chest_mat * Mat4::::from(self.head); + let mandible_l_mat = head_mat * Mat4::::from(self.mandible_l); + let mandible_r_mat = head_mat * Mat4::::from(self.mandible_r); + let wing_fl_mat = chest_mat * Mat4::::from(self.wing_fl); + let wing_fr_mat = chest_mat * Mat4::::from(self.wing_fr); + let wing_bl_mat = chest_mat * Mat4::::from(self.wing_bl); + let wing_br_mat = chest_mat * Mat4::::from(self.wing_br); + let leg_fl_mat = chest_mat * Mat4::::from(self.leg_fl); + let leg_fr_mat = chest_mat * Mat4::::from(self.leg_fr); + let leg_fcl_mat = chest_mat * Mat4::::from(self.leg_fcl); + let leg_fcr_mat = chest_mat * Mat4::::from(self.leg_fcr); + let leg_bcl_mat = chest_mat * Mat4::::from(self.leg_bcl); + let leg_bcr_mat = chest_mat * Mat4::::from(self.leg_bcr); + let leg_bl_mat = chest_mat * Mat4::::from(self.leg_bl); + let leg_br_mat = chest_mat * Mat4::::from(self.leg_br); + + *(<&mut [_; Self::BONE_COUNT]>::try_from(&mut buf[0..Self::BONE_COUNT]).unwrap()) = [ + make_bone(head_mat), + make_bone(chest_mat), + make_bone(mandible_l_mat), + make_bone(mandible_r_mat), + make_bone(wing_fl_mat), + make_bone(wing_fr_mat), + make_bone(wing_bl_mat), + make_bone(wing_br_mat), + make_bone(leg_fl_mat), + make_bone(leg_fr_mat), + make_bone(leg_fcl_mat), + make_bone(leg_fcr_mat), + make_bone(leg_bcl_mat), + make_bone(leg_bcr_mat), + make_bone(leg_bl_mat), + make_bone(leg_br_mat), + ]; + + use comp::arthropod::Species::*; + let (mount_bone_mat, mount_bone_ori) = match (body.species, body.body_type) { + _ => (chest_mat, self.chest.orientation), + }; + // Offset from the mounted bone's origin. + // Note: This could be its own bone if we need to animate it independently. + let mount_position = (mount_bone_mat * Vec4::from_point(mount_point(&body))) + .homogenized() + .xyz(); + // NOTE: We apply the ori from base_mat externally so we don't need to worry + // about it here for now. + let mount_orientation = mount_bone_ori; + + Offsets { + lantern: None, + mount_bone: Transform { + position: mount_position, + orientation: mount_orientation, + scale: Vec3::one(), + }, + } + } +} + +pub struct SkeletonAttr { + head: (f32, f32), + chest: (f32, f32), + mandible_l: (f32, f32, f32), + mandible_r: (f32, f32, f32), + wing_fl: (f32, f32, f32), + wing_fr: (f32, f32, f32), + wing_bl: (f32, f32, f32), + wing_br: (f32, f32, f32), + leg_fl: (f32, f32, f32), + leg_fr: (f32, f32, f32), + leg_fcl: (f32, f32, f32), + leg_fcr: (f32, f32, f32), + leg_bcl: (f32, f32, f32), + leg_bcr: (f32, f32, f32), + leg_bl: (f32, f32, f32), + leg_br: (f32, f32, f32), + scaler: f32, +} + +impl<'a> std::convert::TryFrom<&'a comp::Body> for SkeletonAttr { + type Error = (); + + fn try_from(body: &'a comp::Body) -> Result { + match body { + comp::Body::Arthropod(body) => Ok(SkeletonAttr::from(body)), + _ => Err(()), + } + } +} + +impl Default for SkeletonAttr { + fn default() -> Self { + Self { + head: (0.0, 0.0), + chest: (0.0, 0.0), + mandible_l: (0.0, 0.0, 0.0), + mandible_r: (0.0, 0.0, 0.0), + wing_fl: (0.0, 0.0, 0.0), + wing_fr: (0.0, 0.0, 0.0), + wing_bl: (0.0, 0.0, 0.0), + wing_br: (0.0, 0.0, 0.0), + leg_fl: (0.0, 0.0, 0.0), + leg_fr: (0.0, 0.0, 0.0), + leg_fcl: (0.0, 0.0, 0.0), + leg_fcr: (0.0, 0.0, 0.0), + leg_bcl: (0.0, 0.0, 0.0), + leg_bcr: (0.0, 0.0, 0.0), + leg_bl: (0.0, 0.0, 0.0), + leg_br: (0.0, 0.0, 0.0), + scaler: 0.0, + } + } +} + +impl<'a> From<&'a Body> for SkeletonAttr { + fn from(body: &'a Body) -> Self { + use comp::arthropod::Species::*; + Self { + head: match (body.species, body.body_type) { + (Tarantula, _) => (8.0, 4.0), + }, + chest: match (body.species, body.body_type) { + (Tarantula, _) => (1.0, -7.0), + }, + mandible_l: match (body.species, body.body_type) { + (Tarantula, _) => (3.0, 0.0, -4.0), + }, + mandible_r: match (body.species, body.body_type) { + (Tarantula, _) => (3.0, 0.0, -4.0), + }, + wing_fl: match (body.species, body.body_type) { + (Tarantula, _) => (3.0, 0.0, -4.0), + }, + wing_fr: match (body.species, body.body_type) { + (Tarantula, _) => (3.0, 0.0, -4.0), + }, + wing_bl: match (body.species, body.body_type) { + (Tarantula, _) => (3.0, 0.0, -4.0), + }, + wing_br: match (body.species, body.body_type) { + (Tarantula, _) => (3.0, 0.0, -4.0), + }, + leg_fl: match (body.species, body.body_type) { + (Tarantula, _) => (2.5, -3.0, -4.0), + }, + leg_fr: match (body.species, body.body_type) { + (Tarantula, _) => (3.0, -0.5, -7.0), + }, + leg_fcl: match (body.species, body.body_type) { + (Tarantula, _) => (2.5, -3.0, -4.0), + }, + leg_fcr: match (body.species, body.body_type) { + (Tarantula, _) => (3.0, -0.5, -7.0), + }, + leg_bcl: match (body.species, body.body_type) { + (Tarantula, _) => (2.5, -3.0, -4.0), + }, + leg_bcr: match (body.species, body.body_type) { + (Tarantula, _) => (3.0, -0.5, -7.0), + }, + leg_bl: match (body.species, body.body_type) { + (Tarantula, _) => (2.5, -3.0, -4.0), + }, + leg_br: match (body.species, body.body_type) { + (Tarantula, _) => (3.0, -0.5, -7.0), + }, + scaler: match (body.species, body.body_type) { + (Tarantula, _) => (1.0), + }, + } + } +} + +fn mount_point(body: &Body) -> Vec3 { + use comp::arthropod::{BodyType::*, Species::*}; + match (body.species, body.body_type) { + (_, _) => (0.0, -6.0, 6.0), + } + .into() +} diff --git a/voxygen/anim/src/arthropod/run.rs b/voxygen/anim/src/arthropod/run.rs new file mode 100644 index 0000000000..64ea5eedea --- /dev/null +++ b/voxygen/anim/src/arthropod/run.rs @@ -0,0 +1,94 @@ +use super::{super::Animation, ArthropodSkeleton, SkeletonAttr}; +//use std::{f32::consts::PI, ops::Mul}; +use super::super::vek::*; +use std::f32::consts::{FRAC_PI_2, PI}; + +pub struct RunAnimation; + +impl Animation for RunAnimation { + type Dependency<'a> = (Vec3, Vec3, Vec3, f32, Vec3, f32); + type Skeleton = ArthropodSkeleton; + + #[cfg(feature = "use-dyn-lib")] + const UPDATE_FN: &'static [u8] = b"arthropod_run\0"; + + #[cfg_attr(feature = "be-dyn-lib", export_name = "arthropod_run")] + fn update_skeleton_inner<'a>( + skeleton: &Self::Skeleton, + (velocity, orientation, last_ori, _global_time, avg_vel, acc_vel): Self::Dependency<'a>, + anim_time: f32, + rate: &mut f32, + s_a: &SkeletonAttr, + ) -> Self::Skeleton { + let mut next = (*skeleton).clone(); + let speed = (Vec2::::from(velocity).magnitude()).min(22.0); + *rate = 1.0; + + //let speednorm = speed / 13.0; + let speednorm = (speed / 13.0).powf(0.25); + let mixed_vel = acc_vel + anim_time * 6.0; //sets run frequency using speed, with anim_time setting a floor + + let speedmult = 1.0; + let lab: f32 = 0.6; //6 + + let short = ((1.0 + / (0.72 + + 0.28 * ((mixed_vel * 1.0 * lab * speedmult + PI * -0.15 - 0.5).sin()).powi(2))) + .sqrt()) + * ((mixed_vel * 1.0 * lab * speedmult + PI * -0.15 - 0.5).sin()) + * speednorm; + + // + let shortalt = (mixed_vel * 1.0 * lab * speedmult + PI * 3.0 / 8.0 - 0.5).sin() * speednorm; + + //FL + let foot1a = (mixed_vel * 1.0 * lab * speedmult + 0.0 + PI).sin() * speednorm; //1.5 + let foot1b = (mixed_vel * 1.0 * lab * speedmult + FRAC_PI_2 + PI).sin() * speednorm; //1.9 + //FR + let foot2a = (mixed_vel * 1.0 * lab * speedmult).sin() * speednorm; //1.2 + let foot2b = (mixed_vel * 1.0 * lab * speedmult + FRAC_PI_2).sin() * speednorm; //1.6 + let ori: Vec2 = Vec2::from(orientation); + let last_ori = Vec2::from(last_ori); + let tilt = if ::vek::Vec2::new(ori, last_ori) + .map(|o| o.magnitude_squared()) + .map(|m| m > 0.001 && m.is_finite()) + .reduce_and() + && ori.angle_between(last_ori).is_finite() + { + ori.angle_between(last_ori).min(0.2) + * last_ori.determine_side(Vec2::zero(), ori).signum() + } else { + 0.0 + } * 1.3; + let x_tilt = avg_vel.z.atan2(avg_vel.xy().magnitude()) * speednorm; + + next.chest.scale = Vec3::one() / s_a.scaler; + + next.head.position = Vec3::new(0.0, s_a.head.0, s_a.head.1); + + next.chest.position = Vec3::new(0.0, s_a.chest.0, s_a.chest.1); + + next.mandible_l.position = Vec3::new(-s_a.mandible_l.0, s_a.mandible_l.1, s_a.mandible_l.2); + next.mandible_r.position = Vec3::new(s_a.mandible_r.0, s_a.mandible_r.1, s_a.mandible_r.2); + + next.wing_fl.position = Vec3::new(-s_a.wing_fl.0, s_a.wing_fl.1, s_a.wing_fl.2); + next.wing_fr.position = Vec3::new(s_a.wing_fr.0, s_a.wing_fr.1, s_a.wing_fr.2); + + next.wing_bl.position = Vec3::new(-s_a.wing_bl.0, s_a.wing_bl.1, s_a.wing_bl.2); + next.wing_br.position = Vec3::new(s_a.wing_br.0, s_a.wing_br.1, s_a.wing_br.2); + + next.leg_fl.position = Vec3::new(-s_a.leg_fl.0, s_a.leg_fl.1, s_a.leg_fl.2); + next.leg_fr.position = Vec3::new(s_a.leg_fr.0, s_a.leg_fr.1, s_a.leg_fr.2); + + next.leg_fcl.position = Vec3::new(-s_a.leg_fcl.0, s_a.leg_fcl.1, s_a.leg_fcl.2); + next.leg_fcr.position = Vec3::new(s_a.leg_fcr.0, s_a.leg_fcr.1, s_a.leg_fcr.2); + + next.leg_bcl.position = Vec3::new(-s_a.leg_bcl.0, s_a.leg_bcl.1, s_a.leg_bcl.2); + next.leg_bcr.position = Vec3::new(s_a.leg_bcr.0, s_a.leg_bcr.1, s_a.leg_bcr.2); + + next.leg_bl.position = Vec3::new(-s_a.leg_bl.0, s_a.leg_bl.1, s_a.leg_bl.2); + next.leg_br.position = Vec3::new(s_a.leg_br.0, s_a.leg_br.1, s_a.leg_br.2); + + next + } +} diff --git a/voxygen/anim/src/lib.rs b/voxygen/anim/src/lib.rs index dfe3ac86d2..f60ca96751 100644 --- a/voxygen/anim/src/lib.rs +++ b/voxygen/anim/src/lib.rs @@ -47,6 +47,7 @@ macro_rules! skeleton_impls { } } +pub mod arthropod; pub mod biped_large; pub mod biped_small; pub mod bird_large; diff --git a/voxygen/egui/src/lib.rs b/voxygen/egui/src/lib.rs index 8c80955a42..d1233d462c 100644 --- a/voxygen/egui/src/lib.rs +++ b/voxygen/egui/src/lib.rs @@ -716,6 +716,7 @@ fn body_species(body: &Body) -> String { Body::Golem(body) => format!("{:?}", body.species), Body::Theropod(body) => format!("{:?}", body.species), Body::QuadrupedLow(body) => format!("{:?}", body.species), + Body::Arthropod(body) => format!("{:?}", body.species), Body::Ship(body) => format!("{:?}", body), } } diff --git a/voxygen/src/scene/figure/load.rs b/voxygen/src/scene/figure/load.rs index 084eb5b301..684a279cd7 100644 --- a/voxygen/src/scene/figure/load.rs +++ b/voxygen/src/scene/figure/load.rs @@ -2,6 +2,7 @@ use super::cache::{FigureKey, ToolKey}; use common::{ assets::{self, AssetExt, AssetHandle, DotVoxAsset, ReloadWatcher, Ron}, comp::{ + arthropod::{self, BodyType as ABodyType, Species as ASpecies}, biped_large::{self, BodyType as BLBodyType, Species as BLSpecies}, biped_small, bird_large::{self, BodyType as BLABodyType, Species as BLASpecies}, @@ -2151,6 +2152,384 @@ impl TheropodLateralSpec { (lateral, Vec3::from(spec.foot_r.offset)) } } + +//// +#[derive(Deserialize)] +struct ArthropodCentralSpec(HashMap<(ASpecies, ABodyType), SidedACentralVoxSpec>); + +#[derive(Deserialize)] +struct SidedACentralVoxSpec { + head: ArthropodCentralSubSpec, + chest: ArthropodCentralSubSpec, +} +#[derive(Deserialize)] +struct ArthropodCentralSubSpec { + offset: [f32; 3], // Should be relative to initial origin + central: VoxSimple, +} +#[derive(Deserialize)] +struct ArthropodLateralSpec(HashMap<(ASpecies, ABodyType), SidedALateralVoxSpec>); + +#[derive(Deserialize)] +struct SidedALateralVoxSpec { + mandible_l: ArthropodLateralSubSpec, + mandible_r: ArthropodLateralSubSpec, + wing_fl: ArthropodLateralSubSpec, + wing_fr: ArthropodLateralSubSpec, + wing_bl: ArthropodLateralSubSpec, + wing_br: ArthropodLateralSubSpec, + leg_fl: ArthropodLateralSubSpec, + leg_fr: ArthropodLateralSubSpec, + leg_fcl: ArthropodLateralSubSpec, + leg_fcr: ArthropodLateralSubSpec, + leg_bcl: ArthropodLateralSubSpec, + leg_bcr: ArthropodLateralSubSpec, + leg_bl: ArthropodLateralSubSpec, + leg_br: ArthropodLateralSubSpec, +} +#[derive(Deserialize)] +struct ArthropodLateralSubSpec { + offset: [f32; 3], // Should be relative to initial origin + lateral: VoxSimple, +} +make_vox_spec!( + arthropod::Body, + struct ArthropodSpec { + central: ArthropodCentralSpec = "voxygen.voxel.Arthropod_central_manifest", + lateral: ArthropodLateralSpec = "voxygen.voxel.Arthropod_lateral_manifest", + }, + |FigureKey { body, .. }, spec| { + [ + Some(spec.central.read().0.mesh_head( + body.species, + body.body_type, + )), + Some(spec.central.read().0.mesh_chest( + body.species, + body.body_type, + )), + Some(spec.lateral.read().0.mesh_mandible_l( + body.species, + body.body_type, + )), + Some(spec.lateral.read().0.mesh_mandible_r( + body.species, + body.body_type, + )), + Some(spec.lateral.read().0.mesh_wing_fl( + body.species, + body.body_type, + )), + Some(spec.lateral.read().0.mesh_wing_fr( + body.species, + body.body_type, + )), + Some(spec.lateral.read().0.mesh_wing_bl( + body.species, + body.body_type, + )), + Some(spec.lateral.read().0.mesh_wing_br( + body.species, + body.body_type, + )), + Some(spec.lateral.read().0.mesh_leg_fl( + body.species, + body.body_type, + )), + Some(spec.lateral.read().0.mesh_leg_fr( + body.species, + body.body_type, + )), + Some(spec.lateral.read().0.mesh_leg_fcl( + body.species, + body.body_type, + )), + Some(spec.lateral.read().0.mesh_leg_fcr( + body.species, + body.body_type, + )), + Some(spec.lateral.read().0.mesh_leg_bcl( + body.species, + body.body_type, + )), + Some(spec.lateral.read().0.mesh_leg_bcr( + body.species, + body.body_type, + )), + Some(spec.lateral.read().0.mesh_leg_bl( + body.species, + body.body_type, + )), + Some(spec.lateral.read().0.mesh_leg_br( + body.species, + body.body_type, + )), + ] + }, +); + +impl ArthropodCentralSpec { + fn mesh_head(&self, species: ASpecies, body_type: ABodyType) -> BoneMeshes { + let spec = match self.0.get(&(species, body_type)) { + Some(spec) => spec, + None => { + error!( + "No head specification exists for the combination of {:?} and {:?}", + species, body_type + ); + return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5)); + }, + }; + let central = graceful_load_segment(&spec.head.central.0); + + (central, Vec3::from(spec.head.offset)) + } + + fn mesh_chest(&self, species: ASpecies, body_type: ABodyType) -> BoneMeshes { + let spec = match self.0.get(&(species, body_type)) { + Some(spec) => spec, + None => { + error!( + "No chest specification exists for the combination of {:?} and {:?}", + species, body_type + ); + return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5)); + }, + }; + let central = graceful_load_segment(&spec.chest.central.0); + + (central, Vec3::from(spec.chest.offset)) + } +} +impl ArthropodLateralSpec { + fn mesh_mandible_l(&self, species: ASpecies, body_type: ABodyType) -> BoneMeshes { + let spec = match self.0.get(&(species, body_type)) { + Some(spec) => spec, + None => { + error!( + "No left mandible specification exists for the combination of {:?} and {:?}", + species, body_type + ); + return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5)); + }, + }; + let lateral = graceful_load_segment_flipped(&spec.mandible_l.lateral.0, true); + + (lateral, Vec3::from(spec.mandible_l.offset)) + } + + fn mesh_mandible_r(&self, species: ASpecies, body_type: ABodyType) -> BoneMeshes { + let spec = match self.0.get(&(species, body_type)) { + Some(spec) => spec, + None => { + error!( + "No right mandible specification exists for the combination of {:?} and {:?}", + species, body_type + ); + return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5)); + }, + }; + let lateral = graceful_load_segment(&spec.mandible_r.lateral.0); + + (lateral, Vec3::from(spec.mandible_r.offset)) + } + + fn mesh_wing_fl(&self, species: ASpecies, body_type: ABodyType) -> BoneMeshes { + let spec = match self.0.get(&(species, body_type)) { + Some(spec) => spec, + None => { + error!( + "No front left wing specification exists for the combination of {:?} and {:?}", + species, body_type + ); + return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5)); + }, + }; + let lateral = graceful_load_segment_flipped(&spec.wing_fl.lateral.0, true); + + (lateral, Vec3::from(spec.wing_fl.offset)) + } + + fn mesh_wing_fr(&self, species: ASpecies, body_type: ABodyType) -> BoneMeshes { + let spec = match self.0.get(&(species, body_type)) { + Some(spec) => spec, + None => { + error!( + "No front right wing specification exists for the combination of {:?} and {:?}", + species, body_type + ); + return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5)); + }, + }; + let lateral = graceful_load_segment(&spec.wing_fr.lateral.0); + + (lateral, Vec3::from(spec.wing_fr.offset)) + } + + fn mesh_wing_bl(&self, species: ASpecies, body_type: ABodyType) -> BoneMeshes { + let spec = match self.0.get(&(species, body_type)) { + Some(spec) => spec, + None => { + error!( + "No back left wing specification exists for the combination of {:?} and {:?}", + species, body_type + ); + return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5)); + }, + }; + let lateral = graceful_load_segment_flipped(&spec.wing_bl.lateral.0, true); + + (lateral, Vec3::from(spec.wing_bl.offset)) + } + + fn mesh_wing_br(&self, species: ASpecies, body_type: ABodyType) -> BoneMeshes { + let spec = match self.0.get(&(species, body_type)) { + Some(spec) => spec, + None => { + error!( + "No back right wing specification exists for the combination of {:?} and {:?}", + species, body_type + ); + return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5)); + }, + }; + let lateral = graceful_load_segment(&spec.wing_br.lateral.0); + + (lateral, Vec3::from(spec.wing_br.offset)) + } + + fn mesh_leg_fl(&self, species: ASpecies, body_type: ABodyType) -> BoneMeshes { + let spec = match self.0.get(&(species, body_type)) { + Some(spec) => spec, + None => { + error!( + "No front left leg specification exists for the combination of {:?} and {:?}", + species, body_type + ); + return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5)); + }, + }; + let lateral = graceful_load_segment_flipped(&spec.leg_fl.lateral.0, true); + + (lateral, Vec3::from(spec.leg_fl.offset)) + } + + fn mesh_leg_fr(&self, species: ASpecies, body_type: ABodyType) -> BoneMeshes { + let spec = match self.0.get(&(species, body_type)) { + Some(spec) => spec, + None => { + error!( + "No front right leg specification exists for the combination of {:?} and {:?}", + species, body_type + ); + return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5)); + }, + }; + let lateral = graceful_load_segment(&spec.leg_fr.lateral.0); + + (lateral, Vec3::from(spec.leg_fr.offset)) + } + + fn mesh_leg_fcl(&self, species: ASpecies, body_type: ABodyType) -> BoneMeshes { + let spec = match self.0.get(&(species, body_type)) { + Some(spec) => spec, + None => { + error!( + "No front center left leg specification exists for the combination of {:?} \ + and {:?}", + species, body_type + ); + return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5)); + }, + }; + let lateral = graceful_load_segment_flipped(&spec.leg_fcl.lateral.0, true); + + (lateral, Vec3::from(spec.leg_fcl.offset)) + } + + fn mesh_leg_fcr(&self, species: ASpecies, body_type: ABodyType) -> BoneMeshes { + let spec = match self.0.get(&(species, body_type)) { + Some(spec) => spec, + None => { + error!( + "No front center right leg specification exists for the combination of {:?} \ + and {:?}", + species, body_type + ); + return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5)); + }, + }; + let lateral = graceful_load_segment(&spec.leg_fcr.lateral.0); + + (lateral, Vec3::from(spec.leg_fcr.offset)) + } + + fn mesh_leg_bcl(&self, species: ASpecies, body_type: ABodyType) -> BoneMeshes { + let spec = match self.0.get(&(species, body_type)) { + Some(spec) => spec, + None => { + error!( + "No back center left leg specification exists for the combination of {:?} and \ + {:?}", + species, body_type + ); + return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5)); + }, + }; + let lateral = graceful_load_segment_flipped(&spec.leg_bcl.lateral.0, true); + + (lateral, Vec3::from(spec.leg_bcl.offset)) + } + + fn mesh_leg_bcr(&self, species: ASpecies, body_type: ABodyType) -> BoneMeshes { + let spec = match self.0.get(&(species, body_type)) { + Some(spec) => spec, + None => { + error!( + "No back center right leg specification exists for the combination of {:?} \ + and {:?}", + species, body_type + ); + return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5)); + }, + }; + let lateral = graceful_load_segment(&spec.leg_bcr.lateral.0); + + (lateral, Vec3::from(spec.leg_bcr.offset)) + } + + fn mesh_leg_bl(&self, species: ASpecies, body_type: ABodyType) -> BoneMeshes { + let spec = match self.0.get(&(species, body_type)) { + Some(spec) => spec, + None => { + error!( + "No back left leg specification exists for the combination of {:?} and {:?}", + species, body_type + ); + return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5)); + }, + }; + let lateral = graceful_load_segment_flipped(&spec.leg_bl.lateral.0, true); + + (lateral, Vec3::from(spec.leg_bl.offset)) + } + + fn mesh_leg_br(&self, species: ASpecies, body_type: ABodyType) -> BoneMeshes { + let spec = match self.0.get(&(species, body_type)) { + Some(spec) => spec, + None => { + error!( + "No back right leg specification exists for the combination of {:?} and {:?}", + species, body_type + ); + return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5)); + }, + }; + let lateral = graceful_load_segment(&spec.leg_br.lateral.0); + + (lateral, Vec3::from(spec.leg_br.offset)) + } +} //// #[derive(Deserialize)] struct FishMediumCentralSpec(HashMap<(FMSpecies, FMBodyType), SidedFMCentralVoxSpec>); diff --git a/voxygen/src/scene/figure/mod.rs b/voxygen/src/scene/figure/mod.rs index 46bfce12a0..08183c236c 100644 --- a/voxygen/src/scene/figure/mod.rs +++ b/voxygen/src/scene/figure/mod.rs @@ -21,7 +21,7 @@ use crate::{ }, }; use anim::{ - biped_large::BipedLargeSkeleton, biped_small::BipedSmallSkeleton, + arthropod::ArthropodSkeleton, biped_large::BipedLargeSkeleton, biped_small::BipedSmallSkeleton, bird_large::BirdLargeSkeleton, bird_medium::BirdMediumSkeleton, character::CharacterSkeleton, dragon::DragonSkeleton, fish_medium::FishMediumSkeleton, fish_small::FishSmallSkeleton, golem::GolemSkeleton, object::ObjectSkeleton, quadruped_low::QuadrupedLowSkeleton, @@ -119,6 +119,7 @@ struct FigureMgrStates { object_states: HashMap>, ship_states: HashMap>, volume_states: HashMap>, + arthropod_states: HashMap>, } impl FigureMgrStates { @@ -140,6 +141,7 @@ impl FigureMgrStates { object_states: HashMap::new(), ship_states: HashMap::new(), volume_states: HashMap::new(), + arthropod_states: HashMap::new(), } } @@ -207,6 +209,10 @@ impl FigureMgrStates { self.volume_states.get_mut(entity).map(DerefMut::deref_mut) } }, + Body::Arthropod(_) => self + .arthropod_states + .get_mut(entity) + .map(DerefMut::deref_mut), } } @@ -237,6 +243,7 @@ impl FigureMgrStates { self.volume_states.remove(entity).map(|e| e.meta) } }, + Body::Arthropod(_) => self.arthropod_states.remove(entity).map(|e| e.meta), } } @@ -258,6 +265,7 @@ impl FigureMgrStates { self.object_states.retain(|k, v| f(k, &mut *v)); self.ship_states.retain(|k, v| f(k, &mut *v)); self.volume_states.retain(|k, v| f(k, &mut *v)); + self.arthropod_states.retain(|k, v| f(k, &mut *v)); } fn count(&self) -> usize { @@ -278,6 +286,7 @@ impl FigureMgrStates { + self.object_states.len() + self.ship_states.len() + self.volume_states.len() + + self.arthropod_states.len() } fn count_visible(&self) -> usize { @@ -350,6 +359,11 @@ impl FigureMgrStates { .iter() .filter(|(_, c)| c.visible()) .count() + + self + .arthropod_states + .iter() + .filter(|(_, c)| c.visible()) + .count() + self.ship_states.iter().filter(|(_, c)| c.visible()).count() + self .volume_states @@ -377,6 +391,7 @@ pub struct FigureMgr { ship_model_cache: FigureModelCache, golem_model_cache: FigureModelCache, volume_model_cache: FigureModelCache, + arthropod_model_cache: FigureModelCache, states: FigureMgrStates, } @@ -400,6 +415,7 @@ impl FigureMgr { ship_model_cache: FigureModelCache::new(), golem_model_cache: FigureModelCache::new(), volume_model_cache: FigureModelCache::new(), + arthropod_model_cache: FigureModelCache::new(), states: FigureMgrStates::default(), } } @@ -433,6 +449,7 @@ impl FigureMgr { self.ship_model_cache.clean(&mut self.col_lights, tick); self.golem_model_cache.clean(&mut self.col_lights, tick); self.volume_model_cache.clean(&mut self.col_lights, tick); + self.arthropod_model_cache.clean(&mut self.col_lights, tick); } pub fn update_lighting(&mut self, scene_data: &SceneData) { @@ -3425,6 +3442,152 @@ impl FigureMgr { body, ); }, + Body::Arthropod(body) => { + let (model, skeleton_attr) = self.arthropod_model_cache.get_or_create_model( + renderer, + &mut self.col_lights, + body, + inventory, + tick, + player_camera_mode, + player_character_state, + &slow_jobs, + ); + + let state = self + .states + .arthropod_states + .entry(entity) + .or_insert_with(|| { + FigureState::new(renderer, ArthropodSkeleton::default(), body) + }); + + // Average velocity relative to the current ground + let rel_avg_vel = state.avg_vel - physics.ground_vel; + + let (character, last_character) = match (character, last_character) { + (Some(c), Some(l)) => (c, l), + _ => continue, + }; + + if !character.same_variant(&last_character.0) { + state.state_time = 0.0; + } + + let target_base = match ( + physics.on_ground.is_some(), + rel_vel.magnitude_squared() > MOVING_THRESHOLD_SQR, // Moving + physics.in_liquid().is_some(), // In water + ) { + // Standing + (true, false, false) => anim::arthropod::IdleAnimation::update_skeleton( + &ArthropodSkeleton::default(), + time, + state.state_time, + &mut state_animation_rate, + skeleton_attr, + ), + // Running + (true, true, false) => anim::arthropod::RunAnimation::update_skeleton( + &ArthropodSkeleton::default(), + ( + rel_vel, + // TODO: Update to use the quaternion. + ori * anim::vek::Vec3::::unit_y(), + state.last_ori * anim::vek::Vec3::::unit_y(), + time, + rel_avg_vel, + state.acc_vel, + ), + state.state_time, + &mut state_animation_rate, + skeleton_attr, + ), + // In air + (false, _, false) => anim::arthropod::JumpAnimation::update_skeleton( + &ArthropodSkeleton::default(), + ( + rel_vel.magnitude(), + // TODO: Update to use the quaternion. + ori * anim::vek::Vec3::::unit_y(), + state.last_ori * anim::vek::Vec3::::unit_y(), + time, + rel_avg_vel, + ), + state.state_time, + &mut state_animation_rate, + skeleton_attr, + ), + _ => anim::arthropod::IdleAnimation::update_skeleton( + &ArthropodSkeleton::default(), + time, + state.state_time, + &mut state_animation_rate, + skeleton_attr, + ), + }; + let target_bones = match &character { + CharacterState::ComboMelee(s) => { + let stage_index = (s.stage - 1) as usize; + let stage_time = s.timer.as_secs_f32(); + let stage_progress = + if let Some(stage) = s.static_data.stage_data.get(stage_index) { + match s.stage_section { + StageSection::Buildup => { + stage_time / stage.base_buildup_duration.as_secs_f32() + }, + StageSection::Swing => { + stage_time / stage.base_swing_duration.as_secs_f32() + }, + StageSection::Recover => { + stage_time / stage.base_recover_duration.as_secs_f32() + }, + _ => 0.0, + } + } else { + 0.0 + }; + match s.stage { + 1 => anim::arthropod::AlphaAnimation::update_skeleton( + &target_base, + ( + rel_vel.magnitude(), + time, + Some(s.stage_section), + state.state_time, + ), + stage_progress, + &mut state_animation_rate, + skeleton_attr, + ), + _ => anim::arthropod::AlphaAnimation::update_skeleton( + &target_base, + ( + rel_vel.magnitude(), + time, + Some(s.stage_section), + state.state_time, + ), + stage_progress, + &mut state_animation_rate, + skeleton_attr, + ), + } + }, + // TODO! + _ => target_base, + }; + + state.skeleton = anim::vek::Lerp::lerp(&state.skeleton, &target_bones, dt_lerp); + state.update( + renderer, + &mut update_buf, + &common_params, + state_animation_rate, + model, + body, + ); + }, Body::BirdLarge(body) => { let (model, skeleton_attr) = self.bird_large_model_cache.get_or_create_model( renderer, @@ -5141,7 +5304,11 @@ impl FigureMgr { object_model_cache, ship_model_cache, golem_model_cache, +<<<<<<< HEAD volume_model_cache, +======= + arthropod_model_cache, +>>>>>>> 9b36d29d2 (Adds arthropod skeleton) states: FigureMgrStates { character_states, @@ -5159,7 +5326,11 @@ impl FigureMgr { golem_states, object_states, ship_states, +<<<<<<< HEAD volume_states, +======= + arthropod_states, +>>>>>>> 9b36d29d2 (Adds arthropod skeleton) }, } = self; let col_lights = &*col_lights_; @@ -5372,6 +5543,22 @@ impl FigureMgr { ), ) }), + Body::Arthropod(body) => arthropod_states + .get(&entity) + .filter(|state| filter_state(*state)) + .map(move |state| { + ( + state.bound(), + arthropod_model_cache.get_model( + col_lights, + body, + inventory, + tick, + player_camera_mode, + character_state, + ), + ) + }), Body::Object(body) => object_states .get(&entity) .filter(|state| filter_state(*state))