]> git.jsancho.org Git - lugaru.git/blob - Source/Animation/Skeleton.cpp
Applied clang-format on all files
[lugaru.git] / Source / Animation / Skeleton.cpp
1 /*
2 Copyright (C) 2003, 2010 - Wolfire Games
3 Copyright (C) 2010-2016 - Lugaru contributors (see AUTHORS file)
4
5 This file is part of Lugaru.
6
7 Lugaru is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
11
12 Lugaru is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with Lugaru.  If not, see <http://www.gnu.org/licenses/>.
19 */
20
21 #include "Animation/Skeleton.hpp"
22
23 #include "Animation/Animation.hpp"
24 #include "Audio/openal_wrapper.hpp"
25 #include "Game.hpp"
26 #include "Tutorial.hpp"
27 #include "Utils/Folders.hpp"
28
29 extern float multiplier;
30 extern float gravity;
31 extern Terrain terrain;
32 extern int environment;
33 extern float camerashake;
34 extern bool freeze;
35 extern int detail;
36
37 extern int whichjointstartarray[26];
38 extern int whichjointendarray[26];
39
40 Skeleton::Skeleton()
41     : selected(0)
42     , id(0)
43     , num_models(0)
44     , clothes(false)
45     , spinny(false)
46     , skinsize(0)
47     , checkdelay(0)
48     , longdead(0)
49     , broken(false)
50     , free(0)
51     , oldfree(0)
52     , freetime(0)
53     , freefall(false)
54 {
55     memset(forwardjoints, 0, sizeof(forwardjoints));
56     memset(lowforwardjoints, 0, sizeof(lowforwardjoints));
57     memset(jointlabels, 0, sizeof(jointlabels));
58     memset(skinText, 0, sizeof(skinText));
59 }
60
61 /* EFFECT
62  * sets forward, lowforward, specialforward[]
63  *
64  * USES:
65  * Skeleton::Load
66  * Person/Person::DoAnimations
67  * Person/Person::DrawSkeleton
68  */
69 void Skeleton::FindForwards()
70 {
71     //Find forward vectors
72     CrossProduct(joints[forwardjoints[1]].position - joints[forwardjoints[0]].position, joints[forwardjoints[2]].position - joints[forwardjoints[0]].position, &forward);
73     Normalise(&forward);
74
75     CrossProduct(joints[lowforwardjoints[1]].position - joints[lowforwardjoints[0]].position, joints[lowforwardjoints[2]].position - joints[lowforwardjoints[0]].position, &lowforward);
76     Normalise(&lowforward);
77
78     //Special forwards
79     specialforward[0] = forward;
80
81     specialforward[1] = jointPos(rightshoulder) + jointPos(rightwrist);
82     specialforward[1] = jointPos(rightelbow) - specialforward[1] / 2;
83     specialforward[1] += forward * .4;
84     Normalise(&specialforward[1]);
85     specialforward[2] = jointPos(leftshoulder) + jointPos(leftwrist);
86     specialforward[2] = jointPos(leftelbow) - specialforward[2] / 2;
87     specialforward[2] += forward * .4;
88     Normalise(&specialforward[2]);
89
90     specialforward[3] = jointPos(righthip) + jointPos(rightankle);
91     specialforward[3] = specialforward[3] / 2 - jointPos(rightknee);
92     specialforward[3] += lowforward * .4;
93     Normalise(&specialforward[3]);
94     specialforward[4] = jointPos(lefthip) + jointPos(leftankle);
95     specialforward[4] = specialforward[4] / 2 - jointPos(leftknee);
96     specialforward[4] += lowforward * .4;
97     Normalise(&specialforward[4]);
98 }
99
100 /* EFFECT
101  * TODO
102  *
103  * USES:
104  * Person/Person::RagDoll
105  * Person/Person::DoStuff
106  * Person/IKHelper
107  */
108 float Skeleton::DoConstraints(XYZ* coords, float* scale)
109 {
110     const float elasticity = .3;
111     XYZ bounceness;
112     const int numrepeats = 3;
113     float groundlevel = .15;
114     unsigned i;
115     XYZ temp;
116     XYZ terrainnormal;
117     int whichhit;
118     float frictionness;
119     XYZ terrainlight;
120     int whichpatchx;
121     int whichpatchz;
122     float damage = 0; // eventually returned from function
123     bool breaking = false;
124
125     if (free) {
126         freetime += multiplier;
127
128         whichpatchx = coords->x / (terrain.size / subdivision * terrain.scale);
129         whichpatchz = coords->z / (terrain.size / subdivision * terrain.scale);
130
131         terrainlight = *coords;
132         Object::SphereCheckPossible(&terrainlight, 1);
133
134         //Add velocity
135         for (i = 0; i < joints.size(); i++) {
136             joints[i].position = joints[i].position + joints[i].velocity * multiplier;
137
138             switch (joints[i].label) {
139                 case head:
140                     groundlevel = .8;
141                     break;
142                 case righthand:
143                 case rightwrist:
144                 case rightelbow:
145                 case lefthand:
146                 case leftwrist:
147                 case leftelbow:
148                     groundlevel = .2;
149                     break;
150                 default:
151                     groundlevel = .15;
152                     break;
153             }
154
155             joints[i].position.y -= groundlevel;
156             joints[i].oldvelocity = joints[i].velocity;
157         }
158
159         float tempmult = multiplier;
160         //multiplier/=numrepeats;
161
162         for (int j = 0; j < numrepeats; j++) {
163             float r = .05;
164             // right leg constraints?
165             if (!joint(rightknee).locked && !joint(righthip).locked) {
166                 temp = jointPos(rightknee) - (jointPos(righthip) + jointPos(rightankle)) / 2;
167                 while (normaldotproduct(temp, lowforward) > -.1 && !sphere_line_intersection(&jointPos(righthip), &jointPos(rightankle), &jointPos(rightknee), &r)) {
168                     jointPos(rightknee) -= lowforward * .05;
169                     if (spinny)
170                         jointVel(rightknee) -= lowforward * .05 / multiplier / 4;
171                     else
172                         jointVel(rightknee) -= lowforward * .05;
173                     jointPos(rightankle) += lowforward * .025;
174                     if (spinny)
175                         jointVel(rightankle) += lowforward * .025 / multiplier / 4;
176                     else
177                         jointVel(rightankle) += lowforward * .25;
178                     jointPos(righthip) += lowforward * .025;
179                     if (spinny)
180                         jointVel(righthip) += lowforward * .025 / multiplier / 4;
181                     else
182                         jointVel(righthip) += lowforward * .025;
183                     temp = jointPos(rightknee) - (jointPos(righthip) + jointPos(rightankle)) / 2;
184                 }
185             }
186
187             // left leg constraints?
188             if (!joint(leftknee).locked && !joint(lefthip).locked) {
189                 temp = jointPos(leftknee) - (jointPos(lefthip) + jointPos(leftankle)) / 2;
190                 while (normaldotproduct(temp, lowforward) > -.1 && !sphere_line_intersection(&jointPos(lefthip), &jointPos(leftankle), &jointPos(leftknee), &r)) {
191                     jointPos(leftknee) -= lowforward * .05;
192                     if (spinny)
193                         jointVel(leftknee) -= lowforward * .05 / multiplier / 4;
194                     else
195                         jointVel(leftknee) -= lowforward * .05;
196                     jointPos(leftankle) += lowforward * .025;
197                     if (spinny)
198                         jointVel(leftankle) += lowforward * .025 / multiplier / 4;
199                     else
200                         jointVel(leftankle) += lowforward * .25;
201                     jointPos(lefthip) += lowforward * .025;
202                     if (spinny)
203                         jointVel(lefthip) += lowforward * .025 / multiplier / 4;
204                     else
205                         jointVel(lefthip) += lowforward * .025;
206                     temp = jointPos(leftknee) - (jointPos(lefthip) + jointPos(leftankle)) / 2;
207                 }
208             }
209
210             for (i = 0; i < joints.size(); i++) {
211                 if (joints[i].locked && !spinny && findLengthfast(&joints[i].velocity) > 320)
212                     joints[i].locked = 0;
213                 if (spinny && findLengthfast(&joints[i].velocity) > 600)
214                     joints[i].locked = 0;
215                 if (joints[i].delay > 0) {
216                     bool freely = true;
217                     for (unsigned j = 0; j < joints.size(); j++) {
218                         if (joints[j].locked)
219                             freely = false;
220                     }
221                     if (freely)
222                         joints[i].delay -= multiplier * 3;
223                 }
224             }
225
226             for (i = 0; i < muscles.size(); i++) {
227                 //Length constraints
228                 muscles[i].DoConstraint(spinny);
229             }
230
231             float friction;
232             for (i = 0; i < joints.size(); i++) {
233                 //Length constraints
234                 //Ground constraint
235                 groundlevel = 0;
236                 if (joints[i].position.y * (*scale) + coords->y < terrain.getHeight(joints[i].position.x * (*scale) + coords->x, joints[i].position.z * (*scale) + coords->z) + groundlevel) {
237                     freefall = 0;
238                     friction = 1.5;
239                     if (joints[i].label == groin && !joints[i].locked && joints[i].delay <= 0) {
240                         joints[i].locked = 1;
241                         joints[i].delay = 1;
242                         if (!Tutorial::active || id == 0) {
243                             emit_sound_at(landsound1, joints[i].position * (*scale) + *coords, 128.);
244                         }
245                         breaking = true;
246                     }
247
248                     if (joints[i].label == head && !joints[i].locked && joints[i].delay <= 0) {
249                         joints[i].locked = 1;
250                         joints[i].delay = 1;
251                         if (!Tutorial::active || id == 0) {
252                             emit_sound_at(landsound2, joints[i].position * (*scale) + *coords, 128.);
253                         }
254                     }
255
256                     terrainnormal = terrain.getNormal(joints[i].position.x * (*scale) + coords->x, joints[i].position.z * (*scale) + coords->z);
257                     ReflectVector(&joints[i].velocity, &terrainnormal);
258                     bounceness = terrainnormal * findLength(&joints[i].velocity) * (abs(normaldotproduct(joints[i].velocity, terrainnormal)));
259                     if (!joints[i].locked)
260                         damage += findLengthfast(&bounceness) / 4000;
261                     if (findLengthfast(&joints[i].velocity) < findLengthfast(&bounceness))
262                         bounceness = 0;
263                     frictionness = abs(normaldotproduct(joints[i].velocity, terrainnormal));
264                     joints[i].velocity -= bounceness;
265                     if (1 - friction * frictionness > 0)
266                         joints[i].velocity *= 1 - friction * frictionness;
267                     else
268                         joints[i].velocity = 0;
269
270                     if (!Tutorial::active || id == 0)
271                         if (findLengthfast(&bounceness) > 8000 && breaking) {
272                             // FIXME: this crashes because k is not initialized!
273                             // to reproduce, type 'wolfie' in console and play a while
274                             // I'll just comment it out for now
275                             //Object::objects[k]->model.MakeDecal(breakdecal, DoRotation(temp - Object::objects[k]->position, 0, -Object::objects[k]->yaw, 0), .4, .5, Random() % 360);
276                             Sprite::MakeSprite(cloudsprite, joints[i].position * (*scale) + *coords, joints[i].velocity * .06, 1, 1, 1, 4, .2);
277                             breaking = false;
278                             camerashake += .6;
279
280                             emit_sound_at(breaksound2, joints[i].position * (*scale) + *coords);
281
282                             addEnvSound(*coords, 64);
283                         }
284
285                     if (findLengthfast(&bounceness) > 2500) {
286                         Normalise(&bounceness);
287                         bounceness = bounceness * 50;
288                     }
289
290                     joints[i].velocity += bounceness * elasticity;
291
292                     if (findLengthfast(&joints[i].velocity) > findLengthfast(&joints[i].oldvelocity)) {
293                         bounceness = 0;
294                         joints[i].velocity = joints[i].oldvelocity;
295                     }
296
297                     if (joints[i].locked == 0)
298                         if (findLengthfast(&joints[i].velocity) < 1)
299                             joints[i].locked = 1;
300
301                     if (environment == snowyenvironment && findLengthfast(&bounceness) > 500 && terrain.getOpacity(joints[i].position.x * (*scale) + coords->x, joints[i].position.z * (*scale) + coords->z) < .2) {
302                         terrainlight = terrain.getLighting(joints[i].position.x * (*scale) + coords->x, joints[i].position.z * (*scale) + coords->z);
303                         Sprite::MakeSprite(cloudsprite, joints[i].position * (*scale) + *coords, joints[i].velocity * .06, terrainlight.x, terrainlight.y, terrainlight.z, .5, .7);
304                         if (detail == 2)
305                             terrain.MakeDecal(bodyprintdecal, joints[i].position * (*scale) + *coords, .4, .4, 0);
306                     } else if (environment == desertenvironment && findLengthfast(&bounceness) > 500 && terrain.getOpacity(joints[i].position.x * (*scale) + coords->x, joints[i].position.z * (*scale) + coords->z) < .2) {
307                         terrainlight = terrain.getLighting(joints[i].position.x * (*scale) + coords->x, joints[i].position.z * (*scale) + coords->z);
308                         Sprite::MakeSprite(cloudsprite, joints[i].position * (*scale) + *coords, joints[i].velocity * .06, terrainlight.x * 190 / 255, terrainlight.y * 170 / 255, terrainlight.z * 108 / 255, .5, .7);
309                     }
310
311                     else if (environment == grassyenvironment && findLengthfast(&bounceness) > 500 && terrain.getOpacity(joints[i].position.x * (*scale) + coords->x, joints[i].position.z * (*scale) + coords->z) < .2) {
312                         terrainlight = terrain.getLighting(joints[i].position.x * (*scale) + coords->x, joints[i].position.z * (*scale) + coords->z);
313                         Sprite::MakeSprite(cloudsprite, joints[i].position * (*scale) + *coords, joints[i].velocity * .06, terrainlight.x * 90 / 255, terrainlight.y * 70 / 255, terrainlight.z * 8 / 255, .5, .5);
314                     } else if (findLengthfast(&bounceness) > 500)
315                         Sprite::MakeSprite(cloudsprite, joints[i].position * (*scale) + *coords, joints[i].velocity * .06, terrainlight.x, terrainlight.y, terrainlight.z, .5, .2);
316
317                     joints[i].position.y = (terrain.getHeight(joints[i].position.x * (*scale) + coords->x, joints[i].position.z * (*scale) + coords->z) + groundlevel - coords->y) / (*scale);
318                     if (longdead > 100)
319                         broken = 1;
320                 }
321                 for (unsigned int m = 0; m < terrain.patchobjects[whichpatchx][whichpatchz].size(); m++) {
322                     unsigned int k = terrain.patchobjects[whichpatchx][whichpatchz][m];
323                     if (k < Object::objects.size()) {
324                         if (Object::objects[k]->possible) {
325                             friction = Object::objects[k]->friction;
326                             XYZ start = joints[i].realoldposition;
327                             XYZ end = joints[i].position * (*scale) + *coords;
328                             whichhit = Object::objects[k]->model.LineCheckPossible(&start, &end, &temp, &Object::objects[k]->position, &Object::objects[k]->yaw);
329                             if (whichhit != -1) {
330                                 if (joints[i].label == groin && !joints[i].locked && joints[i].delay <= 0) {
331                                     joints[i].locked = 1;
332                                     joints[i].delay = 1;
333                                     if (!Tutorial::active || id == 0) {
334                                         emit_sound_at(landsound1, joints[i].position * (*scale) + *coords, 128.);
335                                     }
336                                     breaking = true;
337                                 }
338
339                                 if (joints[i].label == head && !joints[i].locked && joints[i].delay <= 0) {
340                                     joints[i].locked = 1;
341                                     joints[i].delay = 1;
342                                     if (!Tutorial::active || id == 0) {
343                                         emit_sound_at(landsound2, joints[i].position * (*scale) + *coords, 128.);
344                                     }
345                                 }
346
347                                 terrainnormal = DoRotation(Object::objects[k]->model.Triangles[whichhit].facenormal, 0, Object::objects[k]->yaw, 0) * -1;
348                                 if (terrainnormal.y > .8)
349                                     freefall = 0;
350                                 bounceness = terrainnormal * findLength(&joints[i].velocity) * (abs(normaldotproduct(joints[i].velocity, terrainnormal)));
351                                 if (findLengthfast(&joints[i].velocity) > findLengthfast(&joints[i].oldvelocity)) {
352                                     bounceness = 0;
353                                     joints[i].velocity = joints[i].oldvelocity;
354                                 }
355                                 if (!Tutorial::active || id == 0)
356                                     if (findLengthfast(&bounceness) > 4000 && breaking) {
357                                         Object::objects[k]->model.MakeDecal(breakdecal, DoRotation(temp - Object::objects[k]->position, 0, -Object::objects[k]->yaw, 0), .4, .5, Random() % 360);
358                                         Sprite::MakeSprite(cloudsprite, joints[i].position * (*scale) + *coords, joints[i].velocity * .06, 1, 1, 1, 4, .2);
359                                         breaking = false;
360                                         camerashake += .6;
361
362                                         emit_sound_at(breaksound2, joints[i].position * (*scale) + *coords);
363
364                                         addEnvSound(*coords, 64);
365                                     }
366                                 if (Object::objects[k]->type == treetrunktype) {
367                                     Object::objects[k]->rotx += joints[i].velocity.x * multiplier * .4;
368                                     Object::objects[k]->roty += joints[i].velocity.z * multiplier * .4;
369                                     Object::objects[k + 1]->rotx += joints[i].velocity.x * multiplier * .4;
370                                     Object::objects[k + 1]->roty += joints[i].velocity.z * multiplier * .4;
371                                 }
372                                 if (!joints[i].locked)
373                                     damage += findLengthfast(&bounceness) / 2500;
374                                 ReflectVector(&joints[i].velocity, &terrainnormal);
375                                 frictionness = abs(normaldotproduct(joints[i].velocity, terrainnormal));
376                                 joints[i].velocity -= bounceness;
377                                 if (1 - friction * frictionness > 0)
378                                     joints[i].velocity *= 1 - friction * frictionness;
379                                 else
380                                     joints[i].velocity = 0;
381                                 if (findLengthfast(&bounceness) > 2500) {
382                                     Normalise(&bounceness);
383                                     bounceness = bounceness * 50;
384                                 }
385                                 joints[i].velocity += bounceness * elasticity;
386
387                                 if (!joints[i].locked)
388                                     if (findLengthfast(&joints[i].velocity) < 1) {
389                                         joints[i].locked = 1;
390                                     }
391                                 if (findLengthfast(&bounceness) > 500)
392                                     Sprite::MakeSprite(cloudsprite, joints[i].position * (*scale) + *coords, joints[i].velocity * .06, 1, 1, 1, .5, .2);
393                                 joints[i].position = (temp - *coords) / (*scale) + terrainnormal * .005;
394                                 if (longdead > 100)
395                                     broken = 1;
396                             }
397                         }
398                     }
399                 }
400                 joints[i].realoldposition = joints[i].position * (*scale) + *coords;
401             }
402         }
403         multiplier = tempmult;
404
405         for (unsigned int m = 0; m < terrain.patchobjects[whichpatchx][whichpatchz].size(); m++) {
406             unsigned int k = terrain.patchobjects[whichpatchx][whichpatchz][m];
407             if (Object::objects[k]->possible) {
408                 for (i = 0; i < 26; i++) {
409                     //Make this less stupid
410                     XYZ start = joints[jointlabels[whichjointstartarray[i]]].position * (*scale) + *coords;
411                     XYZ end = joints[jointlabels[whichjointendarray[i]]].position * (*scale) + *coords;
412                     whichhit = Object::objects[k]->model.LineCheckSlidePossible(&start, &end, &Object::objects[k]->position, &Object::objects[k]->yaw);
413                     if (whichhit != -1) {
414                         joints[jointlabels[whichjointendarray[i]]].position = (end - *coords) / (*scale);
415                         for (unsigned j = 0; j < muscles.size(); j++) {
416                             if ((muscles[j].parent1->label == whichjointstartarray[i] && muscles[j].parent2->label == whichjointendarray[i]) || (muscles[j].parent2->label == whichjointstartarray[i] && muscles[j].parent1->label == whichjointendarray[i]))
417                                 muscles[j].DoConstraint(spinny);
418                         }
419                     }
420                 }
421             }
422         }
423
424         for (i = 0; i < joints.size(); i++) {
425             switch (joints[i].label) {
426                 case head:
427                     groundlevel = .8;
428                     break;
429                 case righthand:
430                 case rightwrist:
431                 case rightelbow:
432                 case lefthand:
433                 case leftwrist:
434                 case leftelbow:
435                     groundlevel = .2;
436                     break;
437                 default:
438                     groundlevel = .15;
439                     break;
440             }
441             joints[i].position.y += groundlevel;
442             joints[i].mass = 1;
443             if (joints[i].label == lefthip || joints[i].label == leftknee || joints[i].label == leftankle || joints[i].label == righthip || joints[i].label == rightknee || joints[i].label == rightankle)
444                 joints[i].mass = 2;
445             if (joints[i].locked) {
446                 joints[i].mass = 4;
447             }
448         }
449
450         return damage;
451     }
452
453     if (!free) {
454         for (i = 0; i < muscles.size(); i++) {
455             if (muscles[i].type == boneconnect)
456                 muscles[i].DoConstraint(0);
457         }
458     }
459
460     return 0;
461 }
462
463 /* EFFECT
464  * applies gravity to the skeleton
465  *
466  * USES:
467  * Person/Person::DoStuff
468  */
469 void Skeleton::DoGravity(float* scale)
470 {
471     for (unsigned i = 0; i < joints.size(); i++) {
472         if (
473             (
474                 ((joints[i].label != leftknee) && (joints[i].label != rightknee)) ||
475                 (lowforward.y > -.1) ||
476                 (joints[i].mass < 5)) &&
477             (((joints[i].label != leftelbow) && (joints[i].label != rightelbow)) ||
478              (forward.y < .3))) {
479             joints[i].velocity.y += gravity * multiplier / (*scale);
480         }
481     }
482 }
483
484 /* EFFECT
485  * set muscles[which].rotate1
486  *     .rotate2
487  *     .rotate3
488  *
489  * special case if animation == hanganim
490  */
491 void Skeleton::FindRotationMuscle(int which, int animation)
492 {
493     XYZ p1, p2, fwd;
494     float dist;
495
496     p1 = muscles[which].parent1->position;
497     p2 = muscles[which].parent2->position;
498     dist = findDistance(&p1, &p2);
499     if (p1.y - p2.y <= dist)
500         muscles[which].rotate2 = asin((p1.y - p2.y) / dist);
501     if (p1.y - p2.y > dist)
502         muscles[which].rotate2 = asin(1.f);
503     muscles[which].rotate2 *= 360.0 / 6.2831853;
504
505     p1.y = 0;
506     p2.y = 0;
507     dist = findDistance(&p1, &p2);
508     if (p1.z - p2.z <= dist)
509         muscles[which].rotate1 = acos((p1.z - p2.z) / dist);
510     if (p1.z - p2.z > dist)
511         muscles[which].rotate1 = acos(1.f);
512     muscles[which].rotate1 *= 360.0 / 6.2831853;
513     if (p1.x > p2.x)
514         muscles[which].rotate1 = 360 - muscles[which].rotate1;
515     if (!isnormal(muscles[which].rotate1))
516         muscles[which].rotate1 = 0;
517     if (!isnormal(muscles[which].rotate2))
518         muscles[which].rotate2 = 0;
519
520     const int label1 = muscles[which].parent1->label;
521     const int label2 = muscles[which].parent2->label;
522     switch (label1) {
523         case head:
524             fwd = specialforward[0];
525             break;
526         case rightshoulder:
527         case rightelbow:
528         case rightwrist:
529         case righthand:
530             fwd = specialforward[1];
531             break;
532         case leftshoulder:
533         case leftelbow:
534         case leftwrist:
535         case lefthand:
536             fwd = specialforward[2];
537             break;
538         case righthip:
539         case rightknee:
540         case rightankle:
541         case rightfoot:
542             fwd = specialforward[3];
543             break;
544         case lefthip:
545         case leftknee:
546         case leftankle:
547         case leftfoot:
548             fwd = specialforward[4];
549             break;
550         default:
551             if (muscles[which].parent1->lower)
552                 fwd = lowforward;
553             else
554                 fwd = forward;
555             break;
556     }
557
558     if (animation == hanganim) {
559         if (label1 == righthand || label2 == righthand) {
560             fwd = 0;
561             fwd.x = -1;
562         }
563         if (label1 == lefthand || label2 == lefthand) {
564             fwd = 0;
565             fwd.x = 1;
566         }
567     }
568
569     if (free == 0) {
570         if (label1 == rightfoot || label2 == rightfoot) {
571             fwd.y -= .3;
572         }
573         if (label1 == leftfoot || label2 == leftfoot) {
574             fwd.y -= .3;
575         }
576     }
577
578     fwd = DoRotation(fwd, 0, muscles[which].rotate1 - 90, 0);
579     fwd = DoRotation(fwd, 0, 0, muscles[which].rotate2 - 90);
580     fwd.y = 0;
581     fwd /= findLength(&fwd);
582     if (fwd.z <= 1 && fwd.z >= -1)
583         muscles[which].rotate3 = acos(0 - fwd.z);
584     else
585         muscles[which].rotate3 = acos(-1.f);
586     muscles[which].rotate3 *= 360.0 / 6.2831853;
587     if (0 > fwd.x)
588         muscles[which].rotate3 = 360 - muscles[which].rotate3;
589     if (!isnormal(muscles[which].rotate3))
590         muscles[which].rotate3 = 0;
591 }
592
593 /* EFFECT
594  * load skeleton
595  * takes filenames for three skeleton files and various models
596  */
597 void Skeleton::Load(const std::string& filename, const std::string& lowfilename, const std::string& clothesfilename,
598                     const std::string& modelfilename, const std::string& model2filename,
599                     const std::string& model3filename, const std::string& model4filename,
600                     const std::string& model5filename, const std::string& model6filename,
601                     const std::string& model7filename, const std::string& modellowfilename,
602                     const std::string& modelclothesfilename, bool clothes)
603 {
604     GLfloat M[16];
605     FILE* tfile;
606     float lSize;
607     int j, num_joints, num_muscles;
608
609     LOGFUNC;
610
611     num_models = 7;
612
613     // load various models
614     // rotate, scale, do normals, do texcoords for each as needed
615
616     model[0].loadnotex(modelfilename);
617     model[1].loadnotex(model2filename);
618     model[2].loadnotex(model3filename);
619     model[3].loadnotex(model4filename);
620     model[4].loadnotex(model5filename);
621     model[5].loadnotex(model6filename);
622     model[6].loadnotex(model7filename);
623
624     for (int i = 0; i < num_models; i++) {
625         model[i].Rotate(180, 0, 0);
626         model[i].Scale(.04, .04, .04);
627         model[i].CalculateNormals(0);
628     }
629
630     drawmodel.load(modelfilename);
631     drawmodel.Rotate(180, 0, 0);
632     drawmodel.Scale(.04, .04, .04);
633     drawmodel.FlipTexCoords();
634     if ((Tutorial::active) && (id != 0)) {
635         drawmodel.UniformTexCoords();
636         drawmodel.ScaleTexCoords(0.1);
637     }
638     drawmodel.CalculateNormals(0);
639
640     modellow.loadnotex(modellowfilename);
641     modellow.Rotate(180, 0, 0);
642     modellow.Scale(.04, .04, .04);
643     modellow.CalculateNormals(0);
644
645     drawmodellow.load(modellowfilename);
646     drawmodellow.Rotate(180, 0, 0);
647     drawmodellow.Scale(.04, .04, .04);
648     drawmodellow.FlipTexCoords();
649     if (Tutorial::active && id != 0)
650         drawmodellow.UniformTexCoords();
651     if (Tutorial::active && id != 0)
652         drawmodellow.ScaleTexCoords(0.1);
653     drawmodellow.CalculateNormals(0);
654
655     if (clothes) {
656         modelclothes.loadnotex(modelclothesfilename);
657         modelclothes.Rotate(180, 0, 0);
658         modelclothes.Scale(.041, .04, .041);
659         modelclothes.CalculateNormals(0);
660
661         drawmodelclothes.load(modelclothesfilename);
662         drawmodelclothes.Rotate(180, 0, 0);
663         drawmodelclothes.Scale(.04, .04, .04);
664         drawmodelclothes.FlipTexCoords();
665         drawmodelclothes.CalculateNormals(0);
666     }
667
668     // FIXME: three similar blocks follow, one for each of:
669     // filename, lowfilename, clothesfilename
670
671     // load skeleton
672
673     tfile = Folders::openMandatoryFile(Folders::getResourcePath(filename), "rb");
674
675     // read num_joints
676     funpackf(tfile, "Bi", &num_joints);
677
678     joints.resize(num_joints);
679
680     // read info for each joint
681     for (int i = 0; i < num_joints; i++) {
682         joints[i].load(tfile, joints);
683     }
684
685     // read num_muscles
686     funpackf(tfile, "Bi", &num_muscles);
687
688     // allocate memory
689     muscles.resize(num_muscles);
690
691     // for each muscle...
692     for (int i = 0; i < num_muscles; i++) {
693         muscles[i].load(tfile, model[0].vertexNum, joints);
694     }
695
696     // read forwardjoints (?)
697     for (j = 0; j < 3; j++) {
698         funpackf(tfile, "Bi", &forwardjoints[j]);
699     }
700     // read lowforwardjoints (?)
701     for (j = 0; j < 3; j++) {
702         funpackf(tfile, "Bi", &lowforwardjoints[j]);
703     }
704
705     // ???
706     for (j = 0; j < num_muscles; j++) {
707         for (unsigned i = 0; i < muscles[j].vertices.size(); i++) {
708             for (int k = 0; k < num_models; k++) {
709                 if (muscles[j].vertices[i] < model[k].vertexNum) {
710                     model[k].owner[muscles[j].vertices[i]] = j;
711                 }
712             }
713         }
714     }
715
716     // calculate some stuff
717     FindForwards();
718     for (int i = 0; i < num_muscles; i++) {
719         FindRotationMuscle(i, -1);
720     }
721     // this seems to use opengl purely for matrix calculations
722     for (int k = 0; k < num_models; k++) {
723         for (int i = 0; i < model[k].vertexNum; i++) {
724             model[k].vertex[i] = model[k].vertex[i] - (muscles[model[k].owner[i]].parent1->position + muscles[model[k].owner[i]].parent2->position) / 2;
725             glMatrixMode(GL_MODELVIEW);
726             glPushMatrix();
727             glLoadIdentity();
728             glRotatef(muscles[model[k].owner[i]].rotate3, 0, 1, 0);
729             glRotatef(muscles[model[k].owner[i]].rotate2 - 90, 0, 0, 1);
730             glRotatef(muscles[model[k].owner[i]].rotate1 - 90, 0, 1, 0);
731             glTranslatef(model[k].vertex[i].x, model[k].vertex[i].y, model[k].vertex[i].z);
732             glGetFloatv(GL_MODELVIEW_MATRIX, M);
733             model[k].vertex[i].x = M[12] * 1;
734             model[k].vertex[i].y = M[13] * 1;
735             model[k].vertex[i].z = M[14] * 1;
736             glPopMatrix();
737         }
738         model[k].CalculateNormals(0);
739     }
740     fclose(tfile);
741
742     // load ???
743
744     tfile = Folders::openMandatoryFile(Folders::getResourcePath(lowfilename), "rb");
745
746     // skip joints section
747
748     fseek(tfile, sizeof(num_joints), SEEK_CUR);
749     for (int i = 0; i < num_joints; i++) {
750         // skip joint info
751         lSize = sizeof(XYZ) + sizeof(float) + sizeof(float) + 1 //sizeof(bool)
752                 + 1                                             //sizeof(bool)
753                 + sizeof(int) + 1                               //sizeof(bool)
754                 + 1                                             //sizeof(bool)
755                 + sizeof(int) + sizeof(int) + 1                 //sizeof(bool)
756                 + sizeof(int);
757         fseek(tfile, lSize, SEEK_CUR);
758     }
759
760     // skip num_muscles
761     fseek(tfile, sizeof(num_muscles), SEEK_CUR);
762
763     for (int i = 0; i < num_muscles; i++) {
764         // skip muscle info
765         lSize = sizeof(float) + sizeof(float) + sizeof(float) + sizeof(float) + sizeof(float) + sizeof(int);
766         fseek(tfile, lSize, SEEK_CUR);
767
768         muscles[i].loadVerticesLow(tfile, modellow.vertexNum);
769
770         // skip more stuff
771         lSize = 1; //sizeof(bool);
772         fseek(tfile, lSize, SEEK_CUR);
773         lSize = sizeof(int);
774         fseek(tfile, lSize, SEEK_CUR);
775         fseek(tfile, lSize, SEEK_CUR);
776     }
777
778     for (j = 0; j < num_muscles; j++) {
779         for (unsigned i = 0; i < muscles[j].verticeslow.size(); i++) {
780             if (muscles[j].verticeslow[i] < modellow.vertexNum) {
781                 modellow.owner[muscles[j].verticeslow[i]] = j;
782             }
783         }
784     }
785
786     // use opengl for its matrix math
787     for (int i = 0; i < modellow.vertexNum; i++) {
788         modellow.vertex[i] = modellow.vertex[i] - (muscles[modellow.owner[i]].parent1->position + muscles[modellow.owner[i]].parent2->position) / 2;
789         glMatrixMode(GL_MODELVIEW);
790         glPushMatrix();
791         glLoadIdentity();
792         glRotatef(muscles[modellow.owner[i]].rotate3, 0, 1, 0);
793         glRotatef(muscles[modellow.owner[i]].rotate2 - 90, 0, 0, 1);
794         glRotatef(muscles[modellow.owner[i]].rotate1 - 90, 0, 1, 0);
795         glTranslatef(modellow.vertex[i].x, modellow.vertex[i].y, modellow.vertex[i].z);
796         glGetFloatv(GL_MODELVIEW_MATRIX, M);
797         modellow.vertex[i].x = M[12];
798         modellow.vertex[i].y = M[13];
799         modellow.vertex[i].z = M[14];
800         glPopMatrix();
801     }
802
803     modellow.CalculateNormals(0);
804
805     // load clothes
806
807     if (clothes) {
808         tfile = Folders::openMandatoryFile(Folders::getResourcePath(clothesfilename), "rb");
809
810         // skip num_joints
811         fseek(tfile, sizeof(num_joints), SEEK_CUR);
812
813         for (int i = 0; i < num_joints; i++) {
814             // skip joint info
815             lSize = sizeof(XYZ) + sizeof(float) + sizeof(float) + 1 //sizeof(bool)
816                     + 1                                             //sizeof(bool)
817                     + sizeof(int) + 1                               //sizeof(bool)
818                     + 1                                             //sizeof(bool)
819                     + sizeof(int) + sizeof(int) + 1                 //sizeof(bool)
820                     + sizeof(int);
821             fseek(tfile, lSize, SEEK_CUR);
822         }
823
824         // skip num_muscles
825         fseek(tfile, sizeof(num_muscles), SEEK_CUR);
826
827         for (int i = 0; i < num_muscles; i++) {
828             // skip muscle info
829             lSize = sizeof(float) + sizeof(float) + sizeof(float) + sizeof(float) + sizeof(float) + sizeof(int);
830             fseek(tfile, lSize, SEEK_CUR);
831
832             muscles[i].loadVerticesClothes(tfile, modelclothes.vertexNum);
833
834             // skip more stuff
835             lSize = 1; //sizeof(bool);
836             fseek(tfile, lSize, SEEK_CUR);
837             lSize = sizeof(int);
838             fseek(tfile, lSize, SEEK_CUR);
839             fseek(tfile, lSize, SEEK_CUR);
840         }
841
842         // ???
843         lSize = sizeof(int);
844         for (j = 0; j < num_muscles; j++) {
845             for (unsigned i = 0; i < muscles[j].verticesclothes.size(); i++) {
846                 if (muscles[j].verticesclothes.size() && muscles[j].verticesclothes[i] < modelclothes.vertexNum) {
847                     modelclothes.owner[muscles[j].verticesclothes[i]] = j;
848                 }
849             }
850         }
851
852         // use opengl for its matrix math
853         for (int i = 0; i < modelclothes.vertexNum; i++) {
854             modelclothes.vertex[i] = modelclothes.vertex[i] - (muscles[modelclothes.owner[i]].parent1->position + muscles[modelclothes.owner[i]].parent2->position) / 2;
855             glMatrixMode(GL_MODELVIEW);
856             glPushMatrix();
857             glLoadIdentity();
858             glRotatef(muscles[modelclothes.owner[i]].rotate3, 0, 1, 0);
859             glRotatef(muscles[modelclothes.owner[i]].rotate2 - 90, 0, 0, 1);
860             glRotatef(muscles[modelclothes.owner[i]].rotate1 - 90, 0, 1, 0);
861             glTranslatef(modelclothes.vertex[i].x, modelclothes.vertex[i].y, modelclothes.vertex[i].z);
862             glGetFloatv(GL_MODELVIEW_MATRIX, M);
863             modelclothes.vertex[i].x = M[12];
864             modelclothes.vertex[i].y = M[13];
865             modelclothes.vertex[i].z = M[14];
866             glPopMatrix();
867         }
868
869         modelclothes.CalculateNormals(0);
870     }
871     fclose(tfile);
872
873     for (int i = 0; i < num_joints; i++) {
874         for (j = 0; j < num_joints; j++) {
875             if (joints[i].label == j)
876                 jointlabels[j] = i;
877         }
878     }
879
880     free = 0;
881 }