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