]> git.jsancho.org Git - lugaru.git/blob - Source/Skeleton.cpp
35fb1f795d6fb054c988d6e242a919c38378f8fd
[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, l, 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, tempmuscle;
838
839     int newload;
840     int edit;
841
842     LOGFUNC;
843
844
845     newload = 0;
846
847     num_models = 7;
848
849     // load various models
850     // rotate, scale, do normals, do texcoords for each as needed
851
852     model[0].loadnotex(modelfilename);
853     model[1].loadnotex(model2filename);
854     model[2].loadnotex(model3filename);
855     model[3].loadnotex(model4filename);
856     model[4].loadnotex(model5filename);
857     model[5].loadnotex(model6filename);
858     model[6].loadnotex(model7filename);
859
860     for (i = 0; i < num_models; i++) {
861         model[i].Rotate(180, 0, 0);
862         model[i].Scale(.04, .04, .04);
863         model[i].CalculateNormals(0);
864     }
865
866     drawmodel.load(modelfilename, 0);
867     drawmodel.Rotate(180, 0, 0);
868     drawmodel.Scale(.04, .04, .04);
869     drawmodel.FlipTexCoords();
870     if (tutoriallevel == 1 && id != 0)
871         drawmodel.UniformTexCoords();
872     if (tutoriallevel == 1 && id != 0)
873         drawmodel.ScaleTexCoords(0.1);
874     drawmodel.CalculateNormals(0);
875
876     modellow.loadnotex(modellowfilename);
877     modellow.Rotate(180, 0, 0);
878     modellow.Scale(.04, .04, .04);
879     modellow.CalculateNormals(0);
880
881     drawmodellow.load(modellowfilename, 0);
882     drawmodellow.Rotate(180, 0, 0);
883     drawmodellow.Scale(.04, .04, .04);
884     drawmodellow.FlipTexCoords();
885     if (tutoriallevel == 1 && id != 0)
886         drawmodellow.UniformTexCoords();
887     if (tutoriallevel == 1 && id != 0)
888         drawmodellow.ScaleTexCoords(0.1);
889     drawmodellow.CalculateNormals(0);
890
891     if (clothes) {
892         modelclothes.loadnotex(modelclothesfilename);
893         modelclothes.Rotate(180, 0, 0);
894         modelclothes.Scale(.041, .04, .041);
895         modelclothes.CalculateNormals(0);
896
897         drawmodelclothes.load(modelclothesfilename, 0);
898         drawmodelclothes.Rotate(180, 0, 0);
899         drawmodelclothes.Scale(.04, .04, .04);
900         drawmodelclothes.FlipTexCoords();
901         drawmodelclothes.CalculateNormals(0);
902     }
903
904     // FIXME: three similar blocks follow, one for each of:
905     // filename, lowfilename, clothesfilename
906
907     // load skeleton
908
909     tfile = fopen( ConvertFileName(filename), "rb" );
910
911     if (1) { // FIXME: should this be if(tfile) ?
912         // read num_joints
913         funpackf(tfile, "Bi", &num_joints);
914
915         // allocate memory
916         //joints.resize(num_joints);
917         if (joints)
918             delete [] joints; //dealloc2(joints);
919         joints = (Joint*)new Joint[num_joints]; //malloc(sizeof(Joint)*num_joints);
920
921         // read info for each joint
922         for (i = 0; i < num_joints; i++) {
923             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);
924             funpackf(tfile, "Bb Bb", &joints[i].hasparent, &joints[i].locked);
925             funpackf(tfile, "Bi", &joints[i].modelnum);
926             funpackf(tfile, "Bb Bb", &joints[i].visible, &joints[i].sametwist);
927             funpackf(tfile, "Bi Bi", &joints[i].label, &joints[i].hasgun);
928             funpackf(tfile, "Bb", &joints[i].lower);
929             funpackf(tfile, "Bi", &parentID);
930             if (joints[i].hasparent)
931                 joints[i].parent = &joints[parentID];
932             joints[i].velocity = 0;
933             joints[i].oldposition = joints[i].position;
934         }
935
936         // read num_muscles
937         tempmuscle = 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         newload = 1;
947
948         // for each muscle...
949         for (i = 0; i < num_muscles; i++) {
950             // read info
951             tempmuscle = muscles[i].numvertices;
952             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);
953
954             // allocate memory for vertices
955             //muscles[i].vertices.clear();
956             //muscles[i].vertices.resize(muscles[i].numvertices);
957             //if(muscles[i].vertices)dealloc2(muscles[i].vertices);
958             muscles[i].vertices = (int*)malloc(sizeof(int) * muscles[i].numvertices);
959
960             // read vertices
961             edit = 0;
962             for (j = 0; j < muscles[i].numvertices - edit; j++) {
963                 funpackf(tfile, "Bi", &muscles[i].vertices[j + edit]);
964                 if (muscles[i].vertices[j + edit] >= model[0].vertexNum) {
965                     muscles[i].numvertices--;
966                     edit--;
967                 }
968             }
969
970             // read more info
971             funpackf(tfile, "Bb Bi", &muscles[i].visible, &parentID);
972             muscles[i].parent1 = &joints[parentID];
973             funpackf(tfile, "Bi", &parentID);
974             muscles[i].parent2 = &joints[parentID];
975         }
976
977         // read forwardjoints (?)
978         for (j = 0; j < 3; j++) {
979             funpackf(tfile, "Bi", &forwardjoints[j]);
980         }
981         // read lowforwardjoints (?)
982         for (j = 0; j < 3; j++) {
983             funpackf(tfile, "Bi", &lowforwardjoints[j]);
984         }
985
986         // ???
987         for (j = 0; j < num_muscles; j++) {
988             for (i = 0; i < muscles[j].numvertices; i++) {
989                 for (int k = 0; k < num_models; k++) {
990                     if (muscles[j].numvertices && muscles[j].vertices[i] < model[k].vertexNum)
991                         model[k].owner[muscles[j].vertices[i]] = j;
992                 }
993             }
994         }
995
996         // calculate some stuff
997         FindForwards();
998         for (i = 0; i < num_joints; i++) {
999             joints[i].startpos = joints[i].position;
1000         }
1001         for (i = 0; i < num_muscles; i++) {
1002             FindRotationMuscle(i, -1);
1003         }
1004         // this seems to use opengl purely for matrix calculations
1005         for (int k = 0; k < num_models; k++) {
1006             for (i = 0; i < model[k].vertexNum; i++) {
1007                 model[k].vertex[i] = model[k].vertex[i] - (muscles[model[k].owner[i]].parent1->position + muscles[model[k].owner[i]].parent2->position) / 2;
1008                 glMatrixMode(GL_MODELVIEW);
1009                 glPushMatrix();
1010                 glLoadIdentity();
1011                 glRotatef(muscles[model[k].owner[i]].rotate3, 0, 1, 0);
1012                 glRotatef(muscles[model[k].owner[i]].rotate2 - 90, 0, 0, 1);
1013                 glRotatef(muscles[model[k].owner[i]].rotate1 - 90, 0, 1, 0);
1014                 glTranslatef(model[k].vertex[i].x, model[k].vertex[i].y, model[k].vertex[i].z);
1015                 glGetFloatv(GL_MODELVIEW_MATRIX, M);
1016                 model[k].vertex[i].x = M[12] * 1;
1017                 model[k].vertex[i].y = M[13] * 1;
1018                 model[k].vertex[i].z = M[14] * 1;
1019                 glPopMatrix();
1020             }
1021             model[k].CalculateNormals(0);
1022         }
1023     }
1024     fclose(tfile);
1025
1026     // load ???
1027
1028     tfile = fopen( ConvertFileName(lowfilename), "rb" );
1029
1030     if (1) { // FIXME: should this be if(tfile) ?
1031         // skip joints section
1032
1033         lSize = sizeof(num_joints);
1034         fseek(tfile, lSize, SEEK_CUR);
1035         //joints = new Joint[num_joints];
1036         //jointlabels = new int[num_joints];
1037         for (i = 0; i < num_joints; i++) {
1038             // skip joint info
1039             lSize = sizeof(XYZ)
1040                     + sizeof(float)
1041                     + sizeof(float)
1042                     + 1 //sizeof(bool)
1043                     + 1 //sizeof(bool)
1044                     + sizeof(int)
1045                     + 1 //sizeof(bool)
1046                     + 1 //sizeof(bool)
1047                     + sizeof(int)
1048                     + sizeof(int)
1049                     + 1 //sizeof(bool)
1050                     + sizeof(int);
1051             fseek(tfile, lSize, SEEK_CUR);
1052
1053             if (joints[i].hasparent)
1054                 joints[i].parent = &joints[parentID];
1055             joints[i].velocity = 0;
1056             joints[i].oldposition = joints[i].position;
1057         }
1058
1059         // read num_muscles
1060         funpackf(tfile, "Bi", &num_muscles);
1061         //muscles = new Muscle[num_muscles];
1062
1063         for (i = 0; i < num_muscles; i++) {
1064             // skip muscle info
1065             lSize = sizeof(float)
1066                     + sizeof(float)
1067                     + sizeof(float)
1068                     + sizeof(float)
1069                     + sizeof(float)
1070                     + sizeof(int);
1071             fseek(tfile, lSize, SEEK_CUR);
1072
1073             // read numverticeslow
1074             tempmuscle = muscles[i].numverticeslow;
1075             funpackf(tfile, "Bi", &muscles[i].numverticeslow);
1076
1077             if (muscles[i].numverticeslow) {
1078                 // allocate memory
1079                 //muscles[i].verticeslow.clear();
1080                 //muscles[i].verticeslow.resize(muscles[i].numverticeslow);
1081                 //if(muscles[i].verticeslow)dealloc2(muscles[i].verticeslow);
1082                 muscles[i].verticeslow = (int*)malloc(sizeof(int) * muscles[i].numverticeslow);
1083
1084                 // read verticeslow
1085                 edit = 0;
1086                 for (j = 0; j < muscles[i].numverticeslow - edit; j++) {
1087                     funpackf(tfile, "Bi", &muscles[i].verticeslow[j + edit]);
1088                     if (muscles[i].verticeslow[j + edit] >= modellow.vertexNum) {
1089                         muscles[i].numverticeslow--;
1090                         edit--;
1091                     }
1092                 }
1093             }
1094
1095             // skip more stuff
1096             lSize = 1; //sizeof(bool);
1097             fseek ( tfile, lSize, SEEK_CUR);
1098             lSize = sizeof(int);
1099             fseek ( tfile, lSize, SEEK_CUR);
1100             fseek ( tfile, lSize, SEEK_CUR);
1101         }
1102
1103         // ???
1104         lSize = sizeof(int);
1105         for (j = 0; j < num_muscles; j++) {
1106             for (i = 0; i < muscles[j].numverticeslow; i++) {
1107                 if (muscles[j].numverticeslow && muscles[j].verticeslow[i] < modellow.vertexNum)
1108                     modellow.owner[muscles[j].verticeslow[i]] = j;
1109             }
1110         }
1111
1112         /*FindForwards();
1113         for(i=0;i<num_joints;i++){
1114         joints[i].startpos=joints[i].position;
1115         }
1116         for(i=0;i<num_muscles;i++){
1117         FindRotationMuscle(i,-1);
1118         }*/
1119
1120         // use opengl for its matrix math
1121         for (i = 0; i < modellow.vertexNum; i++) {
1122             modellow.vertex[i] = modellow.vertex[i] - (muscles[modellow.owner[i]].parent1->position + muscles[modellow.owner[i]].parent2->position) / 2;
1123             glMatrixMode(GL_MODELVIEW);
1124             glPushMatrix();
1125             glLoadIdentity();
1126             glRotatef(muscles[modellow.owner[i]].rotate3, 0, 1, 0);
1127             glRotatef(muscles[modellow.owner[i]].rotate2 - 90, 0, 0, 1);
1128             glRotatef(muscles[modellow.owner[i]].rotate1 - 90, 0, 1, 0);
1129             glTranslatef(modellow.vertex[i].x, modellow.vertex[i].y, modellow.vertex[i].z);
1130             glGetFloatv(GL_MODELVIEW_MATRIX, M);
1131             modellow.vertex[i].x = M[12];
1132             modellow.vertex[i].y = M[13];
1133             modellow.vertex[i].z = M[14];
1134             glPopMatrix();
1135         }
1136
1137         modellow.CalculateNormals(0);
1138     }
1139
1140     // load clothes
1141
1142     if (clothes) {
1143         tfile = fopen( ConvertFileName(clothesfilename), "rb" ); // FIXME: where's the check for valid load
1144
1145         // skip num_joints
1146         lSize = sizeof(num_joints);
1147         fseek ( tfile, lSize, SEEK_CUR);
1148         //joints = new Joint[num_joints];
1149         //jointlabels = new int[num_joints];
1150
1151         for (i = 0; i < num_joints; i++) {
1152             // skip joint info
1153             lSize = sizeof(XYZ)
1154                     + sizeof(float)
1155                     + sizeof(float)
1156                     + 1 //sizeof(bool)
1157                     + 1 //sizeof(bool)
1158                     + sizeof(int)
1159                     + 1 //sizeof(bool)
1160                     + 1 //sizeof(bool)
1161                     + sizeof(int)
1162                     + sizeof(int)
1163                     + 1 //sizeof(bool)
1164                     + sizeof(int);
1165             fseek(tfile, lSize, SEEK_CUR);
1166
1167             if (joints[i].hasparent)
1168                 joints[i].parent = &joints[parentID];
1169             joints[i].velocity = 0;
1170             joints[i].oldposition = joints[i].position;
1171         }
1172
1173         // read num_muscles
1174         funpackf(tfile, "Bi", &num_muscles);
1175         //muscles = new Muscle[num_muscles];
1176
1177         for (i = 0; i < num_muscles; i++) {
1178             // skip muscle info
1179             lSize = sizeof(float)
1180                     + sizeof(float)
1181                     + sizeof(float)
1182                     + sizeof(float)
1183                     + sizeof(float)
1184                     + sizeof(int);
1185             fseek(tfile, lSize, SEEK_CUR);
1186
1187             // read numverticesclothes
1188             tempmuscle = muscles[i].numverticesclothes;
1189             funpackf(tfile, "Bi", &muscles[i].numverticesclothes);
1190
1191             // read verticesclothes
1192             if (muscles[i].numverticesclothes) {
1193                 //muscles[i].verticesclothes.clear();
1194                 //muscles[i].verticesclothes.resize(muscles[i].numverticesclothes);
1195                 //if(muscles[i].verticesclothes)dealloc2(muscles[i].verticesclothes);
1196                 muscles[i].verticesclothes = (int*)malloc(sizeof(int) * muscles[i].numverticesclothes);
1197                 edit = 0;
1198                 for (j = 0; j < muscles[i].numverticesclothes - edit; j++) {
1199                     funpackf(tfile, "Bi", &muscles[i].verticesclothes[j + edit]);
1200                     if (muscles[i].verticesclothes[j + edit] >= modelclothes.vertexNum) {
1201                         muscles[i].numverticesclothes--;
1202                         edit--;
1203                     }
1204                 }
1205             }
1206
1207             // skip more stuff
1208             lSize = 1; //sizeof(bool);
1209             fseek ( tfile, lSize, SEEK_CUR);
1210             lSize = sizeof(int);
1211             fseek ( tfile, lSize, SEEK_CUR);
1212             fseek ( tfile, lSize, SEEK_CUR);
1213         }
1214
1215         // ???
1216         lSize = sizeof(int);
1217         for (j = 0; j < num_muscles; j++) {
1218             for (i = 0; i < muscles[j].numverticesclothes; i++) {
1219                 if (muscles[j].numverticesclothes && muscles[j].verticesclothes[i] < modelclothes.vertexNum)
1220                     modelclothes.owner[muscles[j].verticesclothes[i]] = j;
1221             }
1222         }
1223
1224         /*FindForwards();
1225         for(i=0;i<num_joints;i++){
1226         joints[i].startpos=joints[i].position;
1227         }
1228         for(i=0;i<num_muscles;i++){
1229         FindRotationMuscle(i,-1);
1230         }*/
1231
1232         // use opengl for its matrix math
1233         for (i = 0; i < modelclothes.vertexNum; i++) {
1234             modelclothes.vertex[i] = modelclothes.vertex[i] - (muscles[modelclothes.owner[i]].parent1->position + muscles[modelclothes.owner[i]].parent2->position) / 2;
1235             glMatrixMode(GL_MODELVIEW);
1236             glPushMatrix();
1237             glLoadIdentity();
1238             glRotatef(muscles[modelclothes.owner[i]].rotate3, 0, 1, 0);
1239             glRotatef(muscles[modelclothes.owner[i]].rotate2 - 90, 0, 0, 1);
1240             glRotatef(muscles[modelclothes.owner[i]].rotate1 - 90, 0, 1, 0);
1241             glTranslatef(modelclothes.vertex[i].x, modelclothes.vertex[i].y, modelclothes.vertex[i].z);
1242             glGetFloatv(GL_MODELVIEW_MATRIX, M);
1243             modelclothes.vertex[i].x = M[12];
1244             modelclothes.vertex[i].y = M[13];
1245             modelclothes.vertex[i].z = M[14];
1246             glPopMatrix();
1247         }
1248
1249         modelclothes.CalculateNormals(0);
1250     }
1251     fclose(tfile);
1252
1253     for (i = 0; i < num_joints; i++) {
1254         for (j = 0; j < num_joints; j++) {
1255             if (joints[i].label == j)
1256                 jointlabels[j] = i;
1257         }
1258     }
1259
1260     free = 0;
1261 }
1262
1263 Animation::Animation()
1264 {
1265     numframes = 0;
1266     height = 0;
1267     attack = 0;
1268     joints = 0;
1269     weapontargetnum = 0;
1270
1271     position = 0;
1272     twist = 0;
1273     twist2 = 0;
1274     speed = 0;
1275     onground = 0;
1276     forward = 0;
1277     label = 0;
1278     weapontarget = 0;
1279 }
1280
1281 Animation::~Animation()
1282 {
1283     deallocate();
1284 }
1285
1286 void Animation::deallocate()
1287 {
1288     int i = 0;
1289
1290     if (position) {
1291         for (i = 0; i < joints; i++)
1292             dealloc2(position[i]);
1293
1294         dealloc2(position);
1295     }
1296     position = 0;
1297
1298     if (twist) {
1299         for (i = 0; i < joints; i++)
1300             dealloc2(twist[i]);
1301
1302         dealloc2(twist);
1303     }
1304     twist = 0;
1305
1306     if (twist2) {
1307         for (i = 0; i < joints; i++)
1308             dealloc2(twist2[i]);
1309
1310         dealloc2(twist2);
1311     }
1312     twist2 = 0;
1313
1314     if (onground) {
1315         for (i = 0; i < joints; i++)
1316             dealloc2(onground[i]);
1317
1318         dealloc2(onground);
1319     }
1320     onground = 0;
1321
1322     if (speed)
1323         dealloc2(speed);
1324     speed = 0;
1325
1326     if (forward)
1327         dealloc2(forward);
1328     forward = 0;
1329
1330     if (weapontarget)
1331         dealloc2(weapontarget);
1332     weapontarget = 0;
1333
1334     if (label)
1335         dealloc2(label);
1336     label = 0;
1337
1338     joints = 0;
1339 }
1340
1341 Skeleton::Skeleton()
1342 {
1343     num_joints = 0;
1344
1345     num_muscles = 0;
1346
1347     selected = 0;
1348
1349     memset(forwardjoints, 0, sizeof(forwardjoints));
1350     // XYZ forward;
1351
1352     id = 0;
1353
1354     memset(lowforwardjoints, 0, sizeof(lowforwardjoints));
1355     // XYZ lowforward;
1356
1357     // XYZ specialforward[5];
1358     memset(jointlabels, 0, sizeof(jointlabels));
1359
1360     // Model model[7];
1361     // Model modellow;
1362     // Model modelclothes;
1363     num_models = 0;
1364
1365     // Model drawmodel;
1366     // Model drawmodellow;
1367     // Model drawmodelclothes;
1368
1369     clothes = 0;
1370     spinny = 0;
1371
1372     memset(skinText, 0, sizeof(skinText));
1373     skinsize = 0;
1374
1375     checkdelay = 0;
1376
1377     longdead = 0;
1378     broken = 0;
1379
1380     free = 0;
1381     oldfree = 0;
1382     freetime = 0;
1383     freefall = 0;
1384
1385     joints = 0;
1386     muscles = 0;
1387 }
1388
1389 Skeleton::~Skeleton()
1390 {
1391     if (muscles) {
1392         delete [] muscles;
1393     }
1394     muscles = 0;
1395
1396     if (joints) {
1397         delete [] joints;
1398     }
1399     joints = 0;
1400 }
1401
1402 Muscle::Muscle()
1403 {
1404     vertices = 0;
1405     verticeslow = 0;
1406     verticesclothes = 0;
1407
1408     numvertices = 0;
1409     numverticeslow = 0;
1410     numverticesclothes = 0;
1411     length = 0;
1412     targetlength = 0;
1413     parent1 = 0;
1414     parent2 = 0;
1415     maxlength = 0;
1416     minlength = 0;
1417     type = 0;
1418     visible = 0;
1419     rotate1 = 0, rotate2 = 0, rotate3 = 0;
1420     lastrotate1 = 0, lastrotate2 = 0, lastrotate3 = 0;
1421     oldrotate1 = 0, oldrotate2 = 0, oldrotate3 = 0;
1422     newrotate1 = 0, newrotate2 = 0, newrotate3 = 0;
1423
1424     strength = 0;
1425 }
1426
1427 Muscle::~Muscle()
1428 {
1429     dealloc2(vertices);
1430     dealloc2(verticeslow);
1431     dealloc2(verticesclothes);
1432 }
1433
1434 Animation & Animation::operator = (const Animation & ani)
1435 {
1436     int i = 0;
1437
1438     bool allocate = true;
1439
1440     allocate = ((ani.numframes != numframes) || (ani.joints != joints));
1441
1442     if (allocate)
1443         deallocate();
1444
1445     numframes = ani.numframes;
1446     height = ani.height;
1447     attack = ani.attack;
1448     joints = ani.joints;
1449     weapontargetnum = ani.weapontargetnum;
1450
1451     if (allocate)
1452         position = (XYZ**)malloc(sizeof(XYZ*)*ani.joints);
1453     for (i = 0; i < ani.joints; i++) {
1454         if (allocate)
1455             position[i] = (XYZ*)malloc(sizeof(XYZ) * ani.numframes);
1456         memcpy(position[i], ani.position[i], sizeof(XYZ)*ani.numframes);
1457     }
1458
1459     if (allocate)
1460         twist = (float**)malloc(sizeof(float*)*ani.joints);
1461     for (i = 0; i < ani.joints; i++) {
1462         if (allocate)
1463             twist[i] = (float*)malloc(sizeof(float) * ani.numframes);
1464         memcpy(twist[i], ani.twist[i], sizeof(float)*ani.numframes);
1465     }
1466
1467     if (allocate)
1468         twist2 = (float**)malloc(sizeof(float*)*ani.joints);
1469     for (i = 0; i < ani.joints; i++) {
1470         if (allocate)
1471             twist2[i] = (float*)malloc(sizeof(float) * ani.numframes);
1472         memcpy(twist2[i], ani.twist2[i], sizeof(float)*ani.numframes);
1473     }
1474
1475     if (allocate)
1476         speed = (float*)malloc(sizeof(float) * ani.numframes);
1477     memcpy(speed, ani.speed, sizeof(float)*ani.numframes);
1478
1479     if (allocate)
1480         onground = (bool**)malloc(sizeof(bool*)*ani.joints);
1481     for (i = 0; i < ani.joints; i++) {
1482         if (allocate)
1483             onground[i] = (bool*)malloc(sizeof(bool) * ani.numframes);
1484         memcpy(onground[i], ani.onground[i], sizeof(bool)*ani.numframes);
1485     }
1486
1487     if (allocate)
1488         forward = (XYZ*)malloc(sizeof(XYZ) * ani.numframes);
1489     memcpy(forward, ani.forward, sizeof(XYZ)*ani.numframes);
1490
1491     if (allocate)
1492         weapontarget = (XYZ*)malloc(sizeof(XYZ) * ani.numframes);
1493     memcpy(weapontarget, ani.weapontarget, sizeof(XYZ)*ani.numframes);
1494
1495     if (allocate)
1496         label = (int*)malloc(sizeof(int) * ani.numframes);
1497     memcpy(label, ani.label, sizeof(int)*ani.numframes);
1498
1499     return (*this);
1500 }
1501
1502
1503
1504
1505 #if 0
1506
1507 // the following functions are not used anywhere
1508
1509 /* EFFECT
1510  * sets forward, lowforward, specialforward[]
1511  *
1512  * USES:
1513  * NONE
1514  */
1515 void Skeleton::FindForwardsfirst()
1516 {
1517     //Find forward vectors
1518     CrossProduct(joints[forwardjoints[1]].position - joints[forwardjoints[0]].position, joints[forwardjoints[2]].position - joints[forwardjoints[0]].position, &forward);
1519     Normalise(&forward);
1520
1521     CrossProduct(joints[lowforwardjoints[1]].position - joints[lowforwardjoints[0]].position, joints[lowforwardjoints[2]].position - joints[lowforwardjoints[0]].position, &lowforward);
1522     Normalise(&lowforward);
1523
1524     //Special forwards
1525     specialforward[0] = forward;
1526     specialforward[1] = forward;
1527     specialforward[2] = forward;
1528     specialforward[3] = forward;
1529     specialforward[4] = forward;
1530
1531 }
1532
1533 /* EFFECT
1534  *
1535  * USES:
1536  * NONE
1537  */
1538 void Skeleton::Draw(int muscleview)
1539 {
1540     static float jointcolor[4];
1541
1542     if (muscleview != 2) {
1543         jointcolor[0] = 0;
1544         jointcolor[1] = 0;
1545         jointcolor[2] = .5;
1546         jointcolor[3] = 1;
1547     }
1548
1549     if (muscleview == 2) {
1550         jointcolor[0] = 0;
1551         jointcolor[1] = 0;
1552         jointcolor[2] = 0;
1553         jointcolor[3] = .5;
1554     }
1555     //Calc motionblur-ness
1556     for (int i = 0; i < num_joints; i++) {
1557         joints[i].oldposition = joints[i].position;
1558         joints[i].blurred = findDistance(&joints[i].position, &joints[i].oldposition) * 100;
1559         if (joints[i].blurred < 1)
1560             joints[i].blurred = 1;
1561     }
1562
1563     //Do Motionblur
1564     glDepthMask(0);
1565     glEnable(GL_BLEND);
1566     glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1567     glBegin(GL_QUADS);
1568     for (int i = 0; i < num_joints; i++) {
1569         if (joints[i].hasparent) {
1570             glColor4f(jointcolor[0], jointcolor[1], jointcolor[2], jointcolor[3] / joints[i].blurred);
1571             glVertex3f(joints[i].position.x, joints[i].position.y, joints[i].position.z);
1572             glColor4f(jointcolor[0], jointcolor[1], jointcolor[2], jointcolor[3] / joints[i].parent->blurred);
1573             glVertex3f(joints[i].parent->position.x, joints[i].parent->position.y, joints[i].parent->position.z);
1574             glColor4f(jointcolor[0], jointcolor[1], jointcolor[2], jointcolor[3] / joints[i].parent->blurred);
1575             glVertex3f(joints[i].parent->oldposition.x, joints[i].parent->oldposition.y, joints[i].parent->oldposition.z);
1576             glColor4f(jointcolor[0], jointcolor[1], jointcolor[2], jointcolor[3] / joints[i].blurred);
1577             glVertex3f(joints[i].oldposition.x, joints[i].oldposition.y, joints[i].oldposition.z);
1578         }
1579     }
1580     for (int i = 0; i < num_muscles; i++) {
1581         if (muscles[i].type == boneconnect) {
1582             glColor4f(jointcolor[0], jointcolor[1], jointcolor[2], jointcolor[3] / muscles[i].parent2->blurred);
1583             glVertex3f(muscles[i].parent1->position.x, muscles[i].parent1->position.y, muscles[i].parent1->position.z);
1584             glColor4f(jointcolor[0], jointcolor[1], jointcolor[2], jointcolor[3] / muscles[i].parent2->blurred);
1585             glVertex3f(muscles[i].parent2->position.x, muscles[i].parent2->position.y, muscles[i].parent2->position.z);
1586             glColor4f(jointcolor[0], jointcolor[1], jointcolor[2], jointcolor[3] / muscles[i].parent2->blurred);
1587             glVertex3f(muscles[i].parent2->oldposition.x, muscles[i].parent2->oldposition.y, muscles[i].parent2->oldposition.z);
1588             glColor4f(jointcolor[0], jointcolor[1], jointcolor[2], jointcolor[3] / muscles[i].parent1->blurred);
1589             glVertex3f(muscles[i].parent1->oldposition.x, muscles[i].parent1->oldposition.y, muscles[i].parent1->oldposition.z);
1590         }
1591     }
1592     glEnd();
1593
1594     glBegin(GL_LINES);
1595     for (int i = 0; i < num_joints; i++) {
1596         if (joints[i].hasparent) {
1597             glColor4f(jointcolor[0], jointcolor[1], jointcolor[2], jointcolor[3] / joints[i].blurred);
1598             glVertex3f(joints[i].position.x, joints[i].position.y, joints[i].position.z);
1599             glColor4f(jointcolor[0], jointcolor[1], jointcolor[2], jointcolor[3] / joints[i].parent->blurred);
1600             glVertex3f(joints[i].parent->position.x, joints[i].parent->position.y, joints[i].parent->position.z);
1601         }
1602     }
1603     /*for(int i=0; i<num_joints; i++){
1604     if(joints[i].hasparent){
1605     glColor4f(jointcolor[0],jointcolor[1],jointcolor[2],1);
1606     glVertex3f(joints[i].position.x,joints[i].position.y,joints[i].position.z);
1607     glColor4f(jointcolor[0],jointcolor[1],jointcolor[2],1);
1608     glVertex3f(joints[i].position.x+forward.x,joints[i].position.y+forward.y,joints[i].position.z+forward.z);
1609     }
1610     }*/
1611     for (int i = 0; i < num_muscles; i++) {
1612         if (muscles[i].type == boneconnect) {
1613             glColor4f(jointcolor[0], jointcolor[1], jointcolor[2], jointcolor[3] / muscles[i].parent1->blurred);
1614             glVertex3f(muscles[i].parent1->position.x, muscles[i].parent1->position.y, muscles[i].parent1->position.z);
1615             glColor4f(jointcolor[0], jointcolor[1], jointcolor[2], jointcolor[3] / muscles[i].parent2->blurred);
1616             glVertex3f(muscles[i].parent2->position.x, muscles[i].parent2->position.y, muscles[i].parent2->position.z);
1617         }
1618     }
1619     glColor3f(.6, .6, 0);
1620     if (muscleview == 1)
1621         for (int i = 0; i < num_muscles; i++) {
1622             if (muscles[i].type != boneconnect) {
1623                 glVertex3f(muscles[i].parent1->position.x, muscles[i].parent1->position.y, muscles[i].parent1->position.z);
1624                 glVertex3f(muscles[i].parent2->position.x, muscles[i].parent2->position.y, muscles[i].parent2->position.z);
1625             }
1626         }
1627     glEnd();
1628
1629     if (muscleview != 2) {
1630         glPointSize(3);
1631         glBegin(GL_POINTS);
1632         for (int i = 0; i < num_joints; i++) {
1633             if (i != selected)
1634                 glColor4f(0, 0, .5, 1);
1635             if (i == selected)
1636                 glColor4f(1, 1, 0, 1);
1637             if (joints[i].locked && i != selected)
1638                 glColor4f(1, 0, 0, 1);
1639             glVertex3f(joints[i].position.x, joints[i].position.y, joints[i].position.z);
1640         }
1641         glEnd();
1642     }
1643
1644     //Set old position to current position
1645     if (muscleview == 2)
1646         for (int i = 0; i < num_joints; i++) {
1647             joints[i].oldposition = joints[i].position;
1648         }
1649     glDepthMask(1);
1650 }
1651
1652 /* EFFECT
1653  *
1654  * USES:
1655  * NONE
1656  */
1657 void Skeleton::AddJoint(float x, float y, float z, int which)
1658 {
1659     if (num_joints < max_joints - 1) {
1660         joints[num_joints].velocity = 0;
1661         joints[num_joints].position.x = x;
1662         joints[num_joints].position.y = y;
1663         joints[num_joints].position.z = z;
1664         joints[num_joints].mass = 1;
1665         joints[num_joints].locked = 0;
1666
1667         /*if(which>=num_joints||which<0)*/
1668         joints[num_joints].hasparent = 0;
1669         /*if(which<num_joints&&which>=0){
1670         joints[num_joints].parent=&joints[which];
1671         joints[num_joints].hasparent=1;
1672         joints[num_joints].length=findDistance(joints[num_joints].position,joints[num_joints].parent->position);
1673         }*/
1674         num_joints++;
1675         if (which < num_joints && which >= 0)
1676             AddMuscle(num_joints - 1, which, 0, 10, boneconnect);
1677     }
1678 }
1679
1680 /* EFFECT
1681  *
1682  * USES:
1683  * NONE
1684  */
1685 void Skeleton::DeleteJoint(int whichjoint)
1686 {
1687     if (whichjoint < num_joints && whichjoint >= 0) {
1688         joints[whichjoint].velocity = joints[num_joints - 1].velocity;
1689         joints[whichjoint].position = joints[num_joints - 1].position;
1690         joints[whichjoint].oldposition = joints[num_joints - 1].oldposition;
1691         joints[whichjoint].hasparent = joints[num_joints - 1].hasparent;
1692         joints[whichjoint].parent = joints[num_joints - 1].parent;
1693         joints[whichjoint].length = joints[num_joints - 1].length;
1694         joints[whichjoint].locked = joints[num_joints - 1].locked;
1695         joints[whichjoint].modelnum = joints[num_joints - 1].modelnum;
1696         joints[whichjoint].visible = joints[num_joints - 1].visible;
1697
1698         for (int i = 0; i < num_muscles; i++) {
1699             while (muscles[i].parent1 == &joints[whichjoint] && i < num_muscles)DeleteMuscle(i);
1700             while (muscles[i].parent2 == &joints[whichjoint] && i < num_muscles)DeleteMuscle(i);
1701         }
1702         for (int i = 0; i < num_muscles; i++) {
1703             while (muscles[i].parent1 == &joints[num_joints - 1] && i < num_muscles)muscles[i].parent1 = &joints[whichjoint];
1704             while (muscles[i].parent2 == &joints[num_joints - 1] && i < num_muscles)muscles[i].parent2 = &joints[whichjoint];
1705         }
1706         for (int i = 0; i < num_joints; i++) {
1707             if (joints[i].parent == &joints[whichjoint])
1708                 joints[i].hasparent = 0;
1709         }
1710         for (int i = 0; i < num_joints; i++) {
1711             if (joints[i].parent == &joints[num_joints - 1])
1712                 joints[i].parent = &joints[whichjoint];
1713         }
1714
1715         num_joints--;
1716     }
1717 }
1718
1719 /* EFFECT
1720  *
1721  * USES:
1722  * Skeleton::DeleteJoint - UNUSED
1723  */
1724 void Skeleton::DeleteMuscle(int whichmuscle)
1725 {
1726     if (whichmuscle < num_muscles) {
1727         muscles[whichmuscle].minlength = muscles[num_muscles - 1].minlength;
1728         muscles[whichmuscle].maxlength = muscles[num_muscles - 1].maxlength;
1729         muscles[whichmuscle].strength = muscles[num_muscles - 1].strength;
1730         muscles[whichmuscle].parent1 = muscles[num_muscles - 1].parent1;
1731         muscles[whichmuscle].parent2 = muscles[num_muscles - 1].parent2;
1732         muscles[whichmuscle].length = muscles[num_muscles - 1].length;
1733         muscles[whichmuscle].visible = muscles[num_muscles - 1].visible;
1734         muscles[whichmuscle].type = muscles[num_muscles - 1].type;
1735         muscles[whichmuscle].targetlength = muscles[num_muscles - 1].targetlength;
1736
1737         num_muscles--;
1738     }
1739 }
1740
1741 /* EFFECT
1742  *
1743  * USES:
1744  * NONE
1745  */
1746 void Skeleton::SetJoint(float x, float y, float z, int which, int whichjoint)
1747 {
1748     if (whichjoint < num_joints) {
1749         joints[whichjoint].velocity = 0;
1750         joints[whichjoint].position.x = x;
1751         joints[whichjoint].position.y = y;
1752         joints[whichjoint].position.z = z;
1753
1754         if (which >= num_joints || which < 0)
1755             joints[whichjoint].hasparent = 0;
1756         if (which < num_joints && which >= 0) {
1757             joints[whichjoint].parent = &joints[which];
1758             joints[whichjoint].hasparent = 1;
1759             joints[whichjoint].length = findDistance(&joints[whichjoint].position, &joints[whichjoint].parent->position);
1760         }
1761     }
1762 }
1763
1764 /* EFFECT
1765  *
1766  * USES:
1767  * Skeleton::AddJoint - UNUSED
1768  */
1769 void Skeleton::AddMuscle(int attach1, int attach2, float minlength, float maxlength, int type)
1770 {
1771     const int max_muscles = 100; // FIXME: Probably can be dropped
1772     if (num_muscles < max_muscles - 1 && attach1 < num_joints && attach1 >= 0 && attach2 < num_joints && attach2 >= 0 && attach1 != attach2) {
1773         muscles[num_muscles].parent1 = &joints[attach1];
1774         muscles[num_muscles].parent2 = &joints[attach2];
1775         muscles[num_muscles].length = findDistance(&muscles[num_muscles].parent1->position, &muscles[num_muscles].parent2->position);
1776         muscles[num_muscles].targetlength = findDistance(&muscles[num_muscles].parent1->position, &muscles[num_muscles].parent2->position);
1777         muscles[num_muscles].strength = .7;
1778         muscles[num_muscles].type = type;
1779         muscles[num_muscles].minlength = minlength;
1780         muscles[num_muscles].maxlength = maxlength;
1781
1782         num_muscles++;
1783     }
1784 }
1785
1786 /* EFFECT
1787  *
1788  * USES:
1789  * NONE
1790  */
1791 void Skeleton::MusclesSet()
1792 {
1793     for (int i = 0; i < num_muscles; i++) {
1794         muscles[i].length = findDistance(&muscles[i].parent1->position, &muscles[i].parent2->position);
1795     }
1796 }
1797
1798 /* EFFECT
1799  *
1800  * USES:
1801  * NONE
1802  */
1803 void Skeleton::DoBalance()
1804 {
1805     /*XYZ newpoint;
1806     newpoint=joints[0].position;
1807     newpoint.x=(joints[2].position.x+joints[4].position.x)/2;
1808     newpoint.z=(joints[2].position.z+joints[4].position.z)/2;
1809     joints[0].velocity=joints[0].velocity+(newpoint-joints[0].position);
1810     //Move child point to within certain distance of parent point
1811     joints[0].position=newpoint;
1812
1813     MusclesSet();*/
1814 }
1815
1816 #endif
1817