veloren_voxygen_anim/character/
mod.rs

1pub mod basic;
2pub mod boost;
3pub mod climb;
4pub mod collect;
5pub mod consume;
6pub mod crawl;
7pub mod dance;
8pub mod equip;
9pub mod glidewield;
10pub mod gliding;
11pub mod idle;
12pub mod jump;
13pub mod mount;
14pub mod multi;
15pub mod music;
16pub mod pet;
17pub mod roll;
18pub mod run;
19pub mod sit;
20pub mod sleep;
21pub mod sneak;
22pub mod sneakequip;
23pub mod sneakwield;
24pub mod staggered;
25pub mod stand;
26pub mod steer;
27pub mod stunned;
28pub mod swim;
29pub mod swimwield;
30pub mod talk;
31pub mod wallrun;
32pub mod wield;
33
34// Reexports
35pub use self::{
36    basic::{BasicAction, BasicActionDependency},
37    boost::BoostAnimation,
38    climb::ClimbAnimation,
39    collect::CollectAnimation,
40    consume::ConsumeAnimation,
41    crawl::CrawlAnimation,
42    dance::DanceAnimation,
43    equip::EquipAnimation,
44    glidewield::GlideWieldAnimation,
45    gliding::GlidingAnimation,
46    idle::IdleAnimation,
47    jump::JumpAnimation,
48    mount::MountAnimation,
49    multi::{MultiAction, MultiActionDependency},
50    music::MusicAnimation,
51    pet::PetAnimation,
52    roll::RollAnimation,
53    run::RunAnimation,
54    sit::SitAnimation,
55    sleep::SleepAnimation,
56    sneak::SneakAnimation,
57    sneakequip::SneakEquipAnimation,
58    sneakwield::SneakWieldAnimation,
59    staggered::StaggeredAnimation,
60    stand::StandAnimation,
61    steer::SteerAnimation,
62    stunned::StunnedAnimation,
63    swim::SwimAnimation,
64    swimwield::SwimWieldAnimation,
65    talk::TalkAnimation,
66    wallrun::WallrunAnimation,
67    wield::WieldAnimation,
68};
69use super::{FigureBoneData, Offsets, Skeleton, TrailSource, make_bone, vek::*};
70use common::comp::{
71    self,
72    tool::{Hands, ToolKind},
73};
74use core::{convert::TryFrom, f32::consts::PI};
75
76pub type Body = comp::humanoid::Body;
77
78skeleton_impls!(struct CharacterSkeleton {
79    + head,
80    + chest,
81    + belt,
82    + back,
83    + shorts,
84    + hand_l,
85    + hand_r,
86    + foot_l,
87    + foot_r,
88    + shoulder_l,
89    + shoulder_r,
90    + glider,
91    + main,
92    + second,
93    + lantern,
94    + hold,
95    torso,
96    control,
97    control_l,
98    control_r,
99    :: // Begin non-bone fields
100    holding_lantern: bool,
101    // The offset from the back that carried weapons should be given to avoid clipping due to, say, a backpack
102    back_carry_offset: f32,
103    main_weapon_trail: bool,
104    off_weapon_trail: bool,
105    // Cannot exist at same time as weapon trails. Since gliding and attacking are mutually exclusive, should never be a concern.
106    glider_trails: bool,
107});
108
109impl CharacterSkeleton {
110    pub fn new(holding_lantern: bool, back_carry_offset: f32) -> Self {
111        Self {
112            holding_lantern,
113            back_carry_offset,
114            ..Self::default()
115        }
116    }
117}
118
119impl Skeleton for CharacterSkeleton {
120    type Attr = SkeletonAttr;
121    type Body = Body;
122
123    const BONE_COUNT: usize = 16;
124    #[cfg(feature = "use-dyn-lib")]
125    const COMPUTE_FN: &'static [u8] = b"character_compute_mats\0";
126
127    #[cfg_attr(feature = "be-dyn-lib", export_name = "character_compute_mats")]
128    fn compute_matrices_inner(
129        &self,
130        base_mat: Mat4<f32>,
131        buf: &mut [FigureBoneData; super::MAX_BONE_COUNT],
132        body: Self::Body,
133    ) -> Offsets {
134        // TODO: extract scaler from body to it's own method so we can call that
135        // directly instead of going through SkeletonAttr? (note todo also
136        // appiles to other body variant animations)
137        let base_mat = base_mat * Mat4::scaling_3d(SkeletonAttr::from(&body).scaler / 11.0);
138
139        let torso_mat = base_mat * Mat4::<f32>::from(self.torso);
140        let chest_mat = torso_mat * Mat4::<f32>::from(self.chest);
141        let head_mat = chest_mat * Mat4::<f32>::from(self.head);
142        let shorts_mat = chest_mat * Mat4::<f32>::from(self.shorts);
143        let control_mat = chest_mat * Mat4::<f32>::from(self.control);
144        let control_l_mat = control_mat * Mat4::<f32>::from(self.control_l);
145        let control_r_mat = control_mat * Mat4::<f32>::from(self.control_r);
146        let hand_r_mat = control_r_mat * Mat4::<f32>::from(self.hand_r);
147
148        let hand_l_mat = Mat4::<f32>::from(self.hand_l);
149        let lantern_mat = if self.holding_lantern {
150            hand_r_mat
151        } else {
152            shorts_mat
153        } * Mat4::<f32>::from(self.lantern);
154        let main_mat = control_l_mat * Mat4::<f32>::from(self.main);
155        let second_mat = control_r_mat * Mat4::<f32>::from(self.second);
156        let glider_mat = chest_mat * Mat4::<f32>::from(self.glider);
157
158        *(<&mut [_; Self::BONE_COUNT]>::try_from(&mut buf[0..Self::BONE_COUNT]).unwrap()) = [
159            make_bone(head_mat),
160            make_bone(chest_mat),
161            make_bone(chest_mat * Mat4::<f32>::from(self.belt)),
162            make_bone(chest_mat * Mat4::<f32>::from(self.back)),
163            make_bone(shorts_mat),
164            make_bone(control_l_mat * hand_l_mat),
165            make_bone(hand_r_mat),
166            make_bone(torso_mat * Mat4::<f32>::from(self.foot_l)),
167            make_bone(torso_mat * Mat4::<f32>::from(self.foot_r)),
168            make_bone(chest_mat * Mat4::<f32>::from(self.shoulder_l)),
169            make_bone(chest_mat * Mat4::<f32>::from(self.shoulder_r)),
170            make_bone(glider_mat),
171            make_bone(main_mat),
172            make_bone(second_mat),
173            make_bone(lantern_mat),
174            // FIXME: Should this be control_l_mat?
175            make_bone(control_mat * hand_l_mat * Mat4::<f32>::from(self.hold)),
176        ];
177
178        // Offset from the mounted bone's origin.
179        // Note: This could be its own bone if we need to animate it independently.
180        let mount_position = (chest_mat * Vec4::from_point(Vec3::new(5.5, 0.0, 6.5)))
181            .homogenized()
182            .xyz();
183        // NOTE: We apply the ori from base_mat externally so we don't need to worry
184        // about it here for now.
185        let mount_orientation =
186            self.torso.orientation * self.chest.orientation * Quaternion::rotation_y(0.4);
187
188        let weapon_trails = self.main_weapon_trail || self.off_weapon_trail;
189        Offsets {
190            lantern: Some((lantern_mat * Vec4::new(0.0, 0.5, -6.0, 1.0)).xyz()),
191            viewpoint: Some((head_mat * Vec4::new(0.0, 0.0, 4.0, 1.0)).xyz()),
192            mount_bone: Transform {
193                position: mount_position,
194                orientation: mount_orientation,
195                scale: Vec3::one(),
196            },
197            primary_trail_mat: if weapon_trails {
198                self.main_weapon_trail
199                    .then_some((main_mat, TrailSource::Weapon))
200            } else {
201                self.glider_trails
202                    .then_some((glider_mat, TrailSource::GliderLeft))
203            },
204            secondary_trail_mat: if weapon_trails {
205                self.off_weapon_trail
206                    .then_some((second_mat, TrailSource::Weapon))
207            } else {
208                self.glider_trails
209                    .then_some((glider_mat, TrailSource::GliderRight))
210            },
211            ..Default::default()
212        }
213    }
214}
215
216pub struct SkeletonAttr {
217    scaler: f32,
218    head_scale: f32,
219    head: (f32, f32),
220    chest: (f32, f32),
221    belt: (f32, f32),
222    back: (f32, f32),
223    shorts: (f32, f32),
224    hand: (f32, f32, f32),
225    foot: (f32, f32, f32),
226    shoulder: (f32, f32, f32),
227    lantern: (f32, f32, f32),
228    shl: (f32, f32, f32, f32, f32, f32),
229    shr: (f32, f32, f32, f32, f32, f32),
230    sc: (f32, f32, f32, f32, f32, f32),
231    hhl: (f32, f32, f32, f32, f32, f32),
232    hhr: (f32, f32, f32, f32, f32, f32),
233    hc: (f32, f32, f32, f32, f32, f32),
234    sthl: (f32, f32, f32, f32, f32, f32),
235    sthr: (f32, f32, f32, f32, f32, f32),
236    stc: (f32, f32, f32, f32, f32, f32),
237    ahl: (f32, f32, f32, f32, f32, f32),
238    ahr: (f32, f32, f32, f32, f32, f32),
239    ac: (f32, f32, f32, f32, f32, f32),
240    bhl: (f32, f32, f32, f32, f32, f32),
241    bhr: (f32, f32, f32, f32, f32, f32),
242    bc: (f32, f32, f32, f32, f32, f32),
243}
244
245impl Default for SkeletonAttr {
246    fn default() -> Self {
247        Self {
248            scaler: 0.0,
249            head_scale: 0.0,
250            head: (0.0, 0.0),
251            chest: (0.0, 0.0),
252            belt: (0.0, 0.0),
253            back: (0.0, 0.0),
254            shorts: (0.0, 0.0),
255            hand: (0.0, 0.0, 0.0),
256            foot: (0.0, 0.0, 0.0),
257            shoulder: (0.0, 0.0, 0.0),
258            lantern: (0.0, 0.0, 0.0),
259            shl: (0.0, 0.0, 0.0, 0.0, 0.0, 0.0),
260            shr: (0.0, 0.0, 0.0, 0.0, 0.0, 0.0),
261            sc: (0.0, 0.0, 0.0, 0.0, 0.0, 0.0),
262            hhl: (0.0, 0.0, 10.0, 0.0, 0.0, 0.0),
263            hhr: (0.0, 0.0, 0.0, 0.0, 0.0, 0.0),
264            hc: (0.0, 0.0, 0.0, 0.0, 0.0, 0.0),
265            sthl: (0.0, 0.0, 10.0, 0.0, 0.0, 0.0),
266            sthr: (0.0, 0.0, 0.0, 0.0, 0.0, 0.0),
267            stc: (0.0, 0.0, 0.0, 0.0, 0.0, 0.0),
268            ahl: (0.0, 0.0, 10.0, 0.0, 0.0, 0.0),
269            ahr: (0.0, 0.0, 0.0, 0.0, 0.0, 0.0),
270            ac: (0.0, 0.0, 0.0, 0.0, 0.0, 0.0),
271            bhl: (0.0, 0.0, 10.0, 0.0, 0.0, 0.0),
272            bhr: (0.0, 0.0, 0.0, 0.0, 0.0, 0.0),
273            bc: (0.0, 0.0, 0.0, 0.0, 0.0, 0.0),
274        }
275    }
276}
277
278impl<'a> TryFrom<&'a comp::Body> for SkeletonAttr {
279    type Error = ();
280
281    fn try_from(body: &'a comp::Body) -> Result<Self, Self::Error> {
282        match body {
283            comp::Body::Humanoid(body) => Ok(SkeletonAttr::from(body)),
284            _ => Err(()),
285        }
286    }
287}
288
289impl<'a> From<&'a Body> for SkeletonAttr {
290    fn from(body: &'a Body) -> Self {
291        use comp::humanoid::{BodyType::*, Species::*};
292        Self {
293            scaler: body.scaler(),
294            head_scale: match (body.species, body.body_type) {
295                (Orc, Male) => 0.9,
296                (Orc, Female) => 0.9,
297                (Human, Male) => 0.9,
298                (Human, Female) => 0.9,
299                (Elf, Male) => 0.9,
300                (Elf, Female) => 0.9,
301                (Dwarf, Male) => 1.0,
302                (Dwarf, Female) => 1.0,
303                (Draugr, Male) => 0.9,
304                (Draugr, Female) => 0.9,
305                (Danari, Male) => 1.15,
306                (Danari, Female) => 1.15,
307            },
308            head: match (body.species, body.body_type) {
309                (Orc, Male) => (-2.0, 9.0),
310                (Orc, Female) => (-2.0, 9.5),
311                (Human, Male) => (-2.3, 9.5),
312                (Human, Female) => (-2.0, 9.5),
313                (Elf, Male) => (-2.5, 9.5),
314                (Elf, Female) => (-1.0, 9.5),
315                (Dwarf, Male) => (-2.0, 10.0),
316                (Dwarf, Female) => (-2.0, 9.5),
317                (Draugr, Male) => (-1.5, 8.5),
318                (Draugr, Female) => (-1.5, 9.5),
319                (Danari, Male) => (-1.5, 7.0),
320                (Danari, Female) => (-1.5, 7.0),
321            },
322            chest: (0.0, 8.0),
323            belt: (0.0, -2.0),
324            back: (-3.1, 7.25),
325            shorts: (0.0, -5.0),
326            hand: (7.0, -0.25, 0.5),
327            foot: (3.4, 0.5, 2.0),
328            shoulder: (5.0, 0.0, 5.0),
329            lantern: (5.0, 2.5, 5.5),
330            shl: (-0.75, -1.0, 0.5, 1.47, -0.2, 0.0),
331            shr: (0.75, -1.5, -2.5, 1.47, 0.3, 0.0),
332            sc: (-6.0, 6.0, 0.0, -0.5, 0.0, 0.0),
333            hhl: (0.1, 0.0, 11.0, 4.71, 0.0, PI),
334            hhr: (0.0, 0.0, 0.0, 4.71, 0.0, PI),
335            hc: (6.0, 7.0, 1.0, -0.3, -PI / 2.0, 3.64),
336            sthl: (0.0, 0.0, 6.0, 1.97, 0.0, 0.0),
337            sthr: (0.0, 0.0, 0.0, 1.27, 0.2, 0.0),
338            stc: (-5.0, 7.0, -2.0, -0.3, 0.15, 0.0),
339            ahl: (-0.5, -1.0, 7.0, 1.17, PI, 0.0),
340            ahr: (0.0, -1.0, 1.0, -2.0, 0.0, PI),
341            ac: (-8.0, 11.0, 3.0, 2.0, 0.0, 0.0),
342            bhl: (0.0, -4.0, 1.0, PI / 2.0, 0.0, 0.0),
343            bhr: (1.0, 2.0, -2.0, PI / 2.0, 0.0, 0.0),
344            bc: (-5.0, 9.0, 1.0, 0.0, 1.2, -0.6),
345        }
346    }
347}
348
349impl CharacterSkeleton {
350    /// Animate tools (main and secondary) on the character's back, taking in
351    /// account backpack offsets.
352    pub fn do_tools_on_back(
353        &mut self,
354        hands: (Option<Hands>, Option<Hands>),
355        active_tool_kind: Option<ToolKind>,
356        second_tool_kind: Option<ToolKind>,
357    ) {
358        match (hands, active_tool_kind, second_tool_kind) {
359            ((Some(Hands::Two), _), tool, _) | ((None, Some(Hands::Two)), _, tool) => match tool {
360                Some(ToolKind::Bow) => {
361                    self.main.position = Vec3::new(0.0, -5.0 - self.back_carry_offset, 6.0);
362                    self.main.orientation =
363                        Quaternion::rotation_y(2.5) * Quaternion::rotation_z(PI / 2.0);
364                },
365                Some(ToolKind::Staff) | Some(ToolKind::Sceptre) => {
366                    self.main.position = Vec3::new(2.0, -5.0 - self.back_carry_offset, -1.0);
367                    self.main.orientation =
368                        Quaternion::rotation_y(-0.5) * Quaternion::rotation_z(PI / 2.0);
369                },
370                Some(ToolKind::Shield) => {
371                    self.main.position = Vec3::new(-2.0, -3.0 - self.back_carry_offset, 1.0);
372                    self.main.orientation =
373                        Quaternion::rotation_y(-0.75) * Quaternion::rotation_z(PI / 2.0);
374                },
375                _ => {
376                    self.main.position = Vec3::new(-7.0, -5.0 - self.back_carry_offset, 15.0);
377                    self.main.orientation =
378                        Quaternion::rotation_y(2.5) * Quaternion::rotation_z(PI / 2.0);
379                },
380            },
381            ((_, _), _, _) => {},
382        }
383
384        match hands {
385            (Some(Hands::One), _) => match active_tool_kind {
386                Some(ToolKind::Dagger) => {
387                    self.main.position = Vec3::new(5.0, 1.0 - self.back_carry_offset, 2.0);
388                    self.main.orientation =
389                        Quaternion::rotation_x(-1.35 * PI) * Quaternion::rotation_z(2.0 * PI);
390                },
391                Some(ToolKind::Axe) | Some(ToolKind::Hammer) | Some(ToolKind::Sword) => {
392                    self.main.position = Vec3::new(-4.0, -4.5 - self.back_carry_offset, 10.0);
393                    self.main.orientation =
394                        Quaternion::rotation_y(2.5) * Quaternion::rotation_z(PI / 2.0);
395                },
396                Some(ToolKind::Shield) => {
397                    self.main.position = Vec3::new(-2.0, -4.0 - self.back_carry_offset, 3.0);
398                    self.main.orientation =
399                        Quaternion::rotation_y(0.25 * PI) * Quaternion::rotation_z(-1.5 * PI);
400                },
401                _ => {},
402            },
403            (_, _) => {},
404        }
405        match hands {
406            (None | Some(Hands::One), Some(Hands::One)) => match second_tool_kind {
407                Some(ToolKind::Dagger) => {
408                    self.second.position = Vec3::new(-5.0, 1.0 - self.back_carry_offset, 2.0);
409                    self.second.orientation =
410                        Quaternion::rotation_x(-1.35 * PI) * Quaternion::rotation_z(-2.0 * PI);
411                },
412                Some(ToolKind::Axe) | Some(ToolKind::Hammer) | Some(ToolKind::Sword) => {
413                    self.second.position = Vec3::new(4.0, -5.0 - self.back_carry_offset, 10.0);
414                    self.second.orientation =
415                        Quaternion::rotation_y(-2.5) * Quaternion::rotation_z(-PI / 2.0);
416                },
417                Some(ToolKind::Shield) => {
418                    self.second.position = Vec3::new(1.5, -4.0 - self.back_carry_offset, 3.0);
419                    self.second.orientation =
420                        Quaternion::rotation_y(-0.25 * PI) * Quaternion::rotation_z(1.5 * PI);
421                },
422                _ => {},
423            },
424            (_, _) => {},
425        }
426    }
427
428    /// If we're holding a lantern, animate hold the lantern in a reasonable
429    /// position.
430    pub fn do_hold_lantern(
431        &mut self,
432        s_a: &SkeletonAttr,
433        anim_time: f32,
434        acc_vel: f32,
435        speednorm: f32,
436        impact: f32,
437        tilt: f32,
438    ) {
439        let lab = 2.0 / s_a.scaler;
440
441        let short = ((5.0 / (1.5 + 3.5 * ((acc_vel * lab * 1.6 + PI * 0.5).sin()).powi(2))).sqrt())
442            * ((acc_vel * lab * 1.6 + PI * 0.5).sin());
443
444        let shorte = ((1.0 / (0.8 + 0.2 * ((acc_vel * lab * 1.6).sin()).powi(2))).sqrt())
445            * ((acc_vel * lab * 1.6).sin());
446
447        self.lantern.position = Vec3::new(s_a.lantern.0, s_a.lantern.1, s_a.lantern.2);
448        self.lantern.orientation = Quaternion::rotation_x(shorte * 0.7 * speednorm.powi(2) + 0.4)
449            * Quaternion::rotation_y(shorte * 0.4 * speednorm.powi(2));
450        self.lantern.scale = Vec3::one() * 0.65;
451        self.hold.scale = Vec3::one() * 0.0;
452
453        if self.holding_lantern {
454            self.hand_r.position = Vec3::new(
455                s_a.hand.0 + 1.0,
456                s_a.hand.1 + 2.0 - impact * 0.2,
457                s_a.hand.2 + 12.0 + impact * -0.1,
458            );
459            self.hand_r.orientation = Quaternion::rotation_x(2.25) * Quaternion::rotation_z(0.9);
460            self.shoulder_r.orientation = Quaternion::rotation_x(short * -0.15 + 2.0);
461
462            let fast = (anim_time * 8.0).sin();
463            let fast2 = (anim_time * 6.0 + 8.0).sin();
464
465            self.lantern.position = Vec3::new(-0.5, -0.5, -2.5);
466            self.lantern.orientation = self.hand_r.orientation.inverse()
467                * Quaternion::rotation_x(
468                    (fast + 0.5) * 1.0 * speednorm + (tilt.abs() * 2.0).min(PI * 0.5),
469                )
470                * Quaternion::rotation_y(tilt * 1.0 * fast + tilt * 1.0 + fast2 * speednorm * 0.25);
471        }
472    }
473}
474
475pub fn hammer_start(next: &mut CharacterSkeleton, s_a: &SkeletonAttr) {
476    next.main.position = Vec3::new(0.0, 0.0, 0.0);
477    next.main.orientation = Quaternion::rotation_z(0.0);
478    next.hand_l.position = Vec3::new(s_a.hhl.0, s_a.hhl.1 + 3.0, s_a.hhl.2 - 1.0);
479    next.hand_l.orientation = Quaternion::rotation_x(s_a.hhl.3)
480        * Quaternion::rotation_y(s_a.hhl.4)
481        * Quaternion::rotation_z(s_a.hhl.5);
482    next.hand_r.position = Vec3::new(s_a.hhr.0, s_a.hhr.1 + 3.0, s_a.hhr.2 + 1.0);
483    next.hand_r.orientation = Quaternion::rotation_x(s_a.hhr.3)
484        * Quaternion::rotation_y(s_a.hhr.4)
485        * Quaternion::rotation_z(s_a.hhr.5);
486
487    next.control.position = Vec3::new(s_a.hc.0 - 1.0, s_a.hc.1, s_a.hc.2 - 3.0);
488    next.control.orientation = Quaternion::rotation_x(s_a.hc.3)
489        * Quaternion::rotation_y(s_a.hc.4)
490        * Quaternion::rotation_z(s_a.hc.5);
491}
492
493pub fn twist_back(next: &mut CharacterSkeleton, move1: f32, c: f32, h: f32, b: f32, s: f32) {
494    next.chest.orientation.rotate_z(move1 * c);
495    next.head.orientation.rotate_z(move1 * -h);
496    next.belt.orientation.rotate_z(move1 * -b);
497    next.shorts.orientation.rotate_z(move1 * -s);
498}
499
500pub fn twist_forward(next: &mut CharacterSkeleton, move2: f32, c: f32, h: f32, b: f32, s: f32) {
501    next.chest.orientation.rotate_z(move2 * -c);
502    next.head.orientation.rotate_z(move2 * h);
503    next.belt.orientation.rotate_z(move2 * b);
504    next.shorts.orientation.rotate_z(move2 * s);
505}
506
507pub fn dual_wield_start(next: &mut CharacterSkeleton) {
508    next.main.position = Vec3::new(0.0, 0.0, 0.0);
509    next.main.orientation = Quaternion::rotation_z(0.0);
510    next.second.position = Vec3::new(0.0, 0.0, 0.0);
511    next.second.orientation = Quaternion::rotation_z(0.0);
512
513    next.control_l.position =
514        next.hand_l.position * Vec3::new(0.5, 0.5, 0.3) + Vec3::new(-4.0, 0.0, 0.0);
515    next.control_l.orientation = Quaternion::lerp(
516        next.hand_l.orientation,
517        Quaternion::rotation_x(PI * -0.5),
518        0.65,
519    );
520    next.hand_l.position = Vec3::new(0.0, -2.0, 0.0);
521    next.hand_l.orientation = Quaternion::rotation_x(PI * 0.5);
522
523    next.control_r.position =
524        next.hand_r.position * Vec3::new(0.5, 0.5, 0.3) + Vec3::new(4.0, 0.0, 0.0);
525    next.control_r.orientation = Quaternion::lerp(
526        next.hand_r.orientation,
527        Quaternion::rotation_x(PI * -0.5),
528        0.65,
529    );
530    next.hand_r.position = Vec3::new(0.0, -2.0, 0.0);
531    next.hand_r.orientation = Quaternion::rotation_x(PI * 0.5);
532}