]> git.xonotic.org Git - xonotic/netradiant.git/blob - libs/entitylib.h
Merge commit '70b21eafbe10c90172922d8a7af4f06b9a3b242d' into master-merge
[xonotic/netradiant.git] / libs / entitylib.h
1 /*
2    Copyright (C) 2001-2006, William Joseph.
3    All Rights Reserved.
4
5    This file is part of GtkRadiant.
6
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.
11
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.
16
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
20  */
21
22 #if !defined ( INCLUDED_ENTITYLIB_H )
23 #define INCLUDED_ENTITYLIB_H
24
25 #include "ireference.h"
26 #include "debugging/debugging.h"
27
28 #include "ientity.h"
29 #include "irender.h"
30 #include "igl.h"
31 #include "selectable.h"
32
33 #include "generic/callback.h"
34 #include "math/vector.h"
35 #include "math/aabb.h"
36 #include "undolib.h"
37 #include "string/pooledstring.h"
38 #include "generic/referencecounted.h"
39 #include "scenelib.h"
40 #include "container/container.h"
41 #include "eclasslib.h"
42
43 #include <list>
44 #include <set>
45
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 ) ) );
48
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 ) ) );
53
54         glBegin( GL_LINES );
55
56         glVertex3fv( vector3_to_array( origin ) );
57         glVertex3fv( vector3_to_array( endpoint ) );
58
59         glVertex3fv( vector3_to_array( endpoint ) );
60         glVertex3fv( vector3_to_array( tip1 ) );
61
62         glVertex3fv( vector3_to_array( endpoint ) );
63         glVertex3fv( vector3_to_array( tip2 ) );
64
65         glVertex3fv( vector3_to_array( endpoint ) );
66         glVertex3fv( vector3_to_array( tip3 ) );
67
68         glVertex3fv( vector3_to_array( endpoint ) );
69         glVertex3fv( vector3_to_array( tip4 ) );
70
71         glVertex3fv( vector3_to_array( tip1 ) );
72         glVertex3fv( vector3_to_array( tip3 ) );
73
74         glVertex3fv( vector3_to_array( tip3 ) );
75         glVertex3fv( vector3_to_array( tip2 ) );
76
77         glVertex3fv( vector3_to_array( tip2 ) );
78         glVertex3fv( vector3_to_array( tip4 ) );
79
80         glVertex3fv( vector3_to_array( tip4 ) );
81         glVertex3fv( vector3_to_array( tip1 ) );
82
83         glEnd();
84 }
85
86 class SelectionIntersection;
87
88 inline void aabb_testselect( const AABB& aabb, SelectionTest& test, SelectionIntersection& best ){
89         const IndexPointer::index_type indices[24] = {
90                 2, 1, 5, 6,
91                 1, 0, 4, 5,
92                 0, 1, 2, 3,
93                 3, 7, 4, 0,
94                 3, 2, 6, 7,
95                 7, 6, 5, 4,
96         };
97
98         Vector3 points[8];
99         aabb_corners( aabb, points );
100         test.TestQuads( VertexPointer( reinterpret_cast<VertexPointer::pointer>( points ), sizeof( Vector3 ) ), IndexPointer( indices, 24 ), best );
101 }
102
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)
110         };
111 #if 1
112         glVertexPointer( 3, GL_FLOAT, 0, points );
113         glDrawElements( GL_LINES, sizeof( indices ) / sizeof( indices[0] ), GL_UNSIGNED_INT, indices );
114 #else
115         glBegin( GL_LINES );
116         for ( std::size_t i = 0; i < sizeof( indices ) / sizeof( indices[0] ); ++i )
117         {
118                 glVertex3fv( points[indices[i]] );
119         }
120         glEnd();
121 #endif
122 }
123
124 inline void aabb_draw_flatshade( const Vector3 points[8] ){
125         glBegin( GL_QUADS );
126
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] ) );
132
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] ) );
138
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] ) );
144
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] ) );
150
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] ) );
156
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] ) );
162
163         glEnd();
164 }
165
166 inline void aabb_draw_wire( const AABB& aabb ){
167         Vector3 points[8];
168         aabb_corners( aabb, points );
169         aabb_draw_wire( points );
170 }
171
172 inline void aabb_draw_flatshade( const AABB& aabb ){
173         Vector3 points[8];
174         aabb_corners( aabb, points );
175         aabb_draw_flatshade( points );
176 }
177
178 inline void aabb_draw_textured( const AABB& aabb ){
179         Vector3 points[8];
180         aabb_corners( aabb, points );
181
182         glBegin( GL_QUADS );
183
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] ) );
193
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] ) );
203
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] ) );
213
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] ) );
223
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] ) );
233
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] ) );
243
244         glEnd();
245 }
246
247 inline void aabb_draw_solid( const AABB& aabb, RenderStateFlags state ){
248         if ( state & RENDER_TEXTURE ) {
249                 aabb_draw_textured( aabb );
250         }
251         else
252         {
253                 aabb_draw_flatshade( aabb );
254         }
255 }
256
257 inline void aabb_draw( const AABB& aabb, RenderStateFlags state ){
258         if ( state & RENDER_FILL ) {
259                 aabb_draw_solid( aabb, state );
260         }
261         else
262         {
263                 aabb_draw_wire( aabb );
264         }
265 }
266
267 class RenderableSolidAABB : public OpenGLRenderable
268 {
269 const AABB& m_aabb;
270 public:
271 RenderableSolidAABB( const AABB& aabb ) : m_aabb( aabb ){
272 }
273 void render( RenderStateFlags state ) const {
274         aabb_draw_solid( m_aabb, state );
275 }
276 };
277
278 class RenderableWireframeAABB : public OpenGLRenderable
279 {
280 const AABB& m_aabb;
281 public:
282 RenderableWireframeAABB( const AABB& aabb ) : m_aabb( aabb ){
283 }
284 void render( RenderStateFlags state ) const {
285         aabb_draw_wire( m_aabb );
286 }
287 };
288
289
290 /// \brief A key/value pair of strings.
291 ///
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
295 {
296         typedef UnsortedSet<KeyObserver> KeyObservers;
297
298         std::size_t m_refcount;
299         KeyObservers m_observers;
300         CopiedString m_string;
301         const char* m_empty;
302         ObservedUndoableObject<CopiedString> m_undo;
303         static EntityCreator::KeyValueChangedFunc m_entityKeyValueChanged;
304
305 public:
306         KeyValue( const char* string, const char* empty )
307                 : m_refcount( 0 ), m_string( string ), m_empty( empty ), m_undo( m_string, UndoImportCaller( *this ) ){
308                 notify();
309         }
310         ~KeyValue(){
311                 ASSERT_MESSAGE( m_observers.empty(), "KeyValue::~KeyValue: observers still attached" );
312         }
313
314         static void setKeyValueChangedFunc( EntityCreator::KeyValueChangedFunc func ){
315                 m_entityKeyValueChanged = func;
316         }
317
318         void IncRef(){
319                 ++m_refcount;
320         }
321         void DecRef(){
322                 if ( --m_refcount == 0 ) {
323                         delete this;
324                 }
325         }
326
327         void instanceAttach( MapFile* map ){
328                 m_undo.instanceAttach( map );
329         }
330         void instanceDetach( MapFile* map ){
331                 m_undo.instanceDetach( map );
332         }
333
334         void attach( const KeyObserver& observer ){
335                 ( *m_observers.insert ( observer ) )( c_str() );
336         }
337         void detach( const KeyObserver& observer ){
338                 observer( m_empty );
339                 m_observers.erase( observer );
340         }
341         const char* c_str() const {
342                 if ( string_empty( m_string.c_str() ) ) {
343                         return m_empty;
344                 }
345                 return m_string.c_str();
346         }
347         void assign( const char* other ){
348                 if ( !string_equal( m_string.c_str(), other ) ) {
349                         m_undo.save();
350                         m_string = other;
351                         notify();
352                 }
353         }
354
355         void notify(){
356                 m_entityKeyValueChanged();
357                 KeyObservers::reverse_iterator i = m_observers.rbegin();
358                 while ( i != m_observers.rend() )
359                 {
360                         ( *i++ )( c_str() );
361                 }
362         }
363
364         void importState( const CopiedString& string ){
365                 m_string = string;
366
367                 notify();
368         }
369         typedef MemberCaller<KeyValue, void(const CopiedString&), &KeyValue::importState> UndoImportCaller;
370 };
371
372 /// \brief An unsorted list of key/value pairs.
373 ///
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
378 {
379 public:
380         typedef KeyValue Value;
381
382         static StringPool& getPool(){
383                 return Static<StringPool, KeyContext>::instance();
384         }
385 private:
386         static EntityCreator::KeyValueChangedFunc m_entityKeyValueChanged;
387         static Counter* m_counter;
388
389         EntityClass* m_eclass;
390
391         class KeyContext {};
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;
397
398         typedef UnsortedSet<Observer*> Observers;
399         Observers m_observers;
400
401         ObservedUndoableObject<KeyValues> m_undo;
402         bool m_instanced;
403
404         bool m_observerMutex;
405
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 )
409                 {
410                         ( *i )->insert( key, value );
411                 }
412                 m_observerMutex = false;
413         }
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 )
417                 {
418                         ( *i )->erase( key, value );
419                 }
420                 m_observerMutex = false;
421         }
422
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 );
426
427                 if ( m_instanced ) {
428                         ( *i ).second->instanceAttach( m_undo.map() );
429                 }
430         }
431
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 );
436                 }
437                 else
438                 {
439                         m_undo.save();
440                         insert( key, KeyValuePtr( new KeyValue( value, EntityClass_valueForKey( *m_eclass, key ) ) ) );
441                 }
442         }
443
444         void erase( KeyValues::iterator i ){
445                 if ( m_instanced ) {
446                         ( *i ).second->instanceDetach( m_undo.map() );
447                 }
448
449                 Key key( ( *i ).first );
450                 KeyValuePtr value( ( *i ).second );
451                 m_keyValues.erase( i );
452                 notifyErase( key.c_str(), *value );
453         }
454
455         void erase( const char* key ){
456                 KeyValues::iterator i = m_keyValues.find( key );
457                 if ( i != m_keyValues.end() ) {
458                         m_undo.save();
459                         erase( i );
460                 }
461         }
462
463 public:
464         bool m_isContainer;
465
466         EntityKeyValues( EntityClass* eclass ) :
467                 m_eclass( eclass ),
468                 m_undo( m_keyValues, UndoImportCaller( *this ) ),
469                 m_instanced( false ),
470                 m_observerMutex( false ),
471                 m_isContainer( !eclass->fixedsize ){
472         }
473         EntityKeyValues( const EntityKeyValues& other ) :
474                 Entity( 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 )
481                 {
482                         insert( ( *i ).first.c_str(), ( *i ).second->c_str() );
483                 }
484         }
485         ~EntityKeyValues(){
486                 for ( Observers::iterator i = m_observers.begin(); i != m_observers.end(); )
487                 {
488             // post-increment to allow current element to be removed safely
489                         ( *i++ )->clear();
490                 }
491                 ASSERT_MESSAGE( m_observers.empty(), "EntityKeyValues::~EntityKeyValues: observers still attached" );
492         }
493
494         static void setKeyValueChangedFunc( EntityCreator::KeyValueChangedFunc func ){
495                 m_entityKeyValueChanged = func;
496                 KeyValue::setKeyValueChangedFunc( func );
497         }
498         static void setCounter( Counter* counter ){
499                 m_counter = counter;
500         }
501
502         void importState( const KeyValues& keyValues ){
503                 for ( KeyValues::iterator i = m_keyValues.begin(); i != m_keyValues.end(); )
504                 {
505                         erase( i++ );
506                 }
507
508                 for ( KeyValues::const_iterator i = keyValues.begin(); i != keyValues.end(); ++i )
509                 {
510                         insert( ( *i ).first.c_str(), ( *i ).second );
511                 }
512
513                 m_entityKeyValueChanged();
514         }
515         typedef MemberCaller<EntityKeyValues, void(const KeyValues&), &EntityKeyValues::importState> UndoImportCaller;
516
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 )
521                 {
522                         observer.insert( ( *i ).first.c_str(), *( *i ).second );
523                 }
524         }
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 )
529                 {
530                         observer.erase( ( *i ).first.c_str(), *( *i ).second );
531                 }
532         }
533
534         void forEachKeyValue_instanceAttach( MapFile* map ){
535                 for ( KeyValues::const_iterator i = m_keyValues.begin(); i != m_keyValues.end(); ++i )
536                 {
537                         ( *i ).second->instanceAttach( map );
538                 }
539         }
540         void forEachKeyValue_instanceDetach( MapFile* map ){
541                 for ( KeyValues::const_iterator i = m_keyValues.begin(); i != m_keyValues.end(); ++i )
542                 {
543                         ( *i ).second->instanceDetach( map );
544                 }
545         }
546
547         void instanceAttach( MapFile* map ){
548                 if ( m_counter != 0 ) {
549                         m_counter->increment();
550                 }
551
552                 m_instanced = true;
553                 forEachKeyValue_instanceAttach( map );
554                 m_undo.instanceAttach( map );
555         }
556         void instanceDetach( MapFile* map ){
557                 if ( m_counter != 0 ) {
558                         m_counter->decrement();
559                 }
560
561                 m_undo.instanceDetach( map );
562                 forEachKeyValue_instanceDetach( map );
563                 m_instanced = false;
564         }
565
566     // entity
567         EntityClass& getEntityClass() const {
568                 return *m_eclass;
569         }
570         void forEachKeyValue( Visitor& visitor ) const {
571                 for ( KeyValues::const_iterator i = m_keyValues.begin(); i != m_keyValues.end(); ++i )
572                 {
573                         visitor.visit( ( *i ).first.c_str(), ( *i ).second->c_str() );
574                 }
575         }
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
579                         erase( key );
580                 }
581                 else
582                 {
583                         insert( key, value );
584                 }
585                 m_entityKeyValueChanged();
586         }
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();
591                 }
592
593                 return EntityClass_valueForKey( *m_eclass, key );
594         }
595
596         bool isContainer() const {
597                 return m_isContainer;
598         }
599 };
600
601 /// \brief A Resource reference with a controlled lifetime.
602 /// \brief The resource is released when the ResourceReference is destroyed.
603 class ResourceReference
604 {
605         CopiedString m_name;
606         Resource* m_resource;
607 public:
608         ResourceReference( const char* name )
609                 : m_name( name ){
610                 capture();
611         }
612         ResourceReference( const ResourceReference& other )
613                 : m_name( other.m_name ){
614                 capture();
615         }
616         ResourceReference& operator=( const ResourceReference& other ){
617                 ResourceReference tmp( other );
618                 tmp.swap( *this );
619                 return *this;
620         }
621         ~ResourceReference(){
622                 release();
623         }
624
625         void capture(){
626                 m_resource = GlobalReferenceCache().capture( m_name.c_str() );
627         }
628         void release(){
629                 GlobalReferenceCache().release( m_name.c_str() );
630         }
631
632         const char* getName() const {
633                 return m_name.c_str();
634         }
635         void setName( const char* name ){
636                 ResourceReference tmp( name );
637                 tmp.swap( *this );
638         }
639
640         void swap( ResourceReference& other ){
641                 std::swap( m_resource, other.m_resource );
642                 std::swap( m_name, other.m_name );
643         }
644
645         void attach( ModuleObserver& observer ){
646                 m_resource->attach( observer );
647         }
648         void detach( ModuleObserver& observer ){
649                 m_resource->detach( observer );
650         }
651
652         Resource* get(){
653                 return m_resource;
654         }
655 };
656
657 namespace std
658 {
659     /// \brief Swaps the values of \p self and \p other.
660     /// Overloads std::swap.
661         inline void swap( ResourceReference& self, ResourceReference& other ){
662                 self.swap( other );
663         }
664 }
665
666 #endif