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 }