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