]> git.xonotic.org Git - xonotic/netradiant.git/blob - libs/entitylib.h
Merge commit 'fe73dd74d0e40a33c090993390e4d5721a1f9e05' into garux-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 public:
305
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         void forEachKeyValue_notifyInsert(){
423                 for ( KeyValues::const_iterator i = m_keyValues.begin(); i != m_keyValues.end(); ++i )
424                 {
425                         notifyInsert( ( *i ).first.c_str(), *( *i ).second );
426                 }
427         }
428         void forEachKeyValue_notifyErase(){
429                 for ( KeyValues::const_iterator i = m_keyValues.begin(); i != m_keyValues.end(); ++i )
430                 {
431                         notifyErase( ( *i ).first.c_str(), *( *i ).second );
432                 }
433         }
434
435         void insert( const char* key, const KeyValuePtr& keyValue ){
436                 KeyValues::iterator i = m_keyValues.insert( KeyValues::value_type( key, keyValue ) );
437                 notifyInsert( key, *( *i ).second );
438
439                 if ( m_instanced ) {
440                         ( *i ).second->instanceAttach( m_undo.map() );
441                 }
442         }
443
444         void insert( const char* key, const char* value ){
445                 KeyValues::iterator i = m_keyValues.find( key );
446                 if ( i != m_keyValues.end() ) {
447                         ( *i ).second->assign( value );
448                 }
449                 else
450                 {
451                         m_undo.save();
452                         insert( key, KeyValuePtr( new KeyValue( value, EntityClass_valueForKey( *m_eclass, key ) ) ) );
453                 }
454         }
455
456         void erase( KeyValues::iterator i ){
457                 if ( m_instanced ) {
458                         ( *i ).second->instanceDetach( m_undo.map() );
459                 }
460
461                 Key key( ( *i ).first );
462                 KeyValuePtr value( ( *i ).second );
463                 m_keyValues.erase( i );
464                 notifyErase( key.c_str(), *value );
465         }
466
467         void erase( const char* key ){
468                 KeyValues::iterator i = m_keyValues.find( key );
469                 if ( i != m_keyValues.end() ) {
470                         m_undo.save();
471                         erase( i );
472                 }
473         }
474
475 public:
476         bool m_isContainer;
477
478         EntityKeyValues( EntityClass* eclass ) :
479                 m_eclass( eclass ),
480                 m_undo( m_keyValues, UndoImportCaller( *this ) ),
481                 m_instanced( false ),
482                 m_observerMutex( false ),
483                 m_isContainer( !eclass->fixedsize ){
484         }
485         EntityKeyValues( const EntityKeyValues& other ) :
486                 Entity( other ),
487                 m_eclass( &other.getEntityClass() ),
488                 m_undo( m_keyValues, UndoImportCaller( *this ) ),
489                 m_instanced( false ),
490                 m_observerMutex( false ),
491                 m_isContainer( other.m_isContainer ){
492                 for ( KeyValues::const_iterator i = other.m_keyValues.begin(); i != other.m_keyValues.end(); ++i )
493                 {
494                         insert( ( *i ).first.c_str(), ( *i ).second->c_str() );
495                 }
496         }
497         ~EntityKeyValues(){
498                 for ( Observers::iterator i = m_observers.begin(); i != m_observers.end(); )
499                 {
500             // post-increment to allow current element to be removed safely
501                         ( *i++ )->clear();
502                 }
503                 ASSERT_MESSAGE( m_observers.empty(), "EntityKeyValues::~EntityKeyValues: observers still attached" );
504         }
505
506         static void setKeyValueChangedFunc( EntityCreator::KeyValueChangedFunc func ){
507                 m_entityKeyValueChanged = func;
508                 KeyValue::setKeyValueChangedFunc( func );
509         }
510         static void setCounter( Counter* counter ){
511                 m_counter = counter;
512         }
513
514         void importState( const KeyValues& keyValues ){
515                 for ( KeyValues::iterator i = m_keyValues.begin(); i != m_keyValues.end(); )
516                 {
517                         erase( i++ );
518                 }
519
520                 for ( KeyValues::const_iterator i = keyValues.begin(); i != keyValues.end(); ++i )
521                 {
522                         insert( ( *i ).first.c_str(), ( *i ).second );
523                 }
524
525                 m_entityKeyValueChanged();
526         }
527         typedef MemberCaller<EntityKeyValues, void(const KeyValues&), &EntityKeyValues::importState> UndoImportCaller;
528
529         void attach( Observer& observer ){
530                 ASSERT_MESSAGE( !m_observerMutex, "observer cannot be attached during iteration" );
531                 m_observers.insert( &observer );
532                 for ( KeyValues::const_iterator i = m_keyValues.begin(); i != m_keyValues.end(); ++i )
533                 {
534                         observer.insert( ( *i ).first.c_str(), *( *i ).second );
535                 }
536         }
537         void detach( Observer& observer ){
538                 ASSERT_MESSAGE( !m_observerMutex, "observer cannot be detached during iteration" );
539                 m_observers.erase( &observer );
540                 for ( KeyValues::const_iterator i = m_keyValues.begin(); i != m_keyValues.end(); ++i )
541                 {
542                         observer.erase( ( *i ).first.c_str(), *( *i ).second );
543                 }
544         }
545
546         void forEachKeyValue_instanceAttach( MapFile* map ){
547                 for ( KeyValues::const_iterator i = m_keyValues.begin(); i != m_keyValues.end(); ++i )
548                 {
549                         ( *i ).second->instanceAttach( map );
550                 }
551         }
552         void forEachKeyValue_instanceDetach( MapFile* map ){
553                 for ( KeyValues::const_iterator i = m_keyValues.begin(); i != m_keyValues.end(); ++i )
554                 {
555                         ( *i ).second->instanceDetach( map );
556                 }
557         }
558
559         void instanceAttach( MapFile* map ){
560                 if ( m_counter != 0 ) {
561                         m_counter->increment();
562                 }
563
564                 m_instanced = true;
565                 forEachKeyValue_instanceAttach( map );
566                 m_undo.instanceAttach( map );
567         }
568         void instanceDetach( MapFile* map ){
569                 if ( m_counter != 0 ) {
570                         m_counter->decrement();
571                 }
572
573                 m_undo.instanceDetach( map );
574                 forEachKeyValue_instanceDetach( map );
575                 m_instanced = false;
576         }
577
578     // entity
579         EntityClass& getEntityClass() const {
580                 return *m_eclass;
581         }
582         void forEachKeyValue( Visitor& visitor ) const {
583                 for ( KeyValues::const_iterator i = m_keyValues.begin(); i != m_keyValues.end(); ++i )
584                 {
585                         visitor.visit( ( *i ).first.c_str(), ( *i ).second->c_str() );
586                 }
587         }
588         void setKeyValue( const char* key, const char* value ){
589                 if ( value[0] == '\0'
590              /*|| string_equal(EntityClass_valueForKey(*m_eclass, key), value)*/ ) { // don't delete values equal to default
591                         erase( key );
592                 }
593                 else
594                 {
595                         insert( key, value );
596                 }
597                 m_entityKeyValueChanged();
598         }
599         const char* getKeyValue( const char* key ) const {
600                 KeyValues::const_iterator i = m_keyValues.find( key );
601                 if ( i != m_keyValues.end() ) {
602                         return ( *i ).second->c_str();
603                 }
604
605                 return EntityClass_valueForKey( *m_eclass, key );
606         }
607
608         bool isContainer() const {
609                 return m_isContainer;
610         }
611 };
612
613 /// \brief A Resource reference with a controlled lifetime.
614 /// \brief The resource is released when the ResourceReference is destroyed.
615 class ResourceReference
616 {
617         CopiedString m_name;
618         Resource* m_resource;
619 public:
620         ResourceReference( const char* name )
621                 : m_name( name ){
622                 capture();
623         }
624         ResourceReference( const ResourceReference& other )
625                 : m_name( other.m_name ){
626                 capture();
627         }
628         ResourceReference& operator=( const ResourceReference& other ){
629                 ResourceReference tmp( other );
630                 tmp.swap( *this );
631                 return *this;
632         }
633         ~ResourceReference(){
634                 release();
635         }
636
637         void capture(){
638                 m_resource = GlobalReferenceCache().capture( m_name.c_str() );
639         }
640         void release(){
641                 GlobalReferenceCache().release( m_name.c_str() );
642         }
643
644         const char* getName() const {
645                 return m_name.c_str();
646         }
647         void setName( const char* name ){
648                 ResourceReference tmp( name );
649                 tmp.swap( *this );
650         }
651
652         void swap( ResourceReference& other ){
653                 std::swap( m_resource, other.m_resource );
654                 std::swap( m_name, other.m_name );
655         }
656
657         void attach( ModuleObserver& observer ){
658                 m_resource->attach( observer );
659         }
660         void detach( ModuleObserver& observer ){
661                 m_resource->detach( observer );
662         }
663
664         Resource* get(){
665                 return m_resource;
666         }
667 };
668
669 namespace std
670 {
671     /// \brief Swaps the values of \p self and \p other.
672     /// Overloads std::swap.
673         inline void swap( ResourceReference& self, ResourceReference& other ){
674                 self.swap( other );
675         }
676 }
677
678 #endif