skincache.cpp 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349
  1. /*
  2. Copyright (C) 2001-2006, William Joseph.
  3. All Rights Reserved.
  4. This file is part of GtkRadiant.
  5. GtkRadiant is free software; you can redistribute it and/or modify
  6. it under the terms of the GNU General Public License as published by
  7. the Free Software Foundation; either version 2 of the License, or
  8. (at your option) any later version.
  9. GtkRadiant is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. GNU General Public License for more details.
  13. You should have received a copy of the GNU General Public License
  14. along with GtkRadiant; if not, write to the Free Software
  15. Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
  16. */
  17. #include "skincache.h"
  18. #include "ifilesystem.h"
  19. #include "iscriplib.h"
  20. #include "iarchive.h"
  21. #include "modelskin.h"
  22. #include <map>
  23. #include "stream/stringstream.h"
  24. #include "generic/callback.h"
  25. #include "container/cache.h"
  26. #include "container/hashfunc.h"
  27. #include "os/path.h"
  28. #include "moduleobservers.h"
  29. #include "modulesystem/singletonmodule.h"
  30. #include "stringio.h"
  31. void parseShaderName(CopiedString& name, const char* token)
  32. {
  33. StringOutputStream cleaned(256);
  34. cleaned << PathCleaned(token);
  35. name = cleaned.c_str();
  36. }
  37. class Doom3ModelSkin
  38. {
  39. typedef std::map<CopiedString, CopiedString> Remaps;
  40. Remaps m_remaps;
  41. public:
  42. bool parseTokens(Tokeniser& tokeniser)
  43. {
  44. RETURN_FALSE_IF_FAIL(Tokeniser_parseToken(tokeniser, "{"));
  45. tokeniser.nextLine();
  46. for(;;)
  47. {
  48. const char* token = tokeniser.getToken();
  49. if(token == 0)
  50. {
  51. return false;
  52. }
  53. if(string_equal(token, "}"))
  54. {
  55. tokeniser.nextLine();
  56. return true;
  57. }
  58. else if(string_equal(token, "model"))
  59. {
  60. //const char* model =
  61. tokeniser.getToken();
  62. }
  63. else
  64. {
  65. CopiedString from, to;
  66. parseShaderName(from, token);
  67. tokeniser.nextLine(); // hack to handle badly formed skins
  68. parseShaderName(to, tokeniser.getToken());
  69. if(!string_equal(from.c_str(), to.c_str()))
  70. {
  71. m_remaps.insert(Remaps::value_type(from, to));
  72. }
  73. }
  74. tokeniser.nextLine();
  75. }
  76. }
  77. const char* getRemap(const char* name) const
  78. {
  79. Remaps::const_iterator i = m_remaps.find(name);
  80. if(i != m_remaps.end())
  81. {
  82. return (*i).second.c_str();
  83. }
  84. return "";
  85. }
  86. void forEachRemap(const SkinRemapCallback& callback) const
  87. {
  88. for(Remaps::const_iterator i = m_remaps.begin(); i != m_remaps.end(); ++i)
  89. {
  90. callback(SkinRemap((*i).first.c_str(), (*i).second.c_str()));
  91. }
  92. }
  93. };
  94. class GlobalSkins
  95. {
  96. public:
  97. typedef std::map<CopiedString, Doom3ModelSkin> SkinMap;
  98. SkinMap m_skins;
  99. Doom3ModelSkin g_nullSkin;
  100. Doom3ModelSkin& getSkin(const char* name)
  101. {
  102. SkinMap::iterator i = m_skins.find(name);
  103. if(i != m_skins.end())
  104. {
  105. return (*i).second;
  106. }
  107. return g_nullSkin;
  108. }
  109. bool parseTokens(Tokeniser& tokeniser)
  110. {
  111. tokeniser.nextLine();
  112. for(;;)
  113. {
  114. const char* token = tokeniser.getToken();
  115. if(token == 0)
  116. {
  117. // end of token stream
  118. return true;
  119. }
  120. if(!string_equal(token, "skin"))
  121. {
  122. Tokeniser_unexpectedError(tokeniser, token, "skin");
  123. return false;
  124. }
  125. const char* other = tokeniser.getToken();
  126. if(other == 0)
  127. {
  128. Tokeniser_unexpectedError(tokeniser, token, "#string");
  129. return false;
  130. }
  131. CopiedString name;
  132. parseShaderName(name, other);
  133. Doom3ModelSkin& skin = m_skins[name];
  134. RETURN_FALSE_IF_FAIL(skin.parseTokens(tokeniser));
  135. }
  136. }
  137. void parseFile(const char* name)
  138. {
  139. StringOutputStream relativeName(64);
  140. relativeName << "skins/" << name;
  141. ArchiveTextFile* file = GlobalFileSystem().openTextFile(relativeName.c_str());
  142. if(file != 0)
  143. {
  144. globalOutputStream() << "parsing skins from " << makeQuoted(name) << "\n";
  145. {
  146. Tokeniser& tokeniser = GlobalScriptLibrary().m_pfnNewSimpleTokeniser(file->getInputStream());
  147. parseTokens(tokeniser);
  148. tokeniser.release();
  149. }
  150. file->release();
  151. }
  152. else
  153. {
  154. globalErrorStream() << "failed to open " << makeQuoted(name) << "\n";
  155. }
  156. }
  157. typedef MemberCaller1<GlobalSkins, const char*, &GlobalSkins::parseFile> ParseFileCaller;
  158. void construct()
  159. {
  160. GlobalFileSystem().forEachFile("skins/", "skin", ParseFileCaller(*this));
  161. }
  162. void destroy()
  163. {
  164. m_skins.clear();
  165. }
  166. void realise()
  167. {
  168. construct();
  169. }
  170. void unrealise()
  171. {
  172. destroy();
  173. }
  174. };
  175. GlobalSkins g_skins;
  176. class Doom3ModelSkinCacheElement : public ModelSkin
  177. {
  178. ModuleObservers m_observers;
  179. Doom3ModelSkin* m_skin;
  180. public:
  181. Doom3ModelSkinCacheElement() : m_skin(0)
  182. {
  183. }
  184. void attach(ModuleObserver& observer)
  185. {
  186. m_observers.attach(observer);
  187. if(realised())
  188. {
  189. observer.realise();
  190. }
  191. }
  192. void detach(ModuleObserver& observer)
  193. {
  194. if(realised())
  195. {
  196. observer.unrealise();
  197. }
  198. m_observers.detach(observer);
  199. }
  200. bool realised() const
  201. {
  202. return m_skin != 0;
  203. }
  204. void realise(const char* name)
  205. {
  206. ASSERT_MESSAGE(!realised(), "Doom3ModelSkinCacheElement::realise: already realised");
  207. m_skin = &g_skins.getSkin(name);
  208. m_observers.realise();
  209. }
  210. void unrealise()
  211. {
  212. ASSERT_MESSAGE(realised(), "Doom3ModelSkinCacheElement::unrealise: not realised");
  213. m_observers.unrealise();
  214. m_skin = 0;
  215. }
  216. const char* getRemap(const char* name) const
  217. {
  218. ASSERT_MESSAGE(realised(), "Doom3ModelSkinCacheElement::getRemap: not realised");
  219. return m_skin->getRemap(name);
  220. }
  221. void forEachRemap(const SkinRemapCallback& callback) const
  222. {
  223. ASSERT_MESSAGE(realised(), "Doom3ModelSkinCacheElement::forEachRemap: not realised");
  224. m_skin->forEachRemap(callback);
  225. }
  226. };
  227. class Doom3ModelSkinCache : public ModelSkinCache, public ModuleObserver
  228. {
  229. class CreateDoom3ModelSkin
  230. {
  231. Doom3ModelSkinCache& m_cache;
  232. public:
  233. explicit CreateDoom3ModelSkin(Doom3ModelSkinCache& cache)
  234. : m_cache(cache)
  235. {
  236. }
  237. Doom3ModelSkinCacheElement* construct(const CopiedString& name)
  238. {
  239. Doom3ModelSkinCacheElement* skin = new Doom3ModelSkinCacheElement;
  240. if(m_cache.realised())
  241. {
  242. skin->realise(name.c_str());
  243. }
  244. return skin;
  245. }
  246. void destroy(Doom3ModelSkinCacheElement* skin)
  247. {
  248. if(m_cache.realised())
  249. {
  250. skin->unrealise();
  251. }
  252. delete skin;
  253. }
  254. };
  255. typedef HashedCache<CopiedString, Doom3ModelSkinCacheElement, HashString, std::equal_to<CopiedString>, CreateDoom3ModelSkin> Cache;
  256. Cache m_cache;
  257. bool m_realised;
  258. public:
  259. typedef ModelSkinCache Type;
  260. STRING_CONSTANT(Name, "*");
  261. ModelSkinCache* getTable()
  262. {
  263. return this;
  264. }
  265. Doom3ModelSkinCache() : m_cache(CreateDoom3ModelSkin(*this)), m_realised(false)
  266. {
  267. GlobalFileSystem().attach(*this);
  268. }
  269. ~Doom3ModelSkinCache()
  270. {
  271. GlobalFileSystem().detach(*this);
  272. }
  273. ModelSkin& capture(const char* name)
  274. {
  275. return *m_cache.capture(name);
  276. }
  277. void release(const char* name)
  278. {
  279. m_cache.release(name);
  280. }
  281. bool realised() const
  282. {
  283. return m_realised;
  284. }
  285. void realise()
  286. {
  287. g_skins.realise();
  288. m_realised = true;
  289. for(Cache::iterator i = m_cache.begin(); i != m_cache.end(); ++i)
  290. {
  291. (*i).value->realise((*i).key.c_str());
  292. }
  293. }
  294. void unrealise()
  295. {
  296. m_realised = false;
  297. for(Cache::iterator i = m_cache.begin(); i != m_cache.end(); ++i)
  298. {
  299. (*i).value->unrealise();
  300. }
  301. g_skins.unrealise();
  302. }
  303. };
  304. class Doom3ModelSkinCacheDependencies : public GlobalFileSystemModuleRef, public GlobalScripLibModuleRef
  305. {
  306. };
  307. typedef SingletonModule<Doom3ModelSkinCache, Doom3ModelSkinCacheDependencies> Doom3ModelSkinCacheModule;
  308. Doom3ModelSkinCacheModule g_Doom3ModelSkinCacheModule;
  309. void Doom3ModelSkinCacheModule_selfRegister(ModuleServer& server)
  310. {
  311. g_Doom3ModelSkinCacheModule.selfRegister();
  312. }