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
22 #if !defined ( INCLUDED_ENTITYLIB_H )
23 #define INCLUDED_ENTITYLIB_H
25 #include "ireference.h"
26 #include "debugging/debugging.h"
31 #include "selectable.h"
33 #include "generic/callback.h"
34 #include "math/vector.h"
35 #include "math/aabb.h"
37 #include "string/pooledstring.h"
38 #include "generic/referencecounted.h"
40 #include "container/container.h"
41 #include "eclasslib.h"
46 inline void arrow_draw( const Vector3& origin, const Vector3& direction_forward, const Vector3& direction_left, const Vector3& direction_up ){
47 Vector3 endpoint( vector3_added( origin, vector3_scaled( direction_forward, 32.0 ) ) );
49 Vector3 tip1( vector3_added( vector3_added( endpoint, vector3_scaled( direction_forward, -8.0 ) ), vector3_scaled( direction_up, -4.0 ) ) );
50 Vector3 tip2( vector3_added( tip1, vector3_scaled( direction_up, 8.0 ) ) );
51 Vector3 tip3( vector3_added( vector3_added( endpoint, vector3_scaled( direction_forward, -8.0 ) ), vector3_scaled( direction_left, -4.0 ) ) );
52 Vector3 tip4( vector3_added( tip3, vector3_scaled( direction_left, 8.0 ) ) );
56 glVertex3fv( vector3_to_array( origin ) );
57 glVertex3fv( vector3_to_array( endpoint ) );
59 glVertex3fv( vector3_to_array( endpoint ) );
60 glVertex3fv( vector3_to_array( tip1 ) );
62 glVertex3fv( vector3_to_array( endpoint ) );
63 glVertex3fv( vector3_to_array( tip2 ) );
65 glVertex3fv( vector3_to_array( endpoint ) );
66 glVertex3fv( vector3_to_array( tip3 ) );
68 glVertex3fv( vector3_to_array( endpoint ) );
69 glVertex3fv( vector3_to_array( tip4 ) );
71 glVertex3fv( vector3_to_array( tip1 ) );
72 glVertex3fv( vector3_to_array( tip3 ) );
74 glVertex3fv( vector3_to_array( tip3 ) );
75 glVertex3fv( vector3_to_array( tip2 ) );
77 glVertex3fv( vector3_to_array( tip2 ) );
78 glVertex3fv( vector3_to_array( tip4 ) );
80 glVertex3fv( vector3_to_array( tip4 ) );
81 glVertex3fv( vector3_to_array( tip1 ) );
86 class SelectionIntersection;
88 inline void aabb_testselect( const AABB& aabb, SelectionTest& test, SelectionIntersection& best ){
89 const IndexPointer::index_type indices[24] = {
99 aabb_corners( aabb, points );
100 test.TestQuads( VertexPointer( reinterpret_cast<VertexPointer::pointer>( points ), sizeof( Vector3 ) ), IndexPointer( indices, 24 ), best );
103 inline void aabb_draw_wire( const Vector3 points[8] ){
104 unsigned int indices[26] = {
105 0, 1, 1, 2, 2, 3, 3, 0,
106 4, 5, 5, 6, 6, 7, 7, 4,
107 0, 4, 1, 5, 2, 6, 3, 7,
108 // 0, 6, 1, 7, 2, 4, 3, 5 // X cross
109 1, 7 // diagonal line (connect mins to maxs corner)
112 glVertexPointer( 3, GL_FLOAT, 0, points );
113 glDrawElements( GL_LINES, sizeof( indices ) / sizeof( indices[0] ), GL_UNSIGNED_INT, indices );
116 for ( std::size_t i = 0; i < sizeof( indices ) / sizeof( indices[0] ); ++i )
118 glVertex3fv( points[indices[i]] );
124 inline void aabb_draw_flatshade( const Vector3 points[8] ){
127 glNormal3fv( vector3_to_array( aabb_normals[0] ) );
128 glVertex3fv( vector3_to_array( points[2] ) );
129 glVertex3fv( vector3_to_array( points[1] ) );
130 glVertex3fv( vector3_to_array( points[5] ) );
131 glVertex3fv( vector3_to_array( points[6] ) );
133 glNormal3fv( vector3_to_array( aabb_normals[1] ) );
134 glVertex3fv( vector3_to_array( points[1] ) );
135 glVertex3fv( vector3_to_array( points[0] ) );
136 glVertex3fv( vector3_to_array( points[4] ) );
137 glVertex3fv( vector3_to_array( points[5] ) );
139 glNormal3fv( vector3_to_array( aabb_normals[2] ) );
140 glVertex3fv( vector3_to_array( points[0] ) );
141 glVertex3fv( vector3_to_array( points[1] ) );
142 glVertex3fv( vector3_to_array( points[2] ) );
143 glVertex3fv( vector3_to_array( points[3] ) );
145 glNormal3fv( vector3_to_array( aabb_normals[3] ) );
146 glVertex3fv( vector3_to_array( points[0] ) );
147 glVertex3fv( vector3_to_array( points[3] ) );
148 glVertex3fv( vector3_to_array( points[7] ) );
149 glVertex3fv( vector3_to_array( points[4] ) );
151 glNormal3fv( vector3_to_array( aabb_normals[4] ) );
152 glVertex3fv( vector3_to_array( points[3] ) );
153 glVertex3fv( vector3_to_array( points[2] ) );
154 glVertex3fv( vector3_to_array( points[6] ) );
155 glVertex3fv( vector3_to_array( points[7] ) );
157 glNormal3fv( vector3_to_array( aabb_normals[5] ) );
158 glVertex3fv( vector3_to_array( points[7] ) );
159 glVertex3fv( vector3_to_array( points[6] ) );
160 glVertex3fv( vector3_to_array( points[5] ) );
161 glVertex3fv( vector3_to_array( points[4] ) );
166 inline void aabb_draw_wire( const AABB& aabb ){
168 aabb_corners( aabb, points );
169 aabb_draw_wire( points );
172 inline void aabb_draw_flatshade( const AABB& aabb ){
174 aabb_corners( aabb, points );
175 aabb_draw_flatshade( points );
178 inline void aabb_draw_textured( const AABB& aabb ){
180 aabb_corners( aabb, points );
184 glNormal3fv( vector3_to_array( aabb_normals[0] ) );
185 glTexCoord2fv( aabb_texcoord_topleft );
186 glVertex3fv( vector3_to_array( points[2] ) );
187 glTexCoord2fv( aabb_texcoord_topright );
188 glVertex3fv( vector3_to_array( points[1] ) );
189 glTexCoord2fv( aabb_texcoord_botright );
190 glVertex3fv( vector3_to_array( points[5] ) );
191 glTexCoord2fv( aabb_texcoord_botleft );
192 glVertex3fv( vector3_to_array( points[6] ) );
194 glNormal3fv( vector3_to_array( aabb_normals[1] ) );
195 glTexCoord2fv( aabb_texcoord_topleft );
196 glVertex3fv( vector3_to_array( points[1] ) );
197 glTexCoord2fv( aabb_texcoord_topright );
198 glVertex3fv( vector3_to_array( points[0] ) );
199 glTexCoord2fv( aabb_texcoord_botright );
200 glVertex3fv( vector3_to_array( points[4] ) );
201 glTexCoord2fv( aabb_texcoord_botleft );
202 glVertex3fv( vector3_to_array( points[5] ) );
204 glNormal3fv( vector3_to_array( aabb_normals[2] ) );
205 glTexCoord2fv( aabb_texcoord_topleft );
206 glVertex3fv( vector3_to_array( points[0] ) );
207 glTexCoord2fv( aabb_texcoord_topright );
208 glVertex3fv( vector3_to_array( points[1] ) );
209 glTexCoord2fv( aabb_texcoord_botright );
210 glVertex3fv( vector3_to_array( points[2] ) );
211 glTexCoord2fv( aabb_texcoord_botleft );
212 glVertex3fv( vector3_to_array( points[3] ) );
214 glNormal3fv( vector3_to_array( aabb_normals[3] ) );
215 glTexCoord2fv( aabb_texcoord_topleft );
216 glVertex3fv( vector3_to_array( points[0] ) );
217 glTexCoord2fv( aabb_texcoord_topright );
218 glVertex3fv( vector3_to_array( points[3] ) );
219 glTexCoord2fv( aabb_texcoord_botright );
220 glVertex3fv( vector3_to_array( points[7] ) );
221 glTexCoord2fv( aabb_texcoord_botleft );
222 glVertex3fv( vector3_to_array( points[4] ) );
224 glNormal3fv( vector3_to_array( aabb_normals[4] ) );
225 glTexCoord2fv( aabb_texcoord_topleft );
226 glVertex3fv( vector3_to_array( points[3] ) );
227 glTexCoord2fv( aabb_texcoord_topright );
228 glVertex3fv( vector3_to_array( points[2] ) );
229 glTexCoord2fv( aabb_texcoord_botright );
230 glVertex3fv( vector3_to_array( points[6] ) );
231 glTexCoord2fv( aabb_texcoord_botleft );
232 glVertex3fv( vector3_to_array( points[7] ) );
234 glNormal3fv( vector3_to_array( aabb_normals[5] ) );
235 glTexCoord2fv( aabb_texcoord_topleft );
236 glVertex3fv( vector3_to_array( points[7] ) );
237 glTexCoord2fv( aabb_texcoord_topright );
238 glVertex3fv( vector3_to_array( points[6] ) );
239 glTexCoord2fv( aabb_texcoord_botright );
240 glVertex3fv( vector3_to_array( points[5] ) );
241 glTexCoord2fv( aabb_texcoord_botleft );
242 glVertex3fv( vector3_to_array( points[4] ) );
247 inline void aabb_draw_solid( const AABB& aabb, RenderStateFlags state ){
248 if ( state & RENDER_TEXTURE ) {
249 aabb_draw_textured( aabb );
253 aabb_draw_flatshade( aabb );
257 inline void aabb_draw( const AABB& aabb, RenderStateFlags state ){
258 if ( state & RENDER_FILL ) {
259 aabb_draw_solid( aabb, state );
263 aabb_draw_wire( aabb );
267 class RenderableSolidAABB : public OpenGLRenderable
271 RenderableSolidAABB( const AABB& aabb ) : m_aabb( aabb ){
273 void render( RenderStateFlags state ) const {
274 aabb_draw_solid( m_aabb, state );
278 class RenderableWireframeAABB : public OpenGLRenderable
282 RenderableWireframeAABB( const AABB& aabb ) : m_aabb( aabb ){
284 void render( RenderStateFlags state ) const {
285 aabb_draw_wire( m_aabb );
290 /// \brief A key/value pair of strings.
292 /// - Notifies observers when value changes - value changes to "" on destruction.
293 /// - Provides undo support through the global undo system.
294 class KeyValue : public EntityKeyValue
296 typedef UnsortedSet<KeyObserver> KeyObservers;
298 std::size_t m_refcount;
299 KeyObservers m_observers;
300 CopiedString m_string;
302 ObservedUndoableObject<CopiedString> m_undo;
303 static EntityCreator::KeyValueChangedFunc m_entityKeyValueChanged;
306 KeyValue( const char* string, const char* empty )
307 : m_refcount( 0 ), m_string( string ), m_empty( empty ), m_undo( m_string, UndoImportCaller( *this ) ){
311 ASSERT_MESSAGE( m_observers.empty(), "KeyValue::~KeyValue: observers still attached" );
314 static void setKeyValueChangedFunc( EntityCreator::KeyValueChangedFunc func ){
315 m_entityKeyValueChanged = func;
322 if ( --m_refcount == 0 ) {
327 void instanceAttach( MapFile* map ){
328 m_undo.instanceAttach( map );
330 void instanceDetach( MapFile* map ){
331 m_undo.instanceDetach( map );
334 void attach( const KeyObserver& observer ){
335 ( *m_observers.insert ( observer ) )( c_str() );
337 void detach( const KeyObserver& observer ){
339 m_observers.erase( observer );
341 const char* c_str() const {
342 if ( string_empty( m_string.c_str() ) ) {
345 return m_string.c_str();
347 void assign( const char* other ){
348 if ( !string_equal( m_string.c_str(), other ) ) {
356 m_entityKeyValueChanged();
357 KeyObservers::reverse_iterator i = m_observers.rbegin();
358 while ( i != m_observers.rend() )
364 void importState( const CopiedString& string ){
369 typedef MemberCaller<KeyValue, void(const CopiedString&), &KeyValue::importState> UndoImportCaller;
372 /// \brief An unsorted list of key/value pairs.
374 /// - Notifies observers when a pair is inserted or removed.
375 /// - Provides undo support through the global undo system.
376 /// - New keys are appended to the end of the list.
377 class EntityKeyValues : public Entity
380 typedef KeyValue Value;
382 static StringPool& getPool(){
383 return Static<StringPool, KeyContext>::instance();
386 static EntityCreator::KeyValueChangedFunc m_entityKeyValueChanged;
387 static Counter* m_counter;
389 EntityClass* m_eclass;
392 typedef Static<StringPool, KeyContext> KeyPool;
393 typedef PooledString<KeyPool> Key;
394 typedef SmartPointer<KeyValue> KeyValuePtr;
395 typedef UnsortedMap<Key, KeyValuePtr> KeyValues;
396 KeyValues m_keyValues;
398 typedef UnsortedSet<Observer*> Observers;
399 Observers m_observers;
401 ObservedUndoableObject<KeyValues> m_undo;
404 bool m_observerMutex;
406 void notifyInsert( const char* key, Value& value ){
407 m_observerMutex = true;
408 for ( Observers::iterator i = m_observers.begin(); i != m_observers.end(); ++i )
410 ( *i )->insert( key, value );
412 m_observerMutex = false;
414 void notifyErase( const char* key, Value& value ){
415 m_observerMutex = true;
416 for ( Observers::iterator i = m_observers.begin(); i != m_observers.end(); ++i )
418 ( *i )->erase( key, value );
420 m_observerMutex = false;
423 void insert( const char* key, const KeyValuePtr& keyValue ){
424 KeyValues::iterator i = m_keyValues.insert( KeyValues::value_type( key, keyValue ) );
425 notifyInsert( key, *( *i ).second );
428 ( *i ).second->instanceAttach( m_undo.map() );
432 void insert( const char* key, const char* value ){
433 KeyValues::iterator i = m_keyValues.find( key );
434 if ( i != m_keyValues.end() ) {
435 ( *i ).second->assign( value );
440 insert( key, KeyValuePtr( new KeyValue( value, EntityClass_valueForKey( *m_eclass, key ) ) ) );
444 void erase( KeyValues::iterator i ){
446 ( *i ).second->instanceDetach( m_undo.map() );
449 Key key( ( *i ).first );
450 KeyValuePtr value( ( *i ).second );
451 m_keyValues.erase( i );
452 notifyErase( key.c_str(), *value );
455 void erase( const char* key ){
456 KeyValues::iterator i = m_keyValues.find( key );
457 if ( i != m_keyValues.end() ) {
466 EntityKeyValues( EntityClass* eclass ) :
468 m_undo( m_keyValues, UndoImportCaller( *this ) ),
469 m_instanced( false ),
470 m_observerMutex( false ),
471 m_isContainer( !eclass->fixedsize ){
473 EntityKeyValues( const EntityKeyValues& other ) :
475 m_eclass( &other.getEntityClass() ),
476 m_undo( m_keyValues, UndoImportCaller( *this ) ),
477 m_instanced( false ),
478 m_observerMutex( false ),
479 m_isContainer( other.m_isContainer ){
480 for ( KeyValues::const_iterator i = other.m_keyValues.begin(); i != other.m_keyValues.end(); ++i )
482 insert( ( *i ).first.c_str(), ( *i ).second->c_str() );
486 for ( Observers::iterator i = m_observers.begin(); i != m_observers.end(); )
488 // post-increment to allow current element to be removed safely
491 ASSERT_MESSAGE( m_observers.empty(), "EntityKeyValues::~EntityKeyValues: observers still attached" );
494 static void setKeyValueChangedFunc( EntityCreator::KeyValueChangedFunc func ){
495 m_entityKeyValueChanged = func;
496 KeyValue::setKeyValueChangedFunc( func );
498 static void setCounter( Counter* counter ){
502 void importState( const KeyValues& keyValues ){
503 for ( KeyValues::iterator i = m_keyValues.begin(); i != m_keyValues.end(); )
508 for ( KeyValues::const_iterator i = keyValues.begin(); i != keyValues.end(); ++i )
510 insert( ( *i ).first.c_str(), ( *i ).second );
513 m_entityKeyValueChanged();
515 typedef MemberCaller<EntityKeyValues, void(const KeyValues&), &EntityKeyValues::importState> UndoImportCaller;
517 void attach( Observer& observer ){
518 ASSERT_MESSAGE( !m_observerMutex, "observer cannot be attached during iteration" );
519 m_observers.insert( &observer );
520 for ( KeyValues::const_iterator i = m_keyValues.begin(); i != m_keyValues.end(); ++i )
522 observer.insert( ( *i ).first.c_str(), *( *i ).second );
525 void detach( Observer& observer ){
526 ASSERT_MESSAGE( !m_observerMutex, "observer cannot be detached during iteration" );
527 m_observers.erase( &observer );
528 for ( KeyValues::const_iterator i = m_keyValues.begin(); i != m_keyValues.end(); ++i )
530 observer.erase( ( *i ).first.c_str(), *( *i ).second );
534 void forEachKeyValue_instanceAttach( MapFile* map ){
535 for ( KeyValues::const_iterator i = m_keyValues.begin(); i != m_keyValues.end(); ++i )
537 ( *i ).second->instanceAttach( map );
540 void forEachKeyValue_instanceDetach( MapFile* map ){
541 for ( KeyValues::const_iterator i = m_keyValues.begin(); i != m_keyValues.end(); ++i )
543 ( *i ).second->instanceDetach( map );
547 void instanceAttach( MapFile* map ){
548 if ( m_counter != 0 ) {
549 m_counter->increment();
553 forEachKeyValue_instanceAttach( map );
554 m_undo.instanceAttach( map );
556 void instanceDetach( MapFile* map ){
557 if ( m_counter != 0 ) {
558 m_counter->decrement();
561 m_undo.instanceDetach( map );
562 forEachKeyValue_instanceDetach( map );
567 EntityClass& getEntityClass() const {
570 void forEachKeyValue( Visitor& visitor ) const {
571 for ( KeyValues::const_iterator i = m_keyValues.begin(); i != m_keyValues.end(); ++i )
573 visitor.visit( ( *i ).first.c_str(), ( *i ).second->c_str() );
576 void setKeyValue( const char* key, const char* value ){
577 if ( value[0] == '\0'
578 /*|| string_equal(EntityClass_valueForKey(*m_eclass, key), value)*/ ) { // don't delete values equal to default
583 insert( key, value );
585 m_entityKeyValueChanged();
587 const char* getKeyValue( const char* key ) const {
588 KeyValues::const_iterator i = m_keyValues.find( key );
589 if ( i != m_keyValues.end() ) {
590 return ( *i ).second->c_str();
593 return EntityClass_valueForKey( *m_eclass, key );
596 bool isContainer() const {
597 return m_isContainer;
601 /// \brief A Resource reference with a controlled lifetime.
602 /// \brief The resource is released when the ResourceReference is destroyed.
603 class ResourceReference
606 Resource* m_resource;
608 ResourceReference( const char* name )
612 ResourceReference( const ResourceReference& other )
613 : m_name( other.m_name ){
616 ResourceReference& operator=( const ResourceReference& other ){
617 ResourceReference tmp( other );
621 ~ResourceReference(){
626 m_resource = GlobalReferenceCache().capture( m_name.c_str() );
629 GlobalReferenceCache().release( m_name.c_str() );
632 const char* getName() const {
633 return m_name.c_str();
635 void setName( const char* name ){
636 ResourceReference tmp( name );
640 void swap( ResourceReference& other ){
641 std::swap( m_resource, other.m_resource );
642 std::swap( m_name, other.m_name );
645 void attach( ModuleObserver& observer ){
646 m_resource->attach( observer );
648 void detach( ModuleObserver& observer ){
649 m_resource->detach( observer );
659 /// \brief Swaps the values of \p self and \p other.
660 /// Overloads std::swap.
661 inline void swap( ResourceReference& self, ResourceReference& other ){