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 "skincache.h"
24 #include "ifilesystem.h"
25 #include "iscriplib.h"
27 #include "modelskin.h"
31 #include "stream/stringstream.h"
32 #include "generic/callback.h"
33 #include "container/cache.h"
34 #include "container/hashfunc.h"
36 #include "moduleobservers.h"
37 #include "modulesystem/singletonmodule.h"
40 void parseShaderName( CopiedString& name, const char* token ){
41 StringOutputStream cleaned( 256 );
42 cleaned << PathCleaned( token );
43 name = cleaned.c_str();
48 typedef std::map<CopiedString, CopiedString> Remaps;
51 bool parseTokens( Tokeniser& tokeniser ){
52 RETURN_FALSE_IF_FAIL( Tokeniser_parseToken( tokeniser, "{" ) );
56 const char* token = tokeniser.getToken();
60 if ( string_equal( token, "}" ) ) {
64 else if ( string_equal( token, "model" ) ) {
70 CopiedString from, to;
71 parseShaderName( from, token );
73 tokeniser.nextLine(); // hack to handle badly formed skins
75 parseShaderName( to, tokeniser.getToken() );
77 if ( !string_equal( from.c_str(), to.c_str() ) ) {
78 m_remaps.insert( Remaps::value_type( from, to ) );
84 const char* getRemap( const char* name ) const {
85 Remaps::const_iterator i = m_remaps.find( name );
86 if ( i != m_remaps.end() ) {
87 return ( *i ).second.c_str();
91 void forEachRemap( const SkinRemapCallback& callback ) const {
92 for ( Remaps::const_iterator i = m_remaps.begin(); i != m_remaps.end(); ++i )
94 callback( SkinRemap( ( *i ).first.c_str(), ( *i ).second.c_str() ) );
102 typedef std::map<CopiedString, Doom3ModelSkin> SkinMap;
104 Doom3ModelSkin g_nullSkin;
106 Doom3ModelSkin& getSkin( const char* name ){
107 SkinMap::iterator i = m_skins.find( name );
108 if ( i != m_skins.end() ) {
109 return ( *i ).second;
115 bool parseTokens( Tokeniser& tokeniser ){
116 tokeniser.nextLine();
119 const char* token = tokeniser.getToken();
121 // end of token stream
124 if ( !string_equal( token, "skin" ) ) {
125 Tokeniser_unexpectedError( tokeniser, token, "skin" );
128 const char* other = tokeniser.getToken();
130 Tokeniser_unexpectedError( tokeniser, token, "#string" );
134 parseShaderName( name, other );
135 Doom3ModelSkin& skin = m_skins[name];
136 RETURN_FALSE_IF_FAIL( skin.parseTokens( tokeniser ) );
140 void parseFile( const char* name ){
141 StringOutputStream relativeName( 64 );
142 relativeName << "skins/" << name;
143 ArchiveTextFile* file = GlobalFileSystem().openTextFile( relativeName.c_str() );
145 globalOutputStream() << "parsing skins from " << makeQuoted( name ) << "\n";
147 Tokeniser& tokeniser = GlobalScriptLibrary().m_pfnNewSimpleTokeniser( file->getInputStream() );
148 parseTokens( tokeniser );
155 globalErrorStream() << "failed to open " << makeQuoted( name ) << "\n";
159 typedef MemberCaller1<GlobalSkins, const char*, &GlobalSkins::parseFile> ParseFileCaller;
162 GlobalFileSystem().forEachFile( "skins/", "skin", ParseFileCaller( *this ) );
180 class Doom3ModelSkinCacheElement : public ModelSkin
182 ModuleObservers m_observers;
183 Doom3ModelSkin* m_skin;
185 Doom3ModelSkinCacheElement() : m_skin( 0 ){
187 void attach( ModuleObserver& observer ){
188 m_observers.attach( observer );
193 void detach( ModuleObserver& observer ){
195 observer.unrealise();
197 m_observers.detach( observer );
199 bool realised() const {
202 void realise( const char* name ){
203 ASSERT_MESSAGE( !realised(), "Doom3ModelSkinCacheElement::realise: already realised" );
204 m_skin = &g_skins.getSkin( name );
205 m_observers.realise();
208 ASSERT_MESSAGE( realised(), "Doom3ModelSkinCacheElement::unrealise: not realised" );
209 m_observers.unrealise();
212 const char* getRemap( const char* name ) const {
213 ASSERT_MESSAGE( realised(), "Doom3ModelSkinCacheElement::getRemap: not realised" );
214 return m_skin->getRemap( name );
216 void forEachRemap( const SkinRemapCallback& callback ) const {
217 ASSERT_MESSAGE( realised(), "Doom3ModelSkinCacheElement::forEachRemap: not realised" );
218 m_skin->forEachRemap( callback );
222 class Doom3ModelSkinCache : public ModelSkinCache, public ModuleObserver
224 class CreateDoom3ModelSkin
226 Doom3ModelSkinCache& m_cache;
228 explicit CreateDoom3ModelSkin( Doom3ModelSkinCache& cache )
231 Doom3ModelSkinCacheElement* construct( const CopiedString& name ){
232 Doom3ModelSkinCacheElement* skin = new Doom3ModelSkinCacheElement;
233 if ( m_cache.realised() ) {
234 skin->realise( name.c_str() );
238 void destroy( Doom3ModelSkinCacheElement* skin ){
239 if ( m_cache.realised() ) {
246 typedef HashedCache<CopiedString, Doom3ModelSkinCacheElement, HashString, std::equal_to<CopiedString>, CreateDoom3ModelSkin> Cache;
251 typedef ModelSkinCache Type;
252 STRING_CONSTANT( Name, "*" );
253 ModelSkinCache* getTable(){
257 Doom3ModelSkinCache() : m_cache( CreateDoom3ModelSkin( *this ) ), m_realised( false ){
258 GlobalFileSystem().attach( *this );
260 ~Doom3ModelSkinCache(){
261 GlobalFileSystem().detach( *this );
264 ModelSkin& capture( const char* name ){
265 return *m_cache.capture( name );
267 void release( const char* name ){
268 m_cache.release( name );
271 bool realised() const {
277 for ( Cache::iterator i = m_cache.begin(); i != m_cache.end(); ++i )
279 ( *i ).value->realise( ( *i ).key.c_str() );
284 for ( Cache::iterator i = m_cache.begin(); i != m_cache.end(); ++i )
286 ( *i ).value->unrealise();
292 class Doom3ModelSkinCacheDependencies : public GlobalFileSystemModuleRef, public GlobalScripLibModuleRef
296 typedef SingletonModule<Doom3ModelSkinCache, Doom3ModelSkinCacheDependencies> Doom3ModelSkinCacheModule;
298 Doom3ModelSkinCacheModule g_Doom3ModelSkinCacheModule;
300 void Doom3ModelSkinCacheModule_selfRegister( ModuleServer& server ){
301 g_Doom3ModelSkinCacheModule.selfRegister();