/*
-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"
+#include "globaldefs.h"
#include "debugging/debugging.h"
#include "iselection.h"
#include "iundo.h"
#include "imap.h"
+
MapModules& ReferenceAPI_getMapModules();
+
#include "imodel.h"
+
ModelModules& ReferenceAPI_getModelModules();
+
#include "ifilesystem.h"
#include "iarchive.h"
#include "ifiletypes.h"
#include "map.h"
#include "filetypes.h"
+extern bool g_writeMapComments;
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, g_writeMapComments );
+ 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 GDEF_OS_WINDOWS
+ 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 CopiedString& path, const CopiedString& 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 CopiedString& path ) const {
+ return path_hash( path.c_str() );
+ }
};
typedef std::pair<CopiedString, CopiedString> 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<ModelKey, NodeSmartReference, ModelKeyHash, ModelKeyEqual> 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.insert( ModelKey( path, name ), NodeSmartReference( node ) );
+ }
+ return g_modelCache.insert( ModelKey( "", "" ), g_nullModel );
}
-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<MapChanged>());
- }
- }
- 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 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( makeCallbackF(MapChanged) );
+ }
+ }
+
+ 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<CopiedString, ModelResource, PathHash, PathEqual> ModelReferences;
- ModelReferences m_references;
- std::size_t m_unrealised;
-
- class ModelReferencesSnapshot
- {
- ModelReferences& m_references;
- typedef std::list<ModelReferences::iterator> 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<CopiedString, ModelResource, PathHash, PathEqual> ModelReferences;
+ModelReferences m_references;
+std::size_t m_unrealised;
+
+class ModelReferencesSnapshot
+{
+ModelReferences& m_references;
+typedef std::list<ModelReferences::iterator> 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(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();
- }
- }
- }
+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();
+ }
+ }
+}
};
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 ).value->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 ).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();
}
-void FlushReferences()
-{
- ModelCache_clear();
+void FlushReferences(){
+ ModelCache_clear();
- g_referenceCache.clear();
+ g_referenceCache.clear();
}
-ReferenceCache& GetReferenceCache()
-{
- return g_referenceCache;
+ReferenceCache& GetReferenceCache(){
+ return g_referenceCache;
}
#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<ReferenceAPI, ReferenceDependencies> ReferenceModule;
typedef Static<ReferenceModule> 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( );
}