remove RSA's md4.c, replace by DP's
[xonotic/netradiant.git] / tools / quake2 / qdata_heretic2 / qd_skeletons.c
1 /*
2 Copyright (C) 1999-2006 Id Software, Inc. and contributors.
3 For a list of contributors, see the accompanying CONTRIBUTORS file.
4
5 This file is part of GtkRadiant.
6
7 GtkRadiant is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
11
12 GtkRadiant is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with GtkRadiant; if not, write to the Free Software
19 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
20 */
21
22 #include "qd_skeletons.h"
23 #include "skeletons.h"
24 #include "qd_fmodel.h"
25 #include "angles.h"
26 #include "token.h"
27 #include "qdata.h"
28 #include "reference.h"
29
30 #include <assert.h>
31 #include <math.h>
32 #include <memory.h>
33
34
35 // We're assuming no more than 16 reference points, with no more than 32 characters in the name
36 char RefPointNameList[REF_MAX_POINTS][REF_MAX_STRLEN];
37 int      RefPointNum = 0;
38
39 Skeletalfmheader_t g_skelModel;
40
41 void ClearSkeletalModel()
42 {
43         g_skelModel.type = SKEL_NULL;
44         g_skelModel.clustered = false;
45         g_skelModel.references = REF_NULL;
46 }
47
48 //==========================================================================
49 //
50 // LoadHRCClustered
51 //
52 //==========================================================================
53
54 // Places the null terminated src string into the dest string less any trailing digits or underscores
55 void StripTrailingDigits(char *src, char *dest)
56 {
57 #ifndef NDEBUG
58         int max = SKELETAL_NAME_MAX; // should be sufficient for inteded use on names from hrc files
59 #endif
60         int i = 0;
61
62         while(src[i] != '\0')
63         {
64                 ++i;
65 #ifndef NDEBUG
66                 assert(i < max);
67 #endif
68         }
69
70         while((src[--i] >= '0' && src[i] <= '9') || src[i] == '_')
71         {
72
73         }
74
75         memcpy(dest, src, ++i);
76
77         dest[i] = '\0';
78 }
79
80 static void LoadHRCClustered(char *fileName, int **clusterList, int *num_verts, int skelType)
81 {
82         extern void HandleHRCModel(triangle_t **triList, int *triangleCount, 
83                 mesh_node_t **nodesList, int *num_mesh_nodes, int ActiveNode, int Depth);
84
85         extern mesh_node_t      *pmnodes;
86
87         triangle_t *triList;
88 //      mesh_node_t *nodesList;
89         int num_mesh_nodes = 0, triangleCount = 0;
90
91 #if 0
92         int i;
93         int j, numVerts;
94         char stripped[SKELETAL_NAME_MAX];
95
96         for( i = 1; i < numJointsInSkeleton[skelType] + 1; ++i)
97         {
98                 num_verts[i] = 0;
99         }
100
101         TK_OpenSource(fileName);
102         TK_FetchRequire(TK_HRCH);
103         TK_FetchRequire(TK_COLON);
104         TK_FetchRequire(TK_SOFTIMAGE);
105
106         TK_Beyond(TK_CLUSTERS);
107
108         while(TK_Search(TK_CLUSTER_NAME) != TK_EOF)
109         {
110                 TK_Require(TK_STRING);
111
112                 StripTrailingDigits(tk_String, stripped);
113
114                 for( i = 0; i < numJointsInSkeleton[skelType]; ++i)
115                 {
116                         if(stricmp(stripped, skeletonJointNames[skeletonNameOffsets[skelType]+i]) == 0)
117                         {
118                                 i = -i + numJointsInSkeleton[skelType] - 1;
119
120                                 TK_BeyondRequire(TK_NUM_CLUSTER_VERTICES, TK_INTNUMBER);
121
122                                 numVerts = tk_IntNumber;
123
124                                 if(!num_verts[i+1])     // first set of verts for cluster
125                                 {
126                                         clusterList[i] = SafeMalloc(numVerts*sizeof(int), "LoadHRCClustered");
127                                         assert(clusterList[i]);
128                                 }
129                                 else                            // any later sets of verts need to copy current
130                                 {
131                                         int *temp;
132
133                                         temp = SafeMalloc((num_verts[i+1]+numVerts)*sizeof(int), "LoadHRCClustered");
134                                         assert(temp);
135
136                                         memcpy(temp + numVerts, clusterList[i], num_verts[i+1]*sizeof(int));
137
138                                         free(clusterList[i]);
139
140                                         clusterList[i] = temp;
141                                 }
142
143                                 // currently this function is only called by LoadModelClusters.
144                                 // Apparently the matching free has disappeared, 
145                                 // should probably be free at the end of FMCmd_Base
146
147                                 TK_Beyond(TK_LBRACE);
148
149                                 for(j = 0; j < numVerts; ++j)
150                                 {
151                                         TK_Require(TK_INTNUMBER);
152                                         clusterList[i][j] = tk_IntNumber;
153                                         TK_Fetch();
154                                 }
155
156                                 num_verts[i+1] += numVerts;
157
158                                 break;
159                         }
160                 }
161         }
162
163         num_verts[0] = numJointsInSkeleton[skelType];
164 #endif
165
166 #if 1   // get the index number localized to the root
167 //      for( i = 1; i < numJointsInSkeleton[skelType] + 1; ++i)
168 //      {
169 //              g_skelModel.num_verts[i] = 0;
170 //      }
171
172         TK_OpenSource(fileName);
173         TK_FetchRequire(TK_HRCH);
174         TK_FetchRequire(TK_COLON);
175         TK_FetchRequire(TK_SOFTIMAGE);
176
177         // prime it
178         TK_Beyond(TK_MODEL);
179
180         triList = (triangle_t *) SafeMalloc(MAXTRIANGLES*sizeof(triangle_t), "Triangle list");
181         memset(triList,0,MAXTRIANGLES*sizeof(triangle_t));
182 //      nodesList = SafeMalloc(MAX_FM_MESH_NODES * sizeof(mesh_node_t), "Mesh Node List");
183         pmnodes = (mesh_node_t *) SafeMalloc(MAX_FM_MESH_NODES * sizeof(mesh_node_t), "Mesh Node List");
184
185         memset(pmnodes, 0, MAX_FM_MESH_NODES * sizeof(mesh_node_t));
186
187         // this should eventually use a stripped down version of this
188         HandleHRCModel(&triList, &triangleCount, &pmnodes, &num_mesh_nodes, 0, 0);
189
190 //      free(nodesList);
191         free(triList);
192
193         num_verts[0] = numJointsInSkeleton[skelType];
194 #endif
195 }
196
197 void ReadHRCClusterList(mesh_node_t *meshNode, int baseIndex)
198 {
199         int i, j, numVerts;
200         tokenType_t nextToken;
201         char stripped[SKELETAL_NAME_MAX];
202
203         meshNode->clustered = true;
204
205         nextToken = TK_Get(TK_CLUSTER_NAME);
206
207         while (nextToken == TK_CLUSTER_NAME)
208         {
209                 TK_FetchRequire(TK_STRING);
210
211                 StripTrailingDigits(tk_String, stripped);
212
213                 for( i = 0; i < numJointsInSkeleton[g_skelModel.type]; ++i)
214                 {
215                         if(stricmp(stripped, skeletonJointNames[skeletonNameOffsets[g_skelModel.type]+i]) == 0)
216                         {
217                                 i = -i + numJointsInSkeleton[g_skelModel.type] - 1;
218
219                                 TK_BeyondRequire(TK_NUM_CLUSTER_VERTICES, TK_INTNUMBER);
220
221                                 numVerts = tk_IntNumber;
222
223                                 if(!baseIndex)
224                                 {
225                                         meshNode->clusters[i] = (int *) SafeMalloc(numVerts*sizeof(int), "ReadHRCClusterList");
226                                         assert(meshNode->clusters[i]);
227                                 }
228                                 else
229                                 {
230                                         int *temp; 
231
232                                         temp = meshNode->clusters[i];
233                                         meshNode->clusters[i] = (int *) SafeMalloc((meshNode->num_verts[i+1]+numVerts)*sizeof(int), "ReadHRCClusterList");
234                                         assert(meshNode->clusters[i]);
235
236                                         memcpy(meshNode->clusters[i], temp, meshNode->num_verts[i+1]*sizeof(int));
237                                         free(temp);
238                                 }
239
240                                 // currently this function is only called by LoadModelClusters.
241                                 // Apparently the matching free has disappeared, 
242                                 // should probably be free at the end of FMCmd_Base
243
244                                 TK_Beyond(TK_LBRACE);
245
246                                 for(j = 0; j < numVerts; ++j)
247                                 {
248                                         TK_Require(TK_INTNUMBER);
249                                         meshNode->clusters[i][baseIndex+j] = tk_IntNumber+baseIndex;
250                                         TK_Fetch();
251                                 }
252
253                                 if(baseIndex)
254                                 {
255                                         meshNode->num_verts[i+1] += numVerts;
256                                 }
257                                 else
258                                 {
259                                         meshNode->num_verts[i+1] = numVerts;
260                                 }
261
262                                 break;
263                         }
264                 }
265
266                 TK_BeyondRequire(TK_CLUSTER_STATE, TK_INTNUMBER);
267                 nextToken = TK_Fetch();
268         }
269 }
270
271 static void LoadHRCGlobals(char *fileName)
272 {
273         int i;
274
275         TK_OpenSource(fileName);
276         TK_FetchRequire(TK_HRCH);
277         TK_FetchRequire(TK_COLON);
278         TK_FetchRequire(TK_SOFTIMAGE);
279         TK_Beyond(TK_MODEL);
280
281         TK_Beyond(TK_SCALING);
282         for(i = 0; i < 3; i++)
283         {
284                 TK_Require(TK_FLOATNUMBER);
285                 g_skelModel.scaling[i] = tk_FloatNumber;
286                 TK_Fetch();
287         }
288
289         TK_Beyond(TK_ROTATION);
290         for(i = 0; i < 3; i++)
291         {
292                 TK_Require(TK_FLOATNUMBER);
293                 g_skelModel.rotation[i] = tk_FloatNumber;
294                 TK_Fetch();
295         }
296
297         TK_Beyond(TK_TRANSLATION);
298         for(i = 0; i < 3; i++)
299         {
300                 TK_Require(TK_FLOATNUMBER);
301                 g_skelModel.translation[i] = tk_FloatNumber;
302                 TK_Fetch();
303         }
304 }
305
306 static void ParseVec3(vec3_t in)
307 {
308         TK_Require(TK_FLOATNUMBER);
309         in[1] = tk_FloatNumber;
310         TK_FetchRequire(TK_FLOATNUMBER);
311         in[2] = tk_FloatNumber;
312         TK_FetchRequire(TK_FLOATNUMBER);
313         in[0] = tk_FloatNumber;
314 }
315
316 static void ParseVec3d(vec3d_t in)
317 {
318         TK_Require(TK_FLOATNUMBER);
319         in[1] = tk_FloatNumber;
320         TK_FetchRequire(TK_FLOATNUMBER);
321         in[2] = tk_FloatNumber;
322         TK_FetchRequire(TK_FLOATNUMBER);
323         in[0] = tk_FloatNumber;
324 }
325
326 static void ParseRotation3(vec3_t in)
327 {
328         TK_Require(TK_FLOATNUMBER);
329         in[1] = tk_FloatNumber;
330         TK_FetchRequire(TK_FLOATNUMBER);
331         in[2] = tk_FloatNumber;
332         TK_FetchRequire(TK_FLOATNUMBER);
333         in[0] = tk_FloatNumber;
334 }
335
336 static void ParseRotation3d(vec3d_t in)
337 {
338         TK_Require(TK_FLOATNUMBER);
339         in[1] = tk_FloatNumber;
340         TK_FetchRequire(TK_FLOATNUMBER);
341         in[2] = tk_FloatNumber;
342         TK_FetchRequire(TK_FLOATNUMBER);
343         in[0] = tk_FloatNumber;
344 }
345
346 static void ParseTranslation3(vec3_t in)
347 {
348         TK_Require(TK_FLOATNUMBER);
349         in[1] = tk_FloatNumber;
350         TK_FetchRequire(TK_FLOATNUMBER);
351         in[2] = tk_FloatNumber;
352         TK_FetchRequire(TK_FLOATNUMBER);
353         in[0] = tk_FloatNumber;
354 }
355
356 static void ParseTranslation3d(vec3d_t in)
357 {
358         TK_Require(TK_FLOATNUMBER);
359         in[1] = tk_FloatNumber;
360         TK_FetchRequire(TK_FLOATNUMBER);
361         in[2] = tk_FloatNumber;
362         TK_FetchRequire(TK_FLOATNUMBER);
363         in[0] = tk_FloatNumber;
364 }
365
366 static void LoadHRCJointList(char *fileName, QD_SkeletalJoint_t *jointList, int skelType)
367 {
368 #define MAX_STACK 64
369         int i, j;
370         vec3d_t curTranslation[MAX_STACK], curRotation[MAX_STACK], curScale[MAX_STACK];
371         int curCorrespondingJoint[MAX_STACK];
372         int currentStack = 0, stackSize;
373         double cx, sx, cy, sy, cz, sz;
374         double rx, ry, rz;
375         double x2, y2, z2;
376         char stripped[SKELETAL_NAME_MAX];
377         Placement_d_t *placement;
378
379         TK_OpenSource(fileName);
380         TK_FetchRequire(TK_HRCH);
381         TK_FetchRequire(TK_COLON);
382         TK_FetchRequire(TK_SOFTIMAGE);
383
384         TK_Beyond(TK_MODEL);
385
386         while(TK_Search(TK_NAME) != TK_EOF)
387         {
388                 TK_Require(TK_STRING);
389
390                 StripTrailingDigits(tk_String, stripped);
391
392                 if(stricmp(stripped, skeletonRootNames[skeletonRNameOffsets[skelType]]) == 0)
393                 {
394                         break;
395                 }
396         }
397
398         if(tk_Token == TK_EOF)
399         {
400                 Error("Bone Chain Root: %s not found\n", skeletonRootNames[skeletonRNameOffsets[skelType]]);
401                 return;
402         }
403
404         TK_Beyond(TK_SCALING);
405
406         ParseVec3d(curScale[currentStack]);
407
408         TK_Beyond(TK_ROTATION);
409
410         ParseRotation3d(curRotation[currentStack]);
411
412         TK_Beyond(TK_TRANSLATION);
413
414         ParseVec3d(curTranslation[currentStack]);
415
416         // account for global model translation
417         curTranslation[currentStack][1] += g_skelModel.translation[0];
418         curTranslation[currentStack][2] += g_skelModel.translation[1];
419         curTranslation[currentStack][0] += g_skelModel.translation[2];
420
421         curCorrespondingJoint[currentStack] = -1;
422
423         ++currentStack;
424
425         for(i = 0; i < numJointsInSkeleton[skelType]; ++i)
426         {
427                 while(1)
428                 {
429                         TK_Beyond(TK_MODEL);
430
431                         TK_BeyondRequire(TK_NAME, TK_STRING);
432
433                         StripTrailingDigits(tk_String, stripped);
434
435                         if(stricmp(stripped, skeletonJointNames[skeletonNameOffsets[skelType]+i]) == 0)
436                                 break;
437
438                         TK_Beyond(TK_SCALING);
439
440                         ParseVec3d(curScale[currentStack]);
441
442                         TK_Beyond(TK_ROTATION);
443
444                         ParseRotation3d(curRotation[currentStack]);
445
446                         TK_Beyond(TK_TRANSLATION);
447
448                         ParseVec3d(curTranslation[currentStack]);
449
450                         curCorrespondingJoint[currentStack] = -1;
451
452                         ++currentStack;
453                 }
454
455                 TK_Beyond(TK_SCALING);
456
457                 ParseVec3d(curScale[currentStack]);
458
459                 TK_Beyond(TK_ROTATION);
460
461                 ParseRotation3d(curRotation[currentStack]);
462
463                 jointList[i].rotation[1] = curRotation[currentStack][1];
464                 jointList[i].rotation[2] = curRotation[currentStack][2];
465                 jointList[i].rotation[0] = curRotation[currentStack][0];
466
467                 TK_Beyond(TK_TRANSLATION);
468
469                 ParseVec3d(curTranslation[currentStack]);
470
471 //              jointList[i].placement.origin[1] = curTranslation[currentStack][1];
472 //              jointList[i].placement.origin[2] = curTranslation[currentStack][2];
473 //              jointList[i].placement.origin[0] = curTranslation[currentStack][0];
474
475                 jointList[i].placement.origin[1] = 0.0;
476                 jointList[i].placement.origin[2] = 0.0;
477                 jointList[i].placement.origin[0] = 0.0;
478
479                 jointList[i].placement.direction[1] = 20.0;
480                 jointList[i].placement.direction[2] = 0.0;
481                 jointList[i].placement.direction[0] = 0.0;
482
483                 jointList[i].placement.up[1] = 0.0;
484                 jointList[i].placement.up[2] = 20.0;
485                 jointList[i].placement.up[0] = 0.0;
486
487                 curCorrespondingJoint[currentStack] = i;
488
489                 ++currentStack;
490         }
491
492         stackSize = currentStack;
493
494 #if 0
495         // rotate the direction and up vectors to correspond to the rotation
496         for(i = 0; i < numJointsInSkeleton[skelType]; ++i)
497         {
498                 rx = jointList[i].rotation[0]*ANGLE_TO_RAD;
499                 ry = jointList[i].rotation[1]*ANGLE_TO_RAD;
500                 rz = jointList[i].rotation[2]*ANGLE_TO_RAD;
501
502                 cx = cos(rx);
503                 sx = sin(rx);
504
505                 cy = cos(ry);
506                 sy = sin(ry);
507
508                 cz = cos(rz);
509                 sz = sin(rz);
510
511                 // y-axis rotation for direction
512                 x2 = jointList[i].placement.direction[0]*cy+jointList[i].placement.direction[2]*sy;
513                 z2 = -jointList[i].placement.direction[0]*sy+jointList[i].placement.direction[2]*cy;
514                 jointList[i].placement.direction[0] = x2;
515                 jointList[i].placement.direction[2] = z2;
516
517                 // y-axis rotation for up
518                 x2 = jointList[i].placement.up[0]*cy+jointList[i].placement.up[2]*sy;
519                 z2 = -jointList[i].placement.up[0]*sy+jointList[i].placement.up[2]*cy;
520                 jointList[i].placement.up[0] = x2;
521                 jointList[i].placement.up[2] = z2;
522
523                 // z-axis rotation for direction
524                 x2 = jointList[i].placement.direction[0]*cz-jointList[i].placement.direction[1]*sz;
525                 y2 = jointList[i].placement.direction[0]*sz+jointList[i].placement.direction[1]*cz;
526                 jointList[i].placement.direction[0] = x2;
527                 jointList[i].placement.direction[1] = y2;
528
529                 // z-axis rotation for up
530                 x2 = jointList[i].placement.up[0]*cz-jointList[i].placement.up[1]*sz;
531                 y2 = jointList[i].placement.up[0]*sz+jointList[i].placement.up[1]*cz;
532                 jointList[i].placement.up[0] = x2;
533                 jointList[i].placement.up[1] = y2;
534
535                 // x-axis rotation for direction vector
536                 y2 = jointList[i].placement.direction[1]*cx-jointList[i].placement.direction[2]*sx;
537                 z2 = jointList[i].placement.direction[1]*sx+jointList[i].placement.direction[2]*cx;
538                 jointList[i].placement.direction[1] = y2;
539                 jointList[i].placement.direction[2] = z2;
540
541                 // x-axis rotation for up vector
542                 y2 = jointList[i].placement.up[1]*cx-jointList[i].placement.up[2]*sx;
543                 z2 = jointList[i].placement.up[1]*sx+jointList[i].placement.up[2]*cx;
544                 jointList[i].placement.up[1] = y2;
545                 jointList[i].placement.up[2] = z2;
546
547                 // translate direction to a point in the model
548                 jointList[i].placement.direction[0] += jointList[i].placement.origin[0];
549                 jointList[i].placement.direction[1] += jointList[i].placement.origin[1];
550                 jointList[i].placement.direction[2] += jointList[i].placement.origin[2];
551
552                 // translate up to a point in the model
553                 jointList[i].placement.up[0] += jointList[i].placement.origin[0];
554                 jointList[i].placement.up[1] += jointList[i].placement.origin[1];
555                 jointList[i].placement.up[2] += jointList[i].placement.origin[2];
556         }
557 #endif
558
559         for(i = stackSize - 1; i >= 0; --i)
560         {
561                 rx = curRotation[i][0]*ANGLE_TO_RAD;
562                 ry = curRotation[i][1]*ANGLE_TO_RAD;
563                 rz = curRotation[i][2]*ANGLE_TO_RAD;
564
565                 cx = cos(rx);
566                 sx = sin(rx);
567
568                 cy = cos(ry);
569                 sy = sin(ry);
570
571                 cz = cos(rz);
572                 sz = sin(rz);
573
574 #if 1
575                 for(j = i; j < stackSize; ++j)
576                 {
577                         if(curCorrespondingJoint[j] != -1)
578                         {
579                                 placement = &jointList[curCorrespondingJoint[j]].placement;
580
581                                 // y-axis rotation for origin
582                                 x2 = placement->origin[0]*cy+placement->origin[2]*sy;
583                                 z2 = -placement->origin[0]*sy+placement->origin[2]*cy;
584                                 placement->origin[0] = x2;
585                                 placement->origin[2] = z2;
586
587                                 // y-axis rotation for direction
588                                 x2 = placement->direction[0]*cy+placement->direction[2]*sy;
589                                 z2 = -placement->direction[0]*sy+placement->direction[2]*cy;
590                                 placement->direction[0] = x2;
591                                 placement->direction[2] = z2;
592
593                                 // y-axis rotation for up
594                                 x2 = placement->up[0]*cy+placement->up[2]*sy;
595                                 z2 = -placement->up[0]*sy+placement->up[2]*cy;
596                                 placement->up[0] = x2;
597                                 placement->up[2] = z2;
598
599                                 // z-axis rotation for origin
600                                 x2 = placement->origin[0]*cz-placement->origin[1]*sz;
601                                 y2 = placement->origin[0]*sz+placement->origin[1]*cz;
602                                 placement->origin[0] = x2;
603                                 placement->origin[1] = y2;
604
605                                 // z-axis rotation for direction
606                                 x2 = placement->direction[0]*cz-placement->direction[1]*sz;
607                                 y2 = placement->direction[0]*sz+placement->direction[1]*cz;
608                                 placement->direction[0] = x2;
609                                 placement->direction[1] = y2;
610
611                                 // z-axis rotation for up
612                                 x2 = placement->up[0]*cz-placement->up[1]*sz;
613                                 y2 = placement->up[0]*sz+placement->up[1]*cz;
614                                 placement->up[0] = x2;
615                                 placement->up[1] = y2;
616
617                                 // x-axis rotation for origin
618                                 y2 = placement->origin[1]*cx-placement->origin[2]*sx;
619                                 z2 = placement->origin[1]*sx+placement->origin[2]*cx;
620                                 placement->origin[1] = y2;
621                                 placement->origin[2] = z2;
622
623                                 // x-axis rotation for direction vector
624                                 y2 = placement->direction[1]*cx-placement->direction[2]*sx;
625                                 z2 = placement->direction[1]*sx+placement->direction[2]*cx;
626                                 placement->direction[1] = y2;
627                                 placement->direction[2] = z2;
628
629                                 // x-axis rotation for up vector
630                                 y2 = placement->up[1]*cx-placement->up[2]*sx;
631                                 z2 = placement->up[1]*sx+placement->up[2]*cx;
632                                 placement->up[1] = y2;
633                                 placement->up[2] = z2;
634
635                                 // translate origin
636                                 placement->origin[0] += curTranslation[i][0];
637                                 placement->origin[1] += curTranslation[i][1];
638                                 placement->origin[2] += curTranslation[i][2];
639
640                                 // translate back to local coord
641                                 placement->direction[0] += curTranslation[i][0];
642                                 placement->direction[1] += curTranslation[i][1];
643                                 placement->direction[2] += curTranslation[i][2];
644
645                                 // translate back to local coord
646                                 placement->up[0] += curTranslation[i][0];
647                                 placement->up[1] += curTranslation[i][1];
648                                 placement->up[2] += curTranslation[i][2];
649                         }
650                 }
651 #else
652                 // This screwed up and needs to be sorted out!!!
653                 // The stack info needs to be written too instead of the jointList for j > numJoints for Skeleton
654                 for(j = i-1; j < stackSize-1; ++j)
655                 {
656                         // y-axis rotation for origin
657                         x2 = jointList[j].placement.origin[0]*cy+jointList[j].placement.origin[2]*sy;
658                         z2 = -jointList[j].placement.origin[0]*sy+jointList[j].placement.origin[2]*cy;
659                         jointList[j].placement.origin[0] = x2;
660                         jointList[j].placement.origin[2] = z2;
661
662                         // y-axis rotation for direction
663                         x2 = jointList[j].placement.direction[0]*cy+jointList[j].placement.direction[2]*sy;
664                         z2 = -jointList[j].placement.direction[0]*sy+jointList[j].placement.direction[2]*cy;
665                         jointList[j].placement.direction[0] = x2;
666                         jointList[j].placement.direction[2] = z2;
667
668                         // y-axis rotation for up
669                         x2 = jointList[j].placement.up[0]*cy+jointList[j].placement.up[2]*sy;
670                         z2 = -jointList[j].placement.up[0]*sy+jointList[j].placement.up[2]*cy;
671                         jointList[j].placement.up[0] = x2;
672                         jointList[j].placement.up[2] = z2;
673
674                         // z-axis rotation for origin
675                         x2 = jointList[j].placement.origin[0]*cz-jointList[j].placement.origin[1]*sz;
676                         y2 = jointList[j].placement.origin[0]*sz+jointList[j].placement.origin[1]*cz;
677                         jointList[j].placement.origin[0] = x2;
678                         jointList[j].placement.origin[1] = y2;
679
680                         // z-axis rotation for direction
681                         x2 = jointList[j].placement.direction[0]*cz-jointList[j].placement.direction[1]*sz;
682                         y2 = jointList[j].placement.direction[0]*sz+jointList[j].placement.direction[1]*cz;
683                         jointList[j].placement.direction[0] = x2;
684                         jointList[j].placement.direction[1] = y2;
685
686                         // z-axis rotation for up
687                         x2 = jointList[j].placement.up[0]*cz-jointList[j].placement.up[1]*sz;
688                         y2 = jointList[j].placement.up[0]*sz+jointList[j].placement.up[1]*cz;
689                         jointList[j].placement.up[0] = x2;
690                         jointList[j].placement.up[1] = y2;
691
692                         // x-axis rotation for origin
693                         y2 = jointList[j].placement.origin[1]*cx-jointList[j].placement.origin[2]*sx;
694                         z2 = jointList[j].placement.origin[1]*sx+jointList[j].placement.origin[2]*cx;
695                         jointList[j].placement.origin[1] = y2;
696                         jointList[j].placement.origin[2] = z2;
697
698                         // x-axis rotation for direction vector
699                         y2 = jointList[j].placement.direction[1]*cx-jointList[j].placement.direction[2]*sx;
700                         z2 = jointList[j].placement.direction[1]*sx+jointList[j].placement.direction[2]*cx;
701                         jointList[j].placement.direction[1] = y2;
702                         jointList[j].placement.direction[2] = z2;
703
704                         // x-axis rotation for up vector
705                         y2 = jointList[j].placement.up[1]*cx-jointList[j].placement.up[2]*sx;
706                         z2 = jointList[j].placement.up[1]*sx+jointList[j].placement.up[2]*cx;
707                         jointList[j].placement.up[1] = y2;
708                         jointList[j].placement.up[2] = z2;
709
710                         if(curCorrespondingJoint[j+1] != -1)
711                         {
712                                 // translate origin
713                                 jointList[j].placement.origin[0] += curTranslation[i-1][0];
714                                 jointList[j].placement.origin[1] += curTranslation[i-1][1];
715                                 jointList[j].placement.origin[2] += curTranslation[i-1][2];
716
717                                 // translate back to local coord
718                                 jointList[j].placement.direction[0] += curTranslation[i-1][0];
719                                 jointList[j].placement.direction[1] += curTranslation[i-1][1];
720                                 jointList[j].placement.direction[2] += curTranslation[i-1][2];
721
722                                 // translate back to local coord
723                                 jointList[j].placement.up[0] += curTranslation[i-1][0];
724                                 jointList[j].placement.up[1] += curTranslation[i-1][1];
725                                 jointList[j].placement.up[2] += curTranslation[i-1][2];
726                         }
727                 }
728 #endif
729         }
730 }
731
732 void LoadModelTransform(char *fileName)
733 {
734         FILE *file1;
735     int dot = '.';
736         char *dotstart;
737         char    InputFileName[256];
738
739         dotstart = strrchr(fileName,dot); // Does it already have an extension on the file name?
740
741         if (!dotstart)
742         {
743                 strcpy(InputFileName, fileName);
744                 strcat(InputFileName, ".hrc");
745                 if((file1 = fopen(InputFileName, "rb")) != NULL)
746                 {
747                         fclose(file1);
748
749                         LoadHRCGlobals(InputFileName);
750
751                         printf(" - assuming .HRC\n");
752                         return;
753                 }
754
755                 Error("\n Could not open file '%s':\n"
756                         "No HRC match.\n", fileName);
757         }
758         else
759         {
760                 if((file1 = fopen(fileName, "rb")) != NULL)
761                 {
762 //                      printf("\n");
763                         fclose(file1);
764                         if (strcmp(dotstart,".hrc") == 0 || strcmp(dotstart,".HRC") == 0)
765                         {
766                                 LoadHRCGlobals(fileName);
767                                 return;
768                         }
769                 }
770
771                 Error("Could not open file '%s':\n",fileName);
772         }
773 }
774
775 void LoadModelClusters(char *fileName, int **clusterList, int *num_verts, int skelType)
776 {
777         FILE *file1;
778     int dot = '.';
779         char *dotstart;
780         char    InputFileName[256];
781
782         dotstart = strrchr(fileName,dot); // Does it already have an extension on the file name?
783
784         if (!dotstart)
785         {
786                 strcpy(InputFileName, fileName);
787                 strcat(InputFileName, ".hrc");
788                 if((file1 = fopen(InputFileName, "rb")) != NULL)
789                 {
790                         fclose(file1);
791
792                         LoadHRCClustered(InputFileName, clusterList, num_verts, skelType);
793
794                         printf(" - assuming .HRC\n");
795                         return;
796                 }
797
798                 Error("\n Could not open file '%s':\n"
799                         "No HRC match.\n", fileName);
800         }
801         else
802         {
803                 if((file1 = fopen(fileName, "rb")) != NULL)
804                 {
805 //                      printf("\n");
806                         fclose(file1);
807                         if (strcmp(dotstart,".hrc") == 0 || strcmp(dotstart,".HRC") == 0)
808                         {
809                                 LoadHRCClustered(fileName, clusterList, num_verts, skelType);
810                                 return;
811                         }
812                 }
813
814                 Error("Could not open file '%s':\n",fileName);
815         }
816 }
817
818 void LoadSkeleton(char *fileName, QD_SkeletalJoint_t *jointList, int skelType)
819 {
820         FILE *file1;
821     int dot = '.';
822         char *dotstart;
823         char    InputFileName[256];
824
825         dotstart = strrchr(fileName,dot); // Does it already have an extension on the file name?
826
827         if (!dotstart)
828         {
829                 strcpy(InputFileName, fileName);
830                 strcat(InputFileName, ".hrc");
831                 if((file1 = fopen(InputFileName, "rb")) != NULL)
832                 {
833                         fclose(file1);
834
835                         LoadHRCJointList(InputFileName, jointList, skelType);
836
837                         printf(" - assuming .HRC\n");
838                         return;
839                 }
840
841                 Error("\n Could not open file '%s':\n"
842                         "No HRC.\n", fileName);
843         }
844         else
845         {
846                 if((file1 = fopen(fileName, "rb")) != NULL)
847                 {
848 //                      printf("\n");
849                         fclose(file1);
850                         if (strcmp(dotstart,".hrc") == 0 || strcmp(dotstart,".HRC") == 0)
851                         {
852                                 LoadHRCJointList(fileName, jointList, skelType);
853
854                                 return;
855                         }
856                 }
857
858                 Error("Could not open file '%s':\n",fileName);
859         }
860 }
861
862 /*
863 ===============
864 GrabSkeletalFrame
865 ===============
866 */
867 void GrabSkeletalFrame(char *frame)
868 {
869         char    file1[1024];
870         char    *framefile;
871         fmframe_t       *fr;
872
873         framefile = FindFrameFile (frame);
874
875         sprintf (file1, "%s/%s", cdarchive, framefile);
876         ExpandPathAndArchive (file1);
877
878         sprintf (file1, "%s/%s",cddir, framefile);
879
880         printf ("Grabbing Skeletal Frame %s\n", file1);
881
882         fr = &g_frames[fmheader.num_frames - 1]; // last frame read in
883
884         LoadSkeleton(file1, fr->joints, g_skelModel.type);
885 }
886
887 /*
888 ===============
889 GrabModelTransform
890 ===============
891 */
892 void GrabModelTransform(char *frame)
893 {
894         char    file1[1024];
895         char    *framefile;
896         fmframe_t       *fr;
897
898         framefile = FindFrameFile (frame);
899
900         sprintf (file1, "%s/%s", cdarchive, framefile);
901         ExpandPathAndArchive (file1);
902
903         sprintf (file1, "%s/%s",cddir, framefile);
904
905 //      printf ("grabbing %s\n", file1);
906
907         fr = &g_frames[fmheader.num_frames - 1]; // last frame read in
908
909         LoadModelTransform(file1);
910 }
911
912 void Cmd_FMCluster()
913 {
914         char file1[1024];
915
916         GetScriptToken (false);
917
918         printf ("---------------------\n");
919         sprintf (file1, "%s/%s", cdpartial, token);
920         printf ("%s\n", file1);
921
922         ExpandPathAndArchive (file1);
923
924         sprintf (file1, "%s/%s", cddir, token);
925
926         g_skelModel.clustered = -1;
927
928         LoadModelClusters(file1, (int **)&g_skelModel.clusters, (int *)&g_skelModel.num_verts, g_skelModel.type);
929
930         g_skelModel.new_num_verts[0] = g_skelModel.num_verts[0];
931
932         g_skelModel.clustered = true;
933 }
934
935 void Cmd_FMSkeleton()
936 {
937         GetScriptToken (false);
938         g_skelModel.type = atoi(token);
939 }
940
941 void Cmd_FMSkeletalFrame()
942 {
943         while (ScriptTokenAvailable())
944         {
945                 GetScriptToken (false);
946                 if (g_skipmodel)
947                 {
948                         GetScriptToken (false);
949                         continue;
950                 }
951                 if (g_release || g_archive)
952                 {
953                         fmheader.num_frames = 1;        // don't skip the writeout
954                         GetScriptToken (false);
955                         continue;
956                 }
957
958                 H_printf("#define FRAME_%-16s\t%i\n", token, fmheader.num_frames);
959
960                 GrabModelTransform (token);
961                 GrabFrame (token);
962                 GrabSkeletalFrame (token);
963
964                 // need to add the up and dir points to the frame bounds here
965                 // using AddPointToBounds (ptrivert[index_xyz].v, fr->mins, fr->maxs);
966                 // then remove fudge in determining scale on frame write out
967         }
968 }
969
970 static void LoadHRCReferences(char *fileName, fmframe_t *fr)
971 {
972 #define MAX_STACK 64
973         int i, j, k;
974         vec3d_t curTranslation[MAX_STACK], curRotation[MAX_STACK];
975         int curCorrespondingJoint[MAX_STACK];
976         int currentStack, stackSize;
977         double cx, sx, cy, sy, cz, sz;
978         double rx, ry, rz;
979         double x2, y2, z2;
980         char stripped[SKELETAL_NAME_MAX];
981         Placement_d_t *placement;
982         int refnum;
983
984         TK_OpenSource(fileName);
985         TK_FetchRequire(TK_HRCH);
986         TK_FetchRequire(TK_COLON);
987         TK_FetchRequire(TK_SOFTIMAGE);
988
989         if (RefPointNum <= 0)
990         {       // There were no labels indicated in the QDT, so use the hard-coded stuff.
991                 refnum = numReferences[g_skelModel.references];
992         }
993         else
994         {
995                 refnum = RefPointNum;
996         }
997
998         for(k = 0; k < refnum; ++k)
999         {
1000                 currentStack = 0;
1001
1002                 // Load the root to get translation and initial rotation
1003 //              TK_Beyond(TK_MODEL);
1004
1005                 while(TK_Search(TK_NAME) != TK_EOF)
1006                 {
1007                         TK_Require(TK_STRING);
1008
1009                         StripTrailingDigits(tk_String, stripped);
1010
1011                         if (RefPointNum == 0)
1012                         {       // Hard coded refpoint labels
1013                                 if(stricmp(stripped, 
1014                                         referenceRootNames[referenceRootNameOffsets[g_skelModel.references]+k]) == 0)
1015                                 {
1016                                         break;
1017                                 }
1018                         }
1019                         else
1020                         {       // labels indicated by the QDT
1021                                 if(stricmp(stripped, RefPointNameList[k]) == 0)
1022                                 {
1023                                         break;
1024                                 }
1025                         }
1026                 }
1027
1028                 if(tk_Token == TK_EOF)
1029                 {
1030                         if (RefPointNum == 0)
1031                         {       // Hard coded refpoint labels
1032                                 Error("Bone Chain Root: %s not found\n", referenceRootNames[referenceRootNameOffsets[g_skelModel.references]]);
1033                         }
1034                         else
1035                         {       // labels indicated by the QDT
1036                                 Error("Bone Chain Root: %s not found\n", RefPointNameList[k]);
1037                         }
1038                         return;
1039                 }
1040
1041 //              TK_Beyond(TK_SCALING);
1042
1043 //              ParseVec3d(curScale[currentStack]);
1044
1045                 TK_Beyond(TK_ROTATION);
1046
1047                 ParseRotation3d(curRotation[currentStack]);
1048
1049                 TK_Beyond(TK_TRANSLATION);
1050
1051                 ParseVec3d(curTranslation[currentStack]);
1052
1053                 // account for global model translation
1054                 curTranslation[currentStack][1] += g_skelModel.translation[0];
1055                 curTranslation[currentStack][2] += g_skelModel.translation[1];
1056                 curTranslation[currentStack][0] += g_skelModel.translation[2];
1057
1058                 curCorrespondingJoint[currentStack] = -1;
1059
1060 //              rjr - this one not needed, as there is also a stack increment 20 lines below???
1061 //              ++currentStack;
1062
1063                 // Load the joint to get orientation
1064                 TK_Beyond(TK_MODEL);
1065
1066 //              TK_Beyond(TK_SCALING);
1067
1068 //              ParseVec3d(curScale[currentStack]);
1069
1070                 TK_Beyond(TK_ROTATION);
1071
1072                 ParseRotation3d(curRotation[currentStack]);
1073
1074 //              TK_Beyond(TK_TRANSLATION);
1075
1076 //              ParseVec3d(curTranslation[currentStack]);
1077
1078                 fr->references[k].placement.origin[1] = 0.0;
1079                 fr->references[k].placement.origin[2] = 0.0;
1080                 fr->references[k].placement.origin[0] = 0.0;
1081
1082                 fr->references[k].placement.direction[1] = 20.0;
1083                 fr->references[k].placement.direction[2] = 0.0;
1084                 fr->references[k].placement.direction[0] = 0.0;
1085
1086                 fr->references[k].placement.up[1] = 0.0;
1087                 fr->references[k].placement.up[2] = 20.0;
1088                 fr->references[k].placement.up[0] = 0.0;
1089
1090                 curCorrespondingJoint[currentStack] = k;
1091
1092                 ++currentStack;
1093
1094                 stackSize = currentStack;
1095
1096                 for(i = stackSize - 1; i >= 0; --i)
1097                 {
1098                         rx = curRotation[i][0]*ANGLE_TO_RAD;
1099                         ry = curRotation[i][1]*ANGLE_TO_RAD;
1100                         rz = curRotation[i][2]*ANGLE_TO_RAD;
1101
1102                         cx = cos(rx);
1103                         sx = sin(rx);
1104
1105                         cy = cos(ry);
1106                         sy = sin(ry);
1107
1108                         cz = cos(rz);
1109                         sz = sin(rz);
1110
1111                         for(j = i; j < stackSize; ++j)
1112                         {
1113                                 if(curCorrespondingJoint[j] != -1)
1114                                 {
1115                                         placement = &fr->references[curCorrespondingJoint[j]].placement;
1116
1117                                         // y-axis rotation for origin
1118                                         x2 = placement->origin[0]*cy+placement->origin[2]*sy;
1119                                         z2 = -placement->origin[0]*sy+placement->origin[2]*cy;
1120                                         placement->origin[0] = x2;
1121                                         placement->origin[2] = z2;
1122
1123                                         // y-axis rotation for direction
1124                                         x2 = placement->direction[0]*cy+placement->direction[2]*sy;
1125                                         z2 = -placement->direction[0]*sy+placement->direction[2]*cy;
1126                                         placement->direction[0] = x2;
1127                                         placement->direction[2] = z2;
1128
1129                                         // y-axis rotation for up
1130                                         x2 = placement->up[0]*cy+placement->up[2]*sy;
1131                                         z2 = -placement->up[0]*sy+placement->up[2]*cy;
1132                                         placement->up[0] = x2;
1133                                         placement->up[2] = z2;
1134
1135                                         // z-axis rotation for origin
1136                                         x2 = placement->origin[0]*cz-placement->origin[1]*sz;
1137                                         y2 = placement->origin[0]*sz+placement->origin[1]*cz;
1138                                         placement->origin[0] = x2;
1139                                         placement->origin[1] = y2;
1140
1141                                         // z-axis rotation for direction
1142                                         x2 = placement->direction[0]*cz-placement->direction[1]*sz;
1143                                         y2 = placement->direction[0]*sz+placement->direction[1]*cz;
1144                                         placement->direction[0] = x2;
1145                                         placement->direction[1] = y2;
1146
1147                                         // z-axis rotation for up
1148                                         x2 = placement->up[0]*cz-placement->up[1]*sz;
1149                                         y2 = placement->up[0]*sz+placement->up[1]*cz;
1150                                         placement->up[0] = x2;
1151                                         placement->up[1] = y2;
1152
1153                                         // x-axis rotation for origin
1154                                         y2 = placement->origin[1]*cx-placement->origin[2]*sx;
1155                                         z2 = placement->origin[1]*sx+placement->origin[2]*cx;
1156                                         placement->origin[1] = y2;
1157                                         placement->origin[2] = z2;
1158
1159                                         // x-axis rotation for direction vector
1160                                         y2 = placement->direction[1]*cx-placement->direction[2]*sx;
1161                                         z2 = placement->direction[1]*sx+placement->direction[2]*cx;
1162                                         placement->direction[1] = y2;
1163                                         placement->direction[2] = z2;
1164
1165                                         // x-axis rotation for up vector
1166                                         y2 = placement->up[1]*cx-placement->up[2]*sx;
1167                                         z2 = placement->up[1]*sx+placement->up[2]*cx;
1168                                         placement->up[1] = y2;
1169                                         placement->up[2] = z2;
1170
1171                                         // translate origin
1172                                         placement->origin[0] += curTranslation[i][0];
1173                                         placement->origin[1] += curTranslation[i][1];
1174                                         placement->origin[2] += curTranslation[i][2];
1175
1176                                         // translate back to local coord
1177                                         placement->direction[0] += curTranslation[i][0];
1178                                         placement->direction[1] += curTranslation[i][1];
1179                                         placement->direction[2] += curTranslation[i][2];
1180
1181                                         // translate back to local coord
1182                                         placement->up[0] += curTranslation[i][0];
1183                                         placement->up[1] += curTranslation[i][1];
1184                                         placement->up[2] += curTranslation[i][2];
1185
1186                                 }
1187                         }
1188                 }
1189                 printf("%f, %f, %f\n", placement->origin[0], placement->origin[1], placement->origin[2]);
1190         }
1191         printf("\n");
1192 }
1193
1194 void Cmd_FMReferenced()
1195 {
1196         int i;
1197
1198         GetScriptToken (false);
1199         g_skelModel.references = atoi(token);
1200
1201         // Guess what?  Now, we now want a list of strings to look for here instead of a hard-coded list
1202         for (i=0; i<REF_MAX_POINTS; i++)
1203         {
1204                 if (ScriptTokenAvailable())
1205                 {       // There is yet another reference point waiting.
1206                         GetScriptToken(false);
1207                         strcpy(RefPointNameList[i], token);
1208                 }
1209                 else
1210                 {
1211                         break;
1212                 }
1213         }
1214
1215         RefPointNum = i;
1216
1217         if (RefPointNum > 0)
1218         {
1219                 printf("Searching for %d different reference points.\n", RefPointNum);
1220         }
1221         else
1222         {
1223                 printf("Using built-in reference points.\n");
1224         }
1225
1226 }
1227
1228 void LoadReferences(char *fileName, fmframe_t *fr)
1229 {
1230         FILE *file1;
1231     int dot = '.';
1232         char *dotstart;
1233         char    InputFileName[256];
1234
1235         dotstart = strrchr(fileName,dot); // Does it already have an extension on the file name?
1236
1237         if (!dotstart)
1238         {
1239                 strcpy(InputFileName, fileName);
1240                 strcat(InputFileName, ".hrc");
1241                 if((file1 = fopen(InputFileName, "rb")) != NULL)
1242                 {
1243                         fclose(file1);
1244
1245                         LoadHRCReferences(InputFileName, fr);
1246
1247                         printf(" - assuming .HRC\n");
1248                         return;
1249                 }
1250
1251                 Error("\n Could not open file '%s':\n"
1252                         "No HRC.\n", fileName);
1253         }
1254         else
1255         {
1256                 if((file1 = fopen(fileName, "rb")) != NULL)
1257                 {
1258                         printf("\n");
1259                         fclose(file1);
1260                         if (strcmp(dotstart,".hrc") == 0 || strcmp(dotstart,".HRC") == 0)
1261                         {
1262                                 LoadHRCReferences(fileName, fr);
1263
1264                                 return;
1265                         }
1266                 }
1267
1268                 Error("Could not open file '%s':\n",fileName);
1269         }
1270 }
1271
1272 void GrabReferencedFrame(char *frame)
1273 {
1274         char    file1[1024];
1275         char    *framefile;
1276         fmframe_t       *fr;
1277
1278         framefile = FindFrameFile (frame);
1279
1280         sprintf (file1, "%s/%s", cdarchive, framefile);
1281         ExpandPathAndArchive (file1);
1282
1283         sprintf (file1, "%s/%s",cddir, framefile);
1284
1285         printf ("Grabbing Referenced %s\n", file1);
1286
1287         fr = &g_frames[fmheader.num_frames - 1]; // last frame read in
1288
1289         LoadReferences(file1, fr);
1290 }
1291