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 
arrow_draw(const Vector3 & origin,const Vector3 & direction_forward,const Vector3 & direction_left,const Vector3 & direction_up)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 
aabb_testselect(const AABB & aabb,SelectionTest & test,SelectionIntersection & best)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 
aabb_draw_wire(const Vector3 points[8])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 
aabb_draw_flatshade(const Vector3 points[8])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 
aabb_draw_wire(const AABB & aabb)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 
aabb_draw_flatshade(const AABB & aabb)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 
aabb_draw_textured(const AABB & aabb)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 
aabb_draw_solid(const AABB & aabb,RenderStateFlags state)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 
aabb_draw(const AABB & aabb,RenderStateFlags state)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:
RenderableSolidAABB(const AABB & aabb)271 RenderableSolidAABB( const AABB& aabb ) : m_aabb( aabb ){
272 }
render(RenderStateFlags state)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:
RenderableWireframeAABB(const AABB & aabb)282 RenderableWireframeAABB( const AABB& aabb ) : m_aabb( aabb ){
283 }
render(RenderStateFlags state)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 
KeyValue(const char * string,const char * empty)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 }
~KeyValue()310 ~KeyValue(){
311 	ASSERT_MESSAGE( m_observers.empty(), "KeyValue::~KeyValue: observers still attached" );
312 }
313 
setKeyValueChangedFunc(EntityCreator::KeyValueChangedFunc func)314 static void setKeyValueChangedFunc( EntityCreator::KeyValueChangedFunc func ){
315 	m_entityKeyValueChanged = func;
316 }
317 
IncRef()318 void IncRef(){
319 	++m_refcount;
320 }
DecRef()321 void DecRef(){
322 	if ( --m_refcount == 0 ) {
323 		delete this;
324 	}
325 }
326 
instanceAttach(MapFile * map)327 void instanceAttach( MapFile* map ){
328 	m_undo.instanceAttach( map );
329 }
instanceDetach(MapFile * map)330 void instanceDetach( MapFile* map ){
331 	m_undo.instanceDetach( map );
332 }
333 
attach(const KeyObserver & observer)334 void attach( const KeyObserver& observer ){
335 	( *m_observers.insert ( observer ) )( c_str() );
336 }
detach(const KeyObserver & observer)337 void detach( const KeyObserver& observer ){
338 	observer( m_empty );
339 	m_observers.erase( observer );
340 }
c_str()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 }
assign(const char * other)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 
notify()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 
importState(const CopiedString & string)364 void importState( const CopiedString& string ){
365 	m_string = string;
366 
367 	notify();
368 }
369 typedef MemberCaller1<KeyValue, 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 
getPool()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 
notifyInsert(const char * key,Value & value)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 	}
notifyErase(const char * key,Value & value)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 	}
forEachKeyValue_notifyInsert()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 	}
forEachKeyValue_notifyErase()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 
insert(const char * key,const KeyValuePtr & keyValue)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 
insert(const char * key,const char * value)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 
erase(KeyValues::iterator i)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 
erase(const char * key)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 
EntityKeyValues(EntityClass * eclass)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 	}
EntityKeyValues(const EntityKeyValues & other)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 	}
~EntityKeyValues()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 
setKeyValueChangedFunc(EntityCreator::KeyValueChangedFunc func)506 	static void setKeyValueChangedFunc( EntityCreator::KeyValueChangedFunc func ){
507 		m_entityKeyValueChanged = func;
508 		KeyValue::setKeyValueChangedFunc( func );
509 	}
setCounter(Counter * counter)510 	static void setCounter( Counter* counter ){
511 		m_counter = counter;
512 	}
513 
importState(const KeyValues & keyValues)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 MemberCaller1<EntityKeyValues, const KeyValues&, &EntityKeyValues::importState> UndoImportCaller;
528 
attach(Observer & observer)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 	}
detach(Observer & observer)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 
forEachKeyValue_instanceAttach(MapFile * map)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 	}
forEachKeyValue_instanceDetach(MapFile * map)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 
instanceAttach(MapFile * map)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 	}
instanceDetach(MapFile * map)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
getEntityClass()579 	EntityClass& getEntityClass() const {
580 		return *m_eclass;
581 	}
forEachKeyValue(Visitor & visitor)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 	}
setKeyValue(const char * key,const char * value)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 	}
getKeyValue(const char * key)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 
isContainer()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:
ResourceReference(const char * name)620 	ResourceReference( const char* name )
621 		: m_name( name ){
622 		capture();
623 	}
ResourceReference(const ResourceReference & other)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 	}
~ResourceReference()633 	~ResourceReference(){
634 		release();
635 	}
636 
capture()637 	void capture(){
638 		m_resource = GlobalReferenceCache().capture( m_name.c_str() );
639 	}
release()640 	void release(){
641 		GlobalReferenceCache().release( m_name.c_str() );
642 	}
643 
getName()644 	const char* getName() const {
645 		return m_name.c_str();
646 	}
setName(const char * name)647 	void setName( const char* name ){
648 		ResourceReference tmp( name );
649 		tmp.swap( *this );
650 	}
651 
swap(ResourceReference & other)652 	void swap( ResourceReference& other ){
653 		std::swap( m_resource, other.m_resource );
654 		std::swap( m_name, other.m_name );
655 	}
656 
attach(ModuleObserver & observer)657 	void attach( ModuleObserver& observer ){
658 		m_resource->attach( observer );
659 	}
detach(ModuleObserver & observer)660 	void detach( ModuleObserver& observer ){
661 		m_resource->detach( observer );
662 	}
663 
get()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.
swap(ResourceReference & self,ResourceReference & other)673 	inline void swap( ResourceReference& self, ResourceReference& other ){
674 		self.swap( other );
675 	}
676 }
677 
678 #endif
679