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