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