2 Copyright (C) 2001-2006, William Joseph.
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
22 #include "eclass_doom3.h"
24 #include "debugging/debugging.h"
28 #include "ifilesystem.h"
29 #include "iscriplib.h"
31 #include "qerplugin.h"
33 #include "generic/callback.h"
34 #include "string/string.h"
35 #include "eclasslib.h"
38 #include "stream/stringstream.h"
39 #include "moduleobservers.h"
46 RawString(const char* value) : m_value(value)
49 const char* c_str() const
55 inline bool operator<(const RawString& self, const RawString& other)
57 return string_less_nocase(self.c_str(), other.c_str());
60 typedef std::map<RawString, EntityClass*> EntityClasses;
61 EntityClasses g_EntityClassDoom3_classes;
62 EntityClass *g_EntityClassDoom3_bad = 0;
65 void EntityClassDoom3_clear()
67 for(EntityClasses::iterator i = g_EntityClassDoom3_classes.begin(); i != g_EntityClassDoom3_classes.end(); ++i)
69 (*i).second->free((*i).second);
71 g_EntityClassDoom3_classes.clear();
74 // entityClass will be inserted only if another of the same name does not already exist.
75 // if entityClass was inserted, the same object is returned, otherwise the already-existing object is returned.
76 EntityClass* EntityClassDoom3_insertUnique(EntityClass* entityClass)
78 return (*g_EntityClassDoom3_classes.insert(EntityClasses::value_type(entityClass->name(), entityClass)).first).second;
81 void EntityClassDoom3_forEach(EntityClassVisitor& visitor)
83 for(EntityClasses::iterator i = g_EntityClassDoom3_classes.begin(); i != g_EntityClassDoom3_classes.end(); ++i)
85 visitor.visit((*i).second);
89 inline void printParseError(const char* message)
91 globalErrorStream() << message;
94 #define PARSE_RETURN_FALSE_IF_FAIL(expression) if(!(expression)) { printParseError(FILE_LINE "\nparse failed: " #expression "\n"); return false; } else
96 bool EntityClassDoom3_parseToken(Tokeniser& tokeniser)
98 const char* token = tokeniser.getToken();
99 PARSE_RETURN_FALSE_IF_FAIL(token != 0);
103 bool EntityClassDoom3_parseToken(Tokeniser& tokeniser, const char* string)
105 const char* token = tokeniser.getToken();
106 PARSE_RETURN_FALSE_IF_FAIL(token != 0);
107 return string_equal(token, string);
110 bool EntityClassDoom3_parseString(Tokeniser& tokeniser, const char*& s)
112 const char* token = tokeniser.getToken();
113 PARSE_RETURN_FALSE_IF_FAIL(token != 0);
118 bool EntityClassDoom3_parseString(Tokeniser& tokeniser, CopiedString& s)
120 const char* token = tokeniser.getToken();
121 PARSE_RETURN_FALSE_IF_FAIL(token != 0);
126 bool EntityClassDoom3_parseString(Tokeniser& tokeniser, StringOutputStream& s)
128 const char* token = tokeniser.getToken();
129 PARSE_RETURN_FALSE_IF_FAIL(token != 0);
134 bool EntityClassDoom3_parseUnknown(Tokeniser& tokeniser)
137 PARSE_RETURN_FALSE_IF_FAIL(EntityClassDoom3_parseToken(tokeniser));
139 //globalOutputStream() << "parsing unknown block " << makeQuoted(name) << "\n";
141 PARSE_RETURN_FALSE_IF_FAIL(EntityClassDoom3_parseToken(tokeniser, "{"));
142 tokeniser.nextLine();
144 std::size_t depth = 1;
148 PARSE_RETURN_FALSE_IF_FAIL(EntityClassDoom3_parseString(tokeniser, token));
149 if(string_equal(token, "}"))
153 tokeniser.nextLine();
157 else if(string_equal(token, "{"))
161 tokeniser.nextLine();
173 CopiedString m_parent;
174 typedef std::map<CopiedString, CopiedString> Anims;
176 Model() : m_resolved(false)
181 typedef std::map<CopiedString, Model> Models;
185 void Model_resolveInheritance(const char* name, Model& model)
187 if(model.m_resolved == false)
189 model.m_resolved = true;
191 if(!string_empty(model.m_parent.c_str()))
193 Models::iterator i = g_models.find(model.m_parent);
194 if(i == g_models.end())
196 globalErrorStream() << "model " << name << " inherits unknown model " << model.m_parent.c_str() << "\n";
200 Model_resolveInheritance((*i).first.c_str(), (*i).second);
201 model.m_mesh = (*i).second.m_mesh;
202 model.m_skin = (*i).second.m_skin;
208 bool EntityClassDoom3_parseModel(Tokeniser& tokeniser)
211 PARSE_RETURN_FALSE_IF_FAIL(EntityClassDoom3_parseString(tokeniser, name));
213 Model& model = g_models[name];
215 PARSE_RETURN_FALSE_IF_FAIL(EntityClassDoom3_parseToken(tokeniser, "{"));
216 tokeniser.nextLine();
220 const char* parameter;
221 PARSE_RETURN_FALSE_IF_FAIL(EntityClassDoom3_parseString(tokeniser, parameter));
222 if(string_equal(parameter, "}"))
224 tokeniser.nextLine();
227 else if(string_equal(parameter, "inherit"))
229 PARSE_RETURN_FALSE_IF_FAIL(EntityClassDoom3_parseString(tokeniser, model.m_parent));
230 tokeniser.nextLine();
232 else if(string_equal(parameter, "remove"))
234 //const char* remove =
235 PARSE_RETURN_FALSE_IF_FAIL(EntityClassDoom3_parseToken(tokeniser));
236 tokeniser.nextLine();
238 else if(string_equal(parameter, "mesh"))
240 PARSE_RETURN_FALSE_IF_FAIL(EntityClassDoom3_parseString(tokeniser, model.m_mesh));
241 tokeniser.nextLine();
243 else if(string_equal(parameter, "skin"))
245 PARSE_RETURN_FALSE_IF_FAIL(EntityClassDoom3_parseString(tokeniser, model.m_skin));
246 tokeniser.nextLine();
248 else if(string_equal(parameter, "offset"))
250 PARSE_RETURN_FALSE_IF_FAIL(EntityClassDoom3_parseToken(tokeniser, "("));
251 PARSE_RETURN_FALSE_IF_FAIL(EntityClassDoom3_parseToken(tokeniser));
252 PARSE_RETURN_FALSE_IF_FAIL(EntityClassDoom3_parseToken(tokeniser));
253 PARSE_RETURN_FALSE_IF_FAIL(EntityClassDoom3_parseToken(tokeniser));
254 PARSE_RETURN_FALSE_IF_FAIL(EntityClassDoom3_parseToken(tokeniser, ")"));
255 tokeniser.nextLine();
257 else if(string_equal(parameter, "channel"))
259 //const char* channelName =
260 PARSE_RETURN_FALSE_IF_FAIL(EntityClassDoom3_parseToken(tokeniser));
261 PARSE_RETURN_FALSE_IF_FAIL(EntityClassDoom3_parseToken(tokeniser, "("));
265 PARSE_RETURN_FALSE_IF_FAIL(EntityClassDoom3_parseString(tokeniser, end));
266 if(string_equal(end, ")"))
268 tokeniser.nextLine();
273 else if(string_equal(parameter, "anim"))
275 CopiedString animName;
276 PARSE_RETURN_FALSE_IF_FAIL(EntityClassDoom3_parseString(tokeniser, animName));
277 const char* animFile;
278 PARSE_RETURN_FALSE_IF_FAIL(EntityClassDoom3_parseString(tokeniser, animFile));
279 model.m_anims.insert(Model::Anims::value_type(animName, animFile));
282 PARSE_RETURN_FALSE_IF_FAIL(EntityClassDoom3_parseString(tokeniser, token));
284 while(string_equal(token, ","))
286 PARSE_RETURN_FALSE_IF_FAIL(EntityClassDoom3_parseString(tokeniser, animFile));
287 PARSE_RETURN_FALSE_IF_FAIL(EntityClassDoom3_parseString(tokeniser, token));
290 if(string_equal(token, "{"))
295 PARSE_RETURN_FALSE_IF_FAIL(EntityClassDoom3_parseString(tokeniser, end));
296 if(string_equal(end, "}"))
298 tokeniser.nextLine();
301 tokeniser.nextLine();
306 tokeniser.ungetToken();
311 globalErrorStream() << "unknown model parameter: " << makeQuoted(parameter) << "\n";
314 tokeniser.nextLine();
319 inline bool char_isSpaceOrTab(char c)
321 return c == ' ' || c == '\t';
324 inline bool char_isNotSpaceOrTab(char c)
326 return !char_isSpaceOrTab(c);
329 template<typename Predicate>
330 inline const char* string_find_if(const char* string, Predicate predicate)
332 for(; *string != 0; ++string)
334 if(predicate(*string))
342 inline const char* string_findFirstSpaceOrTab(const char* string)
344 return string_find_if(string, char_isSpaceOrTab);
347 inline const char* string_findFirstNonSpaceOrTab(const char* string)
349 return string_find_if(string, char_isNotSpaceOrTab);
353 static bool EntityClass_parse(EntityClass& entityClass, Tokeniser& tokeniser)
355 PARSE_RETURN_FALSE_IF_FAIL(EntityClassDoom3_parseString(tokeniser, entityClass.m_name));
357 PARSE_RETURN_FALSE_IF_FAIL(EntityClassDoom3_parseToken(tokeniser, "{"));
358 tokeniser.nextLine();
360 StringOutputStream usage(256);
361 StringOutputStream description(256);
362 CopiedString* currentDescription = 0;
363 StringOutputStream* currentString = 0;
368 PARSE_RETURN_FALSE_IF_FAIL(EntityClassDoom3_parseString(tokeniser, key));
370 const char* last = string_findFirstSpaceOrTab(key);
371 CopiedString first(StringRange(key, last));
373 if(!string_empty(last))
375 last = string_findFirstNonSpaceOrTab(last);
378 if(currentString != 0 && string_equal(key, "\\"))
380 tokeniser.nextLine();
381 *currentString << " ";
382 PARSE_RETURN_FALSE_IF_FAIL(EntityClassDoom3_parseString(tokeniser, *currentString));
386 if(currentDescription != 0)
388 *currentDescription = description.c_str();
390 currentDescription = 0;
394 if(string_equal(key, "}"))
396 tokeniser.nextLine();
399 else if(string_equal(key, "model"))
402 PARSE_RETURN_FALSE_IF_FAIL(EntityClassDoom3_parseString(tokeniser, token));
403 entityClass.fixedsize = true;
404 StringOutputStream buffer(256);
405 buffer << PathCleaned(token);
406 entityClass.m_modelpath = buffer.c_str();
408 else if(string_equal(key, "editor_color"))
411 PARSE_RETURN_FALSE_IF_FAIL(EntityClassDoom3_parseString(tokeniser, value));
412 if(!string_empty(value))
414 entityClass.colorSpecified = true;
415 bool success = string_parse_vector3(value, entityClass.color);
416 ASSERT_MESSAGE(success, "editor_color: parse error");
419 else if(string_equal(key, "editor_ragdoll"))
421 //bool ragdoll = atoi(tokeniser.getToken()) != 0;
422 PARSE_RETURN_FALSE_IF_FAIL(EntityClassDoom3_parseToken(tokeniser));
424 else if(string_equal(key, "editor_mins"))
426 entityClass.sizeSpecified = true;
428 PARSE_RETURN_FALSE_IF_FAIL(EntityClassDoom3_parseString(tokeniser, value));
429 if(!string_empty(value) && !string_equal(value, "?"))
431 entityClass.fixedsize = true;
432 bool success = string_parse_vector3(value, entityClass.mins);
433 ASSERT_MESSAGE(success, "editor_mins: parse error");
436 else if(string_equal(key, "editor_maxs"))
438 entityClass.sizeSpecified = true;
440 PARSE_RETURN_FALSE_IF_FAIL(EntityClassDoom3_parseString(tokeniser, value));
441 if(!string_empty(value) && !string_equal(value, "?"))
443 entityClass.fixedsize = true;
444 bool success = string_parse_vector3(value, entityClass.maxs);
445 ASSERT_MESSAGE(success, "editor_maxs: parse error");
448 else if(string_equal(key, "editor_usage"))
450 PARSE_RETURN_FALSE_IF_FAIL(EntityClassDoom3_parseString(tokeniser, usage));
451 currentString = &usage;
453 else if(string_equal_n(key, "editor_usage", 12))
455 PARSE_RETURN_FALSE_IF_FAIL(EntityClassDoom3_parseString(tokeniser, usage));
456 currentString = &usage;
458 else if(string_equal(key, "editor_rotatable")
459 || string_equal(key, "editor_showangle")
460 || string_equal(key, "editor_showangles") // typo? in prey movables.def
461 || string_equal(key, "editor_mover")
462 || string_equal(key, "editor_model")
463 || string_equal(key, "editor_material")
464 || string_equal(key, "editor_combatnode")
465 || (!string_empty(last) && string_equal(first.c_str(), "editor_gui"))
466 || string_equal_n(key, "editor_copy", 11))
468 PARSE_RETURN_FALSE_IF_FAIL(EntityClassDoom3_parseToken(tokeniser));
470 else if(!string_empty(last) && (string_equal(first.c_str(), "editor_var") || string_equal(first.c_str(), "editor_string")))
472 EntityClassAttribute& attribute = EntityClass_insertAttribute(entityClass, last).second;
473 attribute.m_type = "string";
474 currentDescription = &attribute.m_description;
475 currentString = &description;
476 PARSE_RETURN_FALSE_IF_FAIL(EntityClassDoom3_parseString(tokeniser, description));
478 else if(!string_empty(last) && string_equal(first.c_str(), "editor_float"))
480 EntityClassAttribute& attribute = EntityClass_insertAttribute(entityClass, last).second;
481 attribute.m_type = "string";
482 currentDescription = &attribute.m_description;
483 currentString = &description;
484 PARSE_RETURN_FALSE_IF_FAIL(EntityClassDoom3_parseString(tokeniser, description));
486 else if(!string_empty(last) && string_equal(first.c_str(), "editor_snd"))
488 EntityClassAttribute& attribute = EntityClass_insertAttribute(entityClass, last).second;
489 attribute.m_type = "sound";
490 currentDescription = &attribute.m_description;
491 currentString = &description;
492 PARSE_RETURN_FALSE_IF_FAIL(EntityClassDoom3_parseString(tokeniser, description));
494 else if(!string_empty(last) && string_equal(first.c_str(), "editor_bool"))
496 EntityClassAttribute& attribute = EntityClass_insertAttribute(entityClass, last).second;
497 attribute.m_type = "boolean";
498 currentDescription = &attribute.m_description;
499 currentString = &description;
500 PARSE_RETURN_FALSE_IF_FAIL(EntityClassDoom3_parseString(tokeniser, description));
502 else if(!string_empty(last) && string_equal(first.c_str(), "editor_int"))
504 EntityClassAttribute& attribute = EntityClass_insertAttribute(entityClass, last).second;
505 attribute.m_type = "integer";
506 currentDescription = &attribute.m_description;
507 currentString = &description;
508 PARSE_RETURN_FALSE_IF_FAIL(EntityClassDoom3_parseString(tokeniser, description));
510 else if(!string_empty(last) && string_equal(first.c_str(), "editor_model"))
512 EntityClassAttribute& attribute = EntityClass_insertAttribute(entityClass, last).second;
513 attribute.m_type = "model";
514 currentDescription = &attribute.m_description;
515 currentString = &description;
516 PARSE_RETURN_FALSE_IF_FAIL(EntityClassDoom3_parseString(tokeniser, description));
518 else if(!string_empty(last) && string_equal(first.c_str(), "editor_color"))
520 EntityClassAttribute& attribute = EntityClass_insertAttribute(entityClass, last).second;
521 attribute.m_type = "color";
522 currentDescription = &attribute.m_description;
523 currentString = &description;
524 PARSE_RETURN_FALSE_IF_FAIL(EntityClassDoom3_parseString(tokeniser, description));
526 else if(!string_empty(last) && (string_equal(first.c_str(), "editor_material") || string_equal(first.c_str(), "editor_mat")))
528 EntityClassAttribute& attribute = EntityClass_insertAttribute(entityClass, last).second;
529 attribute.m_type = "shader";
530 currentDescription = &attribute.m_description;
531 currentString = &description;
532 PARSE_RETURN_FALSE_IF_FAIL(EntityClassDoom3_parseString(tokeniser, description));
534 else if(string_equal(key, "inherit"))
536 entityClass.inheritanceResolved = false;
537 ASSERT_MESSAGE(entityClass.m_parent.empty(), "only one 'inherit' supported per entityDef");
539 PARSE_RETURN_FALSE_IF_FAIL(EntityClassDoom3_parseString(tokeniser, token));
540 entityClass.m_parent.push_back(token);
542 // begin quake4-specific keys
543 else if(string_equal(key, "editor_targetonsel"))
545 //const char* value =
546 PARSE_RETURN_FALSE_IF_FAIL(EntityClassDoom3_parseToken(tokeniser));
548 else if(string_equal(key, "editor_menu"))
550 //const char* value =
551 PARSE_RETURN_FALSE_IF_FAIL(EntityClassDoom3_parseToken(tokeniser));
553 else if(string_equal(key, "editor_ignore"))
555 //const char* value =
556 PARSE_RETURN_FALSE_IF_FAIL(EntityClassDoom3_parseToken(tokeniser));
558 // end quake4-specific keys
559 // begin ignore prey (unknown/unused?) entity keys
560 else if(string_equal(key, "editor_light")
561 || string_equal(key, "editor_def def_debrisspawner")
562 || string_equal(key, "editor_def def_drop")
563 || string_equal(key, "editor_def def_guihand")
564 || string_equal(key, "editor_def def_mine"))
566 //const char* value =
567 PARSE_RETURN_FALSE_IF_FAIL(EntityClassDoom3_parseToken(tokeniser));
569 // end ignore prey entity keys
572 CopiedString tmp(key);
573 ASSERT_MESSAGE(!string_equal_n(key, "editor_", 7), "unsupported editor key: " << makeQuoted(key));
574 EntityClassAttribute& attribute = EntityClass_insertAttribute(entityClass, key).second;
575 attribute.m_type = "string";
577 PARSE_RETURN_FALSE_IF_FAIL(EntityClassDoom3_parseString(tokeniser, value));
578 if(string_equal(value, "}")) // hack for quake4 powerups.def bug
580 globalErrorStream() << "entityDef " << makeQuoted(entityClass.m_name.c_str()) << " key " << makeQuoted(tmp.c_str()) << " has no value\n";
585 attribute.m_value = value;
588 tokeniser.nextLine();
591 entityClass.m_comments = usage.c_str();
593 if(string_equal(entityClass.m_name.c_str(), "light"))
596 EntityClassAttribute& attribute = EntityClass_insertAttribute(entityClass, "light_radius").second;
597 attribute.m_type = "vector3";
598 attribute.m_value = "300 300 300";
601 EntityClassAttribute& attribute = EntityClass_insertAttribute(entityClass, "light_center").second;
602 attribute.m_type = "vector3";
605 EntityClassAttribute& attribute = EntityClass_insertAttribute(entityClass, "noshadows").second;
606 attribute.m_type = "boolean";
607 attribute.m_value = "0";
610 EntityClassAttribute& attribute = EntityClass_insertAttribute(entityClass, "nospecular").second;
611 attribute.m_type = "boolean";
612 attribute.m_value = "0";
615 EntityClassAttribute& attribute = EntityClass_insertAttribute(entityClass, "nodiffuse").second;
616 attribute.m_type = "boolean";
617 attribute.m_value = "0";
620 EntityClassAttribute& attribute = EntityClass_insertAttribute(entityClass, "falloff").second;
621 attribute.m_type = "real";
628 bool EntityClassDoom3_parseEntityDef(Tokeniser& tokeniser)
630 EntityClass* entityClass = Eclass_Alloc();
631 entityClass->free = &Eclass_Free;
633 if(!EntityClass_parse(*entityClass, tokeniser))
635 eclass_capture_state(entityClass); // finish constructing the entity so that it can be destroyed cleanly.
636 entityClass->free(entityClass);
640 EntityClass* inserted = EntityClassDoom3_insertUnique(entityClass);
641 if(inserted != entityClass)
643 globalErrorStream() << "entityDef " << entityClass->name() << " is already defined, second definition ignored\n";
644 eclass_capture_state(entityClass); // finish constructing the entity so that it can be destroyed cleanly.
645 entityClass->free(entityClass);
650 bool EntityClassDoom3_parseBlock(Tokeniser& tokeniser, const char* blockType)
652 if(string_equal(blockType, "entityDef"))
654 return EntityClassDoom3_parseEntityDef(tokeniser);
656 else if(string_equal(blockType, "model"))
658 return EntityClassDoom3_parseModel(tokeniser);
662 return EntityClassDoom3_parseUnknown(tokeniser);
666 bool EntityClassDoom3_parse(TextInputStream& inputStream, const char* filename)
668 Tokeniser& tokeniser = GlobalScriptLibrary().m_pfnNewScriptTokeniser(inputStream);
670 tokeniser.nextLine();
674 const char* blockType = tokeniser.getToken();
679 CopiedString tmp(blockType);
680 if(!EntityClassDoom3_parseBlock(tokeniser, tmp.c_str()))
682 globalErrorStream() << GlobalFileSystem().findFile(filename) << filename << ":" << (unsigned int)tokeniser.getLine() << ": " << tmp.c_str() << " parse failed, skipping rest of file\n";
691 void EntityClassDoom3_loadFile(const char* filename)
693 globalOutputStream() << "parsing entity classes from " << makeQuoted(filename) << "\n";
695 StringOutputStream fullname(256);
696 fullname << "def/" << filename;
698 ArchiveTextFile* file = GlobalFileSystem().openTextFile(fullname.c_str());
701 EntityClassDoom3_parse(file->getInputStream(), fullname.c_str());
706 EntityClass* EntityClassDoom3_findOrInsert(const char *name, bool has_brushes)
708 ASSERT_NOTNULL(name);
710 if(string_empty(name))
712 return g_EntityClassDoom3_bad;
715 EntityClasses::iterator i = g_EntityClassDoom3_classes.find(name);
716 if(i != g_EntityClassDoom3_classes.end()
717 //&& string_equal((*i).first, name)
723 EntityClass* e = EntityClass_Create_Default(name, has_brushes);
724 EntityClass* inserted = EntityClassDoom3_insertUnique(e);
725 ASSERT_MESSAGE(inserted == e, "");
729 const ListAttributeType* EntityClassDoom3_findListType(const char* name)
735 void EntityClass_resolveInheritance(EntityClass* derivedClass)
737 if(derivedClass->inheritanceResolved == false)
739 derivedClass->inheritanceResolved = true;
740 EntityClasses::iterator i = g_EntityClassDoom3_classes.find(derivedClass->m_parent.front().c_str());
741 if(i == g_EntityClassDoom3_classes.end())
743 globalErrorStream() << "failed to find entityDef " << makeQuoted(derivedClass->m_parent.front().c_str()) << " inherited by " << makeQuoted(derivedClass->m_name.c_str()) << "\n";
747 EntityClass* parentClass = (*i).second;
748 EntityClass_resolveInheritance(parentClass);
749 if(!derivedClass->colorSpecified)
751 derivedClass->colorSpecified = parentClass->colorSpecified;
752 derivedClass->color = parentClass->color;
754 if(!derivedClass->sizeSpecified)
756 derivedClass->sizeSpecified = parentClass->sizeSpecified;
757 derivedClass->mins = parentClass->mins;
758 derivedClass->maxs = parentClass->maxs;
759 derivedClass->fixedsize = parentClass->fixedsize;
762 for(EntityClassAttributes::iterator j = parentClass->m_attributes.begin(); j != parentClass->m_attributes.end(); ++j)
764 EntityClass_insertAttribute(*derivedClass, (*j).first.c_str(), (*j).second);
770 class EntityClassDoom3 : public ModuleObserver
772 std::size_t m_unrealised;
773 ModuleObservers m_observers;
775 EntityClassDoom3() : m_unrealised(2)
780 if(--m_unrealised == 0)
782 globalOutputStream() << "searching vfs directory " << makeQuoted("def") << " for *.def\n";
783 GlobalFileSystem().forEachFile("def/", "def", FreeCaller1<const char*, EntityClassDoom3_loadFile>());
786 for(Models::iterator i = g_models.begin(); i != g_models.end(); ++i)
788 Model_resolveInheritance((*i).first.c_str(), (*i).second);
792 for(EntityClasses::iterator i = g_EntityClassDoom3_classes.begin(); i != g_EntityClassDoom3_classes.end(); ++i)
794 EntityClass_resolveInheritance((*i).second);
795 if(!string_empty((*i).second->m_modelpath.c_str()))
797 Models::iterator j = g_models.find((*i).second->m_modelpath);
798 if(j != g_models.end())
800 (*i).second->m_modelpath = (*j).second.m_mesh;
801 (*i).second->m_skin = (*j).second.m_skin;
804 eclass_capture_state((*i).second);
806 StringOutputStream usage(256);
808 usage << "-------- NOTES --------\n";
810 if(!string_empty((*i).second->m_comments.c_str()))
812 usage << (*i).second->m_comments.c_str() << "\n";
815 usage << "\n-------- KEYS --------\n";
817 for(EntityClassAttributes::iterator j = (*i).second->m_attributes.begin(); j != (*i).second->m_attributes.end(); ++j)
819 const char* name = EntityClassAttributePair_getName(*j);
820 const char* description = EntityClassAttributePair_getDescription(*j);
821 if(!string_equal(name, description))
823 usage << EntityClassAttributePair_getName(*j) << " : " << EntityClassAttributePair_getDescription(*j) << "\n";
827 (*i).second->m_comments = usage.c_str();
831 m_observers.realise();
836 if(++m_unrealised == 1)
838 m_observers.unrealise();
839 EntityClassDoom3_clear();
842 void attach(ModuleObserver& observer)
844 m_observers.attach(observer);
846 void detach(ModuleObserver& observer)
848 m_observers.detach(observer);
852 EntityClassDoom3 g_EntityClassDoom3;
854 void EntityClassDoom3_attach(ModuleObserver& observer)
856 g_EntityClassDoom3.attach(observer);
858 void EntityClassDoom3_detach(ModuleObserver& observer)
860 g_EntityClassDoom3.detach(observer);
863 void EntityClassDoom3_realise()
865 g_EntityClassDoom3.realise();
867 void EntityClassDoom3_unrealise()
869 g_EntityClassDoom3.unrealise();
872 void EntityClassDoom3_construct()
874 GlobalFileSystem().attach(g_EntityClassDoom3);
876 // start by creating the default unknown eclass
877 g_EntityClassDoom3_bad = EClass_Create("UNKNOWN_CLASS", Vector3(0.0f, 0.5f, 0.0f), "");
879 EntityClassDoom3_realise();
882 void EntityClassDoom3_destroy()
884 EntityClassDoom3_unrealise();
886 g_EntityClassDoom3_bad->free(g_EntityClassDoom3_bad);
888 GlobalFileSystem().detach(g_EntityClassDoom3);
891 class EntityClassDoom3Dependencies : public GlobalFileSystemModuleRef, public GlobalShaderCacheModuleRef
895 class EntityClassDoom3API
897 EntityClassManager m_eclassmanager;
899 typedef EntityClassManager Type;
900 STRING_CONSTANT(Name, "doom3");
902 EntityClassDoom3API()
904 EntityClassDoom3_construct();
906 m_eclassmanager.findOrInsert = &EntityClassDoom3_findOrInsert;
907 m_eclassmanager.findListType = &EntityClassDoom3_findListType;
908 m_eclassmanager.forEach = &EntityClassDoom3_forEach;
909 m_eclassmanager.attach = &EntityClassDoom3_attach;
910 m_eclassmanager.detach = &EntityClassDoom3_detach;
911 m_eclassmanager.realise = &EntityClassDoom3_realise;
912 m_eclassmanager.unrealise = &EntityClassDoom3_unrealise;
914 ~EntityClassDoom3API()
916 EntityClassDoom3_destroy();
918 EntityClassManager* getTable()
920 return &m_eclassmanager;
924 #include "modulesystem/singletonmodule.h"
925 #include "modulesystem/moduleregistry.h"
927 typedef SingletonModule<EntityClassDoom3API, EntityClassDoom3Dependencies> EntityClassDoom3Module;
928 typedef Static<EntityClassDoom3Module> StaticEntityClassDoom3Module;
929 StaticRegisterModule staticRegisterEntityClassDoom3(StaticEntityClassDoom3Module::instance());