NOW I do it right: #woxblox#
[divverent/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 {
48         Vector3 endpoint(vector3_added(origin, vector3_scaled(direction_forward, 32.0)));
49
50   Vector3 tip1(vector3_added(vector3_added(endpoint, vector3_scaled(direction_forward, -8.0)), vector3_scaled(direction_up, -4.0)));
51         Vector3 tip2(vector3_added(tip1, vector3_scaled(direction_up, 8.0)));
52   Vector3 tip3(vector3_added(vector3_added(endpoint, vector3_scaled(direction_forward, -8.0)), vector3_scaled(direction_left, -4.0)));
53         Vector3 tip4(vector3_added(tip3, vector3_scaled(direction_left, 8.0)));
54
55   glBegin (GL_LINES);
56
57   glVertex3fv(vector3_to_array(origin));
58   glVertex3fv(vector3_to_array(endpoint));
59
60   glVertex3fv(vector3_to_array(endpoint));
61   glVertex3fv(vector3_to_array(tip1));
62
63   glVertex3fv(vector3_to_array(endpoint));
64   glVertex3fv(vector3_to_array(tip2));
65
66   glVertex3fv(vector3_to_array(endpoint));
67   glVertex3fv(vector3_to_array(tip3));
68
69   glVertex3fv(vector3_to_array(endpoint));
70   glVertex3fv(vector3_to_array(tip4));
71
72   glVertex3fv(vector3_to_array(tip1));
73   glVertex3fv(vector3_to_array(tip3));
74
75   glVertex3fv(vector3_to_array(tip3));
76   glVertex3fv(vector3_to_array(tip2));
77
78   glVertex3fv(vector3_to_array(tip2));
79   glVertex3fv(vector3_to_array(tip4));
80
81   glVertex3fv(vector3_to_array(tip4));
82   glVertex3fv(vector3_to_array(tip1));
83
84   glEnd();
85 }
86
87 class SelectionIntersection;
88
89 inline void aabb_testselect(const AABB& aabb, SelectionTest& test, SelectionIntersection& best)
90 {
91   const IndexPointer::index_type indices[24] = {
92     2, 1, 5, 6,
93     1, 0, 4, 5,
94     0, 1, 2, 3,
95     3, 7, 4, 0,
96     3, 2, 6, 7,
97     7, 6, 5, 4,
98   };
99
100   Vector3 points[8];
101   aabb_corners(aabb, points);
102   test.TestQuads(VertexPointer(reinterpret_cast<VertexPointer::pointer>(points), sizeof(Vector3)), IndexPointer(indices, 24), best);
103 }
104
105 inline void aabb_draw_wire(const Vector3 points[8])
106 {
107   unsigned int indices[26] = {
108     0, 1, 1, 2, 2, 3, 3, 0,
109     4, 5, 5, 6, 6, 7, 7, 4,
110     0, 4, 1, 5, 2, 6, 3, 7,
111     // 0, 6, 1, 7, 2, 4, 3, 5 // X cross
112     1, 7 // diagonal line (connect mins to maxs corner)
113   };
114 #if 1
115   glVertexPointer(3, GL_FLOAT, 0, points);
116   glDrawElements(GL_LINES, sizeof(indices)/sizeof(indices[0]), GL_UNSIGNED_INT, indices);
117 #else
118   glBegin(GL_LINES);
119   for(std::size_t i = 0; i < sizeof(indices)/sizeof(indices[0]); ++i)
120   {
121     glVertex3fv(points[indices[i]]);
122   }
123   glEnd();
124 #endif
125 }
126
127 inline void aabb_draw_flatshade(const Vector3 points[8])
128 {
129   glBegin(GL_QUADS);
130
131   glNormal3fv(vector3_to_array(aabb_normals[0]));
132   glVertex3fv(vector3_to_array(points[2]));
133   glVertex3fv(vector3_to_array(points[1]));
134   glVertex3fv(vector3_to_array(points[5]));
135   glVertex3fv(vector3_to_array(points[6]));
136
137   glNormal3fv(vector3_to_array(aabb_normals[1]));
138   glVertex3fv(vector3_to_array(points[1]));
139   glVertex3fv(vector3_to_array(points[0]));
140   glVertex3fv(vector3_to_array(points[4]));
141   glVertex3fv(vector3_to_array(points[5]));
142
143   glNormal3fv(vector3_to_array(aabb_normals[2]));
144   glVertex3fv(vector3_to_array(points[0]));
145   glVertex3fv(vector3_to_array(points[1]));
146   glVertex3fv(vector3_to_array(points[2]));
147   glVertex3fv(vector3_to_array(points[3]));
148
149   glNormal3fv(vector3_to_array(aabb_normals[3]));
150   glVertex3fv(vector3_to_array(points[0]));
151   glVertex3fv(vector3_to_array(points[3]));
152   glVertex3fv(vector3_to_array(points[7]));
153   glVertex3fv(vector3_to_array(points[4]));
154
155   glNormal3fv(vector3_to_array(aabb_normals[4]));
156   glVertex3fv(vector3_to_array(points[3]));
157   glVertex3fv(vector3_to_array(points[2]));
158   glVertex3fv(vector3_to_array(points[6]));
159   glVertex3fv(vector3_to_array(points[7]));
160
161   glNormal3fv(vector3_to_array(aabb_normals[5]));
162   glVertex3fv(vector3_to_array(points[7]));
163   glVertex3fv(vector3_to_array(points[6]));
164   glVertex3fv(vector3_to_array(points[5]));
165   glVertex3fv(vector3_to_array(points[4]));
166
167   glEnd();
168 }
169
170 inline void aabb_draw_wire(const AABB& aabb)
171 {
172   Vector3 points[8];
173         aabb_corners(aabb, points);
174   aabb_draw_wire(points);
175 }
176
177 inline void aabb_draw_flatshade(const AABB& aabb)
178 {
179   Vector3 points[8];
180         aabb_corners(aabb, points);
181   aabb_draw_flatshade(points);
182 }
183
184 inline void aabb_draw_textured(const AABB& aabb)
185 {
186   Vector3 points[8];
187         aabb_corners(aabb, points);
188
189   glBegin(GL_QUADS);
190
191   glNormal3fv(vector3_to_array(aabb_normals[0]));
192   glTexCoord2fv(aabb_texcoord_topleft);
193   glVertex3fv(vector3_to_array(points[2]));
194   glTexCoord2fv(aabb_texcoord_topright);
195   glVertex3fv(vector3_to_array(points[1]));
196   glTexCoord2fv(aabb_texcoord_botright);
197   glVertex3fv(vector3_to_array(points[5]));
198   glTexCoord2fv(aabb_texcoord_botleft);
199   glVertex3fv(vector3_to_array(points[6]));
200
201   glNormal3fv(vector3_to_array(aabb_normals[1]));
202   glTexCoord2fv(aabb_texcoord_topleft);
203   glVertex3fv(vector3_to_array(points[1]));
204   glTexCoord2fv(aabb_texcoord_topright);
205   glVertex3fv(vector3_to_array(points[0]));
206   glTexCoord2fv(aabb_texcoord_botright);
207   glVertex3fv(vector3_to_array(points[4]));
208   glTexCoord2fv(aabb_texcoord_botleft);
209   glVertex3fv(vector3_to_array(points[5]));
210
211   glNormal3fv(vector3_to_array(aabb_normals[2]));
212   glTexCoord2fv(aabb_texcoord_topleft);
213   glVertex3fv(vector3_to_array(points[0]));
214   glTexCoord2fv(aabb_texcoord_topright);
215   glVertex3fv(vector3_to_array(points[1]));
216   glTexCoord2fv(aabb_texcoord_botright);
217   glVertex3fv(vector3_to_array(points[2]));
218   glTexCoord2fv(aabb_texcoord_botleft);
219   glVertex3fv(vector3_to_array(points[3]));
220
221   glNormal3fv(vector3_to_array(aabb_normals[3]));
222   glTexCoord2fv(aabb_texcoord_topleft);
223   glVertex3fv(vector3_to_array(points[0]));
224   glTexCoord2fv(aabb_texcoord_topright);
225   glVertex3fv(vector3_to_array(points[3]));
226   glTexCoord2fv(aabb_texcoord_botright);
227   glVertex3fv(vector3_to_array(points[7]));
228   glTexCoord2fv(aabb_texcoord_botleft);
229   glVertex3fv(vector3_to_array(points[4]));
230
231   glNormal3fv(vector3_to_array(aabb_normals[4]));
232   glTexCoord2fv(aabb_texcoord_topleft);
233   glVertex3fv(vector3_to_array(points[3]));
234   glTexCoord2fv(aabb_texcoord_topright);
235   glVertex3fv(vector3_to_array(points[2]));
236   glTexCoord2fv(aabb_texcoord_botright);
237   glVertex3fv(vector3_to_array(points[6]));
238   glTexCoord2fv(aabb_texcoord_botleft);
239   glVertex3fv(vector3_to_array(points[7]));
240
241   glNormal3fv(vector3_to_array(aabb_normals[5]));
242   glTexCoord2fv(aabb_texcoord_topleft);
243   glVertex3fv(vector3_to_array(points[7]));
244   glTexCoord2fv(aabb_texcoord_topright);
245   glVertex3fv(vector3_to_array(points[6]));
246   glTexCoord2fv(aabb_texcoord_botright);
247   glVertex3fv(vector3_to_array(points[5]));
248   glTexCoord2fv(aabb_texcoord_botleft);
249   glVertex3fv(vector3_to_array(points[4]));
250
251   glEnd();
252 }
253
254 inline void aabb_draw_solid(const AABB& aabb, RenderStateFlags state)
255 {
256   if(state & RENDER_TEXTURE)
257   {
258     aabb_draw_textured(aabb);
259   }
260   else
261   {
262     aabb_draw_flatshade(aabb);
263   }
264 }
265
266 inline void aabb_draw(const AABB& aabb, RenderStateFlags state)
267 {
268   if(state & RENDER_FILL)
269   {
270     aabb_draw_solid(aabb, state);
271   }
272   else
273   {
274     aabb_draw_wire(aabb);
275   }
276 }
277
278 class RenderableSolidAABB : public OpenGLRenderable
279 {
280   const AABB& m_aabb;
281 public:
282   RenderableSolidAABB(const AABB& aabb) : m_aabb(aabb)
283   {
284   }
285   void render(RenderStateFlags state) const
286   {
287     aabb_draw_solid(m_aabb, state);
288   }
289 };
290
291 class RenderableWireframeAABB : public OpenGLRenderable
292 {
293   const AABB& m_aabb;
294 public:
295   RenderableWireframeAABB(const AABB& aabb) : m_aabb(aabb)
296   {
297   }
298   void render(RenderStateFlags state) const
299   {
300     aabb_draw_wire(m_aabb);
301   }
302 };
303
304
305 /// \brief A key/value pair of strings.
306 ///
307 /// - Notifies observers when value changes - value changes to "" on destruction.
308 /// - Provides undo support through the global undo system.
309 class KeyValue : public EntityKeyValue
310 {
311   typedef UnsortedSet<KeyObserver> KeyObservers;
312
313   std::size_t m_refcount;
314   KeyObservers m_observers;
315   CopiedString m_string;
316   const char* m_empty;
317   ObservedUndoableObject<CopiedString> m_undo;
318   static EntityCreator::KeyValueChangedFunc m_entityKeyValueChanged;
319 public:
320
321   KeyValue(const char* string, const char* empty)
322     : m_refcount(0), m_string(string), m_empty(empty), m_undo(m_string, UndoImportCaller(*this))
323   {
324     notify();
325   }
326   ~KeyValue()
327   {
328     ASSERT_MESSAGE(m_observers.empty(), "KeyValue::~KeyValue: observers still attached");
329   }
330
331   static void setKeyValueChangedFunc(EntityCreator::KeyValueChangedFunc func)
332   {
333     m_entityKeyValueChanged = func;
334   }
335
336   void IncRef()
337   {
338     ++m_refcount;
339   }
340   void DecRef()
341   {
342     if(--m_refcount == 0)
343     {
344       delete this;
345     }
346   }
347
348   void instanceAttach(MapFile* map)
349   {
350     m_undo.instanceAttach(map);
351   }
352   void instanceDetach(MapFile* map)
353   {
354     m_undo.instanceDetach(map);
355   }
356
357   void attach(const KeyObserver& observer)
358   {
359     (*m_observers.insert(observer))(c_str());
360   }
361   void detach(const KeyObserver& observer)
362   {
363     observer(m_empty);
364     m_observers.erase(observer);
365   }
366   const char* c_str() const
367   {
368     if(string_empty(m_string.c_str()))
369     {
370       return m_empty;
371     }
372     return m_string.c_str();
373   }
374   void assign(const char* other)
375   {
376     if(!string_equal(m_string.c_str(), other))
377     {
378       m_undo.save();
379       m_string = other;
380       notify();
381     }
382   }
383
384   void notify()
385   {
386     m_entityKeyValueChanged();
387     KeyObservers::reverse_iterator i = m_observers.rbegin();
388     while(i != m_observers.rend())
389     {
390       (*i++)(c_str());
391     }
392   }
393
394   void importState(const CopiedString& string)
395   {
396     m_string = string;
397
398     notify();
399   }
400   typedef MemberCaller1<KeyValue, const CopiedString&, &KeyValue::importState> UndoImportCaller;
401 };
402
403 /// \brief An unsorted list of key/value pairs.
404 ///
405 /// - Notifies observers when a pair is inserted or removed.
406 /// - Provides undo support through the global undo system.
407 /// - New keys are appended to the end of the list.
408 class EntityKeyValues : public Entity
409 {
410 public:
411   typedef KeyValue Value;
412
413   static StringPool& getPool()
414   {
415     return Static<StringPool, KeyContext>::instance();
416   }
417 private:
418   static EntityCreator::KeyValueChangedFunc m_entityKeyValueChanged;
419   static Counter* m_counter;
420
421   EntityClass* m_eclass;
422
423   class KeyContext{};
424   typedef Static<StringPool, KeyContext> KeyPool;
425   typedef PooledString<KeyPool> Key;
426   typedef SmartPointer<KeyValue> KeyValuePtr;
427   typedef UnsortedMap<Key, KeyValuePtr> KeyValues;
428   KeyValues m_keyValues;
429
430   typedef UnsortedSet<Observer*> Observers;
431   Observers m_observers;
432
433   ObservedUndoableObject<KeyValues> m_undo;
434   bool m_instanced;
435
436   bool m_observerMutex;
437
438   void notifyInsert(const char* key, Value& value)
439   {
440     m_observerMutex = true;
441     for(Observers::iterator i = m_observers.begin(); i != m_observers.end(); ++i)
442     {
443       (*i)->insert(key, value);
444     }
445     m_observerMutex = false;
446   }
447   void notifyErase(const char* key, Value& value)
448   {
449     m_observerMutex = true;
450     for(Observers::iterator i = m_observers.begin(); i != m_observers.end(); ++i)
451     {
452       (*i)->erase(key, value);
453     }
454     m_observerMutex = false;
455   }
456   void forEachKeyValue_notifyInsert()
457   {
458     for(KeyValues::const_iterator i = m_keyValues.begin(); i != m_keyValues.end(); ++i)
459     {
460       notifyInsert((*i).first.c_str(), *(*i).second);
461     }
462   }
463   void forEachKeyValue_notifyErase()
464   {
465     for(KeyValues::const_iterator i = m_keyValues.begin(); i != m_keyValues.end(); ++i)
466     {
467       notifyErase((*i).first.c_str(), *(*i).second);
468     }
469   }
470
471   void insert(const char* key, const KeyValuePtr& keyValue)
472   {
473     KeyValues::iterator i = m_keyValues.insert(KeyValues::value_type(key, keyValue));
474     notifyInsert(key, *(*i).second);
475
476     if(m_instanced)
477     {
478       (*i).second->instanceAttach(m_undo.map());
479     }
480   }
481
482   void insert(const char* key, const char* value)
483   {
484     KeyValues::iterator i = m_keyValues.find(key);
485     if(i != m_keyValues.end())
486     {
487       (*i).second->assign(value);
488     }
489     else
490     {
491       m_undo.save();
492       insert(key, KeyValuePtr(new KeyValue(value, EntityClass_valueForKey(*m_eclass, key))));
493     }
494   }
495
496   void erase(KeyValues::iterator i)
497   {
498     if(m_instanced)
499     {
500       (*i).second->instanceDetach(m_undo.map());
501     }
502
503     Key key((*i).first);
504     KeyValuePtr value((*i).second);
505     m_keyValues.erase(i);
506     notifyErase(key.c_str(), *value);
507   }
508
509   void erase(const char* key)
510   {
511     KeyValues::iterator i = m_keyValues.find(key);
512     if(i != m_keyValues.end())
513     {
514       m_undo.save();
515       erase(i);
516     }
517   }
518
519 public:
520   bool m_isContainer;
521
522   EntityKeyValues(EntityClass* eclass) :
523     m_eclass(eclass),
524     m_undo(m_keyValues, UndoImportCaller(*this)),
525     m_instanced(false),
526     m_observerMutex(false),
527     m_isContainer(!eclass->fixedsize)
528   {
529   }
530   EntityKeyValues(const EntityKeyValues& other) :
531     Entity(other),
532     m_eclass(&other.getEntityClass()),
533     m_undo(m_keyValues, UndoImportCaller(*this)),
534     m_instanced(false),
535     m_observerMutex(false),
536     m_isContainer(other.m_isContainer)
537   {
538     for(KeyValues::const_iterator i = other.m_keyValues.begin(); i != other.m_keyValues.end(); ++i)
539     {
540       insert((*i).first.c_str(), (*i).second->c_str());
541     }
542   }
543   ~EntityKeyValues()
544   {
545     for(Observers::iterator i = m_observers.begin(); i != m_observers.end();)
546     {
547       // post-increment to allow current element to be removed safely
548       (*i++)->clear();
549     }
550     ASSERT_MESSAGE(m_observers.empty(), "EntityKeyValues::~EntityKeyValues: observers still attached");
551   }
552
553   static void setKeyValueChangedFunc(EntityCreator::KeyValueChangedFunc func)
554   {
555     m_entityKeyValueChanged = func;
556     KeyValue::setKeyValueChangedFunc(func);
557   }
558   static void setCounter(Counter* counter)
559   {
560     m_counter = counter;
561   }
562
563   void importState(const KeyValues& keyValues)
564   {
565     for(KeyValues::iterator i = m_keyValues.begin(); i != m_keyValues.end();)
566     {
567       erase(i++);
568     }
569
570     for(KeyValues::const_iterator i = keyValues.begin(); i != keyValues.end(); ++i)
571     {
572       insert((*i).first.c_str(), (*i).second);
573     }
574
575     m_entityKeyValueChanged();
576   }
577   typedef MemberCaller1<EntityKeyValues, const KeyValues&, &EntityKeyValues::importState> UndoImportCaller;
578
579   void attach(Observer& observer)
580   {
581     ASSERT_MESSAGE(!m_observerMutex, "observer cannot be attached during iteration");
582     m_observers.insert(&observer);
583     for(KeyValues::const_iterator i = m_keyValues.begin(); i != m_keyValues.end(); ++i)
584     {
585       observer.insert((*i).first.c_str(), *(*i).second);
586     }
587   }
588   void detach(Observer& observer)
589   {
590     ASSERT_MESSAGE(!m_observerMutex, "observer cannot be detached during iteration");
591     m_observers.erase(&observer);
592     for(KeyValues::const_iterator i = m_keyValues.begin(); i != m_keyValues.end(); ++i)
593     {
594       observer.erase((*i).first.c_str(), *(*i).second);
595     }
596   }
597
598   void forEachKeyValue_instanceAttach(MapFile* map)
599   {
600     for(KeyValues::const_iterator i = m_keyValues.begin(); i != m_keyValues.end(); ++i)
601     {
602       (*i).second->instanceAttach(map);
603     }
604   }
605   void forEachKeyValue_instanceDetach(MapFile* map)
606   {
607     for(KeyValues::const_iterator i = m_keyValues.begin(); i != m_keyValues.end(); ++i)
608     {
609       (*i).second->instanceDetach(map);
610     }
611   }
612
613   void instanceAttach(MapFile* map)
614   {
615     if(m_counter != 0)
616     {
617       m_counter->increment();
618     }
619
620     m_instanced = true;
621     forEachKeyValue_instanceAttach(map);
622     m_undo.instanceAttach(map);
623   }
624   void instanceDetach(MapFile* map)
625   {
626     if(m_counter != 0)
627     {
628       m_counter->decrement();
629     }
630
631     m_undo.instanceDetach(map);
632     forEachKeyValue_instanceDetach(map);
633     m_instanced = false;
634   }
635
636   // entity
637   EntityClass& getEntityClass() const
638   {
639     return *m_eclass;
640   }
641   void forEachKeyValue(Visitor& visitor) const
642   {
643     for(KeyValues::const_iterator i = m_keyValues.begin(); i != m_keyValues.end(); ++i)
644     {
645       visitor.visit((*i).first.c_str(), (*i).second->c_str());
646     }
647   }
648   void setKeyValue(const char* key, const char* value)
649   {
650     if(value[0] == '\0'
651       /*|| string_equal(EntityClass_valueForKey(*m_eclass, key), value)*/) // don't delete values equal to default
652     {
653       erase(key);
654     }
655     else
656     {
657       insert(key, value);
658     }
659     m_entityKeyValueChanged();
660   }
661   const char* getKeyValue(const char* key) const
662   {
663     KeyValues::const_iterator i = m_keyValues.find(key);
664     if(i != m_keyValues.end())
665     {
666       return (*i).second->c_str();
667     }
668
669     return EntityClass_valueForKey(*m_eclass, key);
670   }
671
672   bool isContainer() const
673   {
674     return m_isContainer;
675   }
676 };
677
678 /// \brief A Resource reference with a controlled lifetime.
679 /// \brief The resource is released when the ResourceReference is destroyed.
680 class ResourceReference
681 {
682   CopiedString m_name;
683   Resource* m_resource;
684 public:
685   ResourceReference(const char* name)
686     : m_name(name)
687   {
688     capture();
689   }
690   ResourceReference(const ResourceReference& other)
691     : m_name(other.m_name)
692   {
693     capture();
694   }
695   ResourceReference& operator=(const ResourceReference& other)
696   {
697     ResourceReference tmp(other);
698     tmp.swap(*this);
699     return *this;
700   }
701   ~ResourceReference()
702   {
703     release();
704   }
705
706   void capture()
707   {
708     m_resource = GlobalReferenceCache().capture(m_name.c_str());
709   }
710   void release()
711   {
712     GlobalReferenceCache().release(m_name.c_str());
713   }
714
715   const char* getName() const
716   {
717     return m_name.c_str();
718   }
719   void setName(const char* name)
720   {
721     ResourceReference tmp(name);
722     tmp.swap(*this);
723   }
724
725   void swap(ResourceReference& other)
726   {
727     std::swap(m_resource, other.m_resource);
728     std::swap(m_name, other.m_name);
729   }
730
731   void attach(ModuleObserver& observer)
732   {
733     m_resource->attach(observer);
734   }
735   void detach(ModuleObserver& observer)
736   {
737     m_resource->detach(observer);
738   }
739
740   Resource* get()
741   {
742     return m_resource;
743   }
744 };
745
746 namespace std
747 {
748   /// \brief Swaps the values of \p self and \p other.
749   /// Overloads std::swap.
750   inline void swap(ResourceReference& self, ResourceReference& other)
751   {
752     self.swap(other);
753   }
754 }
755
756 #endif