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