X-Git-Url: http://git.xonotic.org/?a=blobdiff_plain;f=radiant%2Freferencecache.cpp;h=5773fa32b8d614c0065709ae3e01ea03c33f1fd8;hb=a95f121300992ffd496a1e0ad43e300878d0221e;hp=d41b9344036eee4296cd3d1d8828dbcad32afc3a;hpb=107765f0e4b543dfc346851ee5b4605cc17eb1c6;p=xonotic%2Fnetradiant.git diff --git a/radiant/referencecache.cpp b/radiant/referencecache.cpp index d41b9344..5773fa32 100644 --- a/radiant/referencecache.cpp +++ b/radiant/referencecache.cpp @@ -1,23 +1,23 @@ /* -Copyright (C) 2001-2006, William Joseph. -All Rights Reserved. + Copyright (C) 2001-2006, William Joseph. + All Rights Reserved. -This file is part of GtkRadiant. + This file is part of GtkRadiant. -GtkRadiant is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2 of the License, or -(at your option) any later version. + GtkRadiant is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. -GtkRadiant is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. + GtkRadiant is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. -You should have received a copy of the GNU General Public License -along with GtkRadiant; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -*/ + You should have received a copy of the GNU General Public License + along with GtkRadiant; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ #include "referencecache.h" @@ -57,724 +57,620 @@ ModelModules& ReferenceAPI_getModelModules(); bool References_Saved(); -void MapChanged() -{ - Map_SetModified(g_map, !References_Saved()); +void MapChanged(){ + Map_SetModified( g_map, !References_Saved() ); } EntityCreator* g_entityCreator = 0; -bool MapResource_loadFile(const MapFormat& format, scene::Node& root, const char* filename) -{ - globalOutputStream() << "Open file " << filename << " for read..."; - TextFileInputStream file(filename); - if(!file.failed()) - { - globalOutputStream() << "success\n"; - ScopeDisableScreenUpdates disableScreenUpdates(path_get_filename_start(filename), "Loading Map"); - ASSERT_NOTNULL(g_entityCreator); - format.readGraph(root, file, *g_entityCreator); - return true; - } - else - { - globalErrorStream() << "failure\n"; - return false; - } -} - -NodeSmartReference MapResource_load(const MapFormat& format, const char* path, const char* name) -{ - NodeSmartReference root(NewMapRoot(name)); +bool MapResource_loadFile( const MapFormat& format, scene::Node& root, const char* filename ){ + globalOutputStream() << "Open file " << filename << " for read..."; + TextFileInputStream file( filename ); + if ( !file.failed() ) { + globalOutputStream() << "success\n"; + ScopeDisableScreenUpdates disableScreenUpdates( path_get_filename_start( filename ), "Loading Map" ); + ASSERT_NOTNULL( g_entityCreator ); + format.readGraph( root, file, *g_entityCreator ); + return true; + } + else + { + globalErrorStream() << "failure\n"; + return false; + } +} + +NodeSmartReference MapResource_load( const MapFormat& format, const char* path, const char* name ){ + NodeSmartReference root( NewMapRoot( name ) ); - StringOutputStream fullpath(256); - fullpath << path << name; + StringOutputStream fullpath( 256 ); + fullpath << path << name; - if(path_is_absolute(fullpath.c_str())) - { - MapResource_loadFile(format, root, fullpath.c_str()); - } - else - { - globalErrorStream() << "map path is not fully qualified: " << makeQuoted(fullpath.c_str()) << "\n"; - } + if ( path_is_absolute( fullpath.c_str() ) ) { + MapResource_loadFile( format, root, fullpath.c_str() ); + } + else + { + globalErrorStream() << "map path is not fully qualified: " << makeQuoted( fullpath.c_str() ) << "\n"; + } - return root; + return root; } -bool MapResource_saveFile(const MapFormat& format, scene::Node& root, GraphTraversalFunc traverse, const char* filename) -{ - //ASSERT_MESSAGE(path_is_absolute(filename), "MapResource_saveFile: path is not absolute: " << makeQuoted(filename)); - globalOutputStream() << "Open file " << filename << " for write..."; - TextFileOutputStream file(filename); - if(!file.failed()) - { - globalOutputStream() << "success\n"; - ScopeDisableScreenUpdates disableScreenUpdates(path_get_filename_start(filename), "Saving Map"); - format.writeGraph(root, traverse, file); - return true; - } - - globalErrorStream() << "failure\n"; - return false; -} - -bool file_saveBackup(const char* path) -{ - if(file_writeable(path)) - { - StringOutputStream backup(256); - backup << StringRange(path, path_get_extension(path)) << "bak"; +bool MapResource_saveFile( const MapFormat& format, scene::Node& root, GraphTraversalFunc traverse, const char* filename ){ + //ASSERT_MESSAGE(path_is_absolute(filename), "MapResource_saveFile: path is not absolute: " << makeQuoted(filename)); + globalOutputStream() << "Open file " << filename << " for write..."; + TextFileOutputStream file( filename ); + if ( !file.failed() ) { + globalOutputStream() << "success\n"; + ScopeDisableScreenUpdates disableScreenUpdates( path_get_filename_start( filename ), "Saving Map" ); + format.writeGraph( root, traverse, file ); + return true; + } + + globalErrorStream() << "failure\n"; + return false; +} + +bool file_saveBackup( const char* path ){ + if ( file_writeable( path ) ) { + StringOutputStream backup( 256 ); + backup << StringRange( path, path_get_extension( path ) ) << "bak"; - return (!file_exists(backup.c_str()) || file_remove(backup.c_str())) // remove backup - && file_move(path, backup.c_str()); // rename current to backup - } + return ( !file_exists( backup.c_str() ) || file_remove( backup.c_str() ) ) // remove backup + && file_move( path, backup.c_str() ); // rename current to backup + } - globalErrorStream() << "map path is not writeable: " << makeQuoted(path) << "\n"; - return false; + globalErrorStream() << "map path is not writeable: " << makeQuoted( path ) << "\n"; + return false; } -bool MapResource_save(const MapFormat& format, scene::Node& root, const char* path, const char* name) -{ - StringOutputStream fullpath(256); - fullpath << path << name; +bool MapResource_save( const MapFormat& format, scene::Node& root, const char* path, const char* name ){ + StringOutputStream fullpath( 256 ); + fullpath << path << name; - if(path_is_absolute(fullpath.c_str())) - { - if(!file_exists(fullpath.c_str()) || file_saveBackup(fullpath.c_str())) - { - return MapResource_saveFile(format, root, Map_Traverse, fullpath.c_str()); - } + if ( path_is_absolute( fullpath.c_str() ) ) { + if ( !file_exists( fullpath.c_str() ) || file_saveBackup( fullpath.c_str() ) ) { + return MapResource_saveFile( format, root, Map_Traverse, fullpath.c_str() ); + } - globalErrorStream() << "failed to save a backup map file: " << makeQuoted(fullpath.c_str()) << "\n"; - return false; - } + globalErrorStream() << "failed to save a backup map file: " << makeQuoted( fullpath.c_str() ) << "\n"; + return false; + } - globalErrorStream() << "map path is not fully qualified: " << makeQuoted(fullpath.c_str()) << "\n"; - return false; + globalErrorStream() << "map path is not fully qualified: " << makeQuoted( fullpath.c_str() ) << "\n"; + return false; } namespace { - NodeSmartReference g_nullNode(NewNullNode()); - NodeSmartReference g_nullModel(g_nullNode); +NodeSmartReference g_nullNode( NewNullNode() ); +NodeSmartReference g_nullModel( g_nullNode ); } class NullModelLoader : public ModelLoader { public: - scene::Node& loadModel(ArchiveFile& file) - { - return g_nullModel; - } +scene::Node& loadModel( ArchiveFile& file ){ + return g_nullModel; +} }; namespace { - NullModelLoader g_NullModelLoader; +NullModelLoader g_NullModelLoader; } /// \brief Returns the model loader for the model \p type or 0 if the model \p type has no loader module -ModelLoader* ModelLoader_forType(const char* type) -{ - const char* moduleName = findModuleName(&GlobalFiletypes(), ModelLoader::Name(), type); - if(string_not_empty(moduleName)) - { - ModelLoader* table = ReferenceAPI_getModelModules().findModule(moduleName); - if(table != 0) - { - return table; - } - else - { - globalErrorStream() << "ERROR: Model type incorrectly registered: \"" << moduleName << "\"\n"; - return &g_NullModelLoader; - } - } - return 0; -} - -NodeSmartReference ModelResource_load(ModelLoader* loader, const char* name) -{ - ScopeDisableScreenUpdates disableScreenUpdates(path_get_filename_start(name), "Loading Model"); +ModelLoader* ModelLoader_forType( const char* type ){ + const char* moduleName = findModuleName( &GlobalFiletypes(), ModelLoader::Name(), type ); + if ( string_not_empty( moduleName ) ) { + ModelLoader* table = ReferenceAPI_getModelModules().findModule( moduleName ); + if ( table != 0 ) { + return table; + } + else + { + globalErrorStream() << "ERROR: Model type incorrectly registered: \"" << moduleName << "\"\n"; + return &g_NullModelLoader; + } + } + return 0; +} + +NodeSmartReference ModelResource_load( ModelLoader* loader, const char* name ){ + ScopeDisableScreenUpdates disableScreenUpdates( path_get_filename_start( name ), "Loading Model" ); - NodeSmartReference model(g_nullModel); + NodeSmartReference model( g_nullModel ); - { - ArchiveFile* file = GlobalFileSystem().openFile(name); + { + ArchiveFile* file = GlobalFileSystem().openFile( name ); - if(file != 0) - { - globalOutputStream() << "Loaded Model: \"" << name << "\"\n"; - model = loader->loadModel(*file); - file->release(); - } - else - { - globalErrorStream() << "Model load failed: \"" << name << "\"\n"; - } - } + if ( file != 0 ) { + globalOutputStream() << "Loaded Model: \"" << name << "\"\n"; + model = loader->loadModel( *file ); + file->release(); + } + else + { + globalErrorStream() << "Model load failed: \"" << name << "\"\n"; + } + } - model.get().m_isRoot = true; + model.get().m_isRoot = true; - return model; + return model; } -inline hash_t path_hash(const char* path, hash_t previous = 0) -{ -#if defined(WIN32) - return string_hash_nocase(path, previous); +inline hash_t path_hash( const char* path, hash_t previous = 0 ){ +#if defined( WIN32 ) + return string_hash_nocase( path, previous ); #else // UNIX - return string_hash(path, previous); + return string_hash( path, previous ); #endif } struct PathEqual { - bool operator()(const CopiedString& path, const CopiedString& other) const - { - return path_equal(path.c_str(), other.c_str()); - } + bool operator()( const std::string& path, const std::string& other ) const { + return path_equal( path.c_str(), other.c_str() ); + } }; struct PathHash { - typedef hash_t hash_type; - hash_type operator()(const CopiedString& path) const - { - return path_hash(path.c_str()); - } + typedef hash_t hash_type; + hash_type operator()( const std::string& path ) const { + return path_hash( path.c_str() ); + } }; -typedef std::pair ModelKey; +typedef std::pair ModelKey; struct ModelKeyEqual { - bool operator()(const ModelKey& key, const ModelKey& other) const - { - return path_equal(key.first.c_str(), other.first.c_str()) && path_equal(key.second.c_str(), other.second.c_str()); - } + bool operator()( const ModelKey& key, const ModelKey& other ) const { + return path_equal( key.first.c_str(), other.first.c_str() ) && path_equal( key.second.c_str(), other.second.c_str() ); + } }; struct ModelKeyHash { - typedef hash_t hash_type; - hash_type operator()(const ModelKey& key) const - { - return hash_combine(path_hash(key.first.c_str()), path_hash(key.second.c_str())); - } + typedef hash_t hash_type; + hash_type operator()( const ModelKey& key ) const { + return hash_combine( path_hash( key.first.c_str() ), path_hash( key.second.c_str() ) ); + } }; typedef HashTable ModelCache; ModelCache g_modelCache; bool g_modelCache_enabled = true; -ModelCache::iterator ModelCache_find(const char* path, const char* name) -{ - if(g_modelCache_enabled) - { - return g_modelCache.find(ModelKey(path, name)); - } - return g_modelCache.end(); +ModelCache::iterator ModelCache_find( const char* path, const char* name ){ + if ( g_modelCache_enabled ) { + return g_modelCache.find( ModelKey( path, name ) ); + } + return g_modelCache.end(); } -ModelCache::iterator ModelCache_insert(const char* path, const char* name, scene::Node& node) -{ - if(g_modelCache_enabled) - { - return g_modelCache.insert(ModelKey(path, name), NodeSmartReference(node)); - } - return g_modelCache.insert(ModelKey("", ""), g_nullModel); +ModelCache::iterator ModelCache_insert( const char* path, const char* name, scene::Node& node ){ + if ( g_modelCache_enabled ) { + return g_modelCache.emplace( ModelKey( path, name ), NodeSmartReference( node ) ).first; + } + return g_modelCache.emplace( ModelKey( "", "" ), g_nullModel ).first; } -void ModelCache_flush(const char* path, const char* name) -{ - ModelCache::iterator i = g_modelCache.find(ModelKey(path, name)); - if(i != g_modelCache.end()) - { - //ASSERT_MESSAGE((*i).value.getCount() == 0, "resource flushed while still in use: " << (*i).key.first.c_str() << (*i).key.second.c_str()); - g_modelCache.erase(i); - } +void ModelCache_flush( const char* path, const char* name ){ + ModelCache::iterator i = g_modelCache.find( ModelKey( path, name ) ); + if ( i != g_modelCache.end() ) { + //ASSERT_MESSAGE((*i).value.getCount() == 0, "resource flushed while still in use: " << (*i).key.first.c_str() << (*i).key.second.c_str()); + g_modelCache.erase( i ); + } } -void ModelCache_clear() -{ - g_modelCache_enabled = false; - g_modelCache.clear(); - g_modelCache_enabled = true; +void ModelCache_clear(){ + g_modelCache_enabled = false; + g_modelCache.clear(); + g_modelCache_enabled = true; } -NodeSmartReference Model_load(ModelLoader* loader, const char* path, const char* name, const char* type) -{ - if(loader != 0) - { - return ModelResource_load(loader, name); - } - else - { - const char* moduleName = findModuleName(&GlobalFiletypes(), MapFormat::Name(), type); - if(string_not_empty(moduleName)) - { - const MapFormat* format = ReferenceAPI_getMapModules().findModule(moduleName); - if(format != 0) - { - return MapResource_load(*format, path, name); - } - else - { - globalErrorStream() << "ERROR: Map type incorrectly registered: \"" << moduleName << "\"\n"; - return g_nullModel; - } - } - else - { - if(string_not_empty(type)) - { - globalErrorStream() << "Model type not supported: \"" << name << "\"\n"; - } - return g_nullModel; - } - } +NodeSmartReference Model_load( ModelLoader* loader, const char* path, const char* name, const char* type ){ + if ( loader != 0 ) { + return ModelResource_load( loader, name ); + } + else + { + const char* moduleName = findModuleName( &GlobalFiletypes(), MapFormat::Name(), type ); + if ( string_not_empty( moduleName ) ) { + const MapFormat* format = ReferenceAPI_getMapModules().findModule( moduleName ); + if ( format != 0 ) { + return MapResource_load( *format, path, name ); + } + else + { + globalErrorStream() << "ERROR: Map type incorrectly registered: \"" << moduleName << "\"\n"; + return g_nullModel; + } + } + else + { + if ( string_not_empty( type ) ) { + globalErrorStream() << "Model type not supported: \"" << name << "\"\n"; + } + return g_nullModel; + } + } } namespace { - bool g_realised = false; +bool g_realised = false; - // name may be absolute or relative - const char* rootPath(const char* name) - { - return GlobalFileSystem().findRoot( - path_is_absolute(name) - ? name - : GlobalFileSystem().findFile(name) - ); - } +// name may be absolute or relative +const char* rootPath( const char* name ){ + return GlobalFileSystem().findRoot( + path_is_absolute( name ) + ? name + : GlobalFileSystem().findFile( name ) + ); +} } struct ModelResource : public Resource { - NodeSmartReference m_model; - const CopiedString m_originalName; - CopiedString m_path; - CopiedString m_name; - CopiedString m_type; - ModelLoader* m_loader; - ModuleObservers m_observers; - std::time_t m_modified; - std::size_t m_unrealised; - - ModelResource(const CopiedString& name) : - m_model(g_nullModel), - m_originalName(name), - m_type(path_get_extension(name.c_str())), - m_loader(0), - m_modified(0), - m_unrealised(1) - { - m_loader = ModelLoader_forType(m_type.c_str()); - - if(g_realised) - { - realise(); - } - } - ~ModelResource() - { - if(realised()) - { - unrealise(); - } - ASSERT_MESSAGE(!realised(), "ModelResource::~ModelResource: resource reference still realised: " << makeQuoted(m_name.c_str())); - } - // NOT COPYABLE - ModelResource(const ModelResource&); - // NOT ASSIGNABLE - ModelResource& operator=(const ModelResource&); - - void setModel(const NodeSmartReference& model) - { - m_model = model; - } - void clearModel() - { - m_model = g_nullModel; - } - - void loadCached() - { - if(g_modelCache_enabled) - { - // cache lookup - ModelCache::iterator i = ModelCache_find(m_path.c_str(), m_name.c_str()); - if(i == g_modelCache.end()) - { - i = ModelCache_insert( - m_path.c_str(), - m_name.c_str(), - Model_load(m_loader, m_path.c_str(), m_name.c_str(), m_type.c_str()) - ); - } - - setModel((*i).value); - } - else - { - setModel(Model_load(m_loader, m_path.c_str(), m_name.c_str(), m_type.c_str())); - } - } - - void loadModel() - { - loadCached(); - connectMap(); - mapSave(); - } - - bool load() - { - ASSERT_MESSAGE(realised(), "resource not realised"); - if(m_model == g_nullModel) - { - loadModel(); - } - - return m_model != g_nullModel; - } - bool save() - { - if(!mapSaved()) - { - const char* moduleName = findModuleName(GetFileTypeRegistry(), MapFormat::Name(), m_type.c_str()); - if(string_not_empty(moduleName)) - { - const MapFormat* format = ReferenceAPI_getMapModules().findModule(moduleName); - if(format != 0 && MapResource_save(*format, m_model.get(), m_path.c_str(), m_name.c_str())) - { - mapSave(); - return true; - } - } - } - return false; - } - void flush() - { - if(realised()) - { - ModelCache_flush(m_path.c_str(), m_name.c_str()); - } - } - scene::Node* getNode() - { - //if(m_model != g_nullModel) - { - return m_model.get_pointer(); - } - //return 0; - } - void setNode(scene::Node* node) - { - ModelCache::iterator i = ModelCache_find(m_path.c_str(), m_name.c_str()); - if(i != g_modelCache.end()) - { - (*i).value = NodeSmartReference(*node); - } - setModel(NodeSmartReference(*node)); - - connectMap(); - } - void attach(ModuleObserver& observer) - { - if(realised()) - { - observer.realise(); - } - m_observers.attach(observer); - } - void detach(ModuleObserver& observer) - { - if(realised()) - { - observer.unrealise(); - } - m_observers.detach(observer); - } - bool realised() - { - return m_unrealised == 0; - } - void realise() - { - ASSERT_MESSAGE(m_unrealised != 0, "ModelResource::realise: already realised"); - if(--m_unrealised == 0) - { - m_path = rootPath(m_originalName.c_str()); - m_name = path_make_relative(m_originalName.c_str(), m_path.c_str()); - - //globalOutputStream() << "ModelResource::realise: " << m_path.c_str() << m_name.c_str() << "\n"; - - m_observers.realise(); - } - } - void unrealise() - { - if(++m_unrealised == 1) - { - m_observers.unrealise(); - - //globalOutputStream() << "ModelResource::unrealise: " << m_path.c_str() << m_name.c_str() << "\n"; - clearModel(); - } - } - bool isMap() const - { - return Node_getMapFile(m_model) != 0; - } - void connectMap() - { - MapFile* map = Node_getMapFile(m_model); - if(map != 0) - { - map->setChangedCallback(FreeCaller()); - } - } - std::time_t modified() const - { - StringOutputStream fullpath(256); - fullpath << m_path.c_str() << m_name.c_str(); - return file_modified(fullpath.c_str()); - } - void mapSave() - { - m_modified = modified(); - MapFile* map = Node_getMapFile(m_model); - if(map != 0) - { - map->save(); - } - } - bool mapSaved() const - { - MapFile* map = Node_getMapFile(m_model); - if(map != 0) - { - return m_modified == modified() && map->saved(); - } - return true; - } - bool isModified() const - { - return ((!string_empty(m_path.c_str()) // had or has an absolute path - && m_modified != modified()) // AND disk timestamp changed - || !path_equal(rootPath(m_originalName.c_str()), m_path.c_str())); // OR absolute vfs-root changed - } - void refresh() - { - if(isModified()) - { - flush(); - unrealise(); - realise(); - } - } + NodeSmartReference m_model; + const std::string m_originalName; + std::string m_path; + std::string m_name; + std::string m_type; + ModelLoader* m_loader; + ModuleObservers m_observers; + std::time_t m_modified; + std::size_t m_unrealised; + + ModelResource( const std::string& name ) : + m_model( g_nullModel ), + m_originalName( name ), + m_type( path_get_extension( name.c_str() ) ), + m_loader( 0 ), + m_modified( 0 ), + m_unrealised( 1 ){ + m_loader = ModelLoader_forType( m_type.c_str() ); + + if ( g_realised ) { + realise(); + } + } + ~ModelResource(){ + if ( realised() ) { + unrealise(); + } + ASSERT_MESSAGE( !realised(), "ModelResource::~ModelResource: resource reference still realised: " << makeQuoted( m_name.c_str() ) ); + } + // NOT COPYABLE + ModelResource( const ModelResource& ); + // NOT ASSIGNABLE + ModelResource& operator=( const ModelResource& ); + + void setModel( const NodeSmartReference& model ){ + m_model = model; + } + void clearModel(){ + m_model = g_nullModel; + } + + void loadCached(){ + if ( g_modelCache_enabled ) { + // cache lookup + ModelCache::iterator i = ModelCache_find( m_path.c_str(), m_name.c_str() ); + if ( i == g_modelCache.end() ) { + i = ModelCache_insert( + m_path.c_str(), + m_name.c_str(), + Model_load( m_loader, m_path.c_str(), m_name.c_str(), m_type.c_str() ) + ); + } + + setModel( ( *i ).second ); + } + else + { + setModel( Model_load( m_loader, m_path.c_str(), m_name.c_str(), m_type.c_str() ) ); + } + } + + void loadModel(){ + loadCached(); + connectMap(); + mapSave(); + } + + bool load(){ + ASSERT_MESSAGE( realised(), "resource not realised" ); + if ( m_model == g_nullModel ) { + loadModel(); + } + + return m_model != g_nullModel; + } + bool save(){ + if ( !mapSaved() ) { + const char* moduleName = findModuleName( GetFileTypeRegistry(), MapFormat::Name(), m_type.c_str() ); + if ( string_not_empty( moduleName ) ) { + const MapFormat* format = ReferenceAPI_getMapModules().findModule( moduleName ); + if ( format != 0 && MapResource_save( *format, m_model.get(), m_path.c_str(), m_name.c_str() ) ) { + mapSave(); + return true; + } + } + } + return false; + } + void flush(){ + if ( realised() ) { + ModelCache_flush( m_path.c_str(), m_name.c_str() ); + } + } + scene::Node* getNode(){ + //if(m_model != g_nullModel) + { + return m_model.get_pointer(); + } + //return 0; + } + void setNode( scene::Node* node ){ + ModelCache::iterator i = ModelCache_find( m_path.c_str(), m_name.c_str() ); + if ( i != g_modelCache.end() ) { + ( *i ).second = NodeSmartReference( *node ); + } + setModel( NodeSmartReference( *node ) ); + + connectMap(); + } + void attach( ModuleObserver& observer ){ + if ( realised() ) { + observer.realise(); + } + m_observers.attach( observer ); + } + void detach( ModuleObserver& observer ){ + if ( realised() ) { + observer.unrealise(); + } + m_observers.detach( observer ); + } + bool realised(){ + return m_unrealised == 0; + } + void realise(){ + ASSERT_MESSAGE( m_unrealised != 0, "ModelResource::realise: already realised" ); + if ( --m_unrealised == 0 ) { + m_path = rootPath( m_originalName.c_str() ); + m_name = path_make_relative( m_originalName.c_str(), m_path.c_str() ); + + //globalOutputStream() << "ModelResource::realise: " << m_path.c_str() << m_name.c_str() << "\n"; + + m_observers.realise(); + } + } + void unrealise(){ + if ( ++m_unrealised == 1 ) { + m_observers.unrealise(); + + //globalOutputStream() << "ModelResource::unrealise: " << m_path.c_str() << m_name.c_str() << "\n"; + clearModel(); + } + } + bool isMap() const { + return Node_getMapFile( m_model ) != 0; + } + void connectMap(){ + MapFile* map = Node_getMapFile( m_model ); + if ( map != 0 ) { + map->setChangedCallback( FreeCaller() ); + } + } + std::time_t modified() const { + StringOutputStream fullpath( 256 ); + fullpath << m_path.c_str() << m_name.c_str(); + return file_modified( fullpath.c_str() ); + } + void mapSave(){ + m_modified = modified(); + MapFile* map = Node_getMapFile( m_model ); + if ( map != 0 ) { + map->save(); + } + } + bool mapSaved() const { + MapFile* map = Node_getMapFile( m_model ); + if ( map != 0 ) { + return m_modified == modified() && map->saved(); + } + return true; + } + bool isModified() const { + return ( ( !string_empty( m_path.c_str() ) // had or has an absolute path + && m_modified != modified() ) // AND disk timestamp changed + || !path_equal( rootPath( m_originalName.c_str() ), m_path.c_str() ) ); // OR absolute vfs-root changed + } + void refresh(){ + if ( isModified() ) { + flush(); + unrealise(); + realise(); + } + } }; class HashtableReferenceCache : public ReferenceCache, public ModuleObserver { - typedef HashedCache ModelReferences; - ModelReferences m_references; - std::size_t m_unrealised; - - class ModelReferencesSnapshot - { - ModelReferences& m_references; - typedef std::list Iterators; - Iterators m_iterators; - public: - typedef Iterators::iterator iterator; - ModelReferencesSnapshot(ModelReferences& references) : m_references(references) - { - for(ModelReferences::iterator i = m_references.begin(); i != m_references.end(); ++i) - { - m_references.capture(i); - m_iterators.push_back(i); - } - } - ~ModelReferencesSnapshot() - { - for(Iterators::iterator i = m_iterators.begin(); i != m_iterators.end(); ++i) - { - m_references.release(*i); - } - } - iterator begin() - { - return m_iterators.begin(); - } - iterator end() - { - return m_iterators.end(); - } - }; +typedef HashedCache ModelReferences; +ModelReferences m_references; +std::size_t m_unrealised; +class ModelReferencesSnapshot +{ +ModelReferences& m_references; +typedef std::list Iterators; +Iterators m_iterators; public: +typedef Iterators::iterator iterator; +ModelReferencesSnapshot( ModelReferences& references ) : m_references( references ){ + for ( ModelReferences::iterator i = m_references.begin(); i != m_references.end(); ++i ) + { + m_references.capture( i ); + m_iterators.push_back( i ); + } +} +~ModelReferencesSnapshot(){ + for ( Iterators::iterator i = m_iterators.begin(); i != m_iterators.end(); ++i ) + { + m_references.release( *i ); + } +} +iterator begin(){ + return m_iterators.begin(); +} +iterator end(){ + return m_iterators.end(); +} +}; + +public: + +typedef ModelReferences::iterator iterator; + +HashtableReferenceCache() : m_unrealised( 1 ){ +} + +iterator begin(){ + return m_references.begin(); +} +iterator end(){ + return m_references.end(); +} + +void clear(){ + m_references.clear(); +} + +Resource* capture( const char* path ){ + //globalOutputStream() << "capture: \"" << path << "\"\n"; + return m_references.capture( std::string( path ) ).get(); +} +void release( const char* path ){ + m_references.release( std::string( path ) ); + //globalOutputStream() << "release: \"" << path << "\"\n"; +} + +void setEntityCreator( EntityCreator& entityCreator ){ + g_entityCreator = &entityCreator; +} - typedef ModelReferences::iterator iterator; - - HashtableReferenceCache() : m_unrealised(1) - { - } - - iterator begin() - { - return m_references.begin(); - } - iterator end() - { - return m_references.end(); - } - - void clear() - { - m_references.clear(); - } - - Resource* capture(const char* path) - { - //globalOutputStream() << "capture: \"" << path << "\"\n"; - return m_references.capture(CopiedString(path)).get(); - } - void release(const char* path) - { - m_references.release(CopiedString(path)); - //globalOutputStream() << "release: \"" << path << "\"\n"; - } - - void setEntityCreator(EntityCreator& entityCreator) - { - g_entityCreator = &entityCreator; - } - - bool realised() const - { - return m_unrealised == 0; - } - void realise() - { - ASSERT_MESSAGE(m_unrealised != 0, "HashtableReferenceCache::realise: already realised"); - if(--m_unrealised == 0) - { - g_realised = true; - - { - ModelReferencesSnapshot snapshot(m_references); - for(ModelReferencesSnapshot::iterator i = snapshot.begin(); i != snapshot.end(); ++i) - { - ModelReferences::value_type& value = *(*i); - if(value.value.count() != 1) - { - value.value.get()->realise(); - } - } - } - } - } - void unrealise() - { - if(++m_unrealised == 1) - { - g_realised = false; - - { - ModelReferencesSnapshot snapshot(m_references); - for(ModelReferencesSnapshot::iterator i = snapshot.begin(); i != snapshot.end(); ++i) - { - ModelReferences::value_type& value = *(*i); - if(value.value.count() != 1) - { - value.value.get()->unrealise(); - } - } - } - - ModelCache_clear(); - } - } - void refresh() - { - ModelReferencesSnapshot snapshot(m_references); - for(ModelReferencesSnapshot::iterator i = snapshot.begin(); i != snapshot.end(); ++i) - { - ModelResource* resource = (*(*i)).value.get(); - if(!resource->isMap()) - { - resource->refresh(); - } - } - } +bool realised() const { + return m_unrealised == 0; +} +void realise(){ + ASSERT_MESSAGE( m_unrealised != 0, "HashtableReferenceCache::realise: already realised" ); + if ( --m_unrealised == 0 ) { + g_realised = true; + + { + ModelReferencesSnapshot snapshot( m_references ); + for ( ModelReferencesSnapshot::iterator i = snapshot.begin(); i != snapshot.end(); ++i ) + { + ModelReferences::value_type& value = *( *i ); + if ( value.second.count() != 1 ) { + value.second.get()->realise(); + } + } + } + } +} +void unrealise(){ + if ( ++m_unrealised == 1 ) { + g_realised = false; + + { + ModelReferencesSnapshot snapshot( m_references ); + for ( ModelReferencesSnapshot::iterator i = snapshot.begin(); i != snapshot.end(); ++i ) + { + ModelReferences::value_type& value = *( *i ); + if ( value.second.count() != 1 ) { + value.second.get()->unrealise(); + } + } + } + + ModelCache_clear(); + } +} +void refresh(){ + ModelReferencesSnapshot snapshot( m_references ); + for ( ModelReferencesSnapshot::iterator i = snapshot.begin(); i != snapshot.end(); ++i ) + { + ModelResource* resource = ( *( *i ) ).second.get(); + if ( !resource->isMap() ) { + resource->refresh(); + } + } +} }; namespace { - HashtableReferenceCache g_referenceCache; +HashtableReferenceCache g_referenceCache; } #if 0 class ResourceVisitor { public: - virtual void visit(const char* name, const char* path, const -}; +virtual void visit( const char* name, const char* path, const + }; #endif -void SaveReferences() -{ - ScopeDisableScreenUpdates disableScreenUpdates("Processing...", "Saving Map"); - for(HashtableReferenceCache::iterator i = g_referenceCache.begin(); i != g_referenceCache.end(); ++i) - { - (*i).value->save(); - } - MapChanged(); +void SaveReferences(){ + ScopeDisableScreenUpdates disableScreenUpdates( "Processing...", "Saving Map" ); + for ( HashtableReferenceCache::iterator i = g_referenceCache.begin(); i != g_referenceCache.end(); ++i ) + { + ( *i ).second->save(); + } + MapChanged(); } -bool References_Saved() -{ - for(HashtableReferenceCache::iterator i = g_referenceCache.begin(); i != g_referenceCache.end(); ++i) - { - scene::Node* node = (*i).value->getNode(); - if(node != 0) - { - MapFile* map = Node_getMapFile(*node); - if(map != 0 && !map->saved()) - { - return false; - } - } - } - return true; -} - -void RefreshReferences() -{ - ScopeDisableScreenUpdates disableScreenUpdates("Processing...", "Refreshing Models"); - g_referenceCache.refresh(); +bool References_Saved(){ + for ( HashtableReferenceCache::iterator i = g_referenceCache.begin(); i != g_referenceCache.end(); ++i ) + { + scene::Node* node = ( *i ).second->getNode(); + if ( node != 0 ) { + MapFile* map = Node_getMapFile( *node ); + if ( map != 0 && !map->saved() ) { + return false; + } + } + } + return true; } +void RefreshReferences(){ + ScopeDisableScreenUpdates disableScreenUpdates( "Processing...", "Refreshing Models" ); + g_referenceCache.refresh(); +} -void FlushReferences() -{ - ModelCache_clear(); - g_referenceCache.clear(); +void FlushReferences(){ + ModelCache_clear(); + + g_referenceCache.clear(); } -ReferenceCache& GetReferenceCache() -{ - return g_referenceCache; +ReferenceCache& GetReferenceCache(){ + return g_referenceCache; } @@ -783,64 +679,57 @@ ReferenceCache& GetReferenceCache() #include "modulesystem/moduleregistry.h" class ReferenceDependencies : - public GlobalRadiantModuleRef, - public GlobalFileSystemModuleRef, - public GlobalFiletypesModuleRef + public GlobalRadiantModuleRef, + public GlobalFileSystemModuleRef, + public GlobalFiletypesModuleRef { - ModelModulesRef m_model_modules; - MapModulesRef m_map_modules; +ModelModulesRef m_model_modules; +MapModulesRef m_map_modules; public: - ReferenceDependencies() : - m_model_modules(GlobalRadiant().getRequiredGameDescriptionKeyValue("modeltypes")), - m_map_modules(GlobalRadiant().getRequiredGameDescriptionKeyValue("maptypes")) - { - } - ModelModules& getModelModules() - { - return m_model_modules.get(); - } - MapModules& getMapModules() - { - return m_map_modules.get(); - } +ReferenceDependencies() : + m_model_modules( GlobalRadiant().getRequiredGameDescriptionKeyValue( "modeltypes" ) ), + m_map_modules( GlobalRadiant().getRequiredGameDescriptionKeyValue( "maptypes" ) ) +{ +} +ModelModules& getModelModules(){ + return m_model_modules.get(); +} +MapModules& getMapModules(){ + return m_map_modules.get(); +} }; class ReferenceAPI : public TypeSystemRef { - ReferenceCache* m_reference; +ReferenceCache* m_reference; public: - typedef ReferenceCache Type; - STRING_CONSTANT(Name, "*"); - - ReferenceAPI() - { - g_nullModel = NewNullModel(); - - GlobalFileSystem().attach(g_referenceCache); - - m_reference = &GetReferenceCache(); - } - ~ReferenceAPI() - { - GlobalFileSystem().detach(g_referenceCache); - - g_nullModel = g_nullNode; - } - ReferenceCache* getTable() - { - return m_reference; - } +typedef ReferenceCache Type; +STRING_CONSTANT( Name, "*" ); + +ReferenceAPI(){ + g_nullModel = NewNullModel(); + + GlobalFileSystem().attach( g_referenceCache ); + + m_reference = &GetReferenceCache(); +} +~ReferenceAPI(){ + GlobalFileSystem().detach( g_referenceCache ); + + g_nullModel = g_nullNode; +} +ReferenceCache* getTable(){ + return m_reference; +} }; typedef SingletonModule ReferenceModule; typedef Static StaticReferenceModule; -StaticRegisterModule staticRegisterReference(StaticReferenceModule::instance()); +StaticRegisterModule staticRegisterReference( StaticReferenceModule::instance() ); -ModelModules& ReferenceAPI_getModelModules() -{ - return StaticReferenceModule::instance().getDependencies().getModelModules(); +ModelModules& ReferenceAPI_getModelModules(){ + return StaticReferenceModule::instance().getDependencies().getModelModules(); } -MapModules& ReferenceAPI_getMapModules() -{ - return StaticReferenceModule::instance().getDependencies().getMapModules(); +MapModules& ReferenceAPI_getMapModules(){ + return StaticReferenceModule::instance().getDependencies().getMapModules( ); }