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