Merge branch 'munou/anim-refactor' into 'master'

anim-refactor

See merge request veloren/veloren!4977
This commit is contained in:
Marcel
2025-07-23 16:29:53 +02:00
38 changed files with 1755 additions and 1407 deletions

View File

@ -1278,6 +1278,9 @@
Simple(
"common.items.armor.misc.head.bamboo_twig",
): "armor-misc-head-bamboo_twig",
Simple(
"common.items.armor.misc.head.pipe",
): "armor-misc-head-pipe",
Simple(
"common.items.armor.misc.head.bear_bonnet",
): "armor-misc-head-bear_bonnet",

View File

@ -0,0 +1,10 @@
ItemDef(
legacy_name: "Pipe",
legacy_description: "Each puff you take fills you with a sense of euphoria.",
kind: Armor((
kind: Head,
stats: Direct(()),
)),
quality: Common,
tags: [],
)

View File

@ -35,6 +35,7 @@ ItemDef(
"bronze_pants",
"bronze_shoulder",
"bronze_head",
"pipe",
// Weapon components
"short_hilt",
"medium_hilt",

View File

@ -1896,6 +1896,14 @@
],
craft_sprite: Some(Anvil),
),
"pipe": (
output: ("common.items.armor.misc.head.pipe", 1),
inputs: [
(Item("common.items.crafting_ing.twigs"), 3, false),
(Item("common.items.crafting_ing.living_embers"), 1, false),
],
craft_sprite: Some(CraftingBench),
),
"seashell_necklace": (
output: ("common.items.armor.misc.neck.shell", 1),
inputs: [

View File

@ -198,6 +198,8 @@ armor-misc-neck-topaz = Topaz Necklace
.desc = A copper necklace, with topaz embedded in the center.
armor-misc-head-bamboo_twig = Bamboo Twig
.desc = A tiny stray shoot from a larger bamboo shaft.
armor-misc-head-pipe = Pipe
.desc = Each puff you take fills you with a sense of euphoria.
armor-misc-head-bear_bonnet = Bear Bonnet
.desc = Wearing the guise of a ferocious bear, its fury becomes your own.
armor-misc-head-boreal_warhelm = Boreal Warhelmet

View File

@ -3393,6 +3393,10 @@
"voxel.armor.misc.head.bamboo_twig",
(2.5, 4.5, 0.0), (-120.0, -240.0,1.0), 2.3,
),
Simple("common.items.armor.misc.head.pipe"): VoxTrans(
"voxel.armor.misc.head.pipe",
(2.5, 4.5, 0.0), (-120.0, -240.0,1.0), 2.3,
),
Simple("common.items.armor.misc.head.scarlet_spectacles"): VoxTrans(
"voxel.armor.misc.head.scarlet_spectacles.scarlet_spectacles",
(-0.5, 0.0, 0.0), (295.0, 30.0, 0.0), 0.9,

View File

@ -111,6 +111,7 @@ const int FIRE_GIGAS_EXPLOSION = 70;
const int FIRE_PILLAR_INDICATOR = 71;
const int FIRE_PILLAR = 72;
const int FIRE_LOW_SHOCKWAVE = 73;
const int PIPE_SMOKE = 74;
// meters per second squared (acceleration)
const float earth_gravity = 9.807;
@ -1180,6 +1181,17 @@ void main() {
spin_in_axis(vec3(rand6, rand7, rand8), percent() * 10 + 3 * rand9)
);
break;
case PIPE_SMOKE:
attr = Attr(
linear_motion(
vec3(0),
vec3(rand2 * 0.02, rand3 * 0.02, 1.0 + rand4 * 0.1)
),
vec3(1.0 - slow_start(0.01)),
vec4(vec3(0.8, 0.8, 1) * 0.125 * (3.8 + rand0), start_end(1.0, 0.0)),
spin_in_axis(vec3(rand6, rand7, rand8), rand9 * 3 + lifetime * 0.5)
);
break;
default:
attr = Attr(
linear_motion(

BIN
assets/voxygen/voxel/armor/misc/head/pipe.vox (Stored with Git LFS) Normal file

Binary file not shown.

View File

@ -294,6 +294,54 @@
color: None
),
//
(Danari, Male, "common.items.armor.misc.head.pipe"): (
vox_spec: ("armor.misc.head.pipe", (1.0, 2.0, -2.0)),
color: None
),
(Danari, Female, "common.items.armor.misc.head.pipe"): (
vox_spec: ("armor.misc.head.pipe", (1.0, 2.0, -2.0)),
color: None
),
(Dwarf, Male, "common.items.armor.misc.head.pipe"): (
vox_spec: ("armor.misc.head.pipe", (-2.0, 3.0, -5.0)),
color: None
),
(Dwarf, Female, "common.items.armor.misc.head.pipe"): (
vox_spec: ("armor.misc.head.pipe", (-2.0, 3.0, -4.0)),
color: None
),
(Human, Male, "common.items.armor.misc.head.pipe"): (
vox_spec: ("armor.misc.head.pipe", (-1.0, 2.0, -4.0)),
color: None
),
(Human, Female, "common.items.armor.misc.head.pipe"): (
vox_spec: ("armor.misc.head.pipe", (-1.0, 3.0, -4.0)),
color: None
),
(Draugr, Male, "common.items.armor.misc.head.pipe"): (
vox_spec: ("armor.misc.head.pipe", (-3.0, 1.0, -2.0)),
color: None
),
(Draugr, Female, "common.items.armor.misc.head.pipe"): (
vox_spec: ("armor.misc.head.pipe", (-3.0, 1.0, -3.0)),
color: None
),
(Elf, Male, "common.items.armor.misc.head.pipe"): (
vox_spec: ("armor.misc.head.pipe", (-0.0, 2.0, -4.0)),
color: None
),
(Elf, Female, "common.items.armor.misc.head.pipe"): (
vox_spec: ("armor.misc.head.pipe", (-0.0, 2.0, -4.0)),
color: None
),
(Orc, Male, "common.items.armor.misc.head.pipe"): (
vox_spec: ("armor.misc.head.pipe", (1.0, 3.0, -1.0)),
color: None
),
(Orc, Female, "common.items.armor.misc.head.pipe"): (
vox_spec: ("armor.misc.head.pipe", (0.0, 0.0, -3.0)),
color: None
),
(Human, Male, "common.items.armor.misc.head.wanderers_hat"): (
vox_spec: ("armor.misc.head.wanderers_hat", (-4, -6.0, 4.0)),
color: None

View File

@ -860,8 +860,9 @@
Simple("common.items.armor.misc.head.howl_cowl"): "voxel.armor.misc.head.howl_cowl",
Simple("common.items.armor.misc.head.bear_bonnet"): "voxel.armor.misc.head.bear_bonnet",
Simple("common.items.armor.misc.head.bamboo_twig"): "voxel.armor.misc.head.bamboo_twig",
Simple("common.items.armor.misc.head.pipe"): "voxel.armor.misc.head.pipe",
Simple("common.items.armor.misc.head.bandana.thief"): "voxel.armor.misc.head.bandana.thief",
Simple("common.items.armor.misc.head.wanderers_hat"): "voxel.armor.misc.head.wanderers_hat",
Simple("common.items.armor.misc.head.wanderers_hat"): "voxel.armor.misc.head.wanderers_hat",
Simple("common.items.armor.misc.head.bandana.red"): "voxel.armor.misc.head.bandana.red",
Simple("common.items.armor.misc.head.straw"): "voxel.armor.misc.head.straw",
Simple("common.items.armor.misc.head.hood"): "voxel.armor.misc.head.hood",

View File

@ -15,36 +15,37 @@ pub use self::{
stunned::StunnedAnimation,
};
use super::{FigureBoneData, Offsets, Skeleton, make_bone, vek::*};
use super::{FigureBoneData, Skeleton, vek::*};
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,
skeleton_impls!(struct ArthropodSkeleton ComputedArthropodSkeleton {
+ 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;
type ComputedSkeleton = ComputedArthropodSkeleton;
const BONE_COUNT: usize = 16;
const BONE_COUNT: usize = ComputedArthropodSkeleton::BONE_COUNT;
#[cfg(feature = "use-dyn-lib")]
const COMPUTE_FN: &'static [u8] = b"arthropod_compute_s\0";
@ -55,7 +56,7 @@ impl Skeleton for ArthropodSkeleton {
base_mat: Mat4<f32>,
buf: &mut [FigureBoneData; super::MAX_BONE_COUNT],
body: Self::Body,
) -> Offsets {
) -> Self::ComputedSkeleton {
let base_mat = base_mat * Mat4::scaling_3d(SkeletonAttr::from(&body).scaler / 6.0);
let chest_mat = base_mat * Mat4::<f32>::from(self.chest);
@ -75,52 +76,27 @@ impl Skeleton for ArthropodSkeleton {
let leg_bl_mat = chest_mat * Mat4::<f32>::from(self.leg_bl);
let leg_br_mat = chest_mat * Mat4::<f32>::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) {
(
Hornbeetle | Leafbeetle | Stagbeetle | Weevil | Moltencrawler | Mosscrawler
| Sandcrawler | Dagonite,
_,
) => (head_mat, self.head.orientation),
_ => (chest_mat, self.chest.orientation),
let computed_skeleton = ComputedArthropodSkeleton {
head: head_mat,
chest: chest_mat,
mandible_l: mandible_l_mat,
mandible_r: mandible_r_mat,
wing_fl: wing_fl_mat,
wing_fr: wing_fr_mat,
wing_bl: wing_bl_mat,
wing_br: wing_br_mat,
leg_fl: leg_fl_mat,
leg_fr: leg_fr_mat,
leg_fcl: leg_fcl_mat,
leg_fcr: leg_fcr_mat,
leg_bcl: leg_bcl_mat,
leg_bcr: leg_bcr_mat,
leg_bl: leg_bl_mat,
leg_br: leg_br_mat,
};
// 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 {
viewpoint: Some((head_mat * Vec4::new(0.0, 7.0, 0.0, 1.0)).xyz()),
mount_bone: Transform {
position: mount_position,
orientation: mount_orientation,
scale: Vec3::one(),
},
..Default::default()
}
computed_skeleton.set_figure_bone_data(buf);
computed_skeleton
}
}
@ -338,9 +314,31 @@ impl<'a> From<&'a Body> for SkeletonAttr {
}
}
fn mount_point(body: &Body) -> Vec3<f32> {
pub fn mount_mat(
body: &Body,
computed_skeleton: &ComputedArthropodSkeleton,
skeleton: &ArthropodSkeleton,
) -> (Mat4<f32>, Quaternion<f32>) {
use comp::arthropod::Species::*;
match (body.species, body.body_type) {
(
Hornbeetle | Leafbeetle | Stagbeetle | Weevil | Moltencrawler | Mosscrawler
| Sandcrawler | Dagonite,
_,
) => (computed_skeleton.head, skeleton.head.orientation),
_ => (computed_skeleton.chest, skeleton.chest.orientation),
}
}
pub fn mount_transform(
body: &Body,
computed_skeleton: &ComputedArthropodSkeleton,
skeleton: &ArthropodSkeleton,
) -> Transform<f32, f32, f32> {
use comp::arthropod::Species::*;
let mount_point = match (body.species, body.body_type) {
(Tarantula, _) => (0.0, 1.0, 4.0),
(Blackwidow, _) => (0.0, 0.0, 5.0),
(Antlion, _) => (0.0, 2.0, 3.5),
@ -355,5 +353,12 @@ fn mount_point(body: &Body) -> Vec3<f32> {
(Dagonite, _) => (0.0, 8.5, 6.0),
(Emberfly, _) => (0.0, 3.0, 4.0),
}
.into()
.into();
let (mount_mat, orientation) = mount_mat(body, computed_skeleton, skeleton);
Transform {
position: mount_mat.mul_point(mount_point),
orientation,
scale: Vec3::one(),
}
}

View File

@ -36,46 +36,47 @@ pub use self::{
stunned::StunnedAnimation, summon::SummonAnimation, wield::WieldAnimation,
};
use super::{FigureBoneData, Offsets, Skeleton, make_bone, vek::*};
use super::{FigureBoneData, Skeleton, vek::*};
use common::comp::{self};
use core::{convert::TryFrom, f32::consts::PI};
pub type Body = comp::biped_large::Body;
skeleton_impls!(struct BipedLargeSkeleton {
+ head,
+ jaw,
+ upper_torso,
+ lower_torso,
+ tail,
+ main,
+ second,
+ shoulder_l,
+ shoulder_r,
+ hand_l,
+ hand_r,
+ leg_l,
+ leg_r,
+ foot_l,
+ foot_r,
+ hold,
torso,
control,
control_l,
control_r,
weapon_l,
weapon_r,
leg_control_l,
leg_control_r,
arm_control_l,
arm_control_r,
skeleton_impls!(struct BipedLargeSkeleton ComputedBipedLargeSkeleton {
+ head
+ jaw
+ upper_torso
+ lower_torso
+ tail
+ main
+ second
+ shoulder_l
+ shoulder_r
+ hand_l
+ hand_r
+ leg_l
+ leg_r
+ foot_l
+ foot_r
+ hold
torso
control
control_l
control_r
weapon_l
weapon_r
leg_control_l
leg_control_r
arm_control_l
arm_control_r
});
impl Skeleton for BipedLargeSkeleton {
type Attr = SkeletonAttr;
type Body = Body;
type ComputedSkeleton = ComputedBipedLargeSkeleton;
const BONE_COUNT: usize = 16;
const BONE_COUNT: usize = ComputedBipedLargeSkeleton::BONE_COUNT;
#[cfg(feature = "use-dyn-lib")]
const COMPUTE_FN: &'static [u8] = b"biped_large_compute_mats\0";
@ -88,7 +89,7 @@ impl Skeleton for BipedLargeSkeleton {
base_mat: Mat4<f32>,
buf: &mut [FigureBoneData; super::MAX_BONE_COUNT],
body: Self::Body,
) -> Offsets {
) -> Self::ComputedSkeleton {
let base_mat = base_mat * Mat4::scaling_3d(SkeletonAttr::from(&body).scaler / 8.0);
let torso_mat = base_mat * Mat4::<f32>::from(self.torso);
@ -114,60 +115,28 @@ impl Skeleton for BipedLargeSkeleton {
let jaw_mat = head_mat * Mat4::<f32>::from(self.jaw);
*(<&mut [_; Self::BONE_COUNT]>::try_from(&mut buf[0..Self::BONE_COUNT]).unwrap()) = [
make_bone(head_mat),
make_bone(jaw_mat),
make_bone(upper_torso_mat),
make_bone(lower_torso_mat),
make_bone(lower_torso_mat * Mat4::<f32>::from(self.tail)),
make_bone(upper_torso_mat * weapon_l_mat * Mat4::<f32>::from(self.main)),
make_bone(upper_torso_mat * weapon_r_mat * Mat4::<f32>::from(self.second)),
make_bone(arm_control_l * Mat4::<f32>::from(self.shoulder_l)),
make_bone(arm_control_r * Mat4::<f32>::from(self.shoulder_r)),
make_bone(
arm_control_l * weapon_l_mat * control_l_mat * Mat4::<f32>::from(self.hand_l),
),
make_bone(
arm_control_r * weapon_r_mat * control_r_mat * Mat4::<f32>::from(self.hand_r),
),
make_bone(leg_control_l * leg_l),
make_bone(leg_control_r * leg_r),
make_bone(leg_control_l * Mat4::<f32>::from(self.foot_l)),
make_bone(leg_control_r * Mat4::<f32>::from(self.foot_r)),
let computed_skeleton = ComputedBipedLargeSkeleton {
head: head_mat,
jaw: jaw_mat,
upper_torso: upper_torso_mat,
lower_torso: lower_torso_mat,
tail: lower_torso_mat * Mat4::<f32>::from(self.tail),
main: upper_torso_mat * weapon_l_mat * Mat4::<f32>::from(self.main),
second: upper_torso_mat * weapon_r_mat * Mat4::<f32>::from(self.second),
shoulder_l: arm_control_l * Mat4::<f32>::from(self.shoulder_l),
shoulder_r: arm_control_r * Mat4::<f32>::from(self.shoulder_r),
hand_l: arm_control_l * weapon_l_mat * control_l_mat * Mat4::<f32>::from(self.hand_l),
hand_r: arm_control_r * weapon_r_mat * control_r_mat * Mat4::<f32>::from(self.hand_r),
leg_l: leg_control_l * leg_l,
leg_r: leg_control_r * leg_r,
foot_l: leg_control_l * Mat4::<f32>::from(self.foot_l),
foot_r: leg_control_r * Mat4::<f32>::from(self.foot_r),
// FIXME: Should this be control_l_mat?
make_bone(upper_torso_mat * control_mat * hand_l_mat * Mat4::<f32>::from(self.hold)),
];
use comp::biped_large::Species::*;
// NOTE: We apply the ori from base_mat externally so we don't need to worry
// about it here for now.
let (mount_mat, mount_orientation) = match (body.species, body.body_type) {
(Dullahan | Occultsaurok | Mightysaurok | Slysaurok | Tidalwarrior, _) => (
upper_torso_mat,
self.torso.orientation * self.upper_torso.orientation,
),
_ => (
arm_control_r * Mat4::<f32>::from(self.shoulder_r),
self.torso.orientation
* self.upper_torso.orientation
* self.arm_control_r.orientation
* self.shoulder_r.orientation,
),
hold: upper_torso_mat * control_mat * hand_l_mat * Mat4::<f32>::from(self.hold),
};
// 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_mat.mul_point(mount_point(&body));
Offsets {
viewpoint: Some((jaw_mat * Vec4::new(0.0, 4.0, 0.0, 1.0)).xyz()),
mount_bone: Transform {
position: mount_position,
orientation: mount_orientation,
scale: Vec3::one(),
},
..Default::default()
}
computed_skeleton.set_figure_bone_data(buf);
computed_skeleton
}
}
@ -726,9 +695,38 @@ impl<'a> From<&'a Body> for SkeletonAttr {
}
}
fn mount_point(body: &Body) -> Vec3<f32> {
use comp::biped_large::{BodyType::*, Species::*};
pub fn mount_mat(
body: &Body,
computed_skeleton: &ComputedBipedLargeSkeleton,
skeleton: &BipedLargeSkeleton,
) -> (Mat4<f32>, Quaternion<f32>) {
use comp::biped_large::Species::*;
match (body.species, body.body_type) {
(Dullahan | Occultsaurok | Mightysaurok | Slysaurok | Tidalwarrior, _) => (
computed_skeleton.upper_torso,
skeleton.torso.orientation * skeleton.upper_torso.orientation,
),
_ => (
computed_skeleton.upper_torso
* Mat4::<f32>::from(skeleton.arm_control_r)
* Mat4::<f32>::from(skeleton.shoulder_r),
skeleton.torso.orientation
* skeleton.upper_torso.orientation
* skeleton.arm_control_r.orientation
* skeleton.shoulder_r.orientation,
),
}
}
pub fn mount_transform(
body: &Body,
computed_skeleton: &ComputedBipedLargeSkeleton,
skeleton: &BipedLargeSkeleton,
) -> Transform<f32, f32, f32> {
use comp::biped_large::{BodyType::*, Species::*};
let mount_point = match (body.species, body.body_type) {
(Ogre, Female) => (0.5, 0.0, 0.5),
(Ogre, Male) => (-1.0, -3.0, 2.5),
(Cyclops, _) => (0.0, 3.0, 1.0),
@ -766,7 +764,14 @@ fn mount_point(body: &Body) -> Vec3<f32> {
(Executioner, _) => (0.0, 0.0, 0.0),
(Gigasfire, _) => (1.0, 2.0, 4.5),
}
.into()
.into();
let (mount_mat, orientation) = mount_mat(body, computed_skeleton, skeleton);
Transform {
position: mount_mat.mul_point(mount_point),
orientation,
scale: Vec3::one(),
}
}
pub fn init_gigas_fire(next: &mut BipedLargeSkeleton) {

View File

@ -25,27 +25,27 @@ pub use self::{
stunned::StunnedAnimation, summon::SummonAnimation, wield::WieldAnimation,
};
use super::{FigureBoneData, Offsets, Skeleton, make_bone, vek::*};
use super::{FigureBoneData, Skeleton, vek::*};
use common::comp::{self};
use core::convert::TryFrom;
use std::f32::consts::PI;
pub type Body = comp::biped_small::Body;
skeleton_impls!(struct BipedSmallSkeleton {
+ head,
+ chest,
+ pants,
+ tail,
+ main,
+ second,
+ hand_l,
+ hand_r,
+ foot_l,
+ foot_r,
control,
control_l,
control_r,
skeleton_impls!(struct BipedSmallSkeleton ComputedBipedSmallSkeleton {
+ head
+ chest
+ pants
+ tail
+ main
+ second
+ hand_l
+ hand_r
+ foot_l
+ foot_r
control
control_l
control_r
:: // Begin non-bone fields
// Allows right hand to not be moved by control bone
detach_right: bool,
@ -54,8 +54,9 @@ skeleton_impls!(struct BipedSmallSkeleton {
impl Skeleton for BipedSmallSkeleton {
type Attr = SkeletonAttr;
type Body = Body;
type ComputedSkeleton = ComputedBipedSmallSkeleton;
const BONE_COUNT: usize = 10;
const BONE_COUNT: usize = ComputedBipedSmallSkeleton::BONE_COUNT;
#[cfg(feature = "use-dyn-lib")]
const COMPUTE_FN: &'static [u8] = b"biped_small_compute_mats\0";
@ -68,7 +69,7 @@ impl Skeleton for BipedSmallSkeleton {
base_mat: Mat4<f32>,
buf: &mut [FigureBoneData; super::MAX_BONE_COUNT],
body: Self::Body,
) -> Offsets {
) -> Self::ComputedSkeleton {
let base_mat = base_mat * Mat4::scaling_3d(SkeletonAttr::from(&body).scaler / 11.0);
let chest_mat = base_mat * Mat4::<f32>::from(self.chest);
@ -78,53 +79,27 @@ impl Skeleton for BipedSmallSkeleton {
let control_r_mat = Mat4::<f32>::from(self.control_r);
let head_mat = chest_mat * Mat4::<f32>::from(self.head);
let tail_mat = pants_mat * Mat4::<f32>::from(self.tail);
*(<&mut [_; Self::BONE_COUNT]>::try_from(&mut buf[0..Self::BONE_COUNT]).unwrap()) = [
make_bone(head_mat),
make_bone(chest_mat),
make_bone(pants_mat),
make_bone(tail_mat),
make_bone(control_mat * Mat4::<f32>::from(self.main)),
make_bone(control_mat * control_r_mat * Mat4::<f32>::from(self.second)),
make_bone(control_mat * control_l_mat * Mat4::<f32>::from(self.hand_l)),
make_bone(
if self.detach_right {
chest_mat
} else {
control_mat
} * control_r_mat
* Mat4::<f32>::from(self.hand_r),
),
make_bone(base_mat * Mat4::<f32>::from(self.foot_l)),
make_bone(base_mat * Mat4::<f32>::from(self.foot_r)),
];
use comp::biped_small::Species::*;
let (mount_mat, mount_orientation) = match (body.species, body.body_type) {
(Sahagin | Mandragora | Kappa | Gnoll | Bushly | Irrwurz | TreasureEgg, _) => {
(chest_mat, self.chest.orientation)
},
(GoblinThug | GoblinChucker | GoblinRuffian, _) => (
chest_mat,
self.chest.orientation * Quaternion::rotation_x(0.7),
),
(Myrmidon, _) => (
tail_mat,
self.chest.orientation * self.pants.orientation * self.tail.orientation,
),
_ => (head_mat, self.chest.orientation * self.head.orientation),
let computed_skeleton = ComputedBipedSmallSkeleton {
head: head_mat,
chest: chest_mat,
pants: pants_mat,
tail: tail_mat,
main: control_mat * Mat4::<f32>::from(self.main),
second: control_mat * control_r_mat * Mat4::<f32>::from(self.second),
hand_l: control_mat * control_l_mat * Mat4::<f32>::from(self.hand_l),
hand_r: if self.detach_right {
chest_mat
} else {
control_mat
} * control_r_mat
* Mat4::<f32>::from(self.hand_r),
foot_l: base_mat * Mat4::<f32>::from(self.foot_l),
foot_r: base_mat * Mat4::<f32>::from(self.foot_r),
};
let mount_position = mount_mat.mul_point(mount_point(&body));
Offsets {
viewpoint: Some((head_mat * Vec4::new(0.0, 0.0, 0.0, 1.0)).xyz()),
// TODO: see quadruped_medium for how to animate this
mount_bone: Transform {
position: mount_position,
orientation: mount_orientation,
scale: Vec3::one(),
},
..Default::default()
}
computed_skeleton.set_figure_bone_data(buf);
computed_skeleton
}
}
@ -666,10 +641,41 @@ pub fn biped_small_wield_bow(
Quaternion::rotation_x(-0.3 + 0.5 * speednorm) * Quaternion::rotation_y(0.5 * speednorm);
}
fn mount_point(body: &Body) -> Vec3<f32> {
pub fn mount_mat(
body: &Body,
computed_skeleton: &ComputedBipedSmallSkeleton,
skeleton: &BipedSmallSkeleton,
) -> (Mat4<f32>, Quaternion<f32>) {
use comp::biped_small::Species::*;
// TODO: Come up with a way to position rider
match (body.species, body.body_type) {
(Sahagin | Mandragora | Kappa | Gnoll | Bushly | Irrwurz | TreasureEgg, _) => {
(computed_skeleton.chest, skeleton.chest.orientation)
},
(GoblinThug | GoblinChucker | GoblinRuffian, _) => (
computed_skeleton.chest,
skeleton.chest.orientation * Quaternion::rotation_x(0.7),
),
(Myrmidon, _) => (
computed_skeleton.tail,
skeleton.chest.orientation * skeleton.pants.orientation * skeleton.tail.orientation,
),
_ => (
computed_skeleton.head,
skeleton.chest.orientation * skeleton.head.orientation,
),
}
}
pub fn mount_transform(
body: &Body,
computed_skeleton: &ComputedBipedSmallSkeleton,
skeleton: &BipedSmallSkeleton,
) -> Transform<f32, f32, f32> {
use comp::biped_small::Species::*;
// TODO: Come up with a way to position rider
let mount_point = match (body.species, body.body_type) {
(Gnome, _) => (0.0, -4.0, -1.0),
(Sahagin, _) => (0.0, 0.0, 5.0),
(Adlet, _) => (0.0, -4.0, 1.0),
@ -702,5 +708,12 @@ fn mount_point(body: &Body) -> Vec3<f32> {
(PurpleLegoom, _) => (0.0, -3.5, 7.5),
(RedLegoom, _) => (0.0, -3.5, 5.0),
}
.into()
.into();
let (mount_mat, orientation) = mount_mat(body, computed_skeleton, skeleton);
Transform {
position: mount_mat.mul_point(mount_point),
orientation,
scale: Vec3::one(),
}
}

View File

@ -23,36 +23,37 @@ pub use self::{
summon::SummonAnimation, swim::SwimAnimation,
};
use super::{FigureBoneData, Offsets, Skeleton, make_bone, vek::*};
use super::{FigureBoneData, Skeleton, vek::*};
use common::comp::{self};
use core::convert::TryFrom;
pub type Body = comp::bird_large::Body;
skeleton_impls!(struct BirdLargeSkeleton {
+ head,
+ beak,
+ neck,
+ chest,
+ tail_front,
+ tail_rear,
+ wing_in_l,
+ wing_in_r,
+ wing_mid_l,
+ wing_mid_r,
+ wing_out_l,
+ wing_out_r,
+ leg_l,
+ leg_r,
+ foot_l,
+ foot_r,
skeleton_impls!(struct BirdLargeSkeleton ComputedBirdLargeSkeleton {
+ head
+ beak
+ neck
+ chest
+ tail_front
+ tail_rear
+ wing_in_l
+ wing_in_r
+ wing_mid_l
+ wing_mid_r
+ wing_out_l
+ wing_out_r
+ leg_l
+ leg_r
+ foot_l
+ foot_r
});
impl Skeleton for BirdLargeSkeleton {
type Attr = SkeletonAttr;
type Body = Body;
type ComputedSkeleton = ComputedBirdLargeSkeleton;
const BONE_COUNT: usize = 16;
const BONE_COUNT: usize = ComputedBirdLargeSkeleton::BONE_COUNT;
#[cfg(feature = "use-dyn-lib")]
const COMPUTE_FN: &'static [u8] = b"bird_large_compute_mats\0";
@ -66,7 +67,7 @@ impl Skeleton for BirdLargeSkeleton {
base_mat: Mat4<f32>,
buf: &mut [FigureBoneData; super::MAX_BONE_COUNT],
body: Self::Body,
) -> Offsets {
) -> Self::ComputedSkeleton {
let base_mat = base_mat * Mat4::scaling_3d(SkeletonAttr::from(&body).scaler / 8.0);
let chest_mat = base_mat * Mat4::<f32>::from(self.chest);
@ -86,49 +87,27 @@ impl Skeleton for BirdLargeSkeleton {
let foot_l_mat = leg_l_mat * Mat4::<f32>::from(self.foot_l);
let foot_r_mat = leg_r_mat * Mat4::<f32>::from(self.foot_r);
*(<&mut [_; Self::BONE_COUNT]>::try_from(&mut buf[0..Self::BONE_COUNT]).unwrap()) = [
make_bone(head_mat),
make_bone(beak_mat),
make_bone(neck_mat),
make_bone(chest_mat),
make_bone(tail_front_mat),
make_bone(tail_rear_mat),
make_bone(wing_in_l_mat),
make_bone(wing_in_r_mat),
make_bone(wing_mid_l_mat),
make_bone(wing_mid_r_mat),
make_bone(wing_out_l_mat),
make_bone(wing_out_r_mat),
make_bone(leg_l_mat),
make_bone(leg_r_mat),
make_bone(foot_l_mat),
make_bone(foot_r_mat),
];
use comp::bird_large::Species::*;
// NOTE: We apply the ori from base_mat externally so we don't need to worry
// about it here for now.
let (mount_mat, mount_orientation) = match (body.species, body.body_type) {
(SeaWyvern | FlameWyvern | Phoenix | Cockatrice, _) => {
(chest_mat, self.chest.orientation)
},
_ => (neck_mat, self.chest.orientation * self.neck.orientation),
let computed_skeleton = ComputedBirdLargeSkeleton {
head: head_mat,
beak: beak_mat,
neck: neck_mat,
chest: chest_mat,
tail_front: tail_front_mat,
tail_rear: tail_rear_mat,
wing_in_l: wing_in_l_mat,
wing_in_r: wing_in_r_mat,
wing_mid_l: wing_mid_l_mat,
wing_mid_r: wing_mid_r_mat,
wing_out_l: wing_out_l_mat,
wing_out_r: wing_out_r_mat,
leg_l: leg_l_mat,
leg_r: leg_r_mat,
foot_l: foot_l_mat,
foot_r: foot_r_mat,
};
// Offset from the mounted bone's origin.
let mount_position = (mount_mat * Vec4::from_point(mount_point(&body)))
.homogenized()
.xyz();
Offsets {
viewpoint: Some((head_mat * Vec4::new(0.0, 3.0, 6.0, 1.0)).xyz()),
mount_bone: Transform {
position: mount_position,
orientation: mount_orientation,
scale: Vec3::one(),
},
..Default::default()
}
computed_skeleton.set_figure_bone_data(buf);
computed_skeleton
}
}
@ -327,9 +306,32 @@ impl<'a> From<&'a Body> for SkeletonAttr {
}
}
fn mount_point(body: &Body) -> Vec3<f32> {
pub fn mount_mat(
body: &Body,
computed_skeleton: &ComputedBirdLargeSkeleton,
skeleton: &BirdLargeSkeleton,
) -> (Mat4<f32>, Quaternion<f32>) {
use comp::bird_large::Species::*;
match (body.species, body.body_type) {
(SeaWyvern | FlameWyvern | Phoenix | Cockatrice, _) => {
(computed_skeleton.chest, skeleton.chest.orientation)
},
_ => (
computed_skeleton.neck,
skeleton.chest.orientation * skeleton.neck.orientation,
),
}
}
pub fn mount_transform(
body: &Body,
computed_skeleton: &ComputedBirdLargeSkeleton,
skeleton: &BirdLargeSkeleton,
) -> Transform<f32, f32, f32> {
use comp::bird_large::Species::*;
let mount_point = match (body.species, body.body_type) {
(Phoenix, _) => (0.0, 0.5, 7.5),
(Cockatrice, _) => (0.0, 5.0, 6.5),
(Roc, _) => (0.0, 5.5, 6.5),
@ -339,5 +341,12 @@ fn mount_point(body: &Body) -> Vec3<f32> {
(SeaWyvern, _) => (0.0, 8.0, 7.0),
(WealdWyvern, _) => (0.0, 0.0, 9.0),
}
.into()
.into();
let (mount_mat, orientation) = mount_mat(body, computed_skeleton, skeleton);
Transform {
position: mount_mat.mul_point(mount_point),
orientation,
scale: Vec3::one(),
}
}

View File

@ -18,29 +18,30 @@ pub use self::{
shoot::ShootAnimation, stunned::StunnedAnimation, summon::SummonAnimation, swim::SwimAnimation,
};
use super::{FigureBoneData, Offsets, Skeleton, make_bone, vek::*};
use super::{FigureBoneData, Skeleton, vek::*};
use common::comp::{self};
use core::convert::TryFrom;
pub type Body = comp::bird_medium::Body;
skeleton_impls!(struct BirdMediumSkeleton {
+ head,
+ chest,
+ tail,
+ wing_in_l,
+ wing_in_r,
+ wing_out_l,
+ wing_out_r,
+ leg_l,
+ leg_r,
skeleton_impls!(struct BirdMediumSkeleton ComputedBirdMediumSkeleton {
+ head
+ chest
+ tail
+ wing_in_l
+ wing_in_r
+ wing_out_l
+ wing_out_r
+ leg_l
+ leg_r
});
impl Skeleton for BirdMediumSkeleton {
type Attr = SkeletonAttr;
type Body = Body;
type ComputedSkeleton = ComputedBirdMediumSkeleton;
const BONE_COUNT: usize = 9;
const BONE_COUNT: usize = ComputedBirdMediumSkeleton::BONE_COUNT;
#[cfg(feature = "use-dyn-lib")]
const COMPUTE_FN: &'static [u8] = b"bird_medium_compute_mats\0";
@ -54,7 +55,7 @@ impl Skeleton for BirdMediumSkeleton {
base_mat: Mat4<f32>,
buf: &mut [FigureBoneData; super::MAX_BONE_COUNT],
body: Self::Body,
) -> Offsets {
) -> Self::ComputedSkeleton {
let base_mat = base_mat * Mat4::scaling_3d(SkeletonAttr::from(&body).scaler / 8.0);
let chest_mat = base_mat * Mat4::<f32>::from(self.chest);
@ -67,37 +68,20 @@ impl Skeleton for BirdMediumSkeleton {
let leg_l_mat = base_mat * Mat4::<f32>::from(self.leg_l);
let leg_r_mat = base_mat * Mat4::<f32>::from(self.leg_r);
*(<&mut [_; Self::BONE_COUNT]>::try_from(&mut buf[0..Self::BONE_COUNT]).unwrap()) = [
make_bone(head_mat),
make_bone(chest_mat),
make_bone(tail_mat),
make_bone(wing_in_l_mat),
make_bone(wing_in_r_mat),
make_bone(wing_out_l_mat),
make_bone(wing_out_r_mat),
make_bone(leg_l_mat),
make_bone(leg_r_mat),
];
use common::comp::body::bird_medium::Species::*;
let computed_skeleton = ComputedBirdMediumSkeleton {
head: head_mat,
chest: chest_mat,
tail: tail_mat,
wing_in_l: wing_in_l_mat,
wing_in_r: wing_in_r_mat,
wing_out_l: wing_out_l_mat,
wing_out_r: wing_out_r_mat,
leg_l: leg_l_mat,
leg_r: leg_r_mat,
};
let (mount_bone_mat, mount_bone_ori) = (chest_mat, self.chest.orientation);
let mount_position = mount_bone_mat.mul_point(mount_point(&body));
let mount_orientation = mount_bone_ori;
Offsets {
viewpoint: match body.species {
Bat | BloodmoonBat | VampireBat => {
Some((head_mat * Vec4::new(0.0, 5.0, -4.0, 1.0)).xyz())
},
_ => Some((head_mat * Vec4::new(0.0, 3.0, 2.0, 1.0)).xyz()),
},
mount_bone: Transform {
position: mount_position,
orientation: mount_orientation,
scale: Vec3::one(),
},
..Default::default()
}
computed_skeleton.set_figure_bone_data(buf);
computed_skeleton
}
}
@ -312,9 +296,29 @@ impl<'a> From<&'a Body> for SkeletonAttr {
}
}
fn mount_point(body: &Body) -> Vec3<f32> {
pub fn viewpoint(body: &Body) -> Vec4<f32> {
use comp::bird_medium::Species::*;
match body.species {
Bat | BloodmoonBat | VampireBat => Vec4::new(0.0, 5.0, -4.0, 1.0),
_ => Vec4::new(0.0, 3.0, 2.0, 1.0),
}
}
pub fn mount_mat(
computed_skeleton: &ComputedBirdMediumSkeleton,
skeleton: &BirdMediumSkeleton,
) -> (Mat4<f32>, Quaternion<f32>) {
(computed_skeleton.chest, skeleton.chest.orientation)
}
pub fn mount_transform(
body: &Body,
computed_skeleton: &ComputedBirdMediumSkeleton,
skeleton: &BirdMediumSkeleton,
) -> Transform<f32, f32, f32> {
use comp::bird_medium::{BodyType::*, Species::*};
match (body.species, body.body_type) {
let mount_point = match (body.species, body.body_type) {
(SnowyOwl, _) => (0.0, -4.0, 2.0),
(HornedOwl, _) => (0.0, -4.0, 1.0),
(Duck, _) => (0.0, -3.0, 2.0),
@ -335,5 +339,12 @@ fn mount_point(body: &Body) -> Vec3<f32> {
(BloodmoonBat, _) => (0.0, 0.5, 3.5),
(VampireBat, _) => (0.0, 0.0, -1.5),
}
.into()
.into();
let (mount_mat, orientation) = mount_mat(computed_skeleton, skeleton);
Transform {
position: mount_mat.mul_point(mount_point),
orientation,
scale: Vec3::one(),
}
}

View File

@ -68,7 +68,7 @@ pub use self::{
wallrun::WallrunAnimation,
wield::WieldAnimation,
};
use super::{FigureBoneData, Offsets, Skeleton, TrailSource, make_bone, vek::*};
use super::{FigureBoneData, Skeleton, vek::*};
use common::comp::{
self,
tool::{Hands, ToolKind},
@ -77,27 +77,27 @@ use core::{convert::TryFrom, f32::consts::PI};
pub type Body = comp::humanoid::Body;
skeleton_impls!(struct CharacterSkeleton {
+ head,
+ chest,
+ belt,
+ back,
+ shorts,
+ hand_l,
+ hand_r,
+ foot_l,
+ foot_r,
+ shoulder_l,
+ shoulder_r,
+ glider,
+ main,
+ second,
+ lantern,
+ hold,
torso,
control,
control_l,
control_r,
skeleton_impls!(struct CharacterSkeleton ComputedCharacterSkeleton {
+ head
+ chest
+ belt
+ back
+ shorts
+ hand_l
+ hand_r
+ foot_l
+ foot_r
+ shoulder_l
+ shoulder_r
+ glider
+ main
+ second
+ lantern
+ hold
torso
control
control_l
control_r
:: // Begin non-bone fields
holding_lantern: bool,
// The offset from the back that carried weapons should be given to avoid clipping due to, say, a backpack
@ -121,8 +121,9 @@ impl CharacterSkeleton {
impl Skeleton for CharacterSkeleton {
type Attr = SkeletonAttr;
type Body = Body;
type ComputedSkeleton = ComputedCharacterSkeleton;
const BONE_COUNT: usize = 16;
const BONE_COUNT: usize = ComputedCharacterSkeleton::BONE_COUNT;
#[cfg(feature = "use-dyn-lib")]
const COMPUTE_FN: &'static [u8] = b"character_compute_mats\0";
@ -132,7 +133,7 @@ impl Skeleton for CharacterSkeleton {
base_mat: Mat4<f32>,
buf: &mut [FigureBoneData; super::MAX_BONE_COUNT],
body: Self::Body,
) -> Offsets {
) -> Self::ComputedSkeleton {
// TODO: extract scaler from body to it's own method so we can call that
// directly instead of going through SkeletonAttr? (note todo also
// appiles to other body variant animations)
@ -157,61 +158,28 @@ impl Skeleton for CharacterSkeleton {
let second_mat = control_r_mat * Mat4::<f32>::from(self.second);
let glider_mat = chest_mat * Mat4::<f32>::from(self.glider);
*(<&mut [_; Self::BONE_COUNT]>::try_from(&mut buf[0..Self::BONE_COUNT]).unwrap()) = [
make_bone(head_mat),
make_bone(chest_mat),
make_bone(chest_mat * Mat4::<f32>::from(self.belt)),
make_bone(chest_mat * Mat4::<f32>::from(self.back)),
make_bone(shorts_mat),
make_bone(control_l_mat * hand_l_mat),
make_bone(hand_r_mat),
make_bone(torso_mat * Mat4::<f32>::from(self.foot_l)),
make_bone(torso_mat * Mat4::<f32>::from(self.foot_r)),
make_bone(chest_mat * Mat4::<f32>::from(self.shoulder_l)),
make_bone(chest_mat * Mat4::<f32>::from(self.shoulder_r)),
make_bone(glider_mat),
make_bone(main_mat),
make_bone(second_mat),
make_bone(lantern_mat),
let computed_skeleton = ComputedCharacterSkeleton {
head: head_mat,
chest: chest_mat,
belt: chest_mat * Mat4::<f32>::from(self.belt),
back: chest_mat * Mat4::<f32>::from(self.back),
shorts: shorts_mat,
hand_l: control_l_mat * hand_l_mat,
hand_r: hand_r_mat,
foot_l: torso_mat * Mat4::<f32>::from(self.foot_l),
foot_r: torso_mat * Mat4::<f32>::from(self.foot_r),
shoulder_l: chest_mat * Mat4::<f32>::from(self.shoulder_l),
shoulder_r: chest_mat * Mat4::<f32>::from(self.shoulder_r),
glider: glider_mat,
main: main_mat,
second: second_mat,
lantern: lantern_mat,
// FIXME: Should this be control_l_mat?
make_bone(control_mat * hand_l_mat * Mat4::<f32>::from(self.hold)),
];
hold: control_mat * hand_l_mat * Mat4::<f32>::from(self.hold),
};
// Offset from the mounted bone's origin.
// Note: This could be its own bone if we need to animate it independently.
let mount_position = (chest_mat * Vec4::from_point(Vec3::new(5.5, 0.0, 6.5)))
.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 =
self.torso.orientation * self.chest.orientation * Quaternion::rotation_y(0.4);
let weapon_trails = self.main_weapon_trail || self.off_weapon_trail;
Offsets {
lantern: Some((lantern_mat * Vec4::new(0.0, 0.5, -6.0, 1.0)).xyz()),
viewpoint: Some((head_mat * Vec4::new(0.0, 0.0, 4.0, 1.0)).xyz()),
mount_bone: Transform {
position: mount_position,
orientation: mount_orientation,
scale: Vec3::one(),
},
primary_trail_mat: if weapon_trails {
self.main_weapon_trail
.then_some((main_mat, TrailSource::Weapon))
} else {
self.glider_trails
.then_some((glider_mat, TrailSource::GliderLeft))
},
secondary_trail_mat: if weapon_trails {
self.off_weapon_trail
.then_some((second_mat, TrailSource::Weapon))
} else {
self.glider_trails
.then_some((glider_mat, TrailSource::GliderRight))
},
..Default::default()
}
computed_skeleton.set_figure_bone_data(buf);
computed_skeleton
}
}
@ -348,6 +316,28 @@ impl<'a> From<&'a Body> for SkeletonAttr {
}
}
pub fn mount_mat(
computed_skeleton: &ComputedCharacterSkeleton,
skeleton: &CharacterSkeleton,
) -> (Mat4<f32>, Quaternion<f32>) {
(
computed_skeleton.chest,
skeleton.torso.orientation * skeleton.chest.orientation * Quaternion::rotation_y(0.4),
)
}
pub fn mount_transform(
computed_skeleton: &ComputedCharacterSkeleton,
skeleton: &CharacterSkeleton,
) -> Transform<f32, f32, f32> {
let (mount_mat, orientation) = mount_mat(computed_skeleton, skeleton);
Transform {
position: mount_mat.mul_point(Vec3::new(5.5, 0.0, 6.5)),
orientation,
scale: Vec3::one(),
}
}
impl CharacterSkeleton {
/// Animate tools (main and secondary) on the character's back, taking in
/// account backpack offsets.

View File

@ -18,33 +18,34 @@ pub use self::{
use common::comp::{self};
use super::{FigureBoneData, Offsets, Skeleton, make_bone, vek::*};
use super::{FigureBoneData, Skeleton, vek::*};
pub type Body = comp::crustacean::Body;
skeleton_impls!(struct CrustaceanSkeleton {
+ chest,
+ tail_f,
+ tail_b,
+ arm_l,
+ pincer_l0,
+ pincer_l1,
+ arm_r,
+ pincer_r0,
+ pincer_r1,
+ leg_fl,
+ leg_cl,
+ leg_bl,
+ leg_fr,
+ leg_cr,
+ leg_br,
skeleton_impls!(struct CrustaceanSkeleton ComputedCrustaceanSkeleton {
+ chest
+ tail_f
+ tail_b
+ arm_l
+ pincer_l0
+ pincer_l1
+ arm_r
+ pincer_r0
+ pincer_r1
+ leg_fl
+ leg_cl
+ leg_bl
+ leg_fr
+ leg_cr
+ leg_br
});
impl Skeleton for CrustaceanSkeleton {
type Attr = SkeletonAttr;
type Body = Body;
type ComputedSkeleton = ComputedCrustaceanSkeleton;
const BONE_COUNT: usize = 15;
const BONE_COUNT: usize = ComputedCrustaceanSkeleton::BONE_COUNT;
#[cfg(feature = "use-dyn-lib")]
const COMPUTE_FN: &'static [u8] = b"crustacean_compute_s\0";
@ -55,7 +56,7 @@ impl Skeleton for CrustaceanSkeleton {
base_mat: Mat4<f32>,
buf: &mut [FigureBoneData; super::MAX_BONE_COUNT],
body: Self::Body,
) -> Offsets {
) -> Self::ComputedSkeleton {
let base_mat = base_mat * Mat4::scaling_3d(SkeletonAttr::from(&body).scaler / 6.0);
let chest_mat = base_mat * Mat4::<f32>::from(self.chest);
@ -74,45 +75,26 @@ impl Skeleton for CrustaceanSkeleton {
let leg_cr_mat = chest_mat * Mat4::<f32>::from(self.leg_cr);
let leg_br_mat = chest_mat * Mat4::<f32>::from(self.leg_br);
*(<&mut [_; Self::BONE_COUNT]>::try_from(&mut buf[0..Self::BONE_COUNT]).unwrap()) = [
make_bone(chest_mat),
make_bone(tail_f_mat),
make_bone(tail_b_mat),
make_bone(arm_l_mat),
make_bone(pincer_l0_mat),
make_bone(pincer_l1_mat),
make_bone(arm_r_mat),
make_bone(pincer_r0_mat),
make_bone(pincer_r1_mat),
make_bone(leg_fl_mat),
make_bone(leg_cl_mat),
make_bone(leg_bl_mat),
make_bone(leg_fr_mat),
make_bone(leg_cr_mat),
make_bone(leg_br_mat),
];
let computed_skeleton = ComputedCrustaceanSkeleton {
chest: chest_mat,
tail_f: tail_f_mat,
tail_b: tail_b_mat,
arm_l: arm_l_mat,
pincer_l0: pincer_l0_mat,
pincer_l1: pincer_l1_mat,
arm_r: arm_r_mat,
pincer_r0: pincer_r0_mat,
pincer_r1: pincer_r1_mat,
leg_fl: leg_fl_mat,
leg_cl: leg_cl_mat,
leg_bl: leg_bl_mat,
leg_fr: leg_fr_mat,
leg_cr: leg_cr_mat,
leg_br: leg_br_mat,
};
// TODO: mount points
//use comp::arthropod::Species::*;
let (mount_bone_mat, mount_bone_ori) = (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 {
viewpoint: Some((chest_mat * Vec4::new(0.0, 7.0, 0.0, 1.0)).xyz()),
mount_bone: Transform {
position: mount_position,
orientation: mount_orientation,
scale: Vec3::one(),
},
..Default::default()
}
computed_skeleton.set_figure_bone_data(buf);
computed_skeleton
}
}
@ -175,12 +157,31 @@ impl<'a> From<&'a Body> for SkeletonAttr {
}
}
fn mount_point(body: &Body) -> Vec3<f32> {
pub fn mount_mat(
computed_skeleton: &ComputedCrustaceanSkeleton,
skeleton: &CrustaceanSkeleton,
) -> (Mat4<f32>, Quaternion<f32>) {
(computed_skeleton.chest, skeleton.chest.orientation)
}
pub fn mount_transform(
body: &Body,
computed_skeleton: &ComputedCrustaceanSkeleton,
skeleton: &CrustaceanSkeleton,
) -> Transform<f32, f32, f32> {
use comp::crustacean::Species::*;
match (body.species, body.body_type) {
let mount_point = match (body.species, body.body_type) {
(Crab, _) => (0.0, -3.5, 6.0),
(SoldierCrab, _) => (0.0, -2.5, 8.0),
(Karkatha, _) => (0.0, -1.0, 32.0),
}
.into()
.into();
let (mount_mat, orientation) = mount_mat(computed_skeleton, skeleton);
Transform {
position: mount_mat.mul_point(mount_point),
orientation,
scale: Vec3::one(),
}
}

View File

@ -5,35 +5,36 @@ pub mod run;
// Reexports
pub use self::{fly::FlyAnimation, idle::IdleAnimation, run::RunAnimation};
use super::{FigureBoneData, Offsets, Skeleton, make_bone, vek::*};
use super::{FigureBoneData, Skeleton, vek::*};
use common::comp;
use core::convert::TryFrom;
pub type Body = comp::dragon::Body;
skeleton_impls!(struct DragonSkeleton {
+ head_upper,
+ head_lower,
+ jaw,
+ chest_front,
+ chest_rear,
+ tail_front,
+ tail_rear,
+ wing_in_l,
+ wing_in_r,
+ wing_out_l,
+ wing_out_r,
+ foot_fl,
+ foot_fr,
+ foot_bl,
+ foot_br,
skeleton_impls!(struct DragonSkeleton ComputedDragonSkeleton {
+ head_upper
+ head_lower
+ jaw
+ chest_front
+ chest_rear
+ tail_front
+ tail_rear
+ wing_in_l
+ wing_in_r
+ wing_out_l
+ wing_out_r
+ foot_fl
+ foot_fr
+ foot_bl
+ foot_br
});
impl Skeleton for DragonSkeleton {
type Attr = SkeletonAttr;
type Body = Body;
type ComputedSkeleton = ComputedDragonSkeleton;
const BONE_COUNT: usize = 15;
const BONE_COUNT: usize = ComputedDragonSkeleton::BONE_COUNT;
#[cfg(feature = "use-dyn-lib")]
const COMPUTE_FN: &'static [u8] = b"dragon_compute_mats\0";
@ -43,8 +44,8 @@ impl Skeleton for DragonSkeleton {
&self,
base_mat: Mat4<f32>,
buf: &mut [FigureBoneData; super::MAX_BONE_COUNT],
body: Self::Body,
) -> Offsets {
_body: Self::Body,
) -> Self::ComputedSkeleton {
let base_mat = base_mat * Mat4::scaling_3d(1.0);
let chest_front_mat = base_mat * Mat4::<f32>::from(self.chest_front);
let chest_rear_mat = chest_front_mat * Mat4::<f32>::from(self.chest_rear);
@ -54,46 +55,57 @@ impl Skeleton for DragonSkeleton {
let tail_front_mat = chest_rear_mat * Mat4::<f32>::from(self.tail_front);
let head_upper_mat = head_lower_mat * Mat4::<f32>::from(self.head_upper);
*(<&mut [_; Self::BONE_COUNT]>::try_from(&mut buf[0..Self::BONE_COUNT]).unwrap()) = [
make_bone(head_upper_mat),
make_bone(head_lower_mat),
make_bone(head_upper_mat * Mat4::<f32>::from(self.jaw)),
make_bone(chest_front_mat),
make_bone(chest_rear_mat),
make_bone(tail_front_mat),
make_bone(tail_front_mat * Mat4::<f32>::from(self.tail_rear)),
make_bone(wing_in_l_mat),
make_bone(wing_in_r_mat),
make_bone(wing_in_l_mat * Mat4::<f32>::from(self.wing_out_l)),
make_bone(wing_in_r_mat * Mat4::<f32>::from(self.wing_out_r)),
make_bone(chest_front_mat * Mat4::<f32>::from(self.foot_fl)),
make_bone(chest_front_mat * Mat4::<f32>::from(self.foot_fr)),
make_bone(chest_rear_mat * Mat4::<f32>::from(self.foot_bl)),
make_bone(chest_rear_mat * Mat4::<f32>::from(self.foot_br)),
];
let computed_skeleton = ComputedDragonSkeleton {
head_upper: head_upper_mat,
head_lower: head_lower_mat,
jaw: head_upper_mat * Mat4::<f32>::from(self.jaw),
chest_front: chest_front_mat,
chest_rear: chest_rear_mat,
tail_front: tail_front_mat,
tail_rear: tail_front_mat * Mat4::<f32>::from(self.tail_rear),
wing_in_l: wing_in_l_mat,
wing_in_r: wing_in_r_mat,
wing_out_l: wing_in_l_mat * Mat4::<f32>::from(self.wing_out_l),
wing_out_r: wing_in_r_mat * Mat4::<f32>::from(self.wing_out_r),
foot_fl: chest_front_mat * Mat4::<f32>::from(self.foot_fl),
foot_fr: chest_front_mat * Mat4::<f32>::from(self.foot_fr),
foot_bl: chest_rear_mat * Mat4::<f32>::from(self.foot_bl),
foot_br: chest_rear_mat * Mat4::<f32>::from(self.foot_br),
};
let mount_position = chest_front_mat.mul_point(mount_point(&body));
let mount_orientation = self.chest_front.orientation;
Offsets {
viewpoint: Some((head_upper_mat * Vec4::new(0.0, 8.0, 0.0, 1.0)).xyz()),
// TODO: see quadruped_medium for how to animate this
mount_bone: Transform {
position: mount_position,
orientation: mount_orientation,
..Default::default()
},
..Default::default()
}
computed_skeleton.set_figure_bone_data(buf);
computed_skeleton
}
}
fn mount_point(body: &Body) -> Vec3<f32> {
pub fn mount_mat(
computed_skeleton: &ComputedDragonSkeleton,
skeleton: &DragonSkeleton,
) -> (Mat4<f32>, Quaternion<f32>) {
(
computed_skeleton.chest_front,
skeleton.chest_front.orientation,
)
}
pub fn mount_transform(
body: &Body,
computed_skeleton: &ComputedDragonSkeleton,
skeleton: &DragonSkeleton,
) -> Transform<f32, f32, f32> {
use comp::dragon::Species::*;
match (body.species, body.body_type) {
let mount_point = match (body.species, body.body_type) {
(Reddragon, _) => (0.0, 0.5, 5.5),
}
.into()
.into();
let (mount_mat, orientation) = mount_mat(computed_skeleton, skeleton);
Transform {
position: mount_mat.mul_point(mount_point),
orientation,
scale: Vec3::one(),
}
}
pub struct SkeletonAttr {

View File

@ -4,27 +4,28 @@ pub mod swim;
// Reexports
pub use self::{idle::IdleAnimation, swim::SwimAnimation};
use super::{FigureBoneData, Offsets, Skeleton, make_bone, vek::*};
use super::{FigureBoneData, Skeleton, vek::*};
use common::comp::{self};
use core::convert::TryFrom;
pub type Body = comp::fish_medium::Body;
skeleton_impls!(struct FishMediumSkeleton {
+ head,
+ jaw,
+ chest_front,
+ chest_back,
+ tail,
+ fin_l,
+ fin_r,
skeleton_impls!(struct FishMediumSkeleton ComputedFishMediumSkeleton {
+ head
+ jaw
+ chest_front
+ chest_back
+ tail
+ fin_l
+ fin_r
});
impl Skeleton for FishMediumSkeleton {
type Attr = SkeletonAttr;
type Body = Body;
type ComputedSkeleton = ComputedFishMediumSkeleton;
const BONE_COUNT: usize = 7;
const BONE_COUNT: usize = ComputedFishMediumSkeleton::BONE_COUNT;
#[cfg(feature = "use-dyn-lib")]
const COMPUTE_FN: &'static [u8] = b"fish_medium_compute_mats\0";
@ -36,38 +37,26 @@ impl Skeleton for FishMediumSkeleton {
&self,
base_mat: Mat4<f32>,
buf: &mut [FigureBoneData; super::MAX_BONE_COUNT],
body: Self::Body,
) -> Offsets {
_body: Self::Body,
) -> Self::ComputedSkeleton {
let base_mat = base_mat * Mat4::scaling_3d(1.0 / 11.0);
let chest_front_mat = base_mat * Mat4::<f32>::from(self.chest_front);
let chest_back_mat = Mat4::<f32>::from(self.chest_back);
let head_mat = chest_front_mat * Mat4::<f32>::from(self.head);
*(<&mut [_; Self::BONE_COUNT]>::try_from(&mut buf[0..Self::BONE_COUNT]).unwrap()) = [
make_bone(head_mat),
make_bone(head_mat * Mat4::<f32>::from(self.jaw)),
make_bone(chest_front_mat),
make_bone(chest_front_mat * chest_back_mat),
make_bone(chest_front_mat * chest_back_mat * Mat4::<f32>::from(self.tail)),
make_bone(chest_front_mat * Mat4::<f32>::from(self.fin_l)),
make_bone(chest_front_mat * Mat4::<f32>::from(self.fin_r)),
];
let computed_skeleton = ComputedFishMediumSkeleton {
head: head_mat,
jaw: head_mat * Mat4::<f32>::from(self.jaw),
chest_front: chest_front_mat,
chest_back: chest_front_mat * chest_back_mat,
tail: chest_front_mat * chest_back_mat * Mat4::<f32>::from(self.tail),
fin_l: chest_front_mat * Mat4::<f32>::from(self.fin_l),
fin_r: chest_front_mat * Mat4::<f32>::from(self.fin_r),
};
let (mount_bone_mat, mount_bone_ori) = (head_mat, self.head.orientation);
let mount_position = mount_bone_mat.mul_point(mount_point(&body));
let mount_orientation = mount_bone_ori;
Offsets {
viewpoint: Some((head_mat * Vec4::new(0.0, 5.0, 0.0, 1.0)).xyz()),
// TODO: see quadruped_medium for how to animate this
mount_bone: Transform {
position: mount_position,
orientation: mount_orientation,
scale: Vec3::one(),
},
..Default::default()
}
computed_skeleton.set_figure_bone_data(buf);
computed_skeleton
}
}
@ -148,11 +137,30 @@ impl<'a> From<&'a Body> for SkeletonAttr {
}
}
fn mount_point(body: &Body) -> Vec3<f32> {
pub fn mount_mat(
computed_skeleton: &ComputedFishMediumSkeleton,
skeleton: &FishMediumSkeleton,
) -> (Mat4<f32>, Quaternion<f32>) {
(computed_skeleton.head, skeleton.head.orientation)
}
pub fn mount_transform(
body: &Body,
computed_skeleton: &ComputedFishMediumSkeleton,
skeleton: &FishMediumSkeleton,
) -> Transform<f32, f32, f32> {
use comp::fish_medium::Species::*;
match (body.species, body.body_type) {
let mount_point = match (body.species, body.body_type) {
(Marlin, _) => (0.0, 0.5, 3.0),
(Icepike, _) => (0.0, 0.5, 4.0),
}
.into()
.into();
let (mount_mat, orientation) = mount_mat(computed_skeleton, skeleton);
Transform {
position: mount_mat.mul_point(mount_point),
orientation,
scale: Vec3::one(),
}
}

View File

@ -4,24 +4,25 @@ pub mod swim;
// Reexports
pub use self::{idle::IdleAnimation, swim::SwimAnimation};
use super::{FigureBoneData, Offsets, Skeleton, make_bone, vek::*};
use super::{FigureBoneData, Skeleton, vek::*};
use common::comp::{self};
use core::convert::TryFrom;
pub type Body = comp::fish_small::Body;
skeleton_impls!(struct FishSmallSkeleton {
+ chest,
+ tail,
+ fin_l,
+ fin_r,
skeleton_impls!(struct FishSmallSkeleton ComputedFishSmallSkeleton {
+ chest
+ tail
+ fin_l
+ fin_r
});
impl Skeleton for FishSmallSkeleton {
type Attr = SkeletonAttr;
type Body = Body;
type ComputedSkeleton = ComputedFishSmallSkeleton;
const BONE_COUNT: usize = 4;
const BONE_COUNT: usize = ComputedFishSmallSkeleton::BONE_COUNT;
#[cfg(feature = "use-dyn-lib")]
const COMPUTE_FN: &'static [u8] = b"fish_small_compute_mats\0";
@ -33,32 +34,20 @@ impl Skeleton for FishSmallSkeleton {
&self,
base_mat: Mat4<f32>,
buf: &mut [FigureBoneData; super::MAX_BONE_COUNT],
body: Self::Body,
) -> Offsets {
_body: Self::Body,
) -> Self::ComputedSkeleton {
let base_mat = base_mat * Mat4::scaling_3d(1.0 / 13.0);
let chest_mat = base_mat * Mat4::<f32>::from(self.chest);
*(<&mut [_; Self::BONE_COUNT]>::try_from(&mut buf[0..Self::BONE_COUNT]).unwrap()) = [
make_bone(chest_mat),
make_bone(chest_mat * Mat4::<f32>::from(self.tail)),
make_bone(chest_mat * Mat4::<f32>::from(self.fin_l)),
make_bone(chest_mat * Mat4::<f32>::from(self.fin_r)),
];
let computed_skeleton = ComputedFishSmallSkeleton {
chest: chest_mat,
tail: chest_mat * Mat4::<f32>::from(self.tail),
fin_l: chest_mat * Mat4::<f32>::from(self.fin_l),
fin_r: chest_mat * Mat4::<f32>::from(self.fin_r),
};
let (mount_bone_mat, mount_bone_ori) = (chest_mat, self.chest.orientation);
let mount_position = mount_bone_mat.mul_point(mount_point(&body));
let mount_orientation = mount_bone_ori;
Offsets {
viewpoint: Some((chest_mat * Vec4::new(0.0, 3.0, 0.0, 1.0)).xyz()),
// TODO: see quadruped_medium for how to animate this
mount_bone: Transform {
position: mount_position,
orientation: mount_orientation,
scale: Vec3::one(),
},
..Default::default()
}
computed_skeleton.set_figure_bone_data(buf);
computed_skeleton
}
}
@ -121,11 +110,30 @@ impl<'a> From<&'a Body> for SkeletonAttr {
}
}
fn mount_point(body: &Body) -> Vec3<f32> {
pub fn mount_mat(
computed_skeleton: &ComputedFishSmallSkeleton,
skeleton: &FishSmallSkeleton,
) -> (Mat4<f32>, Quaternion<f32>) {
(computed_skeleton.chest, skeleton.chest.orientation)
}
pub fn mount_transform(
body: &Body,
computed_skeleton: &ComputedFishSmallSkeleton,
skeleton: &FishSmallSkeleton,
) -> Transform<f32, f32, f32> {
use comp::fish_small::Species::*;
match (body.species, body.body_type) {
let mount_point = match (body.species, body.body_type) {
(Clownfish, _) => (0.0, 0.5, 3.0),
(Piranha, _) => (0.0, -1.0, 4.5),
}
.into()
.into();
let (mount_mat, orientation) = mount_mat(computed_skeleton, skeleton);
Transform {
position: mount_mat.mul_point(mount_point),
orientation,
scale: Vec3::one(),
}
}

View File

@ -1,4 +1,4 @@
use super::{FigureBoneData, Offsets, Skeleton, make_bone, vek::*};
use super::{FigureBoneData, Skeleton, make_bone, vek::*};
pub type Body = ();
@ -20,6 +20,7 @@ impl<Factor> Lerp<Factor> for &FixtureSkeleton {
impl Skeleton for FixtureSkeleton {
type Attr = SkeletonAttr;
type Body = Body;
type ComputedSkeleton = ();
const BONE_COUNT: usize = 1;
#[cfg(feature = "use-dyn-lib")]
@ -31,9 +32,8 @@ impl Skeleton for FixtureSkeleton {
base_mat: Mat4<f32>,
buf: &mut [FigureBoneData; super::MAX_BONE_COUNT],
(): Self::Body,
) -> Offsets {
) -> Self::ComputedSkeleton {
buf[0] = make_bone(base_mat);
Offsets::default()
}
}

View File

@ -12,33 +12,34 @@ pub use self::{
run::RunAnimation, shockwave::ShockwaveAnimation, shoot::ShootAnimation,
};
use super::{FigureBoneData, Offsets, Skeleton, make_bone, vek::*};
use super::{FigureBoneData, Skeleton, vek::*};
use common::comp::{self};
use core::convert::TryFrom;
pub type Body = comp::golem::Body;
skeleton_impls!(struct GolemSkeleton {
+ head,
+ jaw,
+ upper_torso,
+ lower_torso,
+ shoulder_l,
+ shoulder_r,
+ hand_l,
+ hand_r,
+ leg_l,
+ leg_r,
+ foot_l,
+ foot_r,
torso,
skeleton_impls!(struct GolemSkeleton ComputedGolemSkeleton {
+ head
+ jaw
+ upper_torso
+ lower_torso
+ shoulder_l
+ shoulder_r
+ hand_l
+ hand_r
+ leg_l
+ leg_r
+ foot_l
+ foot_r
torso
});
impl Skeleton for GolemSkeleton {
type Attr = SkeletonAttr;
type Body = Body;
type ComputedSkeleton = ComputedGolemSkeleton;
const BONE_COUNT: usize = 12;
const BONE_COUNT: usize = ComputedGolemSkeleton::BONE_COUNT;
#[cfg(feature = "use-dyn-lib")]
const COMPUTE_FN: &'static [u8] = b"golem_compute_mats\0";
@ -48,7 +49,7 @@ impl Skeleton for GolemSkeleton {
base_mat: Mat4<f32>,
buf: &mut [FigureBoneData; super::MAX_BONE_COUNT],
body: Self::Body,
) -> Offsets {
) -> Self::ComputedSkeleton {
let base_mat = base_mat * Mat4::scaling_3d(SkeletonAttr::from(&body).scaler / 8.0);
let torso_mat = base_mat * Mat4::<f32>::from(self.torso);
@ -60,37 +61,23 @@ impl Skeleton for GolemSkeleton {
let shoulder_r_mat = upper_torso_mat * Mat4::<f32>::from(self.shoulder_r);
let head_mat = upper_torso_mat * Mat4::<f32>::from(self.head);
*(<&mut [_; Self::BONE_COUNT]>::try_from(&mut buf[0..Self::BONE_COUNT]).unwrap()) = [
make_bone(head_mat),
make_bone(upper_torso_mat * Mat4::<f32>::from(self.head) * Mat4::<f32>::from(self.jaw)),
make_bone(upper_torso_mat),
make_bone(lower_torso_mat),
make_bone(upper_torso_mat * Mat4::<f32>::from(self.shoulder_l)),
make_bone(upper_torso_mat * Mat4::<f32>::from(self.shoulder_r)),
make_bone(shoulder_l_mat * Mat4::<f32>::from(self.hand_l)),
make_bone(shoulder_r_mat * Mat4::<f32>::from(self.hand_r)),
make_bone(leg_l_mat),
make_bone(leg_r_mat),
make_bone(leg_l_mat * Mat4::<f32>::from(self.foot_l)),
make_bone(leg_r_mat * Mat4::<f32>::from(self.foot_r)),
];
let computed_skeleton = ComputedGolemSkeleton {
head: head_mat,
jaw: upper_torso_mat * Mat4::<f32>::from(self.head) * Mat4::<f32>::from(self.jaw),
upper_torso: upper_torso_mat,
lower_torso: lower_torso_mat,
shoulder_l: upper_torso_mat * Mat4::<f32>::from(self.shoulder_l),
shoulder_r: upper_torso_mat * Mat4::<f32>::from(self.shoulder_r),
hand_l: shoulder_l_mat * Mat4::<f32>::from(self.hand_l),
hand_r: shoulder_r_mat * Mat4::<f32>::from(self.hand_r),
leg_l: leg_l_mat,
leg_r: leg_r_mat,
foot_l: leg_l_mat * Mat4::<f32>::from(self.foot_l),
foot_r: leg_r_mat * Mat4::<f32>::from(self.foot_r),
};
let (mount_mat, mount_orientation) = (
head_mat,
self.torso.orientation * self.upper_torso.orientation * self.head.orientation,
);
let mount_position = mount_mat.mul_point(mount_point(&body));
Offsets {
viewpoint: Some((head_mat * Vec4::new(0.0, 0.0, 5.0, 1.0)).xyz()),
// TODO: see quadruped_medium for how to animate this
mount_bone: Transform {
position: mount_position,
orientation: mount_orientation,
scale: Vec3::one(),
},
..Default::default()
}
computed_skeleton.set_figure_bone_data(buf);
computed_skeleton
}
}
@ -253,9 +240,24 @@ impl<'a> From<&'a Body> for SkeletonAttr {
}
}
fn mount_point(body: &Body) -> Vec3<f32> {
pub fn mount_mat(
computed_skeleton: &ComputedGolemSkeleton,
skeleton: &GolemSkeleton,
) -> (Mat4<f32>, Quaternion<f32>) {
(
computed_skeleton.head,
skeleton.torso.orientation * skeleton.upper_torso.orientation * skeleton.head.orientation,
)
}
pub fn mount_transform(
body: &Body,
computed_skeleton: &ComputedGolemSkeleton,
skeleton: &GolemSkeleton,
) -> Transform<f32, f32, f32> {
use comp::golem::Species::*;
match (body.species, body.body_type) {
let mount_point = match (body.species, body.body_type) {
(StoneGolem, _) => (0.0, 0.5, 10.0),
(Treant, _) => (0.0, 0.0, 14.0),
(ClayGolem, _) => (0.0, 0.0, 12.0),
@ -266,5 +268,12 @@ fn mount_point(body: &Body) -> Vec3<f32> {
(Mogwai, _) => (0.0, 11.0, 10.5),
(IronGolem, _) => (0.0, 0.0, 17.0),
}
.into()
.into();
let (mount_mat, orientation) = mount_mat(computed_skeleton, skeleton);
Transform {
position: mount_mat.mul_point(mount_point),
orientation,
scale: Vec3::one(),
}
}

View File

@ -3,22 +3,23 @@ pub mod idle;
// Reexports
pub use self::idle::IdleAnimation;
use super::{FigureBoneData, Offsets, Skeleton, make_bone, vek::*};
use super::{FigureBoneData, Skeleton, vek::*};
use common::comp::{self, body::item::ItemArmorKind};
use core::convert::TryFrom;
use std::f32::consts::PI;
pub type Body = comp::body::item::Body;
skeleton_impls!(struct ItemSkeleton {
+ bone0,
skeleton_impls!(struct ItemSkeleton ComputedItemSkeleton {
+ bone0
});
impl Skeleton for ItemSkeleton {
type Attr = SkeletonAttr;
type Body = Body;
type ComputedSkeleton = ComputedItemSkeleton;
const BONE_COUNT: usize = 1;
const BONE_COUNT: usize = ComputedItemSkeleton::BONE_COUNT;
#[cfg(feature = "use-dyn-lib")]
const COMPUTE_FN: &'static [u8] = b"item_compute_mats\0";
@ -28,21 +29,15 @@ impl Skeleton for ItemSkeleton {
base_mat: Mat4<f32>,
buf: &mut [FigureBoneData; super::MAX_BONE_COUNT],
body: Self::Body,
) -> Offsets {
) -> Self::ComputedSkeleton {
let scale_mat = Mat4::scaling_3d(1.0 / 11.0 * Self::scale(&body));
let bone0_mat = base_mat * scale_mat * Mat4::<f32>::from(self.bone0);
*(<&mut [_; Self::BONE_COUNT]>::try_from(&mut buf[0..Self::BONE_COUNT]).unwrap()) =
[make_bone(bone0_mat)];
Offsets {
lantern: Some((bone0_mat * Vec4::new(0.0, 0.0, 3.5, 1.0)).xyz()),
mount_bone: Transform {
position: comp::Body::Item(body).mount_offset().into_tuple().into(),
..Default::default()
},
..Default::default()
}
let computed_skeleton = ComputedItemSkeleton { bone0: bone0_mat };
computed_skeleton.set_figure_bone_data(buf);
computed_skeleton
}
}

View File

@ -2,15 +2,43 @@
#[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");
macro_rules! replace_with_unit {
($_:tt) => {
()
};
}
macro_rules! skeleton_impls {
{ struct $Skeleton:ident { $( $(+ $bone_vis:vis)? $bone:ident ),* $(,)? $(:: $($field:ident : $field_ty:ty),* $(,)? )? } } => {
{
struct $Skeleton:ident $ComputedSkeleton:ident {
$(+ $mesh_bone:ident)*
$($bone:ident)*
$(::
$($field:ident : $field_ty:ty),* $(,)?
)?
}
} => {
#[derive(Clone, Default)]
pub struct $ComputedSkeleton {
$(pub $mesh_bone: $crate::vek::Mat4<f32>,)*
}
impl $ComputedSkeleton {
pub const BONE_COUNT: usize = [$(replace_with_unit!($mesh_bone),)*].len();
pub fn set_figure_bone_data(&self, buf: &mut [$crate::FigureBoneData; $crate::MAX_BONE_COUNT]) {
*(<&mut [_; Self::BONE_COUNT]>::try_from(&mut buf[0..Self::BONE_COUNT]).unwrap()) = [
$($crate::make_bone(self.$mesh_bone),)*
];
}
}
#[derive(Clone, Default)]
pub struct $Skeleton {
$(
$($bone_vis)? $bone: $crate::Bone,
)*
$(pub $mesh_bone: $crate::Bone,)*
$(pub $bone: $crate::Bone,)*
$($(
$field : $field_ty,
pub $field : $field_ty,
)*)?
}
@ -23,9 +51,8 @@ macro_rules! skeleton_impls {
fn lerp_unclamped_precise(from: Self, to: Self, factor: Factor) -> Self::Output {
Self::Output {
$(
$bone: Lerp::lerp_unclamped_precise(from.$bone, to.$bone, factor),
)*
$($mesh_bone: Lerp::lerp_unclamped_precise(from.$mesh_bone, to.$mesh_bone, factor),)*
$($bone: Lerp::lerp_unclamped_precise(from.$bone, to.$bone, factor),)*
$($(
$field : to.$field.clone(),
)*)?
@ -34,9 +61,8 @@ macro_rules! skeleton_impls {
fn lerp_unclamped(from: Self, to: Self, factor: Factor) -> Self::Output {
Self::Output {
$(
$bone: Lerp::lerp_unclamped(from.$bone, to.$bone, factor),
)*
$($mesh_bone: Lerp::lerp_unclamped(from.$mesh_bone, to.$mesh_bone, factor),)*
$($bone: Lerp::lerp_unclamped(from.$bone, to.$bone, factor),)*
$($(
$field : to.$field.clone(),
)*)?
@ -71,7 +97,6 @@ pub mod vek;
use self::vek::*;
use bytemuck::{Pod, Zeroable};
use common::comp::tool::ToolKind;
#[cfg(feature = "use-dyn-lib")]
use {
common_dynlib::LoadedLib, lazy_static::lazy_static, std::ffi::CStr, std::sync::Arc,
@ -105,68 +130,10 @@ lazy_static! {
#[cfg(feature = "use-dyn-lib")]
pub fn init() { lazy_static::initialize(&LIB); }
// Offsets that will be returned after computing the skeleton matrices
#[derive(Default)]
pub struct Offsets {
pub lantern: Option<Vec3<f32>>,
pub viewpoint: Option<Vec3<f32>>,
pub mount_bone: Transform<f32, f32, f32>,
pub primary_trail_mat: Option<(Mat4<f32>, TrailSource)>,
pub secondary_trail_mat: Option<(Mat4<f32>, TrailSource)>,
pub heads: Vec<Vec3<f32>>,
pub tail: Option<(Vec3<f32>, Vec3<f32>)>,
}
#[derive(Clone, Copy)]
pub enum TrailSource {
Weapon,
GliderLeft,
GliderRight,
Propeller(f32),
}
impl TrailSource {
pub fn relative_offsets(&self, tool: Option<ToolKind>) -> (Vec4<f32>, Vec4<f32>) {
// Offsets
const GLIDER_VERT: f32 = 5.0;
const GLIDER_HORIZ: f32 = 15.0;
// Trail width
const GLIDER_WIDTH: f32 = 1.0;
match self {
Self::Weapon => {
let lengths = match tool {
Some(ToolKind::Sword) => (0.0, 29.25),
Some(ToolKind::Axe) => (10.0, 19.25),
Some(ToolKind::Hammer) => (10.0, 19.25),
Some(ToolKind::Staff) => (10.0, 19.25),
Some(ToolKind::Sceptre) => (10.0, 19.25),
_ => (0.0, 0.0),
};
(
Vec4::new(0.0, 0.0, lengths.0, 1.0),
Vec4::new(0.0, 0.0, lengths.1, 1.0),
)
},
Self::GliderLeft => (
Vec4::new(GLIDER_HORIZ, 0.0, GLIDER_VERT, 1.0),
Vec4::new(GLIDER_HORIZ + GLIDER_WIDTH, 0.0, GLIDER_VERT, 1.0),
),
Self::GliderRight => (
Vec4::new(-GLIDER_HORIZ, 0.0, GLIDER_VERT, 1.0),
Vec4::new(-(GLIDER_HORIZ + GLIDER_WIDTH), 0.0, GLIDER_VERT, 1.0),
),
Self::Propeller(length) => (
Vec4::new(0.0, 0.0, *length * 0.5, 1.0),
Vec4::new(0.0, 0.0, *length, 1.0),
),
}
}
}
pub trait Skeleton: Send + Sync + 'static {
type Attr;
type Body;
type ComputedSkeleton;
const BONE_COUNT: usize;
@ -178,7 +145,7 @@ pub trait Skeleton: Send + Sync + 'static {
base_mat: Mat4<f32>,
buf: &mut [FigureBoneData; MAX_BONE_COUNT],
body: Self::Body,
) -> Offsets {
) -> Self::ComputedSkeleton {
#[cfg(not(feature = "use-dyn-lib"))]
{
self.compute_matrices_inner(base_mat, buf, body)
@ -189,7 +156,12 @@ pub trait Skeleton: Send + Sync + 'static {
let lib = &lock.as_ref().unwrap().lib;
let compute_fn: common_dynlib::Symbol<
fn(&Self, Mat4<f32>, &mut [FigureBoneData; MAX_BONE_COUNT], Self::Body) -> Offsets,
fn(
&Self,
Mat4<f32>,
&mut [FigureBoneData; MAX_BONE_COUNT],
Self::Body,
) -> Self::ComputedSkeleton,
> = unsafe { lib.get(Self::COMPUTE_FN) }.unwrap_or_else(|e| {
panic!(
"Trying to use: {} but had error: {:?}",
@ -210,7 +182,7 @@ pub trait Skeleton: Send + Sync + 'static {
base_mat: Mat4<f32>,
buf: &mut [FigureBoneData; MAX_BONE_COUNT],
body: Self::Body,
) -> Offsets;
) -> Self::ComputedSkeleton;
}
pub fn compute_matrices<S: Skeleton>(
@ -218,7 +190,7 @@ pub fn compute_matrices<S: Skeleton>(
base_mat: Mat4<f32>,
buf: &mut [FigureBoneData; MAX_BONE_COUNT],
body: S::Body,
) -> Offsets {
) -> S::ComputedSkeleton {
S::compute_matrices(skeleton, base_mat, buf, body)
}

View File

@ -5,22 +5,23 @@ pub mod shoot;
// Reexports
pub use self::{beam::BeamAnimation, idle::IdleAnimation, shoot::ShootAnimation};
use super::{FigureBoneData, Offsets, Skeleton, make_bone, vek::*};
use super::{FigureBoneData, Skeleton, vek::*};
use common::comp::{self};
use core::convert::TryFrom;
pub type Body = comp::object::Body;
skeleton_impls!(struct ObjectSkeleton {
+ bone0,
+ bone1,
skeleton_impls!(struct ObjectSkeleton ComputedObjectSkeleton {
+ bone0
+ bone1
});
impl Skeleton for ObjectSkeleton {
type Attr = SkeletonAttr;
type Body = Body;
type ComputedSkeleton = ComputedObjectSkeleton;
const BONE_COUNT: usize = 2;
const BONE_COUNT: usize = ComputedObjectSkeleton::BONE_COUNT;
#[cfg(feature = "use-dyn-lib")]
const COMPUTE_FN: &'static [u8] = b"object_compute_mats\0";
@ -29,24 +30,19 @@ impl Skeleton for ObjectSkeleton {
&self,
base_mat: Mat4<f32>,
buf: &mut [FigureBoneData; super::MAX_BONE_COUNT],
body: Self::Body,
) -> Offsets {
_body: Self::Body,
) -> Self::ComputedSkeleton {
let scale_mat = Mat4::scaling_3d(1.0 / 11.0);
let bone0_mat = base_mat * scale_mat * Mat4::<f32>::from(self.bone0);
*(<&mut [_; Self::BONE_COUNT]>::try_from(&mut buf[0..Self::BONE_COUNT]).unwrap()) = [
make_bone(bone0_mat),
make_bone(scale_mat * Mat4::<f32>::from(self.bone1)), /* Decorellated from ori */
];
Offsets {
// TODO: see quadruped_medium for how to animate this
mount_bone: Transform {
position: comp::Body::Object(body).mount_offset().into_tuple().into(),
..Default::default()
},
..Default::default()
}
let computed_skeleton = ComputedObjectSkeleton {
bone0: bone0_mat,
bone1: scale_mat * Mat4::<f32>::from(self.bone1), /* Decorellated from ori */
};
computed_skeleton.set_figure_bone_data(buf);
computed_skeleton
}
}

View File

@ -1,5 +1,3 @@
use crate::{Offsets, make_bone};
use super::{
Skeleton,
vek::{Lerp, Mat4, Transform, Vec3, Vec4},
@ -10,23 +8,23 @@ use vek::Quaternion;
pub type Body = comp::plugin::Body;
skeleton_impls!(struct PluginSkeleton {
+ bone0,
+ bone1,
+ bone2,
+ bone3,
+ bone4,
+ bone5,
+ bone6,
+ bone7,
+ bone8,
+ bone9,
+ bone10,
+ bone11,
+ bone12,
+ bone13,
+ bone14,
+ bone15,
skeleton_impls!(struct PluginSkeleton ComputedPluginSkeleton {
+ bone0
+ bone1
+ bone2
+ bone3
+ bone4
+ bone5
+ bone6
+ bone7
+ bone8
+ bone9
+ bone10
+ bone11
+ bone12
+ bone13
+ bone14
+ bone15
});
impl PluginSkeleton {
@ -71,8 +69,9 @@ impl PluginSkeleton {
impl Skeleton for PluginSkeleton {
type Attr = SkeletonAttr;
type Body = Body;
type ComputedSkeleton = ComputedPluginSkeleton;
const BONE_COUNT: usize = 16;
const BONE_COUNT: usize = ComputedPluginSkeleton::BONE_COUNT;
#[cfg(feature = "use-dyn-lib")]
const COMPUTE_FN: &'static [u8] = b"plugin_compute_mats\0";
@ -81,43 +80,31 @@ impl Skeleton for PluginSkeleton {
&self,
base_mat: Mat4<f32>,
buf: &mut [crate::FigureBoneData; crate::MAX_BONE_COUNT],
body: Self::Body,
) -> crate::Offsets {
_body: Self::Body,
) -> Self::ComputedSkeleton {
let base_mat = base_mat * Mat4::scaling_3d(1.0 / 13.0);
*(<&mut [_; Self::BONE_COUNT]>::try_from(&mut buf[0..Self::BONE_COUNT]).unwrap()) = [
make_bone(base_mat * Mat4::<f32>::from(self.bone0)),
make_bone(base_mat * Mat4::<f32>::from(self.bone1)),
make_bone(base_mat * Mat4::<f32>::from(self.bone2)),
make_bone(base_mat * Mat4::<f32>::from(self.bone3)),
make_bone(base_mat * Mat4::<f32>::from(self.bone4)),
make_bone(base_mat * Mat4::<f32>::from(self.bone5)),
make_bone(base_mat * Mat4::<f32>::from(self.bone6)),
make_bone(base_mat * Mat4::<f32>::from(self.bone7)),
make_bone(base_mat * Mat4::<f32>::from(self.bone8)),
make_bone(base_mat * Mat4::<f32>::from(self.bone9)),
make_bone(base_mat * Mat4::<f32>::from(self.bone10)),
make_bone(base_mat * Mat4::<f32>::from(self.bone11)),
make_bone(base_mat * Mat4::<f32>::from(self.bone12)),
make_bone(base_mat * Mat4::<f32>::from(self.bone13)),
make_bone(base_mat * Mat4::<f32>::from(self.bone14)),
make_bone(base_mat * Mat4::<f32>::from(self.bone15)),
];
Offsets {
lantern: None,
viewpoint: Some(
(base_mat * Mat4::<f32>::from(self.bone0) * Vec4::new(0.0, 3.0, 0.0, 1.0)).xyz(),
),
// TODO: see quadruped_medium for how to animate this
mount_bone: Transform {
position: comp::Body::Plugin(body).mount_offset().into_tuple().into(),
..Default::default()
},
primary_trail_mat: None,
secondary_trail_mat: None,
heads: Default::default(),
tail: None,
}
let computed_skeleton = ComputedPluginSkeleton {
bone0: base_mat * Mat4::<f32>::from(self.bone0),
bone1: base_mat * Mat4::<f32>::from(self.bone1),
bone2: base_mat * Mat4::<f32>::from(self.bone2),
bone3: base_mat * Mat4::<f32>::from(self.bone3),
bone4: base_mat * Mat4::<f32>::from(self.bone4),
bone5: base_mat * Mat4::<f32>::from(self.bone5),
bone6: base_mat * Mat4::<f32>::from(self.bone6),
bone7: base_mat * Mat4::<f32>::from(self.bone7),
bone8: base_mat * Mat4::<f32>::from(self.bone8),
bone9: base_mat * Mat4::<f32>::from(self.bone9),
bone10: base_mat * Mat4::<f32>::from(self.bone10),
bone11: base_mat * Mat4::<f32>::from(self.bone11),
bone12: base_mat * Mat4::<f32>::from(self.bone12),
bone13: base_mat * Mat4::<f32>::from(self.bone13),
bone14: base_mat * Mat4::<f32>::from(self.bone14),
bone15: base_mat * Mat4::<f32>::from(self.bone15),
};
computed_skeleton.set_figure_bone_data(buf);
computed_skeleton
}
}

View File

@ -21,7 +21,7 @@ pub use self::{
tailwhip::TailwhipAnimation,
};
use super::{FigureBoneData, Offsets, Skeleton, make_bone, vek::*};
use super::{FigureBoneData, Skeleton, vek::*};
use common::{
comp::{self},
states::utils::StageSection,
@ -30,31 +30,32 @@ use core::convert::TryFrom;
pub type Body = comp::quadruped_low::Body;
skeleton_impls!(struct QuadrupedLowSkeleton {
+ head_c_upper,
+ pub head_c_lower,
+ jaw_c,
+ head_l_upper,
+ pub head_l_lower,
+ jaw_l,
+ head_r_upper,
+ pub head_r_lower,
+ jaw_r,
+ chest,
+ tail_front,
+ tail_rear,
+ foot_fl,
+ foot_fr,
+ foot_bl,
+ foot_br,
mount,
skeleton_impls!(struct QuadrupedLowSkeleton ComputedQuadrupedLowSkeleton {
+ head_c_upper
+ head_c_lower
+ jaw_c
+ head_l_upper
+ head_l_lower
+ jaw_l
+ head_r_upper
+ head_r_lower
+ jaw_r
+ chest
+ tail_front
+ tail_rear
+ foot_fl
+ foot_fr
+ foot_bl
+ foot_br
mount
});
impl Skeleton for QuadrupedLowSkeleton {
type Attr = SkeletonAttr;
type Body = Body;
type ComputedSkeleton = ComputedQuadrupedLowSkeleton;
const BONE_COUNT: usize = 16;
const BONE_COUNT: usize = ComputedQuadrupedLowSkeleton::BONE_COUNT;
#[cfg(feature = "use-dyn-lib")]
const COMPUTE_FN: &'static [u8] = b"quadruped_low_compute_mats\0";
@ -67,13 +68,13 @@ impl Skeleton for QuadrupedLowSkeleton {
base_mat: Mat4<f32>,
buf: &mut [FigureBoneData; super::MAX_BONE_COUNT],
body: Self::Body,
) -> Offsets {
) -> Self::ComputedSkeleton {
let attr = SkeletonAttr::from(&body);
let base_mat = base_mat * Mat4::scaling_3d(attr.scaler / 11.0);
let chest_mat = base_mat * Mat4::<f32>::from(self.chest);
let tail_front = chest_mat * Mat4::<f32>::from(self.tail_front);
let tail_rear = tail_front * Mat4::<f32>::from(self.tail_rear);
let tail_front_mat = chest_mat * Mat4::<f32>::from(self.tail_front);
let tail_rear_mat = tail_front_mat * Mat4::<f32>::from(self.tail_rear);
let head_c_lower_mat = chest_mat * Mat4::<f32>::from(self.head_c_lower);
let head_c_upper_mat = head_c_lower_mat * Mat4::<f32>::from(self.head_c_upper);
let head_l_lower_mat = chest_mat * Mat4::<f32>::from(self.head_l_lower);
@ -81,64 +82,27 @@ impl Skeleton for QuadrupedLowSkeleton {
let head_r_lower_mat = chest_mat * Mat4::<f32>::from(self.head_r_lower);
let head_r_upper_mat = head_r_lower_mat * Mat4::<f32>::from(self.head_r_upper);
*(<&mut [_; Self::BONE_COUNT]>::try_from(&mut buf[0..Self::BONE_COUNT]).unwrap()) = [
make_bone(head_c_upper_mat),
make_bone(head_c_lower_mat),
make_bone(head_c_upper_mat * Mat4::<f32>::from(self.jaw_c)),
make_bone(head_l_upper_mat),
make_bone(head_l_lower_mat),
make_bone(head_l_upper_mat * Mat4::<f32>::from(self.jaw_l)),
make_bone(head_r_upper_mat),
make_bone(head_r_lower_mat),
make_bone(head_r_upper_mat * Mat4::<f32>::from(self.jaw_r)),
make_bone(chest_mat),
make_bone(tail_front),
make_bone(tail_rear),
make_bone(chest_mat * Mat4::<f32>::from(self.foot_fl)),
make_bone(chest_mat * Mat4::<f32>::from(self.foot_fr)),
make_bone(chest_mat * Mat4::<f32>::from(self.foot_bl)),
make_bone(chest_mat * Mat4::<f32>::from(self.foot_br)),
];
//let (mount_bone_mat, mount_bone_ori) = (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.
// NOTE: We apply the ori from base_mat externally so we don't need to worry
// about it here for now.
use comp::quadruped_low::Species::*;
let (mount_bone_mat, mount_bone_ori) = match (body.species, body.body_type) {
(Maneater, _) => (
head_c_upper_mat,
self.chest.orientation
* self.head_c_lower.orientation
* self.head_c_upper.orientation,
),
_ => (chest_mat, self.chest.orientation),
let computed_skeleton = ComputedQuadrupedLowSkeleton {
head_c_upper: head_c_upper_mat,
head_c_lower: head_c_lower_mat,
jaw_c: head_c_upper_mat * Mat4::<f32>::from(self.jaw_c),
head_l_upper: head_l_upper_mat,
head_l_lower: head_l_lower_mat,
jaw_l: head_l_upper_mat * Mat4::<f32>::from(self.jaw_l),
head_r_upper: head_r_upper_mat,
head_r_lower: head_r_lower_mat,
jaw_r: head_r_upper_mat * Mat4::<f32>::from(self.jaw_r),
chest: chest_mat,
tail_front: tail_front_mat,
tail_rear: tail_rear_mat,
foot_fl: chest_mat * Mat4::<f32>::from(self.foot_fl),
foot_fr: chest_mat * Mat4::<f32>::from(self.foot_fr),
foot_bl: chest_mat * Mat4::<f32>::from(self.foot_bl),
foot_br: chest_mat * Mat4::<f32>::from(self.foot_br),
};
let mount_position = (mount_bone_mat * Vec4::from_point(mount_point(&body)))
.homogenized()
.xyz();
let mount_orientation = mount_bone_ori;
Offsets {
viewpoint: Some((head_c_upper_mat * Vec4::new(0.0, 4.0, 1.0, 1.0)).xyz()),
mount_bone: Transform {
position: mount_position,
orientation: mount_orientation,
scale: Vec3::one(),
},
heads: vec![
(head_l_upper_mat * Vec4::unit_w()).xyz(),
(head_c_upper_mat * Vec4::unit_w()).xyz(),
(head_r_upper_mat * Vec4::unit_w()).xyz(),
],
tail: Some((
(tail_front * Vec4::unit_w()).xyz(),
(tail_rear * Vec4::new(0.0, -attr.tail_rear_length, 0.0, 1.0)).xyz(),
)),
..Default::default()
}
computed_skeleton.set_figure_bone_data(buf);
computed_skeleton
}
}
@ -151,7 +115,7 @@ pub struct SkeletonAttr {
chest: (f32, f32),
tail_front: (f32, f32),
tail_rear: (f32, f32),
tail_rear_length: f32,
pub tail_rear_length: f32,
feet_f: (f32, f32, f32),
feet_b: (f32, f32, f32),
lean: (f32, f32),
@ -495,9 +459,32 @@ impl<'a> From<&'a Body> for SkeletonAttr {
}
}
}
fn mount_point(body: &Body) -> Vec3<f32> {
pub fn mount_mat(
body: &Body,
computed_skeleton: &ComputedQuadrupedLowSkeleton,
skeleton: &QuadrupedLowSkeleton,
) -> (Mat4<f32>, Quaternion<f32>) {
use comp::quadruped_low::Species::*;
match (body.species, body.body_type) {
(Maneater, _) => (
computed_skeleton.head_c_upper,
skeleton.chest.orientation
* skeleton.head_c_lower.orientation
* skeleton.head_c_upper.orientation,
),
_ => (computed_skeleton.chest, skeleton.chest.orientation),
}
}
pub fn mount_transform(
body: &Body,
computed_skeleton: &ComputedQuadrupedLowSkeleton,
skeleton: &QuadrupedLowSkeleton,
) -> Transform<f32, f32, f32> {
use comp::quadruped_low::Species::*;
let mount_point = match (body.species, body.body_type) {
(Crocodile, _) => (0.0, 3.5, 3.5),
(Alligator, _) => (0.0, 2.5, 3.0),
(Salamander, _) => (0.0, 2.0, 4.0),
@ -523,7 +510,14 @@ fn mount_point(body: &Body) -> Vec3<f32> {
(Snaretongue, _) => (0.0, 2.0, 6.0),
(Hydra, _) => (0.0, 2.0, 4.0),
}
.into()
.into();
let (mount_mat, orientation) = mount_mat(body, computed_skeleton, skeleton);
Transform {
position: mount_mat.mul_point(mount_point),
orientation,
scale: Vec3::one(),
}
}
pub fn quadruped_low_alpha(

View File

@ -16,7 +16,7 @@ pub use self::{
shockwave::ShockwaveAnimation, stunned::StunnedAnimation,
};
use super::{FigureBoneData, Offsets, Skeleton, make_bone, vek::*};
use super::{FigureBoneData, Skeleton, vek::*};
use common::{
comp::{self},
states::utils::StageSection,
@ -25,30 +25,31 @@ use core::convert::TryFrom;
pub type Body = comp::quadruped_medium::Body;
skeleton_impls!(struct QuadrupedMediumSkeleton {
+ head,
+ neck,
+ jaw,
+ tail,
+ torso_front,
+ torso_back,
+ ears,
+ leg_fl,
+ leg_fr,
+ leg_bl,
+ leg_br,
+ foot_fl,
+ foot_fr,
+ foot_bl,
+ foot_br,
mount,
skeleton_impls!(struct QuadrupedMediumSkeleton ComputedQuadrupedMediumSkeleton {
+ head
+ neck
+ jaw
+ tail
+ torso_front
+ torso_back
+ ears
+ leg_fl
+ leg_fr
+ leg_bl
+ leg_br
+ foot_fl
+ foot_fr
+ foot_bl
+ foot_br
mount
});
impl Skeleton for QuadrupedMediumSkeleton {
type Attr = SkeletonAttr;
type Body = Body;
type ComputedSkeleton = ComputedQuadrupedMediumSkeleton;
const BONE_COUNT: usize = 15;
const BONE_COUNT: usize = ComputedQuadrupedMediumSkeleton::BONE_COUNT;
#[cfg(feature = "use-dyn-lib")]
const COMPUTE_FN: &'static [u8] = b"quadruped_medium_compute_mats\0";
@ -61,7 +62,7 @@ impl Skeleton for QuadrupedMediumSkeleton {
base_mat: Mat4<f32>,
buf: &mut [FigureBoneData; super::MAX_BONE_COUNT],
body: Self::Body,
) -> Offsets {
) -> Self::ComputedSkeleton {
let base_mat = base_mat * Mat4::scaling_3d(SkeletonAttr::from(&body).scaler / 11.0);
let torso_front_mat = base_mat * Mat4::<f32>::from(self.torso_front);
@ -73,77 +74,26 @@ impl Skeleton for QuadrupedMediumSkeleton {
let leg_br_mat = torso_back_mat * Mat4::<f32>::from(self.leg_br);
let head_mat = neck_mat * Mat4::<f32>::from(self.head);
*(<&mut [_; Self::BONE_COUNT]>::try_from(&mut buf[0..Self::BONE_COUNT]).unwrap()) = [
make_bone(head_mat),
make_bone(neck_mat),
make_bone(head_mat * Mat4::<f32>::from(self.jaw)),
make_bone(torso_back_mat * Mat4::<f32>::from(self.tail)),
make_bone(torso_front_mat),
make_bone(torso_back_mat),
make_bone(head_mat * Mat4::<f32>::from(self.ears)),
make_bone(leg_fl_mat),
make_bone(leg_fr_mat),
make_bone(leg_bl_mat),
make_bone(leg_br_mat),
make_bone(leg_fl_mat * Mat4::<f32>::from(self.foot_fl)),
make_bone(leg_fr_mat * Mat4::<f32>::from(self.foot_fr)),
make_bone(leg_bl_mat * Mat4::<f32>::from(self.foot_bl)),
make_bone(leg_br_mat * Mat4::<f32>::from(self.foot_br)),
];
use comp::quadruped_medium::Species::*;
let (mount_bone_mat, mount_bone_ori) = match (body.species, body.body_type) {
(Mammoth, _) => (
head_mat,
self.torso_front.orientation * self.neck.orientation * self.head.orientation,
),
(Akhlut, _) => (
neck_mat,
self.torso_front.orientation * self.neck.orientation,
),
_ => (torso_front_mat, self.torso_front.orientation),
let computed_skeleton = ComputedQuadrupedMediumSkeleton {
head: head_mat,
neck: neck_mat,
jaw: head_mat * Mat4::<f32>::from(self.jaw),
tail: torso_back_mat * Mat4::<f32>::from(self.tail),
torso_front: torso_front_mat,
torso_back: torso_back_mat,
ears: head_mat * Mat4::<f32>::from(self.ears),
leg_fl: leg_fl_mat,
leg_fr: leg_fr_mat,
leg_bl: leg_bl_mat,
leg_br: leg_br_mat,
foot_fl: leg_fl_mat * Mat4::<f32>::from(self.foot_fl),
foot_fr: leg_fr_mat * Mat4::<f32>::from(self.foot_fr),
foot_bl: leg_bl_mat * Mat4::<f32>::from(self.foot_bl),
foot_br: leg_br_mat * Mat4::<f32>::from(self.foot_br),
};
// 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 {
viewpoint: match body.species {
Akhlut | Catoblepas | Lion => {
Some((head_mat * Vec4::new(0.0, 8.0, 0.0, 1.0)).xyz())
},
Barghest | Saber => Some((head_mat * Vec4::new(0.0, 8.0, 3.0, 1.0)).xyz()),
Cattle | Highland | Bonerattler | Ngoubou | Yak => {
Some((head_mat * Vec4::new(0.0, 6.0, -1.0, 1.0)).xyz())
},
Antelope | Deer | Donkey | Bear | Mouflon | Panda => {
Some((head_mat * Vec4::new(0.0, 3.0, 3.0, 1.0)).xyz())
},
Camel | Hirdrasil | Horse | Kelpie | Zebra => {
Some((head_mat * Vec4::new(0.0, 2.0, 5.0, 1.0)).xyz())
},
Darkhound | Llama | Snowleopard | Tiger | Wolf | ClaySteed => {
Some((head_mat * Vec4::new(0.0, 4.0, 1.0, 1.0)).xyz())
},
Dreadhorn | Mammoth | Moose | Tarasque => {
Some((head_mat * Vec4::new(0.0, 13.0, -3.0, 1.0)).xyz())
},
Frostfang => Some((head_mat * Vec4::new(0.0, 5.0, 3.0, 1.0)).xyz()),
Grolgar | Roshwalr => Some((head_mat * Vec4::new(0.0, 8.0, 6.0, 1.0)).xyz()),
_ => Some((head_mat * Vec4::new(0.0, 2.0, 0.0, 1.0)).xyz()),
},
mount_bone: Transform {
position: mount_position,
orientation: mount_orientation,
scale: Vec3::one(),
},
..Default::default()
}
computed_skeleton.set_figure_bone_data(buf);
computed_skeleton
}
}
@ -771,9 +721,55 @@ impl<'a> From<&'a Body> for SkeletonAttr {
}
}
fn mount_point(body: &Body) -> Vec3<f32> {
use comp::quadruped_medium::{BodyType::*, Species::*};
pub fn viewpoint(body: &Body) -> Vec4<f32> {
use comp::quadruped_medium::Species::*;
match body.species {
Akhlut | Catoblepas | Lion => Vec4::new(0.0, 8.0, 0.0, 1.0),
Barghest | Saber => Vec4::new(0.0, 8.0, 3.0, 1.0),
Cattle | Highland | Bonerattler | Ngoubou | Yak => Vec4::new(0.0, 6.0, -1.0, 1.0),
Antelope | Deer | Donkey | Bear | Mouflon | Panda => Vec4::new(0.0, 3.0, 3.0, 1.0),
Camel | Hirdrasil | Horse | Kelpie | Zebra => Vec4::new(0.0, 2.0, 5.0, 1.0),
Darkhound | Llama | Snowleopard | Tiger | Wolf | ClaySteed => Vec4::new(0.0, 4.0, 1.0, 1.0),
Dreadhorn | Mammoth | Moose | Tarasque => Vec4::new(0.0, 13.0, -3.0, 1.0),
Frostfang => Vec4::new(0.0, 5.0, 3.0, 1.0),
Grolgar | Roshwalr => Vec4::new(0.0, 8.0, 6.0, 1.0),
_ => Vec4::new(0.0, 2.0, 0.0, 1.0),
}
}
pub fn mount_mat(
body: &Body,
computed_skeleton: &ComputedQuadrupedMediumSkeleton,
skeleton: &QuadrupedMediumSkeleton,
) -> (Mat4<f32>, Quaternion<f32>) {
use comp::quadruped_medium::Species::*;
match (body.species, body.body_type) {
(Mammoth, _) => (
computed_skeleton.head,
skeleton.torso_front.orientation
* skeleton.neck.orientation
* skeleton.head.orientation,
),
(Akhlut, _) => (
computed_skeleton.neck,
skeleton.torso_front.orientation * skeleton.neck.orientation,
),
_ => (
computed_skeleton.torso_front,
skeleton.torso_front.orientation,
),
}
}
pub fn mount_transform(
body: &Body,
computed_skeleton: &ComputedQuadrupedMediumSkeleton,
skeleton: &QuadrupedMediumSkeleton,
) -> Transform<f32, f32, f32> {
use comp::quadruped_medium::{BodyType::*, Species::*};
let mount_point = match (body.species, body.body_type) {
(Grolgar, _) => (0.0, -6.0, 8.0),
(Saber, _) => (0.0, -17.0, 5.5),
(Tuskram, _) => (0.0, -17.0, 4.0),
@ -814,7 +810,14 @@ fn mount_point(body: &Body) -> Vec3<f32> {
(Bristleback, _) => (0.0, -7.0, 6.0),
(ClaySteed, _) => (0.0, -9.0, 3.0),
}
.into()
.into();
let (mount_mat, orientation) = mount_mat(body, computed_skeleton, skeleton);
Transform {
position: mount_mat.mul_point(mount_point),
orientation,
scale: Vec3::one(),
}
}
pub fn quadruped_medium_alpha(

View File

@ -14,28 +14,29 @@ pub use self::{
stunned::StunnedAnimation,
};
use super::{FigureBoneData, Offsets, Skeleton, make_bone, vek::*};
use super::{FigureBoneData, Skeleton, vek::*};
use common::comp::{self};
use core::convert::TryFrom;
pub type Body = comp::quadruped_small::Body;
skeleton_impls!(struct QuadrupedSmallSkeleton {
+ head,
+ chest,
+ leg_fl,
+ leg_fr,
+ leg_bl,
+ leg_br,
+ tail,
mount,
skeleton_impls!(struct QuadrupedSmallSkeleton ComputedQuadrupedSmallSkeleton {
+ head
+ chest
+ leg_fl
+ leg_fr
+ leg_bl
+ leg_br
+ tail
mount
});
impl Skeleton for QuadrupedSmallSkeleton {
type Attr = SkeletonAttr;
type Body = Body;
type ComputedSkeleton = ComputedQuadrupedSmallSkeleton;
const BONE_COUNT: usize = 7;
const BONE_COUNT: usize = ComputedQuadrupedSmallSkeleton::BONE_COUNT;
#[cfg(feature = "use-dyn-lib")]
const COMPUTE_FN: &'static [u8] = b"quadruped_small_compute_mats\0";
@ -48,34 +49,24 @@ impl Skeleton for QuadrupedSmallSkeleton {
base_mat: Mat4<f32>,
buf: &mut [FigureBoneData; super::MAX_BONE_COUNT],
body: Self::Body,
) -> Offsets {
) -> Self::ComputedSkeleton {
let chest_mat = base_mat
* Mat4::scaling_3d(SkeletonAttr::from(&body).scaler / 11.0)
* Mat4::<f32>::from(self.chest);
let head_mat = chest_mat * Mat4::<f32>::from(self.head);
*(<&mut [_; Self::BONE_COUNT]>::try_from(&mut buf[0..Self::BONE_COUNT]).unwrap()) = [
make_bone(head_mat),
make_bone(chest_mat),
make_bone(chest_mat * Mat4::<f32>::from(self.leg_fl)),
make_bone(chest_mat * Mat4::<f32>::from(self.leg_fr)),
make_bone(chest_mat * Mat4::<f32>::from(self.leg_bl)),
make_bone(chest_mat * Mat4::<f32>::from(self.leg_br)),
make_bone(chest_mat * Mat4::<f32>::from(self.tail)),
];
let (mount_bone_mat, mount_bone_ori) = (chest_mat, self.chest.orientation);
let mount_position = mount_bone_mat.mul_point(mount_point(&body));
let mount_orientation = mount_bone_ori;
let computed_skeleton = ComputedQuadrupedSmallSkeleton {
head: head_mat,
chest: chest_mat,
leg_fl: chest_mat * Mat4::<f32>::from(self.leg_fl),
leg_fr: chest_mat * Mat4::<f32>::from(self.leg_fr),
leg_bl: chest_mat * Mat4::<f32>::from(self.leg_bl),
leg_br: chest_mat * Mat4::<f32>::from(self.leg_br),
tail: chest_mat * Mat4::<f32>::from(self.tail),
};
Offsets {
viewpoint: Some((head_mat * Vec4::new(0.0, 3.0, 0.0, 1.0)).xyz()),
mount_bone: Transform {
position: mount_position,
orientation: mount_orientation,
scale: Vec3::one(),
},
..Default::default()
}
computed_skeleton.set_figure_bone_data(buf);
computed_skeleton
}
}
@ -420,9 +411,21 @@ impl<'a> From<&'a Body> for SkeletonAttr {
}
}
fn mount_point(body: &Body) -> Vec3<f32> {
pub fn mount_mat(
computed_skeleton: &ComputedQuadrupedSmallSkeleton,
skeleton: &QuadrupedSmallSkeleton,
) -> (Mat4<f32>, Quaternion<f32>) {
(computed_skeleton.chest, skeleton.chest.orientation)
}
pub fn mount_transform(
body: &Body,
computed_skeleton: &ComputedQuadrupedSmallSkeleton,
skeleton: &QuadrupedSmallSkeleton,
) -> Transform<f32, f32, f32> {
use comp::quadruped_small::{BodyType::*, Species::*};
match (body.species, body.body_type) {
let mount_point = match (body.species, body.body_type) {
(Pig, _) => (0.0, 1.0, 4.0),
(Fox, _) => (0.0, 0.0, 2.5),
(Sheep, _) => (0.0, -1.0, 3.5),
@ -454,5 +457,12 @@ fn mount_point(body: &Body) -> Vec3<f32> {
(TreantSapling, _) => (0.0, -4.0, 1.5),
(MossySnail, _) => (0.0, -2.0, 6.5),
}
.into()
.into();
let (mount_mat, orientation) = mount_mat(computed_skeleton, skeleton);
Transform {
position: mount_mat.mul_point(mount_point),
orientation,
scale: Vec3::one(),
}
}

View File

@ -3,24 +3,25 @@ pub mod idle;
// Reexports
pub use self::idle::IdleAnimation;
use super::{FigureBoneData, Offsets, Skeleton, TrailSource, make_bone, vek::*};
use super::{FigureBoneData, Skeleton, vek::*};
use common::comp::{self};
use core::convert::TryFrom;
pub type Body = comp::ship::Body;
skeleton_impls!(struct ShipSkeleton {
+ bone0,
+ bone1,
+ bone2,
+ bone3,
skeleton_impls!(struct ShipSkeleton ComputedShipSkeleton {
+ bone0
+ bone1
+ bone2
+ bone3
});
impl Skeleton for ShipSkeleton {
type Attr = SkeletonAttr;
type Body = Body;
type ComputedSkeleton = ComputedShipSkeleton;
const BONE_COUNT: usize = 4;
const BONE_COUNT: usize = ComputedShipSkeleton::BONE_COUNT;
#[cfg(feature = "use-dyn-lib")]
const COMPUTE_FN: &'static [u8] = b"ship_compute_mats\0";
@ -29,38 +30,24 @@ impl Skeleton for ShipSkeleton {
&self,
base_mat: Mat4<f32>,
buf: &mut [FigureBoneData; super::MAX_BONE_COUNT],
body: Self::Body,
) -> Offsets {
_body: Self::Body,
) -> Self::ComputedSkeleton {
// Ships are normal scale
let scale_mat = Mat4::scaling_3d(1.0);
let attr = SkeletonAttr::from(&body);
let bone0_mat = base_mat * scale_mat * Mat4::<f32>::from(self.bone0);
let bone1_mat = bone0_mat * Mat4::<f32>::from(self.bone1);
let bone2_mat = bone0_mat * Mat4::<f32>::from(self.bone2);
*(<&mut [_; Self::BONE_COUNT]>::try_from(&mut buf[0..Self::BONE_COUNT]).unwrap()) = [
make_bone(bone0_mat),
make_bone(bone1_mat),
make_bone(bone2_mat),
make_bone(bone0_mat * Mat4::<f32>::from(self.bone3)),
];
Offsets {
// TODO: see quadruped_medium for how to animate this
mount_bone: Transform {
position: (base_mat * scale_mat)
.mul_point(comp::Body::Ship(body).mount_offset().into_tuple().into()),
..Default::default()
},
primary_trail_mat: attr
.bone1_prop_trail_offset
.map(|offset| (bone1_mat, TrailSource::Propeller(offset))),
secondary_trail_mat: attr
.bone2_prop_trail_offset
.map(|offset| (bone2_mat, TrailSource::Propeller(offset))),
..Default::default()
}
let computed_skeleton = ComputedShipSkeleton {
bone0: bone0_mat,
bone1: bone1_mat,
bone2: bone2_mat,
bone3: bone0_mat * Mat4::<f32>::from(self.bone3),
};
computed_skeleton.set_figure_bone_data(buf);
computed_skeleton
}
}
@ -72,8 +59,8 @@ pub struct SkeletonAttr {
bone1_ori: f32,
bone2_ori: f32,
bone_rotation_rate: f32,
bone1_prop_trail_offset: Option<f32>,
bone2_prop_trail_offset: Option<f32>,
pub bone1_prop_trail_offset: Option<f32>,
pub bone2_prop_trail_offset: Option<f32>,
}
impl<'a> TryFrom<&'a comp::Body> for SkeletonAttr {

View File

@ -10,33 +10,34 @@ pub use self::{
run::RunAnimation,
};
use super::{FigureBoneData, Offsets, Skeleton, make_bone, vek::*};
use super::{FigureBoneData, Skeleton, vek::*};
use common::comp::{self};
use core::convert::TryFrom;
pub type Body = comp::theropod::Body;
skeleton_impls!(struct TheropodSkeleton {
+ head,
+ jaw,
+ neck,
+ chest_front,
+ chest_back,
+ tail_front,
+ tail_back,
+ hand_l,
+ hand_r,
+ leg_l,
+ leg_r,
+ foot_l,
+ foot_r,
skeleton_impls!(struct TheropodSkeleton ComputedTheropodSkeleton {
+ head
+ jaw
+ neck
+ chest_front
+ chest_back
+ tail_front
+ tail_back
+ hand_l
+ hand_r
+ leg_l
+ leg_r
+ foot_l
+ foot_r
});
impl Skeleton for TheropodSkeleton {
type Attr = SkeletonAttr;
type Body = Body;
type ComputedSkeleton = ComputedTheropodSkeleton;
const BONE_COUNT: usize = 13;
const BONE_COUNT: usize = ComputedTheropodSkeleton::BONE_COUNT;
#[cfg(feature = "use-dyn-lib")]
const COMPUTE_FN: &'static [u8] = b"theropod_compute_mats\0";
@ -47,7 +48,7 @@ impl Skeleton for TheropodSkeleton {
base_mat: Mat4<f32>,
buf: &mut [FigureBoneData; super::MAX_BONE_COUNT],
body: Self::Body,
) -> Offsets {
) -> Self::ComputedSkeleton {
let base_mat = base_mat * Mat4::scaling_3d(SkeletonAttr::from(&body).scaler / 11.0);
let chest_front_mat = base_mat * Mat4::<f32>::from(self.chest_front);
@ -58,43 +59,24 @@ impl Skeleton for TheropodSkeleton {
let leg_l_mat = chest_back_mat * Mat4::<f32>::from(self.leg_l);
let leg_r_mat = chest_back_mat * Mat4::<f32>::from(self.leg_r);
*(<&mut [_; Self::BONE_COUNT]>::try_from(&mut buf[0..Self::BONE_COUNT]).unwrap()) = [
make_bone(head_mat),
make_bone(head_mat * Mat4::<f32>::from(self.jaw)),
make_bone(neck_mat),
make_bone(chest_front_mat),
make_bone(chest_back_mat),
make_bone(tail_front_mat),
make_bone(tail_front_mat * Mat4::<f32>::from(self.tail_back)),
make_bone(chest_front_mat * Mat4::<f32>::from(self.hand_l)),
make_bone(chest_front_mat * Mat4::<f32>::from(self.hand_r)),
make_bone(leg_l_mat),
make_bone(leg_r_mat),
make_bone(leg_l_mat * Mat4::<f32>::from(self.foot_l)),
make_bone(leg_r_mat * Mat4::<f32>::from(self.foot_r)),
];
let (mount_mat, mount_orientation) = match (body.species, body.body_type) {
(comp::body::theropod::Species::Archaeos, _) => (neck_mat, self.neck.orientation),
(comp::body::theropod::Species::Odonto, _) => (head_mat, self.head.orientation),
(comp::body::theropod::Species::Yale | comp::body::theropod::Species::Dodarock, _) => {
(chest_back_mat, self.chest_back.orientation)
},
_ => (chest_front_mat, self.chest_front.orientation),
let computed_skeleton = ComputedTheropodSkeleton {
head: head_mat,
jaw: head_mat * Mat4::<f32>::from(self.jaw),
neck: neck_mat,
chest_front: chest_front_mat,
chest_back: chest_back_mat,
tail_front: tail_front_mat,
tail_back: tail_front_mat * Mat4::<f32>::from(self.tail_back),
hand_l: chest_front_mat * Mat4::<f32>::from(self.hand_l),
hand_r: chest_front_mat * Mat4::<f32>::from(self.hand_r),
leg_l: leg_l_mat,
leg_r: leg_r_mat,
foot_l: leg_l_mat * Mat4::<f32>::from(self.foot_l),
foot_r: leg_r_mat * Mat4::<f32>::from(self.foot_r),
};
let mount_position = mount_mat.mul_point(mount_point(&body));
Offsets {
viewpoint: Some((head_mat * Vec4::new(0.0, 2.0, 0.0, 1.0)).xyz()),
// TODO: see quadruped_medium for how to animate this
mount_bone: Transform {
position: mount_position,
orientation: mount_orientation,
..Default::default()
},
..Default::default()
}
computed_skeleton.set_figure_bone_data(buf);
computed_skeleton
}
}
@ -284,9 +266,35 @@ impl<'a> From<&'a Body> for SkeletonAttr {
}
}
fn mount_point(body: &Body) -> Vec3<f32> {
pub fn mount_mat(
body: &Body,
computed_skeleton: &ComputedTheropodSkeleton,
skeleton: &TheropodSkeleton,
) -> (Mat4<f32>, Quaternion<f32>) {
use comp::theropod::Species::*;
match (body.species, body.body_type) {
(Archaeos, _) => (computed_skeleton.neck, skeleton.neck.orientation),
(Odonto, _) => (computed_skeleton.head, skeleton.head.orientation),
(Yale | Dodarock, _) => (
computed_skeleton.chest_back,
skeleton.chest_back.orientation,
),
_ => (
computed_skeleton.chest_front,
skeleton.chest_front.orientation,
),
}
}
pub fn mount_transform(
body: &Body,
computed_skeleton: &ComputedTheropodSkeleton,
skeleton: &TheropodSkeleton,
) -> Transform<f32, f32, f32> {
use comp::theropod::Species::*;
let mount_point = match (body.species, body.body_type) {
(Archaeos, _) => (0.0, 2.5, 6.0),
(Odonto, _) => (0.0, 10.0, 2.0),
(Sandraptor, _) => (0.0, -2.0, 5.0),
@ -298,5 +306,12 @@ fn mount_point(body: &Body) -> Vec3<f32> {
(Dodarock, _) => (0.0, 3.5, 5.0),
(Axebeak, _) => (0.0, -3.5, 6.5),
}
.into()
.into();
let (mount_mat, orientation) = mount_mat(body, computed_skeleton, skeleton);
Transform {
position: mount_mat.mul_point(mount_point),
orientation,
scale: Vec3::one(),
}
}

View File

@ -5,9 +5,9 @@ use anim::{
biped_large::BipedLargeSkeleton, biped_small::BipedSmallSkeleton,
bird_large::BirdLargeSkeleton, bird_medium::BirdMediumSkeleton, character::CharacterSkeleton,
crustacean::CrustaceanSkeleton, dragon::DragonSkeleton, fish_medium::FishMediumSkeleton,
fish_small::FishSmallSkeleton, golem::GolemSkeleton, object::ObjectSkeleton,
quadruped_low::QuadrupedLowSkeleton, quadruped_medium::QuadrupedMediumSkeleton,
quadruped_small::QuadrupedSmallSkeleton, theropod::TheropodSkeleton,
fish_small::FishSmallSkeleton, golem::GolemSkeleton, quadruped_low::QuadrupedLowSkeleton,
quadruped_medium::QuadrupedMediumSkeleton, quadruped_small::QuadrupedSmallSkeleton,
theropod::TheropodSkeleton,
};
use clap::Parser;
use common::{
@ -397,7 +397,7 @@ fn load_npc_bones(
let time = 0.0;
let mut buf = [FigureBoneData::default(); 16];
let offsets = match info.body {
let mount_mat = match info.body {
Body::Humanoid(body) => {
let back_carry_offset = inventory
.equipped(EquipSlot::Armor(ArmorSlot::Back))
@ -429,8 +429,9 @@ fn load_npc_bones(
&mut 1.0,
&anim::character::SkeletonAttr::from(&body),
);
let computed_skel = skel.compute_matrices(base_mat, &mut buf, body);
skel.compute_matrices(base_mat, &mut buf, body)
anim::character::mount_mat(&computed_skel, &skel).0
},
Body::QuadrupedSmall(body) => {
let skel = anim::quadruped_small::IdleAnimation::update_skeleton(
@ -440,8 +441,9 @@ fn load_npc_bones(
&mut 1.0,
&anim::quadruped_small::SkeletonAttr::from(&body),
);
let computed_skel = skel.compute_matrices(base_mat, &mut buf, body);
skel.compute_matrices(base_mat, &mut buf, body)
anim::quadruped_small::mount_mat(&computed_skel, &skel).0
},
Body::QuadrupedMedium(body) => {
let skel = anim::quadruped_medium::IdleAnimation::update_skeleton(
@ -451,7 +453,9 @@ fn load_npc_bones(
&mut 1.0,
&anim::quadruped_medium::SkeletonAttr::from(&body),
);
skel.compute_matrices(base_mat, &mut buf, body)
let computed_skel = skel.compute_matrices(base_mat, &mut buf, body);
anim::quadruped_medium::mount_mat(&body, &computed_skel, &skel).0
},
Body::BirdMedium(body) => {
let skel = anim::bird_medium::IdleAnimation::update_skeleton(
@ -461,7 +465,9 @@ fn load_npc_bones(
&mut 1.0,
&anim::bird_medium::SkeletonAttr::from(&body),
);
skel.compute_matrices(base_mat, &mut buf, body)
let computed_skel = skel.compute_matrices(base_mat, &mut buf, body);
anim::bird_medium::mount_mat(&computed_skel, &skel).0
},
Body::FishMedium(body) => {
let skel = anim::fish_medium::IdleAnimation::update_skeleton(
@ -477,7 +483,9 @@ fn load_npc_bones(
&mut 1.0,
&anim::fish_medium::SkeletonAttr::from(&body),
);
skel.compute_matrices(base_mat, &mut buf, body)
let computed_skel = skel.compute_matrices(base_mat, &mut buf, body);
anim::fish_medium::mount_mat(&computed_skel, &skel).0
},
Body::Dragon(body) => {
let skel = anim::dragon::IdleAnimation::update_skeleton(
@ -487,7 +495,9 @@ fn load_npc_bones(
&mut 1.0,
&anim::dragon::SkeletonAttr::from(&body),
);
skel.compute_matrices(base_mat, &mut buf, body)
let computed_skel = skel.compute_matrices(base_mat, &mut buf, body);
anim::dragon::mount_mat(&computed_skel, &skel).0
},
Body::BirdLarge(body) => {
let skel = anim::bird_large::IdleAnimation::update_skeleton(
@ -497,7 +507,9 @@ fn load_npc_bones(
&mut 1.0,
&anim::bird_large::SkeletonAttr::from(&body),
);
skel.compute_matrices(base_mat, &mut buf, body)
let computed_skel = skel.compute_matrices(base_mat, &mut buf, body);
anim::bird_large::mount_mat(&body, &computed_skel, &skel).0
},
Body::FishSmall(body) => {
let skel = anim::fish_small::IdleAnimation::update_skeleton(
@ -513,7 +525,9 @@ fn load_npc_bones(
&mut 1.0,
&anim::fish_small::SkeletonAttr::from(&body),
);
skel.compute_matrices(base_mat, &mut buf, body)
let computed_skel = skel.compute_matrices(base_mat, &mut buf, body);
anim::fish_small::mount_mat(&computed_skel, &skel).0
},
Body::BipedLarge(body) => {
let skel = anim::biped_large::IdleAnimation::update_skeleton(
@ -523,7 +537,9 @@ fn load_npc_bones(
&mut 1.0,
&anim::biped_large::SkeletonAttr::from(&body),
);
skel.compute_matrices(base_mat, &mut buf, body)
let computed_skel = skel.compute_matrices(base_mat, &mut buf, body);
anim::biped_large::mount_mat(&body, &computed_skel, &skel).0
},
Body::BipedSmall(body) => {
let skel = anim::biped_small::IdleAnimation::update_skeleton(
@ -539,18 +555,11 @@ fn load_npc_bones(
&mut 1.0,
&anim::biped_small::SkeletonAttr::from(&body),
);
skel.compute_matrices(base_mat, &mut buf, body)
},
Body::Object(body) => {
let skel = anim::object::IdleAnimation::update_skeleton(
&ObjectSkeleton::default(),
(active_tool_kind, second_tool_kind, time),
0.0,
&mut 1.0,
&anim::object::SkeletonAttr::from(&body),
);
skel.compute_matrices(base_mat, &mut buf, body)
let computed_skel = skel.compute_matrices(base_mat, &mut buf, body);
anim::biped_small::mount_mat(&body, &computed_skel, &skel).0
},
Body::Object(_) => Mat4::identity(), // Objects do not support mounting
Body::Golem(body) => {
let skel = anim::golem::IdleAnimation::update_skeleton(
&GolemSkeleton::default(),
@ -559,7 +568,9 @@ fn load_npc_bones(
&mut 1.0,
&anim::golem::SkeletonAttr::from(&body),
);
skel.compute_matrices(base_mat, &mut buf, body)
let computed_skel = skel.compute_matrices(base_mat, &mut buf, body);
anim::golem::mount_mat(&computed_skel, &skel).0
},
Body::Theropod(body) => {
let skel = anim::theropod::IdleAnimation::update_skeleton(
@ -569,7 +580,9 @@ fn load_npc_bones(
&mut 1.0,
&anim::theropod::SkeletonAttr::from(&body),
);
skel.compute_matrices(base_mat, &mut buf, body)
let computed_skel = skel.compute_matrices(base_mat, &mut buf, body);
anim::theropod::mount_mat(&body, &computed_skel, &skel).0
},
Body::QuadrupedLow(body) => {
let skel = anim::quadruped_low::IdleAnimation::update_skeleton(
@ -583,7 +596,9 @@ fn load_npc_bones(
&mut 1.0,
&anim::quadruped_low::SkeletonAttr::from(&body),
);
skel.compute_matrices(base_mat, &mut buf, body)
let computed_skel = skel.compute_matrices(base_mat, &mut buf, body);
anim::quadruped_low::mount_mat(&body, &computed_skel, &skel).0
},
Body::Arthropod(body) => {
let skel = anim::arthropod::IdleAnimation::update_skeleton(
@ -593,7 +608,9 @@ fn load_npc_bones(
&mut 1.0,
&anim::arthropod::SkeletonAttr::from(&body),
);
skel.compute_matrices(base_mat, &mut buf, body)
let computed_skel = skel.compute_matrices(base_mat, &mut buf, body);
anim::arthropod::mount_mat(&body, &computed_skel, &skel).0
},
Body::Crustacean(body) => {
let skel = anim::crustacean::IdleAnimation::update_skeleton(
@ -603,7 +620,9 @@ fn load_npc_bones(
&mut 1.0,
&anim::crustacean::SkeletonAttr::from(&body),
);
skel.compute_matrices(base_mat, &mut buf, body)
let computed_skel = skel.compute_matrices(base_mat, &mut buf, body);
anim::crustacean::mount_mat(&computed_skel, &skel).0
},
Body::Item(_) => panic!("Item bodies aren't supported"),
Body::Ship(_) => panic!("Ship bodies aren't supported"),
@ -624,11 +643,7 @@ fn load_npc_bones(
.collect();
if let Some(rider) = info.rider {
bones.extend(load_npc_bones(
*rider,
manifests,
Mat4::from(offsets.mount_bone),
));
bones.extend(load_npc_bones(*rider, manifests, mount_mat));
}
bones

View File

@ -125,6 +125,7 @@ pub enum ParticleMode {
FirePillarIndicator = 71,
FirePillar = 72,
FireLowShockwave = 73,
PipeSmoke = 74,
}
impl ParticleMode {

View File

@ -283,7 +283,7 @@ impl CharacterCacheKey {
}
}
pub(crate) struct FigureModelCache<Skel = anim::character::CharacterSkeleton>
pub(crate) struct FigureModelCache<Skel>
where
Skel: Skeleton,
Skel::Body: BodySpec,

View File

@ -29,13 +29,25 @@ use crate::{
#[cfg(feature = "plugins")]
use anim::plugin::PluginSkeleton;
use anim::{
Animation, Skeleton, arthropod::ArthropodSkeleton, biped_large::BipedLargeSkeleton,
biped_small::BipedSmallSkeleton, bird_large::BirdLargeSkeleton,
bird_medium::BirdMediumSkeleton, character::CharacterSkeleton, crustacean::CrustaceanSkeleton,
dragon::DragonSkeleton, fish_medium::FishMediumSkeleton, fish_small::FishSmallSkeleton,
golem::GolemSkeleton, item::ItemSkeleton, object::ObjectSkeleton,
quadruped_low::QuadrupedLowSkeleton, quadruped_medium::QuadrupedMediumSkeleton,
quadruped_small::QuadrupedSmallSkeleton, ship::ShipSkeleton, theropod::TheropodSkeleton,
Animation, Skeleton,
arthropod::{self, ArthropodSkeleton},
biped_large::{self, BipedLargeSkeleton},
biped_small::{self, BipedSmallSkeleton},
bird_large::{self, BirdLargeSkeleton},
bird_medium::{self, BirdMediumSkeleton},
character::{self, CharacterSkeleton},
crustacean::{self, CrustaceanSkeleton},
dragon::{self, DragonSkeleton},
fish_medium::{self, FishMediumSkeleton},
fish_small::{self, FishSmallSkeleton},
golem::{self, GolemSkeleton},
item::ItemSkeleton,
object::ObjectSkeleton,
quadruped_low::{self, QuadrupedLowSkeleton},
quadruped_medium::{self, QuadrupedMediumSkeleton},
quadruped_small::{self, QuadrupedSmallSkeleton},
ship::ShipSkeleton,
theropod::{self, TheropodSkeleton},
};
use common::{
comp::{
@ -206,26 +218,26 @@ impl<'a, const N: usize> ModelEntryRef<'a, N> {
#[derive(Default)]
pub struct FigureMgrStates {
pub character_states: HashMap<EcsEntity, FigureState<CharacterSkeleton>>,
quadruped_small_states: HashMap<EcsEntity, FigureState<QuadrupedSmallSkeleton>>,
quadruped_medium_states: HashMap<EcsEntity, FigureState<QuadrupedMediumSkeleton>>,
quadruped_low_states: HashMap<EcsEntity, FigureState<QuadrupedLowSkeleton>>,
bird_medium_states: HashMap<EcsEntity, FigureState<BirdMediumSkeleton>>,
fish_medium_states: HashMap<EcsEntity, FigureState<FishMediumSkeleton>>,
theropod_states: HashMap<EcsEntity, FigureState<TheropodSkeleton>>,
dragon_states: HashMap<EcsEntity, FigureState<DragonSkeleton>>,
bird_large_states: HashMap<EcsEntity, FigureState<BirdLargeSkeleton>>,
fish_small_states: HashMap<EcsEntity, FigureState<FishSmallSkeleton>>,
biped_large_states: HashMap<EcsEntity, FigureState<BipedLargeSkeleton>>,
biped_small_states: HashMap<EcsEntity, FigureState<BipedSmallSkeleton>>,
golem_states: HashMap<EcsEntity, FigureState<GolemSkeleton>>,
object_states: HashMap<EcsEntity, FigureState<ObjectSkeleton>>,
item_states: HashMap<EcsEntity, FigureState<ItemSkeleton>>,
ship_states: HashMap<EcsEntity, FigureState<ShipSkeleton, BoundTerrainLocals>>,
volume_states: HashMap<EcsEntity, FigureState<VolumeKey, BoundTerrainLocals>>,
arthropod_states: HashMap<EcsEntity, FigureState<ArthropodSkeleton>>,
crustacean_states: HashMap<EcsEntity, FigureState<CrustaceanSkeleton>>,
pub quadruped_small_states: HashMap<EcsEntity, FigureState<QuadrupedSmallSkeleton>>,
pub quadruped_medium_states: HashMap<EcsEntity, FigureState<QuadrupedMediumSkeleton>>,
pub quadruped_low_states: HashMap<EcsEntity, FigureState<QuadrupedLowSkeleton>>,
pub bird_medium_states: HashMap<EcsEntity, FigureState<BirdMediumSkeleton>>,
pub fish_medium_states: HashMap<EcsEntity, FigureState<FishMediumSkeleton>>,
pub theropod_states: HashMap<EcsEntity, FigureState<TheropodSkeleton>>,
pub dragon_states: HashMap<EcsEntity, FigureState<DragonSkeleton>>,
pub bird_large_states: HashMap<EcsEntity, FigureState<BirdLargeSkeleton>>,
pub fish_small_states: HashMap<EcsEntity, FigureState<FishSmallSkeleton>>,
pub biped_large_states: HashMap<EcsEntity, FigureState<BipedLargeSkeleton>>,
pub biped_small_states: HashMap<EcsEntity, FigureState<BipedSmallSkeleton>>,
pub golem_states: HashMap<EcsEntity, FigureState<GolemSkeleton>>,
pub object_states: HashMap<EcsEntity, FigureState<ObjectSkeleton>>,
pub item_states: HashMap<EcsEntity, FigureState<ItemSkeleton>>,
pub ship_states: HashMap<EcsEntity, FigureState<ShipSkeleton, BoundTerrainLocals>>,
pub volume_states: HashMap<EcsEntity, FigureState<VolumeKey, BoundTerrainLocals>>,
pub arthropod_states: HashMap<EcsEntity, FigureState<ArthropodSkeleton>>,
pub crustacean_states: HashMap<EcsEntity, FigureState<CrustaceanSkeleton>>,
#[cfg(feature = "plugins")]
plugin_states: HashMap<EcsEntity, FigureState<PluginSkeleton>>,
pub plugin_states: HashMap<EcsEntity, FigureState<PluginSkeleton>>,
}
impl FigureMgrStates {
@ -710,7 +722,7 @@ struct FigureUpdateParams<'a> {
pub struct FigureMgr {
atlas: FigureAtlas,
model_cache: FigureModelCache,
character_model_cache: FigureModelCache<CharacterSkeleton>,
theropod_model_cache: FigureModelCache<TheropodSkeleton>,
quadruped_small_model_cache: FigureModelCache<QuadrupedSmallSkeleton>,
quadruped_medium_model_cache: FigureModelCache<QuadrupedMediumSkeleton>,
@ -738,7 +750,7 @@ impl FigureMgr {
pub fn new(renderer: &mut Renderer) -> Self {
Self {
atlas: FigureAtlas::new(renderer),
model_cache: FigureModelCache::new(),
character_model_cache: FigureModelCache::new(),
theropod_model_cache: FigureModelCache::new(),
quadruped_small_model_cache: FigureModelCache::new(),
quadruped_medium_model_cache: FigureModelCache::new(),
@ -770,7 +782,7 @@ impl FigureMgr {
let plugin_reloaded = self.plugin_model_cache.watcher_reloaded();
#[cfg(not(feature = "plugins"))]
let plugin_reloaded = false;
self.model_cache.watcher_reloaded()
self.character_model_cache.watcher_reloaded()
|| self.theropod_model_cache.watcher_reloaded()
|| self.quadruped_small_model_cache.watcher_reloaded()
|| self.quadruped_medium_model_cache.watcher_reloaded()
@ -798,7 +810,7 @@ impl FigureMgr {
if self.any_watcher_reloaded() {
self.atlas.allocator.clear();
self.model_cache.clear_models();
self.character_model_cache.clear_models();
self.theropod_model_cache.clear_models();
self.quadruped_small_model_cache.clear_models();
self.quadruped_medium_model_cache.clear_models();
@ -821,7 +833,7 @@ impl FigureMgr {
self.plugin_model_cache.clear_models();
}
self.model_cache.clean(&mut self.atlas, tick);
self.character_model_cache.clean(&mut self.atlas, tick);
self.theropod_model_cache.clean(&mut self.atlas, tick);
self.quadruped_small_model_cache
.clean(&mut self.atlas, tick);
@ -896,6 +908,7 @@ impl FigureMgr {
} else {
(Rgb::zero(), 0.0, 0.0, true)
};
let lantern_offset = self.lantern_offset(scene_data, entity);
if let Some(lantern_offset) = body
.and_then(|body| self.states.get_mut(body, &entity))
.and_then(|state| {
@ -904,8 +917,7 @@ impl FigureMgr {
interpolated.map(|i| i.pos).unwrap_or(pos.0).into_array(),
);
Some(
state.mount_world_pos
+ anim::vek::Vec3::from(state.lantern_offset?.into_array())
state.mount_world_pos + anim::vek::Vec3::from(lantern_offset?.into_array())
- pos,
)
})
@ -1337,9 +1349,13 @@ impl FigureMgr {
if let Some(is_rider) = is_rider {
let mount = is_rider.mount;
let mount = read_data.id_maps.uid_entity(mount)?;
let body = *read_data.bodies.get(mount)?;
let meta = self.states.get_mut(&body, &mount)?;
Some((meta.mount_transform, meta.mount_world_pos))
if let Some(mount_transform) = self.mount_transform(data.scene_data, mount) {
let body = *read_data.bodies.get(mount)?;
let meta = self.states.get_mut(&body, &mount)?;
Some((mount_transform, meta.mount_world_pos))
} else {
None
}
} else if let Some(is_volume_rider) = is_volume_rider
&& matches!(is_volume_rider.pos.kind, Volume::Entity(_))
{
@ -1370,17 +1386,18 @@ impl FigureMgr {
scale,
mount_transform_pos,
body: Some(body),
tools: (active_tool_kind, second_tool_kind),
col,
dt,
is_player: is_viewpoint,
terrain: data.terrain,
ground_vel: physics.ground_vel,
primary_trail_points: self.trail_points(data.scene_data, entity, true),
secondary_trail_points: self.trail_points(data.scene_data, entity, false),
};
match body {
Body::Humanoid(body) => {
let (model, skeleton_attr) = self.model_cache.get_or_create_model(
let (model, skeleton_attr) = self.character_model_cache.get_or_create_model(
renderer,
&mut self.atlas,
body,
@ -7038,7 +7055,7 @@ impl FigureMgr {
let FigureMgr {
atlas: atlas_,
model_cache,
character_model_cache: model_cache,
theropod_model_cache,
quadruped_small_model_cache,
quadruped_medium_model_cache,
@ -7564,153 +7581,32 @@ impl FigureMgr {
}
}
pub fn get_heads(&self, scene_data: &SceneData, entity: EcsEntity) -> &[anim::vek::Vec3<f32>] {
pub fn get_heads(
&self,
scene_data: &SceneData,
entity: EcsEntity,
) -> Vec<anim::vek::Vec3<f32>> {
scene_data
.state
.ecs()
.read_storage::<Body>()
.get(entity)
.and_then(|b| match b {
Body::Humanoid(_) => self
.states
.character_states
.get(&entity)
.map(|state| &state.heads),
Body::QuadrupedSmall(_) => self
.states
.quadruped_small_states
.get(&entity)
.map(|state| &state.heads),
Body::QuadrupedMedium(_) => self
.states
.quadruped_medium_states
.get(&entity)
.map(|state| &state.heads),
Body::BirdMedium(_) => self
.states
.bird_medium_states
.get(&entity)
.map(|state| &state.heads),
Body::FishMedium(_) => self
.states
.fish_medium_states
.get(&entity)
.map(|state| &state.heads),
Body::Dragon(_) => self
.states
.dragon_states
.get(&entity)
.map(|state| &state.heads),
Body::BirdLarge(_) => self
.states
.bird_large_states
.get(&entity)
.map(|state| &state.heads),
Body::FishSmall(_) => self
.states
.fish_small_states
.get(&entity)
.map(|state| &state.heads),
Body::BipedLarge(_) => self
.states
.biped_large_states
.get(&entity)
.map(|state| &state.heads),
Body::BipedSmall(_) => self
.states
.biped_small_states
.get(&entity)
.map(|state| &state.heads),
Body::Golem(_) => self
.states
.golem_states
.get(&entity)
.map(|state| &state.heads),
Body::Theropod(_) => self
.states
.theropod_states
.get(&entity)
.map(|state| &state.heads),
Body::QuadrupedLow(_) => self
.states
.quadruped_low_states
.get(&entity)
.map(|state| &state.heads),
Body::Arthropod(_) => self
.states
.arthropod_states
.get(&entity)
.map(|state| &state.heads),
Body::Object(_) => self
.states
.object_states
.get(&entity)
.map(|state| &state.heads),
Body::Ship(_) => self
.states
.ship_states
.get(&entity)
.map(|state| &state.heads),
Body::Item(_) => self
.states
.item_states
.get(&entity)
.map(|state| &state.heads),
Body::Crustacean(_) => self
.states
.crustacean_states
.get(&entity)
.map(|state| &state.heads),
Body::Plugin(_) => {
#[cfg(not(feature = "plugins"))]
unreachable!("Plugins require feature");
#[cfg(feature = "plugins")]
self.states
.plugin_states
.get(&entity)
.map(|state| &state.heads)
},
})
.map(|v| v.as_slice())
.unwrap_or(&[])
}
pub fn get_tail(
&self,
scene_data: &SceneData,
entity: EcsEntity,
) -> Option<(anim::vek::Vec3<f32>, anim::vek::Vec3<f32>)> {
scene_data
.state
.ecs()
.read_storage::<Body>()
.get(entity)
.and_then(|b| match b {
Body::Humanoid(_) => self.states.character_states.get(&entity)?.tail,
Body::QuadrupedSmall(_) => self.states.quadruped_small_states.get(&entity)?.tail,
Body::QuadrupedMedium(_) => self.states.quadruped_medium_states.get(&entity)?.tail,
Body::BirdMedium(_) => self.states.bird_medium_states.get(&entity)?.tail,
Body::FishMedium(_) => self.states.fish_medium_states.get(&entity)?.tail,
Body::Dragon(_) => self.states.dragon_states.get(&entity)?.tail,
Body::BirdLarge(_) => self.states.bird_large_states.get(&entity)?.tail,
Body::FishSmall(_) => self.states.fish_small_states.get(&entity)?.tail,
Body::BipedLarge(_) => self.states.biped_large_states.get(&entity)?.tail,
Body::BipedSmall(_) => self.states.biped_small_states.get(&entity)?.tail,
Body::Golem(_) => self.states.golem_states.get(&entity)?.tail,
Body::Theropod(_) => self.states.theropod_states.get(&entity)?.tail,
Body::QuadrupedLow(_) => self.states.quadruped_low_states.get(&entity)?.tail,
Body::Arthropod(_) => self.states.arthropod_states.get(&entity)?.tail,
Body::Object(_) => self.states.object_states.get(&entity)?.tail,
Body::Ship(_) => self.states.ship_states.get(&entity)?.tail,
Body::Item(_) => self.states.item_states.get(&entity)?.tail,
Body::Crustacean(_) => self.states.crustacean_states.get(&entity)?.tail,
Body::Plugin(_) => {
#[cfg(not(feature = "plugins"))]
unreachable!("Plugins require feature");
#[cfg(feature = "plugins")]
self.states.plugin_states.get(&entity)?.tail
},
.map(|state| &state.computed_skeleton)
.map(|skeleton| {
vec![
(skeleton.head_l_upper * Vec4::unit_w()).xyz(),
(skeleton.head_c_upper * Vec4::unit_w()).xyz(),
(skeleton.head_r_upper * Vec4::unit_w()).xyz(),
]
}),
_ => None,
})
.unwrap_or(Vec::new())
}
pub fn viewpoint_offset(&self, scene_data: &SceneData, entity: EcsEntity) -> Vec3<f32> {
@ -7724,92 +7620,95 @@ impl FigureMgr {
.states
.character_states
.get(&entity)
.and_then(|state| state.viewpoint_offset),
.map(|state| &state.computed_skeleton)
.map(|skeleton| (skeleton.head * Vec4::new(0.0, 0.0, 4.0, 1.0)).xyz()),
Body::QuadrupedSmall(_) => self
.states
.quadruped_small_states
.get(&entity)
.and_then(|state| state.viewpoint_offset),
Body::QuadrupedMedium(_) => self
.map(|state| &state.computed_skeleton)
.map(|skeleton| (skeleton.head * Vec4::new(0.0, 3.0, 0.0, 1.0)).xyz()),
Body::QuadrupedMedium(b) => self
.states
.quadruped_medium_states
.get(&entity)
.and_then(|state| state.viewpoint_offset),
Body::BirdMedium(_) => self
.map(|state| &state.computed_skeleton)
.map(|skeleton| (skeleton.head * quadruped_medium::viewpoint(b)).xyz()),
Body::BirdMedium(b) => self
.states
.bird_medium_states
.get(&entity)
.and_then(|state| state.viewpoint_offset),
.map(|state| &state.computed_skeleton)
.map(|skeleton| (skeleton.head * bird_medium::viewpoint(b)).xyz()),
Body::FishMedium(_) => self
.states
.fish_medium_states
.get(&entity)
.and_then(|state| state.viewpoint_offset),
.map(|state| &state.computed_skeleton)
.map(|skeleton| (skeleton.head * Vec4::new(0.0, 5.0, 0.0, 1.0)).xyz()),
Body::Dragon(_) => self
.states
.dragon_states
.get(&entity)
.and_then(|state| state.viewpoint_offset),
.map(|state| &state.computed_skeleton)
.map(|skeleton| (skeleton.head_upper * Vec4::new(0.0, 8.0, 0.0, 1.0)).xyz()),
Body::BirdLarge(_) => self
.states
.bird_large_states
.get(&entity)
.and_then(|state| state.viewpoint_offset),
.map(|state| &state.computed_skeleton)
.map(|skeleton| (skeleton.head * Vec4::new(0.0, 3.0, 6.0, 1.0)).xyz()),
Body::FishSmall(_) => self
.states
.fish_small_states
.get(&entity)
.and_then(|state| state.viewpoint_offset),
.map(|state| &state.computed_skeleton)
.map(|skeleton| (skeleton.chest * Vec4::new(0.0, 3.0, 0.0, 1.0)).xyz()),
Body::BipedLarge(_) => self
.states
.biped_large_states
.get(&entity)
.and_then(|state| state.viewpoint_offset),
.map(|state| &state.computed_skeleton)
.map(|skeleton| (skeleton.jaw * Vec4::new(0.0, 4.0, 0.0, 1.0)).xyz()),
Body::BipedSmall(_) => self
.states
.biped_small_states
.get(&entity)
.and_then(|state| state.viewpoint_offset),
.map(|state| &state.computed_skeleton)
.map(|skeleton| (skeleton.head * Vec4::new(0.0, 0.0, 0.0, 1.0)).xyz()),
Body::Golem(_) => self
.states
.golem_states
.get(&entity)
.and_then(|state| state.viewpoint_offset),
.map(|state| &state.computed_skeleton)
.map(|skeleton| (skeleton.head * Vec4::new(0.0, 0.0, 5.0, 1.0)).xyz()),
Body::Theropod(_) => self
.states
.theropod_states
.get(&entity)
.and_then(|state| state.viewpoint_offset),
.map(|state| &state.computed_skeleton)
.map(|skeleton| (skeleton.head * Vec4::new(0.0, 2.0, 0.0, 1.0)).xyz()),
Body::QuadrupedLow(_) => self
.states
.quadruped_low_states
.get(&entity)
.and_then(|state| state.viewpoint_offset),
.map(|state| &state.computed_skeleton)
.map(|skeleton| (skeleton.head_c_upper * Vec4::new(0.0, 4.0, 1.0, 1.0)).xyz()),
Body::Arthropod(_) => self
.states
.arthropod_states
.get(&entity)
.and_then(|state| state.viewpoint_offset),
Body::Object(_) => self
.states
.object_states
.get(&entity)
.and_then(|state| state.viewpoint_offset),
Body::Ship(_) => self
.states
.ship_states
.get(&entity)
.and_then(|state| state.viewpoint_offset),
Body::Item(_) => self
.states
.item_states
.get(&entity)
.and_then(|state| state.viewpoint_offset),
.map(|state| &state.computed_skeleton)
.map(|skeleton| (skeleton.head * Vec4::new(0.0, 7.0, 0.0, 1.0)).xyz()),
Body::Object(_) => None,
Body::Ship(_) => None,
Body::Item(_) => None,
Body::Crustacean(_) => self
.states
.crustacean_states
.get(&entity)
.and_then(|state| state.viewpoint_offset),
.map(|state| &state.computed_skeleton)
.map(|skeleton| (skeleton.chest * Vec4::new(0.0, 7.0, 0.0, 1.0)).xyz()),
Body::Plugin(_) => {
#[cfg(not(feature = "plugins"))]
unreachable!("Plugins require feature");
@ -7818,13 +7717,240 @@ impl FigureMgr {
self.states
.plugin_states
.get(&entity)
.and_then(|state| state.viewpoint_offset)
.map(|state| &state.computed_skeleton)
.map(|skeleton| (skeleton.bone0 * Vec4::new(0.0, 3.0, 0.0, 1.0)).xyz())
}
},
})
.unwrap_or_else(Vec3::zero)
}
pub fn lantern_offset(&self, scene_data: &SceneData, entity: EcsEntity) -> Option<Vec3<f32>> {
scene_data
.state
.ecs()
.read_storage::<Body>()
.get(entity)
.and_then(|b| match b {
Body::Humanoid(_) => self.states.character_states.get(&entity).map(|state| {
state
.computed_skeleton
.lantern
.mul_point(Vec3::new(0.0, 0.5, -6.0))
}),
Body::Item(_) => self.states.item_states.get(&entity).map(|state| {
state
.computed_skeleton
.bone0
.mul_point(Vec3::new(0.0, 0.0, 3.5))
}),
_ => None,
})
}
pub fn mount_transform(
&self,
scene_data: &SceneData,
entity: EcsEntity,
) -> Option<Transform<f32, f32, f32>> {
scene_data
.state
.ecs()
.read_storage::<Body>()
.get(entity)
.and_then(|body| match body {
Body::Humanoid(_) => self.states.character_states.get(&entity).map(|state| {
character::mount_transform(&state.computed_skeleton, &state.skeleton)
}),
Body::QuadrupedSmall(b) => {
self.states
.quadruped_small_states
.get(&entity)
.map(|state| {
quadruped_small::mount_transform(
b,
&state.computed_skeleton,
&state.skeleton,
)
})
},
Body::QuadrupedMedium(b) => {
self.states
.quadruped_medium_states
.get(&entity)
.map(|state| {
quadruped_medium::mount_transform(
b,
&state.computed_skeleton,
&state.skeleton,
)
})
},
Body::BirdMedium(b) => self.states.bird_medium_states.get(&entity).map(|state| {
bird_medium::mount_transform(b, &state.computed_skeleton, &state.skeleton)
}),
Body::FishMedium(b) => self.states.fish_medium_states.get(&entity).map(|state| {
fish_medium::mount_transform(b, &state.computed_skeleton, &state.skeleton)
}),
Body::Dragon(b) => self.states.dragon_states.get(&entity).map(|state| {
dragon::mount_transform(b, &state.computed_skeleton, &state.skeleton)
}),
Body::BirdLarge(b) => self.states.bird_large_states.get(&entity).map(|state| {
bird_large::mount_transform(b, &state.computed_skeleton, &state.skeleton)
}),
Body::FishSmall(b) => self.states.fish_small_states.get(&entity).map(|state| {
fish_small::mount_transform(b, &state.computed_skeleton, &state.skeleton)
}),
Body::BipedLarge(b) => self.states.biped_large_states.get(&entity).map(|state| {
biped_large::mount_transform(b, &state.computed_skeleton, &state.skeleton)
}),
Body::BipedSmall(b) => self.states.biped_small_states.get(&entity).map(|state| {
biped_small::mount_transform(b, &state.computed_skeleton, &state.skeleton)
}),
Body::Golem(b) => self.states.golem_states.get(&entity).map(|state| {
golem::mount_transform(b, &state.computed_skeleton, &state.skeleton)
}),
Body::Theropod(b) => self.states.theropod_states.get(&entity).map(|state| {
theropod::mount_transform(b, &state.computed_skeleton, &state.skeleton)
}),
Body::QuadrupedLow(b) => {
self.states.quadruped_low_states.get(&entity).map(|state| {
quadruped_low::mount_transform(b, &state.computed_skeleton, &state.skeleton)
})
},
Body::Arthropod(b) => self.states.arthropod_states.get(&entity).map(|state| {
arthropod::mount_transform(b, &state.computed_skeleton, &state.skeleton)
}),
Body::Object(_) => None,
Body::Ship(_) => None,
Body::Item(_) => None,
Body::Crustacean(b) => self.states.crustacean_states.get(&entity).map(|state| {
crustacean::mount_transform(b, &state.computed_skeleton, &state.skeleton)
}),
Body::Plugin(_) => {
#[cfg(not(feature = "plugins"))]
unreachable!("Plugins require feature");
#[cfg(feature = "plugins")]
Some(Transform {
position: body.mount_offset().into_tuple().into(),
..Default::default()
})
},
})
}
fn trail_points(
&self,
scene_data: &SceneData,
entity: EcsEntity,
main_trail: bool,
) -> Option<(anim::vek::Vec3<f32>, anim::vek::Vec3<f32>)> {
let transform_trail = |mat: Mat4<f32>, trail: (Vec3<f32>, Vec3<f32>)| {
(mat.mul_point(trail.0), mat.mul_point(trail.1))
};
scene_data
.state
.ecs()
.read_storage::<Body>()
.get(entity)
.and_then(|body| match body {
Body::Humanoid(_) => self.states.character_states.get(&entity).and_then(|state| {
let weapon_offsets = |slot| {
scene_data
.state
.ecs()
.read_storage::<Inventory>()
.get(entity)
.and_then(|inv| inv.equipped(slot))
.and_then(|item| {
if let ItemKind::Tool(tool) = &*item.kind() {
Some(tool.kind)
} else {
None
}
})
.map(|tool_kind| {
let lengths = match tool_kind {
ToolKind::Sword => (0.0, 29.25),
ToolKind::Axe => (10.0, 19.25),
ToolKind::Hammer => (10.0, 19.25),
ToolKind::Staff => (10.0, 19.25),
ToolKind::Sceptre => (10.0, 19.25),
_ => (0.0, 0.0),
};
(
Vec3::new(0.0, 0.0, lengths.0),
Vec3::new(0.0, 0.0, lengths.1),
)
})
};
let weapon_trails =
state.skeleton.main_weapon_trail || state.skeleton.off_weapon_trail;
if weapon_trails {
if state.skeleton.main_weapon_trail && main_trail {
weapon_offsets(EquipSlot::ActiveMainhand).map(|weapon_offsets| {
transform_trail(state.computed_skeleton.main, weapon_offsets)
})
} else if state.skeleton.off_weapon_trail && !main_trail {
weapon_offsets(EquipSlot::ActiveOffhand).map(|weapon_offsets| {
transform_trail(state.computed_skeleton.second, weapon_offsets)
})
} else {
None
}
} else if state.skeleton.glider_trails {
// Offsets
const GLIDER_VERT: f32 = 5.0;
const GLIDER_HORIZ: f32 = 15.0;
// Trail width
const GLIDER_WIDTH: f32 = 1.0;
if main_trail {
Some(transform_trail(
state.computed_skeleton.glider,
(
Vec3::new(GLIDER_HORIZ, 0.0, GLIDER_VERT),
Vec3::new(GLIDER_HORIZ + GLIDER_WIDTH, 0.0, GLIDER_VERT),
),
))
} else {
Some(transform_trail(
state.computed_skeleton.glider,
(
Vec3::new(-GLIDER_HORIZ, 0.0, GLIDER_VERT),
Vec3::new(-(GLIDER_HORIZ + GLIDER_WIDTH), 0.0, GLIDER_VERT),
),
))
}
} else {
None
}
}),
Body::Ship(b) => self.states.ship_states.get(&entity).and_then(|state| {
let attr = anim::ship::SkeletonAttr::from(b);
let propeller_trail = |length| {
(
Vec3::new(0.0, 0.0, length * 0.5),
Vec3::new(0.0, 0.0, length),
)
};
if main_trail {
attr.bone1_prop_trail_offset.map(|length| {
transform_trail(state.computed_skeleton.bone1, propeller_trail(length))
})
} else {
attr.bone2_prop_trail_offset.map(|length| {
transform_trail(state.computed_skeleton.bone2, propeller_trail(length))
})
}
}),
_ => None,
})
}
pub fn figure_count(&self) -> usize { self.states.count() }
pub fn figure_count_visible(&self) -> usize { self.states.count_visible() }
@ -7997,14 +8123,8 @@ impl FigureAtlas {
}
pub struct FigureStateMeta {
lantern_offset: Option<anim::vek::Vec3<f32>>,
viewpoint_offset: Option<anim::vek::Vec3<f32>>,
heads: Vec<anim::vek::Vec3<f32>>,
tail: Option<(anim::vek::Vec3<f32>, anim::vek::Vec3<f32>)>,
pub main_abs_trail_points: Option<(anim::vek::Vec3<f32>, anim::vek::Vec3<f32>)>,
pub off_abs_trail_points: Option<(anim::vek::Vec3<f32>, anim::vek::Vec3<f32>)>,
// Animation to be applied to rider of this entity
mount_transform: anim::vek::Transform<f32, f32, f32>,
pub primary_abs_trail_points: Option<(anim::vek::Vec3<f32>, anim::vek::Vec3<f32>)>,
pub secondary_abs_trail_points: Option<(anim::vek::Vec3<f32>, anim::vek::Vec3<f32>)>,
// Contains the position of this figure or if it is a rider it will contain the mount's
// mount_world_pos
// Unlike the interpolated position stored in the ecs this will be propagated along
@ -8039,19 +8159,20 @@ impl FigureStateMeta {
}
}
pub struct FigureState<S, D = ()> {
pub struct FigureState<S: Skeleton, D = ()> {
meta: FigureStateMeta,
skeleton: S,
pub skeleton: S,
pub computed_skeleton: S::ComputedSkeleton,
pub extra: D,
}
impl<S, D> Deref for FigureState<S, D> {
impl<S: Skeleton, D> Deref for FigureState<S, D> {
type Target = FigureStateMeta;
fn deref(&self) -> &Self::Target { &self.meta }
}
impl<S, D> DerefMut for FigureState<S, D> {
impl<S: Skeleton, D> DerefMut for FigureState<S, D> {
fn deref_mut(&mut self) -> &mut Self::Target { &mut self.meta }
}
@ -8064,12 +8185,13 @@ pub struct FigureUpdateCommonParameters<'a> {
pub scale: f32,
pub mount_transform_pos: Option<(anim::vek::Transform<f32, f32, f32>, anim::vek::Vec3<f32>)>,
pub body: Option<Body>,
pub tools: (Option<ToolKind>, Option<ToolKind>),
pub col: Rgba<f32>,
pub dt: f32,
pub is_player: bool,
pub terrain: Option<&'a Terrain>,
pub ground_vel: Vec3<f32>,
pub primary_trail_points: Option<(anim::vek::Vec3<f32>, anim::vek::Vec3<f32>)>,
pub secondary_trail_points: Option<(anim::vek::Vec3<f32>, anim::vek::Vec3<f32>)>,
}
pub trait FigureData: Sized {
@ -8107,18 +8229,13 @@ impl FigureData for BoundTerrainLocals {
impl<S: Skeleton, D: FigureData> FigureState<S, D> {
pub fn new(renderer: &mut Renderer, skeleton: S, body: S::Body) -> Self {
let mut buf = [Default::default(); anim::MAX_BONE_COUNT];
let offsets =
let computed_skeleton =
anim::compute_matrices(&skeleton, anim::vek::Mat4::identity(), &mut buf, body);
let bone_consts = figure_bone_data_from_anim(&buf);
Self {
meta: FigureStateMeta {
lantern_offset: offsets.lantern,
viewpoint_offset: offsets.viewpoint,
heads: offsets.heads.clone(),
tail: offsets.tail,
main_abs_trail_points: None,
off_abs_trail_points: None,
mount_transform: offsets.mount_bone,
primary_abs_trail_points: None,
secondary_abs_trail_points: None,
mount_world_pos: anim::vek::Vec3::zero(),
state_time: 0.0,
last_ori: Ori::default().into(),
@ -8134,6 +8251,7 @@ impl<S: Skeleton, D: FigureData> FigureState<S, D> {
bound: renderer.create_figure_bound_locals(&[FigureLocals::default()], bone_consts),
},
skeleton,
computed_skeleton,
extra: D::new(renderer),
}
}
@ -8150,12 +8268,13 @@ impl<S: Skeleton, D: FigureData> FigureState<S, D> {
scale,
mount_transform_pos,
body,
tools,
col,
dt,
is_player,
terrain,
ground_vel,
primary_trail_points,
secondary_trail_points,
}: &FigureUpdateCommonParameters,
state_animation_rate: f32,
model: Option<&impl ModelEntry>,
@ -8288,34 +8407,27 @@ impl<S: Skeleton, D: FigureData> FigureState<S, D> {
);
renderer.update_consts(&mut self.meta.bound.0, &[locals]);
let offsets = anim::compute_matrices(&self.skeleton, mat, buf, skel_body);
self.computed_skeleton = anim::compute_matrices(&self.skeleton, mat, buf, skel_body);
let new_bone_consts = figure_bone_data_from_anim(buf);
renderer.update_consts(&mut self.meta.bound.1, &new_bone_consts[0..S::BONE_COUNT]);
self.lantern_offset = offsets.lantern;
self.viewpoint_offset = offsets.viewpoint;
self.heads.clone_from(&offsets.heads);
self.tail = offsets.tail;
// Handle weapon trails
fn handle_weapon_trails(
fn handle_trails(
trail_mgr: &mut TrailMgr,
new_weapon_trail_mat: Option<(anim::vek::Mat4<f32>, anim::TrailSource)>,
new_rel_trail_points: Option<(anim::vek::Vec3<f32>, anim::vek::Vec3<f32>)>,
old_abs_trail_points: &mut Option<(anim::vek::Vec3<f32>, anim::vek::Vec3<f32>)>,
entity: EcsEntity,
is_main_weapon: bool,
primary_trail: bool,
pos: anim::vek::Vec3<f32>,
tool: Option<ToolKind>,
) {
let weapon_offsets = new_weapon_trail_mat.map(|(mat, trail)| {
let (trail_start, trail_end) = trail.relative_offsets(tool);
((mat * trail_start).xyz(), (mat * trail_end).xyz())
});
let new_abs_trail_points = weapon_offsets.map(|(a, b)| (a + pos, b + pos));
let new_abs_trail_points =
new_rel_trail_points.map(|(start, end)| (start + pos, end + pos));
if let (Some((p1, p2)), Some((p4, p3))) = (&old_abs_trail_points, new_abs_trail_points)
{
let trail_mgr_offset = trail_mgr.offset();
let quad_mesh = trail_mgr.entity_mesh_or_insert(entity, is_main_weapon);
let quad_mesh = trail_mgr.entity_mesh_or_insert(entity, primary_trail);
let vertex = |p: anim::vek::Vec3<f32>| trail::Vertex {
pos: p.into_array(),
};
@ -8326,28 +8438,25 @@ impl<S: Skeleton, D: FigureData> FigureState<S, D> {
}
if let (Some(trail_mgr), Some(entity)) = (trail_mgr, entity) {
handle_weapon_trails(
handle_trails(
trail_mgr,
offsets.primary_trail_mat,
&mut self.main_abs_trail_points,
*primary_trail_points,
&mut self.primary_abs_trail_points,
*entity,
true,
pos_with_mount_offset,
tools.0,
);
handle_weapon_trails(
handle_trails(
trail_mgr,
offsets.secondary_trail_mat,
&mut self.off_abs_trail_points,
*secondary_trail_points,
&mut self.secondary_abs_trail_points,
*entity,
false,
pos_with_mount_offset,
tools.1,
);
}
// TODO: compute the mount bone only when it is needed
self.mount_transform = offsets.mount_bone;
self.mount_world_pos = pos_with_mount_offset;
let smoothing = (5.0 * dt).min(1.0);
@ -8366,8 +8475,6 @@ impl<S: Skeleton, D: FigureData> FigureState<S, D> {
}
pub fn bound(&self) -> &pipelines::figure::BoundLocals { &self.bound }
pub fn skeleton_mut(&mut self) -> &mut S { &mut self.skeleton }
}
fn figure_bone_data_from_anim(

View File

@ -19,6 +19,7 @@ impl From<&Self> for VolumeKey {
impl anim::Skeleton for VolumeKey {
type Attr = Self;
type Body = Self;
type ComputedSkeleton = ();
const BONE_COUNT: usize = 4;
#[cfg(feature = "hot-anim")]
@ -31,7 +32,7 @@ impl anim::Skeleton for VolumeKey {
base_mat: anim::vek::Mat4<f32>,
buf: &mut [anim::FigureBoneData; anim::MAX_BONE_COUNT],
body: Self::Body,
) -> anim::Offsets {
) -> Self::ComputedSkeleton {
self.compute_matrices_inner(base_mat, buf, body)
}
@ -40,7 +41,7 @@ impl anim::Skeleton for VolumeKey {
base_mat: anim::vek::Mat4<f32>,
buf: &mut [anim::FigureBoneData; anim::MAX_BONE_COUNT],
_: Self::Body,
) -> anim::Offsets {
) -> Self::ComputedSkeleton {
let bone = base_mat;
*(<&mut [_; Self::BONE_COUNT]>::try_from(&mut buf[0..Self::BONE_COUNT]).unwrap()) = [
@ -49,8 +50,6 @@ impl anim::Skeleton for VolumeKey {
anim::make_bone(bone),
anim::make_bone(bone),
];
anim::Offsets::default()
}
}

View File

@ -12,8 +12,11 @@ use common::{
assets::{AssetExt, DotVoxAsset},
comp::{
self, Beam, Body, CharacterActivity, CharacterState, Fluid, Inventory, Ori, PhysicsState,
Pos, Scale, Shockwave, Vel, ability::Dodgeable, aura, beam, biped_large, body, buff,
item::Reagent, object, shockwave,
Pos, Scale, Shockwave, Vel,
ability::Dodgeable,
aura, beam, biped_large, body, buff,
item::{ItemDefinitionId, Reagent},
object, shockwave,
},
figure::Segment,
outcome::Outcome,
@ -672,6 +675,7 @@ impl ParticleMgr {
.retain(|p| p.alive_until > scene_data.state.get_time());
// add new Particle
self.maintain_armor_particles(scene_data, figure_mgr);
self.maintain_body_particles(scene_data);
self.maintain_char_state_particles(scene_data, figure_mgr);
self.maintain_beam_particles(scene_data, lights);
@ -693,6 +697,94 @@ impl ParticleMgr {
}
}
fn maintain_armor_particles(&mut self, scene_data: &SceneData, figure_mgr: &FigureMgr) {
prof_span!("ParticleMgr::maintain_armor_particles");
let ecs = scene_data.state.ecs();
for (entity, interpolated, inv) in (
&ecs.entities(),
&ecs.read_storage::<Interpolated>(),
&ecs.read_storage::<Inventory>(),
)
.join()
{
for item in inv.equipped_items() {
if let ItemDefinitionId::Simple(str) = item.item_definition_id() {
if &*str == "common.items.armor.misc.head.pipe" {
self.maintain_pipe_particles(
scene_data,
figure_mgr,
entity,
interpolated.pos,
)
}
}
}
}
}
fn maintain_pipe_particles(
&mut self,
scene_data: &SceneData,
figure_mgr: &FigureMgr,
entity: Entity,
pos: Vec3<f32>,
) {
prof_span!("ParticleMgr::maintain_pipe_particles");
let Some((species, body_type)) = scene_data
.state
.ecs()
.read_storage::<Body>()
.get(entity)
.and_then(|body| {
if let Body::Humanoid(body) = body {
Some((body.species, body.body_type))
} else {
None
}
})
else {
return;
};
let Some(skeleton) = figure_mgr
.states
.character_states
.get(&entity)
.map(|state| &state.computed_skeleton)
else {
return;
};
let time = scene_data.state.get_time();
// TODO: compute offsets instead of hardcoding
use body::humanoid::{BodyType::*, Species::*};
let pipe_offset = match (species, body_type) {
(Orc, Male) => Vec3::new(5.5, 10.5, 0.0),
(Orc, Female) => Vec3::new(4.5, 10.0, -2.5),
(Human, Male) => Vec3::new(4.5, 12.0, -3.0),
(Human, Female) => Vec3::new(4.5, 11.5, -3.0),
(Elf, Male) => Vec3::new(4.5, 12.0, -3.0),
(Elf, Female) => Vec3::new(4.5, 9.5, -3.0),
(Dwarf, Male) => Vec3::new(4.5, 11.0, -4.0),
(Dwarf, Female) => Vec3::new(4.5, 11.0, -3.0),
(Draugr, Male) => Vec3::new(4.5, 9.5, -0.75),
(Draugr, Female) => Vec3::new(4.5, 9.5, -2.0),
(Danari, Male) => Vec3::new(4.5, 10.5, -1.25),
(Danari, Female) => Vec3::new(4.5, 10.5, -1.25),
};
for _ in 0..self.scheduler.heartbeats(Duration::from_secs(6)) {
self.particles.resize_with(self.particles.len() + 10, || {
Particle::new(
Duration::from_millis(1500),
time,
ParticleMode::PipeSmoke,
pos + skeleton.head.mul_point(pipe_offset),
)
});
}
}
fn maintain_body_particles(&mut self, scene_data: &SceneData) {
prof_span!("ParticleMgr::maintain_body_particles");
let ecs = scene_data.state.ecs();
@ -784,6 +876,7 @@ impl ParticleMgr {
figure_mgr: &FigureMgr,
entity: Entity,
pos: Vec3<f32>,
body: &Body,
state: &CharacterState,
inventory: Option<&Inventory>,
) {
@ -808,9 +901,20 @@ impl ParticleMgr {
_ => return,
};
let Some((start, end)) = figure_mgr.get_tail(scene_data, entity) else {
let Some(skeleton) = figure_mgr
.states
.quadruped_low_states
.get(&entity)
.map(|state| &state.computed_skeleton)
else {
return;
};
let Some(attr) = anim::quadruped_low::SkeletonAttr::try_from(body).ok() else {
return;
};
let start = (skeleton.tail_front * Vec4::unit_w()).xyz();
let end = (skeleton.tail_rear * Vec4::new(0.0, -attr.tail_rear_length, 0.0, 1.0)).xyz();
let start = pos + start;
let end = pos + end;
@ -1716,8 +1820,8 @@ impl ParticleMgr {
if let Some(states::glide::Boost::Forward(_)) = &glide.booster
&& let Some(figure_state) =
figure_mgr.states.character_states.get(&entity)
&& let Some(tp0) = figure_state.main_abs_trail_points
&& let Some(tp1) = figure_state.off_abs_trail_points
&& let Some(tp0) = figure_state.primary_abs_trail_points
&& let Some(tp1) = figure_state.secondary_abs_trail_points
{
for _ in 0..self.scheduler.heartbeats(Duration::from_millis(5)) {
self.particles.push(Particle::new(
@ -1796,6 +1900,7 @@ impl ParticleMgr {
figure_mgr,
entity,
interpolated.pos,
body,
character_state,
inventory,
);

View File

@ -290,12 +290,13 @@ impl Scene {
scale: 1.0,
mount_transform_pos: None,
body: None,
tools: (None, None),
col: Rgba::broadcast(1.0),
dt,
is_player: false,
terrain: None,
ground_vel: Vec3::zero(),
primary_trail_points: None,
secondary_trail_points: None,
}
}
@ -305,7 +306,7 @@ impl Scene {
});
let params = figure_params(scene_data.delta_time, self.char_pos);
let tgt_skeleton = anim::character::IdleAnimation::update_skeleton(
char_state.skeleton_mut(),
&char_state.skeleton,
(
active_tool_kind,
second_tool_kind,
@ -317,8 +318,7 @@ impl Scene {
&anim::character::SkeletonAttr::from(&body),
);
let dt_lerp = (scene_data.delta_time * 15.0).min(1.0);
*char_state.skeleton_mut() =
Lerp::lerp(&*char_state.skeleton_mut(), &tgt_skeleton, dt_lerp);
char_state.skeleton = Lerp::lerp(&char_state.skeleton, &tgt_skeleton, dt_lerp);
let (model, _) = self.char_model_cache.get_or_create_model(
renderer,
&mut self.figure_atlas,
@ -348,7 +348,7 @@ impl Scene {
});
let params = figure_params(scene_data.delta_time, self.airship_pos);
let tgt_skeleton = anim::ship::IdleAnimation::update_skeleton(
airship_state.skeleton_mut(),
&airship_state.skeleton,
(
None,
None,
@ -362,8 +362,7 @@ impl Scene {
&anim::ship::SkeletonAttr::from(&airship_body),
);
let dt_lerp = (scene_data.delta_time * 15.0).min(1.0);
*airship_state.skeleton_mut() =
Lerp::lerp(&*airship_state.skeleton_mut(), &tgt_skeleton, dt_lerp);
airship_state.skeleton = Lerp::lerp(&airship_state.skeleton, &tgt_skeleton, dt_lerp);
let (model, _) = self.airship_model_cache.get_or_create_terrain_model(
renderer,
&mut self.figure_atlas,