home *** CD-ROM | disk | FTP | other *** search
/ PC World Komputer 1996 December / PCWKCD1296.iso / sharewar / quake106 / utils / modelgen / modelgen.c < prev    next >
C/C++ Source or Header  |  1996-09-12  |  23KB  |  1,213 lines

  1. //
  2. // modelgen.c: generates a .mdl file from a base triangle file (.tri), a
  3. // texture containing front and back skins (.lbm), and a series of frame
  4. // triangle files (.tri). Result is stored in
  5. // /raid/quake/models/<scriptname>.mdl.
  6. //
  7.  
  8. #define INCLUDELIBS
  9.  
  10. #include <sys/stat.h>
  11.  
  12. #include "modelgen.h"
  13.  
  14. #define MAXVERTS        2048
  15. #define MAXFRAMES        256
  16. #define MAXSKINS        100
  17.  
  18.  
  19. typedef struct {
  20.     aliasframetype_t    type;        // single frame or group of frames
  21.     void                *pdata;        // either a daliasframe_t or group info
  22.     float                interval;    // only used for frames in groups
  23.     int                    numgroupframes;    // only used by group headers
  24.     char                name[16];
  25. } aliaspackage_t;
  26.  
  27. typedef struct {
  28.     aliasskintype_t        type;        // single skin or group of skiins
  29.     void                *pdata;        // either a daliasskinframe_t or group info
  30.     float                interval;    // only used for skins in groups
  31.     int                    numgroupskins;    // only used by group headers
  32. } aliasskinpackage_t;
  33.  
  34. typedef struct {
  35.     int        numnormals;
  36.     float    normals[20][3];
  37. } vertexnormals;
  38.  
  39.  
  40. typedef struct {
  41.     vec3_t        v;
  42.     int            lightnormalindex;
  43. } trivert_t;
  44.  
  45. //============================================================================
  46.  
  47. trivert_t    verts[MAXFRAMES][MAXVERTS];
  48. mdl_t    model;
  49.  
  50. char    file1[1024];
  51. char    skinname[1024];
  52. char    qbasename[1024];
  53. float    scale, scale_up = 1.0;
  54. vec3_t    mins, maxs;
  55. vec3_t    framesmins, framesmaxs;
  56. vec3_t        adjust;
  57.  
  58. aliaspackage_t    frames[MAXFRAMES];
  59.  
  60. aliasskinpackage_t    skins[MAXSKINS];
  61.  
  62. //
  63. // base frame info
  64. //
  65. vec3_t        baseverts[MAXVERTS];
  66. stvert_t    stverts[MAXVERTS];
  67. dtriangle_t    triangles[MAXTRIANGLES];
  68. int            degenerate[MAXTRIANGLES];
  69.  
  70.  
  71. char        cdpartial[256];
  72. char        cddir[256];
  73.  
  74. int            framecount, skincount;
  75. qboolean        cdset;
  76. int            degeneratetris;
  77. int            firstframe = 1;
  78. float        totsize, averagesize;
  79.  
  80. vertexnormals    vnorms[MAXVERTS];
  81.  
  82. #define NUMVERTEXNORMALS    162
  83.  
  84. float    avertexnormals[NUMVERTEXNORMALS][3] = {
  85. #include "anorms.h"
  86. };
  87.  
  88. trivertx_t    tarray[MAXVERTS];
  89.  
  90. char    outname[1024];
  91.  
  92.  
  93. void ClearModel (void)
  94. {
  95.     memset (&model, 0, sizeof(model));
  96.     model.synctype = ST_RAND;    // default
  97.     framecount = skincount = 0;
  98.  
  99.     scale = 0;
  100.     scale_up = 1.0;
  101.     
  102.     VectorCopy (vec3_origin, adjust);
  103.     VectorCopy (vec3_origin, mins);
  104.     VectorCopy (vec3_origin, maxs);
  105.     VectorCopy (vec3_origin, framesmins);
  106.     VectorCopy (vec3_origin, framesmaxs);
  107.  
  108.     degeneratetris = 0;
  109.     cdset = false;
  110.     firstframe = 1;
  111.     totsize = 0.0;
  112. }
  113.  
  114.  
  115. /*
  116. ============
  117. WriteFrame
  118. ============
  119. */
  120. void WriteFrame (FILE *modelouthandle, int framenum)
  121. {
  122.     int                j, k;
  123.     trivert_t        *pframe;
  124.     daliasframe_t    aframe;
  125.     float            v;
  126.  
  127.     pframe = verts[framenum];
  128.  
  129.     strcpy (aframe.name, frames[framenum].name);
  130.  
  131.     for (j=0 ; j<3 ; j++)
  132.     {
  133.         aframe.bboxmin.v[j] = 255;
  134.         aframe.bboxmax.v[j] = 0;
  135.     }
  136.  
  137.     for (j=0 ; j<model.numverts ; j++)
  138.     {
  139.     // all of these are byte values, so no need to deal with endianness
  140.         tarray[j].lightnormalindex = pframe[j].lightnormalindex;
  141.  
  142.         if (tarray[j].lightnormalindex > NUMVERTEXNORMALS)
  143.             Error ("invalid lightnormalindex %d\n",
  144.                     tarray[j].lightnormalindex);
  145.  
  146.         for (k=0 ; k<3 ; k++)
  147.         {
  148.         // scale to byte values & min/max check
  149.             v = (pframe[j].v[k] - model.scale_origin[k]) / model.scale[k];
  150.  
  151.             tarray[j].v[k] = v;
  152.  
  153.             if (tarray[j].v[k] < aframe.bboxmin.v[k])
  154.             {
  155.                 aframe.bboxmin.v[k] = tarray[j].v[k];
  156.             }
  157.             if (tarray[j].v[k] > aframe.bboxmax.v[k])
  158.             {
  159.                 aframe.bboxmax.v[k] = tarray[j].v[k];
  160.             }
  161.             
  162.             
  163.         }
  164.     }
  165.  
  166.     SafeWrite (modelouthandle, &aframe, sizeof (aframe));
  167.  
  168.     SafeWrite (modelouthandle, &tarray[0],
  169.                model.numverts * sizeof(tarray[0]));
  170. }
  171.  
  172.  
  173. /*
  174. ============
  175. WriteGroupBBox
  176. ============
  177. */
  178. void WriteGroupBBox (FILE *modelouthandle, int numframes, int curframe)
  179. {
  180.     int                i, j, k;
  181.     daliasgroup_t    dagroup;
  182.     trivert_t        *pframe;
  183.  
  184.  
  185.     dagroup.numframes = LittleLong (numframes);
  186.  
  187.     for (i=0 ; i<3 ; i++)
  188.     {
  189.         dagroup.bboxmin.v[i] = 255;
  190.         dagroup.bboxmax.v[i] = 0;
  191.     }
  192.  
  193.     for (i=0 ; i<numframes ; i++)
  194.     {
  195.         pframe = (trivert_t *)frames[curframe].pdata;
  196.  
  197.         for (j=0 ; j<model.numverts ; j++)
  198.         {
  199.             for (k=0 ; k<3 ; k++)
  200.             {
  201.             // scale to byte values & min/max check
  202.                 tarray[j].v[k] = (pframe[j].v[k] - model.scale_origin[k]) /
  203.                                     model.scale[k];
  204.                 if (tarray[j].v[k] < dagroup.bboxmin.v[k])
  205.                     dagroup.bboxmin.v[k] = tarray[j].v[k];
  206.                 if (tarray[j].v[k] > dagroup.bboxmax.v[k])
  207.                     dagroup.bboxmax.v[k] = tarray[j].v[k];
  208.             }
  209.         }
  210.  
  211.         curframe++;
  212.     }
  213.  
  214.     SafeWrite (modelouthandle, &dagroup, sizeof(dagroup));
  215. }
  216.  
  217.  
  218. /*
  219. ============
  220. WriteModel
  221. ============
  222. */
  223. void WriteModelFile (FILE *modelouthandle)
  224. {
  225.     int        i, curframe, curskin;
  226.     float    dist[3];
  227.     mdl_t    modeltemp;
  228.  
  229. // Calculate the bounding box for this model
  230.     for (i=0 ; i<3 ; i++)
  231.     {
  232.         printf ("framesmins[%d]: %f, framesmaxs[%d]: %f\n",
  233.                 i, framesmins[i], i, framesmaxs[i]);
  234.         if (fabs (framesmins[i]) > fabs (framesmaxs[i]))
  235.             dist[i] = framesmins[i];
  236.         else
  237.             dist[i] = framesmaxs[i];
  238.  
  239.         model.scale[i] = (framesmaxs[i] - framesmins[i]) / 255.9;
  240.         model.scale_origin[i] = framesmins[i];
  241.     }
  242.  
  243.     model.boundingradius = sqrt(dist[0] * dist[0] +
  244.                                 dist[1] * dist[1] +
  245.                                 dist[2] * dist[2]);
  246.  
  247. //
  248. // write out the model header
  249. //
  250.     modeltemp.ident = LittleLong (IDPOLYHEADER);
  251.     modeltemp.version = LittleLong (ALIAS_VERSION);
  252.     modeltemp.boundingradius = LittleFloat (model.boundingradius);
  253.  
  254.     for (i=0 ; i<3 ; i++)
  255.     {
  256.         modeltemp.scale[i] = LittleFloat (model.scale[i]);
  257.         modeltemp.scale_origin[i] = LittleFloat (model.scale_origin[i]);
  258.         modeltemp.eyeposition[i] = LittleFloat (model.eyeposition[i] +
  259.                 adjust[i]);
  260.     }
  261.  
  262.     modeltemp.flags = LittleLong (model.flags);
  263.     modeltemp.numskins = LittleLong (model.numskins);
  264.     modeltemp.skinwidth = LittleLong (model.skinwidth);
  265.     modeltemp.skinheight = LittleLong (model.skinheight);
  266.     modeltemp.numverts = LittleLong (model.numverts);
  267.     modeltemp.numtris = LittleLong (model.numtris - degeneratetris);
  268.     modeltemp.numframes = LittleLong (model.numframes);
  269.     modeltemp.synctype = LittleFloat (model.synctype);
  270.     averagesize = totsize / model.numtris;
  271.     modeltemp.size = LittleFloat (averagesize);
  272.  
  273.     SafeWrite (modelouthandle, &modeltemp, sizeof(model));
  274.  
  275. //
  276. // write out the skins
  277. //
  278.     curskin = 0;
  279.  
  280.     for (i=0 ; i<model.numskins ; i++)
  281.     {
  282.         SafeWrite (modelouthandle, &skins[curskin].type,
  283.                    sizeof(skins[curskin].type));
  284.  
  285.         SafeWrite (modelouthandle, skins[curskin].pdata,
  286.                    model.skinwidth * model.skinheight);
  287.  
  288.         curskin++;
  289.     }
  290.  
  291. //
  292. // write out the base model (the s & t coordinates for the vertices)
  293. //
  294.     for (i=0 ; i<model.numverts ; i++)
  295.     {
  296.         if (stverts[i].onseam == 3)
  297.         {
  298.             stverts[i].onseam = LittleLong (ALIAS_ONSEAM);
  299.         }
  300.         else
  301.         {
  302.             stverts[i].onseam = LittleLong (0);
  303.         }
  304.  
  305.         stverts[i].s = LittleLong (stverts[i].s);
  306.         stverts[i].t = LittleLong (stverts[i].t);
  307.     }
  308.  
  309.     SafeWrite (modelouthandle, stverts, model.numverts * sizeof(stverts[0]));
  310.  
  311. //
  312. // write out the triangles
  313. //
  314.     for (i=0 ; i<model.numtris ; i++)
  315.     {
  316.         int            j;
  317.         dtriangle_t    tri;
  318.  
  319.         if (!degenerate[i])
  320.         {
  321.             tri.facesfront = LittleLong (triangles[i].facesfront);
  322.  
  323.             for (j=0 ; j<3 ; j++)
  324.             {
  325.                 tri.vertindex[j] = LittleLong (triangles[i].vertindex[j]);
  326.             }
  327.  
  328.             SafeWrite (modelouthandle,
  329.                        &tri,
  330.                        sizeof(tri));
  331.         }
  332.     }
  333.  
  334. //
  335. // write out the frames
  336. //
  337.     curframe = 0;
  338.  
  339.     for (i=0 ; i<model.numframes ; i++)
  340.     {
  341.         SafeWrite (modelouthandle, &frames[curframe].type,
  342.                    sizeof(frames[curframe].type));
  343.  
  344.         if (frames[curframe].type == ALIAS_SINGLE)
  345.         {
  346.         //
  347.         // single (non-grouped) frame
  348.         //
  349.             WriteFrame (modelouthandle, curframe);
  350.             curframe++;
  351.         }
  352.         else
  353.         {
  354.             int                    j, numframes, groupframe;
  355.             float                totinterval;
  356.  
  357.             groupframe = curframe;
  358.             curframe++;
  359.             numframes = frames[groupframe].numgroupframes;
  360.  
  361.         //
  362.         // set and write the group header
  363.         //
  364.             WriteGroupBBox (modelouthandle, numframes, curframe);
  365.  
  366.         //
  367.         // write the interval array
  368.         //
  369.             totinterval = 0.0;
  370.  
  371.             for (j=0 ; j<numframes ; j++)
  372.             {
  373.                 daliasinterval_t    temp;
  374.  
  375.                 totinterval += frames[groupframe+1+j].interval;
  376.                 temp.interval = LittleFloat (totinterval);
  377.  
  378.                 SafeWrite (modelouthandle, &temp, sizeof(temp));
  379.             }
  380.  
  381.             for (j=0 ; j<numframes ; j++)
  382.             {
  383.                 WriteFrame (modelouthandle, curframe);
  384.                 curframe++;
  385.             }
  386.         }
  387.     }
  388. }
  389.  
  390.  
  391. /*
  392. ===============
  393. WriteModel
  394. ===============
  395. */
  396. void WriteModel (void)
  397. {
  398.     FILE        *modelouthandle;
  399. //
  400. // write the model output file
  401. //
  402.     if (!framecount)
  403.     {
  404.         printf ("no frames grabbed, no file generated\n");
  405.         return;
  406.     }
  407.     
  408.     if (!skincount)
  409.         Error ("frames with no skins\n");
  410.  
  411.     StripExtension (outname);
  412.     strcat (outname, ".mdl");
  413.     
  414.     printf ("---------------------\n");
  415.     printf ("writing %s:\n", outname);
  416.     modelouthandle = SafeOpenWrite (outname);
  417.  
  418.     WriteModelFile (modelouthandle);
  419.     
  420.     printf ("%4d frame(s)\n", model.numframes);
  421.     printf ("%4d ungrouped frame(s), including group headers\n", framecount);
  422.     printf ("%4d skin(s)\n", model.numskins);
  423.     printf ("%4d degenerate triangles(s) removed\n", degeneratetris);
  424.     printf ("%4d triangles emitted\n", model.numtris - degeneratetris);
  425.     printf ("pixels per triangle %f\n", averagesize);
  426.  
  427.     printf ("file size: %d\n", (int)ftell (modelouthandle) );
  428.     printf ("---------------------\n");
  429.     
  430.     fclose (modelouthandle);
  431.     
  432.     ClearModel ();
  433. }
  434.  
  435.  
  436. /*
  437. ============
  438. SetSkinValues
  439.  
  440. Called for the base frame
  441. ============
  442. */
  443. void SetSkinValues (void)
  444. {
  445.     int            i;
  446.     float        v;
  447.     int            width, height, iwidth, iheight, skinwidth;
  448.     float        basex, basey;
  449.  
  450.     for (i=0 ; i<3 ; i++)
  451.     {
  452.         mins[i] = 9999999;
  453.         maxs[i] = -9999999;
  454.     }
  455.     
  456.     for (i=0 ; i<model.numverts ; i++)
  457.     {
  458.         int        j;
  459.  
  460.         stverts[i].onseam = 0;
  461.  
  462.         for (j=0 ; j<3 ; j++)
  463.         {
  464.             v = baseverts[i][j];
  465.             if (v < mins[j])
  466.                 mins[j] = v;
  467.             if (v > maxs[j])
  468.                 maxs[j] = v;
  469.         }
  470.     }
  471.     
  472.     for (i=0 ; i<3 ; i++)
  473.     {
  474.         mins[i] = floor(mins[i]);
  475.         maxs[i] = ceil(maxs[i]);
  476.     }
  477.     
  478.     width = maxs[0] - mins[0];
  479.     height = maxs[2] - mins[2];
  480.  
  481.     printf ("width: %i  height: %i\n",width, height);
  482.  
  483.     scale = 8;
  484.     if (width*scale >= 150)
  485.         scale = 150.0 / width;    
  486.     if (height*scale >= 190)
  487.         scale = 190.0 / height;
  488.     iwidth = ceil(width*scale) + 4;
  489.     iheight = ceil(height*scale) + 4;
  490.     
  491.     printf ("scale: %f\n",scale);
  492.     printf ("iwidth: %i  iheight: %i\n",iwidth, iheight);
  493.     
  494. //
  495. // determine which side of each triangle to map the texture to
  496. //
  497.     for (i=0 ; i<model.numtris ; i++)
  498.     {
  499.         int        j;
  500.         vec3_t    vtemp1, vtemp2, normal;
  501.  
  502.         VectorSubtract (baseverts[triangles[i].vertindex[0]],
  503.                         baseverts[triangles[i].vertindex[1]],
  504.                         vtemp1);
  505.         VectorSubtract (baseverts[triangles[i].vertindex[2]],
  506.                         baseverts[triangles[i].vertindex[1]],
  507.                         vtemp2);
  508.         CrossProduct (vtemp1, vtemp2, normal);
  509.  
  510.         if (normal[1] > 0)
  511.         {
  512.             basex = iwidth + 2;
  513.             triangles[i].facesfront = 0;
  514.         }
  515.         else
  516.         {
  517.             basex = 2;
  518.             triangles[i].facesfront = 1;
  519.         }
  520.         basey = 2;
  521.         
  522.         for (j=0 ; j<3 ; j++)
  523.         {
  524.             float        *pbasevert;
  525.             stvert_t    *pstvert;
  526.  
  527.             pbasevert = baseverts[triangles[i].vertindex[j]];
  528.             pstvert = &stverts[triangles[i].vertindex[j]];
  529.  
  530.             if (triangles[i].facesfront)
  531.             {
  532.                 pstvert->onseam |= 1;
  533.             }
  534.             else
  535.             {
  536.                 pstvert->onseam |= 2;
  537.             }
  538.  
  539.             if ((triangles[i].facesfront) || ((pstvert->onseam & 1) == 0))
  540.             {
  541.             // we want the front s value for seam vertices
  542.                 pstvert->s = Q_rint((pbasevert[0] - mins[0]) * scale + basex);
  543.                 pstvert->t = Q_rint((maxs[2] - pbasevert[2]) * scale + basey);
  544.             }
  545.         }
  546.     }
  547.  
  548. // make the width a multiple of 4; some hardware requires this, and it ensures
  549. // dword alignment for each scan
  550.     skinwidth = iwidth*2;
  551.     model.skinwidth = (skinwidth + 3) & ~3;
  552.     model.skinheight = iheight;
  553.  
  554.     printf ("skin width: %i (unpadded width %i)  skin height: %i\n",
  555.             model.skinwidth, skinwidth, model.skinheight);
  556. }
  557.  
  558.  
  559. /*
  560. =================
  561. Cmd_Base
  562. =================
  563. */
  564. void Cmd_Base (void)
  565. {
  566.     triangle_t    *ptri;
  567.     int            i, j, k;
  568.     int        time1;
  569.  
  570.     GetToken (false);
  571.     strcpy (qbasename, token);
  572.  
  573.     sprintf (file1, "%s/%s.tri", cdpartial, token);
  574.     ExpandPathAndArchive (file1);
  575.  
  576.     sprintf (file1, "%s/%s.tri", cddir, token);
  577.     time1 = FileTime (file1);
  578.     if (time1 == -1)
  579.         Error ("%s doesn't exist", file1);
  580.  
  581. //
  582. // load the base triangles
  583. //
  584.     LoadTriangleList (file1, &ptri, &model.numtris);
  585.     printf("NUMBER OF TRIANGLES (including degenerate triangles): %d\n",
  586.             model.numtris);
  587.  
  588. //
  589. // run through all the base triangles, storing each unique vertex in the
  590. // base vertex list and setting the indirect triangles to point to the base
  591. // vertices
  592. //
  593.     for (i=0 ; i<model.numtris ; i++)
  594.     {
  595.         if (VectorCompare (ptri[i].verts[0], ptri[i].verts[1]) ||
  596.             VectorCompare (ptri[i].verts[1], ptri[i].verts[2]) ||
  597.             VectorCompare (ptri[i].verts[2], ptri[i].verts[0]))
  598.         {
  599.             degeneratetris++;
  600.             degenerate[i] = 1;
  601.         }
  602.         else
  603.         {
  604.             degenerate[i] = 0;
  605.         }
  606.  
  607.         for (j=0 ; j<3 ; j++)
  608.         {
  609.             for (k=0 ; k<model.numverts ; k++)
  610.                 if (VectorCompare (ptri[i].verts[j], baseverts[k]))
  611.                     break;    // this vertex is already in the base vertex list
  612.  
  613.             if (k == model.numverts)
  614.             {
  615.             //
  616.             // new vertex
  617.             //
  618.                 VectorCopy (ptri[i].verts[j], baseverts[model.numverts]);
  619.                 model.numverts++;
  620.             }
  621.  
  622.             triangles[i].vertindex[j] = k;
  623.         }
  624.     }
  625.  
  626.     printf ("NUMBER OF VERTEXES: %i\n", model.numverts);
  627.  
  628. //
  629. // calculate s & t for each vertex, and set the skin width and height
  630. //
  631.     SetSkinValues ();
  632. }
  633.  
  634.  
  635. /*
  636. ===============
  637. Cmd_Skin
  638. ===============
  639. */
  640. void Cmd_Skin (void)
  641. {
  642.     byte    *ppal;
  643.     byte    *pskinbitmap;
  644.     byte    *ptemp1, *ptemp2;
  645.     int        i;
  646.     int        time1;
  647.  
  648.     GetToken (false);    
  649.     strcpy (skinname, token);
  650.  
  651.     sprintf (file1, "%s/%s.lbm", cdpartial, token);
  652.     ExpandPathAndArchive (file1);
  653.  
  654.     sprintf (file1, "%s/%s.lbm", cddir, token);
  655.     time1 = FileTime (file1);
  656.     if (time1 == -1)
  657.         Error ("%s not found", file1);
  658.     
  659.     if (TokenAvailable ())
  660.     {
  661.         GetToken (false);
  662.         skins[skincount].interval = atof (token);
  663.         if (skins[skincount].interval <= 0.0)
  664.             Error ("Non-positive interval");
  665.     }
  666.     else
  667.     {
  668.         skins[skincount].interval = 0.1;
  669.     }
  670.     
  671. //
  672. // load in the skin .lbm file
  673. //
  674.     LoadLBM (file1, &pskinbitmap, &ppal);
  675.  
  676. //
  677. // now copy the part of the texture we care about, since LBMs are always
  678. // loaded as 320x200 bitmaps
  679. //
  680.     skins[skincount].pdata =
  681.             malloc (model.skinwidth * model.skinheight);
  682.  
  683.     if (!skins[skincount].pdata)
  684.         Error ("couldn't get memory for skin texture");
  685.  
  686.     ptemp1 = skins[skincount].pdata;
  687.     ptemp2 = pskinbitmap;
  688.  
  689.     for (i=0 ; i<model.skinheight ; i++)
  690.     {
  691.         memcpy (ptemp1, ptemp2, model.skinwidth);
  692.         ptemp1 += model.skinwidth;
  693.         ptemp2 += 320;
  694.     }
  695.  
  696.     skincount++;
  697.  
  698.     if (skincount > MAXSKINS)
  699.         Error ("Too many skins; increase MAXSKINS");
  700. }
  701.  
  702.  
  703. /*
  704. ===============
  705. GrabFrame
  706. ===============
  707. */
  708. void GrabFrame (char *frame, int isgroup)
  709. {
  710.     triangle_t        *ptri;
  711.     int                i, j;
  712.     trivert_t        *ptrivert;
  713.     int                numtris;
  714.     int        time1;
  715.  
  716.     sprintf (file1, "%s/%s.tri", cdpartial, frame);
  717.     ExpandPathAndArchive (file1);
  718.  
  719.     sprintf (file1, "%s/%s.tri",cddir, frame);
  720.     time1 = FileTime (file1);
  721.     if (time1 == -1)
  722.         Error ("%s does not exist",file1);
  723.  
  724.     printf ("grabbing %s\n", file1);
  725.     frames[framecount].interval = 0.1;
  726.     strcpy (frames[framecount].name, frame);
  727.  
  728. //
  729. // load the frame
  730. //
  731.     LoadTriangleList (file1, &ptri, &numtris);
  732.  
  733.     if (numtris != model.numtris)
  734.         Error ("number of triangles doesn't match\n");
  735.  
  736. // set the intervals
  737.     if (isgroup && TokenAvailable ())
  738.     {
  739.         GetToken (false);
  740.         frames[framecount].interval = atof (token);
  741.         if (frames[framecount].interval <= 0.0)
  742.             Error ("Non-positive interval %s %f", token,
  743.                     frames[framecount].interval);
  744.     }
  745.     else
  746.     {
  747.         frames[framecount].interval = 0.1;
  748.     }
  749.     
  750. //
  751. // allocate storage for the frame's vertices
  752. //
  753.     ptrivert = verts[framecount];
  754.  
  755.     frames[framecount].pdata = ptrivert;
  756.     frames[framecount].type = ALIAS_SINGLE;
  757.  
  758.     for (i=0 ; i<model.numverts ; i++)
  759.     {
  760.         vnorms[i].numnormals = 0;
  761.     }
  762.  
  763. //
  764. // store the frame's vertices in the same order as the base. This assumes the
  765. // triangles and vertices in this frame are in exactly the same order as in the
  766. // base
  767. //
  768.     for (i=0 ; i<numtris ; i++)
  769.     {
  770.         vec3_t    vtemp1, vtemp2, normal;
  771.         float    ftemp;
  772.  
  773.         if (degenerate[i])
  774.             continue;
  775.  
  776.         if (firstframe)
  777.         {
  778.             VectorSubtract (ptri[i].verts[0], ptri[i].verts[1], vtemp1);
  779.             VectorSubtract (ptri[i].verts[2], ptri[i].verts[1], vtemp2);
  780.             VectorScale (vtemp1, scale_up, vtemp1);
  781.             VectorScale (vtemp2, scale_up, vtemp2);
  782.             CrossProduct (vtemp1, vtemp2, normal);
  783.  
  784.             totsize += sqrt (normal[0] * normal[0] +
  785.                              normal[1] * normal[1] +
  786.                              normal[2] * normal[2]) / 2.0;
  787.         }
  788.  
  789.         VectorSubtract (ptri[i].verts[0], ptri[i].verts[1], vtemp1);
  790.         VectorSubtract (ptri[i].verts[2], ptri[i].verts[1], vtemp2);
  791.         CrossProduct (vtemp1, vtemp2, normal);
  792.  
  793.         VectorNormalize (normal);
  794.  
  795.     // rotate the normal so the model faces down the positive x axis
  796.         ftemp = normal[0];
  797.         normal[0] = -normal[1];
  798.         normal[1] = ftemp;
  799.  
  800.         for (j=0 ; j<3 ; j++)
  801.         {
  802.             int        k;
  803.             int        vertindex;
  804.  
  805.             vertindex = triangles[i].vertindex[j];
  806.  
  807.         // rotate the vertices so the model faces down the positive x axis
  808.         // also adjust the vertices to the desired origin
  809.             ptrivert[vertindex].v[0] = ((-ptri[i].verts[j][1]) * scale_up) +
  810.                                         adjust[0];
  811.             ptrivert[vertindex].v[1] = (ptri[i].verts[j][0] * scale_up) +
  812.                                         adjust[1];
  813.             ptrivert[vertindex].v[2] = (ptri[i].verts[j][2] * scale_up) +
  814.                                         adjust[2];
  815.  
  816.             for (k=0 ; k<3 ; k++)
  817.             {
  818.                 if (ptrivert[vertindex].v[k] < framesmins[k])
  819.                     framesmins[k] = ptrivert[vertindex].v[k];
  820.  
  821.                 if (ptrivert[vertindex].v[k] > framesmaxs[k])
  822.                     framesmaxs[k] = ptrivert[vertindex].v[k];
  823.             }
  824.  
  825.             VectorCopy (normal,
  826.                         vnorms[vertindex].
  827.                         normals[vnorms[vertindex].numnormals]);
  828.  
  829.             vnorms[vertindex].numnormals++;
  830.         }
  831.     }
  832.  
  833. //
  834. // calculate the vertex normals, match them to the template list, and store the
  835. // index of the best match
  836. //
  837.     for (i=0 ; i<model.numverts ; i++)
  838.     {
  839.         int        j;
  840.         vec3_t    v;
  841.         float    maxdot;
  842.         int        maxdotindex;
  843.  
  844.         if (vnorms[i].numnormals > 0)
  845.         {
  846.             for (j=0 ; j<3 ; j++)
  847.             {
  848.                 int        k;
  849.     
  850.                 v[j] = 0;
  851.                 
  852.                 for (k=0 ; k<vnorms[i].numnormals ; k++)
  853.                 {
  854.                     v[j] += vnorms[i].normals[k][j];
  855.                 }
  856.     
  857.                 v[j] /= vnorms[i].numnormals;
  858.             }
  859.         }
  860.         else
  861.         {
  862.             Error ("Vertex with no non-degenerate triangles attached");
  863.         }
  864.  
  865.         VectorNormalize (v);
  866.  
  867.         maxdot = -999999.0;
  868.         maxdotindex = -1;
  869.  
  870.         for (j=0 ; j<NUMVERTEXNORMALS ; j++)
  871.         {
  872.             float    dot;
  873.  
  874.             dot = DotProduct (v, avertexnormals[j]);
  875.             if (dot > maxdot)
  876.             {
  877.                 maxdot = dot;
  878.                 maxdotindex = j;
  879.             }
  880.         }
  881.  
  882.         ptrivert[i].lightnormalindex = maxdotindex;
  883.     }
  884.  
  885.     framecount++;
  886.  
  887.     if (framecount >= MAXFRAMES)
  888.         Error ("Too many frames; increase MAXFRAMES");
  889.  
  890.     free (ptri);
  891.     firstframe = 0;
  892. }
  893.  
  894. /*
  895. ===============
  896. Cmd_Frame    
  897. ===============
  898. */
  899. void Cmd_Frame (int isgroup)
  900. {
  901.     while (TokenAvailable())
  902.     {
  903.         GetToken (false);
  904.         GrabFrame (token, isgroup);
  905.  
  906.         if (!isgroup)
  907.             model.numframes++;
  908.     }
  909. }
  910.  
  911. /*
  912. ===============
  913. Cmd_SkinGroupStart    
  914. ===============
  915. */
  916. void Cmd_SkinGroupStart (void)
  917. {
  918.     int            groupskin;
  919.  
  920.     groupskin = skincount++;
  921.     if (skincount >= MAXFRAMES)
  922.         Error ("Too many skins; increase MAXSKINS");
  923.  
  924.     skins[groupskin].type = ALIAS_SKIN_GROUP;
  925.     skins[groupskin].numgroupskins = 0;
  926.  
  927.     while (1)
  928.     {
  929.         GetToken (true);
  930.         if (endofscript)
  931.             Error ("End of file during group");
  932.  
  933.         if (!strcmp (token, "$skin"))
  934.         {
  935.             Cmd_Skin ();
  936.             skins[groupskin].numgroupskins++;
  937.         }
  938.         else if (!strcmp (token, "$skingroupend"))
  939.         {
  940.             break;
  941.         }
  942.         else
  943.         {
  944.             Error ("$skin or $skingroupend expected\n");
  945.         }
  946.  
  947.     }
  948.  
  949.     if (skins[groupskin].numgroupskins == 0)
  950.         Error ("Empty group\n");
  951. }
  952.  
  953.  
  954. /*
  955. ===============
  956. Cmd_FrameGroupStart    
  957. ===============
  958. */
  959. void Cmd_FrameGroupStart (void)
  960. {
  961.     int            groupframe;
  962.  
  963.     groupframe = framecount++;
  964.     if (framecount >= MAXFRAMES)
  965.         Error ("Too many frames; increase MAXFRAMES");
  966.  
  967.     frames[groupframe].type = ALIAS_GROUP;
  968.     frames[groupframe].numgroupframes = 0;
  969.  
  970.     while (1)
  971.     {
  972.         GetToken (true);
  973.         if (endofscript)
  974.             Error ("End of file during group");
  975.  
  976.         if (!strcmp (token, "$frame"))
  977.         {
  978.             Cmd_Frame (1);
  979.         }
  980.         else if (!strcmp (token, "$framegroupend"))
  981.         {
  982.             break;
  983.         }
  984.         else
  985.         {
  986.             Error ("$frame or $framegroupend expected\n");
  987.         }
  988.  
  989.     }
  990.  
  991.     frames[groupframe].numgroupframes += framecount - groupframe - 1;
  992.  
  993.     if (frames[groupframe].numgroupframes == 0)
  994.         Error ("Empty group\n");
  995. }
  996.  
  997.  
  998. /*
  999. =================
  1000. Cmd_Origin
  1001. =================
  1002. */
  1003. void Cmd_Origin (void)
  1004. {
  1005.  
  1006. // rotate points into frame of reference so model points down the positive x
  1007. // axis
  1008.     GetToken (false);
  1009.     adjust[1] = -atof (token);
  1010.  
  1011.     GetToken (false);
  1012.     adjust[0] = atof (token);
  1013.  
  1014.     GetToken (false);
  1015.     adjust[2] = -atof (token);
  1016. }
  1017.  
  1018.  
  1019. /*
  1020. =================
  1021. Cmd_Eyeposition
  1022. =================
  1023. */
  1024. void Cmd_Eyeposition (void)
  1025. {
  1026.  
  1027. // rotate points into frame of reference so model points down the positive x
  1028. // axis
  1029.     GetToken (false);
  1030.     model.eyeposition[1] = atof (token);
  1031.  
  1032.     GetToken (false);
  1033.     model.eyeposition[0] = -atof (token);
  1034.  
  1035.     GetToken (false);
  1036.     model.eyeposition[2] = atof (token);
  1037. }
  1038.  
  1039.  
  1040. /*
  1041. =================
  1042. Cmd_ScaleUp
  1043. =================
  1044. */
  1045. void Cmd_ScaleUp (void)
  1046. {
  1047.  
  1048.     GetToken (false);
  1049.     scale_up = atof (token);
  1050. }
  1051.  
  1052. /*
  1053. =================
  1054. Cmd_Flags
  1055. =================
  1056. */
  1057. void Cmd_Flags (void)
  1058. {
  1059.     GetToken (false);
  1060.     model.flags = atoi (token);
  1061. }
  1062.  
  1063.  
  1064. /*
  1065. =================
  1066. Cmd_Modelname
  1067. =================
  1068. */
  1069. void Cmd_Modelname (void)
  1070. {
  1071.     WriteModel ();
  1072.     GetToken (false);
  1073.     strcpy (outname, token);
  1074. }
  1075.  
  1076.  
  1077. /*
  1078. ===============
  1079. ParseScript
  1080. ===============
  1081. */
  1082. void ParseScript (void)
  1083. {
  1084.     while (1)
  1085.     {
  1086.         do
  1087.         {    // look for a line starting with a $ command
  1088.             GetToken (true);
  1089.             if (endofscript)
  1090.                 return;
  1091.             if (token[0] == '$')
  1092.                 break;                
  1093.             while (TokenAvailable())
  1094.                 GetToken (false);
  1095.         } while (1);
  1096.     
  1097.         if (!strcmp (token, "$modelname"))
  1098.         {
  1099.             Cmd_Modelname ();
  1100.         }
  1101.         else if (!strcmp (token, "$base"))
  1102.         {
  1103.             Cmd_Base ();
  1104.         }
  1105.         else if (!strcmp (token, "$cd"))
  1106.         {
  1107.             if (cdset)
  1108.                 Error ("Two $cd in one model");
  1109.             cdset = true;
  1110.             GetToken (false);
  1111.             strcpy (cdpartial, token);
  1112.             strcpy (cddir, ExpandPath(token));
  1113.         }
  1114.         else if (!strcmp (token, "$sync"))
  1115.         {
  1116.             model.synctype = ST_SYNC;
  1117.         }
  1118.         else if (!strcmp (token, "$origin"))
  1119.         {
  1120.             Cmd_Origin ();
  1121.         }
  1122.         else if (!strcmp (token, "$eyeposition"))
  1123.         {
  1124.             Cmd_Eyeposition ();
  1125.         }
  1126.         else if (!strcmp (token, "$scale"))
  1127.         {
  1128.             Cmd_ScaleUp ();
  1129.         }
  1130.         else if (!strcmp (token, "$flags"))
  1131.         {
  1132.             Cmd_Flags ();
  1133.         }
  1134.         else if (!strcmp (token, "$frame"))
  1135.         {
  1136.             Cmd_Frame (0);
  1137.         }
  1138.         else if (!strcmp (token, "$skin"))
  1139.         {
  1140.             Cmd_Skin ();
  1141.             model.numskins++;
  1142.         }        
  1143.         else if (!strcmp (token, "$framegroupstart"))
  1144.         {
  1145.             Cmd_FrameGroupStart ();
  1146.             model.numframes++;
  1147.         }
  1148.         else if (!strcmp (token, "$skingroupstart"))
  1149.         {
  1150.             Cmd_SkinGroupStart ();
  1151.             model.numskins++;
  1152.         }
  1153.         else
  1154.         {
  1155.             Error ("bad command %s\n", token);
  1156.         }
  1157.  
  1158.     }
  1159. }
  1160.  
  1161. /*
  1162. ==============
  1163. main
  1164. ==============
  1165. */
  1166. int main (int argc, char **argv)
  1167. {
  1168.     int        i;
  1169.     char    path[1024];
  1170.  
  1171.     if (argc != 2 && argc != 4)
  1172.         Error ("usage: modelgen [-archive directory] file.qc");
  1173.         
  1174.     if (!strcmp(argv[1], "-archive"))
  1175.     {
  1176.         archive = true;
  1177.         strcpy (archivedir, argv[2]);
  1178.         printf ("Archiving source to: %s\n", archivedir);
  1179.         i = 3;
  1180.     }
  1181.     else
  1182.         i = 1;
  1183.  
  1184. //
  1185. // load the script
  1186. //
  1187.     strcpy (path, argv[i]);
  1188.     DefaultExtension (path, ".qc");
  1189.     SetQdirFromPath (path);
  1190.     LoadScriptFile (path);
  1191.     
  1192. //
  1193. // parse it
  1194. //
  1195.     memset (&model, 0, sizeof(model));
  1196.  
  1197.     for (i=0 ; i<3 ; i++)
  1198.     {
  1199.         framesmins[i] = 9999999;
  1200.         framesmaxs[i] = -9999999;
  1201.     }
  1202.  
  1203.  
  1204.     ClearModel ();
  1205.     strcpy (outname, argv[1]);
  1206.  
  1207.     ParseScript ();
  1208.     WriteModel ();
  1209.     
  1210.     return 0;
  1211. }
  1212.  
  1213.