2 Copyright (C) 1999-2007 id Software, Inc. and contributors.
3 For a list of contributors, see the accompanying CONTRIBUTORS file.
5 This file is part of GtkRadiant.
7 GtkRadiant is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
12 GtkRadiant is distributed in the hope that it will be useful,
13 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.
17 You should have received a copy of the GNU General Public License
18 along with GtkRadiant; if not, write to the Free Software
19 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
24 #if defined (__linux__) || defined (__APPLE__)
29 eclass_t *eclass = NULL;
30 eclass_t *eclass_bad = NULL;
31 const vec3_t smallbox[2] = {{-8,-8,-8},{8,8,8}};
32 char eclass_directory[1024];
34 qboolean parsing_single = false;
38 implementation of the EClass manager API
40 eclass_t** Get_EClass_E()
45 void Set_Eclass_Found(qboolean b)
50 qboolean Get_Parsing_Single()
52 return parsing_single;
56 // md3 cache for misc_models
57 //eclass_t *g_md3Cache = NULL;
61 the classname, color triple, and bounding box are parsed out of comments
62 A ? size means take the exact brush size.
64 / *QUAKED <classname> (0 0 0) ?
65 / *QUAKED <classname> (0 0 0) (-8 -8 -8) (8 8 8)
67 Flag names can follow the size description:
69 / *QUAKED func_door (0 .5 .8) ? START_OPEN STONE_SOUND DOOR_DONT_LINK GOLD_KEY SILVER_KEY
73 void CleanEntityList(eclass_t *&pList)
77 eclass_t* pTemp = pList->next;
79 entitymodel *model = pList->model;
82 delete []model->pTriList;
84 g_string_free( (GString *)model->strSkin, TRUE );
85 model->strSkin = NULL;
89 if (pList->modelpath) {
90 free(pList->modelpath);
91 pList->modelpath = NULL;
93 if (pList->skinpath) {
94 free(pList->skinpath);
95 pList->skinpath = NULL;
99 free(pList->comments);
109 void CleanUpEntities()
111 // NOTE: maybe some leak checks needed .. older versions of Radiant looked like they were freezing more stuff
112 CleanEntityList(eclass);
113 //CleanEntityList(g_md3Cache);
116 free(eclass_bad->name);
117 free(eclass_bad->comments);
123 void EClass_InsertSortedList(eclass_t *&pList, eclass_t *e)
135 if (stricmp (e->name, s->name) < 0)
144 if (!s->next || stricmp (e->name, s->next->name) < 0)
156 Eclass_InsertAlphabetized
159 void Eclass_InsertAlphabetized (eclass_t *e)
162 EClass_InsertSortedList(eclass, e);
174 if (stricmp (e->name, s->name) < 0)
183 if (!s->next || stricmp (e->name, s->next->name) < 0)
195 This looks at each eclass_t, if it has a "modelpath" set then it leaves it alone
196 if it's not set it checks to see if a file called "sprites/<eclassname>.*" exists, and
197 if it does exist then it sets the "modelpath" to "sprites/<eclassname>.spr"
199 void Eclass_CreateSpriteModelPaths()
201 int Counts[4] = { 0, 0, 0, 0 };
202 char filename[512]; // should be big enough, ExtractFileBase doesn't take a buffer size...
205 // get a list of all sprite/*>* files in all sprite/ directories
206 Sys_Printf("Searching VFS for files in sprites/*.* that match entity names...\n");
207 GSList *pFiles = vfsGetFileList("sprites", NULL);
213 // find an eclass without a modelpath.
214 for (e=eclass ; e ; e=e->next)
220 Sys_Printf("Ignoring sprite for entity %s (modelpath: \"%s\")\n",e->name,e->modelpath);
223 continue; // ignore this eclass, it's already got a model
226 // TODO: remove this check when we can have sprites for non-fixed size entities.
230 Sys_Printf("Ignoring sprite for non-fixed-size entity %s\n",e->name);
233 continue; // can't have sprites for non-fixed size entities (yet!)
237 Sys_Printf("Searching for sprite for fixed-size entity %s...",e->name);
239 pFile = pFiles; // point to start of list
241 // look for a file that has the same name, with any extension.
246 // strip the path/ and the .extension.
247 ExtractFileBase((char *)pFile->data,filename);
249 // does the eclass name match the filename?
250 if (stricmp(e->name,filename) == 0)
252 // yes, so generate a sprite filename using the all-encompasing .spr extension
253 // so that the model wrapper knows the sprite model plugin will be the model
254 // plugin used to render it.
255 CString strSpriteName;
256 strSpriteName.Format("sprites/%s.spr",e->name);
257 e->modelpath = strdup(strSpriteName.GetBuffer());
258 Sys_Printf("Found! (\"%s\")\n",(char *)pFile->data);
266 Sys_Printf("not found\n");
270 vfsClearFileDirList(&pFiles);
272 Sys_Printf("%d entities were scanned\n"
273 "%d entities that already had models/sprites were ignored\n"
274 "%d non-fixed-size entities were ignored\n"
275 "%d entities did not have matching sprite files\n"
276 "%d entities had sprite files and have been attached\n",
277 Counts[0],Counts[1],Counts[2],Counts[0]-Counts[3],Counts[3]);
281 void EClass_InitForFileList(GSList *pFiles, _EClassTable *pTable)
283 GSList *pFile = pFiles;
286 // for a given name, we grab the first .def in the vfs
287 // this allows to override baseq3/scripts/entities.def for instance
288 char relPath[PATH_MAX];
289 strcpy(relPath, "scripts/");
290 strcat(relPath, (char*)pFile->data);
291 if (!vfsGetFullPath(relPath, 0, 0))
293 Sys_FPrintf(SYS_ERR, "Failed to find the full path for '%s' in the VFS\n", relPath);
296 pTable->m_pfnScanFile(vfsGetFullPath(relPath, 0, 0));
302 Manually create an eclass_t, for when no modules exist.
303 this replaces and centralizes the eclass_t allocation
305 eclass_t * EClass_Create( const char *name, float col1, float col2, float col3, const vec3_t *mins, const vec3_t *maxs, const char *comments )
310 e = (eclass_t*)malloc(sizeof(*e));
311 memset (e, 0, sizeof(*e));
313 e->name = strdup(name);
315 // grab the color, reformat as texture name
319 sprintf (color, "(%f %f %f)", e->color[0], e->color[1], e->color[2]);
320 e->texdef.SetName(color);
326 // If we set worldspawn to be a fixed-size all the textures are
327 // displayed as flat-shaded. This is a KLUDGE now that we have
328 // multiple game support as the worldspawn entity is game specific.
329 // Note that this is only ever fixed for the user if a definition
330 // for the worldspawn entity was not loaded, this can happen for
332 // a) no entity definition plugin exists
333 // b) no entity definition files were found
334 // c) no entity definition file contained an entry for worldspawn.
336 if (stricmp(name,"worldspawn") != 0) e->fixedsize = true;
339 memcpy(e->mins,mins,sizeof(vec3_t));
340 memcpy(e->maxs,maxs,sizeof(vec3_t));
344 e->comments = strdup(comments);
347 e->comments = (char*)malloc(1);
348 e->comments[0] = '\0';
358 // start by creating the default unknown eclass
359 eclass_bad = EClass_Create("UNKNOWN_CLASS" , 0, 0.5, 0,NULL,NULL,NULL);
361 // now scan the definitions
362 _EClassTable *pTable = &g_EClassDefTable;
365 // read in all scripts/*.<extension>
366 pFiles = vfsGetFileList("scripts", pTable->m_pfnGetExtension());
369 GSList *pFile = pFiles;
373 \todo the MP/SP filtering rules need to be CLEANED UP and SANITIZED
376 // JKII SP/MP mapping mode
377 if (g_pGameDescription->mGameFile == "jk2.game" || g_pGameDescription->mGameFile == "ja.game")
379 if (!strcmp(ValueForKey(g_qeglobals.d_project_entity, "gamemode"), "sp"))
381 // SP mapping, ignore mp_*.def
382 char *name = (char *)pFile->data;
383 if (name[0]=='m' && name[1]=='p' && name[2]=='_')
385 Sys_Printf("Single Player mapping mode. Ignoring '%s'\n", name);
392 // MP mapping, ignore sp_*.def
393 char *name = (char *)pFile->data;
394 if (name[0]=='s' && name[1]=='p' && name[2]=='_')
396 Sys_Printf("Multiplayer mapping mode. Ignoring '%s'\n", name);
403 // STVEF SP/MP mapping mode
404 else if (g_pGameDescription->mGameFile == "stvef.game")
406 if (!strcmp(ValueForKey(g_qeglobals.d_project_entity, "gamemode"), "sp"))
408 // SP mapping, ignore mp_*.def
409 char *name = (char *)pFile->data;
410 if (name[0]=='m' && name[1]=='p' && name[2]=='_')
412 Sys_Printf("Single Player mapping mode. Ignoring '%s'\n", name);
419 // HM mapping, ignore sp_*.def
420 char *name = (char *)pFile->data;
421 if (name[0]=='h' && name[1]=='m' && name[2]=='_')
423 Sys_Printf("HoloMatch mapping mode. Ignoring '%s'\n", name);
429 // for a given name, we grab the first .def in the vfs
430 // this allows to override baseq3/scripts/entities.def for instance
431 char relPath[PATH_MAX];
432 strcpy(relPath, "scripts/");
433 strcat(relPath, (char*)pFile->data);
434 char *fullpath = vfsGetFullPath(relPath, 0, 0);
437 Sys_FPrintf(SYS_ERR, "Failed to find the full path for \"%s\" in the VFS\n", relPath);
440 pTable->m_pfnScanFile(fullpath);
441 if (g_pGameDescription->mEClassSingleLoad)
445 vfsClearFileDirList(&pFiles);
449 Sys_FPrintf(SYS_ERR, "Didn't find any scripts/*.%s files to load EClass information\n", pTable->m_pfnGetExtension());
451 // we deal with two formats max, if the other table exists, loop again
452 if (g_bHaveEClassExt && pTable == &g_EClassDefTable)
453 pTable = &g_EClassExtTable;
455 pTable = NULL; // done, exit
457 Eclass_CreateSpriteModelPaths();
460 eclass_t *Eclass_ForName (const char *name, qboolean has_brushes)
464 if (!name || *name == '\0')
468 // grouping stuff, not an eclass
469 if (strcmp(name, "group_info")==0)
470 Sys_Printf("WARNING: unexpected group_info entity in Eclass_ForName\n");
476 for (e=eclass ; e ; e=e->next)
477 if (!strcmp (name, e->name))
480 // create a new class for it
483 e = EClass_Create(name , 0, 0.5, 0,NULL,NULL,"Not found in source.");
487 e = EClass_Create(name , 0, 0.5, 0,&smallbox[0],&smallbox[1],"Not found in source.");
490 Eclass_InsertAlphabetized (e);