]> de.git.xonotic.org Git - xonotic/netradiant.git/blobdiff - tools/quake2/qdata_heretic2/models.c
set eol-style
[xonotic/netradiant.git] / tools / quake2 / qdata_heretic2 / models.c
index d594cafe135589d1ac7a208aea89319a2461d794..5ae30a15f6bf6530f8dd5936416c3be5b2b312e1 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
-\r
-#include "qdata.h"\r
-#include <assert.h>\r
-#include "jointed.h"\r
-#include "fmodel.h"\r
-\r
-//=================================================================\r
-\r
-typedef struct \r
-{\r
-       int             numnormals;\r
-       vec3_t  normalsum;\r
-} vertexnormals_t;\r
-\r
-typedef struct\r
-{\r
-       vec3_t          v;\r
-       int                     lightnormalindex;\r
-} trivert_t;\r
-\r
-typedef struct\r
-{\r
-       vec3_t          mins, maxs;\r
-       char            name[16];\r
-       trivert_t       v[MAX_VERTS];\r
-       QDataJoint_t    joints[NUM_CLUSTERS]; // ,this\r
-} frame_t;\r
-\r
-// ,and all of this should get out of here, need to use new stuff in fmodels instead\r
-\r
-typedef struct IntListNode_s\r
-{\r
-       int data;\r
-       struct IntListNode_s *next;\r
-} IntListNode_t;  // gaak\r
-\r
-typedef struct\r
-{\r
-       float           scale[3];       // multiply byte verts by this\r
-       float           translate[3];   // then add this\r
-} PartialAliasFrame_t;\r
-\r
-int jointed;\r
-int clustered;\r
-\r
-int *clusters[NUM_CLUSTERS];\r
-IntListNode_t *vertLists[NUM_CLUSTERS];\r
-int            num_verts[NUM_CLUSTERS + 1];\r
-int            new_num_verts[NUM_CLUSTERS + 1];\r
-\r
-// end that\r
-\r
-//================================================================\r
-\r
-frame_t                g_frames[MAX_FRAMES];\r
-//frame_t              *g_frames;\r
-\r
-static dmdl_t          model;\r
-\r
-\r
-float          scale_up;                       // set by $scale\r
-vec3_t         adjust;                         // set by $origin\r
-int                    g_fixedwidth, g_fixedheight;    // set by $skinsize\r
-\r
-\r
-//\r
-// base frame info\r
-//\r
-dstvert_t      base_st[MAX_VERTS];\r
-dtriangle_t    triangles[MAX_TRIANGLES];\r
-\r
-static int                     triangle_st[MAX_TRIANGLES][3][2];\r
-\r
-// the command list holds counts, s/t values, and xyz indexes\r
-// that are valid for every frame\r
-int                    commands[16384];\r
-int                    numcommands;\r
-int                    numglverts;\r
-int                    used[MAX_TRIANGLES];\r
-\r
-char           g_skins[MAX_MD2SKINS][64];\r
-\r
-char           cdarchive[1024];\r
-char           cdpartial[1024];\r
-char           cddir[1024];\r
-\r
-char           modelname[64];  // empty unless $modelname issued (players)\r
-\r
-extern         char            *g_outputDir;\r
-\r
-#define NUMVERTEXNORMALS       162\r
-\r
-float  avertexnormals[NUMVERTEXNORMALS][3] = \r
-{\r
-       #include "anorms.h"\r
-};\r
-\r
-unsigned char pic[SKINPAGE_HEIGHT*SKINPAGE_WIDTH], pic_palette[768];\r
-\r
-FILE   *headerouthandle = NULL;\r
-\r
-//==============================================================\r
-\r
-/*\r
-===============\r
-ClearModel\r
-===============\r
-*/\r
-static void ClearModel (void)\r
-{\r
-       memset (&model, 0, sizeof(model));\r
-\r
-       modelname[0] = 0;\r
-       jointed = NOT_JOINTED;\r
-       clustered = 0;\r
-       scale_up = 1.0; \r
-       VectorCopy (vec3_origin, adjust);\r
-       g_fixedwidth = g_fixedheight = 0;\r
-       g_skipmodel = false;\r
-}\r
-\r
-\r
-void H_printf(char *fmt, ...)\r
-{\r
-       va_list argptr;\r
-       char    name[1024];\r
-\r
-       if (!headerouthandle)\r
-       {\r
-               sprintf (name, "%s/tris.h", cddir);\r
-               headerouthandle = SafeOpenWrite (name);\r
-               fprintf(headerouthandle, "// %s\n\n", cddir);\r
-               fprintf(headerouthandle, "// This file generated by qdata - Do NOT Modify\n\n");\r
-       }\r
-\r
-       va_start (argptr, fmt);\r
-       vfprintf (headerouthandle, fmt, argptr);\r
-       va_end (argptr);\r
-}\r
-\r
-#if 1\r
-/*\r
-============\r
-WriteModelFile\r
-============\r
-*/\r
-void WriteCommonModelFile (FILE *modelouthandle, PartialAliasFrame_t *outFrames)\r
-{\r
-       int                             i;\r
-       dmdl_t                  modeltemp;\r
-       int                             j, k;\r
-       frame_t                 *in;\r
-       daliasframe_t   *out;\r
-       byte                    buffer[MAX_VERTS*4+128];\r
-       float                   v;\r
-       int                             c_on, c_off;\r
-\r
-       model.version = ALIAS_VERSION;\r
-       model.framesize = (int)&((daliasframe_t *)0)->verts[model.num_xyz];\r
-       model.num_glcmds = numcommands;\r
-       model.ofs_skins = sizeof(dmdl_t);\r
-       model.ofs_st = model.ofs_skins + model.num_skins * MAX_SKINNAME;\r
-       model.ofs_tris = model.ofs_st + model.num_st*sizeof(dstvert_t);\r
-       model.ofs_frames = model.ofs_tris + model.num_tris*sizeof(dtriangle_t);\r
-       model.ofs_glcmds = model.ofs_frames + model.num_frames*model.framesize;\r
-       model.ofs_end = model.ofs_glcmds + model.num_glcmds*sizeof(int);\r
-       //\r
-       // write out the model header\r
-       //\r
-       for (i=0 ; i<sizeof(dmdl_t)/4 ; i++)\r
-               ((int *)&modeltemp)[i] = LittleLong (((int *)&model)[i]);\r
-\r
-       SafeWrite (modelouthandle, &modeltemp, sizeof(modeltemp));\r
-\r
-       //\r
-       // write out the skin names\r
-       //\r
-       SafeWrite (modelouthandle, g_skins, model.num_skins * MAX_SKINNAME);\r
-\r
-       //\r
-       // write out the texture coordinates\r
-       //\r
-       c_on = c_off = 0;\r
-       for (i=0 ; i<model.num_st ; i++)\r
-       {\r
-               base_st[i].s = LittleShort (base_st[i].s);\r
-               base_st[i].t = LittleShort (base_st[i].t);\r
-       }\r
-\r
-       SafeWrite (modelouthandle, base_st, model.num_st * sizeof(base_st[0]));\r
-\r
-       //\r
-       // write out the triangles\r
-       //\r
-       for (i=0 ; i<model.num_tris ; i++)\r
-       {\r
-               int                     j;\r
-               dtriangle_t     tri;\r
-\r
-               for (j=0 ; j<3 ; j++)\r
-               {\r
-                       tri.index_xyz[j] = LittleShort (triangles[i].index_xyz[j]);\r
-                       tri.index_st[j] = LittleShort (triangles[i].index_st[j]);\r
-               }\r
-\r
-               SafeWrite (modelouthandle, &tri, sizeof(tri));\r
-       }\r
-\r
-       //\r
-       // write out the frames\r
-       //\r
-       for (i=0 ; i<model.num_frames ; i++)\r
-       {\r
-               in = &g_frames[i];\r
-               out = (daliasframe_t *)buffer;\r
-\r
-               strcpy (out->name, in->name);\r
-               for (j=0 ; j<3 ; j++)\r
-               {\r
-                       out->scale[j] = (in->maxs[j] - in->mins[j])/255;\r
-                       out->translate[j] = in->mins[j];\r
-\r
-                       if(outFrames)\r
-                       {\r
-                               outFrames[i].scale[j] = out->scale[j];\r
-                               outFrames[i].translate[j] = out->translate[j];\r
-                       }\r
-               }\r
-\r
-               for (j=0 ; j<model.num_xyz ; j++)\r
-               {\r
-               // all of these are byte values, so no need to deal with endianness\r
-                       out->verts[j].lightnormalindex = in->v[j].lightnormalindex;\r
-\r
-                       for (k=0 ; k<3 ; k++)\r
-                       {\r
-                       // scale to byte values & min/max check\r
-                               v = Q_rint ( (in->v[j].v[k] - out->translate[k]) / out->scale[k] );\r
-\r
-                       // clamp, so rounding doesn't wrap from 255.6 to 0\r
-                               if (v > 255.0)\r
-                                       v = 255.0;\r
-                               if (v < 0)\r
-                                       v = 0;\r
-                               out->verts[j].v[k] = v;\r
-                       }\r
-               }\r
-\r
-               for (j=0 ; j<3 ; j++)\r
-               {\r
-                       out->scale[j] = LittleFloat (out->scale[j]);\r
-                       out->translate[j] = LittleFloat (out->translate[j]);\r
-               }\r
-\r
-               SafeWrite (modelouthandle, out, model.framesize);\r
-       }\r
-\r
-       //\r
-       // write out glcmds\r
-       //\r
-       SafeWrite (modelouthandle, commands, numcommands*4);\r
-}\r
-\r
-/*\r
-============\r
-WriteModelFile\r
-============\r
-*/\r
-void WriteModelFile (FILE *modelouthandle)\r
-{\r
-       model.ident = IDALIASHEADER;\r
-\r
-       WriteCommonModelFile(modelouthandle, NULL);\r
-}\r
-\r
-/*\r
-============\r
-WriteJointedModelFile\r
-============\r
-*/\r
-void WriteJointedModelFile (FILE *modelouthandle)\r
-{\r
-       int                             i;\r
-       int                             j, k;\r
-       frame_t                 *in;\r
-       float                   v;\r
-       IntListNode_t   *current, *toFree;\r
-       PartialAliasFrame_t outFrames[MAX_FRAMES];\r
-\r
-       model.ident = IDJOINTEDALIASHEADER;\r
-       \r
-       WriteCommonModelFile(modelouthandle, outFrames);\r
-\r
-       // Skeletal Type\r
-       SafeWrite(modelouthandle, &jointed, sizeof(int));\r
-\r
-       // number of joints\r
-       SafeWrite(modelouthandle, &numJointsForSkeleton[jointed], sizeof(int));\r
-\r
-       // number of verts in each cluster\r
-       SafeWrite(modelouthandle, &new_num_verts[1], sizeof(int)*numJointsForSkeleton[jointed]);\r
-\r
-       // cluster verts\r
-       for(i = 0; i < new_num_verts[0]; ++i)\r
-       {\r
-               current = vertLists[i];\r
-               while(current)\r
-               {\r
-                       SafeWrite (modelouthandle, &current->data, sizeof(int));\r
-                       toFree = current;\r
-                       current = current->next;\r
-                       free(toFree);  // freeing of memory allocated in ReplaceClusterIndex called in Cmd_Base\r
-               }\r
-       }\r
-\r
-       for (i=0 ; i<model.num_frames ; i++)\r
-       {\r
-               in = &g_frames[i];\r
-\r
-               for (j = 0 ; j < new_num_verts[0]; ++j)\r
-               {\r
-                       for (k=0 ; k<3 ; k++)\r
-                       {\r
-                               // scale to byte values & min/max check\r
-                               v = Q_rint ( (in->joints[j].placement.origin[k] - outFrames[i].translate[k]) / outFrames[i].scale[k] );\r
-\r
-                               // clamp, so rounding doesn't wrap from 255.6 to 0\r
-                               if (v > 255.0)\r
-                               {\r
-                                       v = 255.0;\r
-                               }\r
-\r
-                               if (v < 0)\r
-                               {\r
-                                       v = 0;\r
-                               }\r
-\r
-                               // write out origin as a float (there's only a few per model, so it's not really \r
-                               // a size issue)\r
-                               SafeWrite (modelouthandle, &v, sizeof(float));\r
-                       }\r
-\r
-                       for (k=0 ; k<3 ; k++)\r
-                       {\r
-                               v = Q_rint ( (in->joints[j].placement.direction[k] - outFrames[i].translate[k]) / outFrames[i].scale[k] );\r
-\r
-                               // clamp, so rounding doesn't wrap from 255.6 to 0\r
-                               if (v > 255.0)\r
-                               {\r
-                                       v = 255.0;\r
-                               }\r
-\r
-                               if (v < 0)\r
-                               {\r
-                                       v = 0;\r
-                               }\r
-\r
-                               // write out origin as a float (there's only a few per model, so it's not really \r
-                               // a size issue)\r
-                               SafeWrite (modelouthandle, &v, sizeof(float));\r
-                       }\r
-\r
-                       for (k=0 ; k<3 ; k++)\r
-                       {\r
-                               v = Q_rint ( (in->joints[j].placement.up[k] - outFrames[i].translate[k]) / outFrames[i].scale[k] );\r
-\r
-                               // clamp, so rounding doesn't wrap from 255.6 to 0\r
-                               if (v > 255.0)\r
-                               {\r
-                                       v = 255.0;\r
-                               }\r
-\r
-                               if (v < 0)\r
-                               {\r
-                                       v = 0;\r
-                               }\r
-\r
-                               // write out origin as a float (there's only a few per model, so it's not really \r
-                               // a size issue)\r
-                               SafeWrite (modelouthandle, &v, sizeof(float));\r
-                       }\r
-               }\r
-       }\r
-}\r
-#else\r
-/*\r
-============\r
-WriteModelFile\r
-============\r
-*/\r
-static void WriteModelFile (FILE *modelouthandle)\r
-{\r
-       int                             i;\r
-       dmdl_t                  modeltemp;\r
-       int                             j, k;\r
-       frame_t                 *in;\r
-       daliasframe_t   *out;\r
-       byte                    buffer[MAX_VERTS*4+128];\r
-       float                   v;\r
-       int                             c_on, c_off;\r
-\r
-       model.ident = IDALIASHEADER;\r
-       model.version = ALIAS_VERSION;\r
-       model.framesize = (int)&((daliasframe_t *)0)->verts[model.num_xyz];\r
-       model.num_glcmds = numcommands;\r
-       model.ofs_skins = sizeof(dmdl_t);\r
-       model.ofs_st = model.ofs_skins + model.num_skins * MAX_SKINNAME;\r
-       model.ofs_tris = model.ofs_st + model.num_st*sizeof(dstvert_t);\r
-       model.ofs_frames = model.ofs_tris + model.num_tris*sizeof(dtriangle_t);\r
-       model.ofs_glcmds = model.ofs_frames + model.num_frames*model.framesize;\r
-       model.ofs_end = model.ofs_glcmds + model.num_glcmds*4;\r
-\r
-       //\r
-       // write out the model header\r
-       //\r
-       for (i=0 ; i<sizeof(dmdl_t)/4 ; i++)\r
-               ((int *)&modeltemp)[i] = LittleLong (((int *)&model)[i]);\r
-\r
-       SafeWrite (modelouthandle, &modeltemp, sizeof(modeltemp));\r
-\r
-       //\r
-       // write out the skin names\r
-       //\r
-       SafeWrite (modelouthandle, g_skins, model.num_skins * MAX_SKINNAME);\r
-\r
-       //\r
-       // write out the texture coordinates\r
-       //\r
-       c_on = c_off = 0;\r
-       for (i=0 ; i<model.num_st ; i++)\r
-       {\r
-               base_st[i].s = LittleShort (base_st[i].s);\r
-               base_st[i].t = LittleShort (base_st[i].t);\r
-       }\r
-\r
-       SafeWrite (modelouthandle, base_st, model.num_st * sizeof(base_st[0]));\r
-\r
-       //\r
-       // write out the triangles\r
-       //\r
-       for (i=0 ; i<model.num_tris ; i++)\r
-       {\r
-               int                     j;\r
-               dtriangle_t     tri;\r
-\r
-               for (j=0 ; j<3 ; j++)\r
-               {\r
-                       tri.index_xyz[j] = LittleShort (triangles[i].index_xyz[j]);\r
-                       tri.index_st[j] = LittleShort (triangles[i].index_st[j]);\r
-               }\r
-\r
-               SafeWrite (modelouthandle, &tri, sizeof(tri));\r
-       }\r
-\r
-       //\r
-       // write out the frames\r
-       //\r
-       for (i=0 ; i<model.num_frames ; i++)\r
-       {\r
-               in = &g_frames[i];\r
-               out = (daliasframe_t *)buffer;\r
-\r
-               strcpy (out->name, in->name);\r
-               for (j=0 ; j<3 ; j++)\r
-               {\r
-                       out->scale[j] = (in->maxs[j] - in->mins[j])/255;\r
-                       out->translate[j] = in->mins[j];\r
-               }\r
-\r
-               for (j=0 ; j<model.num_xyz ; j++)\r
-               {\r
-               // all of these are byte values, so no need to deal with endianness\r
-                       out->verts[j].lightnormalindex = in->v[j].lightnormalindex;\r
-\r
-                       for (k=0 ; k<3 ; k++)\r
-                       {\r
-                       // scale to byte values & min/max check\r
-                               v = Q_rint ( (in->v[j].v[k] - out->translate[k]) / out->scale[k] );\r
-\r
-                       // clamp, so rounding doesn't wrap from 255.6 to 0\r
-                               if (v > 255.0)\r
-                                       v = 255.0;\r
-                               if (v < 0)\r
-                                       v = 0;\r
-                               out->verts[j].v[k] = v;\r
-                       }\r
-               }\r
-\r
-               for (j=0 ; j<3 ; j++)\r
-               {\r
-                       out->scale[j] = LittleFloat (out->scale[j]);\r
-                       out->translate[j] = LittleFloat (out->translate[j]);\r
-               }\r
-\r
-               SafeWrite (modelouthandle, out, model.framesize);\r
-       }\r
-\r
-       //\r
-       // write out glcmds\r
-       //\r
-       SafeWrite (modelouthandle, commands, numcommands*4);\r
-}\r
-#endif\r
-\r
-/*\r
-===============\r
-FinishModel\r
-===============\r
-*/\r
-void FinishModel (void)\r
-{\r
-       FILE            *modelouthandle;\r
-       int                     i;\r
-       char            name[1024];\r
-       \r
-       if (!model.num_frames)\r
-               return;\r
-       \r
-//\r
-// copy to release directory tree if doing a release build\r
-//\r
-       if (g_release)\r
-       {\r
-               if (modelname[0])\r
-                       sprintf (name, "%s", modelname);\r
-               else\r
-                       sprintf (name, "%s/tris.md2", cdpartial);\r
-               ReleaseFile (name);\r
-\r
-               for (i=0 ; i<model.num_skins ; i++)\r
-               {\r
-                       ReleaseFile (g_skins[i]);\r
-               }\r
-               model.num_frames = 0;\r
-               return;\r
-       }\r
-       \r
-//\r
-// write the model output file\r
-//\r
-       if (modelname[0])\r
-               sprintf (name, "%s%s", g_outputDir, modelname);\r
-       else\r
-               sprintf (name, "%s/tris.md2", g_outputDir);\r
-       printf ("saving to %s\n", name);\r
-       CreatePath (name);\r
-       modelouthandle = SafeOpenWrite (name);\r
-\r
-#if 1\r
-       if(jointed != NOT_JOINTED)\r
-               WriteJointedModelFile(modelouthandle);\r
-       else\r
-#endif\r
-               WriteModelFile(modelouthandle);\r
-       \r
-       printf ("%3dx%3d skin\n", model.skinwidth, model.skinheight);\r
-       printf ("First frame boundaries:\n");\r
-       printf ("       minimum x: %3f\n", g_frames[0].mins[0]);\r
-       printf ("       maximum x: %3f\n", g_frames[0].maxs[0]);\r
-       printf ("       minimum y: %3f\n", g_frames[0].mins[1]);\r
-       printf ("       maximum y: %3f\n", g_frames[0].maxs[1]);\r
-       printf ("       minimum z: %3f\n", g_frames[0].mins[2]);\r
-       printf ("       maximum z: %3f\n", g_frames[0].maxs[2]);\r
-       printf ("%4d vertices\n", model.num_xyz);\r
-       printf ("%4d triangles\n", model.num_tris);\r
-       printf ("%4d frame\n", model.num_frames);\r
-       printf ("%4d glverts\n", numglverts);\r
-       printf ("%4d glcmd\n", model.num_glcmds);\r
-       printf ("%4d skins\n", model.num_skins);\r
-       printf ("file size: %d\n", (int)ftell (modelouthandle) );\r
-       printf ("---------------------\n");\r
-       \r
-       fclose (modelouthandle);\r
-\r
-       // finish writing header file\r
-       H_printf("\n");\r
-\r
-       // scale_up is usefull to allow step distances to be adjusted\r
-       H_printf("#define MODEL_SCALE\t\t%f\n", scale_up);\r
-\r
-       fclose (headerouthandle);\r
-       headerouthandle = NULL;\r
-}\r
-\r
-\r
-/*\r
-=================================================================\r
-\r
-ALIAS MODEL DISPLAY LIST GENERATION\r
-\r
-=================================================================\r
-*/\r
-\r
-int            strip_xyz[128];\r
-int            strip_st[128];\r
-int            strip_tris[128];\r
-int            stripcount;\r
-\r
-/*\r
-================\r
-StripLength\r
-================\r
-*/\r
-static int     StripLength (int starttri, int startv)\r
-{\r
-       int                     m1, m2;\r
-       int                     st1, st2;\r
-       int                     j;\r
-       dtriangle_t     *last, *check;\r
-       int                     k;\r
-\r
-       used[starttri] = 2;\r
-\r
-       last = &triangles[starttri];\r
-\r
-       strip_xyz[0] = last->index_xyz[(startv)%3];\r
-       strip_xyz[1] = last->index_xyz[(startv+1)%3];\r
-       strip_xyz[2] = last->index_xyz[(startv+2)%3];\r
-       strip_st[0] = last->index_st[(startv)%3];\r
-       strip_st[1] = last->index_st[(startv+1)%3];\r
-       strip_st[2] = last->index_st[(startv+2)%3];\r
-\r
-       strip_tris[0] = starttri;\r
-       stripcount = 1;\r
-\r
-       m1 = last->index_xyz[(startv+2)%3];\r
-       st1 = last->index_st[(startv+2)%3];\r
-       m2 = last->index_xyz[(startv+1)%3];\r
-       st2 = last->index_st[(startv+1)%3];\r
-\r
-       // look for a matching triangle\r
-nexttri:\r
-       for (j=starttri+1, check=&triangles[starttri+1]\r
-               ; j<model.num_tris ; j++, check++)\r
-       {\r
-               for (k=0 ; k<3 ; k++)\r
-               {\r
-                       if (check->index_xyz[k] != m1)\r
-                               continue;\r
-                       if (check->index_st[k] != st1)\r
-                               continue;\r
-                       if (check->index_xyz[ (k+1)%3 ] != m2)\r
-                               continue;\r
-                       if (check->index_st[ (k+1)%3 ] != st2)\r
-                               continue;\r
-\r
-                       // this is the next part of the fan\r
-\r
-                       // if we can't use this triangle, this tristrip is done\r
-                       if (used[j])\r
-                               goto done;\r
-\r
-                       // the new edge\r
-                       if (stripcount & 1)\r
-                       {\r
-                               m2 = check->index_xyz[ (k+2)%3 ];\r
-                               st2 = check->index_st[ (k+2)%3 ];\r
-                       }\r
-                       else\r
-                       {\r
-                               m1 = check->index_xyz[ (k+2)%3 ];\r
-                               st1 = check->index_st[ (k+2)%3 ];\r
-                       }\r
-\r
-                       strip_xyz[stripcount+2] = check->index_xyz[ (k+2)%3 ];\r
-                       strip_st[stripcount+2] = check->index_st[ (k+2)%3 ];\r
-                       strip_tris[stripcount] = j;\r
-                       stripcount++;\r
-\r
-                       used[j] = 2;\r
-                       goto nexttri;\r
-               }\r
-       }\r
-done:\r
-\r
-       // clear the temp used flags\r
-       for (j=starttri+1 ; j<model.num_tris ; j++)\r
-               if (used[j] == 2)\r
-                       used[j] = 0;\r
-\r
-       return stripcount;\r
-}\r
-\r
-\r
-/*\r
-===========\r
-FanLength\r
-===========\r
-*/\r
-static int     FanLength (int starttri, int startv)\r
-{\r
-       int             m1, m2;\r
-       int             st1, st2;\r
-       int             j;\r
-       dtriangle_t     *last, *check;\r
-       int             k;\r
-\r
-       used[starttri] = 2;\r
-\r
-       last = &triangles[starttri];\r
-\r
-       strip_xyz[0] = last->index_xyz[(startv)%3];\r
-       strip_xyz[1] = last->index_xyz[(startv+1)%3];\r
-       strip_xyz[2] = last->index_xyz[(startv+2)%3];\r
-       strip_st[0] = last->index_st[(startv)%3];\r
-       strip_st[1] = last->index_st[(startv+1)%3];\r
-       strip_st[2] = last->index_st[(startv+2)%3];\r
-\r
-       strip_tris[0] = starttri;\r
-       stripcount = 1;\r
-\r
-       m1 = last->index_xyz[(startv+0)%3];\r
-       st1 = last->index_st[(startv+0)%3];\r
-       m2 = last->index_xyz[(startv+2)%3];\r
-       st2 = last->index_st[(startv+2)%3];\r
-\r
-\r
-       // look for a matching triangle\r
-nexttri:\r
-       for (j=starttri+1, check=&triangles[starttri+1] \r
-               ; j<model.num_tris ; j++, check++)\r
-       {\r
-               for (k=0 ; k<3 ; k++)\r
-               {\r
-                       if (check->index_xyz[k] != m1)\r
-                               continue;\r
-                       if (check->index_st[k] != st1)\r
-                               continue;\r
-                       if (check->index_xyz[ (k+1)%3 ] != m2)\r
-                               continue;\r
-                       if (check->index_st[ (k+1)%3 ] != st2)\r
-                               continue;\r
-\r
-                       // this is the next part of the fan\r
-\r
-                       // if we can't use this triangle, this tristrip is done\r
-                       if (used[j])\r
-                               goto done;\r
-\r
-                       // the new edge\r
-                       m2 = check->index_xyz[ (k+2)%3 ];\r
-                       st2 = check->index_st[ (k+2)%3 ];\r
-\r
-                       strip_xyz[stripcount+2] = m2;\r
-                       strip_st[stripcount+2] = st2;\r
-                       strip_tris[stripcount] = j;\r
-                       stripcount++;\r
-\r
-                       used[j] = 2;\r
-                       goto nexttri;\r
-               }\r
-       }\r
-done:\r
-\r
-       // clear the temp used flags\r
-       for (j=starttri+1 ; j<model.num_tris ; j++)\r
-               if (used[j] == 2)\r
-                       used[j] = 0;\r
-\r
-       return stripcount;\r
-}\r
-\r
-\r
-\r
-/*\r
-================\r
-BuildGlCmds\r
-\r
-Generate a list of trifans or strips\r
-for the model, which holds for all frames\r
-================\r
-*/\r
-static void BuildGlCmds (void)\r
-{\r
-       int             i, j, k;\r
-       int             startv;\r
-       float   s, t;\r
-       int             len, bestlen, besttype;\r
-       int             best_xyz[1024];\r
-       int             best_st[1024];\r
-       int             best_tris[1024];\r
-       int             type;\r
-\r
-       //\r
-       // build tristrips\r
-       //\r
-       numcommands = 0;\r
-       numglverts = 0;\r
-       memset (used, 0, sizeof(used));\r
-       for (i=0 ; i<model.num_tris ; i++)\r
-       {\r
-               // pick an unused triangle and start the trifan\r
-               if (used[i])\r
-                       continue;\r
-\r
-               bestlen = 0;\r
-               for (type = 0 ; type < 2 ; type++)\r
-//     type = 1;\r
-               {\r
-                       for (startv =0 ; startv < 3 ; startv++)\r
-                       {\r
-                               if (type == 1)\r
-                                       len = StripLength (i, startv);\r
-                               else\r
-                                       len = FanLength (i, startv);\r
-                               if (len > bestlen)\r
-                               {\r
-                                       besttype = type;\r
-                                       bestlen = len;\r
-                                       for (j=0 ; j<bestlen+2 ; j++)\r
-                                       {\r
-                                               best_st[j] = strip_st[j];\r
-                                               best_xyz[j] = strip_xyz[j];\r
-                                       }\r
-                                       for (j=0 ; j<bestlen ; j++)\r
-                                               best_tris[j] = strip_tris[j];\r
-                               }\r
-                       }\r
-               }\r
-\r
-               // mark the tris on the best strip/fan as used\r
-               for (j=0 ; j<bestlen ; j++)\r
-                       used[best_tris[j]] = 1;\r
-\r
-               if (besttype == 1)\r
-                       commands[numcommands++] = (bestlen+2);\r
-               else\r
-                       commands[numcommands++] = -(bestlen+2);\r
-\r
-               numglverts += bestlen+2;\r
-\r
-               for (j=0 ; j<bestlen+2 ; j++)\r
-               {\r
-                       // emit a vertex into the reorder buffer\r
-                       k = best_st[j];\r
-\r
-                       // emit s/t coords into the commands stream\r
-                       s = base_st[k].s;\r
-                       t = base_st[k].t;\r
-\r
-                       s = (s + 0.5) / model.skinwidth;\r
-                       t = (t + 0.5) / model.skinheight;\r
-\r
-                       *(float *)&commands[numcommands++] = s;\r
-                       *(float *)&commands[numcommands++] = t;\r
-                       *(int *)&commands[numcommands++] = best_xyz[j];\r
-               }\r
-       }\r
-\r
-       commands[numcommands++] = 0;            // end of list marker\r
-}\r
-\r
-\r
-/*\r
-===============================================================\r
-\r
-BASE FRAME SETUP\r
-\r
-===============================================================\r
-*/\r
-\r
-/*\r
-============\r
-BuildST\r
-\r
-Builds the triangle_st array for the base frame and\r
-model.skinwidth / model.skinheight\r
-\r
-  FIXME: allow this to be loaded from a file for\r
-  arbitrary mappings\r
-============\r
-*/\r
-#if 0\r
-static void OldBuildST (triangle_t *ptri, int numtri)\r
-{\r
-       int                     i, j;\r
-       int                     width, height, iwidth, iheight, swidth;\r
-       float           basex, basey;\r
-       float           s_scale, t_scale;\r
-       float           scale;\r
-       vec3_t          mins, maxs;\r
-       float           *pbasevert;\r
-       vec3_t          vtemp1, vtemp2, normal;\r
-\r
-       //\r
-       // find bounds of all the verts on the base frame\r
-       //\r
-       ClearBounds (mins, maxs);\r
-       \r
-       for (i=0 ; i<numtri ; i++)\r
-               for (j=0 ; j<3 ; j++)\r
-                       AddPointToBounds (ptri[i].verts[j], mins, maxs);\r
-       \r
-       for (i=0 ; i<3 ; i++)\r
-       {\r
-               mins[i] = floor(mins[i]);\r
-               maxs[i] = ceil(maxs[i]);\r
-       }\r
-       \r
-       width = maxs[0] - mins[0];\r
-       height = maxs[2] - mins[2];\r
-\r
-       if (!g_fixedwidth)\r
-       {       // old style\r
-               scale = 8;\r
-               if (width*scale >= 150)\r
-                       scale = 150.0 / width;  \r
-               if (height*scale >= 190)\r
-                       scale = 190.0 / height;\r
-\r
-               s_scale = t_scale = scale;\r
-\r
-               iwidth = ceil(width*s_scale);\r
-               iheight = ceil(height*t_scale);\r
-\r
-               iwidth += 4;\r
-               iheight += 4;\r
-       }\r
-       else\r
-       {       // new style\r
-               iwidth = g_fixedwidth / 2;\r
-               iheight = g_fixedheight;\r
-\r
-               s_scale = (float)(iwidth-4) / width;\r
-               t_scale = (float)(iheight-4) / height;\r
-       }\r
-\r
-//\r
-// determine which side of each triangle to map the texture to\r
-//\r
-       for (i=0 ; i<numtri ; i++)\r
-       {\r
-               VectorSubtract (ptri[i].verts[0], ptri[i].verts[1], vtemp1);\r
-               VectorSubtract (ptri[i].verts[2], ptri[i].verts[1], vtemp2);\r
-               CrossProduct (vtemp1, vtemp2, normal);\r
-\r
-               if (normal[1] > 0)\r
-               {\r
-                       basex = iwidth + 2;\r
-               }\r
-               else\r
-               {\r
-                       basex = 2;\r
-               }\r
-               basey = 2;\r
-               \r
-               for (j=0 ; j<3 ; j++)\r
-               {\r
-                       pbasevert = ptri[i].verts[j];\r
-\r
-                       triangle_st[i][j][0] = Q_rint((pbasevert[0] - mins[0]) * s_scale + basex);\r
-                       triangle_st[i][j][1] = Q_rint((maxs[2] - pbasevert[2]) * t_scale + basey);\r
-               }\r
-       }\r
-\r
-// make the width a multiple of 4; some hardware requires this, and it ensures\r
-// dword alignment for each scan\r
-       swidth = iwidth*2;\r
-       model.skinwidth = (swidth + 3) & ~3;\r
-       model.skinheight = iheight;\r
-}\r
-#endif\r
-\r
-//==========================================================================\r
-//\r
-// DrawScreen\r
-//\r
-//==========================================================================\r
-\r
-void DrawScreen(float s_scale, float t_scale, float iwidth, float iheight)\r
-{\r
-       int i;\r
-       byte *scrpos;\r
-       char buffer[256];\r
-\r
-       // Divider\r
-       scrpos = &pic[(INFO_Y-2)*SKINPAGE_WIDTH];\r
-       for(i = 0; i < SKINPAGE_WIDTH; i++)\r
-       {\r
-               *scrpos++ = 255;\r
-       }\r
-\r
-       sprintf(buffer, "GENSKIN:  ");\r
-       DrawTextChar(16, INFO_Y, buffer);\r
-       \r
-       sprintf(buffer, "( %03d * %03d )   SCALE %f %f, SKINWIDTH %d,"\r
-               " SKINHEIGHT %d", (int)ScaleWidth, (int)ScaleHeight, s_scale, t_scale, (int)iwidth*2, (int)iheight);\r
-       DrawTextChar(80, INFO_Y, buffer);\r
-}\r
-\r
-/*\r
-============\r
-BuildST\r
-\r
-Builds the triangle_st array for the base frame and\r
-model.skinwidth / model.skinheight\r
-\r
-  FIXME: allow this to be loaded from a file for\r
-  arbitrary mappings\r
-============\r
-*/\r
-void BuildST (triangle_t *ptri, int numtri, qboolean DrawSkin)\r
-{\r
-       int                     i, j;\r
-       int                     width, height, iwidth, iheight, swidth;\r
-       float           basex, basey;\r
-       float           scale;\r
-       vec3_t          mins, maxs;\r
-       float           *pbasevert;\r
-       vec3_t          vtemp1, vtemp2, normal;\r
-       float           s_scale, t_scale;\r
-       float           scWidth;\r
-       float           scHeight;\r
-\r
-       //\r
-       // find bounds of all the verts on the base frame\r
-       //\r
-       ClearBounds (mins, maxs);\r
-       \r
-       for (i=0 ; i<numtri ; i++)\r
-               for (j=0 ; j<3 ; j++)\r
-                       AddPointToBounds (ptri[i].verts[j], mins, maxs);\r
-       \r
-       for (i=0 ; i<3 ; i++)\r
-       {\r
-               mins[i] = floor(mins[i]);\r
-               maxs[i] = ceil(maxs[i]);\r
-       }\r
-       \r
-       width = maxs[0] - mins[0];\r
-       height = maxs[2] - mins[2];\r
-\r
-\r
-       scWidth = (ScaleWidth/2)*SCALE_ADJUST_FACTOR;\r
-       scHeight = ScaleHeight*SCALE_ADJUST_FACTOR;\r
-\r
-       scale = scWidth/width;\r
-\r
-       if(height*scale >= scHeight)\r
-       {\r
-               scale = scHeight/height;\r
-       }\r
-\r
-       iwidth = ceil(width*scale)+4;\r
-       iheight = ceil(height*scale)+4;\r
-\r
-       s_scale = (float)(iwidth-4) / width;\r
-       t_scale = (float)(iheight-4) / height;\r
-       t_scale = s_scale;\r
-\r
-       if (DrawSkin)\r
-               DrawScreen(s_scale, t_scale, iwidth, iheight);\r
-\r
-\r
-/*     if (!g_fixedwidth)\r
-       {       // old style\r
-               scale = 8;\r
-               if (width*scale >= 150)\r
-                       scale = 150.0 / width;  \r
-               if (height*scale >= 190)\r
-                       scale = 190.0 / height;\r
-\r
-               s_scale = t_scale = scale;\r
-\r
-               iwidth = ceil(width*s_scale);\r
-               iheight = ceil(height*t_scale);\r
-\r
-               iwidth += 4;\r
-               iheight += 4;\r
-       }\r
-       else\r
-       {       // new style\r
-               iwidth = g_fixedwidth / 2;\r
-               iheight = g_fixedheight;\r
-\r
-               s_scale = (float)(iwidth-4) / width;\r
-               t_scale = (float)(iheight-4) / height;\r
-       }*/\r
-\r
-//\r
-// determine which side of each triangle to map the texture to\r
-//\r
-       for (i=0 ; i<numtri ; i++)\r
-       {\r
-               if (ptri[i].HasUV)\r
-               {\r
-                       for (j=0 ; j<3 ; j++)\r
-                       {\r
-                               triangle_st[i][j][0] = Q_rint(ptri[i].uv[j][0]*iwidth);\r
-                               triangle_st[i][j][1] = Q_rint((1.0f-ptri[i].uv[j][1])*iheight);\r
-                       }\r
-               }\r
-               else\r
-               {\r
-                       VectorSubtract (ptri[i].verts[0], ptri[i].verts[1], vtemp1);\r
-                       VectorSubtract (ptri[i].verts[2], ptri[i].verts[1], vtemp2);\r
-                       CrossProduct (vtemp1, vtemp2, normal);\r
-\r
-                       if (normal[1] > 0)\r
-                       {\r
-                               basex = iwidth + 2;\r
-                       }\r
-                       else\r
-                       {\r
-                               basex = 2;\r
-                       }\r
-                       basey = 2;\r
-                       \r
-                       for (j=0 ; j<3 ; j++)\r
-                       {\r
-                               pbasevert = ptri[i].verts[j];\r
-\r
-                               triangle_st[i][j][0] = Q_rint((pbasevert[0] - mins[0]) * s_scale + basex);\r
-                               triangle_st[i][j][1] = Q_rint((maxs[2] - pbasevert[2]) * t_scale + basey);\r
-                       }\r
-               }\r
-\r
-               DrawLine(triangle_st[i][0][0], triangle_st[i][0][1],\r
-                       triangle_st[i][1][0], triangle_st[i][1][1]);\r
-               DrawLine(triangle_st[i][1][0], triangle_st[i][1][1],\r
-                       triangle_st[i][2][0], triangle_st[i][2][1]);\r
-               DrawLine(triangle_st[i][2][0], triangle_st[i][2][1],\r
-                       triangle_st[i][0][0], triangle_st[i][0][1]); \r
-       }\r
-\r
-// make the width a multiple of 4; some hardware requires this, and it ensures\r
-// dword alignment for each scan\r
-\r
-       swidth = iwidth*2;\r
-       model.skinwidth = (swidth + 3) & ~3;\r
-       model.skinheight = iheight;\r
-}\r
-\r
-\r
-static void ReplaceClusterIndex(int newIndex, int oldindex, int **clusters, \r
-       IntListNode_t **vertLists, int *num_verts, int *new_num_verts)\r
-{\r
-       int i, j;\r
-       IntListNode_t *next;\r
-\r
-       for(j = 0; j < num_verts[0]; ++j)\r
-       {\r
-               for(i = 0; i < num_verts[j+1]; ++i)\r
-               {\r
-                       if(clusters[j][i] == oldindex)\r
-                       {\r
-                               ++new_num_verts[j+1];\r
-\r
-                               next = vertLists[j];\r
-\r
-                               vertLists[j] = (IntListNode_t *) SafeMalloc(sizeof(IntListNode_t), "ReplaceClusterIndex");\r
-                               // Currently freed in WriteJointedModelFile only\r
-\r
-                               vertLists[j]->data = newIndex;\r
-                               vertLists[j]->next = next;\r
-                       }\r
-               }\r
-       }\r
-}\r
-\r
-/*\r
-=================\r
-Cmd_Base\r
-=================\r
-*/\r
-void Cmd_Base (void)\r
-{\r
-       vec3_t          base_xyz[MAX_VERTS];\r
-       triangle_t      *ptri;\r
-       int                     i, j, k;\r
-#if 1\r
-#else\r
-       int             time1;\r
-#endif\r
-       char    file1[1024];\r
-       char    file2[1024];\r
-\r
-       GetScriptToken (false);\r
-\r
-       if (g_skipmodel || g_release || g_archive)\r
-               return;\r
-\r
-       printf ("---------------------\n");\r
-#if 1\r
-       sprintf (file1, "%s/%s", cdpartial, token);\r
-       printf ("%s  ", file1);\r
-\r
-       ExpandPathAndArchive (file1);\r
-\r
-       sprintf (file1, "%s/%s", cddir, token);\r
-#else\r
-       sprintf (file1, "%s/%s.%s", cdarchive, token, trifileext);\r
-       printf ("%s\n", file1);\r
-\r
-       ExpandPathAndArchive (file1);\r
-\r
-       sprintf (file1, "%s/%s.%s", cddir, token, trifileext);\r
-\r
-       time1 = FileTime (file1);\r
-       if (time1 == -1)\r
-               Error ("%s doesn't exist", file1);\r
-#endif\r
-//\r
-// load the base triangles\r
-//\r
-       if (do3ds)\r
-               Load3DSTriangleList (file1, &ptri, &model.num_tris, NULL, NULL);\r
-       else\r
-               LoadTriangleList (file1, &ptri, &model.num_tris, NULL, NULL);\r
-\r
-\r
-       GetScriptToken (false);\r
-       sprintf (file2, "%s/%s.pcx", cddir, token);\r
-//     sprintf (trans_file, "%s/!%s_a.pcx", cddir, token);\r
-\r
-       printf ("skin: %s\n", file2);\r
-       Load256Image (file2, &BasePixels, &BasePalette, &BaseWidth, &BaseHeight);\r
-\r
-       if (BaseWidth != SKINPAGE_WIDTH || BaseHeight != SKINPAGE_HEIGHT)\r
-       {\r
-               if (g_allow_newskin)\r
-               {\r
-                       ScaleWidth = BaseWidth;\r
-                       ScaleHeight = BaseHeight;\r
-               }\r
-               else\r
-               {\r
-                       Error("Invalid skin page size: (%d,%d) should be (%d,%d)",\r
-                               BaseWidth,BaseHeight,SKINPAGE_WIDTH,SKINPAGE_HEIGHT);\r
-               }\r
-       }\r
-       else\r
-       {\r
-               ScaleWidth = (float)ExtractNumber(BasePixels, ENCODED_WIDTH_X,\r
-                       ENCODED_WIDTH_Y);\r
-               ScaleHeight = (float)ExtractNumber(BasePixels, ENCODED_HEIGHT_X,\r
-                       ENCODED_HEIGHT_Y);\r
-       }\r
-\r
-//\r
-// get the ST values\r
-//\r
-       BuildST (ptri, model.num_tris,false);\r
-\r
-//\r
-// run through all the base triangles, storing each unique vertex in the\r
-// base vertex list and setting the indirect triangles to point to the base\r
-// vertices\r
-//\r
-       for (i=0 ; i<model.num_tris ; i++)\r
-       {\r
-               for (j=0 ; j<3 ; j++)\r
-               {\r
-                       // get the xyz index\r
-                       for (k=0 ; k<model.num_xyz ; k++)\r
-                               if (VectorCompare (ptri[i].verts[j], base_xyz[k]))\r
-                                       break;  // this vertex is already in the base vertex list\r
-\r
-                       if (k == model.num_xyz)\r
-                       { // new index\r
-                               VectorCopy (ptri[i].verts[j], base_xyz[model.num_xyz]);\r
-\r
-                               if(clustered)\r
-                                       ReplaceClusterIndex(k, ptri[i].indicies[j], (int **)&clusters, (IntListNode_t **)&vertLists, (int *)&num_verts, (int *)&new_num_verts);\r
-\r
-                               model.num_xyz++;\r
-                       }\r
-\r
-                       triangles[i].index_xyz[j] = k;\r
-\r
-                       // get the st index\r
-                       for (k=0 ; k<model.num_st ; k++)\r
-                               if (triangle_st[i][j][0] == base_st[k].s\r
-                               && triangle_st[i][j][1] == base_st[k].t)\r
-                                       break;  // this vertex is already in the base vertex list\r
-\r
-                       if (k == model.num_st)\r
-                       { // new index\r
-                               base_st[model.num_st].s = triangle_st[i][j][0];\r
-                               base_st[model.num_st].t = triangle_st[i][j][1];\r
-                               model.num_st++;\r
-                       }\r
-\r
-                       triangles[i].index_st[j] = k;\r
-               }\r
-       }\r
-\r
-       // build triangle strips / fans\r
-       BuildGlCmds ();\r
-}\r
-\r
-//===============================================================\r
-\r
-char   *FindFrameFile (char *frame)\r
-{\r
-       int                             time1;\r
-       char                    file1[1024];\r
-       static char             retname[1024];\r
-       char                    base[32];\r
-       char                    suffix[32];\r
-       char                    *s;\r
-\r
-       if (strstr (frame, "."))\r
-               return frame;           // allready in dot format\r
-\r
-       // split 'run1' into 'run' and '1'\r
-       s = frame + strlen(frame)-1;\r
-\r
-       while (s != frame && *s >= '0' && *s <= '9')\r
-               s--;\r
-\r
-       strcpy (suffix, s+1);\r
-       strcpy (base, frame);\r
-       base[s-frame+1] = 0;\r
-\r
-       sprintf (file1, "%s/%s%s.%s",cddir, base, suffix, "hrc");\r
-       time1 = FileTime (file1);\r
-       if (time1 != -1)\r
-       {\r
-               sprintf (retname, "%s%s.%s", base, suffix, "hrc");\r
-               return retname;\r
-       }\r
-\r
-       sprintf (file1, "%s/%s%s.%s",cddir, base, suffix, "asc");\r
-       time1 = FileTime (file1);\r
-       if (time1 != -1)\r
-       {\r
-               sprintf (retname, "%s%s.%s", base, suffix, "asc");\r
-               return retname;\r
-       }\r
-\r
-       sprintf (file1, "%s/%s%s.%s",cddir, base, suffix, "tri");\r
-       time1 = FileTime (file1);\r
-       if (time1 != -1)\r
-       {\r
-               sprintf (retname, "%s%s.%s", base, suffix, "tri");\r
-               return retname;\r
-       }\r
-\r
-       sprintf (file1, "%s/%s%s.%s",cddir, base, suffix, "3ds");\r
-       time1 = FileTime (file1);\r
-       if (time1 != -1)\r
-       {\r
-               sprintf (retname, "%s%s.%s", base, suffix, "3ds");\r
-               return retname;\r
-       }\r
-\r
-       sprintf (file1, "%s/%s%s.%s",cddir, base, suffix, "htr");\r
-       time1 = FileTime (file1);\r
-       if (time1 != -1)\r
-       {\r
-               sprintf (retname, "%s%s.%s", base, suffix, "htr");\r
-               return retname;\r
-       }\r
-\r
-       // check for 'run.1'\r
-       sprintf (file1, "%s/%s.%s",cddir, base, suffix);\r
-       time1 = FileTime (file1);\r
-       if (time1 != -1)\r
-       {\r
-               sprintf (retname, "%s.%s", base, suffix);\r
-               return retname;\r
-       }\r
-\r
-       Error ("frame %s could not be found",frame);\r
-       return NULL;\r
-}\r
-\r
-/*\r
-===============\r
-GrabFrame\r
-===============\r
-*/\r
-static void GrabFrame (char *frame)\r
-{\r
-       triangle_t              *ptri;\r
-       int                             i, j;\r
-       trivert_t               *ptrivert;\r
-       int                             num_tris;\r
-       char                    file1[1024];\r
-       frame_t                 *fr;\r
-       vertexnormals_t vnorms[MAX_VERTS];\r
-       int                             index_xyz;\r
-       char                    *framefile;\r
-\r
-       // the frame 'run1' will be looked for as either\r
-       // run.1 or run1.tri, so the new alias sequence save\r
-       // feature an be used\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  ", file1);\r
-\r
-       if (model.num_frames >= MAX_FRAMES)\r
-               Error ("model.num_frames >= MAX_FRAMES");\r
-       fr = &g_frames[model.num_frames];\r
-       model.num_frames++;\r
-\r
-       strcpy (fr->name, frame);\r
-\r
-//\r
-// load the frame\r
-//\r
-       if (do3ds)\r
-               Load3DSTriangleList (file1, &ptri, &num_tris, NULL, NULL);\r
-       else\r
-               LoadTriangleList (file1, &ptri, &num_tris, NULL, NULL);\r
-\r
-       if (num_tris != model.num_tris)\r
-               Error ("%s: number of triangles doesn't match base frame\n", file1);\r
-\r
-//\r
-// allocate storage for the frame's vertices\r
-//\r
-       ptrivert = fr->v;\r
-\r
-       for (i=0 ; i<model.num_xyz ; i++)\r
-       {\r
-               vnorms[i].numnormals = 0;\r
-               VectorClear (vnorms[i].normalsum);\r
-       }\r
-       ClearBounds (fr->mins, fr->maxs);\r
-\r
-//\r
-// store the frame's vertices in the same order as the base. This assumes the\r
-// triangles and vertices in this frame are in exactly the same order as in the\r
-// base\r
-//\r
-       for (i=0 ; i<num_tris ; i++)\r
-       {\r
-               vec3_t  vtemp1, vtemp2, normal;\r
-               float   ftemp;\r
-\r
-               VectorSubtract (ptri[i].verts[0], ptri[i].verts[1], vtemp1);\r
-               VectorSubtract (ptri[i].verts[2], ptri[i].verts[1], vtemp2);\r
-               CrossProduct (vtemp1, vtemp2, normal);\r
-\r
-               VectorNormalize (normal, normal);\r
-\r
-       // rotate the normal so the model faces down the positive x axis\r
-               ftemp = normal[0];\r
-               normal[0] = -normal[1];\r
-               normal[1] = ftemp;\r
-\r
-               for (j=0 ; j<3 ; j++)\r
-               {\r
-                       index_xyz = triangles[i].index_xyz[j];\r
-\r
-               // rotate the vertices so the model faces down the positive x axis\r
-               // also adjust the vertices to the desired origin\r
-                       ptrivert[index_xyz].v[0] = ((-ptri[i].verts[j][1]) * scale_up) +\r
-                                                                               adjust[0];\r
-                       ptrivert[index_xyz].v[1] = (ptri[i].verts[j][0] * scale_up) +\r
-                                                                               adjust[1];\r
-                       ptrivert[index_xyz].v[2] = (ptri[i].verts[j][2] * scale_up) +\r
-                                                                               adjust[2];\r
-\r
-                       AddPointToBounds (ptrivert[index_xyz].v, fr->mins, fr->maxs);\r
-\r
-                       VectorAdd (vnorms[index_xyz].normalsum, normal, vnorms[index_xyz].normalsum);\r
-                       vnorms[index_xyz].numnormals++;\r
-               }\r
-       }\r
-\r
-//\r
-// calculate the vertex normals, match them to the template list, and store the\r
-// index of the best match\r
-//\r
-       for (i=0 ; i<model.num_xyz ; i++)\r
-       {\r
-               int             j;\r
-               vec3_t  v;\r
-               float   maxdot;\r
-               int             maxdotindex;\r
-               int             c;\r
-\r
-               c = vnorms[i].numnormals;\r
-               if (!c)\r
-                       Error ("Vertex with no triangles attached");\r
-\r
-               VectorScale (vnorms[i].normalsum, 1.0/c, v);\r
-               VectorNormalize (v, v);\r
-\r
-               maxdot = -999999.0;\r
-               maxdotindex = -1;\r
-\r
-               for (j=0 ; j<NUMVERTEXNORMALS ; j++)\r
-               {\r
-                       float   dot;\r
-\r
-                       dot = DotProduct (v, avertexnormals[j]);\r
-                       if (dot > maxdot)\r
-                       {\r
-                               maxdot = dot;\r
-                               maxdotindex = j;\r
-                       }\r
-               }\r
-\r
-               ptrivert[i].lightnormalindex = maxdotindex;\r
-       }\r
-\r
-       free (ptri);\r
-}\r
-\r
-/*\r
-===============\r
-GrabJointedFrame\r
-===============\r
-*/\r
-void GrabJointedFrame(char *frame)\r
-{\r
-       char    file1[1024];\r
-       char    *framefile;\r
-       frame_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[model.num_frames - 1]; // last frame read in\r
-\r
-       LoadJointList(file1, fr->joints, jointed);\r
-}\r
-\r
-/*\r
-===============\r
-GrabGlobals\r
-===============\r
-*/\r
-void GrabGlobals(char *frame)\r
-{\r
-       char    file1[1024];\r
-       char    *framefile;\r
-       frame_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[model.num_frames - 1]; // last frame read in\r
-\r
-       LoadGlobals(file1);\r
-}\r
-\r
-/*\r
-===============\r
-Cmd_Frame      \r
-===============\r
-*/\r
-void Cmd_Frame (void)\r
-{\r
-       while (ScriptTokenAvailable())\r
-       {\r
-               GetScriptToken (false);\r
-               if (g_skipmodel)\r
-                       continue;\r
-               if (g_release || g_archive)\r
-               {\r
-                       model.num_frames = 1;   // don't skip the writeout\r
-                       continue;\r
-               }\r
-\r
-               H_printf("#define FRAME_%-16s\t%i\n", token, model.num_frames);\r
-\r
-               GrabFrame (token);\r
-       }\r
-}\r
-\r
-/*\r
-===============\r
-Cmd_Skin\r
-\r
-Skins aren't actually stored in the file, only a reference\r
-is saved out to the header file.\r
-===============\r
-*/\r
-void Cmd_Skin (void)\r
-{\r
-       byte    *palette;\r
-       byte    *pixels;\r
-       int             width, height;\r
-       byte    *cropped;\r
-       int             y;\r
-       char    name[1024], savename[1024];\r
-\r
-       GetScriptToken (false);\r
-\r
-       if (model.num_skins == MAX_MD2SKINS)\r
-               Error ("model.num_skins == MAX_MD2SKINS");\r
-\r
-       if (g_skipmodel)\r
-               return;\r
-\r
-#if 1\r
-       sprintf (name, "%s/%s.pcx", cddir, token);\r
-       sprintf (savename, "%s/!%s.pcx", g_outputDir, token);\r
-       sprintf (g_skins[model.num_skins], "%s/!%s.pcx", cdpartial, token);\r
-#else\r
-       sprintf (name, "%s/%s.lbm", cdarchive, token);\r
-       strcpy (name, ExpandPathAndArchive( name ) );\r
-//     sprintf (name, "%s/%s.lbm", cddir, token);\r
-\r
-       if (ScriptTokenAvailable())\r
-       {\r
-               GetScriptToken (false);\r
-               sprintf (g_skins[model.num_skins], "%s.pcx", token);\r
-               sprintf (savename, "%s%s.pcx", g_outputDir, g_skins[model.num_skins]);\r
-       }\r
-       else\r
-       {\r
-               sprintf (savename, "%s/%s.pcx", g_outputDir, token);\r
-               sprintf (g_skins[model.num_skins], "%s/%s.pcx", cdpartial, token);\r
-       }\r
-#endif\r
-\r
-       model.num_skins++;\r
-\r
-       if (g_skipmodel || g_release || g_archive)\r
-               return;\r
-\r
-       // load the image\r
-       printf ("loading %s\n", name);\r
-       Load256Image (name, &pixels, &palette, &width, &height);\r
-//     RemapZero (pixels, palette, width, height);\r
-\r
-       // crop it to the proper size\r
-       cropped = (byte *) SafeMalloc (model.skinwidth*model.skinheight, "Cmd_Skin");\r
-       for (y=0 ; y<model.skinheight ; y++)\r
-       {\r
-               memcpy (cropped+y*model.skinwidth,\r
-                       pixels+y*width, model.skinwidth);\r
-       }\r
-\r
-       // save off the new image\r
-       printf ("saving %s\n", savename);\r
-       CreatePath (savename);\r
-       WritePCXfile (savename, cropped, model.skinwidth,\r
-               model.skinheight, palette);\r
-\r
-       free (pixels);\r
-       free (palette);\r
-       free (cropped);\r
-}\r
-\r
-\r
-/*\r
-=================\r
-Cmd_Origin\r
-=================\r
-*/\r
-void Cmd_Origin (void)\r
-{\r
-       // rotate points into frame of reference so model points down the\r
-       // positive x axis\r
-       GetScriptToken (false);\r
-       adjust[1] = -atof (token);\r
-\r
-       GetScriptToken (false);\r
-       adjust[0] = atof (token);\r
-\r
-       GetScriptToken (false);\r
-       adjust[2] = -atof (token);\r
-}\r
-\r
-\r
-/*\r
-=================\r
-Cmd_ScaleUp\r
-=================\r
-*/\r
-void Cmd_ScaleUp (void)\r
-{\r
-       GetScriptToken (false);\r
-       scale_up = atof (token);\r
-       if (g_skipmodel || g_release || g_archive)\r
-               return;\r
-\r
-       printf ("Scale up: %f\n", scale_up);\r
-}\r
-\r
-\r
-/*\r
-=================\r
-Cmd_Skinsize\r
-\r
-Set a skin size other than the default\r
-=================\r
-*/\r
-void Cmd_Skinsize (void)\r
-{\r
-       GetScriptToken (false);\r
-       g_fixedwidth = atoi(token);\r
-       GetScriptToken (false);\r
-       g_fixedheight = atoi(token);\r
-}\r
-\r
-/*\r
-=================\r
-Cmd_Modelname\r
-\r
-Gives a different name/location for the file, instead of the cddir\r
-=================\r
-*/\r
-void Cmd_Modelname (void)\r
-{\r
-       GetScriptToken (false);\r
-       strcpy (modelname, token);\r
-}\r
-\r
-/*\r
-===============\r
-Cmd_Cd\r
-===============\r
-*/\r
-void Cmd_Cd (void)\r
-{\r
-       char temp[256];\r
-\r
-       FinishModel ();\r
-       ClearModel ();\r
-\r
-       GetScriptToken (false);\r
-\r
-       // this is a silly mess...\r
-       sprintf (cdpartial, "models/%s", token); \r
-       sprintf (cdarchive, "%smodels/%s", gamedir+strlen(qdir), token); \r
-       sprintf (cddir, "%s%s", gamedir, cdpartial);\r
-\r
-       // Since we also changed directories on the output side (for mirror) make sure the outputdir is set properly too.\r
-       sprintf(temp, "%s%s", g_outputDir, cdpartial);\r
-       strcpy(g_outputDir, temp);\r
-\r
-       // if -only was specified and this cd doesn't match,\r
-       // skip the model (you only need to match leading chars,\r
-       // so you could regrab all monsters with -only monsters)\r
-       if (!g_only[0])\r
-               return;\r
-       if (strncmp(token, g_only, strlen(g_only)))\r
-       {\r
-               g_skipmodel = true;\r
-               printf ("skipping %s\n", cdpartial);\r
-       }\r
-}\r
-\r
-/*\r
-=================\r
-Cmd_Cluster\r
-=================\r
-*/\r
-void Cmd_Cluster()\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
-       LoadClusters(file1, (int **)&clusters, (int *)&num_verts, jointed);\r
-\r
-       new_num_verts[0] = num_verts[0];\r
-\r
-       clustered = 1;\r
-}\r
-\r
-// Model construction cover functions.\r
-void MODELCMD_Modelname (int modeltype)\r
-{\r
-       if (g_forcemodel)\r
-               modeltype = g_forcemodel;\r
-\r
-       Cmd_Modelname ();\r
-/*\r
-       switch(modeltype)\r
-       {\r
-       case MODEL_MD2:\r
-               Cmd_Modelname ();               \r
-               break;\r
-       case MODEL_FM:\r
-               Cmd_FMModelname ();\r
-               break;\r
-       }\r
-*/\r
-}\r
-\r
-void MODELCMD_Cd (int modeltype)\r
-{\r
-       if (g_forcemodel)\r
-               modeltype = g_forcemodel;\r
-\r
-       switch(modeltype)\r
-       {\r
-       case MODEL_MD2:\r
-               Cmd_Cd ();\r
-               break;\r
-       case MODEL_FM:\r
-               Cmd_FMCd ();\r
-               break;\r
-       }\r
-}\r
-\r
-void MODELCMD_Origin (int modeltype)\r
-{\r
-       if (g_forcemodel)\r
-               modeltype = g_forcemodel;\r
-\r
-       Cmd_Origin ();\r
-/*     switch(modeltype)\r
-       {\r
-       case MODEL_MD2:\r
-               Cmd_Origin ();\r
-               break;\r
-       case MODEL_FM:\r
-               Cmd_FMOrigin ();\r
-               break;\r
-       }\r
-*/\r
-}\r
-\r
-void MODELCMD_Cluster (int modeltype)\r
-{\r
-       if (g_forcemodel)\r
-               modeltype = g_forcemodel;\r
-\r
-       switch(modeltype)\r
-       {\r
-       case MODEL_MD2:\r
-               Cmd_Cluster ();\r
-               break;\r
-       case MODEL_FM:\r
-               Cmd_FMCluster ();\r
-               break;\r
-       }\r
-}\r
-\r
-void MODELCMD_Base (int modeltype)\r
-{\r
-       if (g_forcemodel)\r
-               modeltype = g_forcemodel;\r
-\r
-       switch(modeltype)\r
-       {\r
-       case MODEL_MD2:\r
-               Cmd_Base ();\r
-               break;\r
-       case MODEL_FM:\r
-               Cmd_FMBase (false);\r
-               break;\r
-       }\r
-}\r
-\r
-void MODELCMD_BaseST (int modeltype)\r
-{\r
-       if (g_forcemodel)\r
-               modeltype = g_forcemodel;\r
-\r
-       switch(modeltype)\r
-       {\r
-       case MODEL_MD2:\r
-               Cmd_Base ();\r
-               break;\r
-       case MODEL_FM:\r
-               Cmd_FMBase (true);\r
-               break;\r
-       }\r
-}\r
-\r
-void MODELCMD_ScaleUp (int modeltype)\r
-{\r
-       if (g_forcemodel)\r
-               modeltype = g_forcemodel;\r
-\r
-       Cmd_ScaleUp ();\r
-/*     switch(modeltype)\r
-       {\r
-       case MODEL_MD2:\r
-               Cmd_ScaleUp ();\r
-               break;\r
-       case MODEL_FM:\r
-               Cmd_FMScaleUp ();\r
-               break;\r
-       }\r
-*/\r
-}\r
-\r
-void MODELCMD_Frame (int modeltype)\r
-{\r
-       if (g_forcemodel)\r
-               modeltype = g_forcemodel;\r
-\r
-       switch(modeltype)\r
-       {\r
-       case MODEL_MD2:\r
-               Cmd_Frame ();\r
-               break;\r
-       case MODEL_FM:\r
-               Cmd_FMFrame ();\r
-               break;\r
-       }\r
-}\r
-\r
-void MODELCMD_Skin (int modeltype)\r
-{\r
-       if (g_forcemodel)\r
-               modeltype = g_forcemodel;\r
-\r
-       switch(modeltype)\r
-       {\r
-       case MODEL_MD2:\r
-               Cmd_Skin ();\r
-               break;\r
-       case MODEL_FM:\r
-               Cmd_FMSkin ();\r
-               break;\r
-       }\r
-}\r
-\r
-void MODELCMD_Skinsize (int modeltype)\r
-{\r
-       if (g_forcemodel)\r
-               modeltype = g_forcemodel;\r
-\r
-       Cmd_Skinsize ();\r
-/*\r
-       switch(modeltype)\r
-       {\r
-       case MODEL_MD2:\r
-               Cmd_Skinsize ();\r
-               break;\r
-       case MODEL_FM:\r
-               Cmd_FMSkinsize ();\r
-               break;\r
-       }\r
-*/\r
-}\r
-\r
-void MODELCMD_Skeleton (int modeltype)\r
-{\r
-       if (g_forcemodel)\r
-               modeltype = g_forcemodel;\r
-\r
-       switch(modeltype)\r
-       {\r
-       case MODEL_MD2:\r
-               break;\r
-       case MODEL_FM:\r
-               Cmd_FMSkeleton ();\r
-               break;\r
-       }\r
-}\r
-\r
-void MODELCMD_BeginGroup(int modeltype)\r
-{\r
-       if (g_forcemodel)\r
-               modeltype = g_forcemodel;\r
-\r
-       switch(modeltype)\r
-       {\r
-       case MODEL_MD2:\r
-               break;\r
-       case MODEL_FM:\r
-               Cmd_FMBeginGroup();\r
-               break;\r
-       }\r
-}\r
-\r
-void MODELCMD_EndGroup(int modeltype)\r
-{\r
-       if (g_forcemodel)\r
-               modeltype = g_forcemodel;\r
-\r
-       switch(modeltype)\r
-       {\r
-       case MODEL_MD2:\r
-               break;\r
-       case MODEL_FM:\r
-               Cmd_FMEndGroup();\r
-               break;\r
-       }\r
-}\r
-\r
-void MODELCMD_Referenced(int modeltype)\r
-{\r
-       if (g_forcemodel)\r
-               modeltype = g_forcemodel;\r
-\r
-       switch(modeltype)\r
-       {\r
-       case MODEL_MD2:\r
-               break;\r
-       case MODEL_FM:\r
-               Cmd_FMReferenced();\r
-               break;\r
-       }\r
-}\r
-\r
-void MODELCMD_NodeOrder(int modeltype)\r
-{\r
-       if (g_forcemodel)\r
-               modeltype = g_forcemodel;\r
-\r
-       switch(modeltype)\r
-       {\r
-       case MODEL_MD2:\r
-               break;\r
-       case MODEL_FM:\r
-               Cmd_FMNodeOrder();\r
-               break;\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 "qdata.h"
+#include <assert.h>
+#include "jointed.h"
+#include "fmodel.h"
+
+//=================================================================
+
+typedef struct 
+{
+       int             numnormals;
+       vec3_t  normalsum;
+} vertexnormals_t;
+
+typedef struct
+{
+       vec3_t          v;
+       int                     lightnormalindex;
+} trivert_t;
+
+typedef struct
+{
+       vec3_t          mins, maxs;
+       char            name[16];
+       trivert_t       v[MAX_VERTS];
+       QDataJoint_t    joints[NUM_CLUSTERS]; // ,this
+} frame_t;
+
+// ,and all of this should get out of here, need to use new stuff in fmodels instead
+
+typedef struct IntListNode_s
+{
+       int data;
+       struct IntListNode_s *next;
+} IntListNode_t;  // gaak
+
+typedef struct
+{
+       float           scale[3];       // multiply byte verts by this
+       float           translate[3];   // then add this
+} PartialAliasFrame_t;
+
+int jointed;
+int clustered;
+
+int *clusters[NUM_CLUSTERS];
+IntListNode_t *vertLists[NUM_CLUSTERS];
+int            num_verts[NUM_CLUSTERS + 1];
+int            new_num_verts[NUM_CLUSTERS + 1];
+
+// end that
+
+//================================================================
+
+frame_t                g_frames[MAX_FRAMES];
+//frame_t              *g_frames;
+
+static dmdl_t          model;
+
+
+float          scale_up;                       // set by $scale
+vec3_t         adjust;                         // set by $origin
+int                    g_fixedwidth, g_fixedheight;    // set by $skinsize
+
+
+//
+// base frame info
+//
+dstvert_t      base_st[MAX_VERTS];
+dtriangle_t    triangles[MAX_TRIANGLES];
+
+static int                     triangle_st[MAX_TRIANGLES][3][2];
+
+// the command list holds counts, s/t values, and xyz indexes
+// that are valid for every frame
+int                    commands[16384];
+int                    numcommands;
+int                    numglverts;
+int                    used[MAX_TRIANGLES];
+
+char           g_skins[MAX_MD2SKINS][64];
+
+char           cdarchive[1024];
+char           cdpartial[1024];
+char           cddir[1024];
+
+char           modelname[64];  // empty unless $modelname issued (players)
+
+extern         char            *g_outputDir;
+
+#define NUMVERTEXNORMALS       162
+
+float  avertexnormals[NUMVERTEXNORMALS][3] = 
+{
+       #include "anorms.h"
+};
+
+unsigned char pic[SKINPAGE_HEIGHT*SKINPAGE_WIDTH], pic_palette[768];
+
+FILE   *headerouthandle = NULL;
+
+//==============================================================
+
+/*
+===============
+ClearModel
+===============
+*/
+static void ClearModel (void)
+{
+       memset (&model, 0, sizeof(model));
+
+       modelname[0] = 0;
+       jointed = NOT_JOINTED;
+       clustered = 0;
+       scale_up = 1.0; 
+       VectorCopy (vec3_origin, adjust);
+       g_fixedwidth = g_fixedheight = 0;
+       g_skipmodel = false;
+}
+
+
+void H_printf(char *fmt, ...)
+{
+       va_list argptr;
+       char    name[1024];
+
+       if (!headerouthandle)
+       {
+               sprintf (name, "%s/tris.h", cddir);
+               headerouthandle = SafeOpenWrite (name);
+               fprintf(headerouthandle, "// %s\n\n", cddir);
+               fprintf(headerouthandle, "// This file generated by qdata - Do NOT Modify\n\n");
+       }
+
+       va_start (argptr, fmt);
+       vfprintf (headerouthandle, fmt, argptr);
+       va_end (argptr);
+}
+
+#if 1
+/*
+============
+WriteModelFile
+============
+*/
+void WriteCommonModelFile (FILE *modelouthandle, PartialAliasFrame_t *outFrames)
+{
+       int                             i;
+       dmdl_t                  modeltemp;
+       int                             j, k;
+       frame_t                 *in;
+       daliasframe_t   *out;
+       byte                    buffer[MAX_VERTS*4+128];
+       float                   v;
+       int                             c_on, c_off;
+
+       model.version = ALIAS_VERSION;
+       model.framesize = (int)&((daliasframe_t *)0)->verts[model.num_xyz];
+       model.num_glcmds = numcommands;
+       model.ofs_skins = sizeof(dmdl_t);
+       model.ofs_st = model.ofs_skins + model.num_skins * MAX_SKINNAME;
+       model.ofs_tris = model.ofs_st + model.num_st*sizeof(dstvert_t);
+       model.ofs_frames = model.ofs_tris + model.num_tris*sizeof(dtriangle_t);
+       model.ofs_glcmds = model.ofs_frames + model.num_frames*model.framesize;
+       model.ofs_end = model.ofs_glcmds + model.num_glcmds*sizeof(int);
+       //
+       // write out the model header
+       //
+       for (i=0 ; i<sizeof(dmdl_t)/4 ; i++)
+               ((int *)&modeltemp)[i] = LittleLong (((int *)&model)[i]);
+
+       SafeWrite (modelouthandle, &modeltemp, sizeof(modeltemp));
+
+       //
+       // write out the skin names
+       //
+       SafeWrite (modelouthandle, g_skins, model.num_skins * MAX_SKINNAME);
+
+       //
+       // write out the texture coordinates
+       //
+       c_on = c_off = 0;
+       for (i=0 ; i<model.num_st ; i++)
+       {
+               base_st[i].s = LittleShort (base_st[i].s);
+               base_st[i].t = LittleShort (base_st[i].t);
+       }
+
+       SafeWrite (modelouthandle, base_st, model.num_st * sizeof(base_st[0]));
+
+       //
+       // write out the triangles
+       //
+       for (i=0 ; i<model.num_tris ; i++)
+       {
+               int                     j;
+               dtriangle_t     tri;
+
+               for (j=0 ; j<3 ; j++)
+               {
+                       tri.index_xyz[j] = LittleShort (triangles[i].index_xyz[j]);
+                       tri.index_st[j] = LittleShort (triangles[i].index_st[j]);
+               }
+
+               SafeWrite (modelouthandle, &tri, sizeof(tri));
+       }
+
+       //
+       // write out the frames
+       //
+       for (i=0 ; i<model.num_frames ; i++)
+       {
+               in = &g_frames[i];
+               out = (daliasframe_t *)buffer;
+
+               strcpy (out->name, in->name);
+               for (j=0 ; j<3 ; j++)
+               {
+                       out->scale[j] = (in->maxs[j] - in->mins[j])/255;
+                       out->translate[j] = in->mins[j];
+
+                       if(outFrames)
+                       {
+                               outFrames[i].scale[j] = out->scale[j];
+                               outFrames[i].translate[j] = out->translate[j];
+                       }
+               }
+
+               for (j=0 ; j<model.num_xyz ; j++)
+               {
+               // all of these are byte values, so no need to deal with endianness
+                       out->verts[j].lightnormalindex = in->v[j].lightnormalindex;
+
+                       for (k=0 ; k<3 ; k++)
+                       {
+                       // scale to byte values & min/max check
+                               v = Q_rint ( (in->v[j].v[k] - out->translate[k]) / out->scale[k] );
+
+                       // clamp, so rounding doesn't wrap from 255.6 to 0
+                               if (v > 255.0)
+                                       v = 255.0;
+                               if (v < 0)
+                                       v = 0;
+                               out->verts[j].v[k] = v;
+                       }
+               }
+
+               for (j=0 ; j<3 ; j++)
+               {
+                       out->scale[j] = LittleFloat (out->scale[j]);
+                       out->translate[j] = LittleFloat (out->translate[j]);
+               }
+
+               SafeWrite (modelouthandle, out, model.framesize);
+       }
+
+       //
+       // write out glcmds
+       //
+       SafeWrite (modelouthandle, commands, numcommands*4);
+}
+
+/*
+============
+WriteModelFile
+============
+*/
+void WriteModelFile (FILE *modelouthandle)
+{
+       model.ident = IDALIASHEADER;
+
+       WriteCommonModelFile(modelouthandle, NULL);
+}
+
+/*
+============
+WriteJointedModelFile
+============
+*/
+void WriteJointedModelFile (FILE *modelouthandle)
+{
+       int                             i;
+       int                             j, k;
+       frame_t                 *in;
+       float                   v;
+       IntListNode_t   *current, *toFree;
+       PartialAliasFrame_t outFrames[MAX_FRAMES];
+
+       model.ident = IDJOINTEDALIASHEADER;
+       
+       WriteCommonModelFile(modelouthandle, outFrames);
+
+       // Skeletal Type
+       SafeWrite(modelouthandle, &jointed, sizeof(int));
+
+       // number of joints
+       SafeWrite(modelouthandle, &numJointsForSkeleton[jointed], sizeof(int));
+
+       // number of verts in each cluster
+       SafeWrite(modelouthandle, &new_num_verts[1], sizeof(int)*numJointsForSkeleton[jointed]);
+
+       // cluster verts
+       for(i = 0; i < new_num_verts[0]; ++i)
+       {
+               current = vertLists[i];
+               while(current)
+               {
+                       SafeWrite (modelouthandle, &current->data, sizeof(int));
+                       toFree = current;
+                       current = current->next;
+                       free(toFree);  // freeing of memory allocated in ReplaceClusterIndex called in Cmd_Base
+               }
+       }
+
+       for (i=0 ; i<model.num_frames ; i++)
+       {
+               in = &g_frames[i];
+
+               for (j = 0 ; j < new_num_verts[0]; ++j)
+               {
+                       for (k=0 ; k<3 ; k++)
+                       {
+                               // scale to byte values & min/max check
+                               v = Q_rint ( (in->joints[j].placement.origin[k] - outFrames[i].translate[k]) / outFrames[i].scale[k] );
+
+                               // clamp, so rounding doesn't wrap from 255.6 to 0
+                               if (v > 255.0)
+                               {
+                                       v = 255.0;
+                               }
+
+                               if (v < 0)
+                               {
+                                       v = 0;
+                               }
+
+                               // write out origin as a float (there's only a few per model, so it's not really 
+                               // a size issue)
+                               SafeWrite (modelouthandle, &v, sizeof(float));
+                       }
+
+                       for (k=0 ; k<3 ; k++)
+                       {
+                               v = Q_rint ( (in->joints[j].placement.direction[k] - outFrames[i].translate[k]) / outFrames[i].scale[k] );
+
+                               // clamp, so rounding doesn't wrap from 255.6 to 0
+                               if (v > 255.0)
+                               {
+                                       v = 255.0;
+                               }
+
+                               if (v < 0)
+                               {
+                                       v = 0;
+                               }
+
+                               // write out origin as a float (there's only a few per model, so it's not really 
+                               // a size issue)
+                               SafeWrite (modelouthandle, &v, sizeof(float));
+                       }
+
+                       for (k=0 ; k<3 ; k++)
+                       {
+                               v = Q_rint ( (in->joints[j].placement.up[k] - outFrames[i].translate[k]) / outFrames[i].scale[k] );
+
+                               // clamp, so rounding doesn't wrap from 255.6 to 0
+                               if (v > 255.0)
+                               {
+                                       v = 255.0;
+                               }
+
+                               if (v < 0)
+                               {
+                                       v = 0;
+                               }
+
+                               // write out origin as a float (there's only a few per model, so it's not really 
+                               // a size issue)
+                               SafeWrite (modelouthandle, &v, sizeof(float));
+                       }
+               }
+       }
+}
+#else
+/*
+============
+WriteModelFile
+============
+*/
+static void WriteModelFile (FILE *modelouthandle)
+{
+       int                             i;
+       dmdl_t                  modeltemp;
+       int                             j, k;
+       frame_t                 *in;
+       daliasframe_t   *out;
+       byte                    buffer[MAX_VERTS*4+128];
+       float                   v;
+       int                             c_on, c_off;
+
+       model.ident = IDALIASHEADER;
+       model.version = ALIAS_VERSION;
+       model.framesize = (int)&((daliasframe_t *)0)->verts[model.num_xyz];
+       model.num_glcmds = numcommands;
+       model.ofs_skins = sizeof(dmdl_t);
+       model.ofs_st = model.ofs_skins + model.num_skins * MAX_SKINNAME;
+       model.ofs_tris = model.ofs_st + model.num_st*sizeof(dstvert_t);
+       model.ofs_frames = model.ofs_tris + model.num_tris*sizeof(dtriangle_t);
+       model.ofs_glcmds = model.ofs_frames + model.num_frames*model.framesize;
+       model.ofs_end = model.ofs_glcmds + model.num_glcmds*4;
+
+       //
+       // write out the model header
+       //
+       for (i=0 ; i<sizeof(dmdl_t)/4 ; i++)
+               ((int *)&modeltemp)[i] = LittleLong (((int *)&model)[i]);
+
+       SafeWrite (modelouthandle, &modeltemp, sizeof(modeltemp));
+
+       //
+       // write out the skin names
+       //
+       SafeWrite (modelouthandle, g_skins, model.num_skins * MAX_SKINNAME);
+
+       //
+       // write out the texture coordinates
+       //
+       c_on = c_off = 0;
+       for (i=0 ; i<model.num_st ; i++)
+       {
+               base_st[i].s = LittleShort (base_st[i].s);
+               base_st[i].t = LittleShort (base_st[i].t);
+       }
+
+       SafeWrite (modelouthandle, base_st, model.num_st * sizeof(base_st[0]));
+
+       //
+       // write out the triangles
+       //
+       for (i=0 ; i<model.num_tris ; i++)
+       {
+               int                     j;
+               dtriangle_t     tri;
+
+               for (j=0 ; j<3 ; j++)
+               {
+                       tri.index_xyz[j] = LittleShort (triangles[i].index_xyz[j]);
+                       tri.index_st[j] = LittleShort (triangles[i].index_st[j]);
+               }
+
+               SafeWrite (modelouthandle, &tri, sizeof(tri));
+       }
+
+       //
+       // write out the frames
+       //
+       for (i=0 ; i<model.num_frames ; i++)
+       {
+               in = &g_frames[i];
+               out = (daliasframe_t *)buffer;
+
+               strcpy (out->name, in->name);
+               for (j=0 ; j<3 ; j++)
+               {
+                       out->scale[j] = (in->maxs[j] - in->mins[j])/255;
+                       out->translate[j] = in->mins[j];
+               }
+
+               for (j=0 ; j<model.num_xyz ; j++)
+               {
+               // all of these are byte values, so no need to deal with endianness
+                       out->verts[j].lightnormalindex = in->v[j].lightnormalindex;
+
+                       for (k=0 ; k<3 ; k++)
+                       {
+                       // scale to byte values & min/max check
+                               v = Q_rint ( (in->v[j].v[k] - out->translate[k]) / out->scale[k] );
+
+                       // clamp, so rounding doesn't wrap from 255.6 to 0
+                               if (v > 255.0)
+                                       v = 255.0;
+                               if (v < 0)
+                                       v = 0;
+                               out->verts[j].v[k] = v;
+                       }
+               }
+
+               for (j=0 ; j<3 ; j++)
+               {
+                       out->scale[j] = LittleFloat (out->scale[j]);
+                       out->translate[j] = LittleFloat (out->translate[j]);
+               }
+
+               SafeWrite (modelouthandle, out, model.framesize);
+       }
+
+       //
+       // write out glcmds
+       //
+       SafeWrite (modelouthandle, commands, numcommands*4);
+}
+#endif
+
+/*
+===============
+FinishModel
+===============
+*/
+void FinishModel (void)
+{
+       FILE            *modelouthandle;
+       int                     i;
+       char            name[1024];
+       
+       if (!model.num_frames)
+               return;
+       
+//
+// copy to release directory tree if doing a release build
+//
+       if (g_release)
+       {
+               if (modelname[0])
+                       sprintf (name, "%s", modelname);
+               else
+                       sprintf (name, "%s/tris.md2", cdpartial);
+               ReleaseFile (name);
+
+               for (i=0 ; i<model.num_skins ; i++)
+               {
+                       ReleaseFile (g_skins[i]);
+               }
+               model.num_frames = 0;
+               return;
+       }
+       
+//
+// write the model output file
+//
+       if (modelname[0])
+               sprintf (name, "%s%s", g_outputDir, modelname);
+       else
+               sprintf (name, "%s/tris.md2", g_outputDir);
+       printf ("saving to %s\n", name);
+       CreatePath (name);
+       modelouthandle = SafeOpenWrite (name);
+
+#if 1
+       if(jointed != NOT_JOINTED)
+               WriteJointedModelFile(modelouthandle);
+       else
+#endif
+               WriteModelFile(modelouthandle);
+       
+       printf ("%3dx%3d skin\n", model.skinwidth, model.skinheight);
+       printf ("First frame boundaries:\n");
+       printf ("       minimum x: %3f\n", g_frames[0].mins[0]);
+       printf ("       maximum x: %3f\n", g_frames[0].maxs[0]);
+       printf ("       minimum y: %3f\n", g_frames[0].mins[1]);
+       printf ("       maximum y: %3f\n", g_frames[0].maxs[1]);
+       printf ("       minimum z: %3f\n", g_frames[0].mins[2]);
+       printf ("       maximum z: %3f\n", g_frames[0].maxs[2]);
+       printf ("%4d vertices\n", model.num_xyz);
+       printf ("%4d triangles\n", model.num_tris);
+       printf ("%4d frame\n", model.num_frames);
+       printf ("%4d glverts\n", numglverts);
+       printf ("%4d glcmd\n", model.num_glcmds);
+       printf ("%4d skins\n", model.num_skins);
+       printf ("file size: %d\n", (int)ftell (modelouthandle) );
+       printf ("---------------------\n");
+       
+       fclose (modelouthandle);
+
+       // finish writing header file
+       H_printf("\n");
+
+       // scale_up is usefull to allow step distances to be adjusted
+       H_printf("#define MODEL_SCALE\t\t%f\n", scale_up);
+
+       fclose (headerouthandle);
+       headerouthandle = NULL;
+}
+
+
+/*
+=================================================================
+
+ALIAS MODEL DISPLAY LIST GENERATION
+
+=================================================================
+*/
+
+int            strip_xyz[128];
+int            strip_st[128];
+int            strip_tris[128];
+int            stripcount;
+
+/*
+================
+StripLength
+================
+*/
+static int     StripLength (int starttri, int startv)
+{
+       int                     m1, m2;
+       int                     st1, st2;
+       int                     j;
+       dtriangle_t     *last, *check;
+       int                     k;
+
+       used[starttri] = 2;
+
+       last = &triangles[starttri];
+
+       strip_xyz[0] = last->index_xyz[(startv)%3];
+       strip_xyz[1] = last->index_xyz[(startv+1)%3];
+       strip_xyz[2] = last->index_xyz[(startv+2)%3];
+       strip_st[0] = last->index_st[(startv)%3];
+       strip_st[1] = last->index_st[(startv+1)%3];
+       strip_st[2] = last->index_st[(startv+2)%3];
+
+       strip_tris[0] = starttri;
+       stripcount = 1;
+
+       m1 = last->index_xyz[(startv+2)%3];
+       st1 = last->index_st[(startv+2)%3];
+       m2 = last->index_xyz[(startv+1)%3];
+       st2 = last->index_st[(startv+1)%3];
+
+       // look for a matching triangle
+nexttri:
+       for (j=starttri+1, check=&triangles[starttri+1]
+               ; j<model.num_tris ; j++, check++)
+       {
+               for (k=0 ; k<3 ; k++)
+               {
+                       if (check->index_xyz[k] != m1)
+                               continue;
+                       if (check->index_st[k] != st1)
+                               continue;
+                       if (check->index_xyz[ (k+1)%3 ] != m2)
+                               continue;
+                       if (check->index_st[ (k+1)%3 ] != st2)
+                               continue;
+
+                       // this is the next part of the fan
+
+                       // if we can't use this triangle, this tristrip is done
+                       if (used[j])
+                               goto done;
+
+                       // the new edge
+                       if (stripcount & 1)
+                       {
+                               m2 = check->index_xyz[ (k+2)%3 ];
+                               st2 = check->index_st[ (k+2)%3 ];
+                       }
+                       else
+                       {
+                               m1 = check->index_xyz[ (k+2)%3 ];
+                               st1 = check->index_st[ (k+2)%3 ];
+                       }
+
+                       strip_xyz[stripcount+2] = check->index_xyz[ (k+2)%3 ];
+                       strip_st[stripcount+2] = check->index_st[ (k+2)%3 ];
+                       strip_tris[stripcount] = j;
+                       stripcount++;
+
+                       used[j] = 2;
+                       goto nexttri;
+               }
+       }
+done:
+
+       // clear the temp used flags
+       for (j=starttri+1 ; j<model.num_tris ; j++)
+               if (used[j] == 2)
+                       used[j] = 0;
+
+       return stripcount;
+}
+
+
+/*
+===========
+FanLength
+===========
+*/
+static int     FanLength (int starttri, int startv)
+{
+       int             m1, m2;
+       int             st1, st2;
+       int             j;
+       dtriangle_t     *last, *check;
+       int             k;
+
+       used[starttri] = 2;
+
+       last = &triangles[starttri];
+
+       strip_xyz[0] = last->index_xyz[(startv)%3];
+       strip_xyz[1] = last->index_xyz[(startv+1)%3];
+       strip_xyz[2] = last->index_xyz[(startv+2)%3];
+       strip_st[0] = last->index_st[(startv)%3];
+       strip_st[1] = last->index_st[(startv+1)%3];
+       strip_st[2] = last->index_st[(startv+2)%3];
+
+       strip_tris[0] = starttri;
+       stripcount = 1;
+
+       m1 = last->index_xyz[(startv+0)%3];
+       st1 = last->index_st[(startv+0)%3];
+       m2 = last->index_xyz[(startv+2)%3];
+       st2 = last->index_st[(startv+2)%3];
+
+
+       // look for a matching triangle
+nexttri:
+       for (j=starttri+1, check=&triangles[starttri+1] 
+               ; j<model.num_tris ; j++, check++)
+       {
+               for (k=0 ; k<3 ; k++)
+               {
+                       if (check->index_xyz[k] != m1)
+                               continue;
+                       if (check->index_st[k] != st1)
+                               continue;
+                       if (check->index_xyz[ (k+1)%3 ] != m2)
+                               continue;
+                       if (check->index_st[ (k+1)%3 ] != st2)
+                               continue;
+
+                       // this is the next part of the fan
+
+                       // if we can't use this triangle, this tristrip is done
+                       if (used[j])
+                               goto done;
+
+                       // the new edge
+                       m2 = check->index_xyz[ (k+2)%3 ];
+                       st2 = check->index_st[ (k+2)%3 ];
+
+                       strip_xyz[stripcount+2] = m2;
+                       strip_st[stripcount+2] = st2;
+                       strip_tris[stripcount] = j;
+                       stripcount++;
+
+                       used[j] = 2;
+                       goto nexttri;
+               }
+       }
+done:
+
+       // clear the temp used flags
+       for (j=starttri+1 ; j<model.num_tris ; j++)
+               if (used[j] == 2)
+                       used[j] = 0;
+
+       return stripcount;
+}
+
+
+
+/*
+================
+BuildGlCmds
+
+Generate a list of trifans or strips
+for the model, which holds for all frames
+================
+*/
+static void BuildGlCmds (void)
+{
+       int             i, j, k;
+       int             startv;
+       float   s, t;
+       int             len, bestlen, besttype;
+       int             best_xyz[1024];
+       int             best_st[1024];
+       int             best_tris[1024];
+       int             type;
+
+       //
+       // build tristrips
+       //
+       numcommands = 0;
+       numglverts = 0;
+       memset (used, 0, sizeof(used));
+       for (i=0 ; i<model.num_tris ; i++)
+       {
+               // pick an unused triangle and start the trifan
+               if (used[i])
+                       continue;
+
+               bestlen = 0;
+               for (type = 0 ; type < 2 ; type++)
+//     type = 1;
+               {
+                       for (startv =0 ; startv < 3 ; startv++)
+                       {
+                               if (type == 1)
+                                       len = StripLength (i, startv);
+                               else
+                                       len = FanLength (i, startv);
+                               if (len > bestlen)
+                               {
+                                       besttype = type;
+                                       bestlen = len;
+                                       for (j=0 ; j<bestlen+2 ; j++)
+                                       {
+                                               best_st[j] = strip_st[j];
+                                               best_xyz[j] = strip_xyz[j];
+                                       }
+                                       for (j=0 ; j<bestlen ; j++)
+                                               best_tris[j] = strip_tris[j];
+                               }
+                       }
+               }
+
+               // mark the tris on the best strip/fan as used
+               for (j=0 ; j<bestlen ; j++)
+                       used[best_tris[j]] = 1;
+
+               if (besttype == 1)
+                       commands[numcommands++] = (bestlen+2);
+               else
+                       commands[numcommands++] = -(bestlen+2);
+
+               numglverts += bestlen+2;
+
+               for (j=0 ; j<bestlen+2 ; j++)
+               {
+                       // emit a vertex into the reorder buffer
+                       k = best_st[j];
+
+                       // emit s/t coords into the commands stream
+                       s = base_st[k].s;
+                       t = base_st[k].t;
+
+                       s = (s + 0.5) / model.skinwidth;
+                       t = (t + 0.5) / model.skinheight;
+
+                       *(float *)&commands[numcommands++] = s;
+                       *(float *)&commands[numcommands++] = t;
+                       *(int *)&commands[numcommands++] = best_xyz[j];
+               }
+       }
+
+       commands[numcommands++] = 0;            // end of list marker
+}
+
+
+/*
+===============================================================
+
+BASE FRAME SETUP
+
+===============================================================
+*/
+
+/*
+============
+BuildST
+
+Builds the triangle_st array for the base frame and
+model.skinwidth / model.skinheight
+
+  FIXME: allow this to be loaded from a file for
+  arbitrary mappings
+============
+*/
+#if 0
+static void OldBuildST (triangle_t *ptri, int numtri)
+{
+       int                     i, j;
+       int                     width, height, iwidth, iheight, swidth;
+       float           basex, basey;
+       float           s_scale, t_scale;
+       float           scale;
+       vec3_t          mins, maxs;
+       float           *pbasevert;
+       vec3_t          vtemp1, vtemp2, normal;
+
+       //
+       // find bounds of all the verts on the base frame
+       //
+       ClearBounds (mins, maxs);
+       
+       for (i=0 ; i<numtri ; i++)
+               for (j=0 ; j<3 ; j++)
+                       AddPointToBounds (ptri[i].verts[j], mins, maxs);
+       
+       for (i=0 ; i<3 ; i++)
+       {
+               mins[i] = floor(mins[i]);
+               maxs[i] = ceil(maxs[i]);
+       }
+       
+       width = maxs[0] - mins[0];
+       height = maxs[2] - mins[2];
+
+       if (!g_fixedwidth)
+       {       // old style
+               scale = 8;
+               if (width*scale >= 150)
+                       scale = 150.0 / width;  
+               if (height*scale >= 190)
+                       scale = 190.0 / height;
+
+               s_scale = t_scale = scale;
+
+               iwidth = ceil(width*s_scale);
+               iheight = ceil(height*t_scale);
+
+               iwidth += 4;
+               iheight += 4;
+       }
+       else
+       {       // new style
+               iwidth = g_fixedwidth / 2;
+               iheight = g_fixedheight;
+
+               s_scale = (float)(iwidth-4) / width;
+               t_scale = (float)(iheight-4) / height;
+       }
+
+//
+// determine which side of each triangle to map the texture to
+//
+       for (i=0 ; i<numtri ; i++)
+       {
+               VectorSubtract (ptri[i].verts[0], ptri[i].verts[1], vtemp1);
+               VectorSubtract (ptri[i].verts[2], ptri[i].verts[1], vtemp2);
+               CrossProduct (vtemp1, vtemp2, normal);
+
+               if (normal[1] > 0)
+               {
+                       basex = iwidth + 2;
+               }
+               else
+               {
+                       basex = 2;
+               }
+               basey = 2;
+               
+               for (j=0 ; j<3 ; j++)
+               {
+                       pbasevert = ptri[i].verts[j];
+
+                       triangle_st[i][j][0] = Q_rint((pbasevert[0] - mins[0]) * s_scale + basex);
+                       triangle_st[i][j][1] = Q_rint((maxs[2] - pbasevert[2]) * t_scale + basey);
+               }
+       }
+
+// make the width a multiple of 4; some hardware requires this, and it ensures
+// dword alignment for each scan
+       swidth = iwidth*2;
+       model.skinwidth = (swidth + 3) & ~3;
+       model.skinheight = iheight;
+}
+#endif
+
+//==========================================================================
+//
+// DrawScreen
+//
+//==========================================================================
+
+void DrawScreen(float s_scale, float t_scale, float iwidth, float iheight)
+{
+       int i;
+       byte *scrpos;
+       char buffer[256];
+
+       // Divider
+       scrpos = &pic[(INFO_Y-2)*SKINPAGE_WIDTH];
+       for(i = 0; i < SKINPAGE_WIDTH; i++)
+       {
+               *scrpos++ = 255;
+       }
+
+       sprintf(buffer, "GENSKIN:  ");
+       DrawTextChar(16, INFO_Y, buffer);
+       
+       sprintf(buffer, "( %03d * %03d )   SCALE %f %f, SKINWIDTH %d,"
+               " SKINHEIGHT %d", (int)ScaleWidth, (int)ScaleHeight, s_scale, t_scale, (int)iwidth*2, (int)iheight);
+       DrawTextChar(80, INFO_Y, buffer);
+}
+
+/*
+============
+BuildST
+
+Builds the triangle_st array for the base frame and
+model.skinwidth / model.skinheight
+
+  FIXME: allow this to be loaded from a file for
+  arbitrary mappings
+============
+*/
+void BuildST (triangle_t *ptri, int numtri, qboolean DrawSkin)
+{
+       int                     i, j;
+       int                     width, height, iwidth, iheight, swidth;
+       float           basex, basey;
+       float           scale;
+       vec3_t          mins, maxs;
+       float           *pbasevert;
+       vec3_t          vtemp1, vtemp2, normal;
+       float           s_scale, t_scale;
+       float           scWidth;
+       float           scHeight;
+
+       //
+       // find bounds of all the verts on the base frame
+       //
+       ClearBounds (mins, maxs);
+       
+       for (i=0 ; i<numtri ; i++)
+               for (j=0 ; j<3 ; j++)
+                       AddPointToBounds (ptri[i].verts[j], mins, maxs);
+       
+       for (i=0 ; i<3 ; i++)
+       {
+               mins[i] = floor(mins[i]);
+               maxs[i] = ceil(maxs[i]);
+       }
+       
+       width = maxs[0] - mins[0];
+       height = maxs[2] - mins[2];
+
+
+       scWidth = (ScaleWidth/2)*SCALE_ADJUST_FACTOR;
+       scHeight = ScaleHeight*SCALE_ADJUST_FACTOR;
+
+       scale = scWidth/width;
+
+       if(height*scale >= scHeight)
+       {
+               scale = scHeight/height;
+       }
+
+       iwidth = ceil(width*scale)+4;
+       iheight = ceil(height*scale)+4;
+
+       s_scale = (float)(iwidth-4) / width;
+       t_scale = (float)(iheight-4) / height;
+       t_scale = s_scale;
+
+       if (DrawSkin)
+               DrawScreen(s_scale, t_scale, iwidth, iheight);
+
+
+/*     if (!g_fixedwidth)
+       {       // old style
+               scale = 8;
+               if (width*scale >= 150)
+                       scale = 150.0 / width;  
+               if (height*scale >= 190)
+                       scale = 190.0 / height;
+
+               s_scale = t_scale = scale;
+
+               iwidth = ceil(width*s_scale);
+               iheight = ceil(height*t_scale);
+
+               iwidth += 4;
+               iheight += 4;
+       }
+       else
+       {       // new style
+               iwidth = g_fixedwidth / 2;
+               iheight = g_fixedheight;
+
+               s_scale = (float)(iwidth-4) / width;
+               t_scale = (float)(iheight-4) / height;
+       }*/
+
+//
+// determine which side of each triangle to map the texture to
+//
+       for (i=0 ; i<numtri ; i++)
+       {
+               if (ptri[i].HasUV)
+               {
+                       for (j=0 ; j<3 ; j++)
+                       {
+                               triangle_st[i][j][0] = Q_rint(ptri[i].uv[j][0]*iwidth);
+                               triangle_st[i][j][1] = Q_rint((1.0f-ptri[i].uv[j][1])*iheight);
+                       }
+               }
+               else
+               {
+                       VectorSubtract (ptri[i].verts[0], ptri[i].verts[1], vtemp1);
+                       VectorSubtract (ptri[i].verts[2], ptri[i].verts[1], vtemp2);
+                       CrossProduct (vtemp1, vtemp2, normal);
+
+                       if (normal[1] > 0)
+                       {
+                               basex = iwidth + 2;
+                       }
+                       else
+                       {
+                               basex = 2;
+                       }
+                       basey = 2;
+                       
+                       for (j=0 ; j<3 ; j++)
+                       {
+                               pbasevert = ptri[i].verts[j];
+
+                               triangle_st[i][j][0] = Q_rint((pbasevert[0] - mins[0]) * s_scale + basex);
+                               triangle_st[i][j][1] = Q_rint((maxs[2] - pbasevert[2]) * t_scale + basey);
+                       }
+               }
+
+               DrawLine(triangle_st[i][0][0], triangle_st[i][0][1],
+                       triangle_st[i][1][0], triangle_st[i][1][1]);
+               DrawLine(triangle_st[i][1][0], triangle_st[i][1][1],
+                       triangle_st[i][2][0], triangle_st[i][2][1]);
+               DrawLine(triangle_st[i][2][0], triangle_st[i][2][1],
+                       triangle_st[i][0][0], triangle_st[i][0][1]); 
+       }
+
+// make the width a multiple of 4; some hardware requires this, and it ensures
+// dword alignment for each scan
+
+       swidth = iwidth*2;
+       model.skinwidth = (swidth + 3) & ~3;
+       model.skinheight = iheight;
+}
+
+
+static void ReplaceClusterIndex(int newIndex, int oldindex, int **clusters, 
+       IntListNode_t **vertLists, int *num_verts, int *new_num_verts)
+{
+       int i, j;
+       IntListNode_t *next;
+
+       for(j = 0; j < num_verts[0]; ++j)
+       {
+               for(i = 0; i < num_verts[j+1]; ++i)
+               {
+                       if(clusters[j][i] == oldindex)
+                       {
+                               ++new_num_verts[j+1];
+
+                               next = vertLists[j];
+
+                               vertLists[j] = (IntListNode_t *) SafeMalloc(sizeof(IntListNode_t), "ReplaceClusterIndex");
+                               // Currently freed in WriteJointedModelFile only
+
+                               vertLists[j]->data = newIndex;
+                               vertLists[j]->next = next;
+                       }
+               }
+       }
+}
+
+/*
+=================
+Cmd_Base
+=================
+*/
+void Cmd_Base (void)
+{
+       vec3_t          base_xyz[MAX_VERTS];
+       triangle_t      *ptri;
+       int                     i, j, k;
+#if 1
+#else
+       int             time1;
+#endif
+       char    file1[1024];
+       char    file2[1024];
+
+       GetScriptToken (false);
+
+       if (g_skipmodel || g_release || g_archive)
+               return;
+
+       printf ("---------------------\n");
+#if 1
+       sprintf (file1, "%s/%s", cdpartial, token);
+       printf ("%s  ", file1);
+
+       ExpandPathAndArchive (file1);
+
+       sprintf (file1, "%s/%s", cddir, token);
+#else
+       sprintf (file1, "%s/%s.%s", cdarchive, token, trifileext);
+       printf ("%s\n", file1);
+
+       ExpandPathAndArchive (file1);
+
+       sprintf (file1, "%s/%s.%s", cddir, token, trifileext);
+
+       time1 = FileTime (file1);
+       if (time1 == -1)
+               Error ("%s doesn't exist", file1);
+#endif
+//
+// load the base triangles
+//
+       if (do3ds)
+               Load3DSTriangleList (file1, &ptri, &model.num_tris, NULL, NULL);
+       else
+               LoadTriangleList (file1, &ptri, &model.num_tris, NULL, NULL);
+
+
+       GetScriptToken (false);
+       sprintf (file2, "%s/%s.pcx", cddir, token);
+//     sprintf (trans_file, "%s/!%s_a.pcx", cddir, token);
+
+       printf ("skin: %s\n", file2);
+       Load256Image (file2, &BasePixels, &BasePalette, &BaseWidth, &BaseHeight);
+
+       if (BaseWidth != SKINPAGE_WIDTH || BaseHeight != SKINPAGE_HEIGHT)
+       {
+               if (g_allow_newskin)
+               {
+                       ScaleWidth = BaseWidth;
+                       ScaleHeight = BaseHeight;
+               }
+               else
+               {
+                       Error("Invalid skin page size: (%d,%d) should be (%d,%d)",
+                               BaseWidth,BaseHeight,SKINPAGE_WIDTH,SKINPAGE_HEIGHT);
+               }
+       }
+       else
+       {
+               ScaleWidth = (float)ExtractNumber(BasePixels, ENCODED_WIDTH_X,
+                       ENCODED_WIDTH_Y);
+               ScaleHeight = (float)ExtractNumber(BasePixels, ENCODED_HEIGHT_X,
+                       ENCODED_HEIGHT_Y);
+       }
+
+//
+// get the ST values
+//
+       BuildST (ptri, model.num_tris,false);
+
+//
+// run through all the base triangles, storing each unique vertex in the
+// base vertex list and setting the indirect triangles to point to the base
+// vertices
+//
+       for (i=0 ; i<model.num_tris ; i++)
+       {
+               for (j=0 ; j<3 ; j++)
+               {
+                       // get the xyz index
+                       for (k=0 ; k<model.num_xyz ; k++)
+                               if (VectorCompare (ptri[i].verts[j], base_xyz[k]))
+                                       break;  // this vertex is already in the base vertex list
+
+                       if (k == model.num_xyz)
+                       { // new index
+                               VectorCopy (ptri[i].verts[j], base_xyz[model.num_xyz]);
+
+                               if(clustered)
+                                       ReplaceClusterIndex(k, ptri[i].indicies[j], (int **)&clusters, (IntListNode_t **)&vertLists, (int *)&num_verts, (int *)&new_num_verts);
+
+                               model.num_xyz++;
+                       }
+
+                       triangles[i].index_xyz[j] = k;
+
+                       // get the st index
+                       for (k=0 ; k<model.num_st ; k++)
+                               if (triangle_st[i][j][0] == base_st[k].s
+                               && triangle_st[i][j][1] == base_st[k].t)
+                                       break;  // this vertex is already in the base vertex list
+
+                       if (k == model.num_st)
+                       { // new index
+                               base_st[model.num_st].s = triangle_st[i][j][0];
+                               base_st[model.num_st].t = triangle_st[i][j][1];
+                               model.num_st++;
+                       }
+
+                       triangles[i].index_st[j] = k;
+               }
+       }
+
+       // build triangle strips / fans
+       BuildGlCmds ();
+}
+
+//===============================================================
+
+char   *FindFrameFile (char *frame)
+{
+       int                             time1;
+       char                    file1[1024];
+       static char             retname[1024];
+       char                    base[32];
+       char                    suffix[32];
+       char                    *s;
+
+       if (strstr (frame, "."))
+               return frame;           // allready in dot format
+
+       // split 'run1' into 'run' and '1'
+       s = frame + strlen(frame)-1;
+
+       while (s != frame && *s >= '0' && *s <= '9')
+               s--;
+
+       strcpy (suffix, s+1);
+       strcpy (base, frame);
+       base[s-frame+1] = 0;
+
+       sprintf (file1, "%s/%s%s.%s",cddir, base, suffix, "hrc");
+       time1 = FileTime (file1);
+       if (time1 != -1)
+       {
+               sprintf (retname, "%s%s.%s", base, suffix, "hrc");
+               return retname;
+       }
+
+       sprintf (file1, "%s/%s%s.%s",cddir, base, suffix, "asc");
+       time1 = FileTime (file1);
+       if (time1 != -1)
+       {
+               sprintf (retname, "%s%s.%s", base, suffix, "asc");
+               return retname;
+       }
+
+       sprintf (file1, "%s/%s%s.%s",cddir, base, suffix, "tri");
+       time1 = FileTime (file1);
+       if (time1 != -1)
+       {
+               sprintf (retname, "%s%s.%s", base, suffix, "tri");
+               return retname;
+       }
+
+       sprintf (file1, "%s/%s%s.%s",cddir, base, suffix, "3ds");
+       time1 = FileTime (file1);
+       if (time1 != -1)
+       {
+               sprintf (retname, "%s%s.%s", base, suffix, "3ds");
+               return retname;
+       }
+
+       sprintf (file1, "%s/%s%s.%s",cddir, base, suffix, "htr");
+       time1 = FileTime (file1);
+       if (time1 != -1)
+       {
+               sprintf (retname, "%s%s.%s", base, suffix, "htr");
+               return retname;
+       }
+
+       // check for 'run.1'
+       sprintf (file1, "%s/%s.%s",cddir, base, suffix);
+       time1 = FileTime (file1);
+       if (time1 != -1)
+       {
+               sprintf (retname, "%s.%s", base, suffix);
+               return retname;
+       }
+
+       Error ("frame %s could not be found",frame);
+       return NULL;
+}
+
+/*
+===============
+GrabFrame
+===============
+*/
+static void GrabFrame (char *frame)
+{
+       triangle_t              *ptri;
+       int                             i, j;
+       trivert_t               *ptrivert;
+       int                             num_tris;
+       char                    file1[1024];
+       frame_t                 *fr;
+       vertexnormals_t vnorms[MAX_VERTS];
+       int                             index_xyz;
+       char                    *framefile;
+
+       // the frame 'run1' will be looked for as either
+       // run.1 or run1.tri, so the new alias sequence save
+       // feature an be used
+       framefile = FindFrameFile (frame);
+
+       sprintf (file1, "%s/%s", cdarchive, framefile);
+       ExpandPathAndArchive (file1);
+
+       sprintf (file1, "%s/%s",cddir, framefile);
+
+       printf ("grabbing %s  ", file1);
+
+       if (model.num_frames >= MAX_FRAMES)
+               Error ("model.num_frames >= MAX_FRAMES");
+       fr = &g_frames[model.num_frames];
+       model.num_frames++;
+
+       strcpy (fr->name, frame);
+
+//
+// load the frame
+//
+       if (do3ds)
+               Load3DSTriangleList (file1, &ptri, &num_tris, NULL, NULL);
+       else
+               LoadTriangleList (file1, &ptri, &num_tris, NULL, NULL);
+
+       if (num_tris != model.num_tris)
+               Error ("%s: number of triangles doesn't match base frame\n", file1);
+
+//
+// allocate storage for the frame's vertices
+//
+       ptrivert = fr->v;
+
+       for (i=0 ; i<model.num_xyz ; i++)
+       {
+               vnorms[i].numnormals = 0;
+               VectorClear (vnorms[i].normalsum);
+       }
+       ClearBounds (fr->mins, fr->maxs);
+
+//
+// store the frame's vertices in the same order as the base. This assumes the
+// triangles and vertices in this frame are in exactly the same order as in the
+// base
+//
+       for (i=0 ; i<num_tris ; i++)
+       {
+               vec3_t  vtemp1, vtemp2, normal;
+               float   ftemp;
+
+               VectorSubtract (ptri[i].verts[0], ptri[i].verts[1], vtemp1);
+               VectorSubtract (ptri[i].verts[2], ptri[i].verts[1], vtemp2);
+               CrossProduct (vtemp1, vtemp2, normal);
+
+               VectorNormalize (normal, normal);
+
+       // rotate the normal so the model faces down the positive x axis
+               ftemp = normal[0];
+               normal[0] = -normal[1];
+               normal[1] = ftemp;
+
+               for (j=0 ; j<3 ; j++)
+               {
+                       index_xyz = triangles[i].index_xyz[j];
+
+               // rotate the vertices so the model faces down the positive x axis
+               // also adjust the vertices to the desired origin
+                       ptrivert[index_xyz].v[0] = ((-ptri[i].verts[j][1]) * scale_up) +
+                                                                               adjust[0];
+                       ptrivert[index_xyz].v[1] = (ptri[i].verts[j][0] * scale_up) +
+                                                                               adjust[1];
+                       ptrivert[index_xyz].v[2] = (ptri[i].verts[j][2] * scale_up) +
+                                                                               adjust[2];
+
+                       AddPointToBounds (ptrivert[index_xyz].v, fr->mins, fr->maxs);
+
+                       VectorAdd (vnorms[index_xyz].normalsum, normal, vnorms[index_xyz].normalsum);
+                       vnorms[index_xyz].numnormals++;
+               }
+       }
+
+//
+// calculate the vertex normals, match them to the template list, and store the
+// index of the best match
+//
+       for (i=0 ; i<model.num_xyz ; i++)
+       {
+               int             j;
+               vec3_t  v;
+               float   maxdot;
+               int             maxdotindex;
+               int             c;
+
+               c = vnorms[i].numnormals;
+               if (!c)
+                       Error ("Vertex with no triangles attached");
+
+               VectorScale (vnorms[i].normalsum, 1.0/c, v);
+               VectorNormalize (v, v);
+
+               maxdot = -999999.0;
+               maxdotindex = -1;
+
+               for (j=0 ; j<NUMVERTEXNORMALS ; j++)
+               {
+                       float   dot;
+
+                       dot = DotProduct (v, avertexnormals[j]);
+                       if (dot > maxdot)
+                       {
+                               maxdot = dot;
+                               maxdotindex = j;
+                       }
+               }
+
+               ptrivert[i].lightnormalindex = maxdotindex;
+       }
+
+       free (ptri);
+}
+
+/*
+===============
+GrabJointedFrame
+===============
+*/
+void GrabJointedFrame(char *frame)
+{
+       char    file1[1024];
+       char    *framefile;
+       frame_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[model.num_frames - 1]; // last frame read in
+
+       LoadJointList(file1, fr->joints, jointed);
+}
+
+/*
+===============
+GrabGlobals
+===============
+*/
+void GrabGlobals(char *frame)
+{
+       char    file1[1024];
+       char    *framefile;
+       frame_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[model.num_frames - 1]; // last frame read in
+
+       LoadGlobals(file1);
+}
+
+/*
+===============
+Cmd_Frame      
+===============
+*/
+void Cmd_Frame (void)
+{
+       while (ScriptTokenAvailable())
+       {
+               GetScriptToken (false);
+               if (g_skipmodel)
+                       continue;
+               if (g_release || g_archive)
+               {
+                       model.num_frames = 1;   // don't skip the writeout
+                       continue;
+               }
+
+               H_printf("#define FRAME_%-16s\t%i\n", token, model.num_frames);
+
+               GrabFrame (token);
+       }
+}
+
+/*
+===============
+Cmd_Skin
+
+Skins aren't actually stored in the file, only a reference
+is saved out to the header file.
+===============
+*/
+void Cmd_Skin (void)
+{
+       byte    *palette;
+       byte    *pixels;
+       int             width, height;
+       byte    *cropped;
+       int             y;
+       char    name[1024], savename[1024];
+
+       GetScriptToken (false);
+
+       if (model.num_skins == MAX_MD2SKINS)
+               Error ("model.num_skins == MAX_MD2SKINS");
+
+       if (g_skipmodel)
+               return;
+
+#if 1
+       sprintf (name, "%s/%s.pcx", cddir, token);
+       sprintf (savename, "%s/!%s.pcx", g_outputDir, token);
+       sprintf (g_skins[model.num_skins], "%s/!%s.pcx", cdpartial, token);
+#else
+       sprintf (name, "%s/%s.lbm", cdarchive, token);
+       strcpy (name, ExpandPathAndArchive( name ) );
+//     sprintf (name, "%s/%s.lbm", cddir, token);
+
+       if (ScriptTokenAvailable())
+       {
+               GetScriptToken (false);
+               sprintf (g_skins[model.num_skins], "%s.pcx", token);
+               sprintf (savename, "%s%s.pcx", g_outputDir, g_skins[model.num_skins]);
+       }
+       else
+       {
+               sprintf (savename, "%s/%s.pcx", g_outputDir, token);
+               sprintf (g_skins[model.num_skins], "%s/%s.pcx", cdpartial, token);
+       }
+#endif
+
+       model.num_skins++;
+
+       if (g_skipmodel || g_release || g_archive)
+               return;
+
+       // load the image
+       printf ("loading %s\n", name);
+       Load256Image (name, &pixels, &palette, &width, &height);
+//     RemapZero (pixels, palette, width, height);
+
+       // crop it to the proper size
+       cropped = (byte *) SafeMalloc (model.skinwidth*model.skinheight, "Cmd_Skin");
+       for (y=0 ; y<model.skinheight ; y++)
+       {
+               memcpy (cropped+y*model.skinwidth,
+                       pixels+y*width, model.skinwidth);
+       }
+
+       // save off the new image
+       printf ("saving %s\n", savename);
+       CreatePath (savename);
+       WritePCXfile (savename, cropped, model.skinwidth,
+               model.skinheight, palette);
+
+       free (pixels);
+       free (palette);
+       free (cropped);
+}
+
+
+/*
+=================
+Cmd_Origin
+=================
+*/
+void Cmd_Origin (void)
+{
+       // rotate points into frame of reference so model points down the
+       // positive x axis
+       GetScriptToken (false);
+       adjust[1] = -atof (token);
+
+       GetScriptToken (false);
+       adjust[0] = atof (token);
+
+       GetScriptToken (false);
+       adjust[2] = -atof (token);
+}
+
+
+/*
+=================
+Cmd_ScaleUp
+=================
+*/
+void Cmd_ScaleUp (void)
+{
+       GetScriptToken (false);
+       scale_up = atof (token);
+       if (g_skipmodel || g_release || g_archive)
+               return;
+
+       printf ("Scale up: %f\n", scale_up);
+}
+
+
+/*
+=================
+Cmd_Skinsize
+
+Set a skin size other than the default
+=================
+*/
+void Cmd_Skinsize (void)
+{
+       GetScriptToken (false);
+       g_fixedwidth = atoi(token);
+       GetScriptToken (false);
+       g_fixedheight = atoi(token);
+}
+
+/*
+=================
+Cmd_Modelname
+
+Gives a different name/location for the file, instead of the cddir
+=================
+*/
+void Cmd_Modelname (void)
+{
+       GetScriptToken (false);
+       strcpy (modelname, token);
+}
+
+/*
+===============
+Cmd_Cd
+===============
+*/
+void Cmd_Cd (void)
+{
+       char temp[256];
+
+       FinishModel ();
+       ClearModel ();
+
+       GetScriptToken (false);
+
+       // this is a silly mess...
+       sprintf (cdpartial, "models/%s", token); 
+       sprintf (cdarchive, "%smodels/%s", gamedir+strlen(qdir), token); 
+       sprintf (cddir, "%s%s", gamedir, cdpartial);
+
+       // Since we also changed directories on the output side (for mirror) make sure the outputdir is set properly too.
+       sprintf(temp, "%s%s", g_outputDir, cdpartial);
+       strcpy(g_outputDir, temp);
+
+       // if -only was specified and this cd doesn't match,
+       // skip the model (you only need to match leading chars,
+       // so you could regrab all monsters with -only monsters)
+       if (!g_only[0])
+               return;
+       if (strncmp(token, g_only, strlen(g_only)))
+       {
+               g_skipmodel = true;
+               printf ("skipping %s\n", cdpartial);
+       }
+}
+
+/*
+=================
+Cmd_Cluster
+=================
+*/
+void Cmd_Cluster()
+{
+       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);
+
+       LoadClusters(file1, (int **)&clusters, (int *)&num_verts, jointed);
+
+       new_num_verts[0] = num_verts[0];
+
+       clustered = 1;
+}
+
+// Model construction cover functions.
+void MODELCMD_Modelname (int modeltype)
+{
+       if (g_forcemodel)
+               modeltype = g_forcemodel;
+
+       Cmd_Modelname ();
+/*
+       switch(modeltype)
+       {
+       case MODEL_MD2:
+               Cmd_Modelname ();               
+               break;
+       case MODEL_FM:
+               Cmd_FMModelname ();
+               break;
+       }
+*/
+}
+
+void MODELCMD_Cd (int modeltype)
+{
+       if (g_forcemodel)
+               modeltype = g_forcemodel;
+
+       switch(modeltype)
+       {
+       case MODEL_MD2:
+               Cmd_Cd ();
+               break;
+       case MODEL_FM:
+               Cmd_FMCd ();
+               break;
+       }
+}
+
+void MODELCMD_Origin (int modeltype)
+{
+       if (g_forcemodel)
+               modeltype = g_forcemodel;
+
+       Cmd_Origin ();
+/*     switch(modeltype)
+       {
+       case MODEL_MD2:
+               Cmd_Origin ();
+               break;
+       case MODEL_FM:
+               Cmd_FMOrigin ();
+               break;
+       }
+*/
+}
+
+void MODELCMD_Cluster (int modeltype)
+{
+       if (g_forcemodel)
+               modeltype = g_forcemodel;
+
+       switch(modeltype)
+       {
+       case MODEL_MD2:
+               Cmd_Cluster ();
+               break;
+       case MODEL_FM:
+               Cmd_FMCluster ();
+               break;
+       }
+}
+
+void MODELCMD_Base (int modeltype)
+{
+       if (g_forcemodel)
+               modeltype = g_forcemodel;
+
+       switch(modeltype)
+       {
+       case MODEL_MD2:
+               Cmd_Base ();
+               break;
+       case MODEL_FM:
+               Cmd_FMBase (false);
+               break;
+       }
+}
+
+void MODELCMD_BaseST (int modeltype)
+{
+       if (g_forcemodel)
+               modeltype = g_forcemodel;
+
+       switch(modeltype)
+       {
+       case MODEL_MD2:
+               Cmd_Base ();
+               break;
+       case MODEL_FM:
+               Cmd_FMBase (true);
+               break;
+       }
+}
+
+void MODELCMD_ScaleUp (int modeltype)
+{
+       if (g_forcemodel)
+               modeltype = g_forcemodel;
+
+       Cmd_ScaleUp ();
+/*     switch(modeltype)
+       {
+       case MODEL_MD2:
+               Cmd_ScaleUp ();
+               break;
+       case MODEL_FM:
+               Cmd_FMScaleUp ();
+               break;
+       }
+*/
+}
+
+void MODELCMD_Frame (int modeltype)
+{
+       if (g_forcemodel)
+               modeltype = g_forcemodel;
+
+       switch(modeltype)
+       {
+       case MODEL_MD2:
+               Cmd_Frame ();
+               break;
+       case MODEL_FM:
+               Cmd_FMFrame ();
+               break;
+       }
+}
+
+void MODELCMD_Skin (int modeltype)
+{
+       if (g_forcemodel)
+               modeltype = g_forcemodel;
+
+       switch(modeltype)
+       {
+       case MODEL_MD2:
+               Cmd_Skin ();
+               break;
+       case MODEL_FM:
+               Cmd_FMSkin ();
+               break;
+       }
+}
+
+void MODELCMD_Skinsize (int modeltype)
+{
+       if (g_forcemodel)
+               modeltype = g_forcemodel;
+
+       Cmd_Skinsize ();
+/*
+       switch(modeltype)
+       {
+       case MODEL_MD2:
+               Cmd_Skinsize ();
+               break;
+       case MODEL_FM:
+               Cmd_FMSkinsize ();
+               break;
+       }
+*/
+}
+
+void MODELCMD_Skeleton (int modeltype)
+{
+       if (g_forcemodel)
+               modeltype = g_forcemodel;
+
+       switch(modeltype)
+       {
+       case MODEL_MD2:
+               break;
+       case MODEL_FM:
+               Cmd_FMSkeleton ();
+               break;
+       }
+}
+
+void MODELCMD_BeginGroup(int modeltype)
+{
+       if (g_forcemodel)
+               modeltype = g_forcemodel;
+
+       switch(modeltype)
+       {
+       case MODEL_MD2:
+               break;
+       case MODEL_FM:
+               Cmd_FMBeginGroup();
+               break;
+       }
+}
+
+void MODELCMD_EndGroup(int modeltype)
+{
+       if (g_forcemodel)
+               modeltype = g_forcemodel;
+
+       switch(modeltype)
+       {
+       case MODEL_MD2:
+               break;
+       case MODEL_FM:
+               Cmd_FMEndGroup();
+               break;
+       }
+}
+
+void MODELCMD_Referenced(int modeltype)
+{
+       if (g_forcemodel)
+               modeltype = g_forcemodel;
+
+       switch(modeltype)
+       {
+       case MODEL_MD2:
+               break;
+       case MODEL_FM:
+               Cmd_FMReferenced();
+               break;
+       }
+}
+
+void MODELCMD_NodeOrder(int modeltype)
+{
+       if (g_forcemodel)
+               modeltype = g_forcemodel;
+
+       switch(modeltype)
+       {
+       case MODEL_MD2:
+               break;
+       case MODEL_FM:
+               Cmd_FMNodeOrder();
+               break;
+       }
+}