]> git.jsancho.org Git - lugaru.git/blob - Source/Animation/Skeleton.cpp
Got rid of malloc in Muscle
[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 /**> HEADER FILES <**/
22 #include "Game.h"
23 #include "Animation/Skeleton.h"
24 #include "openal_wrapper.h"
25 #include "Animation/Animation.h"
26 #include "Utils/Folders.h"
27
28 extern float multiplier;
29 extern float gravity;
30 extern Terrain terrain;
31 extern Objects objects;
32 extern int environment;
33 extern float camerashake;
34 extern bool freeze;
35 extern int detail;
36 extern int tutoriallevel;
37
38 extern int whichjointstartarray[26];
39 extern int whichjointendarray[26];
40
41 extern bool visibleloading;
42
43 Skeleton::Skeleton()
44 {
45     num_joints = 0;
46
47     num_muscles = 0;
48
49     selected = 0;
50
51     memset(forwardjoints, 0, sizeof(forwardjoints));
52
53     id = 0;
54
55     memset(lowforwardjoints, 0, sizeof(lowforwardjoints));
56
57     memset(jointlabels, 0, sizeof(jointlabels));
58
59     num_models = 0;
60
61     clothes = 0;
62     spinny = 0;
63
64     memset(skinText, 0, sizeof(skinText));
65     skinsize = 0;
66
67     checkdelay = 0;
68
69     longdead = 0;
70     broken = 0;
71
72     free = 0;
73     oldfree = 0;
74     freetime = 0;
75     freefall = 0;
76
77     joints = 0;
78     muscles = 0;
79 }
80
81 Skeleton::~Skeleton()
82 {
83     if (muscles) {
84         delete [] muscles;
85     }
86     muscles = 0;
87
88     if (joints) {
89         delete [] joints;
90     }
91     joints = 0;
92 }
93
94 /* EFFECT
95  * sets forward, lowforward, specialforward[]
96  *
97  * USES:
98  * Skeleton::Load
99  * Person/Person::DoAnimations
100  * Person/Person::DrawSkeleton
101  */
102 void Skeleton::FindForwards()
103 {
104     //Find forward vectors
105     CrossProduct(joints[forwardjoints[1]].position - joints[forwardjoints[0]].position, joints[forwardjoints[2]].position - joints[forwardjoints[0]].position, &forward);
106     Normalise(&forward);
107
108     CrossProduct(joints[lowforwardjoints[1]].position - joints[lowforwardjoints[0]].position, joints[lowforwardjoints[2]].position - joints[lowforwardjoints[0]].position, &lowforward);
109     Normalise(&lowforward);
110
111     //Special forwards
112     specialforward[0] = forward;
113
114     specialforward[1] = jointPos(rightshoulder) + jointPos(rightwrist);
115     specialforward[1] = jointPos(rightelbow) - specialforward[1] / 2;
116     specialforward[1] += forward * .4;
117     Normalise(&specialforward[1]);
118     specialforward[2] = jointPos(leftshoulder) + jointPos(leftwrist);
119     specialforward[2] = jointPos(leftelbow) - specialforward[2] / 2;
120     specialforward[2] += forward * .4;
121     Normalise(&specialforward[2]);
122
123     specialforward[3] = jointPos(righthip) + jointPos(rightankle);
124     specialforward[3] = specialforward[3] / 2 - jointPos(rightknee);
125     specialforward[3] += lowforward * .4;
126     Normalise(&specialforward[3]);
127     specialforward[4] = jointPos(lefthip) + jointPos(leftankle);
128     specialforward[4] = specialforward[4] / 2 - jointPos(leftknee);
129     specialforward[4] += lowforward * .4;
130     Normalise(&specialforward[4]);
131 }
132
133 /* EFFECT
134  * TODO
135  *
136  * USES:
137  * Person/Person::RagDoll
138  * Person/Person::DoStuff
139  * Person/IKHelper
140  */
141 float Skeleton::DoConstraints(XYZ *coords, float *scale)
142 {
143     float friction = 1.5;
144     const float elasticity = .3;
145     XYZ bounceness;
146     const int numrepeats = 3;
147     float groundlevel = .15;
148     int i, j, k, m;
149     XYZ temp;
150     XYZ terrainnormal;
151     int whichhit;
152     float frictionness;
153     XYZ terrainlight;
154     int whichpatchx;
155     int whichpatchz;
156     float damage = 0; // eventually returned from function
157     bool breaking = false;
158
159     if (free) {
160         freetime += multiplier;
161
162         whichpatchx = coords->x / (terrain.size / subdivision * terrain.scale);
163         whichpatchz = coords->z / (terrain.size / subdivision * terrain.scale);
164
165         terrainlight = *coords;
166         objects.SphereCheckPossible(&terrainlight, 1);
167
168         //Add velocity
169         for (i = 0; i < num_joints; i++) {
170             joints[i].position = joints[i].position + joints[i].velocity * multiplier;
171
172             switch (joints[i].label) {
173             case head:
174                 groundlevel = .8;
175                 break;
176             case righthand:
177             case rightwrist:
178             case rightelbow:
179             case lefthand:
180             case leftwrist:
181             case leftelbow:
182                 groundlevel = .2;
183                 break;
184             default:
185                 groundlevel = .15;
186                 break;
187             }
188
189             joints[i].position.y -= groundlevel;
190             joints[i].oldvelocity = joints[i].velocity;
191         }
192
193         float tempmult = multiplier;
194         //multiplier/=numrepeats;
195
196         for (j = 0; j < numrepeats; j++) {
197             float r = .05;
198             // right leg constraints?
199             if (!joint(rightknee).locked && !joint(righthip).locked) {
200                 temp = jointPos(rightknee) - (jointPos(righthip) + jointPos(rightankle)) / 2;
201                 while (normaldotproduct(temp, lowforward) > -.1 && !sphere_line_intersection(&jointPos(righthip), &jointPos(rightankle), &jointPos(rightknee), &r)) {
202                     jointPos(rightknee) -= lowforward * .05;
203                     if (spinny)
204                         jointVel(rightknee) -= lowforward * .05 / multiplier / 4;
205                     else
206                         jointVel(rightknee) -= lowforward * .05;
207                     jointPos(rightankle) += lowforward * .025;
208                     if (spinny)
209                         jointVel(rightankle) += lowforward * .025 / multiplier / 4;
210                     else
211                         jointVel(rightankle) += lowforward * .25;
212                     jointPos(righthip) += lowforward * .025;
213                     if (spinny)
214                         jointVel(righthip) += lowforward * .025 / multiplier / 4;
215                     else
216                         jointVel(righthip) += lowforward * .025;
217                     temp = jointPos(rightknee) - (jointPos(righthip) + jointPos(rightankle)) / 2;
218                 }
219             }
220
221             // left leg constraints?
222             if (!joint(leftknee).locked && !joint(lefthip).locked) {
223                 temp = jointPos(leftknee) - (jointPos(lefthip) + jointPos(leftankle)) / 2;
224                 while (normaldotproduct(temp, lowforward) > -.1 && !sphere_line_intersection(&jointPos(lefthip), &jointPos(leftankle), &jointPos(leftknee), &r)) {
225                     jointPos(leftknee) -= lowforward * .05;
226                     if (spinny)
227                         jointVel(leftknee) -= lowforward * .05 / multiplier / 4;
228                     else
229                         jointVel(leftknee) -= lowforward * .05;
230                     jointPos(leftankle) += lowforward * .025;
231                     if (spinny)
232                         jointVel(leftankle) += lowforward * .025 / multiplier / 4;
233                     else
234                         jointVel(leftankle) += lowforward * .25;
235                     jointPos(lefthip) += lowforward * .025;
236                     if (spinny)
237                         jointVel(lefthip) += lowforward * .025 / multiplier / 4;
238                     else
239                         jointVel(lefthip) += lowforward * .025;
240                     temp = jointPos(leftknee) - (jointPos(lefthip) + jointPos(leftankle)) / 2;
241                 }
242             }
243
244             for (i = 0; i < num_joints; i++) {
245                 if (joints[i].locked && !spinny && findLengthfast(&joints[i].velocity) > 320)
246                     joints[i].locked = 0;
247                 if (spinny && findLengthfast(&joints[i].velocity) > 600)
248                     joints[i].locked = 0;
249                 if (joints[i].delay > 0) {
250                     bool freely = true;
251                     for (j = 0; j < num_joints; j++) {
252                         if (joints[j].locked)
253                             freely = false;
254                     }
255                     if (freely)
256                         joints[i].delay -= multiplier * 3;
257                 }
258             }
259
260             if (num_muscles)
261                 for (i = 0; i < num_muscles; i++) {
262                     //Length constraints
263                     muscles[i].DoConstraint(spinny);
264                 }
265
266             for (i = 0; i < num_joints; i++) {
267                 //Length constraints
268                 //Ground constraint
269                 groundlevel = 0;
270                 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) {
271                     freefall = 0;
272                     friction = 1.5;
273                     if (joints[i].label == groin && !joints[i].locked && joints[i].delay <= 0) {
274                         joints[i].locked = 1;
275                         joints[i].delay = 1;
276                         if (tutoriallevel != 1 || id == 0) {
277                             emit_sound_at(landsound1, joints[i].position * (*scale) + *coords, 128.);
278                         }
279                         breaking = true;
280                     }
281
282                     if (joints[i].label == head && !joints[i].locked && joints[i].delay <= 0) {
283                         joints[i].locked = 1;
284                         joints[i].delay = 1;
285                         if (tutoriallevel != 1 || id == 0) {
286                             emit_sound_at(landsound2, joints[i].position * (*scale) + *coords, 128.);
287                         }
288                     }
289
290                     terrainnormal = terrain.getNormal(joints[i].position.x * (*scale) + coords->x, joints[i].position.z * (*scale) + coords->z);
291                     ReflectVector(&joints[i].velocity, &terrainnormal);
292                     bounceness = terrainnormal * findLength(&joints[i].velocity) * (abs(normaldotproduct(joints[i].velocity, terrainnormal)));
293                     if (!joints[i].locked)
294                         damage += findLengthfast(&bounceness) / 4000;
295                     if (findLengthfast(&joints[i].velocity) < findLengthfast(&bounceness))
296                         bounceness = 0;
297                     frictionness = abs(normaldotproduct(joints[i].velocity, terrainnormal));
298                     joints[i].velocity -= bounceness;
299                     if (1 - friction * frictionness > 0)
300                         joints[i].velocity *= 1 - friction * frictionness;
301                     else
302                         joints[i].velocity = 0;
303
304                     if (tutoriallevel != 1 || id == 0)
305                         if (findLengthfast(&bounceness) > 8000 && breaking) {
306                             // FIXME: this crashes because k is not initialized!
307                             // to reproduce, type 'wolfie' in console and play a while
308                             // I'll just comment it out for now
309                             //objects.model[k].MakeDecal(breakdecal, DoRotation(temp - objects.position[k], 0, -objects.yaw[k], 0), .4, .5, Random() % 360);
310                             Sprite::MakeSprite(cloudsprite, joints[i].position * (*scale) + *coords, joints[i].velocity * .06, 1, 1, 1, 4, .2);
311                             breaking = false;
312                             camerashake += .6;
313
314                             emit_sound_at(breaksound2, joints[i].position * (*scale) + *coords);
315
316                             addEnvSound(*coords, 64);
317                         }
318
319                     if (findLengthfast(&bounceness) > 2500) {
320                         Normalise(&bounceness);
321                         bounceness = bounceness * 50;
322                     }
323
324                     joints[i].velocity += bounceness * elasticity;
325
326                     if (findLengthfast(&joints[i].velocity) > findLengthfast(&joints[i].oldvelocity)) {
327                         bounceness = 0;
328                         joints[i].velocity = joints[i].oldvelocity;
329                     }
330
331
332                     if (joints[i].locked == 0)
333                         if (findLengthfast(&joints[i].velocity) < 1)
334                             joints[i].locked = 1;
335
336                     if (environment == snowyenvironment && findLengthfast(&bounceness) > 500 && terrain.getOpacity(joints[i].position.x * (*scale) + coords->x, joints[i].position.z * (*scale) + coords->z) < .2) {
337                         terrainlight = terrain.getLighting(joints[i].position.x * (*scale) + coords->x, joints[i].position.z * (*scale) + coords->z);
338                         Sprite::MakeSprite(cloudsprite, joints[i].position * (*scale) + *coords, joints[i].velocity * .06, terrainlight.x, terrainlight.y, terrainlight.z, .5, .7);
339                         if (detail == 2)
340                             terrain.MakeDecal(bodyprintdecal, joints[i].position * (*scale) + *coords, .4, .4, 0);
341                     } else if (environment == desertenvironment && findLengthfast(&bounceness) > 500 && terrain.getOpacity(joints[i].position.x * (*scale) + coords->x, joints[i].position.z * (*scale) + coords->z) < .2) {
342                         terrainlight = terrain.getLighting(joints[i].position.x * (*scale) + coords->x, joints[i].position.z * (*scale) + coords->z);
343                         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);
344                     }
345
346                     else if (environment == grassyenvironment && findLengthfast(&bounceness) > 500 && terrain.getOpacity(joints[i].position.x * (*scale) + coords->x, joints[i].position.z * (*scale) + coords->z) < .2) {
347                         terrainlight = terrain.getLighting(joints[i].position.x * (*scale) + coords->x, joints[i].position.z * (*scale) + coords->z);
348                         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);
349                     } else if (findLengthfast(&bounceness) > 500)
350                         Sprite::MakeSprite(cloudsprite, joints[i].position * (*scale) + *coords, joints[i].velocity * .06, terrainlight.x, terrainlight.y, terrainlight.z, .5, .2);
351
352
353                     joints[i].position.y = (terrain.getHeight(joints[i].position.x * (*scale) + coords->x, joints[i].position.z * (*scale) + coords->z) + groundlevel - coords->y) / (*scale);
354                     if (longdead > 100)
355                         broken = 1;
356                 }
357                 if (terrain.patchobjectnum[whichpatchx][whichpatchz])
358                     for (m = 0; m < terrain.patchobjectnum[whichpatchx][whichpatchz]; m++) {
359                         k = terrain.patchobjects[whichpatchx][whichpatchz][m];
360                         if (k < objects.numobjects && k >= 0)
361                             if (objects.possible[k]) {
362                                 friction = objects.friction[k];
363                                 XYZ start = joints[i].realoldposition;
364                                 XYZ end = joints[i].position * (*scale) + *coords;
365                                 whichhit = objects.model[k].LineCheckPossible(&start, &end, &temp, &objects.position[k], &objects.yaw[k]);
366                                 if (whichhit != -1) {
367                                     if (joints[i].label == groin && !joints[i].locked && joints[i].delay <= 0) {
368                                         joints[i].locked = 1;
369                                         joints[i].delay = 1;
370                                         if (tutoriallevel != 1 || id == 0) {
371                                             emit_sound_at(landsound1, joints[i].position * (*scale) + *coords, 128.);
372                                         }
373                                         breaking = true;
374                                     }
375
376                                     if (joints[i].label == head && !joints[i].locked && joints[i].delay <= 0) {
377                                         joints[i].locked = 1;
378                                         joints[i].delay = 1;
379                                         if (tutoriallevel != 1 || id == 0) {
380                                             emit_sound_at(landsound2, joints[i].position * (*scale) + *coords, 128.);
381                                         }
382                                     }
383
384                                     terrainnormal = DoRotation(objects.model[k].facenormals[whichhit], 0, objects.yaw[k], 0) * -1;
385                                     if (terrainnormal.y > .8)
386                                         freefall = 0;
387                                     bounceness = terrainnormal * findLength(&joints[i].velocity) * (abs(normaldotproduct(joints[i].velocity, terrainnormal)));
388                                     if (findLengthfast(&joints[i].velocity) > findLengthfast(&joints[i].oldvelocity)) {
389                                         bounceness = 0;
390                                         joints[i].velocity = joints[i].oldvelocity;
391                                     }
392                                     if (tutoriallevel != 1 || id == 0)
393                                         if (findLengthfast(&bounceness) > 4000 && breaking) {
394                                             objects.model[k].MakeDecal(breakdecal, DoRotation(temp - objects.position[k], 0, -objects.yaw[k], 0), .4, .5, Random() % 360);
395                                             Sprite::MakeSprite(cloudsprite, joints[i].position * (*scale) + *coords, joints[i].velocity * .06, 1, 1, 1, 4, .2);
396                                             breaking = false;
397                                             camerashake += .6;
398
399                                             emit_sound_at(breaksound2, joints[i].position * (*scale) + *coords);
400
401                                             addEnvSound(*coords, 64);
402                                         }
403                                     if (objects.type[k] == treetrunktype) {
404                                         objects.rotx[k] += joints[i].velocity.x * multiplier * .4;
405                                         objects.roty[k] += joints[i].velocity.z * multiplier * .4;
406                                         objects.rotx[k + 1] += joints[i].velocity.x * multiplier * .4;
407                                         objects.roty[k + 1] += joints[i].velocity.z * multiplier * .4;
408                                     }
409                                     if (!joints[i].locked)
410                                         damage += findLengthfast(&bounceness) / 2500;
411                                     ReflectVector(&joints[i].velocity, &terrainnormal);
412                                     frictionness = abs(normaldotproduct(joints[i].velocity, terrainnormal));
413                                     joints[i].velocity -= bounceness;
414                                     if (1 - friction * frictionness > 0)
415                                         joints[i].velocity *= 1 - friction * frictionness;
416                                     else
417                                         joints[i].velocity = 0;
418                                     if (findLengthfast(&bounceness) > 2500) {
419                                         Normalise(&bounceness);
420                                         bounceness = bounceness * 50;
421                                     }
422                                     joints[i].velocity += bounceness * elasticity;
423
424
425                                     if (!joints[i].locked)
426                                         if (findLengthfast(&joints[i].velocity) < 1) {
427                                             joints[i].locked = 1;
428                                         }
429                                     if (findLengthfast(&bounceness) > 500)
430                                         Sprite::MakeSprite(cloudsprite, joints[i].position * (*scale) + *coords, joints[i].velocity * .06, 1, 1, 1, .5, .2);
431                                     joints[i].position = (temp - *coords) / (*scale) + terrainnormal * .005;
432                                     if (longdead > 100)
433                                         broken = 1;
434                                 }
435                             }
436                     }
437                 joints[i].realoldposition = joints[i].position * (*scale) + *coords;
438             }
439         }
440         multiplier = tempmult;
441
442
443         if (terrain.patchobjectnum[whichpatchx][whichpatchz])
444             for (m = 0; m < terrain.patchobjectnum[whichpatchx][whichpatchz]; m++) {
445                 k = terrain.patchobjects[whichpatchx][whichpatchz][m];
446                 if (objects.possible[k]) {
447                     for (i = 0; i < 26; i++) {
448                         //Make this less stupid
449                         XYZ start = joints[jointlabels[whichjointstartarray[i]]].position * (*scale) + *coords;
450                         XYZ end = joints[jointlabels[whichjointendarray[i]]].position * (*scale) + *coords;
451                         whichhit = objects.model[k].LineCheckSlidePossible(&start, &end, &temp, &objects.position[k], &objects.yaw[k]);
452                         if (whichhit != -1) {
453                             joints[jointlabels[whichjointendarray[i]]].position = (end - *coords) / (*scale);
454                             for (j = 0; j < num_muscles; j++) {
455                                 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]))
456                                     muscles[j].DoConstraint(spinny);
457                             }
458                         }
459                     }
460                 }
461             }
462
463         for (i = 0; i < num_joints; i++) {
464             switch (joints[i].label) {
465             case head:
466                 groundlevel = .8;
467                 break;
468             case righthand:
469             case rightwrist:
470             case rightelbow:
471             case lefthand:
472             case leftwrist:
473             case leftelbow:
474                 groundlevel = .2;
475                 break;
476             default:
477                 groundlevel = .15;
478                 break;
479             }
480             joints[i].position.y += groundlevel;
481             joints[i].mass = 1;
482             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)
483                 joints[i].mass = 2;
484             if (joints[i].locked) {
485                 joints[i].mass = 4;
486             }
487         }
488
489         return damage;
490     }
491
492     if (!free) {
493         for (i = 0; i < num_muscles; i++) {
494             if (muscles[i].type == boneconnect)
495                 muscles[i].DoConstraint(0);
496         }
497     }
498
499     return 0;
500 }
501
502 /* EFFECT
503  * applies gravity to the skeleton
504  *
505  * USES:
506  * Person/Person::DoStuff
507  */
508 void Skeleton::DoGravity(float *scale)
509 {
510     static int i;
511     for (i = 0; i < num_joints; i++) {
512         if (
513                 (
514                     ((joints[i].label != leftknee) && (joints[i].label != rightknee)) ||
515                     (lowforward.y > -.1) ||
516                     (joints[i].mass < 5)
517                 ) && (
518                     ((joints[i].label != leftelbow) && (joints[i].label != rightelbow)) ||
519                     (forward.y < .3)
520                 )
521             )
522             joints[i].velocity.y += gravity * multiplier / (*scale);
523     }
524 }
525
526 /* EFFECT
527  * set muscles[which].rotate1
528  *     .rotate2
529  *     .rotate3
530  *
531  * special case if animation == hanganim
532  */
533 void Skeleton::FindRotationMuscle(int which, int animation)
534 {
535     XYZ p1, p2, fwd;
536     float dist;
537
538     p1 = muscles[which].parent1->position;
539     p2 = muscles[which].parent2->position;
540     dist = findDistance(&p1, &p2);
541     if (p1.y - p2.y <= dist)
542         muscles[which].rotate2 = asin((p1.y - p2.y) / dist);
543     if (p1.y - p2.y > dist)
544         muscles[which].rotate2 = asin(1.f);
545     muscles[which].rotate2 *= 360.0 / 6.2831853;
546
547     p1.y = 0;
548     p2.y = 0;
549     dist = findDistance(&p1, &p2);
550     if (p1.z - p2.z <= dist)
551         muscles[which].rotate1 = acos((p1.z - p2.z) / dist);
552     if (p1.z - p2.z > dist)
553         muscles[which].rotate1 = acos(1.f);
554     muscles[which].rotate1 *= 360.0 / 6.2831853;
555     if (p1.x > p2.x)
556         muscles[which].rotate1 = 360 - muscles[which].rotate1;
557     if (!isnormal(muscles[which].rotate1))
558         muscles[which].rotate1 = 0;
559     if (!isnormal(muscles[which].rotate2))
560         muscles[which].rotate2 = 0;
561
562     const int label1 = muscles[which].parent1->label;
563     const int label2 = muscles[which].parent2->label;
564     switch (label1) {
565     case head:
566         fwd = specialforward[0];
567         break;
568     case rightshoulder:
569     case rightelbow:
570     case rightwrist:
571     case righthand:
572         fwd = specialforward[1];
573         break;
574     case leftshoulder:
575     case leftelbow:
576     case leftwrist:
577     case lefthand:
578         fwd = specialforward[2];
579         break;
580     case righthip:
581     case rightknee:
582     case rightankle:
583     case rightfoot:
584         fwd = specialforward[3];
585         break;
586     case lefthip:
587     case leftknee:
588     case leftankle:
589     case leftfoot:
590         fwd = specialforward[4];
591         break;
592     default:
593         if (muscles[which].parent1->lower)
594             fwd = lowforward;
595         else
596             fwd = forward;
597         break;
598     }
599
600     if (animation == hanganim) {
601         if (label1 == righthand || label2 == righthand) {
602             fwd = 0;
603             fwd.x = -1;
604         }
605         if (label1 == lefthand || label2 == lefthand) {
606             fwd = 0;
607             fwd.x = 1;
608         }
609     }
610
611     if (free == 0) {
612         if (label1 == rightfoot || label2 == rightfoot) {
613             fwd.y -= .3;
614         }
615         if (label1 == leftfoot || label2 == leftfoot) {
616             fwd.y -= .3;
617         }
618     }
619
620     fwd = DoRotation(fwd, 0, muscles[which].rotate1 - 90, 0);
621     fwd = DoRotation(fwd, 0, 0, muscles[which].rotate2 - 90);
622     fwd.y = 0;
623     fwd /= findLength(&fwd);
624     if (fwd.z <= 1 && fwd.z >= -1)
625         muscles[which].rotate3 = acos(0 - fwd.z);
626     else
627         muscles[which].rotate3 = acos(-1.f);
628     muscles[which].rotate3 *= 360.0 / 6.2831853;
629     if (0 > fwd.x)
630         muscles[which].rotate3 = 360 - muscles[which].rotate3;
631     if (!isnormal(muscles[which].rotate3))
632         muscles[which].rotate3 = 0;
633 }
634
635 /* EFFECT
636  * load skeleton
637  * takes filenames for three skeleton files and various models
638  */
639 void Skeleton::Load(const std::string& filename,       const std::string& lowfilename, const std::string& clothesfilename,
640                     const std::string& modelfilename,  const std::string& model2filename,
641                     const std::string& model3filename, const std::string& model4filename,
642                     const std::string& model5filename, const std::string& model6filename,
643                     const std::string& model7filename, const std::string& modellowfilename,
644                     const std::string& modelclothesfilename, bool clothes)
645 {
646     GLfloat M[16];
647     int parentID;
648     FILE *tfile;
649     float lSize;
650     int i, j;
651     int edit;
652
653     LOGFUNC;
654
655     num_models = 7;
656
657     // load various models
658     // rotate, scale, do normals, do texcoords for each as needed
659
660     model[0].loadnotex(modelfilename);
661     model[1].loadnotex(model2filename);
662     model[2].loadnotex(model3filename);
663     model[3].loadnotex(model4filename);
664     model[4].loadnotex(model5filename);
665     model[5].loadnotex(model6filename);
666     model[6].loadnotex(model7filename);
667
668     for (i = 0; i < num_models; i++) {
669         model[i].Rotate(180, 0, 0);
670         model[i].Scale(.04, .04, .04);
671         model[i].CalculateNormals(0);
672     }
673
674     drawmodel.load(modelfilename, 0);
675     drawmodel.Rotate(180, 0, 0);
676     drawmodel.Scale(.04, .04, .04);
677     drawmodel.FlipTexCoords();
678     if ((tutoriallevel == 1) && (id != 0)) {
679         drawmodel.UniformTexCoords();
680         drawmodel.ScaleTexCoords(0.1);
681     }
682     drawmodel.CalculateNormals(0);
683
684     modellow.loadnotex(modellowfilename);
685     modellow.Rotate(180, 0, 0);
686     modellow.Scale(.04, .04, .04);
687     modellow.CalculateNormals(0);
688
689     drawmodellow.load(modellowfilename, 0);
690     drawmodellow.Rotate(180, 0, 0);
691     drawmodellow.Scale(.04, .04, .04);
692     drawmodellow.FlipTexCoords();
693     if (tutoriallevel == 1 && id != 0)
694         drawmodellow.UniformTexCoords();
695     if (tutoriallevel == 1 && id != 0)
696         drawmodellow.ScaleTexCoords(0.1);
697     drawmodellow.CalculateNormals(0);
698
699     if (clothes) {
700         modelclothes.loadnotex(modelclothesfilename);
701         modelclothes.Rotate(180, 0, 0);
702         modelclothes.Scale(.041, .04, .041);
703         modelclothes.CalculateNormals(0);
704
705         drawmodelclothes.load(modelclothesfilename, 0);
706         drawmodelclothes.Rotate(180, 0, 0);
707         drawmodelclothes.Scale(.04, .04, .04);
708         drawmodelclothes.FlipTexCoords();
709         drawmodelclothes.CalculateNormals(0);
710     }
711
712     // FIXME: three similar blocks follow, one for each of:
713     // filename, lowfilename, clothesfilename
714
715     // load skeleton
716
717     tfile = Folders::openMandatoryFile( Folders::getResourcePath(filename), "rb" );
718
719     // read num_joints
720     funpackf(tfile, "Bi", &num_joints);
721
722     // allocate memory
723     if (joints)
724         delete [] joints; //dealloc2(joints);
725     joints = (Joint*)new Joint[num_joints];
726
727     // read info for each joint
728     for (i = 0; i < num_joints; i++) {
729         funpackf(tfile, "Bf Bf Bf Bf Bf", &joints[i].position.x, &joints[i].position.y, &joints[i].position.z, &joints[i].length, &joints[i].mass);
730         funpackf(tfile, "Bb Bb", &joints[i].hasparent, &joints[i].locked);
731         funpackf(tfile, "Bi", &joints[i].modelnum);
732         funpackf(tfile, "Bb Bb", &joints[i].visible, &joints[i].sametwist);
733         funpackf(tfile, "Bi Bi", &joints[i].label, &joints[i].hasgun);
734         funpackf(tfile, "Bb", &joints[i].lower);
735         funpackf(tfile, "Bi", &parentID);
736         if (joints[i].hasparent)
737             joints[i].parent = &joints[parentID];
738         joints[i].velocity = 0;
739         joints[i].oldposition = joints[i].position;
740         joints[i].startpos = joints[i].position;
741     }
742
743     // read num_muscles
744     funpackf(tfile, "Bi", &num_muscles);
745
746     // allocate memory
747     if (muscles)
748         delete [] muscles; //dealloc2(muscles);
749     muscles = (Muscle*)new Muscle[num_muscles]; //malloc(sizeof(Muscle)*num_muscles);
750
751     // for each muscle...
752     for (i = 0; i < num_muscles; i++) {
753         muscles[i].load(tfile, model[0].vertexNum, joints);
754     }
755
756     // read forwardjoints (?)
757     for (j = 0; j < 3; j++) {
758         funpackf(tfile, "Bi", &forwardjoints[j]);
759     }
760     // read lowforwardjoints (?)
761     for (j = 0; j < 3; j++) {
762         funpackf(tfile, "Bi", &lowforwardjoints[j]);
763     }
764
765     // ???
766     for (j = 0; j < num_muscles; j++) {
767         for (i = 0; i < muscles[j].vertices.size(); i++) {
768             for (int k = 0; k < num_models; k++) {
769                 if (muscles[j].vertices[i] < model[k].vertexNum)
770                     model[k].owner[muscles[j].vertices[i]] = j;
771             }
772         }
773     }
774
775     // calculate some stuff
776     FindForwards();
777     for (i = 0; i < num_muscles; i++) {
778         FindRotationMuscle(i, -1);
779     }
780     // this seems to use opengl purely for matrix calculations
781     for (int k = 0; k < num_models; k++) {
782         for (i = 0; i < model[k].vertexNum; i++) {
783             model[k].vertex[i] = model[k].vertex[i] - (muscles[model[k].owner[i]].parent1->position + muscles[model[k].owner[i]].parent2->position) / 2;
784             glMatrixMode(GL_MODELVIEW);
785             glPushMatrix();
786             glLoadIdentity();
787             glRotatef(muscles[model[k].owner[i]].rotate3, 0, 1, 0);
788             glRotatef(muscles[model[k].owner[i]].rotate2 - 90, 0, 0, 1);
789             glRotatef(muscles[model[k].owner[i]].rotate1 - 90, 0, 1, 0);
790             glTranslatef(model[k].vertex[i].x, model[k].vertex[i].y, model[k].vertex[i].z);
791             glGetFloatv(GL_MODELVIEW_MATRIX, M);
792             model[k].vertex[i].x = M[12] * 1;
793             model[k].vertex[i].y = M[13] * 1;
794             model[k].vertex[i].z = M[14] * 1;
795             glPopMatrix();
796         }
797         model[k].CalculateNormals(0);
798     }
799     fclose(tfile);
800
801     // load ???
802
803     tfile = Folders::openMandatoryFile( Folders::getResourcePath(lowfilename), "rb" );
804
805     // skip joints section
806
807     lSize = sizeof(num_joints);
808     fseek(tfile, lSize, SEEK_CUR);
809     for (i = 0; i < num_joints; i++) {
810         // skip joint info
811         lSize = sizeof(XYZ)
812                 + sizeof(float)
813                 + sizeof(float)
814                 + 1 //sizeof(bool)
815                 + 1 //sizeof(bool)
816                 + sizeof(int)
817                 + 1 //sizeof(bool)
818                 + 1 //sizeof(bool)
819                 + sizeof(int)
820                 + sizeof(int)
821                 + 1 //sizeof(bool)
822                 + sizeof(int);
823         fseek(tfile, lSize, SEEK_CUR);
824     }
825
826     // read num_muscles
827     funpackf(tfile, "Bi", &num_muscles);
828
829     for (i = 0; i < num_muscles; i++) {
830         // skip muscle info
831         lSize = sizeof(float)
832                 + sizeof(float)
833                 + sizeof(float)
834                 + sizeof(float)
835                 + sizeof(float)
836                 + sizeof(int);
837         fseek(tfile, lSize, SEEK_CUR);
838
839         muscles[i].loadVerticesLow(tfile, modellow.vertexNum);
840
841         // skip more stuff
842         lSize = 1; //sizeof(bool);
843         fseek ( tfile, lSize, SEEK_CUR);
844         lSize = sizeof(int);
845         fseek ( tfile, lSize, SEEK_CUR);
846         fseek ( tfile, lSize, SEEK_CUR);
847     }
848
849     for (j = 0; j < num_muscles; j++) {
850         for (i = 0; i < muscles[j].verticeslow.size(); i++) {
851             if (muscles[j].verticeslow[i] < modellow.vertexNum)
852                 modellow.owner[muscles[j].verticeslow[i]] = j;
853         }
854     }
855
856     // use opengl for its matrix math
857     for (i = 0; i < modellow.vertexNum; i++) {
858         modellow.vertex[i] = modellow.vertex[i] - (muscles[modellow.owner[i]].parent1->position + muscles[modellow.owner[i]].parent2->position) / 2;
859         glMatrixMode(GL_MODELVIEW);
860         glPushMatrix();
861         glLoadIdentity();
862         glRotatef(muscles[modellow.owner[i]].rotate3, 0, 1, 0);
863         glRotatef(muscles[modellow.owner[i]].rotate2 - 90, 0, 0, 1);
864         glRotatef(muscles[modellow.owner[i]].rotate1 - 90, 0, 1, 0);
865         glTranslatef(modellow.vertex[i].x, modellow.vertex[i].y, modellow.vertex[i].z);
866         glGetFloatv(GL_MODELVIEW_MATRIX, M);
867         modellow.vertex[i].x = M[12];
868         modellow.vertex[i].y = M[13];
869         modellow.vertex[i].z = M[14];
870         glPopMatrix();
871     }
872
873     modellow.CalculateNormals(0);
874
875     // load clothes
876
877     if (clothes) {
878         tfile = Folders::openMandatoryFile( Folders::getResourcePath(clothesfilename), "rb" );
879
880         // skip num_joints
881         lSize = sizeof(num_joints);
882         fseek ( tfile, lSize, SEEK_CUR);
883
884         for (i = 0; i < num_joints; i++) {
885             // skip joint info
886             lSize = sizeof(XYZ)
887                     + sizeof(float)
888                     + sizeof(float)
889                     + 1 //sizeof(bool)
890                     + 1 //sizeof(bool)
891                     + sizeof(int)
892                     + 1 //sizeof(bool)
893                     + 1 //sizeof(bool)
894                     + sizeof(int)
895                     + sizeof(int)
896                     + 1 //sizeof(bool)
897                     + sizeof(int);
898             fseek(tfile, lSize, SEEK_CUR);
899         }
900
901         // read num_muscles
902         funpackf(tfile, "Bi", &num_muscles);
903
904         for (i = 0; i < num_muscles; i++) {
905             // skip muscle info
906             lSize = sizeof(float)
907                     + sizeof(float)
908                     + sizeof(float)
909                     + sizeof(float)
910                     + sizeof(float)
911                     + sizeof(int);
912             fseek(tfile, lSize, SEEK_CUR);
913
914             muscles[i].loadVerticesClothes(tfile, modelclothes.vertexNum);
915
916             // skip more stuff
917             lSize = 1; //sizeof(bool);
918             fseek ( tfile, lSize, SEEK_CUR);
919             lSize = sizeof(int);
920             fseek ( tfile, lSize, SEEK_CUR);
921             fseek ( tfile, lSize, SEEK_CUR);
922         }
923
924         // ???
925         lSize = sizeof(int);
926         for (j = 0; j < num_muscles; j++) {
927             for (i = 0; i < muscles[j].verticesclothes.size(); i++) {
928                 if (muscles[j].verticesclothes.size() && muscles[j].verticesclothes[i] < modelclothes.vertexNum)
929                     modelclothes.owner[muscles[j].verticesclothes[i]] = j;
930             }
931         }
932
933         // use opengl for its matrix math
934         for (i = 0; i < modelclothes.vertexNum; i++) {
935             modelclothes.vertex[i] = modelclothes.vertex[i] - (muscles[modelclothes.owner[i]].parent1->position + muscles[modelclothes.owner[i]].parent2->position) / 2;
936             glMatrixMode(GL_MODELVIEW);
937             glPushMatrix();
938             glLoadIdentity();
939             glRotatef(muscles[modelclothes.owner[i]].rotate3, 0, 1, 0);
940             glRotatef(muscles[modelclothes.owner[i]].rotate2 - 90, 0, 0, 1);
941             glRotatef(muscles[modelclothes.owner[i]].rotate1 - 90, 0, 1, 0);
942             glTranslatef(modelclothes.vertex[i].x, modelclothes.vertex[i].y, modelclothes.vertex[i].z);
943             glGetFloatv(GL_MODELVIEW_MATRIX, M);
944             modelclothes.vertex[i].x = M[12];
945             modelclothes.vertex[i].y = M[13];
946             modelclothes.vertex[i].z = M[14];
947             glPopMatrix();
948         }
949
950         modelclothes.CalculateNormals(0);
951     }
952     fclose(tfile);
953
954     for (i = 0; i < num_joints; i++) {
955         for (j = 0; j < num_joints; j++) {
956             if (joints[i].label == j)
957                 jointlabels[j] = i;
958         }
959     }
960
961     free = 0;
962 }
963
964 #if 0
965
966 // the following functions are not used anywhere
967
968 /* EFFECT
969  * sets forward, lowforward, specialforward[]
970  *
971  * USES:
972  * NONE
973  */
974 void Skeleton::FindForwardsfirst()
975 {
976     //Find forward vectors
977     CrossProduct(joints[forwardjoints[1]].position - joints[forwardjoints[0]].position, joints[forwardjoints[2]].position - joints[forwardjoints[0]].position, &forward);
978     Normalise(&forward);
979
980     CrossProduct(joints[lowforwardjoints[1]].position - joints[lowforwardjoints[0]].position, joints[lowforwardjoints[2]].position - joints[lowforwardjoints[0]].position, &lowforward);
981     Normalise(&lowforward);
982
983     //Special forwards
984     specialforward[0] = forward;
985     specialforward[1] = forward;
986     specialforward[2] = forward;
987     specialforward[3] = forward;
988     specialforward[4] = forward;
989
990 }
991
992 /* EFFECT
993  *
994  * USES:
995  * NONE
996  */
997 void Skeleton::Draw(int muscleview)
998 {
999     static float jointcolor[4];
1000
1001     if (muscleview == 2) {
1002         jointcolor[0] = 0;
1003         jointcolor[1] = 0;
1004         jointcolor[2] = 0;
1005         jointcolor[3] = .5;
1006     } else {
1007         jointcolor[0] = 0;
1008         jointcolor[1] = 0;
1009         jointcolor[2] = .5;
1010         jointcolor[3] = 1;
1011     }
1012
1013     //Calc motionblur-ness
1014     for (int i = 0; i < num_joints; i++) {
1015         joints[i].oldposition = joints[i].position;
1016         joints[i].blurred = findDistance(&joints[i].position, &joints[i].oldposition) * 100;
1017         if (joints[i].blurred < 1)
1018             joints[i].blurred = 1;
1019     }
1020
1021     //Do Motionblur
1022     glDepthMask(0);
1023     glEnable(GL_BLEND);
1024     glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1025     glBegin(GL_QUADS);
1026     for (int i = 0; i < num_joints; i++) {
1027         if (joints[i].hasparent) {
1028             glColor4f(jointcolor[0], jointcolor[1], jointcolor[2], jointcolor[3] / joints[i].blurred);
1029             glVertex3f(joints[i].position.x, joints[i].position.y, joints[i].position.z);
1030             glColor4f(jointcolor[0], jointcolor[1], jointcolor[2], jointcolor[3] / joints[i].parent->blurred);
1031             glVertex3f(joints[i].parent->position.x, joints[i].parent->position.y, joints[i].parent->position.z);
1032             glColor4f(jointcolor[0], jointcolor[1], jointcolor[2], jointcolor[3] / joints[i].parent->blurred);
1033             glVertex3f(joints[i].parent->oldposition.x, joints[i].parent->oldposition.y, joints[i].parent->oldposition.z);
1034             glColor4f(jointcolor[0], jointcolor[1], jointcolor[2], jointcolor[3] / joints[i].blurred);
1035             glVertex3f(joints[i].oldposition.x, joints[i].oldposition.y, joints[i].oldposition.z);
1036         }
1037     }
1038     for (int i = 0; i < num_muscles; i++) {
1039         if (muscles[i].type == boneconnect) {
1040             glColor4f(jointcolor[0], jointcolor[1], jointcolor[2], jointcolor[3] / muscles[i].parent2->blurred);
1041             glVertex3f(muscles[i].parent1->position.x, muscles[i].parent1->position.y, muscles[i].parent1->position.z);
1042             glColor4f(jointcolor[0], jointcolor[1], jointcolor[2], jointcolor[3] / muscles[i].parent2->blurred);
1043             glVertex3f(muscles[i].parent2->position.x, muscles[i].parent2->position.y, muscles[i].parent2->position.z);
1044             glColor4f(jointcolor[0], jointcolor[1], jointcolor[2], jointcolor[3] / muscles[i].parent2->blurred);
1045             glVertex3f(muscles[i].parent2->oldposition.x, muscles[i].parent2->oldposition.y, muscles[i].parent2->oldposition.z);
1046             glColor4f(jointcolor[0], jointcolor[1], jointcolor[2], jointcolor[3] / muscles[i].parent1->blurred);
1047             glVertex3f(muscles[i].parent1->oldposition.x, muscles[i].parent1->oldposition.y, muscles[i].parent1->oldposition.z);
1048         }
1049     }
1050     glEnd();
1051
1052     glBegin(GL_LINES);
1053     for (int i = 0; i < num_joints; i++) {
1054         if (joints[i].hasparent) {
1055             glColor4f(jointcolor[0], jointcolor[1], jointcolor[2], jointcolor[3] / joints[i].blurred);
1056             glVertex3f(joints[i].position.x, joints[i].position.y, joints[i].position.z);
1057             glColor4f(jointcolor[0], jointcolor[1], jointcolor[2], jointcolor[3] / joints[i].parent->blurred);
1058             glVertex3f(joints[i].parent->position.x, joints[i].parent->position.y, joints[i].parent->position.z);
1059         }
1060     }
1061     for (int i = 0; i < num_muscles; i++) {
1062         if (muscles[i].type == boneconnect) {
1063             glColor4f(jointcolor[0], jointcolor[1], jointcolor[2], jointcolor[3] / muscles[i].parent1->blurred);
1064             glVertex3f(muscles[i].parent1->position.x, muscles[i].parent1->position.y, muscles[i].parent1->position.z);
1065             glColor4f(jointcolor[0], jointcolor[1], jointcolor[2], jointcolor[3] / muscles[i].parent2->blurred);
1066             glVertex3f(muscles[i].parent2->position.x, muscles[i].parent2->position.y, muscles[i].parent2->position.z);
1067         }
1068     }
1069     glColor3f(.6, .6, 0);
1070     if (muscleview == 1)
1071         for (int i = 0; i < num_muscles; i++) {
1072             if (muscles[i].type != boneconnect) {
1073                 glVertex3f(muscles[i].parent1->position.x, muscles[i].parent1->position.y, muscles[i].parent1->position.z);
1074                 glVertex3f(muscles[i].parent2->position.x, muscles[i].parent2->position.y, muscles[i].parent2->position.z);
1075             }
1076         }
1077     glEnd();
1078
1079     if (muscleview != 2) {
1080         glPointSize(3);
1081         glBegin(GL_POINTS);
1082         for (int i = 0; i < num_joints; i++) {
1083             if (i != selected)
1084                 glColor4f(0, 0, .5, 1);
1085             if (i == selected)
1086                 glColor4f(1, 1, 0, 1);
1087             if (joints[i].locked && i != selected)
1088                 glColor4f(1, 0, 0, 1);
1089             glVertex3f(joints[i].position.x, joints[i].position.y, joints[i].position.z);
1090         }
1091         glEnd();
1092     }
1093
1094     //Set old position to current position
1095     if (muscleview == 2)
1096         for (int i = 0; i < num_joints; i++) {
1097             joints[i].oldposition = joints[i].position;
1098         }
1099     glDepthMask(1);
1100 }
1101
1102 /* EFFECT
1103  *
1104  * USES:
1105  * NONE
1106  */
1107 void Skeleton::AddJoint(float x, float y, float z, int which)
1108 {
1109     if (num_joints < max_joints - 1) {
1110         joints[num_joints].velocity = 0;
1111         joints[num_joints].position.x = x;
1112         joints[num_joints].position.y = y;
1113         joints[num_joints].position.z = z;
1114         joints[num_joints].mass = 1;
1115         joints[num_joints].locked = 0;
1116
1117         joints[num_joints].hasparent = 0;
1118         num_joints++;
1119         if (which < num_joints && which >= 0)
1120             AddMuscle(num_joints - 1, which, 0, 10, boneconnect);
1121     }
1122 }
1123
1124 /* EFFECT
1125  *
1126  * USES:
1127  * NONE
1128  */
1129 void Skeleton::DeleteJoint(int whichjoint)
1130 {
1131     if (whichjoint < num_joints && whichjoint >= 0) {
1132         joints[whichjoint].velocity = joints[num_joints - 1].velocity;
1133         joints[whichjoint].position = joints[num_joints - 1].position;
1134         joints[whichjoint].oldposition = joints[num_joints - 1].oldposition;
1135         joints[whichjoint].hasparent = joints[num_joints - 1].hasparent;
1136         joints[whichjoint].parent = joints[num_joints - 1].parent;
1137         joints[whichjoint].length = joints[num_joints - 1].length;
1138         joints[whichjoint].locked = joints[num_joints - 1].locked;
1139         joints[whichjoint].modelnum = joints[num_joints - 1].modelnum;
1140         joints[whichjoint].visible = joints[num_joints - 1].visible;
1141
1142         for (int i = 0; i < num_muscles; i++) {
1143             while (muscles[i].parent1 == &joints[whichjoint] && i < num_muscles)DeleteMuscle(i);
1144             while (muscles[i].parent2 == &joints[whichjoint] && i < num_muscles)DeleteMuscle(i);
1145         }
1146         for (int i = 0; i < num_muscles; i++) {
1147             while (muscles[i].parent1 == &joints[num_joints - 1] && i < num_muscles)muscles[i].parent1 = &joints[whichjoint];
1148             while (muscles[i].parent2 == &joints[num_joints - 1] && i < num_muscles)muscles[i].parent2 = &joints[whichjoint];
1149         }
1150         for (int i = 0; i < num_joints; i++) {
1151             if (joints[i].parent == &joints[whichjoint])
1152                 joints[i].hasparent = 0;
1153         }
1154         for (int i = 0; i < num_joints; i++) {
1155             if (joints[i].parent == &joints[num_joints - 1])
1156                 joints[i].parent = &joints[whichjoint];
1157         }
1158
1159         num_joints--;
1160     }
1161 }
1162
1163 /* EFFECT
1164  *
1165  * USES:
1166  * Skeleton::DeleteJoint - UNUSED
1167  */
1168 void Skeleton::DeleteMuscle(int whichmuscle)
1169 {
1170     if (whichmuscle < num_muscles) {
1171         muscles[whichmuscle].minlength = muscles[num_muscles - 1].minlength;
1172         muscles[whichmuscle].maxlength = muscles[num_muscles - 1].maxlength;
1173         muscles[whichmuscle].strength = muscles[num_muscles - 1].strength;
1174         muscles[whichmuscle].parent1 = muscles[num_muscles - 1].parent1;
1175         muscles[whichmuscle].parent2 = muscles[num_muscles - 1].parent2;
1176         muscles[whichmuscle].length = muscles[num_muscles - 1].length;
1177         muscles[whichmuscle].visible = muscles[num_muscles - 1].visible;
1178         muscles[whichmuscle].type = muscles[num_muscles - 1].type;
1179         muscles[whichmuscle].targetlength = muscles[num_muscles - 1].targetlength;
1180
1181         num_muscles--;
1182     }
1183 }
1184
1185 /* EFFECT
1186  *
1187  * USES:
1188  * NONE
1189  */
1190 void Skeleton::SetJoint(float x, float y, float z, int which, int whichjoint)
1191 {
1192     if (whichjoint < num_joints) {
1193         joints[whichjoint].velocity = 0;
1194         joints[whichjoint].position.x = x;
1195         joints[whichjoint].position.y = y;
1196         joints[whichjoint].position.z = z;
1197
1198         if (which >= num_joints || which < 0)
1199             joints[whichjoint].hasparent = 0;
1200         if (which < num_joints && which >= 0) {
1201             joints[whichjoint].parent = &joints[which];
1202             joints[whichjoint].hasparent = 1;
1203             joints[whichjoint].length = findDistance(&joints[whichjoint].position, &joints[whichjoint].parent->position);
1204         }
1205     }
1206 }
1207
1208 /* EFFECT
1209  *
1210  * USES:
1211  * Skeleton::AddJoint - UNUSED
1212  */
1213 void Skeleton::AddMuscle(int attach1, int attach2, float minlength, float maxlength, int type)
1214 {
1215     const int max_muscles = 100; // FIXME: Probably can be dropped
1216     if (num_muscles < max_muscles - 1 && attach1 < num_joints && attach1 >= 0 && attach2 < num_joints && attach2 >= 0 && attach1 != attach2) {
1217         muscles[num_muscles].parent1 = &joints[attach1];
1218         muscles[num_muscles].parent2 = &joints[attach2];
1219         muscles[num_muscles].length = findDistance(&muscles[num_muscles].parent1->position, &muscles[num_muscles].parent2->position);
1220         muscles[num_muscles].targetlength = findDistance(&muscles[num_muscles].parent1->position, &muscles[num_muscles].parent2->position);
1221         muscles[num_muscles].strength = .7;
1222         muscles[num_muscles].type = type;
1223         muscles[num_muscles].minlength = minlength;
1224         muscles[num_muscles].maxlength = maxlength;
1225
1226         num_muscles++;
1227     }
1228 }
1229
1230 /* EFFECT
1231  *
1232  * USES:
1233  * NONE
1234  */
1235 void Skeleton::MusclesSet()
1236 {
1237     for (int i = 0; i < num_muscles; i++) {
1238         muscles[i].length = findDistance(&muscles[i].parent1->position, &muscles[i].parent2->position);
1239     }
1240 }
1241
1242 /* EFFECT
1243  *
1244  * USES:
1245  * NONE
1246  */
1247 void Skeleton::DoBalance()
1248 {
1249     /*XYZ newpoint;
1250     newpoint=joints[0].position;
1251     newpoint.x=(joints[2].position.x+joints[4].position.x)/2;
1252     newpoint.z=(joints[2].position.z+joints[4].position.z)/2;
1253     joints[0].velocity=joints[0].velocity+(newpoint-joints[0].position);
1254     //Move child point to within certain distance of parent point
1255     joints[0].position=newpoint;
1256
1257     MusclesSet();*/
1258 }
1259
1260 #endif
1261