/* 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 "nullmodel.h" #include "debugging/debugging.h" #include "iscenegraph.h" #include "irender.h" #include "iselection.h" #include "iundo.h" #include "ientity.h" #include "ireference.h" #include "igl.h" #include "cullable.h" #include "renderable.h" #include "selectable.h" #include "math/frustum.h" #include "scenelib.h" #include "instancelib.h" #include "entitylib.h" class NullModel : public Bounded, public Cullable { Shader* m_state; AABB m_aabb_local; RenderableSolidAABB m_aabb_solid; RenderableWireframeAABB m_aabb_wire; public: NullModel() : m_aabb_local( Vector3( 0, 0, 0 ), Vector3( 8, 8, 8 ) ), m_aabb_solid( m_aabb_local ), m_aabb_wire( m_aabb_local ){ m_state = GlobalShaderCache().capture( "" ); } ~NullModel(){ GlobalShaderCache().release( "" ); } VolumeIntersectionValue intersectVolume( const VolumeTest& volume, const Matrix4& localToWorld ) const { return volume.TestAABB( m_aabb_local, localToWorld ); } const AABB& localAABB() const { return m_aabb_local; } void renderSolid( Renderer& renderer, const VolumeTest& volume, const Matrix4& localToWorld ) const { renderer.SetState( m_state, Renderer::eFullMaterials ); renderer.addRenderable( m_aabb_solid, localToWorld ); } void renderWireframe( Renderer& renderer, const VolumeTest& volume, const Matrix4& localToWorld ) const { renderer.addRenderable( m_aabb_wire, localToWorld ); } void testSelect( Selector& selector, SelectionTest& test, const Matrix4& localToWorld ){ test.BeginMesh( localToWorld ); SelectionIntersection best; aabb_testselect( m_aabb_local, test, best ); if ( best.valid() ) { selector.addIntersection( best ); } } }; class NullModelInstance : public scene::Instance, public Renderable, public SelectionTestable { class TypeCasts { InstanceTypeCastTable m_casts; public: TypeCasts(){ InstanceContainedCast::install( m_casts ); InstanceContainedCast::install( m_casts ); InstanceStaticCast::install( m_casts ); InstanceStaticCast::install( m_casts ); } InstanceTypeCastTable& get(){ return m_casts; } }; NullModel& m_nullmodel; public: typedef LazyStatic StaticTypeCasts; Bounded& get( NullType){ return m_nullmodel; } Cullable& get( NullType){ return m_nullmodel; } NullModelInstance( const scene::Path& path, scene::Instance* parent, NullModel& nullmodel ) : Instance( path, parent, this, StaticTypeCasts::instance().get() ), m_nullmodel( nullmodel ){ } void renderSolid( Renderer& renderer, const VolumeTest& volume ) const { m_nullmodel.renderSolid( renderer, volume, Instance::localToWorld() ); } void renderWireframe( Renderer& renderer, const VolumeTest& volume ) const { m_nullmodel.renderWireframe( renderer, volume, Instance::localToWorld() ); } void testSelect( Selector& selector, SelectionTest& test ){ m_nullmodel.testSelect( selector, test, Instance::localToWorld() ); } }; class NullModelNode : public scene::Node::Symbiot, public scene::Instantiable { class TypeCasts { NodeTypeCastTable m_casts; public: TypeCasts(){ NodeStaticCast::install( m_casts ); } NodeTypeCastTable& get(){ return m_casts; } }; scene::Node m_node; InstanceSet m_instances; NullModel m_nullmodel; public: typedef LazyStatic StaticTypeCasts; NullModelNode() : m_node( this, this, StaticTypeCasts::instance().get() ){ m_node.m_isRoot = true; } void release(){ delete this; } scene::Node& node(){ return m_node; } scene::Instance* create( const scene::Path& path, scene::Instance* parent ){ return new NullModelInstance( path, parent, m_nullmodel ); } void forEachInstance( const scene::Instantiable::Visitor& visitor ){ m_instances.forEachInstance( visitor ); } void insert( scene::Instantiable::Observer* observer, const scene::Path& path, scene::Instance* instance ){ m_instances.insert( observer, path, instance ); } scene::Instance* erase( scene::Instantiable::Observer* observer, const scene::Path& path ){ return m_instances.erase( observer, path ); } }; NodeSmartReference NewNullModel(){ return NodeSmartReference( ( new NullModelNode )->node() ); } void NullModel_construct(){ } void NullModel_destroy(){ }