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