Quake-III-Arena

Quake III Arena GPL Source Release
Log | Files | Refs

ECLASS.CPP (21201B)


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