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