SLProject  4.2.000
A platform independent 3D computer graphics framework for desktop OS, Android, iOS and online in web browsers
SLEntities.cpp
Go to the documentation of this file.
1 /**
2  * \file SLEntities.cpp
3  * \date June 2022
4  * \authors Marcus Hudritsch
5  * \copyright http://opensource.org/licenses/GPL-3.0
6  * \remarks Please use clangformat to format the code. See more code style on
7  * https://github.com/cpvrlab/SLProject4/wiki/SLProject-Coding-Style
8 */
9 
10 #include <SLEntities.h>
11 #include <SLNode.h>
12 
13 //-----------------------------------------------------------------------------
14 /*!
15  * addChild adds a child node by inserting an SLEntities into a vector in
16  * Depth First Search order. The root node gets the parent ID -1.
17  * The child is inserted right after the parent node.
18  * \param myParentID Index of the parent node
19  * \param entity The entity to add as child of the parent
20  */
22  SLEntity entity)
23 {
24  if (myParentID > (int)_graph.size() || myParentID < -1)
25  SL_EXIT_MSG("Invalid parent ID");
26 
27  SLint entityID; // ID and insert position of new entity
28 
29 #ifdef SL_USE_ENTITIES_DEBUG
30  this->dump(true);
31 #endif
32 
33  if (_graph.empty())
34  {
35  // Root node and ignore myParentID
36  entityID = 0;
37  _graph.push_back(entity);
38  _graph[0].parentID = -1;
39  _graph[0].childCount = 0;
40  _graph[0].om = _graph[0].node->om();
41  _graph[0].node->entityID(0);
42  if (_graph[0].node->parent() != nullptr)
43  SL_EXIT_MSG("Root node parent pointer must be null");
44  }
45  else
46  {
47  entity.parentID = myParentID;
48  entity.childCount = 0;
49  entity.om = entity.node->om();
50 
51  // Loop forward to the insert position
52  SLint insertPos = myParentID + 1;
53  while (insertPos < _graph.size() && _graph[insertPos].parentID >= myParentID)
54  insertPos++;
55 
56  entityID = insertPos;
57  if (entityID == _graph.size())
58  _graph.push_back(entity); // faster than insert
59  else
60  _graph.insert(_graph.begin() + entityID, entity);
61 
62  _graph[myParentID].childCount++;
63 
64  // Increase parentIDs of following subtrees that are greater
65  for (SLuint i = entityID + 1; i < _graph.size(); i++)
66  if (_graph[i].parentID > myParentID)
67  _graph[i].parentID++;
68 
69  // Correct all node->entityIDs
70  for (SLint i = 0; i < _graph.size(); ++i)
71  _graph[i].node->entityID(i);
72  }
73 
74  // Recursively add children of the entity
75  if (_graph[entityID].node->children().size())
76  {
77  for (SLint i = 0; i < _graph[entityID].node->children().size(); ++i)
78  {
79  SLNode* childNode = _graph[entityID].node->children()[i];
80  this->addChildEntity(entityID, SLEntity(childNode));
81  }
82  }
83 }
84 //-----------------------------------------------------------------------------
85 /*! Returns the pointer to the node at id
86  @param id The index of the node to return as a pointer
87  @return The pointer of the node at id
88  */
90 {
91  if (id >= 0 && id < _graph.size())
92  return &_graph[id];
93  else
94  return nullptr;
95 }
96 //-----------------------------------------------------------------------------
97 /*! Returns the ID for the passed SLNode if found else INT32_MIN
98  */
100 {
101  for (SLint i = 0; i < _graph.size(); ++i)
102  if (_graph[i].node == node)
103  return i;
104  return INT32_MIN;
105 }
106 //-----------------------------------------------------------------------------
107 /*! Returns the pointer to the parent of the node at id
108  @param id The index of the node in the scenegraph vector
109  @return The pointer of the parent of the node at id
110  */
112 {
113  if (id >= 1 && id < _graph.size())
114  return &_graph[_graph[id].parentID];
115  else
116  return nullptr;
117 }
118 //-----------------------------------------------------------------------------
119 /*! Returns the parentID for the passed SLNode if found else INT32_MIN
120  */
122 {
123  for (SLEntity& entity : _graph)
124  if (entity.node == node)
125  return entity.parentID;
126  return INT32_MIN;
127 }
128 //-----------------------------------------------------------------------------
129 /*! Updates the world matrix recursively
130  * \param id Index of the current node to update
131  * \param parentWM World transform matrix of the parent
132  * \return The no. of nodes updated
133  */
135 {
136  SLEntity* entity = getEntity(id);
137 
138 #ifdef SL_USE_ENTITIES_DEBUG
139  SLMat4f nodeOM = entity->node->om();
140  if (!entity->om.isEqual(nodeOM))
141  {
142  string nodeName = "nodeOM: " + entity->node->name();
143  entity->om.print("entityOM:");
144  entity->node->om().print(nodeName.c_str());
145  entity->om = entity->node->om();
146  }
147 #endif
148 
149  entity->wm.setMatrix(parentWM * entity->om);
150  entity->wmI.setMatrix(entity->wm.inverted());
151 
152 #ifdef SL_USE_ENTITIES_DEBUG
153  SLMat4f nodeWM = entity->node->updateAndGetWM();
154  if (!entity->wm.isEqual(nodeWM))
155  {
156  string nodeName = "nodeWM: " + entity->node->name();
157  entity->wm.print("entityWM:");
158  nodeWM.print(nodeName.c_str());
159  }
160 #endif
161 
162  SLuint handledChildren = 0;
163  while (handledChildren < entity->childCount)
164  {
165  SLuint childID = id + handledChildren + 1;
166  handledChildren += this->updateWMRec(childID, entity->wm);
167  }
168 
169  return handledChildren + 1;
170 }
171 //-----------------------------------------------------------------------------
172 /*! Prints the scenegraph vector flat or as hierarchical tree as follows:
173  @param doTreeDump Flag if dump as a tree or flat
174 
175 Pattern: ID.Parent.childCount
176 Example from SLEntities::addChild:
177 00.-1.04
178 +--01.00.01
179 | +--02.01.00
180 +--03.00.00
181 +--04.00.02
182 | +--05.04.00
183 | +--06.04.01
184 | | +--07.06.01
185 | | | +--08.07.00
186 +--09.00.00
187 */
188 void SLEntities::dump(SLbool doTreeDump)
189 {
190  if (doTreeDump)
191  {
192  for (SLuint i = 0; i < _graph.size(); ++i)
193  {
194  // Calculate depth
195  SLuint depth = 0;
196  SLint myParentID = _graph[i].parentID;
197  while (myParentID != -1)
198  {
199  depth++;
200  myParentID = _graph[myParentID].parentID;
201  }
202 
203  string tabs;
204  for (int d = 1; d < (int)depth; ++d)
205  tabs += "| ";
206  if (depth > 0)
207  tabs += "+--";
208  cout << tabs;
209 
210  SLstring nodeStr = _graph[i].node ? _graph[i].node->name() : "";
211  printf("%02u(%02d).%02d.%02u-%s\n",
212  i,
213  _graph[i].node->entityID(),
214  _graph[i].parentID,
215  _graph[i].childCount,
216  nodeStr.c_str());
217  }
218  cout << endl;
219  }
220  else
221  {
222  for (SLuint i = 0; i < _graph.size(); ++i)
223  printf("| %02u ", i);
224  cout << "|" << endl;
225 
226  for (SLuint i = 0; i < _graph.size(); ++i)
227  cout << "-------";
228  cout << "-" << endl;
229 
230  for (SLuint i = 0; i < _graph.size(); ++i)
231  if (_graph[i].parentID == -1)
232  printf("|-1 %02u", _graph[i].childCount);
233  else
234  printf("|%02u %02u", _graph[i].parentID, _graph[i].childCount);
235  cout << "|" << endl;
236  }
237  cout << "----------------------------------------------------------" << endl;
238 }
239 //-----------------------------------------------------------------------------
240 /*!
241  * Deletes a node at index id with all with all children
242  @param id Index of node to delete
243  */
245 {
246  assert(id <= _graph.size() &&
247  id >= 0 &&
248  "Invalid id");
249 
250  if (id == 0)
251  _graph.clear();
252  else
253  {
254  // Find the next child with the same parentID
255  SLint toID;
256  SLint myParentID = _graph[id].parentID;
257  for (toID = id + 1; toID < _graph.size(); toID++)
258  if (_graph[toID].parentID == myParentID)
259  break;
260 
261  // Erase the elements in the vector
262  _graph.erase(_graph.begin() + id, _graph.begin() + toID);
263  _graph[myParentID].childCount--;
264 
265  // Decrease parentIDs of following subtrees that are greater
266  SLint numNodesToErase = toID - id;
267  for (SLuint i = id; i < _graph.size(); i++)
268  if (_graph[i].parentID > myParentID)
269  _graph[i].parentID = _graph[i].parentID - numNodesToErase;
270  }
271 }
272 //-----------------------------------------------------------------------------
273 /*! Deletes all children of an entity with the index id. Also sub-children of
274  * those children get deleted.
275  * \param id Index of the parent entity
276  */
278 {
279  assert(id <= _graph.size() &&
280  id >= 0 &&
281  "Invalid id");
282 
283  // Find the next child with the same parentID
284  SLuint toID;
285  SLint myParentID = _graph[id].parentID;
286  for (toID = id + 1; toID < _graph.size(); toID++)
287  if (_graph[toID].parentID == myParentID)
288  break;
289 
290  // Erase the elements in the vector
291  _graph.erase(_graph.begin() + id + 1, _graph.begin() + toID);
292  _graph[id].childCount = 0;
293 
294  // Decrease parentIDs of following subtrees that are greater
295  SLuint numNodesToErase = toID - id;
296  for (SLuint i = id; i < _graph.size(); i++)
297  if (_graph[i].parentID > myParentID)
298  _graph[i].parentID = _graph[i].parentID - numNodesToErase;
299 }
300 //-----------------------------------------------------------------------------
unsigned int SLuint
Definition: SL.h:171
bool SLbool
Definition: SL.h:175
#define SL_EXIT_MSG(message)
Definition: SL.h:240
string SLstring
Definition: SL.h:158
int SLint
Definition: SL.h:170
void deleteEntity(SLint id)
Deletes a node at index id with all its children.
Definition: SLEntities.cpp:244
void addChildEntity(SLint myParentID, SLEntity entity)
Adds a child into the vector nodes right after its parent.
Definition: SLEntities.cpp:21
SLuint size()
Returns the size of the entity vector.
Definition: SLEntities.h:77
SLint updateWMRec(SLint id, SLMat4f &parentWM)
Updates all world matrices and returns no. of updated.
Definition: SLEntities.cpp:134
void deleteChildren(SLint id)
Deletes all children of an entity with index id.
Definition: SLEntities.cpp:277
SLint getEntityID(SLNode *node)
Returns the ID of the entity with a SLNode pointer.
Definition: SLEntities.cpp:99
SLEntity * getParent(SLint id)
Returns the pointer to the parent of a node if id is valid else a nullptr.
Definition: SLEntities.cpp:111
SLVEntity _graph
Vector of SLEntity of entire scenegraph.
Definition: SLEntities.h:83
SLint getParentID(SLNode *node)
Returns the parentID of a SLNode pointer.
Definition: SLEntities.cpp:121
SLEntity * getEntity(SLint id)
Returns the pointer to a node if id is valid else a nullptr.
Definition: SLEntities.cpp:89
void dump(SLbool doTreeDump)
Dump scenegraph as a flat vector or as a tree.
Definition: SLEntities.cpp:188
SLbool isEqual(const SLMat4 &A, SLfloat epsilon=0.01f)
Returns true if one element of the matrix differs more than epsilon.
Definition: SLMat4.h:521
void print(const SLchar *str=nullptr) const
Definition: SLMat4.h:1554
void setMatrix(const SLMat4 &A)
Set matrix by other 4x4 matrix.
Definition: SLMat4.h:335
SLMat4< T > inverted() const
Computes the inverse of a 4x4 non-singular matrix.
Definition: SLMat4.h:1371
SLNode represents a node in a hierarchical scene graph.
Definition: SLNode.h:147
const SLMat4f & updateAndGetWM() const
Definition: SLNode.cpp:703
void om(const SLMat4f &mat)
Definition: SLNode.h:276
void name(const SLstring &Name)
Definition: SLObject.h:34
SLEntity is the Data Oriented Design version of a SLNode.
Definition: SLEntities.h:28
SLuint childCount
Number of children.
Definition: SLEntities.h:35
SLMat4f wm
World matrix for world transform.
Definition: SLEntities.h:37
SLint parentID
ID of the parent node (-1 of no parent)
Definition: SLEntities.h:34
SLMat4f wmI
Inverse world matrix.
Definition: SLEntities.h:38
SLNode * node
Pointer to the corresponding SLNode instance.
Definition: SLEntities.h:39
SLMat4f om
Object matrix for local transforms.
Definition: SLEntities.h:36