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