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