]> git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/blob - qcsrc/client/player_skeleton.qc
Merge branch 'master' into mario/monsters
[xonotic/xonotic-data.pk3dir.git] / qcsrc / client / player_skeleton.qc
1 .float skeleton_modelindex;
2 #define BONETYPE_LOWER 0
3 #define BONETYPE_UPPER 1
4 #define MAX_BONES 128
5 .float skeleton_bonetype[MAX_BONES];
6 .float skeleton_fixrotatebone;
7 .float skeleton_fixtargetbone;
8 .float skeleton_bone;
9 .float skeleton_aimbone;
10 .float skeleton_numbones;
11
12 void skeleton_identifybones(entity e)
13 {
14         float s = e.skeletonindex;
15         float n = (e.skeleton_numbones = skel_get_numbones(s));
16         e.skeleton_aimbone = 0;
17         e.skeleton_fixrotatebone = 0;
18         e.skeleton_fixtargetbone = 0;
19         float i;
20         for(i = 1; i <= n; ++i)
21         {
22                 float t = BONETYPE_LOWER;
23                 float p = skel_get_boneparent(s, i);
24                 if(p > 0)
25                         t = e.(skeleton_bonetype[p-1]);
26                 string nm = skel_get_bonename(s, i);
27                 if(nm == "spine2")
28                 {
29                         e.skeleton_fixrotatebone = i;
30                         t = BONETYPE_UPPER;
31                 }
32                 if(nm == "weapon" || nm == "tag_weapon" || nm == "bip01 r hand")
33                         if(t == BONETYPE_UPPER)
34                                 e.skeleton_fixtargetbone = i;
35                 if(nm == "upperarm_R")
36                         e.skeleton_aimbone = i;
37                 e.(skeleton_bonetype[i-1]) = t;
38         }
39 }
40
41 void skel_set_bone_lerp(float skel, float bone, vector org, float strength)
42 {
43         if(strength >= 1)
44                 return skel_set_bone(skel, bone, org);
45
46         vector fo = v_forward;
47         vector ri = v_right;
48         vector up = v_up;
49         vector oldorg = skel_get_bonerel(skel, bone);
50
51         org = org * strength + oldorg * (1 - strength);
52         v_forward = fo * strength + v_forward * (1 - strength);
53         v_right = ri * strength + v_right * (1 - strength);
54         v_up = up * strength + v_up * (1 - strength);
55         return skel_set_bone(skel, bone, org);
56 }
57
58 void skeleton_fixbone(entity e, float strength, float yawonly)
59 {
60         if(!e.skeleton_fixrotatebone)
61                 return;
62         if(strength <= 0)
63                 return;
64         // model:
65         // T  = M_before_fixrotate * M_fixrotate  * M_after_fixrotate
66         // T' = M_before_fixrotate^-1 * M_fixrotate' * M_after_fixrotate
67         // M_fixrotate' = M_before_fixrotate^-1 * T' * M_after_fixrotate^-1
68         float s = e.skeletonindex;
69
70         skel_get_boneabs(s, skel_get_boneparent(s, e.skeleton_fixrotatebone));
71         vector M_before_fixrotate = fixedvectoangles2(v_forward, v_up);
72         skel_get_boneabs(s, e.skeleton_fixrotatebone);
73         vector M_including_fixrotate = fixedvectoangles2(v_forward, v_up);
74         skel_get_boneabs(s, e.skeleton_fixtargetbone);
75         vector T = fixedvectoangles2(v_forward, v_up);
76         vector M_after_fixrotate = AnglesTransform_LeftDivide(M_including_fixrotate, T);
77         vector T_ = T;
78         if(yawonly)
79                 T__y = 0; // undo yaw
80         else
81                 T_ = '0 0 0'; // undo all
82         vector M_fixrotate_ = AnglesTransform_LeftDivide(M_before_fixrotate, AnglesTransform_RightDivide(T_, M_after_fixrotate));
83         vector org = skel_get_bonerel(s, e.skeleton_fixrotatebone);
84         fixedmakevectors(M_fixrotate_);
85         skel_set_bone_lerp(s, e.skeleton_fixrotatebone, org, strength);
86 }
87
88 void free_skeleton_from_frames(entity e)
89 {
90         if(e.skeletonindex)
91         {
92                 skel_delete(e.skeletonindex);
93                 e.skeletonindex = 0;
94         }
95 }
96
97 void skeleton_from_frames(entity e)
98 {
99         float m = e.modelindex;
100         if(m != e.skeleton_modelindex)
101         {
102                 if(e.skeletonindex)
103                 {
104                         skel_delete(e.skeletonindex);
105                         e.skeletonindex = 0;
106                 }
107                 m = (e.skeleton_modelindex = e.modelindex);
108                 if(m)
109                 {
110                         e.skeletonindex = skel_create(m);
111                         skeleton_identifybones(e);
112                 }
113         }
114         float s = e.skeletonindex;
115         if(!s)
116                 return;
117         float bone;
118         float n = e.skeleton_numbones;
119         float savelerpfrac = e.lerpfrac;
120         float savelerpfrac3 = e.lerpfrac3;
121         float savelerpfrac4 = e.lerpfrac4;
122         for(bone = 0; bone < n; )
123         {
124                 float firstbone = bone;
125                 float bonetype = e.skeleton_bonetype[bone];
126                 for(++bone; (bone < n) && (e.skeleton_bonetype[bone] == bonetype); ++bone)
127                         ;
128                 if(bonetype == BONETYPE_UPPER)
129                 {
130                         // only show frames 1+3 (upper body)
131                         e.lerpfrac = 0;
132                         e.lerpfrac3 = savelerpfrac3 * 2;
133                         e.lerpfrac4 = 0;
134                 }
135                 else
136                 {
137                         // only show frames 2+4 (lower body)
138                         e.lerpfrac = savelerpfrac * 2;
139                         e.lerpfrac3 = 0;
140                         e.lerpfrac4 = savelerpfrac4 * 2;
141                 }
142                 //print(sprintf("Run: bone %d to %d, type %d\n", firstbone + 1, bone, bonetype));
143                 //print(sprintf("frame %d %d %d %d lerpfrac * %d %d %d\n", e.frame, e.frame2, e.frame3, e.frame4, e.lerpfrac, e.lerpfrac3, e.lerpfrac4));
144                 skel_build(s, e, m, 0, firstbone + 1, bone);
145         }
146         e.lerpfrac = savelerpfrac;
147         e.lerpfrac3 = savelerpfrac3;
148         e.lerpfrac4 = savelerpfrac4;
149
150         if(autocvar__animblend_fixbone)
151         {
152                 float l4 = e.lerpfrac4;
153                 float l3 = e.lerpfrac3;
154                 float l2 = e.lerpfrac;
155                 float l1 = 1 - l2 - l3 - l4;
156
157                 // how much of upper body animates same way as lower body?
158                 float equalamount =
159                         (e.frame == e.frame2) * (l1 * l2) +
160                         (e.frame == e.frame4) * (l1 * l4) +
161                         (e.frame3 == e.frame2) * (l3 * l2) +
162                         (e.frame3 == e.frame4) * (l3 * l4);
163                 float maxequalamount = (l1 + l3) * (l2 + l4);
164
165                 // now how strong is the lerp?
166                 float lerpstrength = 1 - equalamount / maxequalamount;
167
168                 // FIX IT
169                 skeleton_fixbone(e, lerpstrength, autocvar__animblend_fixbone >= 2);
170         }
171 }