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