]> git.jsancho.org Git - lugaru.git/blob - Source/Skeleton.cpp
a9f63e258ee438861871746d1baf78a47e7faddf
[lugaru.git] / Source / 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 "Skeleton.h"
24 #include "openal_wrapper.h"
25 #include "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 enum {boneconnect, constraint, muscle};
51
52
53 /* EFFECT
54  * sets strength, length,
55  *      parent1->position, parent2->position,
56  *      parent1->velocity, parent2->velocity
57  * used for ragdolls?
58  *
59  * USES:
60  * Skeleton::DoConstraints
61  */
62 void Muscle::DoConstraint(bool spinny)
63 {
64     // FIXME: relaxlength shouldn't be static, but may not always be set
65     // so I don't want to change the existing behavior even though it's probably a bug
66     static float relaxlength;
67
68     float oldlength = length;
69
70     if (type != boneconnect)
71         relaxlength = findDistance(&parent1->position, &parent2->position);
72
73     if (type == boneconnect)
74         strength = 1;
75     if (type == constraint)
76         strength = 0;
77
78     // clamp strength
79     if (strength < 0)
80         strength = 0;
81     if (strength > 1)
82         strength = 1;
83
84     length -= (length - relaxlength) * (1 - strength) * multiplier * 10000;
85     length -= (length - targetlength) * (strength) * multiplier * 10000;
86     if (strength == 0)
87         length = relaxlength;
88
89     if ((relaxlength - length > 0 && relaxlength - oldlength < 0) || (relaxlength - length < 0 && relaxlength - oldlength > 0))
90         length = relaxlength;
91
92     // clamp length
93     if (length < minlength)
94         length = minlength;
95     if (length > maxlength)
96         length = maxlength;
97
98     if (length == relaxlength)
99         return;
100
101     // relax muscle?
102
103     //Find midpoint
104     XYZ midp = (parent1->position * parent1->mass + parent2->position * parent2->mass) / (parent1->mass + parent2->mass);
105
106     //Find vector from midpoint to second vector
107     XYZ vel = parent2->position - midp;
108
109     //Change to unit vector
110     Normalise(&vel);
111
112     //Apply velocity change
113     XYZ newpoint1 = midp - vel * length * (parent2->mass / (parent1->mass + parent2->mass));
114     XYZ newpoint2 = midp + vel * length * (parent1->mass / (parent1->mass + parent2->mass));
115     if (!freeze && spinny) {
116         parent1->velocity = parent1->velocity + (newpoint1 - parent1->position) / multiplier / 4;
117         parent2->velocity = parent2->velocity + (newpoint2 - parent2->position) / multiplier / 4;
118     } else {
119         parent1->velocity = parent1->velocity + (newpoint1 - parent1->position);
120         parent2->velocity = parent2->velocity + (newpoint2 - parent2->position);
121     }
122
123     //Move child point to within certain distance of parent point
124     parent1->position = newpoint1;
125     parent2->position = newpoint2;
126 }
127
128 /* EFFECT
129  * sets forward, lowforward, specialforward[]
130  *
131  * USES:
132  * Skeleton::Load
133  * Person/Person::DoAnimations
134  * Person/Person::DrawSkeleton
135  */
136 void Skeleton::FindForwards()
137 {
138     //Find forward vectors
139     CrossProduct(joints[forwardjoints[1]].position - joints[forwardjoints[0]].position, joints[forwardjoints[2]].position - joints[forwardjoints[0]].position, &forward);
140     Normalise(&forward);
141
142     CrossProduct(joints[lowforwardjoints[1]].position - joints[lowforwardjoints[0]].position, joints[lowforwardjoints[2]].position - joints[lowforwardjoints[0]].position, &lowforward);
143     Normalise(&lowforward);
144
145     //Special forwards
146     specialforward[0] = forward;
147
148     specialforward[1] = jointPos(rightshoulder) + jointPos(rightwrist);
149     specialforward[1] = jointPos(rightelbow) - specialforward[1] / 2;
150     specialforward[1] += forward * .4;
151     Normalise(&specialforward[1]);
152     specialforward[2] = jointPos(leftshoulder) + jointPos(leftwrist);
153     specialforward[2] = jointPos(leftelbow) - specialforward[2] / 2;
154     specialforward[2] += forward * .4;
155     Normalise(&specialforward[2]);
156
157     specialforward[3] = jointPos(righthip) + jointPos(rightankle);
158     specialforward[3] = specialforward[3] / 2 - jointPos(rightknee);
159     specialforward[3] += lowforward * .4;
160     Normalise(&specialforward[3]);
161     specialforward[4] = jointPos(lefthip) + jointPos(leftankle);
162     specialforward[4] = specialforward[4] / 2 - jointPos(leftknee);
163     specialforward[4] += lowforward * .4;
164     Normalise(&specialforward[4]);
165 }
166
167 /* EFFECT
168  * TODO
169  *
170  * USES:
171  * Person/Person::RagDoll
172  * Person/Person::DoStuff
173  * Person/IKHelper
174  */
175 float Skeleton::DoConstraints(XYZ *coords, float *scale)
176 {
177     float friction = 1.5;
178     const float elasticity = .3;
179     XYZ bounceness;
180     const int numrepeats = 3;
181     float groundlevel = .15;
182     int i, j, k, m;
183     XYZ temp;
184     XYZ terrainnormal;
185     int whichhit;
186     float frictionness;
187     XYZ terrainlight;
188     int whichpatchx;
189     int whichpatchz;
190     float damage = 0; // eventually returned from function
191     bool breaking = false;
192
193     if (free) {
194         freetime += multiplier;
195
196         whichpatchx = coords->x / (terrain.size / subdivision * terrain.scale);
197         whichpatchz = coords->z / (terrain.size / subdivision * terrain.scale);
198
199         terrainlight = *coords;
200         objects.SphereCheckPossible(&terrainlight, 1);
201
202         //Add velocity
203         for (i = 0; i < num_joints; i++) {
204             joints[i].position = joints[i].position + joints[i].velocity * multiplier;
205
206             switch (joints[i].label) {
207             case head:
208                 groundlevel = .8;
209                 break;
210             case righthand:
211             case rightwrist:
212             case rightelbow:
213             case lefthand:
214             case leftwrist:
215             case leftelbow:
216                 groundlevel = .2;
217                 break;
218             default:
219                 groundlevel = .15;
220                 break;
221             }
222
223             joints[i].position.y -= groundlevel;
224             joints[i].oldvelocity = joints[i].velocity;
225         }
226
227         float tempmult = multiplier;
228         //multiplier/=numrepeats;
229
230         for (j = 0; j < numrepeats; j++) {
231             float r = .05;
232             // right leg constraints?
233             if (!joint(rightknee).locked && !joint(righthip).locked) {
234                 temp = jointPos(rightknee) - (jointPos(righthip) + jointPos(rightankle)) / 2;
235                 while (normaldotproduct(temp, lowforward) > -.1 && !sphere_line_intersection(&jointPos(righthip), &jointPos(rightankle), &jointPos(rightknee), &r)) {
236                     jointPos(rightknee) -= lowforward * .05;
237                     if (spinny)
238                         jointVel(rightknee) -= lowforward * .05 / multiplier / 4;
239                     else
240                         jointVel(rightknee) -= lowforward * .05;
241                     jointPos(rightankle) += lowforward * .025;
242                     if (spinny)
243                         jointVel(rightankle) += lowforward * .025 / multiplier / 4;
244                     else
245                         jointVel(rightankle) += lowforward * .25;
246                     jointPos(righthip) += lowforward * .025;
247                     if (spinny)
248                         jointVel(righthip) += lowforward * .025 / multiplier / 4;
249                     else
250                         jointVel(righthip) += lowforward * .025;
251                     temp = jointPos(rightknee) - (jointPos(righthip) + jointPos(rightankle)) / 2;
252                 }
253             }
254
255             // left leg constraints?
256             if (!joint(leftknee).locked && !joint(lefthip).locked) {
257                 temp = jointPos(leftknee) - (jointPos(lefthip) + jointPos(leftankle)) / 2;
258                 while (normaldotproduct(temp, lowforward) > -.1 && !sphere_line_intersection(&jointPos(lefthip), &jointPos(leftankle), &jointPos(leftknee), &r)) {
259                     jointPos(leftknee) -= lowforward * .05;
260                     if (spinny)
261                         jointVel(leftknee) -= lowforward * .05 / multiplier / 4;
262                     else
263                         jointVel(leftknee) -= lowforward * .05;
264                     jointPos(leftankle) += lowforward * .025;
265                     if (spinny)
266                         jointVel(leftankle) += lowforward * .025 / multiplier / 4;
267                     else
268                         jointVel(leftankle) += lowforward * .25;
269                     jointPos(lefthip) += lowforward * .025;
270                     if (spinny)
271                         jointVel(lefthip) += lowforward * .025 / multiplier / 4;
272                     else
273                         jointVel(lefthip) += lowforward * .025;
274                     temp = jointPos(leftknee) - (jointPos(lefthip) + jointPos(leftankle)) / 2;
275                 }
276             }
277
278             for (i = 0; i < num_joints; i++) {
279                 if (joints[i].locked && !spinny && findLengthfast(&joints[i].velocity) > 320)
280                     joints[i].locked = 0;
281                 if (spinny && findLengthfast(&joints[i].velocity) > 600)
282                     joints[i].locked = 0;
283                 if (joints[i].delay > 0) {
284                     bool freely = true;
285                     for (j = 0; j < num_joints; j++) {
286                         if (joints[j].locked)
287                             freely = false;
288                     }
289                     if (freely)
290                         joints[i].delay -= multiplier * 3;
291                 }
292             }
293
294             if (num_muscles)
295                 for (i = 0; i < num_muscles; i++) {
296                     //Length constraints
297                     muscles[i].DoConstraint(spinny);
298                 }
299
300             for (i = 0; i < num_joints; i++) {
301                 //Length constraints
302                 //Ground constraint
303                 groundlevel = 0;
304                 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) {
305                     freefall = 0;
306                     friction = 1.5;
307                     if (joints[i].label == groin && !joints[i].locked && joints[i].delay <= 0) {
308                         joints[i].locked = 1;
309                         joints[i].delay = 1;
310                         if (tutoriallevel != 1 || id == 0) {
311                             emit_sound_at(landsound1, joints[i].position * (*scale) + *coords, 128.);
312                         }
313                         breaking = true;
314                     }
315
316                     if (joints[i].label == head && !joints[i].locked && joints[i].delay <= 0) {
317                         joints[i].locked = 1;
318                         joints[i].delay = 1;
319                         if (tutoriallevel != 1 || id == 0) {
320                             emit_sound_at(landsound2, joints[i].position * (*scale) + *coords, 128.);
321                         }
322                     }
323
324                     terrainnormal = terrain.getNormal(joints[i].position.x * (*scale) + coords->x, joints[i].position.z * (*scale) + coords->z);
325                     ReflectVector(&joints[i].velocity, &terrainnormal);
326                     bounceness = terrainnormal * findLength(&joints[i].velocity) * (abs(normaldotproduct(joints[i].velocity, terrainnormal)));
327                     if (!joints[i].locked)
328                         damage += findLengthfast(&bounceness) / 4000;
329                     if (findLengthfast(&joints[i].velocity) < findLengthfast(&bounceness))
330                         bounceness = 0;
331                     frictionness = abs(normaldotproduct(joints[i].velocity, terrainnormal));
332                     joints[i].velocity -= bounceness;
333                     if (1 - friction * frictionness > 0)
334                         joints[i].velocity *= 1 - friction * frictionness;
335                     else
336                         joints[i].velocity = 0;
337
338                     if (tutoriallevel != 1 || id == 0)
339                         if (findLengthfast(&bounceness) > 8000 && breaking) {
340                             // FIXME: this crashes because k is not initialized!
341                             // to reproduce, type 'wolfie' in console and play a while
342                             // I'll just comment it out for now
343                             //objects.model[k].MakeDecal(breakdecal, DoRotation(temp - objects.position[k], 0, -objects.yaw[k], 0), .4, .5, Random() % 360);
344                             Sprite::MakeSprite(cloudsprite, joints[i].position * (*scale) + *coords, joints[i].velocity * .06, 1, 1, 1, 4, .2);
345                             breaking = false;
346                             camerashake += .6;
347
348                             emit_sound_at(breaksound2, joints[i].position * (*scale) + *coords);
349
350                             addEnvSound(*coords, 64);
351                         }
352
353                     if (findLengthfast(&bounceness) > 2500) {
354                         Normalise(&bounceness);
355                         bounceness = bounceness * 50;
356                     }
357
358                     joints[i].velocity += bounceness * elasticity;
359
360                     if (findLengthfast(&joints[i].velocity) > findLengthfast(&joints[i].oldvelocity)) {
361                         bounceness = 0;
362                         joints[i].velocity = joints[i].oldvelocity;
363                     }
364
365
366                     if (joints[i].locked == 0)
367                         if (findLengthfast(&joints[i].velocity) < 1)
368                             joints[i].locked = 1;
369
370                     if (environment == snowyenvironment && findLengthfast(&bounceness) > 500 && terrain.getOpacity(joints[i].position.x * (*scale) + coords->x, joints[i].position.z * (*scale) + coords->z) < .2) {
371                         terrainlight = terrain.getLighting(joints[i].position.x * (*scale) + coords->x, joints[i].position.z * (*scale) + coords->z);
372                         Sprite::MakeSprite(cloudsprite, joints[i].position * (*scale) + *coords, joints[i].velocity * .06, terrainlight.x, terrainlight.y, terrainlight.z, .5, .7);
373                         if (detail == 2)
374                             terrain.MakeDecal(bodyprintdecal, joints[i].position * (*scale) + *coords, .4, .4, 0);
375                     } else if (environment == desertenvironment && findLengthfast(&bounceness) > 500 && terrain.getOpacity(joints[i].position.x * (*scale) + coords->x, joints[i].position.z * (*scale) + coords->z) < .2) {
376                         terrainlight = terrain.getLighting(joints[i].position.x * (*scale) + coords->x, joints[i].position.z * (*scale) + coords->z);
377                         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);
378                     }
379
380                     else if (environment == grassyenvironment && findLengthfast(&bounceness) > 500 && terrain.getOpacity(joints[i].position.x * (*scale) + coords->x, joints[i].position.z * (*scale) + coords->z) < .2) {
381                         terrainlight = terrain.getLighting(joints[i].position.x * (*scale) + coords->x, joints[i].position.z * (*scale) + coords->z);
382                         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);
383                     } else if (findLengthfast(&bounceness) > 500)
384                         Sprite::MakeSprite(cloudsprite, joints[i].position * (*scale) + *coords, joints[i].velocity * .06, terrainlight.x, terrainlight.y, terrainlight.z, .5, .2);
385
386
387                     joints[i].position.y = (terrain.getHeight(joints[i].position.x * (*scale) + coords->x, joints[i].position.z * (*scale) + coords->z) + groundlevel - coords->y) / (*scale);
388                     if (longdead > 100)
389                         broken = 1;
390                 }
391                 if (terrain.patchobjectnum[whichpatchx][whichpatchz])
392                     for (m = 0; m < terrain.patchobjectnum[whichpatchx][whichpatchz]; m++) {
393                         k = terrain.patchobjects[whichpatchx][whichpatchz][m];
394                         if (k < objects.numobjects && k >= 0)
395                             if (objects.possible[k]) {
396                                 friction = objects.friction[k];
397                                 XYZ start = joints[i].realoldposition;
398                                 XYZ end = joints[i].position * (*scale) + *coords;
399                                 whichhit = objects.model[k].LineCheckPossible(&start, &end, &temp, &objects.position[k], &objects.yaw[k]);
400                                 if (whichhit != -1) {
401                                     if (joints[i].label == groin && !joints[i].locked && joints[i].delay <= 0) {
402                                         joints[i].locked = 1;
403                                         joints[i].delay = 1;
404                                         if (tutoriallevel != 1 || id == 0) {
405                                             emit_sound_at(landsound1, joints[i].position * (*scale) + *coords, 128.);
406                                         }
407                                         breaking = true;
408                                     }
409
410                                     if (joints[i].label == head && !joints[i].locked && joints[i].delay <= 0) {
411                                         joints[i].locked = 1;
412                                         joints[i].delay = 1;
413                                         if (tutoriallevel != 1 || id == 0) {
414                                             emit_sound_at(landsound2, joints[i].position * (*scale) + *coords, 128.);
415                                         }
416                                     }
417
418                                     terrainnormal = DoRotation(objects.model[k].facenormals[whichhit], 0, objects.yaw[k], 0) * -1;
419                                     if (terrainnormal.y > .8)
420                                         freefall = 0;
421                                     bounceness = terrainnormal * findLength(&joints[i].velocity) * (abs(normaldotproduct(joints[i].velocity, terrainnormal)));
422                                     if (findLengthfast(&joints[i].velocity) > findLengthfast(&joints[i].oldvelocity)) {
423                                         bounceness = 0;
424                                         joints[i].velocity = joints[i].oldvelocity;
425                                     }
426                                     if (tutoriallevel != 1 || id == 0)
427                                         if (findLengthfast(&bounceness) > 4000 && breaking) {
428                                             objects.model[k].MakeDecal(breakdecal, DoRotation(temp - objects.position[k], 0, -objects.yaw[k], 0), .4, .5, Random() % 360);
429                                             Sprite::MakeSprite(cloudsprite, joints[i].position * (*scale) + *coords, joints[i].velocity * .06, 1, 1, 1, 4, .2);
430                                             breaking = false;
431                                             camerashake += .6;
432
433                                             emit_sound_at(breaksound2, joints[i].position * (*scale) + *coords);
434
435                                             addEnvSound(*coords, 64);
436                                         }
437                                     if (objects.type[k] == treetrunktype) {
438                                         objects.rotx[k] += joints[i].velocity.x * multiplier * .4;
439                                         objects.roty[k] += joints[i].velocity.z * multiplier * .4;
440                                         objects.rotx[k + 1] += joints[i].velocity.x * multiplier * .4;
441                                         objects.roty[k + 1] += joints[i].velocity.z * multiplier * .4;
442                                     }
443                                     if (!joints[i].locked)
444                                         damage += findLengthfast(&bounceness) / 2500;
445                                     ReflectVector(&joints[i].velocity, &terrainnormal);
446                                     frictionness = abs(normaldotproduct(joints[i].velocity, terrainnormal));
447                                     joints[i].velocity -= bounceness;
448                                     if (1 - friction * frictionness > 0)
449                                         joints[i].velocity *= 1 - friction * frictionness;
450                                     else
451                                         joints[i].velocity = 0;
452                                     if (findLengthfast(&bounceness) > 2500) {
453                                         Normalise(&bounceness);
454                                         bounceness = bounceness * 50;
455                                     }
456                                     joints[i].velocity += bounceness * elasticity;
457
458
459                                     if (!joints[i].locked)
460                                         if (findLengthfast(&joints[i].velocity) < 1) {
461                                             joints[i].locked = 1;
462                                         }
463                                     if (findLengthfast(&bounceness) > 500)
464                                         Sprite::MakeSprite(cloudsprite, joints[i].position * (*scale) + *coords, joints[i].velocity * .06, 1, 1, 1, .5, .2);
465                                     joints[i].position = (temp - *coords) / (*scale) + terrainnormal * .005;
466                                     if (longdead > 100)
467                                         broken = 1;
468                                 }
469                             }
470                     }
471                 joints[i].realoldposition = joints[i].position * (*scale) + *coords;
472             }
473         }
474         multiplier = tempmult;
475
476
477         if (terrain.patchobjectnum[whichpatchx][whichpatchz])
478             for (m = 0; m < terrain.patchobjectnum[whichpatchx][whichpatchz]; m++) {
479                 k = terrain.patchobjects[whichpatchx][whichpatchz][m];
480                 if (objects.possible[k]) {
481                     for (i = 0; i < 26; i++) {
482                         //Make this less stupid
483                         XYZ start = joints[jointlabels[whichjointstartarray[i]]].position * (*scale) + *coords;
484                         XYZ end = joints[jointlabels[whichjointendarray[i]]].position * (*scale) + *coords;
485                         whichhit = objects.model[k].LineCheckSlidePossible(&start, &end, &temp, &objects.position[k], &objects.yaw[k]);
486                         if (whichhit != -1) {
487                             joints[jointlabels[whichjointendarray[i]]].position = (end - *coords) / (*scale);
488                             for (j = 0; j < num_muscles; j++) {
489                                 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]))
490                                     muscles[j].DoConstraint(spinny);
491                             }
492                         }
493                     }
494                 }
495             }
496
497         for (i = 0; i < num_joints; i++) {
498             switch (joints[i].label) {
499             case head:
500                 groundlevel = .8;
501                 break;
502             case righthand:
503             case rightwrist:
504             case rightelbow:
505             case lefthand:
506             case leftwrist:
507             case leftelbow:
508                 groundlevel = .2;
509                 break;
510             default:
511                 groundlevel = .15;
512                 break;
513             }
514             joints[i].position.y += groundlevel;
515             joints[i].mass = 1;
516             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)
517                 joints[i].mass = 2;
518             if (joints[i].locked) {
519                 joints[i].mass = 4;
520             }
521         }
522
523         return damage;
524     }
525
526     if (!free) {
527         for (i = 0; i < num_muscles; i++) {
528             if (muscles[i].type == boneconnect)
529                 muscles[i].DoConstraint(0);
530         }
531     }
532
533     return 0;
534 }
535
536 /* EFFECT
537  * applies gravity to the skeleton
538  *
539  * USES:
540  * Person/Person::DoStuff
541  */
542 void Skeleton::DoGravity(float *scale)
543 {
544     static int i;
545     for (i = 0; i < num_joints; i++) {
546         if (
547                 (
548                     ((joints[i].label != leftknee) && (joints[i].label != rightknee)) ||
549                     (lowforward.y > -.1) ||
550                     (joints[i].mass < 5)
551                 ) && (
552                     ((joints[i].label != leftelbow) && (joints[i].label != rightelbow)) ||
553                     (forward.y < .3)
554                 )
555             )
556             joints[i].velocity.y += gravity * multiplier / (*scale);
557     }
558 }
559
560 /* EFFECT
561  * set muscles[which].rotate1
562  *     .rotate2
563  *     .rotate3
564  *
565  * special case if animation == hanganim
566  */
567 void Skeleton::FindRotationMuscle(int which, int animation)
568 {
569     XYZ p1, p2, fwd;
570     float dist;
571
572     p1 = muscles[which].parent1->position;
573     p2 = muscles[which].parent2->position;
574     dist = findDistance(&p1, &p2);
575     if (p1.y - p2.y <= dist)
576         muscles[which].rotate2 = asin((p1.y - p2.y) / dist);
577     if (p1.y - p2.y > dist)
578         muscles[which].rotate2 = asin(1.f);
579     muscles[which].rotate2 *= 360.0 / 6.2831853;
580
581     p1.y = 0;
582     p2.y = 0;
583     dist = findDistance(&p1, &p2);
584     if (p1.z - p2.z <= dist)
585         muscles[which].rotate1 = acos((p1.z - p2.z) / dist);
586     if (p1.z - p2.z > dist)
587         muscles[which].rotate1 = acos(1.f);
588     muscles[which].rotate1 *= 360.0 / 6.2831853;
589     if (p1.x > p2.x)
590         muscles[which].rotate1 = 360 - muscles[which].rotate1;
591     if (!isnormal(muscles[which].rotate1))
592         muscles[which].rotate1 = 0;
593     if (!isnormal(muscles[which].rotate2))
594         muscles[which].rotate2 = 0;
595
596     const int label1 = muscles[which].parent1->label;
597     const int label2 = muscles[which].parent2->label;
598     switch (label1) {
599     case head:
600         fwd = specialforward[0];
601         break;
602     case rightshoulder:
603     case rightelbow:
604     case rightwrist:
605     case righthand:
606         fwd = specialforward[1];
607         break;
608     case leftshoulder:
609     case leftelbow:
610     case leftwrist:
611     case lefthand:
612         fwd = specialforward[2];
613         break;
614     case righthip:
615     case rightknee:
616     case rightankle:
617     case rightfoot:
618         fwd = specialforward[3];
619         break;
620     case lefthip:
621     case leftknee:
622     case leftankle:
623     case leftfoot:
624         fwd = specialforward[4];
625         break;
626     default:
627         if (muscles[which].parent1->lower)
628             fwd = lowforward;
629         else
630             fwd = forward;
631         break;
632     }
633
634     if (animation == hanganim) {
635         if (label1 == righthand || label2 == righthand) {
636             fwd = 0;
637             fwd.x = -1;
638         }
639         if (label1 == lefthand || label2 == lefthand) {
640             fwd = 0;
641             fwd.x = 1;
642         }
643     }
644
645     if (free == 0) {
646         if (label1 == rightfoot || label2 == rightfoot) {
647             fwd.y -= .3;
648         }
649         if (label1 == leftfoot || label2 == leftfoot) {
650             fwd.y -= .3;
651         }
652     }
653
654     fwd = DoRotation(fwd, 0, muscles[which].rotate1 - 90, 0);
655     fwd = DoRotation(fwd, 0, 0, muscles[which].rotate2 - 90);
656     fwd.y = 0;
657     fwd /= findLength(&fwd);
658     if (fwd.z <= 1 && fwd.z >= -1)
659         muscles[which].rotate3 = acos(0 - fwd.z);
660     else
661         muscles[which].rotate3 = acos(-1.f);
662     muscles[which].rotate3 *= 360.0 / 6.2831853;
663     if (0 > fwd.x)
664         muscles[which].rotate3 = 360 - muscles[which].rotate3;
665     if (!isnormal(muscles[which].rotate3))
666         muscles[which].rotate3 = 0;
667 }
668
669 /* EFFECT
670  * load an animation from file
671  */
672 void Animation::Load(const std::string& filename, int aheight, int aattack)
673 {
674     FILE *tfile;
675     int i, j;
676     XYZ endoffset;
677
678     LOGFUNC;
679
680     // Changing the filename into something the OS can understand
681     std::string filepath = Folders::getResourcePath("Animations/"+filename);
682
683     LOG(std::string("Loading animation...") + filepath);
684
685     // clear existing data
686     deallocate();
687
688     height = aheight;
689     attack = aattack;
690
691     if (visibleloading)
692         Game::LoadingScreen();
693
694     // read file in binary mode
695     tfile = fopen( filepath.c_str(), "rb" );
696     if (tfile) {
697         // read numframes, joints to know how much memory to allocate
698         funpackf(tfile, "Bi Bi", &numframes, &joints);
699
700         // allocate memory for everything
701
702         position = (XYZ**)malloc(sizeof(XYZ*) * joints);
703         for (i = 0; i < joints; i++)
704             position[i] = (XYZ*)malloc(sizeof(XYZ) * numframes);
705
706         twist = (float**)malloc(sizeof(float*) * joints);
707         for (i = 0; i < joints; i++)
708             twist[i] = (float*)malloc(sizeof(float) * numframes);
709
710         twist2 = (float**)malloc(sizeof(float*) * joints);
711         for (i = 0; i < joints; i++)
712             twist2[i] = (float*)malloc(sizeof(float) * numframes);
713
714         speed = (float*)malloc(sizeof(float) * numframes);
715
716         onground = (bool**)malloc(sizeof(bool*) * joints);
717         for (i = 0; i < joints; i++)
718             onground[i] = (bool*)malloc(sizeof(bool) * numframes);
719
720         forward = (XYZ*)malloc(sizeof(XYZ) * numframes);
721         weapontarget = (XYZ*)malloc(sizeof(XYZ) * numframes);
722         label = (int*)malloc(sizeof(int) * numframes);
723
724         // read binary data as animation
725
726         // for each frame...
727         for (i = 0; i < numframes; i++) {
728             // for each joint in the skeleton...
729             for (j = 0; j < joints; j++) {
730                 // read joint position
731                 funpackf(tfile, "Bf Bf Bf", &position[j][i].x, &position[j][i].y, &position[j][i].z);
732             }
733             for (j = 0; j < joints; j++) {
734                 // read twist
735                 funpackf(tfile, "Bf", &twist[j][i]);
736             }
737             for (j = 0; j < joints; j++) {
738                 // read onground (boolean)
739                 unsigned char uch;
740                 funpackf(tfile, "Bb", &uch);
741                 onground[j][i] = (uch != 0);
742             }
743             // read frame speed (?)
744             funpackf(tfile, "Bf", &speed[i]);
745         }
746         // read twist2 for whole animation
747         for (i = 0; i < numframes; i++) {
748             for (j = 0; j < joints; j++) {
749                 funpackf(tfile, "Bf", &twist2[j][i]);
750             }
751         }
752         // read label for each frame
753         for (i = 0; i < numframes; i++) {
754             funpackf(tfile, "Bf", &label[i]);
755         }
756         // read weapontargetnum
757         funpackf(tfile, "Bi", &weapontargetnum);
758         // read weapontarget positions for each frame
759         for (i = 0; i < numframes; i++) {
760             funpackf(tfile, "Bf Bf Bf", &weapontarget[i].x, &weapontarget[i].y, &weapontarget[i].z);
761         }
762
763         fclose(tfile);
764     }
765
766     endoffset = 0;
767     // find average position of certain joints on last frames
768     // and save in endoffset
769     // (not sure what exactly this accomplishes. the y < 1 test confuses me.)
770     for (j = 0; j < joints; j++) {
771         if (position[j][numframes - 1].y < 1)
772             endoffset += position[j][numframes - 1];
773     }
774     endoffset /= joints;
775     offset = endoffset;
776     offset.y = 0;
777 }
778
779
780 /* EFFECT
781  * load skeleton
782  * takes filenames for three skeleton files and various models
783  */
784 void Skeleton::Load(const char *filename,       const char *lowfilename, const char *clothesfilename,
785                     const char *modelfilename,  const char *model2filename,
786                     const char *model3filename, const char *model4filename,
787                     const char *model5filename, const char *model6filename,
788                     const char *model7filename, const char *modellowfilename,
789                     const char *modelclothesfilename, bool clothes)
790 {
791     GLfloat M[16];
792     int parentID;
793     FILE *tfile;
794     float lSize;
795     int i, j;
796     int edit;
797
798     LOGFUNC;
799
800     num_models = 7;
801
802     // load various models
803     // rotate, scale, do normals, do texcoords for each as needed
804
805     model[0].loadnotex(modelfilename);
806     model[1].loadnotex(model2filename);
807     model[2].loadnotex(model3filename);
808     model[3].loadnotex(model4filename);
809     model[4].loadnotex(model5filename);
810     model[5].loadnotex(model6filename);
811     model[6].loadnotex(model7filename);
812
813     for (i = 0; i < num_models; i++) {
814         model[i].Rotate(180, 0, 0);
815         model[i].Scale(.04, .04, .04);
816         model[i].CalculateNormals(0);
817     }
818
819     drawmodel.load(modelfilename, 0);
820     drawmodel.Rotate(180, 0, 0);
821     drawmodel.Scale(.04, .04, .04);
822     drawmodel.FlipTexCoords();
823     if (tutoriallevel == 1 && id != 0)
824         drawmodel.UniformTexCoords();
825     if (tutoriallevel == 1 && id != 0)
826         drawmodel.ScaleTexCoords(0.1);
827     drawmodel.CalculateNormals(0);
828
829     modellow.loadnotex(modellowfilename);
830     modellow.Rotate(180, 0, 0);
831     modellow.Scale(.04, .04, .04);
832     modellow.CalculateNormals(0);
833
834     drawmodellow.load(modellowfilename, 0);
835     drawmodellow.Rotate(180, 0, 0);
836     drawmodellow.Scale(.04, .04, .04);
837     drawmodellow.FlipTexCoords();
838     if (tutoriallevel == 1 && id != 0)
839         drawmodellow.UniformTexCoords();
840     if (tutoriallevel == 1 && id != 0)
841         drawmodellow.ScaleTexCoords(0.1);
842     drawmodellow.CalculateNormals(0);
843
844     if (clothes) {
845         modelclothes.loadnotex(modelclothesfilename);
846         modelclothes.Rotate(180, 0, 0);
847         modelclothes.Scale(.041, .04, .041);
848         modelclothes.CalculateNormals(0);
849
850         drawmodelclothes.load(modelclothesfilename, 0);
851         drawmodelclothes.Rotate(180, 0, 0);
852         drawmodelclothes.Scale(.04, .04, .04);
853         drawmodelclothes.FlipTexCoords();
854         drawmodelclothes.CalculateNormals(0);
855     }
856
857     // FIXME: three similar blocks follow, one for each of:
858     // filename, lowfilename, clothesfilename
859
860     // load skeleton
861
862     tfile = fopen( Folders::getResourcePath(filename).c_str(), "rb" );
863
864     if (1) { // FIXME: should this be if(tfile) ?
865         // read num_joints
866         funpackf(tfile, "Bi", &num_joints);
867
868         // allocate memory
869         if (joints)
870             delete [] joints; //dealloc2(joints);
871         joints = (Joint*)new Joint[num_joints];
872
873         // read info for each joint
874         for (i = 0; i < num_joints; i++) {
875             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);
876             funpackf(tfile, "Bb Bb", &joints[i].hasparent, &joints[i].locked);
877             funpackf(tfile, "Bi", &joints[i].modelnum);
878             funpackf(tfile, "Bb Bb", &joints[i].visible, &joints[i].sametwist);
879             funpackf(tfile, "Bi Bi", &joints[i].label, &joints[i].hasgun);
880             funpackf(tfile, "Bb", &joints[i].lower);
881             funpackf(tfile, "Bi", &parentID);
882             if (joints[i].hasparent)
883                 joints[i].parent = &joints[parentID];
884             joints[i].velocity = 0;
885             joints[i].oldposition = joints[i].position;
886         }
887
888         // read num_muscles
889         funpackf(tfile, "Bi", &num_muscles);
890
891         // allocate memory
892         if (muscles)
893             delete [] muscles; //dealloc2(muscles);
894         muscles = (Muscle*)new Muscle[num_muscles]; //malloc(sizeof(Muscle)*num_muscles);
895
896         // for each muscle...
897         for (i = 0; i < num_muscles; i++) {
898             // read info
899             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);
900
901             // allocate memory for vertices
902             muscles[i].vertices = (int*)malloc(sizeof(int) * muscles[i].numvertices);
903
904             // read vertices
905             edit = 0;
906             for (j = 0; j < muscles[i].numvertices - edit; j++) {
907                 funpackf(tfile, "Bi", &muscles[i].vertices[j + edit]);
908                 if (muscles[i].vertices[j + edit] >= model[0].vertexNum) {
909                     muscles[i].numvertices--;
910                     edit--;
911                 }
912             }
913
914             // read more info
915             funpackf(tfile, "Bb Bi", &muscles[i].visible, &parentID);
916             muscles[i].parent1 = &joints[parentID];
917             funpackf(tfile, "Bi", &parentID);
918             muscles[i].parent2 = &joints[parentID];
919         }
920
921         // read forwardjoints (?)
922         for (j = 0; j < 3; j++) {
923             funpackf(tfile, "Bi", &forwardjoints[j]);
924         }
925         // read lowforwardjoints (?)
926         for (j = 0; j < 3; j++) {
927             funpackf(tfile, "Bi", &lowforwardjoints[j]);
928         }
929
930         // ???
931         for (j = 0; j < num_muscles; j++) {
932             for (i = 0; i < muscles[j].numvertices; i++) {
933                 for (int k = 0; k < num_models; k++) {
934                     if (muscles[j].numvertices && muscles[j].vertices[i] < model[k].vertexNum)
935                         model[k].owner[muscles[j].vertices[i]] = j;
936                 }
937             }
938         }
939
940         // calculate some stuff
941         FindForwards();
942         for (i = 0; i < num_joints; i++) {
943             joints[i].startpos = joints[i].position;
944         }
945         for (i = 0; i < num_muscles; i++) {
946             FindRotationMuscle(i, -1);
947         }
948         // this seems to use opengl purely for matrix calculations
949         for (int k = 0; k < num_models; k++) {
950             for (i = 0; i < model[k].vertexNum; i++) {
951                 model[k].vertex[i] = model[k].vertex[i] - (muscles[model[k].owner[i]].parent1->position + muscles[model[k].owner[i]].parent2->position) / 2;
952                 glMatrixMode(GL_MODELVIEW);
953                 glPushMatrix();
954                 glLoadIdentity();
955                 glRotatef(muscles[model[k].owner[i]].rotate3, 0, 1, 0);
956                 glRotatef(muscles[model[k].owner[i]].rotate2 - 90, 0, 0, 1);
957                 glRotatef(muscles[model[k].owner[i]].rotate1 - 90, 0, 1, 0);
958                 glTranslatef(model[k].vertex[i].x, model[k].vertex[i].y, model[k].vertex[i].z);
959                 glGetFloatv(GL_MODELVIEW_MATRIX, M);
960                 model[k].vertex[i].x = M[12] * 1;
961                 model[k].vertex[i].y = M[13] * 1;
962                 model[k].vertex[i].z = M[14] * 1;
963                 glPopMatrix();
964             }
965             model[k].CalculateNormals(0);
966         }
967     }
968     fclose(tfile);
969
970     // load ???
971
972     tfile = fopen( Folders::getResourcePath(lowfilename).c_str(), "rb" );
973
974     if (1) { // FIXME: should this be if(tfile) ?
975         // skip joints section
976
977         lSize = sizeof(num_joints);
978         fseek(tfile, lSize, SEEK_CUR);
979         for (i = 0; i < num_joints; i++) {
980             // skip joint info
981             lSize = sizeof(XYZ)
982                     + sizeof(float)
983                     + sizeof(float)
984                     + 1 //sizeof(bool)
985                     + 1 //sizeof(bool)
986                     + sizeof(int)
987                     + 1 //sizeof(bool)
988                     + 1 //sizeof(bool)
989                     + sizeof(int)
990                     + sizeof(int)
991                     + 1 //sizeof(bool)
992                     + sizeof(int);
993             fseek(tfile, lSize, SEEK_CUR);
994
995             if (joints[i].hasparent)
996                 joints[i].parent = &joints[parentID];
997             joints[i].velocity = 0;
998             joints[i].oldposition = joints[i].position;
999         }
1000
1001         // read num_muscles
1002         funpackf(tfile, "Bi", &num_muscles);
1003
1004         for (i = 0; i < num_muscles; i++) {
1005             // skip muscle info
1006             lSize = sizeof(float)
1007                     + sizeof(float)
1008                     + sizeof(float)
1009                     + sizeof(float)
1010                     + sizeof(float)
1011                     + sizeof(int);
1012             fseek(tfile, lSize, SEEK_CUR);
1013
1014             // read numverticeslow
1015             funpackf(tfile, "Bi", &muscles[i].numverticeslow);
1016
1017             if (muscles[i].numverticeslow) {
1018                 // allocate memory
1019                 muscles[i].verticeslow = (int*)malloc(sizeof(int) * muscles[i].numverticeslow);
1020
1021                 // read verticeslow
1022                 edit = 0;
1023                 for (j = 0; j < muscles[i].numverticeslow - edit; j++) {
1024                     funpackf(tfile, "Bi", &muscles[i].verticeslow[j + edit]);
1025                     if (muscles[i].verticeslow[j + edit] >= modellow.vertexNum) {
1026                         muscles[i].numverticeslow--;
1027                         edit--;
1028                     }
1029                 }
1030             }
1031
1032             // skip more stuff
1033             lSize = 1; //sizeof(bool);
1034             fseek ( tfile, lSize, SEEK_CUR);
1035             lSize = sizeof(int);
1036             fseek ( tfile, lSize, SEEK_CUR);
1037             fseek ( tfile, lSize, SEEK_CUR);
1038         }
1039
1040         for (j = 0; j < num_muscles; j++) {
1041             for (i = 0; i < muscles[j].numverticeslow; i++) {
1042                 if (muscles[j].verticeslow[i] < modellow.vertexNum)
1043                     modellow.owner[muscles[j].verticeslow[i]] = j;
1044             }
1045         }
1046
1047         // use opengl for its matrix math
1048         for (i = 0; i < modellow.vertexNum; i++) {
1049             modellow.vertex[i] = modellow.vertex[i] - (muscles[modellow.owner[i]].parent1->position + muscles[modellow.owner[i]].parent2->position) / 2;
1050             glMatrixMode(GL_MODELVIEW);
1051             glPushMatrix();
1052             glLoadIdentity();
1053             glRotatef(muscles[modellow.owner[i]].rotate3, 0, 1, 0);
1054             glRotatef(muscles[modellow.owner[i]].rotate2 - 90, 0, 0, 1);
1055             glRotatef(muscles[modellow.owner[i]].rotate1 - 90, 0, 1, 0);
1056             glTranslatef(modellow.vertex[i].x, modellow.vertex[i].y, modellow.vertex[i].z);
1057             glGetFloatv(GL_MODELVIEW_MATRIX, M);
1058             modellow.vertex[i].x = M[12];
1059             modellow.vertex[i].y = M[13];
1060             modellow.vertex[i].z = M[14];
1061             glPopMatrix();
1062         }
1063
1064         modellow.CalculateNormals(0);
1065     }
1066
1067     // load clothes
1068
1069     if (clothes) {
1070         tfile = fopen( Folders::getResourcePath(clothesfilename).c_str(), "rb" ); // FIXME: where's the check for valid load
1071
1072         // skip num_joints
1073         lSize = sizeof(num_joints);
1074         fseek ( tfile, lSize, SEEK_CUR);
1075
1076         for (i = 0; i < num_joints; i++) {
1077             // skip joint info
1078             lSize = sizeof(XYZ)
1079                     + sizeof(float)
1080                     + sizeof(float)
1081                     + 1 //sizeof(bool)
1082                     + 1 //sizeof(bool)
1083                     + sizeof(int)
1084                     + 1 //sizeof(bool)
1085                     + 1 //sizeof(bool)
1086                     + sizeof(int)
1087                     + sizeof(int)
1088                     + 1 //sizeof(bool)
1089                     + sizeof(int);
1090             fseek(tfile, lSize, SEEK_CUR);
1091
1092             if (joints[i].hasparent)
1093                 joints[i].parent = &joints[parentID];
1094             joints[i].velocity = 0;
1095             joints[i].oldposition = joints[i].position;
1096         }
1097
1098         // read num_muscles
1099         funpackf(tfile, "Bi", &num_muscles);
1100
1101         for (i = 0; i < num_muscles; i++) {
1102             // skip muscle info
1103             lSize = sizeof(float)
1104                     + sizeof(float)
1105                     + sizeof(float)
1106                     + sizeof(float)
1107                     + sizeof(float)
1108                     + sizeof(int);
1109             fseek(tfile, lSize, SEEK_CUR);
1110
1111             // read numverticesclothes
1112             funpackf(tfile, "Bi", &muscles[i].numverticesclothes);
1113
1114             // read verticesclothes
1115             if (muscles[i].numverticesclothes) {
1116                 muscles[i].verticesclothes = (int*)malloc(sizeof(int) * muscles[i].numverticesclothes);
1117                 edit = 0;
1118                 for (j = 0; j < muscles[i].numverticesclothes - edit; j++) {
1119                     funpackf(tfile, "Bi", &muscles[i].verticesclothes[j + edit]);
1120                     if (muscles[i].verticesclothes[j + edit] >= modelclothes.vertexNum) {
1121                         muscles[i].numverticesclothes--;
1122                         edit--;
1123                     }
1124                 }
1125             }
1126
1127             // skip more stuff
1128             lSize = 1; //sizeof(bool);
1129             fseek ( tfile, lSize, SEEK_CUR);
1130             lSize = sizeof(int);
1131             fseek ( tfile, lSize, SEEK_CUR);
1132             fseek ( tfile, lSize, SEEK_CUR);
1133         }
1134
1135         // ???
1136         lSize = sizeof(int);
1137         for (j = 0; j < num_muscles; j++) {
1138             for (i = 0; i < muscles[j].numverticesclothes; i++) {
1139                 if (muscles[j].numverticesclothes && muscles[j].verticesclothes[i] < modelclothes.vertexNum)
1140                     modelclothes.owner[muscles[j].verticesclothes[i]] = j;
1141             }
1142         }
1143
1144         // use opengl for its matrix math
1145         for (i = 0; i < modelclothes.vertexNum; i++) {
1146             modelclothes.vertex[i] = modelclothes.vertex[i] - (muscles[modelclothes.owner[i]].parent1->position + muscles[modelclothes.owner[i]].parent2->position) / 2;
1147             glMatrixMode(GL_MODELVIEW);
1148             glPushMatrix();
1149             glLoadIdentity();
1150             glRotatef(muscles[modelclothes.owner[i]].rotate3, 0, 1, 0);
1151             glRotatef(muscles[modelclothes.owner[i]].rotate2 - 90, 0, 0, 1);
1152             glRotatef(muscles[modelclothes.owner[i]].rotate1 - 90, 0, 1, 0);
1153             glTranslatef(modelclothes.vertex[i].x, modelclothes.vertex[i].y, modelclothes.vertex[i].z);
1154             glGetFloatv(GL_MODELVIEW_MATRIX, M);
1155             modelclothes.vertex[i].x = M[12];
1156             modelclothes.vertex[i].y = M[13];
1157             modelclothes.vertex[i].z = M[14];
1158             glPopMatrix();
1159         }
1160
1161         modelclothes.CalculateNormals(0);
1162     }
1163     fclose(tfile);
1164
1165     for (i = 0; i < num_joints; i++) {
1166         for (j = 0; j < num_joints; j++) {
1167             if (joints[i].label == j)
1168                 jointlabels[j] = i;
1169         }
1170     }
1171
1172     free = 0;
1173 }
1174
1175 Animation::Animation()
1176 {
1177     numframes = 0;
1178     height = 0;
1179     attack = 0;
1180     joints = 0;
1181     weapontargetnum = 0;
1182
1183     position = 0;
1184     twist = 0;
1185     twist2 = 0;
1186     speed = 0;
1187     onground = 0;
1188     forward = 0;
1189     label = 0;
1190     weapontarget = 0;
1191 }
1192
1193 Animation::~Animation()
1194 {
1195     deallocate();
1196 }
1197
1198 void Animation::deallocate()
1199 {
1200     int i = 0;
1201
1202     if (position) {
1203         for (i = 0; i < joints; i++)
1204             dealloc2(position[i]);
1205
1206         dealloc2(position);
1207     }
1208     position = 0;
1209
1210     if (twist) {
1211         for (i = 0; i < joints; i++)
1212             dealloc2(twist[i]);
1213
1214         dealloc2(twist);
1215     }
1216     twist = 0;
1217
1218     if (twist2) {
1219         for (i = 0; i < joints; i++)
1220             dealloc2(twist2[i]);
1221
1222         dealloc2(twist2);
1223     }
1224     twist2 = 0;
1225
1226     if (onground) {
1227         for (i = 0; i < joints; i++)
1228             dealloc2(onground[i]);
1229
1230         dealloc2(onground);
1231     }
1232     onground = 0;
1233
1234     if (speed)
1235         dealloc2(speed);
1236     speed = 0;
1237
1238     if (forward)
1239         dealloc2(forward);
1240     forward = 0;
1241
1242     if (weapontarget)
1243         dealloc2(weapontarget);
1244     weapontarget = 0;
1245
1246     if (label)
1247         dealloc2(label);
1248     label = 0;
1249
1250     joints = 0;
1251 }
1252
1253 Skeleton::Skeleton()
1254 {
1255     num_joints = 0;
1256
1257     num_muscles = 0;
1258
1259     selected = 0;
1260
1261     memset(forwardjoints, 0, sizeof(forwardjoints));
1262     // XYZ forward;
1263
1264     id = 0;
1265
1266     memset(lowforwardjoints, 0, sizeof(lowforwardjoints));
1267     // XYZ lowforward;
1268
1269     // XYZ specialforward[5];
1270     memset(jointlabels, 0, sizeof(jointlabels));
1271
1272     // Model model[7];
1273     // Model modellow;
1274     // Model modelclothes;
1275     num_models = 0;
1276
1277     // Model drawmodel;
1278     // Model drawmodellow;
1279     // Model drawmodelclothes;
1280
1281     clothes = 0;
1282     spinny = 0;
1283
1284     memset(skinText, 0, sizeof(skinText));
1285     skinsize = 0;
1286
1287     checkdelay = 0;
1288
1289     longdead = 0;
1290     broken = 0;
1291
1292     free = 0;
1293     oldfree = 0;
1294     freetime = 0;
1295     freefall = 0;
1296
1297     joints = 0;
1298     muscles = 0;
1299 }
1300
1301 Skeleton::~Skeleton()
1302 {
1303     if (muscles) {
1304         delete [] muscles;
1305     }
1306     muscles = 0;
1307
1308     if (joints) {
1309         delete [] joints;
1310     }
1311     joints = 0;
1312 }
1313
1314 Muscle::Muscle()
1315 {
1316     vertices = 0;
1317     verticeslow = 0;
1318     verticesclothes = 0;
1319
1320     numvertices = 0;
1321     numverticeslow = 0;
1322     numverticesclothes = 0;
1323     length = 0;
1324     targetlength = 0;
1325     parent1 = 0;
1326     parent2 = 0;
1327     maxlength = 0;
1328     minlength = 0;
1329     type = 0;
1330     visible = 0;
1331     rotate1 = 0, rotate2 = 0, rotate3 = 0;
1332     lastrotate1 = 0, lastrotate2 = 0, lastrotate3 = 0;
1333     oldrotate1 = 0, oldrotate2 = 0, oldrotate3 = 0;
1334     newrotate1 = 0, newrotate2 = 0, newrotate3 = 0;
1335
1336     strength = 0;
1337 }
1338
1339 Muscle::~Muscle()
1340 {
1341     dealloc2(vertices);
1342     dealloc2(verticeslow);
1343     dealloc2(verticesclothes);
1344 }
1345
1346 Animation & Animation::operator = (const Animation & ani)
1347 {
1348     int i = 0;
1349
1350     bool allocate = ((ani.numframes != numframes) || (ani.joints != joints));
1351
1352     if (allocate)
1353         deallocate();
1354
1355     numframes = ani.numframes;
1356     height = ani.height;
1357     attack = ani.attack;
1358     joints = ani.joints;
1359     weapontargetnum = ani.weapontargetnum;
1360     offset = ani.offset;
1361
1362     if (allocate)
1363         position = (XYZ**)malloc(sizeof(XYZ*)*ani.joints);
1364     for (i = 0; i < ani.joints; i++) {
1365         if (allocate)
1366             position[i] = (XYZ*)malloc(sizeof(XYZ) * ani.numframes);
1367         memcpy(position[i], ani.position[i], sizeof(XYZ)*ani.numframes);
1368     }
1369
1370     if (allocate)
1371         twist = (float**)malloc(sizeof(float*)*ani.joints);
1372     for (i = 0; i < ani.joints; i++) {
1373         if (allocate)
1374             twist[i] = (float*)malloc(sizeof(float) * ani.numframes);
1375         memcpy(twist[i], ani.twist[i], sizeof(float)*ani.numframes);
1376     }
1377
1378     if (allocate)
1379         twist2 = (float**)malloc(sizeof(float*)*ani.joints);
1380     for (i = 0; i < ani.joints; i++) {
1381         if (allocate)
1382             twist2[i] = (float*)malloc(sizeof(float) * ani.numframes);
1383         memcpy(twist2[i], ani.twist2[i], sizeof(float)*ani.numframes);
1384     }
1385
1386     if (allocate)
1387         speed = (float*)malloc(sizeof(float) * ani.numframes);
1388     memcpy(speed, ani.speed, sizeof(float)*ani.numframes);
1389
1390     if (allocate)
1391         onground = (bool**)malloc(sizeof(bool*)*ani.joints);
1392     for (i = 0; i < ani.joints; i++) {
1393         if (allocate)
1394             onground[i] = (bool*)malloc(sizeof(bool) * ani.numframes);
1395         memcpy(onground[i], ani.onground[i], sizeof(bool)*ani.numframes);
1396     }
1397
1398     if (allocate)
1399         forward = (XYZ*)malloc(sizeof(XYZ) * ani.numframes);
1400     memcpy(forward, ani.forward, sizeof(XYZ)*ani.numframes);
1401
1402     if (allocate)
1403         weapontarget = (XYZ*)malloc(sizeof(XYZ) * ani.numframes);
1404     memcpy(weapontarget, ani.weapontarget, sizeof(XYZ)*ani.numframes);
1405
1406     if (allocate)
1407         label = (int*)malloc(sizeof(int) * ani.numframes);
1408     memcpy(label, ani.label, sizeof(int)*ani.numframes);
1409
1410     return (*this);
1411 }
1412
1413
1414
1415
1416 #if 0
1417
1418 // the following functions are not used anywhere
1419
1420 /* EFFECT
1421  * sets forward, lowforward, specialforward[]
1422  *
1423  * USES:
1424  * NONE
1425  */
1426 void Skeleton::FindForwardsfirst()
1427 {
1428     //Find forward vectors
1429     CrossProduct(joints[forwardjoints[1]].position - joints[forwardjoints[0]].position, joints[forwardjoints[2]].position - joints[forwardjoints[0]].position, &forward);
1430     Normalise(&forward);
1431
1432     CrossProduct(joints[lowforwardjoints[1]].position - joints[lowforwardjoints[0]].position, joints[lowforwardjoints[2]].position - joints[lowforwardjoints[0]].position, &lowforward);
1433     Normalise(&lowforward);
1434
1435     //Special forwards
1436     specialforward[0] = forward;
1437     specialforward[1] = forward;
1438     specialforward[2] = forward;
1439     specialforward[3] = forward;
1440     specialforward[4] = forward;
1441
1442 }
1443
1444 /* EFFECT
1445  *
1446  * USES:
1447  * NONE
1448  */
1449 void Skeleton::Draw(int muscleview)
1450 {
1451     static float jointcolor[4];
1452
1453     if (muscleview != 2) {
1454         jointcolor[0] = 0;
1455         jointcolor[1] = 0;
1456         jointcolor[2] = .5;
1457         jointcolor[3] = 1;
1458     }
1459
1460     if (muscleview == 2) {
1461         jointcolor[0] = 0;
1462         jointcolor[1] = 0;
1463         jointcolor[2] = 0;
1464         jointcolor[3] = .5;
1465     }
1466     //Calc motionblur-ness
1467     for (int i = 0; i < num_joints; i++) {
1468         joints[i].oldposition = joints[i].position;
1469         joints[i].blurred = findDistance(&joints[i].position, &joints[i].oldposition) * 100;
1470         if (joints[i].blurred < 1)
1471             joints[i].blurred = 1;
1472     }
1473
1474     //Do Motionblur
1475     glDepthMask(0);
1476     glEnable(GL_BLEND);
1477     glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1478     glBegin(GL_QUADS);
1479     for (int i = 0; i < num_joints; i++) {
1480         if (joints[i].hasparent) {
1481             glColor4f(jointcolor[0], jointcolor[1], jointcolor[2], jointcolor[3] / joints[i].blurred);
1482             glVertex3f(joints[i].position.x, joints[i].position.y, joints[i].position.z);
1483             glColor4f(jointcolor[0], jointcolor[1], jointcolor[2], jointcolor[3] / joints[i].parent->blurred);
1484             glVertex3f(joints[i].parent->position.x, joints[i].parent->position.y, joints[i].parent->position.z);
1485             glColor4f(jointcolor[0], jointcolor[1], jointcolor[2], jointcolor[3] / joints[i].parent->blurred);
1486             glVertex3f(joints[i].parent->oldposition.x, joints[i].parent->oldposition.y, joints[i].parent->oldposition.z);
1487             glColor4f(jointcolor[0], jointcolor[1], jointcolor[2], jointcolor[3] / joints[i].blurred);
1488             glVertex3f(joints[i].oldposition.x, joints[i].oldposition.y, joints[i].oldposition.z);
1489         }
1490     }
1491     for (int i = 0; i < num_muscles; i++) {
1492         if (muscles[i].type == boneconnect) {
1493             glColor4f(jointcolor[0], jointcolor[1], jointcolor[2], jointcolor[3] / muscles[i].parent2->blurred);
1494             glVertex3f(muscles[i].parent1->position.x, muscles[i].parent1->position.y, muscles[i].parent1->position.z);
1495             glColor4f(jointcolor[0], jointcolor[1], jointcolor[2], jointcolor[3] / muscles[i].parent2->blurred);
1496             glVertex3f(muscles[i].parent2->position.x, muscles[i].parent2->position.y, muscles[i].parent2->position.z);
1497             glColor4f(jointcolor[0], jointcolor[1], jointcolor[2], jointcolor[3] / muscles[i].parent2->blurred);
1498             glVertex3f(muscles[i].parent2->oldposition.x, muscles[i].parent2->oldposition.y, muscles[i].parent2->oldposition.z);
1499             glColor4f(jointcolor[0], jointcolor[1], jointcolor[2], jointcolor[3] / muscles[i].parent1->blurred);
1500             glVertex3f(muscles[i].parent1->oldposition.x, muscles[i].parent1->oldposition.y, muscles[i].parent1->oldposition.z);
1501         }
1502     }
1503     glEnd();
1504
1505     glBegin(GL_LINES);
1506     for (int i = 0; i < num_joints; i++) {
1507         if (joints[i].hasparent) {
1508             glColor4f(jointcolor[0], jointcolor[1], jointcolor[2], jointcolor[3] / joints[i].blurred);
1509             glVertex3f(joints[i].position.x, joints[i].position.y, joints[i].position.z);
1510             glColor4f(jointcolor[0], jointcolor[1], jointcolor[2], jointcolor[3] / joints[i].parent->blurred);
1511             glVertex3f(joints[i].parent->position.x, joints[i].parent->position.y, joints[i].parent->position.z);
1512         }
1513     }
1514     for (int i = 0; i < num_muscles; i++) {
1515         if (muscles[i].type == boneconnect) {
1516             glColor4f(jointcolor[0], jointcolor[1], jointcolor[2], jointcolor[3] / muscles[i].parent1->blurred);
1517             glVertex3f(muscles[i].parent1->position.x, muscles[i].parent1->position.y, muscles[i].parent1->position.z);
1518             glColor4f(jointcolor[0], jointcolor[1], jointcolor[2], jointcolor[3] / muscles[i].parent2->blurred);
1519             glVertex3f(muscles[i].parent2->position.x, muscles[i].parent2->position.y, muscles[i].parent2->position.z);
1520         }
1521     }
1522     glColor3f(.6, .6, 0);
1523     if (muscleview == 1)
1524         for (int i = 0; i < num_muscles; i++) {
1525             if (muscles[i].type != boneconnect) {
1526                 glVertex3f(muscles[i].parent1->position.x, muscles[i].parent1->position.y, muscles[i].parent1->position.z);
1527                 glVertex3f(muscles[i].parent2->position.x, muscles[i].parent2->position.y, muscles[i].parent2->position.z);
1528             }
1529         }
1530     glEnd();
1531
1532     if (muscleview != 2) {
1533         glPointSize(3);
1534         glBegin(GL_POINTS);
1535         for (int i = 0; i < num_joints; i++) {
1536             if (i != selected)
1537                 glColor4f(0, 0, .5, 1);
1538             if (i == selected)
1539                 glColor4f(1, 1, 0, 1);
1540             if (joints[i].locked && i != selected)
1541                 glColor4f(1, 0, 0, 1);
1542             glVertex3f(joints[i].position.x, joints[i].position.y, joints[i].position.z);
1543         }
1544         glEnd();
1545     }
1546
1547     //Set old position to current position
1548     if (muscleview == 2)
1549         for (int i = 0; i < num_joints; i++) {
1550             joints[i].oldposition = joints[i].position;
1551         }
1552     glDepthMask(1);
1553 }
1554
1555 /* EFFECT
1556  *
1557  * USES:
1558  * NONE
1559  */
1560 void Skeleton::AddJoint(float x, float y, float z, int which)
1561 {
1562     if (num_joints < max_joints - 1) {
1563         joints[num_joints].velocity = 0;
1564         joints[num_joints].position.x = x;
1565         joints[num_joints].position.y = y;
1566         joints[num_joints].position.z = z;
1567         joints[num_joints].mass = 1;
1568         joints[num_joints].locked = 0;
1569
1570         joints[num_joints].hasparent = 0;
1571         num_joints++;
1572         if (which < num_joints && which >= 0)
1573             AddMuscle(num_joints - 1, which, 0, 10, boneconnect);
1574     }
1575 }
1576
1577 /* EFFECT
1578  *
1579  * USES:
1580  * NONE
1581  */
1582 void Skeleton::DeleteJoint(int whichjoint)
1583 {
1584     if (whichjoint < num_joints && whichjoint >= 0) {
1585         joints[whichjoint].velocity = joints[num_joints - 1].velocity;
1586         joints[whichjoint].position = joints[num_joints - 1].position;
1587         joints[whichjoint].oldposition = joints[num_joints - 1].oldposition;
1588         joints[whichjoint].hasparent = joints[num_joints - 1].hasparent;
1589         joints[whichjoint].parent = joints[num_joints - 1].parent;
1590         joints[whichjoint].length = joints[num_joints - 1].length;
1591         joints[whichjoint].locked = joints[num_joints - 1].locked;
1592         joints[whichjoint].modelnum = joints[num_joints - 1].modelnum;
1593         joints[whichjoint].visible = joints[num_joints - 1].visible;
1594
1595         for (int i = 0; i < num_muscles; i++) {
1596             while (muscles[i].parent1 == &joints[whichjoint] && i < num_muscles)DeleteMuscle(i);
1597             while (muscles[i].parent2 == &joints[whichjoint] && i < num_muscles)DeleteMuscle(i);
1598         }
1599         for (int i = 0; i < num_muscles; i++) {
1600             while (muscles[i].parent1 == &joints[num_joints - 1] && i < num_muscles)muscles[i].parent1 = &joints[whichjoint];
1601             while (muscles[i].parent2 == &joints[num_joints - 1] && i < num_muscles)muscles[i].parent2 = &joints[whichjoint];
1602         }
1603         for (int i = 0; i < num_joints; i++) {
1604             if (joints[i].parent == &joints[whichjoint])
1605                 joints[i].hasparent = 0;
1606         }
1607         for (int i = 0; i < num_joints; i++) {
1608             if (joints[i].parent == &joints[num_joints - 1])
1609                 joints[i].parent = &joints[whichjoint];
1610         }
1611
1612         num_joints--;
1613     }
1614 }
1615
1616 /* EFFECT
1617  *
1618  * USES:
1619  * Skeleton::DeleteJoint - UNUSED
1620  */
1621 void Skeleton::DeleteMuscle(int whichmuscle)
1622 {
1623     if (whichmuscle < num_muscles) {
1624         muscles[whichmuscle].minlength = muscles[num_muscles - 1].minlength;
1625         muscles[whichmuscle].maxlength = muscles[num_muscles - 1].maxlength;
1626         muscles[whichmuscle].strength = muscles[num_muscles - 1].strength;
1627         muscles[whichmuscle].parent1 = muscles[num_muscles - 1].parent1;
1628         muscles[whichmuscle].parent2 = muscles[num_muscles - 1].parent2;
1629         muscles[whichmuscle].length = muscles[num_muscles - 1].length;
1630         muscles[whichmuscle].visible = muscles[num_muscles - 1].visible;
1631         muscles[whichmuscle].type = muscles[num_muscles - 1].type;
1632         muscles[whichmuscle].targetlength = muscles[num_muscles - 1].targetlength;
1633
1634         num_muscles--;
1635     }
1636 }
1637
1638 /* EFFECT
1639  *
1640  * USES:
1641  * NONE
1642  */
1643 void Skeleton::SetJoint(float x, float y, float z, int which, int whichjoint)
1644 {
1645     if (whichjoint < num_joints) {
1646         joints[whichjoint].velocity = 0;
1647         joints[whichjoint].position.x = x;
1648         joints[whichjoint].position.y = y;
1649         joints[whichjoint].position.z = z;
1650
1651         if (which >= num_joints || which < 0)
1652             joints[whichjoint].hasparent = 0;
1653         if (which < num_joints && which >= 0) {
1654             joints[whichjoint].parent = &joints[which];
1655             joints[whichjoint].hasparent = 1;
1656             joints[whichjoint].length = findDistance(&joints[whichjoint].position, &joints[whichjoint].parent->position);
1657         }
1658     }
1659 }
1660
1661 /* EFFECT
1662  *
1663  * USES:
1664  * Skeleton::AddJoint - UNUSED
1665  */
1666 void Skeleton::AddMuscle(int attach1, int attach2, float minlength, float maxlength, int type)
1667 {
1668     const int max_muscles = 100; // FIXME: Probably can be dropped
1669     if (num_muscles < max_muscles - 1 && attach1 < num_joints && attach1 >= 0 && attach2 < num_joints && attach2 >= 0 && attach1 != attach2) {
1670         muscles[num_muscles].parent1 = &joints[attach1];
1671         muscles[num_muscles].parent2 = &joints[attach2];
1672         muscles[num_muscles].length = findDistance(&muscles[num_muscles].parent1->position, &muscles[num_muscles].parent2->position);
1673         muscles[num_muscles].targetlength = findDistance(&muscles[num_muscles].parent1->position, &muscles[num_muscles].parent2->position);
1674         muscles[num_muscles].strength = .7;
1675         muscles[num_muscles].type = type;
1676         muscles[num_muscles].minlength = minlength;
1677         muscles[num_muscles].maxlength = maxlength;
1678
1679         num_muscles++;
1680     }
1681 }
1682
1683 /* EFFECT
1684  *
1685  * USES:
1686  * NONE
1687  */
1688 void Skeleton::MusclesSet()
1689 {
1690     for (int i = 0; i < num_muscles; i++) {
1691         muscles[i].length = findDistance(&muscles[i].parent1->position, &muscles[i].parent2->position);
1692     }
1693 }
1694
1695 /* EFFECT
1696  *
1697  * USES:
1698  * NONE
1699  */
1700 void Skeleton::DoBalance()
1701 {
1702     /*XYZ newpoint;
1703     newpoint=joints[0].position;
1704     newpoint.x=(joints[2].position.x+joints[4].position.x)/2;
1705     newpoint.z=(joints[2].position.z+joints[4].position.z)/2;
1706     joints[0].velocity=joints[0].velocity+(newpoint-joints[0].position);
1707     //Move child point to within certain distance of parent point
1708     joints[0].position=newpoint;
1709
1710     MusclesSet();*/
1711 }
1712
1713 #endif
1714