/
ientity.h
527 lines (448 loc) · 17.1 KB
/
ientity.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
#pragma once
#include "inode.h"
#include "ipath.h"
#include "imodule.h"
#include "irender.h"
#include "inameobserver.h"
#include "iscenegraph.h"
#include "itransformnode.h"
#include <functional>
#include "string/predicate.h"
class IEntityClass;
typedef std::shared_ptr<IEntityClass> IEntityClassPtr;
typedef std::shared_ptr<const IEntityClass> IEntityClassConstPtr;
// Observes a single entity key value and gets notified on change
class KeyObserver: public sigc::trackable
{
public:
using Ptr = std::shared_ptr<KeyObserver>;
virtual ~KeyObserver() {}
/**
* This event gets called when the observed keyvalue changes.
* The new value is passed as argument, which can be an empty string.
*/
virtual void onKeyValueChanged(const std::string& newValue) = 0;
};
/**
* @brief Object representing a single keyvalue (spawnarg) on an entity.
*
* This class exists so that each spawnarg can have its own independent set of
* KeyObservers responding to changes in its value. For most purposes it is
* simpler to use Entity::Observer::onKeyChange, Entity::setKeyValue and
* Entity::getKeyValue to interact with key values.
*/
class EntityKeyValue: public NameObserver
{
public:
virtual ~EntityKeyValue() {}
/// Retrieves the actual value of this key
virtual const std::string& get() const = 0;
/// Sets the value of this key
virtual void assign(const std::string& other) = 0;
/// Attaches a callback to get notified about the key change.
virtual void attach(KeyObserver& observer) = 0;
/**
* @brief Detach the given observer from this key value.
*
* @param observer
* Observer to detach. No action will be taken if this observer is not
* already attached.
*
* @param sendEmptyValue
* If true (the default), the observer will be invoked with an empty value
* before being detached. If false, no final value will be sent.
*/
virtual void detach(KeyObserver& observer, bool sendEmptyValue = true) = 0;
};
typedef std::shared_ptr<EntityKeyValue> EntityKeyValuePtr;
/**
* Interface for a map entity. The Entity is the main building block of a
* map, and the uppermost layer in the scenegraph under the root node. Each
* entity contains a arbitrary dictionary of strings ("properties" or
* "spawnargs") containing information about this entity which is used by the
* game engine to modify its behaviour, and may additionally contain child
* primitives (brushes and patches) depending on its type.
*
* At the minimum, each Entity must contain three properties: "name" which
* contains a map-unique string identifier, "classname" which identifies the
* entity class to the game, and "origin" which stores the location of the
* entity in 3-dimensional world space.
*
* A valid <b>Id Tech 4</b> map must contain at least one entity: the
* "worldspawn" which is the parent of all map geometry primitives.
*
* greebo: Note that keys are treated case-insensitively in Doom 3, so
* the Entity class will return the same result for "MYKeY" as for "mykey".
*/
class Entity
{
public:
// A container with key => value pairs
typedef std::vector< std::pair<std::string, std::string> > KeyValuePairs;
/**
* \brief
* Abstract base class for entity observers.
*
* An entity observer receives notifications when keyvalues are inserted or
* deleted on the entity it is observing.
*/
class Observer
{
public:
virtual ~Observer() {}
/**
* \brief
* Notification that a new key value has been inserted on the entity.
*/
virtual void onKeyInsert(const std::string& key, EntityKeyValue& value)
{ }
/**
* \brief
* Notification that a key value has changed on the entity.
*/
virtual void onKeyChange(const std::string& key, const std::string& val)
{ }
/**
* \brief
* Notification that a key value has been removed from the entity.
*/
virtual void onKeyErase(const std::string& key, EntityKeyValue& value)
{ }
};
// Function typedef to visit actual EntityKeyValue objects, not just the string values
typedef std::function<void(const std::string& key, EntityKeyValue& value)> EntityKeyValueVisitFunctor;
virtual ~Entity() {}
/**
* Return the entity class object for this entity.
*/
virtual IEntityClassPtr getEntityClass() const = 0;
/// Functor to receive keys and values as strings
using KeyValueVisitFunc = std::function<
void(const std::string&, const std::string&)
>;
/**
* \brief Enumerate all keys and values on this entity, optionally including
* inherited spawnargs.
*
* \param func
* Functor to receive each key and its associated value.
*
* \param includeInherited
* true if the functor should be invoked for each inherited spawnarg (from
* the entity class), false if only explicit spawnargs on this particular
* entity should be visited.
*/
virtual void forEachKeyValue(KeyValueVisitFunc func,
bool includeInherited = false) const = 0;
// Similar to above, visiting the EntityKeyValue objects itself, not just the string value.
virtual void forEachEntityKeyValue(const EntityKeyValueVisitFunctor& visitor) = 0;
/** Set a key value on this entity. Setting the value to "" will
* remove the key.
*
* @param key
* The key to set.
*
* @param value
* Value to give the key, or the empty string to remove the key.
*/
virtual void setKeyValue(const std::string& key,
const std::string& value) = 0;
/* Retrieve a key value from the entity.
*
* @param key
* The key to retrieve.
*
* @returns
* The current value for this key, or the empty string if it does not
* exist.
*/
virtual std::string getKeyValue(const std::string& key) const = 0;
/**
* greebo: Checks whether the given key is inherited or not.
*
* @returns: TRUE if the value is inherited,
* FALSE when it is not or when the key doesn't exist at all.
*/
virtual bool isInherited(const std::string& key) const = 0;
/**
* \brief Return the list of keyvalues matching the given prefix.
*
* This method performs a search for all spawnargs whose key matches the
* given prefix, with a suffix consisting of zero or more arbitrary
* characters. For example, if "target" were specified as the prefix, the
* list would include "target", "target0", "target127" etc.
*
* This operation may not have high performance, due to the need to scan
* for matching names, therefore should not be used in performance-critical
* code.
*
* @param prefix
* The prefix to search for, interpreted case-insensitively.
*
* @return
* A list of KeyValue pairs matching the provided prefix. This list will be
* empty if there were no matches.
*/
KeyValuePairs getKeyValuePairs(const std::string& prefix) const
{
KeyValuePairs list;
forEachKeyValue([&](const std::string& k, const std::string& v) {
if (string::istarts_with(k, prefix))
list.push_back(std::make_pair(k, v));
});
return list;
}
/** greebo: Returns true if the entity is a model. For Doom3, this is
* usually true when the classname == "func_static" and
* the non-empty spawnarg "model" != "name".
*/
virtual bool isModel() const = 0;
/**
* Returns true if this entity is the worldspawn, which can be game-specific,
* but is usually true if this entity's classname equals "worldspawn"
*/
virtual bool isWorldspawn() const = 0;
virtual bool isContainer() const = 0;
/**
* \brief
* Attach an Entity::Observer to this Entity.
*/
virtual void attachObserver(Observer* observer) = 0;
/**
* \brief
* Detach an Entity::Observer from this Entity.
*/
virtual void detachObserver(Observer* observer) = 0;
/**
* Returns true if this entity is of type or inherits from the
* given entity class name. className is treated case-sensitively.
*/
virtual bool isOfType(const std::string& className) = 0;
/* ENTITY ATTACHMENTS */
/// Details of an attached entity
struct Attachment
{
/// Entity class of the attached entity
std::string eclass;
/// Vector offset where the attached entity should appear
Vector3 offset;
/// Optional model joint to use as origin
std::string joint;
};
/// A functor which can receive Attachment objects
using AttachmentFunc = std::function<void(const Attachment&)>;
/**
* \brief Iterate over attached entities, if any.
*
* Each entity can define one or more attached entities, which should
* appear at specific offsets relative to the parent entity. Such attached
* entities are for visualisation only, and should not be saved into the
* map as genuine map entities.
*
* \param func
* Functor to receive attachment information.
*/
virtual void forEachAttachment(AttachmentFunc func) const = 0;
};
/// Callback for an entity key value change
using KeyObserverFunc = sigc::slot<void(const std::string&)>;
/**
* \brief Interface for a node which represents an entity.
*
* As well as providing access to the entity data with getEntity(), every
* IEntityNode can clone itself and apply a transformation matrix to its
* children (which might be brushes, patches or other entities).
*/
class IEntityNode : public IRenderEntity,
public virtual scene::INode,
public scene::Cloneable,
public IMatrixTransform
{
public:
virtual ~IEntityNode() {}
/// Get a modifiable reference to the contained Entity
virtual Entity& getEntity() = 0;
/**
* @brief Observe key value changes using a callback function.
*
* This method provides a simpler interface for observing key value changes
* via the use of a callback function, rather than requiring a full
* KeyObserver object to be constructed and maintained by the calling code.
*
* @param key
* The key to observe.
*
* @param func
* Function to call when the key value changes.
*/
virtual void observeKey(const std::string& key, KeyObserverFunc func) = 0;
/**
* greebo: Tells the entity to reload the child model. This usually
* includes removal of the child model node and triggering
* a "skin changed" event.
*/
virtual void refreshModel() = 0;
};
typedef std::shared_ptr<IEntityNode> IEntityNodePtr;
inline Entity* Node_getEntity(const scene::INodePtr& node)
{
IEntityNodePtr entityNode = std::dynamic_pointer_cast<IEntityNode>(node);
if (entityNode != NULL) {
return &(entityNode->getEntity());
}
return NULL;
}
inline bool Node_isEntity(const scene::INodePtr& node)
{
//assert(!((std::dynamic_pointer_cast<IEntityNode>(node) != nullptr) ^ (node->getNodeType() == scene::INode::Type::Entity)));
return node->getNodeType() == scene::INode::Type::Entity;
}
// Represents a set of selected entities
class IEntitySelection
{
public:
virtual ~IEntitySelection() {}
// True if there's no selected entity available
virtual bool empty() const = 0;
// Returns the number of selected entities
virtual std::size_t size() const = 0;
// Iterates over each selected entity, invoking the given functor
virtual void foreachEntity(const std::function<void(Entity*)>& functor) = 0;
// Returns the key value shared by all entities in this set, or an empty string
// if there is no such value.
virtual std::string getSharedKeyValue(const std::string& key, bool includeInherited) = 0;
};
/**
* greebo: This is an abstract representation of a target.
* In Doom3 maps, a Target can be any entity node, that's
* why this object encapsulates a reference to an actual
* scene::INode.
*
* Note: Such a Target object can be empty. That's the case for
* entities referring to non-existing entities in their
* "target" spawnarg.
*
* All ITargetableObjects are owned by the TargetManager class.
*/
class ITargetableObject
{
public:
virtual ~ITargetableObject() {}
// Returns the scene node behind this target. If the named target
// cannot be resolved in the current scene, an empty pointer is returned.
virtual const scene::INode* getNode() const = 0;
// Use this method to check whether the node can be resolved
virtual bool isEmpty() const = 0;
};
typedef std::shared_ptr<ITargetableObject> ITargetableObjectPtr;
/**
* greebo: The TargetManager keeps track of all ITargetableObjects
* in the current scene/map. A TargetManager instance is owned
* by the RootNode. TargetManager instances can be acquired through
* the EntityCreator interface.
*
* Clients acquire a named ITargetableObjectPtr by calling getTarget(). This
* always succeeds - if the named ITargetableObject is not found,
* a new, empty one is created.
*
* ITargetableObject object (can be empty)
* ________
* / \
* Entity | |
* TargetKey ----->>| -------->> holds scene::INodePtr (==NULL, if empty)
* | |
* \________/
*/
class ITargetManager
{
public:
/**
* Returns the Target with the given name.
* This never returns NULL, an ITargetableObject is created if it doesn't exist yet.
*/
virtual ITargetableObjectPtr getTarget(const std::string name) = 0;
/**
* greebo: Associates the named Target with the given scene::INode.
* The Target will be created if it doesn't exist yet.
*/
virtual void associateTarget(const std::string& name, const scene::INode& node) = 0;
/**
* greebo: Disassociates the Target from the given name. The node
* must also be passed to allow the manager to check the request.
* Otherwise it would be possible for cloned nodes to dissociate
* the target from their source node.
*/
virtual void clearTarget(const std::string& name, const scene::INode& node) = 0;
};
typedef std::shared_ptr<ITargetManager> ITargetManagerPtr;
enum class LightEditVertexType : std::size_t
{
StartEndDeselected,
StartEndSelected,
Inactive,
Deselected,
Selected,
NumberOfVertexTypes,
};
const char* const RKEY_SHOW_ENTITY_NAMES("user/ui/xyview/showEntityNames");
const char* const RKEY_SHOW_ALL_SPEAKER_RADII = "user/ui/showAllSpeakerRadii";
const char* const RKEY_SHOW_ALL_LIGHT_RADII = "user/ui/showAllLightRadii";
const char* const RKEY_DRAG_RESIZE_SYMMETRICALLY = "user/ui/dragResizeEntitiesSymmetrically";
const char* const RKEY_ALWAYS_SHOW_LIGHT_VERTICES = "user/ui/alwaysShowLightVertices";
const char* const RKEY_FREE_OBJECT_ROTATION = "user/ui/rotateObjectsIndependently";
const char* const RKEY_SHOW_ENTITY_ANGLES = "user/ui/xyview/showEntityAngles";
/**
* Global entity settings affecting appearance, render options, etc.
*/
class IEntitySettings
{
public:
virtual ~IEntitySettings() {}
virtual const Vector3& getLightVertexColour(LightEditVertexType type) const = 0;
virtual void setLightVertexColour(LightEditVertexType type, const Vector3& value) = 0;
virtual bool getRenderEntityNames() const = 0;
virtual void setRenderEntityNames(bool value) = 0;
virtual bool getShowAllSpeakerRadii() const = 0;
virtual void setShowAllSpeakerRadii(bool value) = 0;
virtual bool getShowAllLightRadii() const = 0;
virtual void setShowAllLightRadii(bool value) = 0;
virtual bool getDragResizeEntitiesSymmetrically() const = 0;
virtual void setDragResizeEntitiesSymmetrically(bool value) = 0;
virtual bool getAlwaysShowLightVertices() const = 0;
virtual void setAlwaysShowLightVertices(bool value) = 0;
virtual bool getFreeObjectRotation() const = 0;
virtual void setFreeObjectRotation(bool value) = 0;
virtual bool getShowEntityAngles() const = 0;
virtual void setShowEntityAngles(bool value) = 0;
virtual sigc::signal<void>& signal_settingsChanged() = 0;
};
const char* const MODULE_ENTITY("EntityModule");
/**
* \brief
* Interface for the entity module.
*/
class IEntityModule :
public RegisterableModule
{
public:
virtual ~IEntityModule() {}
/// Create an entity node with the given entity class.
virtual IEntityNodePtr createEntity(const IEntityClassPtr& eclass) = 0;
// Constructs a new targetmanager instance (used by root nodes)
virtual ITargetManagerPtr createTargetManager() = 0;
// Access to the settings manager
virtual IEntitySettings& getSettings() = 0;
/**
* Create an instance of the given entity at the given position, and return
* the Node containing the new entity.
*
* @returns: the scene::IEntityNodePtr referring to the new entity.
* @throws: cmd::ExecutionFailure if anything goes wrong or the selection is not suitable.
*/
virtual IEntityNodePtr createEntityFromSelection(const std::string& name, const Vector3& origin) = 0;
};
inline IEntityModule& GlobalEntityModule()
{
static module::InstanceReference<IEntityModule> _reference(MODULE_ENTITY);
return _reference;
}