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