]> git.xonotic.org Git - xonotic/netradiant.git/blobdiff - tools/quake2/qdata_heretic2/qd_skeletons.c
set eol-style
[xonotic/netradiant.git] / tools / quake2 / qdata_heretic2 / qd_skeletons.c
index 18868f1ee62c66e18115db0553bd4ece9031234c..f36fb1dff63fcb4494c2da235e4620ac02b92f08 100644 (file)
-/*\r
-Copyright (C) 1999-2007 id Software, Inc. and contributors.\r
-For a list of contributors, see the accompanying CONTRIBUTORS file.\r
-\r
-This file is part of GtkRadiant.\r
-\r
-GtkRadiant is free software; you can redistribute it and/or modify\r
-it under the terms of the GNU General Public License as published by\r
-the Free Software Foundation; either version 2 of the License, or\r
-(at your option) any later version.\r
-\r
-GtkRadiant is distributed in the hope that it will be useful,\r
-but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
-GNU General Public License for more details.\r
-\r
-You should have received a copy of the GNU General Public License\r
-along with GtkRadiant; if not, write to the Free Software\r
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\r
-*/\r
-\r
-#include "qd_skeletons.h"\r
-#include "skeletons.h"\r
-#include "qd_fmodel.h"\r
-#include "angles.h"\r
-#include "token.h"\r
-#include "qdata.h"\r
-#include "reference.h"\r
-\r
-#include <assert.h>\r
-#include <math.h>\r
-#include <memory.h>\r
-\r
-\r
-// We're assuming no more than 16 reference points, with no more than 32 characters in the name\r
-char RefPointNameList[REF_MAX_POINTS][REF_MAX_STRLEN];\r
-int     RefPointNum = 0;\r
-\r
-Skeletalfmheader_t g_skelModel;\r
-\r
-void ClearSkeletalModel()\r
-{\r
-       g_skelModel.type = SKEL_NULL;\r
-       g_skelModel.clustered = false;\r
-       g_skelModel.references = REF_NULL;\r
-}\r
-\r
-//==========================================================================\r
-//\r
-// LoadHRCClustered\r
-//\r
-//==========================================================================\r
-\r
-// Places the null terminated src string into the dest string less any trailing digits or underscores\r
-void StripTrailingDigits(char *src, char *dest)\r
-{\r
-#ifndef NDEBUG\r
-       int max = SKELETAL_NAME_MAX; // should be sufficient for inteded use on names from hrc files\r
-#endif\r
-       int i = 0;\r
-\r
-       while(src[i] != '\0')\r
-       {\r
-               ++i;\r
-#ifndef NDEBUG\r
-               assert(i < max);\r
-#endif\r
-       }\r
-\r
-       while((src[--i] >= '0' && src[i] <= '9') || src[i] == '_')\r
-       {\r
-\r
-       }\r
-\r
-       memcpy(dest, src, ++i);\r
-\r
-       dest[i] = '\0';\r
-}\r
-\r
-static void LoadHRCClustered(char *fileName, int **clusterList, int *num_verts, int skelType)\r
-{\r
-       extern void HandleHRCModel(triangle_t **triList, int *triangleCount, \r
-               mesh_node_t **nodesList, int *num_mesh_nodes, int ActiveNode, int Depth);\r
-\r
-       extern mesh_node_t      *pmnodes;\r
-\r
-       triangle_t *triList;\r
-//     mesh_node_t *nodesList;\r
-       int num_mesh_nodes = 0, triangleCount = 0;\r
-\r
-#if 0\r
-       int i;\r
-       int j, numVerts;\r
-       char stripped[SKELETAL_NAME_MAX];\r
-\r
-       for( i = 1; i < numJointsInSkeleton[skelType] + 1; ++i)\r
-       {\r
-               num_verts[i] = 0;\r
-       }\r
-\r
-       TK_OpenSource(fileName);\r
-       TK_FetchRequire(TK_HRCH);\r
-       TK_FetchRequire(TK_COLON);\r
-       TK_FetchRequire(TK_SOFTIMAGE);\r
-\r
-       TK_Beyond(TK_CLUSTERS);\r
-\r
-       while(TK_Search(TK_CLUSTER_NAME) != TK_EOF)\r
-       {\r
-               TK_Require(TK_STRING);\r
-\r
-               StripTrailingDigits(tk_String, stripped);\r
-\r
-               for( i = 0; i < numJointsInSkeleton[skelType]; ++i)\r
-               {\r
-                       if(stricmp(stripped, skeletonJointNames[skeletonNameOffsets[skelType]+i]) == 0)\r
-                       {\r
-                               i = -i + numJointsInSkeleton[skelType] - 1;\r
-\r
-                               TK_BeyondRequire(TK_NUM_CLUSTER_VERTICES, TK_INTNUMBER);\r
-\r
-                               numVerts = tk_IntNumber;\r
-\r
-                               if(!num_verts[i+1])     // first set of verts for cluster\r
-                               {\r
-                                       clusterList[i] = SafeMalloc(numVerts*sizeof(int), "LoadHRCClustered");\r
-                                       assert(clusterList[i]);\r
-                               }\r
-                               else                            // any later sets of verts need to copy current\r
-                               {\r
-                                       int *temp;\r
-\r
-                                       temp = SafeMalloc((num_verts[i+1]+numVerts)*sizeof(int), "LoadHRCClustered");\r
-                                       assert(temp);\r
-\r
-                                       memcpy(temp + numVerts, clusterList[i], num_verts[i+1]*sizeof(int));\r
-\r
-                                       free(clusterList[i]);\r
-\r
-                                       clusterList[i] = temp;\r
-                               }\r
-\r
-                               // currently this function is only called by LoadModelClusters.\r
-                               // Apparently the matching free has disappeared, \r
-                               // should probably be free at the end of FMCmd_Base\r
-\r
-                               TK_Beyond(TK_LBRACE);\r
-\r
-                               for(j = 0; j < numVerts; ++j)\r
-                               {\r
-                                       TK_Require(TK_INTNUMBER);\r
-                                       clusterList[i][j] = tk_IntNumber;\r
-                                       TK_Fetch();\r
-                               }\r
-\r
-                               num_verts[i+1] += numVerts;\r
-\r
-                               break;\r
-                       }\r
-               }\r
-       }\r
-\r
-       num_verts[0] = numJointsInSkeleton[skelType];\r
-#endif\r
-\r
-#if 1  // get the index number localized to the root\r
-//     for( i = 1; i < numJointsInSkeleton[skelType] + 1; ++i)\r
-//     {\r
-//             g_skelModel.num_verts[i] = 0;\r
-//     }\r
-\r
-       TK_OpenSource(fileName);\r
-       TK_FetchRequire(TK_HRCH);\r
-       TK_FetchRequire(TK_COLON);\r
-       TK_FetchRequire(TK_SOFTIMAGE);\r
-\r
-       // prime it\r
-       TK_Beyond(TK_MODEL);\r
-\r
-       triList = (triangle_t *) SafeMalloc(MAXTRIANGLES*sizeof(triangle_t), "Triangle list");\r
-       memset(triList,0,MAXTRIANGLES*sizeof(triangle_t));\r
-//     nodesList = SafeMalloc(MAX_FM_MESH_NODES * sizeof(mesh_node_t), "Mesh Node List");\r
-       pmnodes = (mesh_node_t *) SafeMalloc(MAX_FM_MESH_NODES * sizeof(mesh_node_t), "Mesh Node List");\r
-\r
-       memset(pmnodes, 0, MAX_FM_MESH_NODES * sizeof(mesh_node_t));\r
-\r
-       // this should eventually use a stripped down version of this\r
-       HandleHRCModel(&triList, &triangleCount, &pmnodes, &num_mesh_nodes, 0, 0);\r
-\r
-//     free(nodesList);\r
-       free(triList);\r
-\r
-       num_verts[0] = numJointsInSkeleton[skelType];\r
-#endif\r
-}\r
-\r
-void ReadHRCClusterList(mesh_node_t *meshNode, int baseIndex)\r
-{\r
-       int i, j, numVerts;\r
-       tokenType_t nextToken;\r
-       char stripped[SKELETAL_NAME_MAX];\r
-\r
-       meshNode->clustered = true;\r
-\r
-       nextToken = TK_Get(TK_CLUSTER_NAME);\r
-\r
-       while (nextToken == TK_CLUSTER_NAME)\r
-       {\r
-               TK_FetchRequire(TK_STRING);\r
-\r
-               StripTrailingDigits(tk_String, stripped);\r
-\r
-               for( i = 0; i < numJointsInSkeleton[g_skelModel.type]; ++i)\r
-               {\r
-                       if(stricmp(stripped, skeletonJointNames[skeletonNameOffsets[g_skelModel.type]+i]) == 0)\r
-                       {\r
-                               i = -i + numJointsInSkeleton[g_skelModel.type] - 1;\r
-\r
-                               TK_BeyondRequire(TK_NUM_CLUSTER_VERTICES, TK_INTNUMBER);\r
-\r
-                               numVerts = tk_IntNumber;\r
-\r
-                               if(!baseIndex)\r
-                               {\r
-                                       meshNode->clusters[i] = (int *) SafeMalloc(numVerts*sizeof(int), "ReadHRCClusterList");\r
-                                       assert(meshNode->clusters[i]);\r
-                               }\r
-                               else\r
-                               {\r
-                                       int *temp; \r
-\r
-                                       temp = meshNode->clusters[i];\r
-                                       meshNode->clusters[i] = (int *) SafeMalloc((meshNode->num_verts[i+1]+numVerts)*sizeof(int), "ReadHRCClusterList");\r
-                                       assert(meshNode->clusters[i]);\r
-\r
-                                       memcpy(meshNode->clusters[i], temp, meshNode->num_verts[i+1]*sizeof(int));\r
-                                       free(temp);\r
-                               }\r
-\r
-                               // currently this function is only called by LoadModelClusters.\r
-                               // Apparently the matching free has disappeared, \r
-                               // should probably be free at the end of FMCmd_Base\r
-\r
-                               TK_Beyond(TK_LBRACE);\r
-\r
-                               for(j = 0; j < numVerts; ++j)\r
-                               {\r
-                                       TK_Require(TK_INTNUMBER);\r
-                                       meshNode->clusters[i][baseIndex+j] = tk_IntNumber+baseIndex;\r
-                                       TK_Fetch();\r
-                               }\r
-\r
-                               if(baseIndex)\r
-                               {\r
-                                       meshNode->num_verts[i+1] += numVerts;\r
-                               }\r
-                               else\r
-                               {\r
-                                       meshNode->num_verts[i+1] = numVerts;\r
-                               }\r
-\r
-                               break;\r
-                       }\r
-               }\r
-\r
-               TK_BeyondRequire(TK_CLUSTER_STATE, TK_INTNUMBER);\r
-               nextToken = TK_Fetch();\r
-       }\r
-}\r
-\r
-static void LoadHRCGlobals(char *fileName)\r
-{\r
-       int i;\r
-\r
-       TK_OpenSource(fileName);\r
-       TK_FetchRequire(TK_HRCH);\r
-       TK_FetchRequire(TK_COLON);\r
-       TK_FetchRequire(TK_SOFTIMAGE);\r
-       TK_Beyond(TK_MODEL);\r
-\r
-       TK_Beyond(TK_SCALING);\r
-       for(i = 0; i < 3; i++)\r
-       {\r
-               TK_Require(TK_FLOATNUMBER);\r
-               g_skelModel.scaling[i] = tk_FloatNumber;\r
-               TK_Fetch();\r
-       }\r
-\r
-       TK_Beyond(TK_ROTATION);\r
-       for(i = 0; i < 3; i++)\r
-       {\r
-               TK_Require(TK_FLOATNUMBER);\r
-               g_skelModel.rotation[i] = tk_FloatNumber;\r
-               TK_Fetch();\r
-       }\r
-\r
-       TK_Beyond(TK_TRANSLATION);\r
-       for(i = 0; i < 3; i++)\r
-       {\r
-               TK_Require(TK_FLOATNUMBER);\r
-               g_skelModel.translation[i] = tk_FloatNumber;\r
-               TK_Fetch();\r
-       }\r
-}\r
-\r
-static void ParseVec3(vec3_t in)\r
-{\r
-       TK_Require(TK_FLOATNUMBER);\r
-       in[1] = tk_FloatNumber;\r
-       TK_FetchRequire(TK_FLOATNUMBER);\r
-       in[2] = tk_FloatNumber;\r
-       TK_FetchRequire(TK_FLOATNUMBER);\r
-       in[0] = tk_FloatNumber;\r
-}\r
-\r
-static void ParseVec3d(vec3d_t in)\r
-{\r
-       TK_Require(TK_FLOATNUMBER);\r
-       in[1] = tk_FloatNumber;\r
-       TK_FetchRequire(TK_FLOATNUMBER);\r
-       in[2] = tk_FloatNumber;\r
-       TK_FetchRequire(TK_FLOATNUMBER);\r
-       in[0] = tk_FloatNumber;\r
-}\r
-\r
-static void ParseRotation3(vec3_t in)\r
-{\r
-       TK_Require(TK_FLOATNUMBER);\r
-       in[1] = tk_FloatNumber;\r
-       TK_FetchRequire(TK_FLOATNUMBER);\r
-       in[2] = tk_FloatNumber;\r
-       TK_FetchRequire(TK_FLOATNUMBER);\r
-       in[0] = tk_FloatNumber;\r
-}\r
-\r
-static void ParseRotation3d(vec3d_t in)\r
-{\r
-       TK_Require(TK_FLOATNUMBER);\r
-       in[1] = tk_FloatNumber;\r
-       TK_FetchRequire(TK_FLOATNUMBER);\r
-       in[2] = tk_FloatNumber;\r
-       TK_FetchRequire(TK_FLOATNUMBER);\r
-       in[0] = tk_FloatNumber;\r
-}\r
-\r
-static void ParseTranslation3(vec3_t in)\r
-{\r
-       TK_Require(TK_FLOATNUMBER);\r
-       in[1] = tk_FloatNumber;\r
-       TK_FetchRequire(TK_FLOATNUMBER);\r
-       in[2] = tk_FloatNumber;\r
-       TK_FetchRequire(TK_FLOATNUMBER);\r
-       in[0] = tk_FloatNumber;\r
-}\r
-\r
-static void ParseTranslation3d(vec3d_t in)\r
-{\r
-       TK_Require(TK_FLOATNUMBER);\r
-       in[1] = tk_FloatNumber;\r
-       TK_FetchRequire(TK_FLOATNUMBER);\r
-       in[2] = tk_FloatNumber;\r
-       TK_FetchRequire(TK_FLOATNUMBER);\r
-       in[0] = tk_FloatNumber;\r
-}\r
-\r
-static void LoadHRCJointList(char *fileName, QD_SkeletalJoint_t *jointList, int skelType)\r
-{\r
-#define MAX_STACK 64\r
-       int i, j;\r
-       vec3d_t curTranslation[MAX_STACK], curRotation[MAX_STACK], curScale[MAX_STACK];\r
-       int curCorrespondingJoint[MAX_STACK];\r
-       int currentStack = 0, stackSize;\r
-       double cx, sx, cy, sy, cz, sz;\r
-       double rx, ry, rz;\r
-       double x2, y2, z2;\r
-       char stripped[SKELETAL_NAME_MAX];\r
-       Placement_d_t *placement;\r
-\r
-       TK_OpenSource(fileName);\r
-       TK_FetchRequire(TK_HRCH);\r
-       TK_FetchRequire(TK_COLON);\r
-       TK_FetchRequire(TK_SOFTIMAGE);\r
-\r
-       TK_Beyond(TK_MODEL);\r
-\r
-       while(TK_Search(TK_NAME) != TK_EOF)\r
-       {\r
-               TK_Require(TK_STRING);\r
-\r
-               StripTrailingDigits(tk_String, stripped);\r
-\r
-               if(stricmp(stripped, skeletonRootNames[skeletonRNameOffsets[skelType]]) == 0)\r
-               {\r
-                       break;\r
-               }\r
-       }\r
-\r
-       if(tk_Token == TK_EOF)\r
-       {\r
-               Error("Bone Chain Root: %s not found\n", skeletonRootNames[skeletonRNameOffsets[skelType]]);\r
-               return;\r
-       }\r
-\r
-       TK_Beyond(TK_SCALING);\r
-\r
-       ParseVec3d(curScale[currentStack]);\r
-\r
-       TK_Beyond(TK_ROTATION);\r
-\r
-       ParseRotation3d(curRotation[currentStack]);\r
-\r
-       TK_Beyond(TK_TRANSLATION);\r
-\r
-       ParseVec3d(curTranslation[currentStack]);\r
-\r
-       // account for global model translation\r
-       curTranslation[currentStack][1] += g_skelModel.translation[0];\r
-       curTranslation[currentStack][2] += g_skelModel.translation[1];\r
-       curTranslation[currentStack][0] += g_skelModel.translation[2];\r
-\r
-       curCorrespondingJoint[currentStack] = -1;\r
-\r
-       ++currentStack;\r
-\r
-       for(i = 0; i < numJointsInSkeleton[skelType]; ++i)\r
-       {\r
-               while(1)\r
-               {\r
-                       TK_Beyond(TK_MODEL);\r
-\r
-                       TK_BeyondRequire(TK_NAME, TK_STRING);\r
-\r
-                       StripTrailingDigits(tk_String, stripped);\r
-\r
-                       if(stricmp(stripped, skeletonJointNames[skeletonNameOffsets[skelType]+i]) == 0)\r
-                               break;\r
-\r
-                       TK_Beyond(TK_SCALING);\r
-\r
-                       ParseVec3d(curScale[currentStack]);\r
-\r
-                       TK_Beyond(TK_ROTATION);\r
-\r
-                       ParseRotation3d(curRotation[currentStack]);\r
-\r
-                       TK_Beyond(TK_TRANSLATION);\r
-\r
-                       ParseVec3d(curTranslation[currentStack]);\r
-\r
-                       curCorrespondingJoint[currentStack] = -1;\r
-\r
-                       ++currentStack;\r
-               }\r
-\r
-               TK_Beyond(TK_SCALING);\r
-\r
-               ParseVec3d(curScale[currentStack]);\r
-\r
-               TK_Beyond(TK_ROTATION);\r
-\r
-               ParseRotation3d(curRotation[currentStack]);\r
-\r
-               jointList[i].rotation[1] = curRotation[currentStack][1];\r
-               jointList[i].rotation[2] = curRotation[currentStack][2];\r
-               jointList[i].rotation[0] = curRotation[currentStack][0];\r
-\r
-               TK_Beyond(TK_TRANSLATION);\r
-\r
-               ParseVec3d(curTranslation[currentStack]);\r
-\r
-//             jointList[i].placement.origin[1] = curTranslation[currentStack][1];\r
-//             jointList[i].placement.origin[2] = curTranslation[currentStack][2];\r
-//             jointList[i].placement.origin[0] = curTranslation[currentStack][0];\r
-\r
-               jointList[i].placement.origin[1] = 0.0;\r
-               jointList[i].placement.origin[2] = 0.0;\r
-               jointList[i].placement.origin[0] = 0.0;\r
-\r
-               jointList[i].placement.direction[1] = 20.0;\r
-               jointList[i].placement.direction[2] = 0.0;\r
-               jointList[i].placement.direction[0] = 0.0;\r
-\r
-               jointList[i].placement.up[1] = 0.0;\r
-               jointList[i].placement.up[2] = 20.0;\r
-               jointList[i].placement.up[0] = 0.0;\r
-\r
-               curCorrespondingJoint[currentStack] = i;\r
-\r
-               ++currentStack;\r
-       }\r
-\r
-       stackSize = currentStack;\r
-\r
-#if 0\r
-       // rotate the direction and up vectors to correspond to the rotation\r
-       for(i = 0; i < numJointsInSkeleton[skelType]; ++i)\r
-       {\r
-               rx = jointList[i].rotation[0]*ANGLE_TO_RAD;\r
-               ry = jointList[i].rotation[1]*ANGLE_TO_RAD;\r
-               rz = jointList[i].rotation[2]*ANGLE_TO_RAD;\r
-\r
-               cx = cos(rx);\r
-               sx = sin(rx);\r
-\r
-               cy = cos(ry);\r
-               sy = sin(ry);\r
-\r
-               cz = cos(rz);\r
-               sz = sin(rz);\r
-\r
-               // y-axis rotation for direction\r
-               x2 = jointList[i].placement.direction[0]*cy+jointList[i].placement.direction[2]*sy;\r
-               z2 = -jointList[i].placement.direction[0]*sy+jointList[i].placement.direction[2]*cy;\r
-               jointList[i].placement.direction[0] = x2;\r
-               jointList[i].placement.direction[2] = z2;\r
-\r
-               // y-axis rotation for up\r
-               x2 = jointList[i].placement.up[0]*cy+jointList[i].placement.up[2]*sy;\r
-               z2 = -jointList[i].placement.up[0]*sy+jointList[i].placement.up[2]*cy;\r
-               jointList[i].placement.up[0] = x2;\r
-               jointList[i].placement.up[2] = z2;\r
-\r
-               // z-axis rotation for direction\r
-               x2 = jointList[i].placement.direction[0]*cz-jointList[i].placement.direction[1]*sz;\r
-               y2 = jointList[i].placement.direction[0]*sz+jointList[i].placement.direction[1]*cz;\r
-               jointList[i].placement.direction[0] = x2;\r
-               jointList[i].placement.direction[1] = y2;\r
-\r
-               // z-axis rotation for up\r
-               x2 = jointList[i].placement.up[0]*cz-jointList[i].placement.up[1]*sz;\r
-               y2 = jointList[i].placement.up[0]*sz+jointList[i].placement.up[1]*cz;\r
-               jointList[i].placement.up[0] = x2;\r
-               jointList[i].placement.up[1] = y2;\r
-\r
-               // x-axis rotation for direction vector\r
-               y2 = jointList[i].placement.direction[1]*cx-jointList[i].placement.direction[2]*sx;\r
-               z2 = jointList[i].placement.direction[1]*sx+jointList[i].placement.direction[2]*cx;\r
-               jointList[i].placement.direction[1] = y2;\r
-               jointList[i].placement.direction[2] = z2;\r
-\r
-               // x-axis rotation for up vector\r
-               y2 = jointList[i].placement.up[1]*cx-jointList[i].placement.up[2]*sx;\r
-               z2 = jointList[i].placement.up[1]*sx+jointList[i].placement.up[2]*cx;\r
-               jointList[i].placement.up[1] = y2;\r
-               jointList[i].placement.up[2] = z2;\r
-\r
-               // translate direction to a point in the model\r
-               jointList[i].placement.direction[0] += jointList[i].placement.origin[0];\r
-               jointList[i].placement.direction[1] += jointList[i].placement.origin[1];\r
-               jointList[i].placement.direction[2] += jointList[i].placement.origin[2];\r
-\r
-               // translate up to a point in the model\r
-               jointList[i].placement.up[0] += jointList[i].placement.origin[0];\r
-               jointList[i].placement.up[1] += jointList[i].placement.origin[1];\r
-               jointList[i].placement.up[2] += jointList[i].placement.origin[2];\r
-       }\r
-#endif\r
-\r
-       for(i = stackSize - 1; i >= 0; --i)\r
-       {\r
-               rx = curRotation[i][0]*ANGLE_TO_RAD;\r
-               ry = curRotation[i][1]*ANGLE_TO_RAD;\r
-               rz = curRotation[i][2]*ANGLE_TO_RAD;\r
-\r
-               cx = cos(rx);\r
-               sx = sin(rx);\r
-\r
-               cy = cos(ry);\r
-               sy = sin(ry);\r
-\r
-               cz = cos(rz);\r
-               sz = sin(rz);\r
-\r
-#if 1\r
-               for(j = i; j < stackSize; ++j)\r
-               {\r
-                       if(curCorrespondingJoint[j] != -1)\r
-                       {\r
-                               placement = &jointList[curCorrespondingJoint[j]].placement;\r
-\r
-                               // y-axis rotation for origin\r
-                               x2 = placement->origin[0]*cy+placement->origin[2]*sy;\r
-                               z2 = -placement->origin[0]*sy+placement->origin[2]*cy;\r
-                               placement->origin[0] = x2;\r
-                               placement->origin[2] = z2;\r
-\r
-                               // y-axis rotation for direction\r
-                               x2 = placement->direction[0]*cy+placement->direction[2]*sy;\r
-                               z2 = -placement->direction[0]*sy+placement->direction[2]*cy;\r
-                               placement->direction[0] = x2;\r
-                               placement->direction[2] = z2;\r
-\r
-                               // y-axis rotation for up\r
-                               x2 = placement->up[0]*cy+placement->up[2]*sy;\r
-                               z2 = -placement->up[0]*sy+placement->up[2]*cy;\r
-                               placement->up[0] = x2;\r
-                               placement->up[2] = z2;\r
-\r
-                               // z-axis rotation for origin\r
-                               x2 = placement->origin[0]*cz-placement->origin[1]*sz;\r
-                               y2 = placement->origin[0]*sz+placement->origin[1]*cz;\r
-                               placement->origin[0] = x2;\r
-                               placement->origin[1] = y2;\r
-\r
-                               // z-axis rotation for direction\r
-                               x2 = placement->direction[0]*cz-placement->direction[1]*sz;\r
-                               y2 = placement->direction[0]*sz+placement->direction[1]*cz;\r
-                               placement->direction[0] = x2;\r
-                               placement->direction[1] = y2;\r
-\r
-                               // z-axis rotation for up\r
-                               x2 = placement->up[0]*cz-placement->up[1]*sz;\r
-                               y2 = placement->up[0]*sz+placement->up[1]*cz;\r
-                               placement->up[0] = x2;\r
-                               placement->up[1] = y2;\r
-\r
-                               // x-axis rotation for origin\r
-                               y2 = placement->origin[1]*cx-placement->origin[2]*sx;\r
-                               z2 = placement->origin[1]*sx+placement->origin[2]*cx;\r
-                               placement->origin[1] = y2;\r
-                               placement->origin[2] = z2;\r
-\r
-                               // x-axis rotation for direction vector\r
-                               y2 = placement->direction[1]*cx-placement->direction[2]*sx;\r
-                               z2 = placement->direction[1]*sx+placement->direction[2]*cx;\r
-                               placement->direction[1] = y2;\r
-                               placement->direction[2] = z2;\r
-\r
-                               // x-axis rotation for up vector\r
-                               y2 = placement->up[1]*cx-placement->up[2]*sx;\r
-                               z2 = placement->up[1]*sx+placement->up[2]*cx;\r
-                               placement->up[1] = y2;\r
-                               placement->up[2] = z2;\r
-\r
-                               // translate origin\r
-                               placement->origin[0] += curTranslation[i][0];\r
-                               placement->origin[1] += curTranslation[i][1];\r
-                               placement->origin[2] += curTranslation[i][2];\r
-\r
-                               // translate back to local coord\r
-                               placement->direction[0] += curTranslation[i][0];\r
-                               placement->direction[1] += curTranslation[i][1];\r
-                               placement->direction[2] += curTranslation[i][2];\r
-\r
-                               // translate back to local coord\r
-                               placement->up[0] += curTranslation[i][0];\r
-                               placement->up[1] += curTranslation[i][1];\r
-                               placement->up[2] += curTranslation[i][2];\r
-                       }\r
-               }\r
-#else\r
-               // This screwed up and needs to be sorted out!!!\r
-               // The stack info needs to be written too instead of the jointList for j > numJoints for Skeleton\r
-               for(j = i-1; j < stackSize-1; ++j)\r
-               {\r
-                       // y-axis rotation for origin\r
-                       x2 = jointList[j].placement.origin[0]*cy+jointList[j].placement.origin[2]*sy;\r
-                       z2 = -jointList[j].placement.origin[0]*sy+jointList[j].placement.origin[2]*cy;\r
-                       jointList[j].placement.origin[0] = x2;\r
-                       jointList[j].placement.origin[2] = z2;\r
-\r
-                       // y-axis rotation for direction\r
-                       x2 = jointList[j].placement.direction[0]*cy+jointList[j].placement.direction[2]*sy;\r
-                       z2 = -jointList[j].placement.direction[0]*sy+jointList[j].placement.direction[2]*cy;\r
-                       jointList[j].placement.direction[0] = x2;\r
-                       jointList[j].placement.direction[2] = z2;\r
-\r
-                       // y-axis rotation for up\r
-                       x2 = jointList[j].placement.up[0]*cy+jointList[j].placement.up[2]*sy;\r
-                       z2 = -jointList[j].placement.up[0]*sy+jointList[j].placement.up[2]*cy;\r
-                       jointList[j].placement.up[0] = x2;\r
-                       jointList[j].placement.up[2] = z2;\r
-\r
-                       // z-axis rotation for origin\r
-                       x2 = jointList[j].placement.origin[0]*cz-jointList[j].placement.origin[1]*sz;\r
-                       y2 = jointList[j].placement.origin[0]*sz+jointList[j].placement.origin[1]*cz;\r
-                       jointList[j].placement.origin[0] = x2;\r
-                       jointList[j].placement.origin[1] = y2;\r
-\r
-                       // z-axis rotation for direction\r
-                       x2 = jointList[j].placement.direction[0]*cz-jointList[j].placement.direction[1]*sz;\r
-                       y2 = jointList[j].placement.direction[0]*sz+jointList[j].placement.direction[1]*cz;\r
-                       jointList[j].placement.direction[0] = x2;\r
-                       jointList[j].placement.direction[1] = y2;\r
-\r
-                       // z-axis rotation for up\r
-                       x2 = jointList[j].placement.up[0]*cz-jointList[j].placement.up[1]*sz;\r
-                       y2 = jointList[j].placement.up[0]*sz+jointList[j].placement.up[1]*cz;\r
-                       jointList[j].placement.up[0] = x2;\r
-                       jointList[j].placement.up[1] = y2;\r
-\r
-                       // x-axis rotation for origin\r
-                       y2 = jointList[j].placement.origin[1]*cx-jointList[j].placement.origin[2]*sx;\r
-                       z2 = jointList[j].placement.origin[1]*sx+jointList[j].placement.origin[2]*cx;\r
-                       jointList[j].placement.origin[1] = y2;\r
-                       jointList[j].placement.origin[2] = z2;\r
-\r
-                       // x-axis rotation for direction vector\r
-                       y2 = jointList[j].placement.direction[1]*cx-jointList[j].placement.direction[2]*sx;\r
-                       z2 = jointList[j].placement.direction[1]*sx+jointList[j].placement.direction[2]*cx;\r
-                       jointList[j].placement.direction[1] = y2;\r
-                       jointList[j].placement.direction[2] = z2;\r
-\r
-                       // x-axis rotation for up vector\r
-                       y2 = jointList[j].placement.up[1]*cx-jointList[j].placement.up[2]*sx;\r
-                       z2 = jointList[j].placement.up[1]*sx+jointList[j].placement.up[2]*cx;\r
-                       jointList[j].placement.up[1] = y2;\r
-                       jointList[j].placement.up[2] = z2;\r
-\r
-                       if(curCorrespondingJoint[j+1] != -1)\r
-                       {\r
-                               // translate origin\r
-                               jointList[j].placement.origin[0] += curTranslation[i-1][0];\r
-                               jointList[j].placement.origin[1] += curTranslation[i-1][1];\r
-                               jointList[j].placement.origin[2] += curTranslation[i-1][2];\r
-\r
-                               // translate back to local coord\r
-                               jointList[j].placement.direction[0] += curTranslation[i-1][0];\r
-                               jointList[j].placement.direction[1] += curTranslation[i-1][1];\r
-                               jointList[j].placement.direction[2] += curTranslation[i-1][2];\r
-\r
-                               // translate back to local coord\r
-                               jointList[j].placement.up[0] += curTranslation[i-1][0];\r
-                               jointList[j].placement.up[1] += curTranslation[i-1][1];\r
-                               jointList[j].placement.up[2] += curTranslation[i-1][2];\r
-                       }\r
-               }\r
-#endif\r
-       }\r
-}\r
-\r
-void LoadModelTransform(char *fileName)\r
-{\r
-       FILE *file1;\r
-    int dot = '.';\r
-       char *dotstart;\r
-       char    InputFileName[256];\r
-\r
-       dotstart = strrchr(fileName,dot); // Does it already have an extension on the file name?\r
-\r
-       if (!dotstart)\r
-       {\r
-               strcpy(InputFileName, fileName);\r
-               strcat(InputFileName, ".hrc");\r
-               if((file1 = fopen(InputFileName, "rb")) != NULL)\r
-               {\r
-                       fclose(file1);\r
-\r
-                       LoadHRCGlobals(InputFileName);\r
-\r
-                       printf(" - assuming .HRC\n");\r
-                       return;\r
-               }\r
-\r
-               Error("\n Could not open file '%s':\n"\r
-                       "No HRC match.\n", fileName);\r
-       }\r
-       else\r
-       {\r
-               if((file1 = fopen(fileName, "rb")) != NULL)\r
-               {\r
-//                     printf("\n");\r
-                       fclose(file1);\r
-                       if (strcmp(dotstart,".hrc") == 0 || strcmp(dotstart,".HRC") == 0)\r
-                       {\r
-                               LoadHRCGlobals(fileName);\r
-                               return;\r
-                       }\r
-               }\r
-\r
-               Error("Could not open file '%s':\n",fileName);\r
-       }\r
-}\r
-\r
-void LoadModelClusters(char *fileName, int **clusterList, int *num_verts, int skelType)\r
-{\r
-       FILE *file1;\r
-    int dot = '.';\r
-       char *dotstart;\r
-       char    InputFileName[256];\r
-\r
-       dotstart = strrchr(fileName,dot); // Does it already have an extension on the file name?\r
-\r
-       if (!dotstart)\r
-       {\r
-               strcpy(InputFileName, fileName);\r
-               strcat(InputFileName, ".hrc");\r
-               if((file1 = fopen(InputFileName, "rb")) != NULL)\r
-               {\r
-                       fclose(file1);\r
-\r
-                       LoadHRCClustered(InputFileName, clusterList, num_verts, skelType);\r
-\r
-                       printf(" - assuming .HRC\n");\r
-                       return;\r
-               }\r
-\r
-               Error("\n Could not open file '%s':\n"\r
-                       "No HRC match.\n", fileName);\r
-       }\r
-       else\r
-       {\r
-               if((file1 = fopen(fileName, "rb")) != NULL)\r
-               {\r
-//                     printf("\n");\r
-                       fclose(file1);\r
-                       if (strcmp(dotstart,".hrc") == 0 || strcmp(dotstart,".HRC") == 0)\r
-                       {\r
-                               LoadHRCClustered(fileName, clusterList, num_verts, skelType);\r
-                               return;\r
-                       }\r
-               }\r
-\r
-               Error("Could not open file '%s':\n",fileName);\r
-       }\r
-}\r
-\r
-void LoadSkeleton(char *fileName, QD_SkeletalJoint_t *jointList, int skelType)\r
-{\r
-       FILE *file1;\r
-    int dot = '.';\r
-       char *dotstart;\r
-       char    InputFileName[256];\r
-\r
-       dotstart = strrchr(fileName,dot); // Does it already have an extension on the file name?\r
-\r
-       if (!dotstart)\r
-       {\r
-               strcpy(InputFileName, fileName);\r
-               strcat(InputFileName, ".hrc");\r
-               if((file1 = fopen(InputFileName, "rb")) != NULL)\r
-               {\r
-                       fclose(file1);\r
-\r
-                       LoadHRCJointList(InputFileName, jointList, skelType);\r
-\r
-                       printf(" - assuming .HRC\n");\r
-                       return;\r
-               }\r
-\r
-               Error("\n Could not open file '%s':\n"\r
-                       "No HRC.\n", fileName);\r
-       }\r
-       else\r
-       {\r
-               if((file1 = fopen(fileName, "rb")) != NULL)\r
-               {\r
-//                     printf("\n");\r
-                       fclose(file1);\r
-                       if (strcmp(dotstart,".hrc") == 0 || strcmp(dotstart,".HRC") == 0)\r
-                       {\r
-                               LoadHRCJointList(fileName, jointList, skelType);\r
-\r
-                               return;\r
-                       }\r
-               }\r
-\r
-               Error("Could not open file '%s':\n",fileName);\r
-       }\r
-}\r
-\r
-/*\r
-===============\r
-GrabSkeletalFrame\r
-===============\r
-*/\r
-void GrabSkeletalFrame(char *frame)\r
-{\r
-       char    file1[1024];\r
-       char    *framefile;\r
-       fmframe_t       *fr;\r
-\r
-       framefile = FindFrameFile (frame);\r
-\r
-       sprintf (file1, "%s/%s", cdarchive, framefile);\r
-       ExpandPathAndArchive (file1);\r
-\r
-       sprintf (file1, "%s/%s",cddir, framefile);\r
-\r
-       printf ("Grabbing Skeletal Frame %s\n", file1);\r
-\r
-       fr = &g_frames[fmheader.num_frames - 1]; // last frame read in\r
-\r
-       LoadSkeleton(file1, fr->joints, g_skelModel.type);\r
-}\r
-\r
-/*\r
-===============\r
-GrabModelTransform\r
-===============\r
-*/\r
-void GrabModelTransform(char *frame)\r
-{\r
-       char    file1[1024];\r
-       char    *framefile;\r
-       fmframe_t       *fr;\r
-\r
-       framefile = FindFrameFile (frame);\r
-\r
-       sprintf (file1, "%s/%s", cdarchive, framefile);\r
-       ExpandPathAndArchive (file1);\r
-\r
-       sprintf (file1, "%s/%s",cddir, framefile);\r
-\r
-//     printf ("grabbing %s\n", file1);\r
-\r
-       fr = &g_frames[fmheader.num_frames - 1]; // last frame read in\r
-\r
-       LoadModelTransform(file1);\r
-}\r
-\r
-void Cmd_FMCluster()\r
-{\r
-       char file1[1024];\r
-\r
-       GetScriptToken (false);\r
-\r
-       printf ("---------------------\n");\r
-       sprintf (file1, "%s/%s", cdpartial, token);\r
-       printf ("%s\n", file1);\r
-\r
-       ExpandPathAndArchive (file1);\r
-\r
-       sprintf (file1, "%s/%s", cddir, token);\r
-\r
-       g_skelModel.clustered = -1;\r
-\r
-       LoadModelClusters(file1, (int **)&g_skelModel.clusters, (int *)&g_skelModel.num_verts, g_skelModel.type);\r
-\r
-       g_skelModel.new_num_verts[0] = g_skelModel.num_verts[0];\r
-\r
-       g_skelModel.clustered = true;\r
-}\r
-\r
-void Cmd_FMSkeleton()\r
-{\r
-       GetScriptToken (false);\r
-       g_skelModel.type = atoi(token);\r
-}\r
-\r
-void Cmd_FMSkeletalFrame()\r
-{\r
-       while (ScriptTokenAvailable())\r
-       {\r
-               GetScriptToken (false);\r
-               if (g_skipmodel)\r
-               {\r
-                       GetScriptToken (false);\r
-                       continue;\r
-               }\r
-               if (g_release || g_archive)\r
-               {\r
-                       fmheader.num_frames = 1;        // don't skip the writeout\r
-                       GetScriptToken (false);\r
-                       continue;\r
-               }\r
-\r
-               H_printf("#define FRAME_%-16s\t%i\n", token, fmheader.num_frames);\r
-\r
-               GrabModelTransform (token);\r
-               GrabFrame (token);\r
-               GrabSkeletalFrame (token);\r
-\r
-               // need to add the up and dir points to the frame bounds here\r
-               // using AddPointToBounds (ptrivert[index_xyz].v, fr->mins, fr->maxs);\r
-               // then remove fudge in determining scale on frame write out\r
-       }\r
-}\r
-\r
-static void LoadHRCReferences(char *fileName, fmframe_t *fr)\r
-{\r
-#define MAX_STACK 64\r
-       int i, j, k;\r
-       vec3d_t curTranslation[MAX_STACK], curRotation[MAX_STACK];\r
-       int curCorrespondingJoint[MAX_STACK];\r
-       int currentStack, stackSize;\r
-       double cx, sx, cy, sy, cz, sz;\r
-       double rx, ry, rz;\r
-       double x2, y2, z2;\r
-       char stripped[SKELETAL_NAME_MAX];\r
-       Placement_d_t *placement;\r
-       int refnum;\r
-\r
-       TK_OpenSource(fileName);\r
-       TK_FetchRequire(TK_HRCH);\r
-       TK_FetchRequire(TK_COLON);\r
-       TK_FetchRequire(TK_SOFTIMAGE);\r
-\r
-       if (RefPointNum <= 0)\r
-       {       // There were no labels indicated in the QDT, so use the hard-coded stuff.\r
-               refnum = numReferences[g_skelModel.references];\r
-       }\r
-       else\r
-       {\r
-               refnum = RefPointNum;\r
-       }\r
-\r
-       for(k = 0; k < refnum; ++k)\r
-       {\r
-               currentStack = 0;\r
-\r
-               // Load the root to get translation and initial rotation\r
-//             TK_Beyond(TK_MODEL);\r
-\r
-               while(TK_Search(TK_NAME) != TK_EOF)\r
-               {\r
-                       TK_Require(TK_STRING);\r
-\r
-                       StripTrailingDigits(tk_String, stripped);\r
-\r
-                       if (RefPointNum == 0)\r
-                       {       // Hard coded refpoint labels\r
-                               if(stricmp(stripped, \r
-                                       referenceRootNames[referenceRootNameOffsets[g_skelModel.references]+k]) == 0)\r
-                               {\r
-                                       break;\r
-                               }\r
-                       }\r
-                       else\r
-                       {       // labels indicated by the QDT\r
-                               if(stricmp(stripped, RefPointNameList[k]) == 0)\r
-                               {\r
-                                       break;\r
-                               }\r
-                       }\r
-               }\r
-\r
-               if(tk_Token == TK_EOF)\r
-               {\r
-                       if (RefPointNum == 0)\r
-                       {       // Hard coded refpoint labels\r
-                               Error("Bone Chain Root: %s not found\n", referenceRootNames[referenceRootNameOffsets[g_skelModel.references]]);\r
-                       }\r
-                       else\r
-                       {       // labels indicated by the QDT\r
-                               Error("Bone Chain Root: %s not found\n", RefPointNameList[k]);\r
-                       }\r
-                       return;\r
-               }\r
-\r
-//             TK_Beyond(TK_SCALING);\r
-\r
-//             ParseVec3d(curScale[currentStack]);\r
-\r
-               TK_Beyond(TK_ROTATION);\r
-\r
-               ParseRotation3d(curRotation[currentStack]);\r
-\r
-               TK_Beyond(TK_TRANSLATION);\r
-\r
-               ParseVec3d(curTranslation[currentStack]);\r
-\r
-               // account for global model translation\r
-               curTranslation[currentStack][1] += g_skelModel.translation[0];\r
-               curTranslation[currentStack][2] += g_skelModel.translation[1];\r
-               curTranslation[currentStack][0] += g_skelModel.translation[2];\r
-\r
-               curCorrespondingJoint[currentStack] = -1;\r
-\r
-//             rjr - this one not needed, as there is also a stack increment 20 lines below???\r
-//             ++currentStack;\r
-\r
-               // Load the joint to get orientation\r
-               TK_Beyond(TK_MODEL);\r
-\r
-//             TK_Beyond(TK_SCALING);\r
-\r
-//             ParseVec3d(curScale[currentStack]);\r
-\r
-               TK_Beyond(TK_ROTATION);\r
-\r
-               ParseRotation3d(curRotation[currentStack]);\r
-\r
-//             TK_Beyond(TK_TRANSLATION);\r
-\r
-//             ParseVec3d(curTranslation[currentStack]);\r
-\r
-               fr->references[k].placement.origin[1] = 0.0;\r
-               fr->references[k].placement.origin[2] = 0.0;\r
-               fr->references[k].placement.origin[0] = 0.0;\r
-\r
-               fr->references[k].placement.direction[1] = 20.0;\r
-               fr->references[k].placement.direction[2] = 0.0;\r
-               fr->references[k].placement.direction[0] = 0.0;\r
-\r
-               fr->references[k].placement.up[1] = 0.0;\r
-               fr->references[k].placement.up[2] = 20.0;\r
-               fr->references[k].placement.up[0] = 0.0;\r
-\r
-               curCorrespondingJoint[currentStack] = k;\r
-\r
-               ++currentStack;\r
-\r
-               stackSize = currentStack;\r
-\r
-               for(i = stackSize - 1; i >= 0; --i)\r
-               {\r
-                       rx = curRotation[i][0]*ANGLE_TO_RAD;\r
-                       ry = curRotation[i][1]*ANGLE_TO_RAD;\r
-                       rz = curRotation[i][2]*ANGLE_TO_RAD;\r
-\r
-                       cx = cos(rx);\r
-                       sx = sin(rx);\r
-\r
-                       cy = cos(ry);\r
-                       sy = sin(ry);\r
-\r
-                       cz = cos(rz);\r
-                       sz = sin(rz);\r
-\r
-                       for(j = i; j < stackSize; ++j)\r
-                       {\r
-                               if(curCorrespondingJoint[j] != -1)\r
-                               {\r
-                                       placement = &fr->references[curCorrespondingJoint[j]].placement;\r
-\r
-                                       // y-axis rotation for origin\r
-                                       x2 = placement->origin[0]*cy+placement->origin[2]*sy;\r
-                                       z2 = -placement->origin[0]*sy+placement->origin[2]*cy;\r
-                                       placement->origin[0] = x2;\r
-                                       placement->origin[2] = z2;\r
-\r
-                                       // y-axis rotation for direction\r
-                                       x2 = placement->direction[0]*cy+placement->direction[2]*sy;\r
-                                       z2 = -placement->direction[0]*sy+placement->direction[2]*cy;\r
-                                       placement->direction[0] = x2;\r
-                                       placement->direction[2] = z2;\r
-\r
-                                       // y-axis rotation for up\r
-                                       x2 = placement->up[0]*cy+placement->up[2]*sy;\r
-                                       z2 = -placement->up[0]*sy+placement->up[2]*cy;\r
-                                       placement->up[0] = x2;\r
-                                       placement->up[2] = z2;\r
-\r
-                                       // z-axis rotation for origin\r
-                                       x2 = placement->origin[0]*cz-placement->origin[1]*sz;\r
-                                       y2 = placement->origin[0]*sz+placement->origin[1]*cz;\r
-                                       placement->origin[0] = x2;\r
-                                       placement->origin[1] = y2;\r
-\r
-                                       // z-axis rotation for direction\r
-                                       x2 = placement->direction[0]*cz-placement->direction[1]*sz;\r
-                                       y2 = placement->direction[0]*sz+placement->direction[1]*cz;\r
-                                       placement->direction[0] = x2;\r
-                                       placement->direction[1] = y2;\r
-\r
-                                       // z-axis rotation for up\r
-                                       x2 = placement->up[0]*cz-placement->up[1]*sz;\r
-                                       y2 = placement->up[0]*sz+placement->up[1]*cz;\r
-                                       placement->up[0] = x2;\r
-                                       placement->up[1] = y2;\r
-\r
-                                       // x-axis rotation for origin\r
-                                       y2 = placement->origin[1]*cx-placement->origin[2]*sx;\r
-                                       z2 = placement->origin[1]*sx+placement->origin[2]*cx;\r
-                                       placement->origin[1] = y2;\r
-                                       placement->origin[2] = z2;\r
-\r
-                                       // x-axis rotation for direction vector\r
-                                       y2 = placement->direction[1]*cx-placement->direction[2]*sx;\r
-                                       z2 = placement->direction[1]*sx+placement->direction[2]*cx;\r
-                                       placement->direction[1] = y2;\r
-                                       placement->direction[2] = z2;\r
-\r
-                                       // x-axis rotation for up vector\r
-                                       y2 = placement->up[1]*cx-placement->up[2]*sx;\r
-                                       z2 = placement->up[1]*sx+placement->up[2]*cx;\r
-                                       placement->up[1] = y2;\r
-                                       placement->up[2] = z2;\r
-\r
-                                       // translate origin\r
-                                       placement->origin[0] += curTranslation[i][0];\r
-                                       placement->origin[1] += curTranslation[i][1];\r
-                                       placement->origin[2] += curTranslation[i][2];\r
-\r
-                                       // translate back to local coord\r
-                                       placement->direction[0] += curTranslation[i][0];\r
-                                       placement->direction[1] += curTranslation[i][1];\r
-                                       placement->direction[2] += curTranslation[i][2];\r
-\r
-                                       // translate back to local coord\r
-                                       placement->up[0] += curTranslation[i][0];\r
-                                       placement->up[1] += curTranslation[i][1];\r
-                                       placement->up[2] += curTranslation[i][2];\r
-\r
-                               }\r
-                       }\r
-               }\r
-               printf("%f, %f, %f\n", placement->origin[0], placement->origin[1], placement->origin[2]);\r
-       }\r
-       printf("\n");\r
-}\r
-\r
-void Cmd_FMReferenced()\r
-{\r
-       int i;\r
-\r
-       GetScriptToken (false);\r
-       g_skelModel.references = atoi(token);\r
-\r
-       // Guess what?  Now, we now want a list of strings to look for here instead of a hard-coded list\r
-       for (i=0; i<REF_MAX_POINTS; i++)\r
-       {\r
-               if (ScriptTokenAvailable())\r
-               {       // There is yet another reference point waiting.\r
-                       GetScriptToken(false);\r
-                       strcpy(RefPointNameList[i], token);\r
-               }\r
-               else\r
-               {\r
-                       break;\r
-               }\r
-       }\r
-\r
-       RefPointNum = i;\r
-\r
-       if (RefPointNum > 0)\r
-       {\r
-               printf("Searching for %d different reference points.\n", RefPointNum);\r
-       }\r
-       else\r
-       {\r
-               printf("Using built-in reference points.\n");\r
-       }\r
-\r
-}\r
-\r
-void LoadReferences(char *fileName, fmframe_t *fr)\r
-{\r
-       FILE *file1;\r
-    int dot = '.';\r
-       char *dotstart;\r
-       char    InputFileName[256];\r
-\r
-       dotstart = strrchr(fileName,dot); // Does it already have an extension on the file name?\r
-\r
-       if (!dotstart)\r
-       {\r
-               strcpy(InputFileName, fileName);\r
-               strcat(InputFileName, ".hrc");\r
-               if((file1 = fopen(InputFileName, "rb")) != NULL)\r
-               {\r
-                       fclose(file1);\r
-\r
-                       LoadHRCReferences(InputFileName, fr);\r
-\r
-                       printf(" - assuming .HRC\n");\r
-                       return;\r
-               }\r
-\r
-               Error("\n Could not open file '%s':\n"\r
-                       "No HRC.\n", fileName);\r
-       }\r
-       else\r
-       {\r
-               if((file1 = fopen(fileName, "rb")) != NULL)\r
-               {\r
-                       printf("\n");\r
-                       fclose(file1);\r
-                       if (strcmp(dotstart,".hrc") == 0 || strcmp(dotstart,".HRC") == 0)\r
-                       {\r
-                               LoadHRCReferences(fileName, fr);\r
-\r
-                               return;\r
-                       }\r
-               }\r
-\r
-               Error("Could not open file '%s':\n",fileName);\r
-       }\r
-}\r
-\r
-void GrabReferencedFrame(char *frame)\r
-{\r
-       char    file1[1024];\r
-       char    *framefile;\r
-       fmframe_t       *fr;\r
-\r
-       framefile = FindFrameFile (frame);\r
-\r
-       sprintf (file1, "%s/%s", cdarchive, framefile);\r
-       ExpandPathAndArchive (file1);\r
-\r
-       sprintf (file1, "%s/%s",cddir, framefile);\r
-\r
-       printf ("Grabbing Referenced %s\n", file1);\r
-\r
-       fr = &g_frames[fmheader.num_frames - 1]; // last frame read in\r
-\r
-       LoadReferences(file1, fr);\r
-}\r
-\r
+/*
+Copyright (C) 1999-2007 id Software, Inc. and contributors.
+For a list of contributors, see the accompanying CONTRIBUTORS file.
+
+This file is part of GtkRadiant.
+
+GtkRadiant is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+GtkRadiant is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GtkRadiant; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+*/
+
+#include "qd_skeletons.h"
+#include "skeletons.h"
+#include "qd_fmodel.h"
+#include "angles.h"
+#include "token.h"
+#include "qdata.h"
+#include "reference.h"
+
+#include <assert.h>
+#include <math.h>
+#include <memory.h>
+
+
+// We're assuming no more than 16 reference points, with no more than 32 characters in the name
+char RefPointNameList[REF_MAX_POINTS][REF_MAX_STRLEN];
+int     RefPointNum = 0;
+
+Skeletalfmheader_t g_skelModel;
+
+void ClearSkeletalModel()
+{
+       g_skelModel.type = SKEL_NULL;
+       g_skelModel.clustered = false;
+       g_skelModel.references = REF_NULL;
+}
+
+//==========================================================================
+//
+// LoadHRCClustered
+//
+//==========================================================================
+
+// Places the null terminated src string into the dest string less any trailing digits or underscores
+void StripTrailingDigits(char *src, char *dest)
+{
+#ifndef NDEBUG
+       int max = SKELETAL_NAME_MAX; // should be sufficient for inteded use on names from hrc files
+#endif
+       int i = 0;
+
+       while(src[i] != '\0')
+       {
+               ++i;
+#ifndef NDEBUG
+               assert(i < max);
+#endif
+       }
+
+       while((src[--i] >= '0' && src[i] <= '9') || src[i] == '_')
+       {
+
+       }
+
+       memcpy(dest, src, ++i);
+
+       dest[i] = '\0';
+}
+
+static void LoadHRCClustered(char *fileName, int **clusterList, int *num_verts, int skelType)
+{
+       extern void HandleHRCModel(triangle_t **triList, int *triangleCount, 
+               mesh_node_t **nodesList, int *num_mesh_nodes, int ActiveNode, int Depth);
+
+       extern mesh_node_t      *pmnodes;
+
+       triangle_t *triList;
+//     mesh_node_t *nodesList;
+       int num_mesh_nodes = 0, triangleCount = 0;
+
+#if 0
+       int i;
+       int j, numVerts;
+       char stripped[SKELETAL_NAME_MAX];
+
+       for( i = 1; i < numJointsInSkeleton[skelType] + 1; ++i)
+       {
+               num_verts[i] = 0;
+       }
+
+       TK_OpenSource(fileName);
+       TK_FetchRequire(TK_HRCH);
+       TK_FetchRequire(TK_COLON);
+       TK_FetchRequire(TK_SOFTIMAGE);
+
+       TK_Beyond(TK_CLUSTERS);
+
+       while(TK_Search(TK_CLUSTER_NAME) != TK_EOF)
+       {
+               TK_Require(TK_STRING);
+
+               StripTrailingDigits(tk_String, stripped);
+
+               for( i = 0; i < numJointsInSkeleton[skelType]; ++i)
+               {
+                       if(stricmp(stripped, skeletonJointNames[skeletonNameOffsets[skelType]+i]) == 0)
+                       {
+                               i = -i + numJointsInSkeleton[skelType] - 1;
+
+                               TK_BeyondRequire(TK_NUM_CLUSTER_VERTICES, TK_INTNUMBER);
+
+                               numVerts = tk_IntNumber;
+
+                               if(!num_verts[i+1])     // first set of verts for cluster
+                               {
+                                       clusterList[i] = SafeMalloc(numVerts*sizeof(int), "LoadHRCClustered");
+                                       assert(clusterList[i]);
+                               }
+                               else                            // any later sets of verts need to copy current
+                               {
+                                       int *temp;
+
+                                       temp = SafeMalloc((num_verts[i+1]+numVerts)*sizeof(int), "LoadHRCClustered");
+                                       assert(temp);
+
+                                       memcpy(temp + numVerts, clusterList[i], num_verts[i+1]*sizeof(int));
+
+                                       free(clusterList[i]);
+
+                                       clusterList[i] = temp;
+                               }
+
+                               // currently this function is only called by LoadModelClusters.
+                               // Apparently the matching free has disappeared, 
+                               // should probably be free at the end of FMCmd_Base
+
+                               TK_Beyond(TK_LBRACE);
+
+                               for(j = 0; j < numVerts; ++j)
+                               {
+                                       TK_Require(TK_INTNUMBER);
+                                       clusterList[i][j] = tk_IntNumber;
+                                       TK_Fetch();
+                               }
+
+                               num_verts[i+1] += numVerts;
+
+                               break;
+                       }
+               }
+       }
+
+       num_verts[0] = numJointsInSkeleton[skelType];
+#endif
+
+#if 1  // get the index number localized to the root
+//     for( i = 1; i < numJointsInSkeleton[skelType] + 1; ++i)
+//     {
+//             g_skelModel.num_verts[i] = 0;
+//     }
+
+       TK_OpenSource(fileName);
+       TK_FetchRequire(TK_HRCH);
+       TK_FetchRequire(TK_COLON);
+       TK_FetchRequire(TK_SOFTIMAGE);
+
+       // prime it
+       TK_Beyond(TK_MODEL);
+
+       triList = (triangle_t *) SafeMalloc(MAXTRIANGLES*sizeof(triangle_t), "Triangle list");
+       memset(triList,0,MAXTRIANGLES*sizeof(triangle_t));
+//     nodesList = SafeMalloc(MAX_FM_MESH_NODES * sizeof(mesh_node_t), "Mesh Node List");
+       pmnodes = (mesh_node_t *) SafeMalloc(MAX_FM_MESH_NODES * sizeof(mesh_node_t), "Mesh Node List");
+
+       memset(pmnodes, 0, MAX_FM_MESH_NODES * sizeof(mesh_node_t));
+
+       // this should eventually use a stripped down version of this
+       HandleHRCModel(&triList, &triangleCount, &pmnodes, &num_mesh_nodes, 0, 0);
+
+//     free(nodesList);
+       free(triList);
+
+       num_verts[0] = numJointsInSkeleton[skelType];
+#endif
+}
+
+void ReadHRCClusterList(mesh_node_t *meshNode, int baseIndex)
+{
+       int i, j, numVerts;
+       tokenType_t nextToken;
+       char stripped[SKELETAL_NAME_MAX];
+
+       meshNode->clustered = true;
+
+       nextToken = TK_Get(TK_CLUSTER_NAME);
+
+       while (nextToken == TK_CLUSTER_NAME)
+       {
+               TK_FetchRequire(TK_STRING);
+
+               StripTrailingDigits(tk_String, stripped);
+
+               for( i = 0; i < numJointsInSkeleton[g_skelModel.type]; ++i)
+               {
+                       if(stricmp(stripped, skeletonJointNames[skeletonNameOffsets[g_skelModel.type]+i]) == 0)
+                       {
+                               i = -i + numJointsInSkeleton[g_skelModel.type] - 1;
+
+                               TK_BeyondRequire(TK_NUM_CLUSTER_VERTICES, TK_INTNUMBER);
+
+                               numVerts = tk_IntNumber;
+
+                               if(!baseIndex)
+                               {
+                                       meshNode->clusters[i] = (int *) SafeMalloc(numVerts*sizeof(int), "ReadHRCClusterList");
+                                       assert(meshNode->clusters[i]);
+                               }
+                               else
+                               {
+                                       int *temp; 
+
+                                       temp = meshNode->clusters[i];
+                                       meshNode->clusters[i] = (int *) SafeMalloc((meshNode->num_verts[i+1]+numVerts)*sizeof(int), "ReadHRCClusterList");
+                                       assert(meshNode->clusters[i]);
+
+                                       memcpy(meshNode->clusters[i], temp, meshNode->num_verts[i+1]*sizeof(int));
+                                       free(temp);
+                               }
+
+                               // currently this function is only called by LoadModelClusters.
+                               // Apparently the matching free has disappeared, 
+                               // should probably be free at the end of FMCmd_Base
+
+                               TK_Beyond(TK_LBRACE);
+
+                               for(j = 0; j < numVerts; ++j)
+                               {
+                                       TK_Require(TK_INTNUMBER);
+                                       meshNode->clusters[i][baseIndex+j] = tk_IntNumber+baseIndex;
+                                       TK_Fetch();
+                               }
+
+                               if(baseIndex)
+                               {
+                                       meshNode->num_verts[i+1] += numVerts;
+                               }
+                               else
+                               {
+                                       meshNode->num_verts[i+1] = numVerts;
+                               }
+
+                               break;
+                       }
+               }
+
+               TK_BeyondRequire(TK_CLUSTER_STATE, TK_INTNUMBER);
+               nextToken = TK_Fetch();
+       }
+}
+
+static void LoadHRCGlobals(char *fileName)
+{
+       int i;
+
+       TK_OpenSource(fileName);
+       TK_FetchRequire(TK_HRCH);
+       TK_FetchRequire(TK_COLON);
+       TK_FetchRequire(TK_SOFTIMAGE);
+       TK_Beyond(TK_MODEL);
+
+       TK_Beyond(TK_SCALING);
+       for(i = 0; i < 3; i++)
+       {
+               TK_Require(TK_FLOATNUMBER);
+               g_skelModel.scaling[i] = tk_FloatNumber;
+               TK_Fetch();
+       }
+
+       TK_Beyond(TK_ROTATION);
+       for(i = 0; i < 3; i++)
+       {
+               TK_Require(TK_FLOATNUMBER);
+               g_skelModel.rotation[i] = tk_FloatNumber;
+               TK_Fetch();
+       }
+
+       TK_Beyond(TK_TRANSLATION);
+       for(i = 0; i < 3; i++)
+       {
+               TK_Require(TK_FLOATNUMBER);
+               g_skelModel.translation[i] = tk_FloatNumber;
+               TK_Fetch();
+       }
+}
+
+static void ParseVec3(vec3_t in)
+{
+       TK_Require(TK_FLOATNUMBER);
+       in[1] = tk_FloatNumber;
+       TK_FetchRequire(TK_FLOATNUMBER);
+       in[2] = tk_FloatNumber;
+       TK_FetchRequire(TK_FLOATNUMBER);
+       in[0] = tk_FloatNumber;
+}
+
+static void ParseVec3d(vec3d_t in)
+{
+       TK_Require(TK_FLOATNUMBER);
+       in[1] = tk_FloatNumber;
+       TK_FetchRequire(TK_FLOATNUMBER);
+       in[2] = tk_FloatNumber;
+       TK_FetchRequire(TK_FLOATNUMBER);
+       in[0] = tk_FloatNumber;
+}
+
+static void ParseRotation3(vec3_t in)
+{
+       TK_Require(TK_FLOATNUMBER);
+       in[1] = tk_FloatNumber;
+       TK_FetchRequire(TK_FLOATNUMBER);
+       in[2] = tk_FloatNumber;
+       TK_FetchRequire(TK_FLOATNUMBER);
+       in[0] = tk_FloatNumber;
+}
+
+static void ParseRotation3d(vec3d_t in)
+{
+       TK_Require(TK_FLOATNUMBER);
+       in[1] = tk_FloatNumber;
+       TK_FetchRequire(TK_FLOATNUMBER);
+       in[2] = tk_FloatNumber;
+       TK_FetchRequire(TK_FLOATNUMBER);
+       in[0] = tk_FloatNumber;
+}
+
+static void ParseTranslation3(vec3_t in)
+{
+       TK_Require(TK_FLOATNUMBER);
+       in[1] = tk_FloatNumber;
+       TK_FetchRequire(TK_FLOATNUMBER);
+       in[2] = tk_FloatNumber;
+       TK_FetchRequire(TK_FLOATNUMBER);
+       in[0] = tk_FloatNumber;
+}
+
+static void ParseTranslation3d(vec3d_t in)
+{
+       TK_Require(TK_FLOATNUMBER);
+       in[1] = tk_FloatNumber;
+       TK_FetchRequire(TK_FLOATNUMBER);
+       in[2] = tk_FloatNumber;
+       TK_FetchRequire(TK_FLOATNUMBER);
+       in[0] = tk_FloatNumber;
+}
+
+static void LoadHRCJointList(char *fileName, QD_SkeletalJoint_t *jointList, int skelType)
+{
+#define MAX_STACK 64
+       int i, j;
+       vec3d_t curTranslation[MAX_STACK], curRotation[MAX_STACK], curScale[MAX_STACK];
+       int curCorrespondingJoint[MAX_STACK];
+       int currentStack = 0, stackSize;
+       double cx, sx, cy, sy, cz, sz;
+       double rx, ry, rz;
+       double x2, y2, z2;
+       char stripped[SKELETAL_NAME_MAX];
+       Placement_d_t *placement;
+
+       TK_OpenSource(fileName);
+       TK_FetchRequire(TK_HRCH);
+       TK_FetchRequire(TK_COLON);
+       TK_FetchRequire(TK_SOFTIMAGE);
+
+       TK_Beyond(TK_MODEL);
+
+       while(TK_Search(TK_NAME) != TK_EOF)
+       {
+               TK_Require(TK_STRING);
+
+               StripTrailingDigits(tk_String, stripped);
+
+               if(stricmp(stripped, skeletonRootNames[skeletonRNameOffsets[skelType]]) == 0)
+               {
+                       break;
+               }
+       }
+
+       if(tk_Token == TK_EOF)
+       {
+               Error("Bone Chain Root: %s not found\n", skeletonRootNames[skeletonRNameOffsets[skelType]]);
+               return;
+       }
+
+       TK_Beyond(TK_SCALING);
+
+       ParseVec3d(curScale[currentStack]);
+
+       TK_Beyond(TK_ROTATION);
+
+       ParseRotation3d(curRotation[currentStack]);
+
+       TK_Beyond(TK_TRANSLATION);
+
+       ParseVec3d(curTranslation[currentStack]);
+
+       // account for global model translation
+       curTranslation[currentStack][1] += g_skelModel.translation[0];
+       curTranslation[currentStack][2] += g_skelModel.translation[1];
+       curTranslation[currentStack][0] += g_skelModel.translation[2];
+
+       curCorrespondingJoint[currentStack] = -1;
+
+       ++currentStack;
+
+       for(i = 0; i < numJointsInSkeleton[skelType]; ++i)
+       {
+               while(1)
+               {
+                       TK_Beyond(TK_MODEL);
+
+                       TK_BeyondRequire(TK_NAME, TK_STRING);
+
+                       StripTrailingDigits(tk_String, stripped);
+
+                       if(stricmp(stripped, skeletonJointNames[skeletonNameOffsets[skelType]+i]) == 0)
+                               break;
+
+                       TK_Beyond(TK_SCALING);
+
+                       ParseVec3d(curScale[currentStack]);
+
+                       TK_Beyond(TK_ROTATION);
+
+                       ParseRotation3d(curRotation[currentStack]);
+
+                       TK_Beyond(TK_TRANSLATION);
+
+                       ParseVec3d(curTranslation[currentStack]);
+
+                       curCorrespondingJoint[currentStack] = -1;
+
+                       ++currentStack;
+               }
+
+               TK_Beyond(TK_SCALING);
+
+               ParseVec3d(curScale[currentStack]);
+
+               TK_Beyond(TK_ROTATION);
+
+               ParseRotation3d(curRotation[currentStack]);
+
+               jointList[i].rotation[1] = curRotation[currentStack][1];
+               jointList[i].rotation[2] = curRotation[currentStack][2];
+               jointList[i].rotation[0] = curRotation[currentStack][0];
+
+               TK_Beyond(TK_TRANSLATION);
+
+               ParseVec3d(curTranslation[currentStack]);
+
+//             jointList[i].placement.origin[1] = curTranslation[currentStack][1];
+//             jointList[i].placement.origin[2] = curTranslation[currentStack][2];
+//             jointList[i].placement.origin[0] = curTranslation[currentStack][0];
+
+               jointList[i].placement.origin[1] = 0.0;
+               jointList[i].placement.origin[2] = 0.0;
+               jointList[i].placement.origin[0] = 0.0;
+
+               jointList[i].placement.direction[1] = 20.0;
+               jointList[i].placement.direction[2] = 0.0;
+               jointList[i].placement.direction[0] = 0.0;
+
+               jointList[i].placement.up[1] = 0.0;
+               jointList[i].placement.up[2] = 20.0;
+               jointList[i].placement.up[0] = 0.0;
+
+               curCorrespondingJoint[currentStack] = i;
+
+               ++currentStack;
+       }
+
+       stackSize = currentStack;
+
+#if 0
+       // rotate the direction and up vectors to correspond to the rotation
+       for(i = 0; i < numJointsInSkeleton[skelType]; ++i)
+       {
+               rx = jointList[i].rotation[0]*ANGLE_TO_RAD;
+               ry = jointList[i].rotation[1]*ANGLE_TO_RAD;
+               rz = jointList[i].rotation[2]*ANGLE_TO_RAD;
+
+               cx = cos(rx);
+               sx = sin(rx);
+
+               cy = cos(ry);
+               sy = sin(ry);
+
+               cz = cos(rz);
+               sz = sin(rz);
+
+               // y-axis rotation for direction
+               x2 = jointList[i].placement.direction[0]*cy+jointList[i].placement.direction[2]*sy;
+               z2 = -jointList[i].placement.direction[0]*sy+jointList[i].placement.direction[2]*cy;
+               jointList[i].placement.direction[0] = x2;
+               jointList[i].placement.direction[2] = z2;
+
+               // y-axis rotation for up
+               x2 = jointList[i].placement.up[0]*cy+jointList[i].placement.up[2]*sy;
+               z2 = -jointList[i].placement.up[0]*sy+jointList[i].placement.up[2]*cy;
+               jointList[i].placement.up[0] = x2;
+               jointList[i].placement.up[2] = z2;
+
+               // z-axis rotation for direction
+               x2 = jointList[i].placement.direction[0]*cz-jointList[i].placement.direction[1]*sz;
+               y2 = jointList[i].placement.direction[0]*sz+jointList[i].placement.direction[1]*cz;
+               jointList[i].placement.direction[0] = x2;
+               jointList[i].placement.direction[1] = y2;
+
+               // z-axis rotation for up
+               x2 = jointList[i].placement.up[0]*cz-jointList[i].placement.up[1]*sz;
+               y2 = jointList[i].placement.up[0]*sz+jointList[i].placement.up[1]*cz;
+               jointList[i].placement.up[0] = x2;
+               jointList[i].placement.up[1] = y2;
+
+               // x-axis rotation for direction vector
+               y2 = jointList[i].placement.direction[1]*cx-jointList[i].placement.direction[2]*sx;
+               z2 = jointList[i].placement.direction[1]*sx+jointList[i].placement.direction[2]*cx;
+               jointList[i].placement.direction[1] = y2;
+               jointList[i].placement.direction[2] = z2;
+
+               // x-axis rotation for up vector
+               y2 = jointList[i].placement.up[1]*cx-jointList[i].placement.up[2]*sx;
+               z2 = jointList[i].placement.up[1]*sx+jointList[i].placement.up[2]*cx;
+               jointList[i].placement.up[1] = y2;
+               jointList[i].placement.up[2] = z2;
+
+               // translate direction to a point in the model
+               jointList[i].placement.direction[0] += jointList[i].placement.origin[0];
+               jointList[i].placement.direction[1] += jointList[i].placement.origin[1];
+               jointList[i].placement.direction[2] += jointList[i].placement.origin[2];
+
+               // translate up to a point in the model
+               jointList[i].placement.up[0] += jointList[i].placement.origin[0];
+               jointList[i].placement.up[1] += jointList[i].placement.origin[1];
+               jointList[i].placement.up[2] += jointList[i].placement.origin[2];
+       }
+#endif
+
+       for(i = stackSize - 1; i >= 0; --i)
+       {
+               rx = curRotation[i][0]*ANGLE_TO_RAD;
+               ry = curRotation[i][1]*ANGLE_TO_RAD;
+               rz = curRotation[i][2]*ANGLE_TO_RAD;
+
+               cx = cos(rx);
+               sx = sin(rx);
+
+               cy = cos(ry);
+               sy = sin(ry);
+
+               cz = cos(rz);
+               sz = sin(rz);
+
+#if 1
+               for(j = i; j < stackSize; ++j)
+               {
+                       if(curCorrespondingJoint[j] != -1)
+                       {
+                               placement = &jointList[curCorrespondingJoint[j]].placement;
+
+                               // y-axis rotation for origin
+                               x2 = placement->origin[0]*cy+placement->origin[2]*sy;
+                               z2 = -placement->origin[0]*sy+placement->origin[2]*cy;
+                               placement->origin[0] = x2;
+                               placement->origin[2] = z2;
+
+                               // y-axis rotation for direction
+                               x2 = placement->direction[0]*cy+placement->direction[2]*sy;
+                               z2 = -placement->direction[0]*sy+placement->direction[2]*cy;
+                               placement->direction[0] = x2;
+                               placement->direction[2] = z2;
+
+                               // y-axis rotation for up
+                               x2 = placement->up[0]*cy+placement->up[2]*sy;
+                               z2 = -placement->up[0]*sy+placement->up[2]*cy;
+                               placement->up[0] = x2;
+                               placement->up[2] = z2;
+
+                               // z-axis rotation for origin
+                               x2 = placement->origin[0]*cz-placement->origin[1]*sz;
+                               y2 = placement->origin[0]*sz+placement->origin[1]*cz;
+                               placement->origin[0] = x2;
+                               placement->origin[1] = y2;
+
+                               // z-axis rotation for direction
+                               x2 = placement->direction[0]*cz-placement->direction[1]*sz;
+                               y2 = placement->direction[0]*sz+placement->direction[1]*cz;
+                               placement->direction[0] = x2;
+                               placement->direction[1] = y2;
+
+                               // z-axis rotation for up
+                               x2 = placement->up[0]*cz-placement->up[1]*sz;
+                               y2 = placement->up[0]*sz+placement->up[1]*cz;
+                               placement->up[0] = x2;
+                               placement->up[1] = y2;
+
+                               // x-axis rotation for origin
+                               y2 = placement->origin[1]*cx-placement->origin[2]*sx;
+                               z2 = placement->origin[1]*sx+placement->origin[2]*cx;
+                               placement->origin[1] = y2;
+                               placement->origin[2] = z2;
+
+                               // x-axis rotation for direction vector
+                               y2 = placement->direction[1]*cx-placement->direction[2]*sx;
+                               z2 = placement->direction[1]*sx+placement->direction[2]*cx;
+                               placement->direction[1] = y2;
+                               placement->direction[2] = z2;
+
+                               // x-axis rotation for up vector
+                               y2 = placement->up[1]*cx-placement->up[2]*sx;
+                               z2 = placement->up[1]*sx+placement->up[2]*cx;
+                               placement->up[1] = y2;
+                               placement->up[2] = z2;
+
+                               // translate origin
+                               placement->origin[0] += curTranslation[i][0];
+                               placement->origin[1] += curTranslation[i][1];
+                               placement->origin[2] += curTranslation[i][2];
+
+                               // translate back to local coord
+                               placement->direction[0] += curTranslation[i][0];
+                               placement->direction[1] += curTranslation[i][1];
+                               placement->direction[2] += curTranslation[i][2];
+
+                               // translate back to local coord
+                               placement->up[0] += curTranslation[i][0];
+                               placement->up[1] += curTranslation[i][1];
+                               placement->up[2] += curTranslation[i][2];
+                       }
+               }
+#else
+               // This screwed up and needs to be sorted out!!!
+               // The stack info needs to be written too instead of the jointList for j > numJoints for Skeleton
+               for(j = i-1; j < stackSize-1; ++j)
+               {
+                       // y-axis rotation for origin
+                       x2 = jointList[j].placement.origin[0]*cy+jointList[j].placement.origin[2]*sy;
+                       z2 = -jointList[j].placement.origin[0]*sy+jointList[j].placement.origin[2]*cy;
+                       jointList[j].placement.origin[0] = x2;
+                       jointList[j].placement.origin[2] = z2;
+
+                       // y-axis rotation for direction
+                       x2 = jointList[j].placement.direction[0]*cy+jointList[j].placement.direction[2]*sy;
+                       z2 = -jointList[j].placement.direction[0]*sy+jointList[j].placement.direction[2]*cy;
+                       jointList[j].placement.direction[0] = x2;
+                       jointList[j].placement.direction[2] = z2;
+
+                       // y-axis rotation for up
+                       x2 = jointList[j].placement.up[0]*cy+jointList[j].placement.up[2]*sy;
+                       z2 = -jointList[j].placement.up[0]*sy+jointList[j].placement.up[2]*cy;
+                       jointList[j].placement.up[0] = x2;
+                       jointList[j].placement.up[2] = z2;
+
+                       // z-axis rotation for origin
+                       x2 = jointList[j].placement.origin[0]*cz-jointList[j].placement.origin[1]*sz;
+                       y2 = jointList[j].placement.origin[0]*sz+jointList[j].placement.origin[1]*cz;
+                       jointList[j].placement.origin[0] = x2;
+                       jointList[j].placement.origin[1] = y2;
+
+                       // z-axis rotation for direction
+                       x2 = jointList[j].placement.direction[0]*cz-jointList[j].placement.direction[1]*sz;
+                       y2 = jointList[j].placement.direction[0]*sz+jointList[j].placement.direction[1]*cz;
+                       jointList[j].placement.direction[0] = x2;
+                       jointList[j].placement.direction[1] = y2;
+
+                       // z-axis rotation for up
+                       x2 = jointList[j].placement.up[0]*cz-jointList[j].placement.up[1]*sz;
+                       y2 = jointList[j].placement.up[0]*sz+jointList[j].placement.up[1]*cz;
+                       jointList[j].placement.up[0] = x2;
+                       jointList[j].placement.up[1] = y2;
+
+                       // x-axis rotation for origin
+                       y2 = jointList[j].placement.origin[1]*cx-jointList[j].placement.origin[2]*sx;
+                       z2 = jointList[j].placement.origin[1]*sx+jointList[j].placement.origin[2]*cx;
+                       jointList[j].placement.origin[1] = y2;
+                       jointList[j].placement.origin[2] = z2;
+
+                       // x-axis rotation for direction vector
+                       y2 = jointList[j].placement.direction[1]*cx-jointList[j].placement.direction[2]*sx;
+                       z2 = jointList[j].placement.direction[1]*sx+jointList[j].placement.direction[2]*cx;
+                       jointList[j].placement.direction[1] = y2;
+                       jointList[j].placement.direction[2] = z2;
+
+                       // x-axis rotation for up vector
+                       y2 = jointList[j].placement.up[1]*cx-jointList[j].placement.up[2]*sx;
+                       z2 = jointList[j].placement.up[1]*sx+jointList[j].placement.up[2]*cx;
+                       jointList[j].placement.up[1] = y2;
+                       jointList[j].placement.up[2] = z2;
+
+                       if(curCorrespondingJoint[j+1] != -1)
+                       {
+                               // translate origin
+                               jointList[j].placement.origin[0] += curTranslation[i-1][0];
+                               jointList[j].placement.origin[1] += curTranslation[i-1][1];
+                               jointList[j].placement.origin[2] += curTranslation[i-1][2];
+
+                               // translate back to local coord
+                               jointList[j].placement.direction[0] += curTranslation[i-1][0];
+                               jointList[j].placement.direction[1] += curTranslation[i-1][1];
+                               jointList[j].placement.direction[2] += curTranslation[i-1][2];
+
+                               // translate back to local coord
+                               jointList[j].placement.up[0] += curTranslation[i-1][0];
+                               jointList[j].placement.up[1] += curTranslation[i-1][1];
+                               jointList[j].placement.up[2] += curTranslation[i-1][2];
+                       }
+               }
+#endif
+       }
+}
+
+void LoadModelTransform(char *fileName)
+{
+       FILE *file1;
+    int dot = '.';
+       char *dotstart;
+       char    InputFileName[256];
+
+       dotstart = strrchr(fileName,dot); // Does it already have an extension on the file name?
+
+       if (!dotstart)
+       {
+               strcpy(InputFileName, fileName);
+               strcat(InputFileName, ".hrc");
+               if((file1 = fopen(InputFileName, "rb")) != NULL)
+               {
+                       fclose(file1);
+
+                       LoadHRCGlobals(InputFileName);
+
+                       printf(" - assuming .HRC\n");
+                       return;
+               }
+
+               Error("\n Could not open file '%s':\n"
+                       "No HRC match.\n", fileName);
+       }
+       else
+       {
+               if((file1 = fopen(fileName, "rb")) != NULL)
+               {
+//                     printf("\n");
+                       fclose(file1);
+                       if (strcmp(dotstart,".hrc") == 0 || strcmp(dotstart,".HRC") == 0)
+                       {
+                               LoadHRCGlobals(fileName);
+                               return;
+                       }
+               }
+
+               Error("Could not open file '%s':\n",fileName);
+       }
+}
+
+void LoadModelClusters(char *fileName, int **clusterList, int *num_verts, int skelType)
+{
+       FILE *file1;
+    int dot = '.';
+       char *dotstart;
+       char    InputFileName[256];
+
+       dotstart = strrchr(fileName,dot); // Does it already have an extension on the file name?
+
+       if (!dotstart)
+       {
+               strcpy(InputFileName, fileName);
+               strcat(InputFileName, ".hrc");
+               if((file1 = fopen(InputFileName, "rb")) != NULL)
+               {
+                       fclose(file1);
+
+                       LoadHRCClustered(InputFileName, clusterList, num_verts, skelType);
+
+                       printf(" - assuming .HRC\n");
+                       return;
+               }
+
+               Error("\n Could not open file '%s':\n"
+                       "No HRC match.\n", fileName);
+       }
+       else
+       {
+               if((file1 = fopen(fileName, "rb")) != NULL)
+               {
+//                     printf("\n");
+                       fclose(file1);
+                       if (strcmp(dotstart,".hrc") == 0 || strcmp(dotstart,".HRC") == 0)
+                       {
+                               LoadHRCClustered(fileName, clusterList, num_verts, skelType);
+                               return;
+                       }
+               }
+
+               Error("Could not open file '%s':\n",fileName);
+       }
+}
+
+void LoadSkeleton(char *fileName, QD_SkeletalJoint_t *jointList, int skelType)
+{
+       FILE *file1;
+    int dot = '.';
+       char *dotstart;
+       char    InputFileName[256];
+
+       dotstart = strrchr(fileName,dot); // Does it already have an extension on the file name?
+
+       if (!dotstart)
+       {
+               strcpy(InputFileName, fileName);
+               strcat(InputFileName, ".hrc");
+               if((file1 = fopen(InputFileName, "rb")) != NULL)
+               {
+                       fclose(file1);
+
+                       LoadHRCJointList(InputFileName, jointList, skelType);
+
+                       printf(" - assuming .HRC\n");
+                       return;
+               }
+
+               Error("\n Could not open file '%s':\n"
+                       "No HRC.\n", fileName);
+       }
+       else
+       {
+               if((file1 = fopen(fileName, "rb")) != NULL)
+               {
+//                     printf("\n");
+                       fclose(file1);
+                       if (strcmp(dotstart,".hrc") == 0 || strcmp(dotstart,".HRC") == 0)
+                       {
+                               LoadHRCJointList(fileName, jointList, skelType);
+
+                               return;
+                       }
+               }
+
+               Error("Could not open file '%s':\n",fileName);
+       }
+}
+
+/*
+===============
+GrabSkeletalFrame
+===============
+*/
+void GrabSkeletalFrame(char *frame)
+{
+       char    file1[1024];
+       char    *framefile;
+       fmframe_t       *fr;
+
+       framefile = FindFrameFile (frame);
+
+       sprintf (file1, "%s/%s", cdarchive, framefile);
+       ExpandPathAndArchive (file1);
+
+       sprintf (file1, "%s/%s",cddir, framefile);
+
+       printf ("Grabbing Skeletal Frame %s\n", file1);
+
+       fr = &g_frames[fmheader.num_frames - 1]; // last frame read in
+
+       LoadSkeleton(file1, fr->joints, g_skelModel.type);
+}
+
+/*
+===============
+GrabModelTransform
+===============
+*/
+void GrabModelTransform(char *frame)
+{
+       char    file1[1024];
+       char    *framefile;
+       fmframe_t       *fr;
+
+       framefile = FindFrameFile (frame);
+
+       sprintf (file1, "%s/%s", cdarchive, framefile);
+       ExpandPathAndArchive (file1);
+
+       sprintf (file1, "%s/%s",cddir, framefile);
+
+//     printf ("grabbing %s\n", file1);
+
+       fr = &g_frames[fmheader.num_frames - 1]; // last frame read in
+
+       LoadModelTransform(file1);
+}
+
+void Cmd_FMCluster()
+{
+       char file1[1024];
+
+       GetScriptToken (false);
+
+       printf ("---------------------\n");
+       sprintf (file1, "%s/%s", cdpartial, token);
+       printf ("%s\n", file1);
+
+       ExpandPathAndArchive (file1);
+
+       sprintf (file1, "%s/%s", cddir, token);
+
+       g_skelModel.clustered = -1;
+
+       LoadModelClusters(file1, (int **)&g_skelModel.clusters, (int *)&g_skelModel.num_verts, g_skelModel.type);
+
+       g_skelModel.new_num_verts[0] = g_skelModel.num_verts[0];
+
+       g_skelModel.clustered = true;
+}
+
+void Cmd_FMSkeleton()
+{
+       GetScriptToken (false);
+       g_skelModel.type = atoi(token);
+}
+
+void Cmd_FMSkeletalFrame()
+{
+       while (ScriptTokenAvailable())
+       {
+               GetScriptToken (false);
+               if (g_skipmodel)
+               {
+                       GetScriptToken (false);
+                       continue;
+               }
+               if (g_release || g_archive)
+               {
+                       fmheader.num_frames = 1;        // don't skip the writeout
+                       GetScriptToken (false);
+                       continue;
+               }
+
+               H_printf("#define FRAME_%-16s\t%i\n", token, fmheader.num_frames);
+
+               GrabModelTransform (token);
+               GrabFrame (token);
+               GrabSkeletalFrame (token);
+
+               // need to add the up and dir points to the frame bounds here
+               // using AddPointToBounds (ptrivert[index_xyz].v, fr->mins, fr->maxs);
+               // then remove fudge in determining scale on frame write out
+       }
+}
+
+static void LoadHRCReferences(char *fileName, fmframe_t *fr)
+{
+#define MAX_STACK 64
+       int i, j, k;
+       vec3d_t curTranslation[MAX_STACK], curRotation[MAX_STACK];
+       int curCorrespondingJoint[MAX_STACK];
+       int currentStack, stackSize;
+       double cx, sx, cy, sy, cz, sz;
+       double rx, ry, rz;
+       double x2, y2, z2;
+       char stripped[SKELETAL_NAME_MAX];
+       Placement_d_t *placement;
+       int refnum;
+
+       TK_OpenSource(fileName);
+       TK_FetchRequire(TK_HRCH);
+       TK_FetchRequire(TK_COLON);
+       TK_FetchRequire(TK_SOFTIMAGE);
+
+       if (RefPointNum <= 0)
+       {       // There were no labels indicated in the QDT, so use the hard-coded stuff.
+               refnum = numReferences[g_skelModel.references];
+       }
+       else
+       {
+               refnum = RefPointNum;
+       }
+
+       for(k = 0; k < refnum; ++k)
+       {
+               currentStack = 0;
+
+               // Load the root to get translation and initial rotation
+//             TK_Beyond(TK_MODEL);
+
+               while(TK_Search(TK_NAME) != TK_EOF)
+               {
+                       TK_Require(TK_STRING);
+
+                       StripTrailingDigits(tk_String, stripped);
+
+                       if (RefPointNum == 0)
+                       {       // Hard coded refpoint labels
+                               if(stricmp(stripped, 
+                                       referenceRootNames[referenceRootNameOffsets[g_skelModel.references]+k]) == 0)
+                               {
+                                       break;
+                               }
+                       }
+                       else
+                       {       // labels indicated by the QDT
+                               if(stricmp(stripped, RefPointNameList[k]) == 0)
+                               {
+                                       break;
+                               }
+                       }
+               }
+
+               if(tk_Token == TK_EOF)
+               {
+                       if (RefPointNum == 0)
+                       {       // Hard coded refpoint labels
+                               Error("Bone Chain Root: %s not found\n", referenceRootNames[referenceRootNameOffsets[g_skelModel.references]]);
+                       }
+                       else
+                       {       // labels indicated by the QDT
+                               Error("Bone Chain Root: %s not found\n", RefPointNameList[k]);
+                       }
+                       return;
+               }
+
+//             TK_Beyond(TK_SCALING);
+
+//             ParseVec3d(curScale[currentStack]);
+
+               TK_Beyond(TK_ROTATION);
+
+               ParseRotation3d(curRotation[currentStack]);
+
+               TK_Beyond(TK_TRANSLATION);
+
+               ParseVec3d(curTranslation[currentStack]);
+
+               // account for global model translation
+               curTranslation[currentStack][1] += g_skelModel.translation[0];
+               curTranslation[currentStack][2] += g_skelModel.translation[1];
+               curTranslation[currentStack][0] += g_skelModel.translation[2];
+
+               curCorrespondingJoint[currentStack] = -1;
+
+//             rjr - this one not needed, as there is also a stack increment 20 lines below???
+//             ++currentStack;
+
+               // Load the joint to get orientation
+               TK_Beyond(TK_MODEL);
+
+//             TK_Beyond(TK_SCALING);
+
+//             ParseVec3d(curScale[currentStack]);
+
+               TK_Beyond(TK_ROTATION);
+
+               ParseRotation3d(curRotation[currentStack]);
+
+//             TK_Beyond(TK_TRANSLATION);
+
+//             ParseVec3d(curTranslation[currentStack]);
+
+               fr->references[k].placement.origin[1] = 0.0;
+               fr->references[k].placement.origin[2] = 0.0;
+               fr->references[k].placement.origin[0] = 0.0;
+
+               fr->references[k].placement.direction[1] = 20.0;
+               fr->references[k].placement.direction[2] = 0.0;
+               fr->references[k].placement.direction[0] = 0.0;
+
+               fr->references[k].placement.up[1] = 0.0;
+               fr->references[k].placement.up[2] = 20.0;
+               fr->references[k].placement.up[0] = 0.0;
+
+               curCorrespondingJoint[currentStack] = k;
+
+               ++currentStack;
+
+               stackSize = currentStack;
+
+               for(i = stackSize - 1; i >= 0; --i)
+               {
+                       rx = curRotation[i][0]*ANGLE_TO_RAD;
+                       ry = curRotation[i][1]*ANGLE_TO_RAD;
+                       rz = curRotation[i][2]*ANGLE_TO_RAD;
+
+                       cx = cos(rx);
+                       sx = sin(rx);
+
+                       cy = cos(ry);
+                       sy = sin(ry);
+
+                       cz = cos(rz);
+                       sz = sin(rz);
+
+                       for(j = i; j < stackSize; ++j)
+                       {
+                               if(curCorrespondingJoint[j] != -1)
+                               {
+                                       placement = &fr->references[curCorrespondingJoint[j]].placement;
+
+                                       // y-axis rotation for origin
+                                       x2 = placement->origin[0]*cy+placement->origin[2]*sy;
+                                       z2 = -placement->origin[0]*sy+placement->origin[2]*cy;
+                                       placement->origin[0] = x2;
+                                       placement->origin[2] = z2;
+
+                                       // y-axis rotation for direction
+                                       x2 = placement->direction[0]*cy+placement->direction[2]*sy;
+                                       z2 = -placement->direction[0]*sy+placement->direction[2]*cy;
+                                       placement->direction[0] = x2;
+                                       placement->direction[2] = z2;
+
+                                       // y-axis rotation for up
+                                       x2 = placement->up[0]*cy+placement->up[2]*sy;
+                                       z2 = -placement->up[0]*sy+placement->up[2]*cy;
+                                       placement->up[0] = x2;
+                                       placement->up[2] = z2;
+
+                                       // z-axis rotation for origin
+                                       x2 = placement->origin[0]*cz-placement->origin[1]*sz;
+                                       y2 = placement->origin[0]*sz+placement->origin[1]*cz;
+                                       placement->origin[0] = x2;
+                                       placement->origin[1] = y2;
+
+                                       // z-axis rotation for direction
+                                       x2 = placement->direction[0]*cz-placement->direction[1]*sz;
+                                       y2 = placement->direction[0]*sz+placement->direction[1]*cz;
+                                       placement->direction[0] = x2;
+                                       placement->direction[1] = y2;
+
+                                       // z-axis rotation for up
+                                       x2 = placement->up[0]*cz-placement->up[1]*sz;
+                                       y2 = placement->up[0]*sz+placement->up[1]*cz;
+                                       placement->up[0] = x2;
+                                       placement->up[1] = y2;
+
+                                       // x-axis rotation for origin
+                                       y2 = placement->origin[1]*cx-placement->origin[2]*sx;
+                                       z2 = placement->origin[1]*sx+placement->origin[2]*cx;
+                                       placement->origin[1] = y2;
+                                       placement->origin[2] = z2;
+
+                                       // x-axis rotation for direction vector
+                                       y2 = placement->direction[1]*cx-placement->direction[2]*sx;
+                                       z2 = placement->direction[1]*sx+placement->direction[2]*cx;
+                                       placement->direction[1] = y2;
+                                       placement->direction[2] = z2;
+
+                                       // x-axis rotation for up vector
+                                       y2 = placement->up[1]*cx-placement->up[2]*sx;
+                                       z2 = placement->up[1]*sx+placement->up[2]*cx;
+                                       placement->up[1] = y2;
+                                       placement->up[2] = z2;
+
+                                       // translate origin
+                                       placement->origin[0] += curTranslation[i][0];
+                                       placement->origin[1] += curTranslation[i][1];
+                                       placement->origin[2] += curTranslation[i][2];
+
+                                       // translate back to local coord
+                                       placement->direction[0] += curTranslation[i][0];
+                                       placement->direction[1] += curTranslation[i][1];
+                                       placement->direction[2] += curTranslation[i][2];
+
+                                       // translate back to local coord
+                                       placement->up[0] += curTranslation[i][0];
+                                       placement->up[1] += curTranslation[i][1];
+                                       placement->up[2] += curTranslation[i][2];
+
+                               }
+                       }
+               }
+               printf("%f, %f, %f\n", placement->origin[0], placement->origin[1], placement->origin[2]);
+       }
+       printf("\n");
+}
+
+void Cmd_FMReferenced()
+{
+       int i;
+
+       GetScriptToken (false);
+       g_skelModel.references = atoi(token);
+
+       // Guess what?  Now, we now want a list of strings to look for here instead of a hard-coded list
+       for (i=0; i<REF_MAX_POINTS; i++)
+       {
+               if (ScriptTokenAvailable())
+               {       // There is yet another reference point waiting.
+                       GetScriptToken(false);
+                       strcpy(RefPointNameList[i], token);
+               }
+               else
+               {
+                       break;
+               }
+       }
+
+       RefPointNum = i;
+
+       if (RefPointNum > 0)
+       {
+               printf("Searching for %d different reference points.\n", RefPointNum);
+       }
+       else
+       {
+               printf("Using built-in reference points.\n");
+       }
+
+}
+
+void LoadReferences(char *fileName, fmframe_t *fr)
+{
+       FILE *file1;
+    int dot = '.';
+       char *dotstart;
+       char    InputFileName[256];
+
+       dotstart = strrchr(fileName,dot); // Does it already have an extension on the file name?
+
+       if (!dotstart)
+       {
+               strcpy(InputFileName, fileName);
+               strcat(InputFileName, ".hrc");
+               if((file1 = fopen(InputFileName, "rb")) != NULL)
+               {
+                       fclose(file1);
+
+                       LoadHRCReferences(InputFileName, fr);
+
+                       printf(" - assuming .HRC\n");
+                       return;
+               }
+
+               Error("\n Could not open file '%s':\n"
+                       "No HRC.\n", fileName);
+       }
+       else
+       {
+               if((file1 = fopen(fileName, "rb")) != NULL)
+               {
+                       printf("\n");
+                       fclose(file1);
+                       if (strcmp(dotstart,".hrc") == 0 || strcmp(dotstart,".HRC") == 0)
+                       {
+                               LoadHRCReferences(fileName, fr);
+
+                               return;
+                       }
+               }
+
+               Error("Could not open file '%s':\n",fileName);
+       }
+}
+
+void GrabReferencedFrame(char *frame)
+{
+       char    file1[1024];
+       char    *framefile;
+       fmframe_t       *fr;
+
+       framefile = FindFrameFile (frame);
+
+       sprintf (file1, "%s/%s", cdarchive, framefile);
+       ExpandPathAndArchive (file1);
+
+       sprintf (file1, "%s/%s",cddir, framefile);
+
+       printf ("Grabbing Referenced %s\n", file1);
+
+       fr = &g_frames[fmheader.num_frames - 1]; // last frame read in
+
+       LoadReferences(file1, fr);
+}
+