home *** CD-ROM | disk | FTP | other *** search
/ PC PowerPlay 58 / pcpp58a.iso / extras / quake 3 source / Q3A_ToolSource.exe / Main / ECLASS.CPP < prev    next >
Encoding:
C/C++ Source or Header  |  2001-01-02  |  20.7 KB  |  912 lines

  1. #include "stdafx.h"
  2. #include "qe3.h"
  3. #include "io.h"
  4. #include "pakstuff.h"
  5. //#include "qertypes.h"
  6.  
  7. eclass_t    *eclass = NULL;
  8. eclass_t    *eclass_bad = NULL;
  9. char        eclass_directory[1024];
  10.  
  11. // md3 cache for misc_models
  12. eclass_t *g_md3Cache = NULL;
  13.  
  14. /*
  15.  
  16. the classname, color triple, and bounding box are parsed out of comments
  17. A ? size means take the exact brush size.
  18.  
  19. /*QUAKED <classname> (0 0 0) ?
  20. /*QUAKED <classname> (0 0 0) (-8 -8 -8) (8 8 8)
  21.  
  22. Flag names can follow the size description:
  23.  
  24. /*QUAKED func_door (0 .5 .8) ? START_OPEN STONE_SOUND DOOR_DONT_LINK GOLD_KEY SILVER_KEY
  25.  
  26. */
  27.  
  28. void CleanEntityList(eclass_t *&pList)
  29. {
  30.   while (pList)
  31.   {
  32.     eclass_t* pTemp = pList->next;
  33.  
  34.     entitymodel *model = pList->model;
  35.     while (model != NULL)
  36.     {
  37.       delete []model->pTriList;
  38.       model = model->pNext;
  39.     }
  40.     
  41.     if (pList->modelpath)
  42.       free(pList->modelpath);
  43.       if (pList->skinpath)            // PGM
  44.           free(pList->skinpath);        // PGM
  45.     
  46.     free(pList->name);
  47.     free(pList->comments);
  48.     free(pList);
  49.     pList = pTemp;
  50.   }
  51.  
  52.   pList = NULL;
  53.  
  54. }
  55.  
  56.  
  57. void CleanUpEntities()
  58. {
  59.   CleanEntityList(eclass);
  60.   CleanEntityList(g_md3Cache);
  61. /*
  62.   while (eclass)
  63.   {
  64.     eclass_t* pTemp = eclass->next;
  65.     delete []eclass->pTriList;
  66.     
  67.     if (eclass->modelpath)
  68.       free(eclass->modelpath);
  69.       if (eclass->skinpath)            // PGM
  70.           free(eclass->skinpath);        // PGM
  71.     
  72.     free(eclass->name);
  73.     free(eclass->comments);
  74.     free(eclass);
  75.     eclass = pTemp;
  76.   }
  77.  
  78.   eclass = NULL;
  79. */
  80.   if (eclass_bad)
  81.   {
  82.     free(eclass_bad->name);
  83.     free(eclass_bad->comments);
  84.     free(eclass_bad);
  85.     eclass_bad = NULL;
  86.   }
  87. }
  88.  
  89. void ExtendBounds(vec3_t v, vec3_t &vMin, vec3_t &vMax)
  90. {
  91.     for (int i = 0 ;i < 3 ;i++)
  92.     {
  93.         vec_t f = v[i];
  94.         
  95.     if (f < vMin[i])
  96.     {
  97.             vMin[i] = f;
  98.     }
  99.  
  100.     if (f > vMax[i])
  101.     {
  102.             vMax[i] = f;
  103.     }
  104.     }
  105. }
  106.  
  107.  
  108.  
  109. // FIXME: this code is a TOTAL clusterfuck
  110. //
  111. void LoadModel(const char *pLocation, eclass_t *e, vec3_t &vMin, vec3_t &vMax, entitymodel *&pModel, const char *pSkin)
  112. {
  113.   // this assumes a path only and uses tris.md2
  114.   // for the model and skin.pcx for the skin
  115.   char cPath[1024];
  116.   char cSkin[1024];
  117.   char cFullLocation[1024];
  118.     //struct _finddata_t fileinfo;
  119.  
  120.   vMin[0] = vMin[1] = vMin[2] = 99999;
  121.   vMax[0] = vMax[1] = vMax[2] = -99999;
  122.  
  123.   bool bMD3 = false;
  124.   bool bASE = false;
  125.  
  126.   strcpy( cFullLocation, pLocation );
  127.  
  128.   if (strstr(pLocation, ".md3"))
  129.   {
  130.     bMD3 = true;
  131.   }
  132.   else if (strstr(pLocation, ".md2") != NULL)
  133.   {
  134.       sprintf( cFullLocation, "%stris.md2", pLocation);
  135.   }
  136.   else if (strstr(pLocation, ".ase") != NULL)
  137.   {
  138.     bASE = true;
  139.   }
  140.  
  141.   sprintf( cPath, "%s/%s", ValueForKey(g_qeglobals.d_project_entity, "basepath"), cFullLocation);
  142.  
  143.   Sys_Printf("Loading model %s...", cPath);
  144.   unsigned char* p = NULL;
  145.   bool bOpen = (LoadFile(cPath, reinterpret_cast<void**>(&p)) > 0);
  146.   if (!bOpen)
  147.   {
  148.     Sys_Printf(" failed. Trying PAK file...");
  149. //    sprintf (cPath, "%stris.md2", pLocation);
  150.       strcpy (cPath, cFullLocation);
  151.       bOpen = (PakLoadAnyFile(cPath, reinterpret_cast<void**>(&p)) > 0);
  152.   }
  153.  
  154.   if (bOpen)
  155.   {
  156.     Sys_Printf(" successful.\n");
  157.  
  158.     if (bASE)
  159.     {
  160. /*
  161.       free(p);
  162.       CString strOut;
  163.       ::GetTempPath(1024, strOut.GetBuffer(1024));
  164.       strOut.ReleaseBuffer();
  165.       AddSlash(strOut);
  166.       strOut += "Temp.ase";
  167.       CopyFile(cPath, strOut, false);
  168.       CString strIn = strOut;
  169.       FindReplace(strOut, ".ase", ".md3");
  170.       strcpy(cPath, strIn);
  171.       strcpy(cSkin, strOut);
  172.       Q3Data_ProduceTempMD3(ValueForKey(g_qeglobals.d_project_entity, "basepath"), cPath, cSkin);
  173.       CString strModel = cPath;
  174.       if (LoadFile(strOut.GetBuffer(0), reinterpret_cast<void**>(&p)) == 0)
  175.       {
  176.         Sys_Printf(" Conversion from ASE failed.\n");
  177.         return;
  178.       }
  179.       bMD3 = true;
  180. */
  181.     }
  182.  
  183.     if (bMD3)
  184.     {
  185.         md3Header_t header;
  186.         md3Surface_t *pSurface;
  187.         header = *(md3Header_t *)p;
  188.       if (pSkin != NULL)
  189.       {
  190.         strcpy(cSkin, pSkin);
  191.       }
  192.         else
  193.       {
  194.             cSkin[0] = '\0';
  195.       }
  196.       int n = header.numFrames;
  197.         pSurface = (md3Surface_t *) (p + header.ofsSurfaces);
  198.         for (int z = 0; z < header.numSurfaces; z++ )
  199.         {
  200.         int nTris = pSurface->numTriangles;
  201.         
  202.         //unsigned char* pTris = reinterpret_cast<unsigned char*>(pSurface);
  203.         //pTris += pSurface->ofsTriangles;
  204.  
  205.         if (nTris > 0)
  206.         {
  207.           int nStart = 0;
  208.           if (pModel->pTriList == NULL)
  209.           {
  210.                 pModel->nModelPosition = 0;
  211.             pModel->pTriList = new trimodel[nTris];
  212.             pModel->nTriCount = nTris;
  213.           }
  214.           else
  215.           {
  216.             // already have one so we need to reallocate
  217.             int nNewCount = pModel->nTriCount + nTris;
  218.             trimodel* pNewModels = new trimodel[nNewCount];
  219.             for (int i = 0; i < pModel->nTriCount; i++)
  220.             {
  221.               memcpy(&pNewModels[i], &pModel->pTriList[i], sizeof(trimodel));
  222.             }
  223.             nStart = pModel->nTriCount;
  224.             pModel->nTriCount = nNewCount;
  225.             //nTris = nNewCount;
  226.             delete [] pModel->pTriList;
  227.             pModel->pTriList = pNewModels;
  228.           }
  229.           
  230.           md3Triangle_t *pTris = reinterpret_cast<md3Triangle_t*>((reinterpret_cast<unsigned char*>(pSurface) + pSurface->ofsTriangles));
  231.           md3XyzNormal_t *pXyz = reinterpret_cast<md3XyzNormal_t*>((reinterpret_cast<unsigned char*>(pSurface) + pSurface->ofsXyzNormals));
  232.           if (e->nFrame < pSurface->numFrames)
  233.           {
  234.             pXyz += (e->nFrame * pSurface->numVerts);
  235.           }
  236.  
  237.           md3St_t *pST = reinterpret_cast<md3St_t*>((reinterpret_cast<unsigned char*>(pSurface) + pSurface->ofsSt)); 
  238.  
  239.           for (int i = 0; i < nTris; i++)
  240.           {
  241.             for (int k = 0; k < 3; k ++)
  242.             {
  243.               for (int j = 0; j < 3; j++)
  244.               {
  245.                 //e->pTriList[i].v[k][j] = (f->verts[tri.index_xyz[k]].v[j] * f->scale[j] + f->translate[j]);
  246.                 pModel->pTriList[nStart].v[k][j] = pXyz[pTris[i].indexes[k]].xyz[j] * MD3_XYZ_SCALE;
  247.               }
  248.                   pModel->pTriList[nStart].st[k][0] = pST[pTris[i].indexes[k]].st[0];
  249.                   pModel->pTriList[nStart].st[k][1] = pST[pTris[i].indexes[k]].st[1];
  250.                    ExtendBounds (pModel->pTriList[nStart].v[k], vMin, vMax);
  251.                 }
  252.             nStart++;
  253.               }
  254.  
  255.         }
  256.  
  257.         md3Shader_t *pShader = reinterpret_cast<md3Shader_t*>((reinterpret_cast<unsigned char*>(pSurface) + pSurface->ofsShaders)); 
  258.         sprintf (cPath, "%s/%s", ValueForKey(g_qeglobals.d_project_entity, "basepath"), pShader->name);
  259.         strlwr(cPath);
  260.            pModel->nTextureBind = Texture_LoadSkin(cPath, &pModel->nSkinWidth, &pModel->nSkinHeight);
  261.         if (pModel->nTextureBind == -1)
  262.         {
  263.           Sys_Printf("Model skin load failed on texture %s\n", cPath);
  264.         }
  265.             pSurface = (md3Surface_t *) ((( char * ) pSurface) + pSurface->ofsEnd);
  266.         pModel->pNext = reinterpret_cast<entitymodel_t*>(qmalloc(sizeof(entitymodel_t)));
  267.         pModel = pModel->pNext;
  268.       }
  269.     }
  270.     else
  271.     {
  272.  
  273.       dmdl_t model;
  274.       daliasframe_t *f;
  275.       unsigned char* pTris = p;
  276.       dstvert_t *pST = NULL;
  277.       int nTris = 0;
  278.  
  279.       // grab model params
  280.       memcpy(&model, p, sizeof(dmdl_t));
  281.       f = (daliasframe_t*)(p + model.ofs_frames);
  282.       pTris += model.ofs_tris;
  283.       pST = reinterpret_cast<dstvert_t*>(p + model.ofs_st);
  284.       nTris = model.num_tris;
  285.  
  286.         if(pSkin)
  287.         {
  288.             strcpy (cSkin, pSkin);
  289.             if ((cSkin[strlen(cSkin)-1] == '\\') || (cSkin[strlen(cSkin)-1] == '/'))
  290.                 strcat(cSkin, "skin.pcx\0");
  291.         }
  292.         else
  293.       {
  294.             strcpy(cSkin, (char *)(p + model.ofs_skins));
  295.       }
  296.  
  297.       sprintf (cPath, "%s/%s", ValueForKey(g_qeglobals.d_project_entity, "basepath"), cSkin);
  298.       strlwr(cPath);
  299.       pModel->nTextureBind = Texture_LoadSkin(cPath, &pModel->nSkinWidth, &pModel->nSkinHeight);
  300.       if (pModel->nTextureBind == -1)
  301.       {
  302.         Sys_Printf("Model skin load failed on texture %s\n", cPath);
  303.       }
  304.       int nStart = 0;
  305.       if (pModel->pTriList == NULL)
  306.       {
  307.             pModel->nModelPosition = 0;
  308.         pModel->pTriList = new trimodel[nTris];
  309.         pModel->nTriCount = nTris;
  310.       }
  311.       else
  312.       {
  313.         // already have one so we need to reallocate
  314.         int nNewCount = pModel->nTriCount + nTris;
  315.         trimodel* pNewModels = new trimodel[nNewCount];
  316.         for (int i = 0; i < pModel->nTriCount; i++)
  317.         {
  318.           memcpy(&pNewModels[i], &pModel->pTriList[i], sizeof(trimodel));
  319.         }
  320.         nStart = pModel->nTriCount;
  321.         pModel->nTriCount = nNewCount;
  322.         nTris = nNewCount;
  323.         delete [] pModel->pTriList;
  324.         pModel->pTriList = pNewModels;
  325.       }
  326.       
  327.       for (int i = nStart; i < nTris; i++)
  328.       {
  329.         dtriangle_t tri;
  330.         memcpy(&tri, pTris, sizeof(dtriangle_t));
  331.         for (int k = 0; k < 3; k ++)
  332.         {
  333.           for (int j = 0; j < 3; j++)
  334.           {
  335.             pModel->pTriList[i].v[k][j] = (f->verts[tri.index_xyz[k]].v[j] * f->scale[j] + f->translate[j]);
  336.           }
  337.  
  338.           pModel->pTriList[i].st[k][0] = pST[tri.index_st[k]].s / pModel->nSkinWidth;
  339.           pModel->pTriList[i].st[k][1] = pST[tri.index_st[k]].t / pModel->nSkinHeight;;
  340.           ExtendBounds (pModel->pTriList[i].v[k], vMin, vMax);
  341.             }
  342.         pTris += sizeof(dtriangle_t);
  343.           }
  344.     }
  345.     free(p);
  346.   }
  347.   else
  348.   {
  349.     Sys_Printf(" failed.\n");
  350.   }
  351.  
  352. #if 0
  353.   if (pModel->pTriList != NULL && pModel->nTriCount > 0 && !bMD3)
  354.   {
  355.       if(fabs(vMin[2]) < ((vMax[2]-vMin[2]) / 10.0))    // > 90% above 0 point.
  356.         pModel->nModelPosition = 1;
  357. //    sprintf (cPath, "%s/%sskin.pcx", ValueForKey(g_qeglobals.d_project_entity, "basepath"), pLocation);
  358.     sprintf (cPath, "%s/%s", ValueForKey(g_qeglobals.d_project_entity, "basepath"), cSkin);
  359.        pModel->nTextureBind = Texture_LoadSkin(cPath, &pModel->nSkinWidth, &pModel->nSkinHeight);
  360.     if (pModel->nTextureBind == -1)
  361.     {
  362. //      sprintf (cPath, "%sskin.pcx", pLocation);
  363.           strcpy (cPath, cSkin);
  364.       pModel->nTextureBind = Texture_LoadSkin(cPath, &pModel->nSkinWidth, &pModel->nSkinHeight);
  365.     }
  366.   }
  367. #endif
  368.  
  369. }
  370.  
  371. void setSpecialLoad(eclass_t *e, const char* pWhat, char*& p)
  372. {
  373.   CString str = e->comments;
  374.   int n = str.Find(pWhat);
  375.   if (n >= 0)
  376.   {
  377.     char* pText = e->comments + n + strlen(pWhat);
  378.     if (*pText == '\"')
  379.       pText++;
  380.  
  381.     str = "";
  382.     while (*pText != '\"' && *pText != '\0')
  383.     {
  384.       str += *pText;
  385.       pText++;
  386.     }
  387.     if (str.GetLength() > 0)
  388.     {         
  389.       p = strdup(str);
  390.       //--LoadModel(str, e);
  391.     }
  392.   }
  393. }
  394.  
  395. char    *debugname;
  396.  
  397. eclass_t *Eclass_InitFromText (char *text)
  398. {
  399.     char    *t;
  400.     int        len;
  401.     int        r, i;
  402.     char    parms[256], *p;
  403.     eclass_t    *e;
  404.     char    color[128];
  405.  
  406.     e = (eclass_t*)qmalloc(sizeof(*e));
  407.     memset (e, 0, sizeof(*e));
  408.     
  409.     text += strlen("/*QUAKED ");
  410.     
  411. // grab the name
  412.     text = COM_Parse (text);
  413.     e->name = (char*)qmalloc (strlen(com_token)+1);
  414.     strcpy (e->name, com_token);
  415.     debugname = e->name;
  416.     
  417. // grab the color, reformat as texture name
  418.     r = sscanf (text," (%f %f %f)", &e->color[0], &e->color[1], &e->color[2]);
  419.     if (r != 3)
  420.         return e;
  421.     sprintf (color, "(%f %f %f)", e->color[0], e->color[1], e->color[2]);
  422.     //strcpy (e->texdef.name, color);
  423.     e->texdef.SetName(color);
  424.  
  425.     while (*text != ')')
  426.     {
  427.         if (!*text)
  428.             return e;
  429.         text++;
  430.     }
  431.     text++;
  432.     
  433. // get the size    
  434.     text = COM_Parse (text);
  435.     if (com_token[0] == '(')
  436.     {    // parse the size as two vectors
  437.         e->fixedsize = true;
  438.         r = sscanf (text,"%f %f %f) (%f %f %f)", &e->mins[0], &e->mins[1], &e->mins[2],
  439.             &e->maxs[0], &e->maxs[1], &e->maxs[2]);
  440.         if (r != 6)
  441.             return e;
  442.  
  443.         for (i=0 ; i<2 ; i++)
  444.         {
  445.             while (*text != ')')
  446.             {
  447.                 if (!*text)
  448.                     return e;
  449.                 text++;
  450.             }
  451.             text++;
  452.         }
  453.     }
  454.     else
  455.     {    // use the brushes
  456.     }
  457.     
  458. // get the flags
  459.     
  460.  
  461. // copy to the first /n
  462.     p = parms;
  463.     while (*text && *text != '\n')
  464.         *p++ = *text++;
  465.     *p = 0;
  466.     text++;
  467.     
  468. // any remaining words are parm flags
  469.     p = parms;
  470.     for (i=0 ; i<8 ; i++)
  471.     {
  472.         p = COM_Parse (p);
  473.         if (!p)
  474.             break;
  475.         strcpy (e->flagnames[i], com_token);
  476.     } 
  477.  
  478. // find the length until close comment
  479.     for (t=text ; t[0] && !(t[0]=='*' && t[1]=='/') ; t++)
  480.     ;
  481.     
  482. // copy the comment block out
  483.     len = t-text;
  484.     e->comments = (char*)qmalloc (len+1);
  485.     memcpy (e->comments, text, len);
  486. #if 0
  487.     for (i=0 ; i<len ; i++)
  488.         if (text[i] == '\n')
  489.             e->comments[i] = '\r';
  490.         else
  491.             e->comments[i] = text[i];
  492. #endif
  493.     e->comments[len] = 0;
  494.     
  495.   setSpecialLoad(e, "model=", e->modelpath);
  496.   setSpecialLoad(e, "skin=", e->skinpath);
  497.   char *pFrame = NULL;
  498.   setSpecialLoad(e, "frame=", pFrame);
  499.   if (pFrame != NULL)
  500.   {
  501.     e->nFrame = atoi(pFrame);
  502.   }
  503.  
  504.   if(!e->skinpath)
  505.       setSpecialLoad(e, "texture=", e->skinpath);
  506.  
  507.   // setup show flags
  508.   e->nShowFlags = 0;
  509.   if (strcmpi(e->name, "light") == 0)
  510.   {
  511.     e->nShowFlags |= ECLASS_LIGHT;
  512.   }
  513.  
  514.   if (  (strnicmp(e->name, "info_player", strlen("info_player")) == 0)
  515.       ||(strnicmp(e->name, "path_corner", strlen("path_corner")) == 0) 
  516.       ||(strnicmp(e->name, "team_ctf", strlen("team_ctf")) == 0) )
  517.   {
  518.     e->nShowFlags |= ECLASS_ANGLE;
  519.   }
  520.   if (strcmpi(e->name, "path") == 0)
  521.   {
  522.     e->nShowFlags |= ECLASS_PATH;
  523.   }
  524.   if (strcmpi(e->name, "misc_model") == 0)
  525.   {
  526.     e->nShowFlags |= ECLASS_MISCMODEL;
  527.   }
  528.  
  529.  
  530.   return e;
  531. }
  532.  
  533. qboolean Eclass_hasModel(eclass_t *e, vec3_t &vMin, vec3_t &vMax)
  534. {
  535.   if (e->modelpath != NULL)
  536.   {
  537.     if (e->model == NULL)
  538.     {
  539.       e->model = reinterpret_cast<entitymodel_t*>(qmalloc(sizeof(entitymodel_t)));
  540.     }
  541.     char *pModelBuff = strdup(e->modelpath);
  542.     char *pSkinBuff = NULL;
  543.     if (e->skinpath)
  544.     {
  545.       pSkinBuff = strdup(e->skinpath);
  546.     }
  547.  
  548.     CStringList Models;
  549.     CStringList Skins;
  550.     char* pToken = strtok(pModelBuff, ";\0");
  551.     while (pToken != NULL)
  552.     {
  553.       Models.AddTail(pToken);
  554.       pToken = strtok(NULL, ";\0");
  555.     }
  556.  
  557.     if (pSkinBuff != NULL)
  558.     {
  559.       pToken = strtok(pSkinBuff, ";\0");
  560.       while (pToken != NULL)
  561.       {
  562.         Skins.AddTail(pToken);
  563.         pToken = strtok(NULL, ";\0");
  564.       }
  565.     }
  566.  
  567.     entitymodel *model = e->model;
  568.     for (int i = 0; i < Models.GetCount(); i++)
  569.     {
  570.       char *pSkin = NULL;
  571.       if (i < Skins.GetCount())
  572.       {
  573.         pSkin = Skins.GetAt(Skins.FindIndex(i)).GetBuffer(0);
  574.       }
  575.       LoadModel(Models.GetAt(Models.FindIndex(i)), e, vMin, vMax, model, pSkin);
  576.       model->pNext = reinterpret_cast<entitymodel_t*>(qmalloc(sizeof(entitymodel_t)));
  577.       model = model->pNext;
  578.     }
  579.  
  580.     // at this poitn vMin and vMax contain the min max of the model
  581.     // which needs to be centered at origin 0, 0, 0
  582.  
  583.     VectorSnap(vMin);
  584.     VectorSnap(vMax);
  585.  
  586.     if (vMax[0] - vMin[0] < 2)
  587.     {
  588.       vMin[0] -= 1;
  589.       vMax[0] += 1;
  590.     }
  591.  
  592.     if (vMin[1] - vMax[1] < 2)
  593.     {
  594.       vMin[1] -= 1;
  595.       vMax[1] += 1;
  596.     }
  597.  
  598.     if (vMax[2] - vMin[2] < 2)
  599.     {
  600.       vMax[2] -= 1;
  601.       vMax[2] += 1;
  602.     }
  603.  
  604.     vec3_t vTemp;
  605.     VectorAdd(vMin, vMax, vTemp);
  606.     VectorScale(vTemp, 0.5, vTemp);
  607.     model = e->model;
  608.     while (model != NULL)
  609.     {
  610.       for (i = 0; i < model->nTriCount; i++)
  611.       {
  612.         for (int j = 0; j < 3; j++)
  613.         {
  614.           ;//VectorSubtract(model->pTriList[i].v[j], vTemp, model->pTriList[i].v[j]);
  615.         }
  616.       }
  617.       model = model->pNext;
  618.     }
  619.  
  620.     free(pModelBuff);
  621.     free(e->modelpath);
  622.     e->modelpath = NULL;
  623.       
  624.     if(e->skinpath)
  625.       {
  626.           free(e->skinpath);
  627.           e->skinpath = NULL;
  628.       free(pSkinBuff);
  629.       }
  630.  
  631.   }
  632.   return (e->model != NULL && e->model->nTriCount > 0);
  633. }
  634.  
  635.  
  636. void EClass_InsertSortedList(eclass_t *&pList, eclass_t *e)
  637. {
  638.     eclass_t    *s;
  639.     
  640.     if (!pList)
  641.     {
  642.         pList = e;
  643.         return;
  644.     }
  645.  
  646.  
  647.     s = pList;
  648.     if (stricmp (e->name, s->name) < 0)
  649.     {
  650.         e->next = s;
  651.         pList = e;
  652.         return;
  653.     }
  654.  
  655.     do
  656.     {
  657.         if (!s->next || stricmp (e->name, s->next->name) < 0)
  658.         {
  659.             e->next = s->next;
  660.             s->next = e;
  661.             return;
  662.         }
  663.         s=s->next;
  664.     } while (1);
  665. }
  666.  
  667. /*
  668. =================
  669. Eclass_InsertAlphabetized
  670. =================
  671. */
  672. void Eclass_InsertAlphabetized (eclass_t *e)
  673. {
  674. #if 1
  675.   EClass_InsertSortedList(eclass, e);
  676. #else
  677.     eclass_t    *s;
  678.     
  679.     if (!eclass)
  680.     {
  681.         eclass = e;
  682.         return;
  683.     }
  684.  
  685.  
  686.     s = eclass;
  687.     if (stricmp (e->name, s->name) < 0)
  688.     {
  689.         e->next = s;
  690.         eclass = e;
  691.         return;
  692.     }
  693.  
  694.     do
  695.     {
  696.         if (!s->next || stricmp (e->name, s->next->name) < 0)
  697.         {
  698.             e->next = s->next;
  699.             s->next = e;
  700.             return;
  701.         }
  702.         s=s->next;
  703.     } while (1);
  704. #endif
  705. }
  706.  
  707.  
  708. /*
  709. =================
  710. Eclass_ScanFile
  711. =================
  712. */
  713.  
  714. qboolean parsing_single = false;
  715. qboolean eclass_found;
  716. eclass_t *eclass_e;
  717. //#ifdef BUILD_LIST
  718. extern bool g_bBuildList;
  719. CString strDefFile;
  720. //#endif
  721. void Eclass_ScanFile (char *filename)
  722. {
  723.     int        size;
  724.     char    *data;
  725.     eclass_t    *e;
  726.     int        i;
  727.     char    temp[1024];
  728.     
  729.     QE_ConvertDOSToUnixName( temp, filename );
  730.     
  731.     Sys_Printf ("ScanFile: %s\n", temp);
  732.     
  733.     // BUG
  734.     size = LoadFile (filename, (void**)&data);
  735.     eclass_found = false;
  736.     for (i=0 ; i<size ; i++)
  737.         if (!strncmp(data+i, "/*QUAKED",8))
  738.         {
  739.             
  740.             //#ifdef BUILD_LIST
  741.             if (g_bBuildList)
  742.             {
  743.                 CString strDef = "";
  744.                 int j = i;
  745.                 while (1)
  746.                 {
  747.                     strDef += *(data+j);
  748.                     if (*(data+j) == '/' && *(data+j-1) == '*')
  749.                         break;
  750.                     j++;
  751.                 }
  752.                 strDef += "\r\n\r\n\r\n";
  753.                 strDefFile += strDef;
  754.             }
  755.             //#endif
  756.             e = Eclass_InitFromText (data+i);
  757.             if (e)
  758.                 Eclass_InsertAlphabetized (e);
  759.             else
  760.                 printf ("Error parsing: %s in %s\n",debugname, filename);
  761.  
  762.             // single ?
  763.             eclass_e = e;
  764.             eclass_found = true;
  765.             if ( parsing_single )
  766.                 break;
  767.         }
  768.         
  769.         free (data);        
  770. }
  771.  
  772.  
  773.  
  774. void Eclass_InitForSourceDirectory (char *path)
  775. {
  776.     struct _finddata_t fileinfo;
  777.     int        handle;
  778.     char    filename[1024];
  779.     char    filebase[1024];
  780.     char    temp[1024];
  781.     char    *s;
  782.  
  783.     QE_ConvertDOSToUnixName( temp, path );
  784.  
  785.     Sys_Printf ("Eclass_InitForSourceDirectory: %s\n", temp );
  786.  
  787.     strcpy (filebase, path);
  788.     s = filebase + strlen(filebase)-1;
  789.     while (*s != '\\' && *s != '/' && s!=filebase)
  790.         s--;
  791.     *s = 0;
  792.  
  793.   CleanUpEntities();
  794.     eclass = NULL;
  795. //#ifdef BUILD_LIST
  796.   if (g_bBuildList)
  797.     strDefFile = "";
  798. //#endif
  799.     handle = _findfirst (path, &fileinfo);
  800.     if (handle != -1)
  801.     {
  802.         do
  803.         {
  804.             sprintf (filename, "%s\\%s", filebase, fileinfo.name);
  805.             Eclass_ScanFile (filename);
  806.         } while (_findnext( handle, &fileinfo ) != -1);
  807.  
  808.         _findclose (handle);
  809.     }
  810.  
  811. //#ifdef BUILD_LIST
  812.   if (g_bBuildList)
  813.   {
  814.     CFile file;
  815.     if (file.Open("c:\\entities.def", CFile::modeCreate | CFile::modeWrite)) 
  816.     {
  817.       file.Write(strDefFile.GetBuffer(0), strDefFile.GetLength());
  818.       file.Close();
  819.     }
  820.   }
  821. //#endif
  822.  
  823.     eclass_bad = Eclass_InitFromText ("/*QUAKED UNKNOWN_CLASS (0 0.5 0) ?");
  824. }
  825.  
  826. eclass_t *Eclass_ForName (char *name, qboolean has_brushes)
  827. {
  828.     eclass_t    *e;
  829.     char        init[1024];
  830.  
  831. #ifdef _DEBUG
  832.   // grouping stuff, not an eclass
  833.   if (strcmp(name, "group_info")==0)
  834.     Sys_Printf("WARNING: unexpected group_info entity in Eclass_ForName\n");
  835. #endif
  836.  
  837.     if (!name)
  838.         return eclass_bad;
  839.  
  840.     for (e=eclass ; e ; e=e->next)
  841.         if (!strcmp (name, e->name))
  842.             return e;
  843.  
  844.     // create a new class for it
  845.     if (has_brushes)
  846.     {
  847.         sprintf (init, "/*QUAKED %s (0 0.5 0) ?\nNot found in source.\n", name);
  848.         e = Eclass_InitFromText (init);
  849.     }
  850.     else
  851.     {
  852.         sprintf (init, "/*QUAKED %s (0 0.5 0) (-8 -8 -8) (8 8 8)\nNot found in source.\n", name);
  853.         e = Eclass_InitFromText (init);
  854.     }
  855.  
  856.     Eclass_InsertAlphabetized (e);
  857.  
  858.     return e;
  859. }
  860.  
  861.  
  862. eclass_t* GetCachedModel(entity_t *pEntity, const char *pName, vec3_t &vMin, vec3_t &vMax)
  863. {
  864.  
  865.     eclass_t *e = NULL;
  866.   if (pName == NULL || strlen(pName) == 0)
  867.   {
  868.     return NULL;
  869.   }
  870.  
  871.     for (e = g_md3Cache; e ; e = e->next)
  872.   {
  873.         if (!strcmp (pName, e->name))
  874.     {
  875.       pEntity->md3Class = e;
  876.       VectorCopy(e->mins, vMin);
  877.       VectorCopy(e->maxs, vMax);
  878.             return e;
  879.     }
  880.   }
  881.  
  882.     e = (eclass_t*)qmalloc(sizeof(*e));
  883.     memset (e, 0, sizeof(*e));
  884.   e->name = strdup(pName);
  885.   e->modelpath = strdup(pName);
  886.   e->skinpath = strdup(pName);
  887.   char *p = strstr(e->skinpath, ".md3");
  888.   if (p != NULL)
  889.   {
  890.     p++;
  891.     strncpy(p, "tga", 3);
  892.   }
  893.   else
  894.   {
  895.     free(e->skinpath);
  896.     e->skinpath = NULL;
  897.   }
  898.  
  899.   e->color[0] = e->color[2] = 0.85;
  900.  
  901.   if (Eclass_hasModel(e, vMin, vMax))
  902.   {
  903.     EClass_InsertSortedList(g_md3Cache, e);
  904.     VectorCopy(vMin, e->mins);
  905.     VectorCopy(vMax, e->maxs);
  906.     pEntity->md3Class = e;
  907.     return e;
  908.   }
  909.  
  910.   return NULL;
  911. }
  912.