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