SLProject  4.2.000
A platform independent 3D computer graphics framework for desktop OS, Android, iOS and online in web browsers
SLScene.cpp
Go to the documentation of this file.
1 /**
2  * \file SLScene.cpp
3  * \date July 2014
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 "SL.h"
11 #include <SLScene.h>
12 #include <Utils.h>
13 #include <SLKeyframeCamera.h>
14 #include <SLGLProgramManager.h>
15 #include <SLSkybox.h>
16 #include <GlobalTimer.h>
17 #include <Profiler.h>
18 #include <SLEntities.h>
19 
20 //-----------------------------------------------------------------------------
21 // Global static instances
24 #ifdef SL_USE_ENTITIES
25 SLEntities SLScene::entities;
26 #endif
27 //-----------------------------------------------------------------------------
28 /*! The constructor of the scene.
29 There will be only one scene for an application and it gets constructed in
30 the C-interface function slCreateScene in SLInterface.cpp that is called by the
31 platform and UI-toolkit dependent window initialization.
32 As examples you can see it in:
33  - app_demo_slproject/glfw: glfwMain.cpp in function main()
34  - app-demo/android: Java_ch_fhnw_comgRT_glES2Lib_onInit()
35  - app_demo_slproject/ios: ViewController.m in method viewDidLoad()
36  - _old/app-Demo-Qt: qtGLWidget::initializeGL()
37  - _old/app-Viewer-Qt: qtGLWidget::initializeGL()
38 */
40  : SLObject(name),
41  _loadTimeMS(0.0f),
42  _frameTimesMS(60, 0.0f),
43  _updateTimesMS(60, 0.0f),
44  _updateAABBTimesMS(60, 0.0f),
45  _updateAnimTimesMS(60, 0.0f),
46  _updateDODTimesMS(60, 0.0f)
47 {
48  _assetManager = nullptr;
49  _root3D = nullptr;
50  _root2D = nullptr;
51  _skybox = nullptr;
52  _info = "";
53  _stopAnimations = false;
54  _fps = 0;
55  _frameTimeMS = 0;
57 }
58 //-----------------------------------------------------------------------------
59 /*! The destructor does the final total deallocation of all global resources.
60 The destructor is called in slTerminate.
61 */
63 {
64  unInit();
65 
66  SL_LOG_DEBUG("Destructor : ~SLScene");
67  SL_LOG_DEBUG("------------------------------------------------------------------");
68 }
69 //-----------------------------------------------------------------------------
70 /*! The scene init is called before a new scene is assembled.
71  */
73 {
74  assert(am && "No asset manager passed to scene");
75 
76  unInit();
77 
78  _assetManager = am;
79 
80  // reset global light settings
81  SLLight::gamma = 1.0f;
82  SLLight::globalAmbient.set(0.15f, 0.15f, 0.15f, 1.0f);
83 
84  // Reset timing variables
85  _frameTimesMS.init(20, 0.0f);
86  _updateTimesMS.init(60, 0.0f);
87  _updateAnimTimesMS.init(60, 0.0f);
88  _updateAABBTimesMS.init(60, 0.0f);
89  _updateDODTimesMS.init(60, 0.0f);
90 }
91 //-----------------------------------------------------------------------------
92 /*! The scene uninitializing clears the scenegraph (_root3D) and all global
93 global resources such as materials, textures & custom shaders loaded with the
94 scene. The standard shaders, the fonts and the 2D-GUI elements remain. They are
95 destructed at process end.
96 */
98 {
99  // delete entire scene graph
100  delete _root3D;
101  _root3D = nullptr;
102  delete _root2D;
103  _root2D = nullptr;
104  _skybox = nullptr;
105 
106  // clear light pointers
107  _lights.clear();
108 
109  _eventHandlers.clear();
111 
112  _selectedMeshes.clear();
113  _selectedNodes.clear();
114 }
115 //-----------------------------------------------------------------------------
116 //! Updates animations and AABBs
117 /*! Updates different updatables in the scene after all views got painted:
118 \n 1) Calculate frame time
119 \n 2) Update all animations
120 \n 3) Update AABBs
121 \n
122 @return true if really something got updated
123 */
124 bool SLScene::onUpdate(bool renderTypeIsRT,
125  bool voxelsAreShown,
126  bool forceCPUSkinning)
127 {
129 
130  /////////////////////////////
131  // 1) Calculate frame time //
132  /////////////////////////////
133 
134  // Calculate the elapsed time for the animation
135  // todo: If slowdown on idle is enabled the delta time will be wrong!
138 
139  // Calculate the frames per second metric
141  SLfloat averagedFrameTimeMS = _frameTimesMS.average();
142  if (averagedFrameTimeMS > 0.001f)
143  _fps = 1 / _frameTimesMS.average() * 1000.0f;
144  else
145  _fps = 0.0f;
146 
147  SLfloat startUpdateMS = GlobalTimer::timeMS();
148 
149  SLbool sceneHasChanged = false;
150 
151  //////////////////////////////
152  // 2) Update all animations //
153  //////////////////////////////
154 
155  SLfloat startAnimUpdateMS = GlobalTimer::timeMS();
156 
157  if (_root3D)
158  _root3D->updateRec();
159  if (_root2D)
160  _root2D->updateRec();
161 
162  // Update node animations
163  sceneHasChanged |= !_stopAnimations && _animManager.update(elapsedTimeSec());
164 
165  // Do software skinning on all changed skeletons. Update any out of date acceleration structure for RT or if they're being rendered.
166  if (_root3D)
167  {
168  if (renderTypeIsRT || voxelsAreShown)
169  forceCPUSkinning = true;
170 
171  // we use a lambda to inform nodes that share a mesh that the mesh got updated (so we don't have to transfer the root node)
172  sceneHasChanged |= _root3D->updateMeshSkins(forceCPUSkinning, [&](SLMesh* mesh)
173  {
174  SLVNode nodes = _root3D->findChildren(mesh, true);
175  for (auto* node : nodes)
176  node->needAABBUpdate(); });
177 
178  if (renderTypeIsRT || voxelsAreShown)
180  }
181 
182  _updateAnimTimesMS.set(GlobalTimer::timeMS() - startAnimUpdateMS);
183 
184  /////////////////////
185  // 3) Update AABBs //
186  /////////////////////
187 
188  // The updateAABBRec call won't generate any overhead if nothing changed
189  SLfloat startAAABBUpdateMS = GlobalTimer::timeMS();
191  if (_root3D)
192  _root3D->updateAABBRec(renderTypeIsRT);
193  if (_root2D)
194  _root2D->updateAABBRec(renderTypeIsRT);
195  _updateAABBTimesMS.set(GlobalTimer::timeMS() - startAAABBUpdateMS);
196 
197 #ifdef SL_USE_ENTITIES
198  SLfloat startDODUpdateMS = GlobalTimer::timeMS();
199  if (entities.size())
200  {
201  SLMat4f root;
202  entities.updateWMRec(0, root);
203  }
204  _updateDODTimesMS.set(GlobalTimer::timeMS() - startDODUpdateMS);
205 #endif
206 
207  // Finish total updateRec time
208  SLfloat updateTimeMS = GlobalTimer::timeMS() - startUpdateMS;
209  _updateTimesMS.set(updateTimeMS);
210 
211  // SL_LOG("SLScene::onUpdate");
212  return sceneHasChanged;
213 }
214 //-----------------------------------------------------------------------------
215 //! Handles the full mesh selection from double-clicks.
216 /*!
217  There are two different selection modes: Full or partial mesh selection.
218  <br>
219  The full selection is done by double-clicking a mesh. Multiple meshes can be
220  selected with SHIFT-double-clicking. The full selection is handled in
221  SLScene::selectNodeMesh. The selected nodes are stored in SLScene::_selectedNodes
222  and the fully or partially selected meshes are stored in SLScene::_selectedMeshes.
223  The SLNode::isSelected and SLMesh::isSelected show if a node or mesh is
224  selected. A node can be selected with or without a mesh. If a mesh is
225  selected, its node is always also selected. A node without mesh can only be
226  selected in the scenegraph window.
227  To avoid a node from selection you can set its drawing bit SL_DB_NOTSELECTABLE.
228  You should transform a node or mesh and show the properties of a node or mesh
229  if only a single node and single full mesh is selected. To get them call
230  SLScene::singleNodeSelected() or SLScene::singleMeshFullSelected().
231  <br>
232  For partial mesh selection see SLMesh::handleRectangleSelection.
233 */
234 void SLScene::selectNodeMesh(SLNode* nodeToSelect, SLMesh* meshToSelect)
235 {
236  // Case 1: Both are nullptr, so unselect all
237  if (!nodeToSelect && !meshToSelect)
238  {
240  return;
241  }
242 
243  if (nodeToSelect && nodeToSelect->drawBit(SL_DB_NOTSELECTABLE))
244  {
245  SL_LOG("Node is not selectable: %s", nodeToSelect->name().c_str());
246  return;
247  }
248 
249  // Case 2: mesh without node selected: This is not allowed
250  if (!nodeToSelect && meshToSelect)
251  SL_EXIT_MSG("SLScene::selectNodeMesh: No node or mesh to select.");
252 
253  // Search in _selectedNodes vector
254  auto foundNode = find(_selectedNodes.begin(),
255  _selectedNodes.end(),
256  nodeToSelect);
257 
258  // Case 3: Node without mesh selected
259  if (nodeToSelect && !meshToSelect)
260  {
261  if (foundNode == _selectedNodes.end())
262  {
263  nodeToSelect->isSelected(true);
264  _selectedNodes.push_back(nodeToSelect);
265  }
266  return;
267  }
268 
269  // Search in _selectedMeshes vector
270  auto foundMesh = find(_selectedMeshes.begin(),
271  _selectedMeshes.end(),
272  meshToSelect);
273 
274  // Case 4: nodeToSelect and meshToSelect are not yet selected: so we select them
275  if (foundNode == _selectedNodes.end() && foundMesh == _selectedMeshes.end())
276  {
277  nodeToSelect->isSelected(true);
278  _selectedNodes.push_back(nodeToSelect);
279  meshToSelect->isSelected(true);
280  meshToSelect->deselectPartialSelection();
281  _selectedMeshes.push_back(meshToSelect);
282  return;
283  }
284 
285  // Case 5: nodeToSelect is already selected but not the mesh: So select only the mesh
286  if (*foundNode == nodeToSelect && foundMesh == _selectedMeshes.end())
287  {
288  nodeToSelect->isSelected(true);
289  meshToSelect->isSelected(true);
290  meshToSelect->deselectPartialSelection();
291  _selectedMeshes.push_back(meshToSelect);
292  return;
293  }
294 
295  // Case 6: nodeToSelect is not selected but the mesh is selected (from another node)
296  if (foundNode == _selectedNodes.end() && *foundMesh == meshToSelect)
297  {
298  nodeToSelect->isSelected(true);
299  _selectedNodes.push_back(nodeToSelect);
300  meshToSelect->isSelected(true);
301  meshToSelect->deselectPartialSelection();
302  _selectedMeshes.push_back(meshToSelect);
303  return;
304  }
305 
306  // Case 7: Both are already selected, so we unselect them.
307  if (nodeToSelect && *foundNode == nodeToSelect && *foundMesh == meshToSelect)
308  {
309  // Check if other mesh from same node is selected
310  bool otherMeshIsSelected = false;
311 
312  SLMesh* nm = nodeToSelect->mesh();
313  for (auto sm : _selectedMeshes)
314  {
315  if (nm == sm && nm != meshToSelect)
316  {
317  otherMeshIsSelected = true;
318  goto endLoop;
319  }
320  }
321 
322  endLoop:
323  if (!otherMeshIsSelected)
324  {
325  nodeToSelect->isSelected(false);
326  _selectedNodes.erase(foundNode);
327  }
328  meshToSelect->deselectPartialSelection();
329  meshToSelect->isSelected(false);
330  _selectedMeshes.erase(foundMesh);
331  return;
332  }
333 
334  SL_EXIT_MSG("SLScene::selectNodeMesh: We should not get here.");
335 }
336 //-----------------------------------------------------------------------------
337 //! Deselects all nodes and its meshes.
339 {
340  for (auto sn : _selectedNodes)
341  sn->isSelected(false);
342  _selectedNodes.clear();
343 
344  for (auto sm : _selectedMeshes)
345  {
346  sm->deselectPartialSelection();
347  sm->isSelected(false);
348  }
349  _selectedMeshes.clear();
350 }
351 //-----------------------------------------------------------------------------
352 //! Returns the number of camera nodes in the scene
354 {
355  if (!_root3D) return 0;
356  deque<SLCamera*> cams = _root3D->findChildren<SLCamera>();
357  return (SLint)cams.size();
358 }
359 //-----------------------------------------------------------------------------
360 //! Returns the next camera in the scene if there is one
362 {
363  if (!_root3D) return nullptr;
364 
365  deque<SLCamera*> cams = _root3D->findChildren<SLCamera>();
366 
367  if (cams.empty()) return nullptr;
368  if (cams.size() == 1) return cams[0];
369 
370  SLint activeIndex = 0;
371  for (SLulong i = 0; i < cams.size(); ++i)
372  {
373  if (cams[i] == activeSVCam)
374  {
375  activeIndex = (SLint)i;
376  break;
377  }
378  }
379 
380  // find next camera, that is not of type SLKeyframeCamera
381  // and if allowAsActiveCam is deactivated
382  do
383  {
384  activeIndex = activeIndex > cams.size() - 2 ? 0 : ++activeIndex;
385  } while (dynamic_cast<SLKeyframeCamera*>(cams[(uint)activeIndex]) &&
386  !dynamic_cast<SLKeyframeCamera*>(cams[(uint)activeIndex])->allowAsActiveCam());
387 
388  return cams[(uint)activeIndex];
389 }
390 //-----------------------------------------------------------------------------
392 {
393  _oculus = std::make_unique<SLGLOculus>(shaderDir);
394  _oculus->init();
395 }
396 //-----------------------------------------------------------------------------
#define PROFILE_FUNCTION()
Definition: Instrumentor.h:41
float SLfloat
Definition: SL.h:173
#define SL_LOG_DEBUG(...)
Definition: SL.h:237
#define SL_LOG(...)
Definition: SL.h:233
unsigned long SLulong
Definition: SL.h:165
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
#define SL_DB_NOTSELECTABLE
Flags an object as selected.
Definition: SLDrawBits.h:21
deque< SLNode * > SLVNode
SLVNode typedef for a vector of SLNodes.
Definition: SLNode.h:26
static float timeMS()
Definition: GlobalTimer.cpp:25
void clear()
Clears and deletes all node animations and skeletons.
SLbool update(SLfloat elapsedTimeSec)
Advances the time of all enabled animation plays.
Toplevel holder of the assets meshes, materials, textures and shaders.
Active or visible camera node class.
Definition: SLCamera.h:54
Scenegraph in Data Oriented Design with flat std::vector of SLEntity.
Definition: SLEntities.h:47
static SLfloat gamma
final output gamma value
Definition: SLLight.h:204
static SLCol4f globalAmbient
static global ambient light intensity
Definition: SLLight.h:202
Global default color attribute material for meshes that have colors per vertex.
Definition: SLMaterial.h:313
static SLMaterialDefaultColorAttribute * _instance
Definition: SLMaterial.h:337
Global default gray color material for meshes that don't define their own.
Definition: SLMaterial.h:284
static SLMaterialDefaultGray * _instance
Definition: SLMaterial.h:308
An SLMesh object is a triangulated mesh, drawn with one draw call.
Definition: SLMesh.h:134
void deselectPartialSelection()
Definition: SLMesh.cpp:698
SLbool isSelected() const
Definition: SLMesh.h:183
SLNode represents a node in a hierarchical scene graph.
Definition: SLNode.h:147
bool updateMeshSkins(bool forceCPUSkinning, const std::function< void(SLMesh *)> &cbInformNodes)
Update all skinned meshes recursively.
Definition: SLNode.cpp:1126
SLbool drawBit(SLuint bit)
Definition: SLNode.h:300
SLMesh * mesh()
Definition: SLNode.h:304
static SLuint numWMUpdates
NO. of calls to updateWMRec per frame.
Definition: SLNode.h:319
void updateRec()
Definition: SLNode.cpp:1107
void isSelected(bool isSelected)
Definition: SLNode.h:286
void updateMeshAccelStructs()
Definition: SLNode.cpp:1149
virtual SLAABBox & updateAABBRec(SLbool updateAlsoAABBinOS)
Definition: SLNode.cpp:731
deque< T * > findChildren(const SLstring &name="", SLbool findRecursive=true, SLbool canContain=false)
Definition: SLNode.h:416
Base class for all other classes.
Definition: SLObject.h:23
void name(const SLstring &Name)
Definition: SLObject.h:34
virtual void unInit()
Definition: SLScene.cpp:97
SLVNode _selectedNodes
Vector of selected nodes. See SLMesh::selectNodeMesh.
Definition: SLScene.h:156
SLVLight _lights
Vector of all lights.
Definition: SLScene.h:147
SLbool _stopAnimations
Global flag for stopping all animations.
Definition: SLScene.h:171
std::unique_ptr< SLGLOculus > _oculus
Oculus Rift interface.
Definition: SLScene.h:173
bool onUpdate(bool renderTypeIsRT, bool voxelsAreShown, bool forceCPUSkinning)
Updates animations and AABBs.
Definition: SLScene.cpp:124
SLSkybox * _skybox
pointer to skybox
Definition: SLScene.h:154
~SLScene() override
Definition: SLScene.cpp:62
void deselectAllNodesAndMeshes()
Deselects all nodes and its meshes.
Definition: SLScene.cpp:338
AvgFloat _frameTimesMS
Averaged total time per frame in ms.
Definition: SLScene.h:165
SLfloat _frameTimeMS
Last frame time in ms.
Definition: SLScene.h:160
SLCamera * nextCameraInScene(SLCamera *activeSVCam)
Returns the next camera in the scene if there is one.
Definition: SLScene.cpp:361
SLint numSceneCameras()
Returns the number of camera nodes in the scene.
Definition: SLScene.cpp:353
AvgFloat _updateDODTimesMS
Averaged time for update the SLEntities graph.
Definition: SLScene.h:169
SLNode * _root3D
Root node for 3D scene.
Definition: SLScene.h:152
SLAssetManager * _assetManager
Pointer to the external assetManager.
Definition: SLScene.h:150
SLVMesh _selectedMeshes
Vector of selected meshes. See SLMesh::selectNodeMesh.
Definition: SLScene.h:157
void initOculus(SLstring shaderDir)
Definition: SLScene.cpp:391
SLstring _info
scene info string
Definition: SLScene.h:155
SLfloat _fps
Averaged no. of frames per second.
Definition: SLScene.h:162
void selectNodeMesh(SLNode *nodeToSelect, SLMesh *meshToSelect)
Handles the full mesh selection from double-clicks.
Definition: SLScene.cpp:234
AvgFloat _updateAABBTimesMS
Averaged time for update the nodes AABB in ms.
Definition: SLScene.h:167
SLVEventHandler _eventHandlers
Vector of all event handler.
Definition: SLScene.h:148
SLScene(const SLstring &name)
Definition: SLScene.cpp:39
SLNode * _root2D
Root node for 2D scene displayed in ortho projection.
Definition: SLScene.h:153
SLfloat _lastUpdateTimeMS
Last time after update in ms.
Definition: SLScene.h:161
SLfloat elapsedTimeSec() const
Definition: SLScene.h:104
AvgFloat _updateAnimTimesMS
Averaged time for update the animations in ms.
Definition: SLScene.h:168
SLAnimManager _animManager
Animation manager instance.
Definition: SLScene.h:149
AvgFloat _updateTimesMS
Averaged time for update in ms.
Definition: SLScene.h:166
void init(SLAssetManager *am)
Definition: SLScene.cpp:72
void set(const T X, const T Y, const T Z, const T W=1)
Definition: SLVec4.h:49
void init(int numValues, T initValue)
Initializes the average value array to a given value.
Definition: Averaged.h:41
void set(T value)
Sets the current value in the value array and builds the average.
Definition: Averaged.h:53
Collection of classes for a state machine implementation used in the Erleb-AR app.
Definition: Event.h:25