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