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
23 ///\brief Represents any entity which has a fixed size specified in its entity-definition and does not display a model (e.g. info_player_start).
25 /// This entity displays an axis-aligned bounding box of the size and colour specified in its entity-definition.
26 /// The "origin" key directly controls the entity's local-to-parent transform.
27 /// An arrow is drawn to visualise the "angle" key.
30 #include "renderable.h"
33 #include "math/frustum.h"
34 #include "selectionlib.h"
35 #include "instancelib.h"
36 #include "transformlib.h"
37 #include "entitylib.h"
39 #include "eclasslib.h"
40 #include "math/line.h"
42 #include "targetable.h"
46 #include "namedentity.h"
47 #include "keyobservers.h"
54 class RenderableArrow : public OpenGLRenderable
56 const Vector3& m_origin;
57 const Vector3& m_angles;
60 RenderableArrow( const Vector3& origin, const Vector3& angles )
61 : m_origin( origin ), m_angles( angles ){
64 void render( RenderStateFlags state ) const {
65 Matrix4 mat = matrix4_rotation_for_euler_xyz_degrees( m_angles );
66 arrow_draw( m_origin, matrix4_transformed_direction( mat, Vector3( 1, 0, 0 ) ), matrix4_transformed_direction( mat, Vector3( 0, 1, 0 ) ), matrix4_transformed_direction( mat, Vector3( 0, 0, 1 ) ) );
70 inline void read_aabb( AABB& aabb, const EntityClass& eclass ){
71 aabb = aabb_for_minmax( eclass.mins, eclass.maxs );
80 EntityKeyValues m_entity;
81 KeyObserverMap m_keyObservers;
82 MatrixTransform m_transform;
84 OriginKey m_originKey;
86 AnglesKey m_anglesKey;
89 ClassnameFilter m_filter;
95 RenderableArrow m_arrow;
96 RenderableSolidAABB m_aabb_solid;
97 RenderableWireframeAABB m_aabb_wire;
98 RenderableNamedEntity m_renderName;
100 Callback<void()> m_transformChanged;
101 Callback<void()> m_evaluateTransform;
104 read_aabb( m_aabb_local, m_entity.getEntityClass() );
106 m_keyObservers.insert( "classname", ClassnameFilter::ClassnameChangedCaller( m_filter ) );
107 m_keyObservers.insert( Static<KeyIsName>::instance().m_nameKey, NamedEntity::IdentifierChangedCaller( m_named ) );
108 m_keyObservers.insert( "angle", AnglesKey::AngleChangedCaller( m_anglesKey ) );
109 m_keyObservers.insert( "angles", AnglesKey::AnglesChangedCaller( m_anglesKey ) );
110 m_keyObservers.insert( "origin", OriginKey::OriginChangedCaller( m_originKey ) );
113 // vc 2k5 compiler fix
118 void updateTransform(){
119 m_transform.localToParent() = g_matrix4_identity;
120 matrix4_translate_by_vec3( m_transform.localToParent(), m_origin );
121 m_transformChanged();
123 typedef MemberCaller<GenericEntity, void(), &GenericEntity::updateTransform> UpdateTransformCaller;
124 void originChanged(){
125 m_origin = m_originKey.m_origin;
128 typedef MemberCaller<GenericEntity, void(), &GenericEntity::originChanged> OriginChangedCaller;
129 void anglesChanged(){
130 m_angles = m_anglesKey.m_angles;
133 typedef MemberCaller<GenericEntity, void(), &GenericEntity::anglesChanged> AnglesChangedCaller;
136 GenericEntity( EntityClass* eclass, scene::Node& node, const Callback<void()>& transformChanged, const Callback<void()>& evaluateTransform ) :
138 m_originKey( OriginChangedCaller( *this ) ),
139 m_origin( ORIGINKEY_IDENTITY ),
140 m_anglesKey( AnglesChangedCaller( *this ) ),
141 m_angles( ANGLESKEY_IDENTITY ),
142 m_filter( m_entity, node ),
144 m_nameKeys( m_entity ),
145 m_arrow( m_aabb_local.origin, m_angles ),
146 m_aabb_solid( m_aabb_local ),
147 m_aabb_wire( m_aabb_local ),
148 m_renderName( m_named, g_vector3_identity ),
149 m_transformChanged( transformChanged ),
150 m_evaluateTransform( evaluateTransform ){
153 GenericEntity( const GenericEntity& other, scene::Node& node, const Callback<void()>& transformChanged, const Callback<void()>& evaluateTransform ) :
154 m_entity( other.m_entity ),
155 m_originKey( OriginChangedCaller( *this ) ),
156 m_origin( ORIGINKEY_IDENTITY ),
157 m_anglesKey( AnglesChangedCaller( *this ) ),
158 m_angles( ANGLESKEY_IDENTITY ),
159 m_filter( m_entity, node ),
161 m_nameKeys( m_entity ),
162 m_arrow( m_aabb_local.origin, m_angles ),
163 m_aabb_solid( m_aabb_local ),
164 m_aabb_wire( m_aabb_local ),
165 m_renderName( m_named, g_vector3_identity ),
166 m_transformChanged( transformChanged ),
167 m_evaluateTransform( evaluateTransform ){
171 InstanceCounter m_instanceCounter;
172 void instanceAttach( const scene::Path& path ){
173 if ( ++m_instanceCounter.m_count == 1 ) {
174 m_filter.instanceAttach();
175 m_entity.instanceAttach( path_find_mapfile( path.begin(), path.end() ) );
176 m_entity.attach( m_keyObservers );
179 void instanceDetach( const scene::Path& path ){
180 if ( --m_instanceCounter.m_count == 0 ) {
181 m_entity.detach( m_keyObservers );
182 m_entity.instanceDetach( path_find_mapfile( path.begin(), path.end() ) );
183 m_filter.instanceDetach();
187 EntityKeyValues& getEntity(){
190 const EntityKeyValues& getEntity() const {
194 Namespaced& getNamespaced(){
197 Nameable& getNameable(){
200 TransformNode& getTransformNode(){
204 const AABB& localAABB() const {
208 VolumeIntersectionValue intersectVolume( const VolumeTest& volume, const Matrix4& localToWorld ) const {
209 return volume.TestAABB( localAABB(), localToWorld );
212 void renderArrow( Renderer& renderer, const VolumeTest& volume, const Matrix4& localToWorld ) const {
213 if ( g_showAngles ) {
214 renderer.addRenderable( m_arrow, localToWorld );
217 void renderSolid( Renderer& renderer, const VolumeTest& volume, const Matrix4& localToWorld ) const {
218 renderer.SetState( m_entity.getEntityClass().m_state_fill, Renderer::eFullMaterials );
219 renderer.addRenderable( m_aabb_solid, localToWorld );
220 renderArrow( renderer, volume, localToWorld );
222 void renderWireframe( Renderer& renderer, const VolumeTest& volume, const Matrix4& localToWorld ) const {
223 renderer.SetState( m_entity.getEntityClass().m_state_wire, Renderer::eWireframeOnly );
224 renderer.addRenderable( m_aabb_wire, localToWorld );
225 renderArrow( renderer, volume, localToWorld );
227 renderer.addRenderable( m_renderName, localToWorld );
232 void testSelect( Selector& selector, SelectionTest& test, const Matrix4& localToWorld ){
233 test.BeginMesh( localToWorld );
235 SelectionIntersection best;
236 aabb_testselect( m_aabb_local, test, best );
237 if ( best.valid() ) {
238 selector.addIntersection( best );
242 void translate( const Vector3& translation ){
243 m_origin = origin_translated( m_origin, translation );
245 void rotate( const Quaternion& rotation ){
246 m_angles = angles_rotated( m_angles, rotation );
248 void snapto( float snap ){
249 m_originKey.m_origin = origin_snapped( m_originKey.m_origin, snap );
250 m_originKey.write( &m_entity );
252 void revertTransform(){
253 m_origin = m_originKey.m_origin;
254 m_angles = m_anglesKey.m_angles;
256 void freezeTransform(){
257 m_originKey.m_origin = m_origin;
258 m_originKey.write( &m_entity );
259 m_anglesKey.m_angles = m_angles;
260 m_anglesKey.write( &m_entity );
262 void transformChanged(){
264 m_evaluateTransform();
267 typedef MemberCaller<GenericEntity, void(), &GenericEntity::transformChanged> TransformChangedCaller;
270 class GenericEntityInstance :
271 public TargetableInstance,
272 public TransformModifier,
274 public SelectionTestable
278 InstanceTypeCastTable m_casts;
281 m_casts = TargetableInstance::StaticTypeCasts::instance().get();
282 InstanceContainedCast<GenericEntityInstance, Bounded>::install( m_casts );
283 InstanceContainedCast<GenericEntityInstance, Cullable>::install( m_casts );
284 InstanceStaticCast<GenericEntityInstance, Renderable>::install( m_casts );
285 InstanceStaticCast<GenericEntityInstance, SelectionTestable>::install( m_casts );
286 InstanceStaticCast<GenericEntityInstance, Transformable>::install( m_casts );
287 InstanceIdentityCast<GenericEntityInstance>::install( m_casts );
289 InstanceTypeCastTable& get(){
294 GenericEntity& m_contained;
295 mutable AABB m_bounds;
298 typedef LazyStatic<TypeCasts> StaticTypeCasts;
300 Bounded& get( NullType<Bounded>){
303 Cullable& get( NullType<Cullable>){
307 STRING_CONSTANT( Name, "GenericEntityInstance" );
309 GenericEntityInstance( const scene::Path& path, scene::Instance* parent, GenericEntity& contained ) :
310 TargetableInstance( path, parent, this, StaticTypeCasts::instance().get(), contained.getEntity(), *this ),
311 TransformModifier( GenericEntity::TransformChangedCaller( contained ), ApplyTransformCaller( *this ) ),
312 m_contained( contained ){
313 m_contained.instanceAttach( Instance::path() );
315 StaticRenderableConnectionLines::instance().attach( *this );
317 ~GenericEntityInstance(){
318 StaticRenderableConnectionLines::instance().detach( *this );
320 m_contained.instanceDetach( Instance::path() );
323 void renderSolid( Renderer& renderer, const VolumeTest& volume ) const {
324 m_contained.renderSolid( renderer, volume, Instance::localToWorld() );
326 void renderWireframe( Renderer& renderer, const VolumeTest& volume ) const {
327 m_contained.renderWireframe( renderer, volume, Instance::localToWorld() );
330 void testSelect( Selector& selector, SelectionTest& test ){
331 m_contained.testSelect( selector, test, Instance::localToWorld() );
334 void evaluateTransform(){
335 if ( getType() == TRANSFORM_PRIMITIVE ) {
336 m_contained.translate( getTranslation() );
337 m_contained.rotate( getRotation() );
340 void applyTransform(){
341 m_contained.revertTransform();
343 m_contained.freezeTransform();
345 typedef MemberCaller<GenericEntityInstance, void(), &GenericEntityInstance::applyTransform> ApplyTransformCaller;
348 class GenericEntityNode :
349 public scene::Node::Symbiot,
350 public scene::Instantiable,
351 public scene::Cloneable
355 NodeTypeCastTable m_casts;
358 NodeStaticCast<GenericEntityNode, scene::Instantiable>::install( m_casts );
359 NodeStaticCast<GenericEntityNode, scene::Cloneable>::install( m_casts );
360 NodeContainedCast<GenericEntityNode, Snappable>::install( m_casts );
361 NodeContainedCast<GenericEntityNode, TransformNode>::install( m_casts );
362 NodeContainedCast<GenericEntityNode, Entity>::install( m_casts );
363 NodeContainedCast<GenericEntityNode, Nameable>::install( m_casts );
364 NodeContainedCast<GenericEntityNode, Namespaced>::install( m_casts );
366 NodeTypeCastTable& get(){
372 InstanceSet m_instances;
375 GenericEntity m_contained;
378 typedef LazyStatic<TypeCasts> StaticTypeCasts;
380 Snappable& get( NullType<Snappable>){
383 TransformNode& get( NullType<TransformNode>){
384 return m_contained.getTransformNode();
386 Entity& get( NullType<Entity>){
387 return m_contained.getEntity();
389 Nameable& get( NullType<Nameable>){
390 return m_contained.getNameable();
392 Namespaced& get( NullType<Namespaced>){
393 return m_contained.getNamespaced();
396 GenericEntityNode( EntityClass* eclass ) :
397 m_node( this, this, StaticTypeCasts::instance().get() ),
398 m_contained( eclass, m_node, InstanceSet::TransformChangedCaller( m_instances ), InstanceSetEvaluateTransform<GenericEntityInstance>::Caller( m_instances ) ){
400 GenericEntityNode( const GenericEntityNode& other ) :
401 scene::Node::Symbiot( other ),
402 scene::Instantiable( other ),
403 scene::Cloneable( other ),
404 m_node( this, this, StaticTypeCasts::instance().get() ),
405 m_contained( other.m_contained, m_node, InstanceSet::TransformChangedCaller( m_instances ), InstanceSetEvaluateTransform<GenericEntityInstance>::Caller( m_instances ) ){
414 scene::Node& clone() const {
415 return ( new GenericEntityNode( *this ) )->node();
418 scene::Instance* create( const scene::Path& path, scene::Instance* parent ){
419 return new GenericEntityInstance( path, parent, m_contained );
421 void forEachInstance( const scene::Instantiable::Visitor& visitor ){
422 m_instances.forEachInstance( visitor );
424 void insert( scene::Instantiable::Observer* observer, const scene::Path& path, scene::Instance* instance ){
425 m_instances.insert( observer, path, instance );
427 scene::Instance* erase( scene::Instantiable::Observer* observer, const scene::Path& path ){
428 return m_instances.erase( observer, path );
432 scene::Node& New_GenericEntity( EntityClass* eclass ){
433 return ( new GenericEntityNode( eclass ) )->node();