netradiant-custom/radiant/scenegraph.cpp
Garux df02774ff5 tweak StringOutputStream use
auto str = StringOutputStream()(bla) use form was not doing copy elision or move, but copy
2024-01-29 16:54:08 +06:00

264 lines
6.5 KiB
C++

/*
Copyright (C) 2001-2006, William Joseph.
All Rights Reserved.
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 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
*/
#include "scenegraph.h"
#include "debugging/debugging.h"
#include <map>
#include <set>
#include <vector>
#include "string/string.h"
#include "signal/signal.h"
#include "scenelib.h"
#include "instancelib.h"
#include "treemodel.h"
template<std::size_t SIZE>
class TypeIdMap
{
typedef const char* TypeName;
typedef TypeName TypeNames[SIZE];
TypeNames m_typeNames;
TypeName* m_typeNamesEnd;
public:
TypeIdMap() : m_typeNamesEnd( m_typeNames ){
}
TypeId getTypeId( const char* name ){
TypeName* i = std::find_if( m_typeNames, m_typeNamesEnd, [name]( const char* other ){ return string_equal( name, other ); } );
if ( i == m_typeNamesEnd ) {
ASSERT_MESSAGE( m_typeNamesEnd != m_typeNames + SIZE, "reached maximum number of type names supported (" << SIZE << ')' );
*m_typeNamesEnd++ = name;
}
return i - m_typeNames;
}
};
class CompiledGraph final : public scene::Graph, public scene::Instantiable::Observer
{
typedef std::map<PathConstReference, scene::Instance*> InstanceMap;
InstanceMap m_instances;
scene::Instantiable::Observer* m_observer;
Signal0 m_boundsChanged;
scene::Path m_rootpath;
Signal0 m_sceneChangedCallbacks;
TypeIdMap<NODETYPEID_MAX> m_nodeTypeIds;
TypeIdMap<INSTANCETYPEID_MAX> m_instanceTypeIds;
public:
CompiledGraph( scene::Instantiable::Observer* observer )
: m_observer( observer ){
}
void addSceneChangedCallback( const SignalHandler& handler ){
m_sceneChangedCallbacks.connectLast( handler );
}
void sceneChanged(){
m_sceneChangedCallbacks();
}
scene::Node& root(){
ASSERT_MESSAGE( !m_rootpath.empty(), "scenegraph root does not exist" );
return m_rootpath.top();
}
void insert_root( scene::Node& root ){
//globalOutputStream() << "insert_root\n";
ASSERT_MESSAGE( m_rootpath.empty(), "scenegraph root already exists" );
root.IncRef();
Node_traverseSubgraph( root, InstanceSubgraphWalker( this, scene::Path(), 0 ) );
m_rootpath.push( makeReference( root ) );
}
void erase_root(){
//globalOutputStream() << "erase_root\n";
ASSERT_MESSAGE( !m_rootpath.empty(), "scenegraph root does not exist" );
scene::Node& root = m_rootpath.top();
m_rootpath.pop();
Node_traverseSubgraph( root, UninstanceSubgraphWalker( this, scene::Path() ) );
root.DecRef();
}
void boundsChanged(){
m_boundsChanged();
}
void traverse( const Walker& walker ){
traverse_subgraph( walker, m_instances.begin() );
}
void traverse_subgraph( const Walker& walker, const scene::Path& start ){
if ( !m_instances.empty() ) {
traverse_subgraph( walker, m_instances.find( PathConstReference( start ) ) );
}
}
scene::Instance* find( const scene::Path& path ){
InstanceMap::iterator i = m_instances.find( PathConstReference( path ) );
if ( i == m_instances.end() ) {
return 0;
}
return ( *i ).second;
}
void insert( scene::Instance* instance ){
m_instances.insert( InstanceMap::value_type( PathConstReference( instance->path() ), instance ) );
m_observer->insert( instance );
}
void erase( scene::Instance* instance ){
m_observer->erase( instance );
m_instances.erase( PathConstReference( instance->path() ) );
}
SignalHandlerId addBoundsChangedCallback( const SignalHandler& boundsChanged ){
return m_boundsChanged.connectLast( boundsChanged );
}
void removeBoundsChangedCallback( SignalHandlerId id ){
m_boundsChanged.disconnect( id );
}
TypeId getNodeTypeId( const char* name ){
return m_nodeTypeIds.getTypeId( name );
}
TypeId getInstanceTypeId( const char* name ){
return m_instanceTypeIds.getTypeId( name );
}
private:
bool pre( const Walker& walker, const InstanceMap::iterator& i ){
return walker.pre( i->first, *i->second );
}
void post( const Walker& walker, const InstanceMap::iterator& i ){
walker.post( i->first, *i->second );
}
void traverse_subgraph( const Walker& walker, InstanceMap::iterator i ){
Stack<InstanceMap::iterator> stack;
if ( i != m_instances.end() ) {
const std::size_t startSize = ( *i ).first.get().size();
do
{
if ( i != m_instances.end()
&& stack.size() < ( ( *i ).first.get().size() - startSize + 1 ) ) {
stack.push( i );
++i;
if ( !pre( walker, stack.top() ) ) {
// skip subgraph
while ( i != m_instances.end()
&& stack.size() < ( ( *i ).first.get().size() - startSize + 1 ) )
{
++i;
}
}
}
else
{
post( walker, stack.top() );
stack.pop();
}
}
while ( !stack.empty() );
}
}
};
namespace
{
CompiledGraph* g_sceneGraph;
GraphTreeModel* g_tree_model;
}
GraphTreeModel* scene_graph_get_tree_model(){
return g_tree_model;
}
class SceneGraphObserver : public scene::Instantiable::Observer
{
public:
void insert( scene::Instance* instance ){
g_sceneGraph->sceneChanged();
graph_tree_model_insert( g_tree_model, *instance );
}
void erase( scene::Instance* instance ){
g_sceneGraph->sceneChanged();
graph_tree_model_erase( g_tree_model, *instance );
}
};
SceneGraphObserver g_SceneGraphObserver;
void SceneGraph_Construct(){
g_tree_model = graph_tree_model_new();
g_sceneGraph = new CompiledGraph( &g_SceneGraphObserver );
}
void SceneGraph_Destroy(){
delete g_sceneGraph;
graph_tree_model_delete( g_tree_model );
}
#include "modulesystem/singletonmodule.h"
#include "modulesystem/moduleregistry.h"
class SceneGraphAPI
{
scene::Graph* m_scenegraph;
public:
typedef scene::Graph Type;
STRING_CONSTANT( Name, "*" );
SceneGraphAPI(){
SceneGraph_Construct();
m_scenegraph = g_sceneGraph;
}
~SceneGraphAPI(){
SceneGraph_Destroy();
}
scene::Graph* getTable(){
return m_scenegraph;
}
};
typedef SingletonModule<SceneGraphAPI> SceneGraphModule;
typedef Static<SceneGraphModule> StaticSceneGraphModule;
StaticRegisterModule staticRegisterSceneGraph( StaticSceneGraphModule::instance() );