SLProject  4.2.000
A platform independent 3D computer graphics framework for desktop OS, Android, iOS and online in web browsers
AppDemoGui.cpp
Go to the documentation of this file.
1 /**
2  * \file AppDemoGui.cpp
3  * \brief UI with the ImGUI framework fully rendered in OpenGL 3+
4  * \date Summer 2017
5  * \authors Marcus Hudritsch
6  * \copyright http://opensource.org/licenses/GPL-3.0
7  * \remarks Please use clangformat to format the code. See more code style on
8  * https://github.com/cpvrlab/SLProject4/wiki/SLProject-Coding-Style
9  */
10 
11 #include <AppDemoGui.h>
12 #include <AppCommon.h>
13 #include <AppDemoSceneID.h>
14 #include <SLEnums.h>
15 #include <Utils.h>
16 #include <SL.h>
17 #include <CVCapture.h>
18 #include <CVImage.h>
19 #include <CVTrackedFeatures.h>
20 #include <SLAssetManager.h>
21 #include <SLAnimPlayback.h>
22 #include <SLGLDepthBuffer.h>
23 #include <SLGLProgramManager.h>
24 #include <SLGLShader.h>
25 #include <SLGLTexture.h>
26 #include <SLInterface.h>
27 #include <SLDeviceRotation.h>
28 #include <SLLightDirect.h>
29 #include <SLLightRect.h>
30 #include <SLLightSpot.h>
31 #include <SLShadowMap.h>
32 #include <SLMaterial.h>
33 #include <SLMesh.h>
34 #include <SLParticleSystem.h>
35 #include <SLNode.h>
36 #include <SLScene.h>
37 #include <SLSceneView.h>
38 #include <SLSkybox.h>
39 #include <SLTexColorLUT.h>
40 #include <SLImGui.h>
41 #include <SLHorizonNode.h>
42 #include <SLFileStorage.h>
43 #include <AverageTiming.h>
44 #include <bezier.hpp>
45 
46 #define IMGUI_DEFINE_MATH_OPERATORS
47 #include <imgui.h>
48 
49 #ifndef SL_EMSCRIPTEN
50 # include <ftplib.h>
51 # include <HttpUtils.h>
52 # include <ZipUtils.h>
53 #endif
54 
55 #include <Profiler.h>
56 
57 #ifdef SL_BUILD_WAI
58 # include <Eigen/Dense>
59 #endif
60 
61 //-----------------------------------------------------------------------------
62 extern CVTracked* gVideoTracker; // Global pointer declared in AppDemoTracking
63 extern SLNode* gVideoTrackedNode; // Global pointer declared in AppDemoTracking
64 extern SLGLTexture* gTexMRI3D; // Global pointer declared in AppDemoLoad
65 extern SLNode* gDragonModel; // Global pointer declared in AppDemoLoad
66 
67 //-----------------------------------------------------------------------------
68 //! Vector getter callback for combo and listbox with std::vector<std::string>
69 static auto vectorGetter =
70  [](void* vec, int idx, const char** out_text)
71 {
72  auto& vector = *(SLVstring*)vec;
73  if (idx < 0 || idx >= (int)vector.size())
74  return false;
75 
76  *out_text = vector.at((SLuint)idx).c_str();
77  return true;
78 };
79 
80 //-----------------------------------------------------------------------------
81 //! Combobox that allows to pass the items as a string vector
82 bool myComboBox(const char* label, int* currIndex, SLVstring& values)
83 {
84  if (values.empty())
85  return false;
86 
87  return ImGui::Combo(label,
88  currIndex,
90  (void*)&values,
91  (int)values.size());
92 }
93 //-----------------------------------------------------------------------------
94 //! Centers the next ImGui window in the parent
96  SLfloat widthPC = 0.9f,
97  SLfloat heightPC = 0.9f)
98 {
99  SLfloat width = (SLfloat)sv->viewportW() * widthPC;
100  SLfloat height = (SLfloat)sv->viewportH() * heightPC;
101  SLfloat offsetX = ((SLfloat)sv->viewportW() - width) * 0.5f;
102  SLfloat offsetY = ((SLfloat)sv->viewportH() - height) * 0.5f;
103  ImGui::SetNextWindowSize(ImVec2(width, height), ImGuiCond_Always);
104  ImGui::SetNextWindowPos(ImVec2(offsetX, offsetY), ImGuiCond_Always);
105 }
106 //-----------------------------------------------------------------------------
107 // Init global static variables
129 std::time_t AppDemoGui::adjustedTime = 0;
131 SLbool AppDemoGui::hideUI = false;
133 
134 // Scene node for Christoffel objects
135 static SLNode* bern = nullptr;
136 static SLNode* balda_stahl = nullptr;
137 static SLNode* balda_glas = nullptr;
138 static SLNode* chrAlt = nullptr;
139 static SLNode* chrNeu = nullptr;
140 
141 // Temp. transform node
142 static SLTransformNode* transformNode = nullptr;
143 
145 Welcome to the SLProject demo app. It is developed at the Computer Science Department of the Bern University of Applied Sciences.
146 The app shows what you can learn in two semesters about 3D computer graphics in real time rendering and ray tracing.
147 The framework is developed in C++ with OpenGL ES so that it can run also on mobile devices.
148 Ray tracing and path tracing provide additional high quality transparencies, reflections and soft shadows.
149 Click the X to close and use the menu File > Load Demo Scenes to choose other scenes that each show-case a specific feature of SLProject.
150 For more information please visit: https://github.com/cpvrlab/SLProject/wiki
151 )";
152 
154 Contributors since 2005 in alphabetic order:
155 Marc Affolter, Martin Christen, Jan Dellsperger, Manuel Frischknecht, Luc Girod, Michael Goettlicher, Michael Schertenleib, Thomas Schneiter, Stefan Thoeni, Timo Tschanz, Marino von Wattenwyl, Marc Wacker, Pascal Zingg
156 
157 Credits for external libraries:
158 - assimp: assimp.sourceforge.net
159 - eigen: eigen.tuxfamily.org
160 - emscripten: emscripten.org
161 - imgui: github.com/ocornut/imgui
162 - gl3w: https://github.com/skaslev/gl3w
163 - glfw: glfw.org
164 - g2o: github.com/RainerKuemmerle/g2o
165 - ktx: khronos.org/ktx
166 - libigl: libigl.github.io
167 - mediapipe: developers.google.com/mediapipe
168 - ORB-SLAM2: github.com/raulmur/ORB_SLAM2
169 - OpenCV: opencv.org
170 - OpenGL: opengl.org
171 - OpenSSL: openssl.org
172 - spa: midcdmz.nrel.gov/spa
173 - stb: single file image library
174 - zlib: zlib.net
175 )";
176 
178 Help for mouse or finger control:
179 - Use left mouse or your finger to rotate the scene
180 - Use mouse-wheel or pinch 2 fingers to go forward/backward
181 - Use middle-mouse or 2 fingers to move sidewards/up-down
182 - Double click or double tap to select object
183 - CTRL-mouse to select vertices of objects
184 - See keyboard shortcuts behind menu commands
185 - Check out the different test scenes under File > Load Test Scene
186 - You can open and dock additional windows from the menu Infos.
187 )";
188 
190 The calibration process requires a chessboard image to be printed and glued on a flat board. You can find the PDF with the chessboard image on:
191 https://github.com/cpvrlab/SLProject/tree/master/data/calibrations/
192 For a calibration you have to take 20 images with detected inner chessboard corners. To take an image you have to click with the mouse
193 or tap with finger into the screen. View the chessboard from the side so that the inner corners cover the full image. Hold the camera or board really still
194 before taking the picture.
195 You can mirror the video image under Preferences > Video. You can check the distance to the chessboard in the dialog Stats. on Video.
196 After calibration the yellow wireframe cube should stick on the chessboard. Please close first this info dialog on the top-left.
197 )";
198 
199 //-----------------------------------------------------------------------------
200 off64_t ftpXferSizeMax = 0;
201 
202 //-----------------------------------------------------------------------------
203 // Callback routine for FTP file transfer to progress the progressbar
204 int ftpCallbackXfer(off64_t xfered, void* arg)
205 {
206  if (ftpXferSizeMax)
207  {
208  int xferedPC = (int)((float)xfered / (float)ftpXferSizeMax * 100.0f);
209  // cout << "Bytes transferred: " << xfered << " (" << xferedPC << ")" << endl;
210  AppCommon::jobProgressNum(xferedPC);
211  }
212  else
213  cout << "Bytes transferred: " << xfered << endl;
214  return xfered ? 1 : 0;
215 }
216 
217 //-----------------------------------------------------------------------------
219 {
220  _horizonVisuEnabled = false;
221 }
222 //-----------------------------------------------------------------------------
223 //! This is the main building function for the GUI of the Demo apps
224 /*! Is is passed to the AppDemoGui::build function in main of the app-demo
225  app. This function will be called once per frame roughly at the end of
226  SLSceneView::onPaint in SLSceneView::draw2DGL by calling ImGui::Render.\n
227  See also the comments on SLImGui.
228  */
230 {
232 
233  // assert(s->assetManager() && "No asset manager assigned to scene!");
235 
236  if (!AppCommon::scene)
237  {
238  ImGui::Begin("Loading",
239  nullptr,
240  ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoBackground | ImGuiWindowFlags_NoNavInputs);
241 
242  float width = static_cast<float>(sv->viewportW());
243  float height = static_cast<float>(sv->viewportH());
244  ImGui::SetWindowSize(ImVec2(width, height));
245  ImGui::SetWindowPos(ImVec2(0, 0));
246 
247  ImVec2 center(0.5f * width, 0.5f * height);
248 
249  ImDrawList* drawList = ImGui::GetWindowDrawList();
250 
251  drawList->AddRectFilled(ImVec2(0, 0), ImVec2(width, height), IM_COL32(40, 40, 40, 255));
252  drawList->AddCircle(center, 50, IM_COL32(105, 125, 145, 255), 0, 10.0f);
253 
254  float offset = 8.0f * static_cast<float>(ImGui::GetTime());
255  drawList->PathArcTo(center, 50, offset, offset + 0.25f * 2 * PI);
256  drawList->PathStroke(IM_COL32(250, 165, 0, 255), 0, 10.0f);
257 
258  const char* text = loadingString.c_str();
259  ImGui::SetCursorPosX(0.5f * (width - ImGui::CalcTextSize(text).x));
260  ImGui::SetCursorPosY(0.5f * height + 100.0f);
261  ImGui::Text(text);
262 
263  ImGui::End();
264  return;
265  }
266 
267  if (AppDemoGui::hideUI ||
268  (sv->camera() && sv->camera()->projType() == P_stereoSideBySideD))
269  {
270  // So far no UI in distorted stereo projection
272  }
273  else
274  {
275  ///////////////////////////////////
276  // Show modeless fullscreen dialogs
277  ///////////////////////////////////
278 
279  // if parallel jobs are running show only the progress information
281  {
282  centerNextWindow(sv, 0.9f, 0.5f);
283  ImGui::Begin("Parallel Job in Progress",
284  &showProgress,
285  ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoNavInputs);
286  ImGui::Text("Parallel Job in Progress:");
287  ImGui::Separator();
288  ImGui::Text("%s", AppCommon::jobProgressMsg().c_str());
289  if (AppCommon::jobProgressMax() > 0)
290  {
291  float num = (float)AppCommon::jobProgressNum();
292  float max = (float)AppCommon::jobProgressMax();
293  ImGui::ProgressBar(num / max);
294  }
295  else
296  {
297  ImGui::Text("Progress: %c", "|/-\\"[(int)(ImGui::GetTime() / 0.05f) & 3]);
298  }
299 
300  ImGui::Separator();
301  ImGui::Text("Parallel Jobs to follow: %u",
302  (uint)AppCommon::jobsToBeThreaded.size());
303  ImGui::Text("Sequential Jobs to follow: %u",
304  (uint)AppCommon::jobsToFollowInMain.size());
305  ImGui::End();
306  return;
307  }
308  else
309  {
310  if (showDockSpace)
311  {
312  static bool opt_fullscreen_persistant = true;
313  bool opt_fullscreen = opt_fullscreen_persistant;
314  static ImGuiDockNodeFlags dockspace_flags = ImGuiDockNodeFlags_PassthruCentralNode;
315 
316  // We are using the ImGuiWindowFlags_NoDocking flag to make the parent window not dockable into,
317  // because it would be confusing to have two docking targets within each others.
318  ImGuiWindowFlags window_flags = ImGuiWindowFlags_NoDocking | ImGuiWindowFlags_NoNavInputs;
319  if (opt_fullscreen)
320  {
321  ImGuiViewport* viewport = ImGui::GetMainViewport();
322  ImGui::SetNextWindowPos(viewport->WorkPos);
323  ImGui::SetNextWindowSize(viewport->WorkSize);
324  ImGui::SetNextWindowViewport(viewport->ID);
325  ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, 0.0f);
326  ImGui::PushStyleVar(ImGuiStyleVar_WindowBorderSize, 0.0f);
327  window_flags |= ImGuiWindowFlags_NoTitleBar |
328  ImGuiWindowFlags_NoCollapse |
329  ImGuiWindowFlags_NoResize |
330  ImGuiWindowFlags_NoMove |
331  ImGuiWindowFlags_NoBringToFrontOnFocus |
332  ImGuiWindowFlags_NoNavFocus;
333  }
334 
335  // When using ImGuiDockNodeFlags_PassthruCentralNode, DockSpace() will render our background
336  // and handle the pass-thru hole, so we ask Begin() to not render a background.
337  if (dockspace_flags & ImGuiDockNodeFlags_PassthruCentralNode)
338  window_flags |= ImGuiWindowFlags_NoBackground;
339 
340  // Important: note that we proceed even if Begin() returns false (aka window is collapsed).
341  // This is because we want to keep our DockSpace() active. If a DockSpace() is inactive,
342  // all active windows docked into it will lose their parent and become undocked.
343  // We cannot preserve the docking relationship between an active window and an inactive docking, otherwise
344  // any change of dockspace/settings would lead to windows being stuck in limbo and never being visible.
345  ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(0.0f, 0.0f));
346  ImGui::Begin("DockSpace Demo", &showDockSpace, window_flags);
347  ImGui::PopStyleVar();
348 
349  if (opt_fullscreen)
350  ImGui::PopStyleVar(2);
351 
352  // DockSpace
353  ImGuiIO& io = ImGui::GetIO();
354  if (io.ConfigFlags & ImGuiConfigFlags_DockingEnable)
355  {
356  ImGuiID dockspace_id = ImGui::GetID("MyDockSpace");
357  ImGui::DockSpace(dockspace_id, ImVec2(0.0f, 0.0f), dockspace_flags);
358  }
359 
360  ImGui::End();
361  }
362 
363  if (showAbout)
364  {
366  ImGui::Begin("About SLProject", &showAbout, ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoNavInputs);
367  ImGui::Text("Version: %s", AppCommon::version.c_str());
368  ImGui::Text("Configuration: %s", AppCommon::configuration.c_str());
369  ImGui::Separator();
370  ImGui::Text("Git Branch: %s (Commit: %s)", AppCommon::gitBranch.c_str(), AppCommon::gitCommit.c_str());
371  ImGui::Text("Git Date: %s", AppCommon::gitDate.c_str());
372  ImGui::Separator();
373  ImGui::TextWrapped("%s", infoAbout.c_str());
374  ImGui::End();
375  return;
376  }
377 
378  if (showHelp)
379  {
381  ImGui::Begin("Help on Interaction", &showHelp, ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoNavInputs);
382  ImGui::TextWrapped("%s", infoHelp.c_str());
383  ImGui::End();
384  return;
385  }
386 
388  {
390  ImGui::Begin("Help on Camera Calibration", &showHelpCalibration, ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoNavInputs);
391  ImGui::TextWrapped("%s", infoCalibrate.c_str());
392  ImGui::End();
393  return;
394  }
395 
396  if (showCredits)
397  {
399  ImGui::Begin("Credits for all Contributors and external Libraries", &showCredits, ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoNavInputs);
400  ImGui::TextWrapped("%s", infoCredits.c_str());
401  ImGui::End();
402  return;
403  }
404 
405  //////////////////
406  // Show rest modal
407  //////////////////
408 
409  buildMenuBar(s, sv);
410 
412 
413  if (showStatsTiming)
414  {
415  SLRenderType rType = sv->renderType();
416  SLfloat ft = s->frameTimesMS().average();
418 
419  SLchar m[2550]; // message character array
420  m[0] = 0; // set zero length
421 
422  if (rType == RT_gl)
423  {
424  // Get averages from average variables (see Averaged)
425  SLfloat captureTime = CVCapture::instance()->captureTimesMS().average();
426  SLfloat updateTime = s->updateTimesMS().average();
427 #ifndef SL_EMSCRIPTEN
428  SLfloat trackingTime = CVTracked::trackingTimesMS.average();
430  SLfloat detect1Time = CVTracked::detect1TimesMS.average();
431  SLfloat detect2Time = CVTracked::detect2TimesMS.average();
433  SLfloat optFlowTime = CVTracked::optFlowTimesMS.average();
435 #endif
436  SLfloat updateAnimTime = s->updateAnimTimesMS().average();
437  SLfloat updateAABBTime = s->updateAABBTimesMS().average();
438  SLfloat shadowMapTime = sv->shadowMapTimeMS().average();
439  SLfloat cullTime = sv->cullTimesMS().average();
440  SLfloat draw3DTime = sv->draw3DTimesMS().average();
441  SLfloat draw2DTime = sv->draw2DTimesMS().average();
442 
443  // Calculate percentage from frame time
444  SLfloat captureTimePC = Utils::clamp(captureTime / ft * 100.0f, 0.0f, 100.0f);
445  SLfloat updateTimePC = Utils::clamp(updateTime / ft * 100.0f, 0.0f, 100.0f);
446 #ifndef SL_EMSCRIPTEN
447  SLfloat trackingTimePC = Utils::clamp(trackingTime / ft * 100.0f, 0.0f, 100.0f);
448  SLfloat detectTimePC = Utils::clamp(detectTime / ft * 100.0f, 0.0f, 100.0f);
449  SLfloat matchTimePC = Utils::clamp(matchTime / ft * 100.0f, 0.0f, 100.0f);
450  SLfloat optFlowTimePC = Utils::clamp(optFlowTime / ft * 100.0f, 0.0f, 100.0f);
451  SLfloat poseTimePC = Utils::clamp(poseTime / ft * 100.0f, 0.0f, 100.0f);
452 #endif
453  SLfloat updateAnimTimePC = Utils::clamp(updateAnimTime / ft * 100.0f, 0.0f, 100.0f);
454  SLfloat updateAABBTimePC = Utils::clamp(updateAABBTime / ft * 100.0f, 0.0f, 100.0f);
455  SLfloat shadowMapTimePC = Utils::clamp(shadowMapTime / ft * 100.0f, 0.0f, 100.0f);
456  SLfloat draw3DTimePC = Utils::clamp(draw3DTime / ft * 100.0f, 0.0f, 100.0f);
457  SLfloat draw2DTimePC = Utils::clamp(draw2DTime / ft * 100.0f, 0.0f, 100.0f);
458  SLfloat cullTimePC = Utils::clamp(cullTime / ft * 100.0f, 0.0f, 100.0f);
459 
460  snprintf(m + strlen(m), sizeof(m), "Renderer : OpenGL\n");
461  snprintf(m + strlen(m), sizeof(m), "Load time : %5.1f ms\n", s->loadTimeMS());
462  snprintf(m + strlen(m), sizeof(m), "Window size: %d x %d\n", sv->viewportW(), sv->viewportH());
463  snprintf(m + strlen(m), sizeof(m), "Drawcalls : %d\n", SLGLVertexArray::totalDrawCalls);
464  snprintf(m + strlen(m), sizeof(m), " Shadow : %d\n", SLShadowMap::drawCalls);
465  snprintf(m + strlen(m), sizeof(m), " Render : %d\n", SLGLVertexArray::totalDrawCalls - SLShadowMap::drawCalls);
466  snprintf(m + strlen(m), sizeof(m), "Primitives : %d\n", SLGLVertexArray::totalPrimitivesRendered);
467  snprintf(m + strlen(m), sizeof(m), "FPS : %5.1f\n", s->fps());
468  snprintf(m + strlen(m), sizeof(m), "Frame time : %5.1f ms (100%%)\n", ft);
469  snprintf(m + strlen(m), sizeof(m), " Capture : %5.1f ms (%3d%%)\n", captureTime, (SLint)captureTimePC);
470  snprintf(m + strlen(m), sizeof(m), " Update : %5.1f ms (%3d%%)\n", updateTime, (SLint)updateTimePC);
471 #ifdef SL_USE_ENTITIES
472  SLfloat updateDODTime = s->updateDODTimesMS().average();
473  SLfloat updateDODTimePC = Utils::clamp(updateDODTime / ft * 100.0f, 0.0f, 100.0f);
474  snprintf(m + strlen(m), sizeof(m), " EntityWM : %5.1f ms (%3d%%)\n", updateDODTime, (SLint)updateDODTimePC);
475 #endif
476  if (!s->animManager().animationNames().empty())
477  {
478  snprintf(m + strlen(m), sizeof(m), " Anim. : %5.1f ms (%3d%%)\n", updateAnimTime, (SLint)updateAnimTimePC);
479  snprintf(m + strlen(m), sizeof(m), " AABB : %5.1f ms (%3d%%)\n", updateAABBTime, (SLint)updateAABBTimePC);
480  }
481 
482 #ifndef SL_EMSCRIPTEN
483  if (vt != VT_NONE && gVideoTracker != nullptr && gVideoTrackedNode != nullptr)
484  {
485  snprintf(m + strlen(m), sizeof(m), " Tracking : %5.1f ms (%3d%%)\n", trackingTime, (SLint)trackingTimePC);
486  snprintf(m + strlen(m), sizeof(m), " Detect : %5.1f ms (%3d%%)\n", detectTime, (SLint)detectTimePC);
487  snprintf(m + strlen(m), sizeof(m), " Det1 : %5.1f ms\n", detect1Time);
488  snprintf(m + strlen(m), sizeof(m), " Det2 : %5.1f ms\n", detect2Time);
489  snprintf(m + strlen(m), sizeof(m), " Match : %5.1f ms (%3d%%)\n", matchTime, (SLint)matchTimePC);
490  snprintf(m + strlen(m), sizeof(m), " OptFlow : %5.1f ms (%3d%%)\n", optFlowTime, (SLint)optFlowTimePC);
491  snprintf(m + strlen(m), sizeof(m), " Pose : %5.1f ms (%3d%%)\n", poseTime, (SLint)poseTimePC);
492  }
493 #endif
494  snprintf(m + strlen(m), sizeof(m), " Shadows : %5.1f ms (%3d%%)\n", shadowMapTime, (SLint)shadowMapTimePC);
495  snprintf(m + strlen(m), sizeof(m), " Culling : %5.1f ms (%3d%%)\n", cullTime, (SLint)cullTimePC);
496  snprintf(m + strlen(m), sizeof(m), " Drawing 3D: %5.1f ms (%3d%%)\n", draw3DTime, (SLint)draw3DTimePC);
497  snprintf(m + strlen(m), sizeof(m), " Drawing 2D: %5.1f ms (%3d%%)\n", draw2DTime, (SLint)draw2DTimePC);
498  }
499  else if (rType == RT_rt)
500  {
501  SLRaytracer* rt = sv->raytracer();
502  SLint rtWidth = (SLint)((float)sv->viewportW() * rt->resolutionFactor());
503  SLint rtHeight = (SLint)((float)sv->viewportH() * rt->resolutionFactor());
504  SLuint rayPrimaries = (SLuint)(rtWidth * rtHeight);
505  SLuint rayTotal = SLRay::totalNumRays();
506  SLfloat renderSec = rt->renderSec();
507  SLfloat fps = renderSec > 0.001f ? 1.0f / rt->renderSec() : 0.0f;
508 
509  snprintf(m + strlen(m), sizeof(m), "Renderer :Ray Tracer\n");
510  snprintf(m + strlen(m), sizeof(m), "Progress :%3d%%\n", rt->progressPC());
511  snprintf(m + strlen(m), sizeof(m), "Frame size :%d x %d\n", rtWidth, rtHeight);
512  snprintf(m + strlen(m), sizeof(m), "FPS :%0.2f\n", fps);
513  snprintf(m + strlen(m), sizeof(m), "Frame Time :%0.3f sec.\n", renderSec);
514  snprintf(m + strlen(m), sizeof(m), "Rays per ms:%0.0f\n", rt->raysPerMS());
515  snprintf(m + strlen(m), sizeof(m), "AA Pixels :%d (%d%%)\n", SLRay::subsampledPixels, (int)((float)SLRay::subsampledPixels / (float)rayPrimaries * 100.0f));
516  snprintf(m + strlen(m), sizeof(m), "Threads :%d\n", rt->numThreads());
517  snprintf(m + strlen(m), sizeof(m), "----------------------------\n");
518  snprintf(m + strlen(m), sizeof(m), "Total rays :%9d (%3d%%)\n", rayTotal, 100);
519  snprintf(m + strlen(m), sizeof(m), " Primary :%9d (%3d%%)\n", rayPrimaries, (int)((float)rayPrimaries / (float)rayTotal * 100.0f));
520  snprintf(m + strlen(m), sizeof(m), " Reflected:%9d (%3d%%)\n", SLRay::reflectedRays, (int)((float)SLRay::reflectedRays / (float)rayTotal * 100.0f));
521  snprintf(m + strlen(m), sizeof(m), " Refracted:%9d (%3d%%)\n", SLRay::refractedRays, (int)((float)SLRay::refractedRays / (float)rayTotal * 100.0f));
522  snprintf(m + strlen(m), sizeof(m), " TIR :%9d (%3d%%)\n", SLRay::tirRays, (int)((float)SLRay::tirRays / (float)rayTotal * 100.0f));
523  snprintf(m + strlen(m), sizeof(m), " Shadow :%9d (%3d%%)\n", SLRay::shadowRays, (int)((float)SLRay::shadowRays / (float)rayTotal * 100.0f));
524  snprintf(m + strlen(m), sizeof(m), " AA :%9d (%3d%%)\n", SLRay::subsampledRays, (int)((float)SLRay::subsampledRays / (float)rayTotal * 100.0f));
525  snprintf(m + strlen(m), sizeof(m), "----------------------------\n");
526  snprintf(m + strlen(m), sizeof(m), "Max. depth :%u\n", SLRay::maxDepthReached);
527  snprintf(m + strlen(m), sizeof(m), "Avg. depth :%0.3f\n", SLRay::avgDepth / (float)rayPrimaries);
528  }
529 #if defined(SL_BUILD_WITH_OPTIX) && defined(SL_HAS_OPTIX)
530  else if (rType == RT_optix_rt)
531  {
532  SLOptixRaytracer* ort = sv->optixRaytracer();
533  snprintf(m + strlen(m), sizeof(m), "Renderer :OptiX Ray Tracer\n");
534  snprintf(m + strlen(m), sizeof(m), "Frame size :%d x %d\n", sv->scrW(), sv->scrH());
535  snprintf(m + strlen(m), sizeof(m), "FPS :%5.1f\n", s->fps());
536  snprintf(m + strlen(m), sizeof(m), "Frame Time :%0.3f sec.\n", 1.0f / s->fps());
537  }
538  else if (rType == RT_optix_pt)
539  {
540  SLOptixPathtracer* opt = sv->optixPathtracer();
541  snprintf(m + strlen(m), sizeof(m), "Renderer :OptiX Ray Tracer\n");
542  snprintf(m + strlen(m), sizeof(m), "Frame size :%d x %d\n", sv->scrW(), sv->scrH());
543  snprintf(m + strlen(m), sizeof(m), "Frame Time :%0.2f sec.\n", opt->renderSec());
544  snprintf(m + strlen(m), sizeof(m), "Denoiser Time :%0.0f ms.\n", opt->denoiserMS());
545  }
546 #endif
547  else if (rType == RT_pt)
548  {
549  SLPathtracer* pt = sv->pathtracer();
550  SLint ptWidth = (SLint)((float)sv->viewportW() * pt->resolutionFactor());
551  SLint ptHeight = (SLint)((float)sv->viewportH() * pt->resolutionFactor());
552  SLuint rayTotal = SLRay::totalNumRays();
553 
554  snprintf(m + strlen(m), sizeof(m), "Renderer :Path Tracer\n");
555  snprintf(m + strlen(m), sizeof(m), "Progress :%3d%%\n", pt->progressPC());
556  snprintf(m + strlen(m), sizeof(m), "Frame size :%d x %d\n", ptWidth, ptHeight);
557  snprintf(m + strlen(m), sizeof(m), "FPS :%0.2f\n", 1.0f / pt->renderSec());
558  snprintf(m + strlen(m), sizeof(m), "Frame Time :%0.2f sec.\n", pt->renderSec());
559  snprintf(m + strlen(m), sizeof(m), "Rays per ms:%0.0f\n", pt->raysPerMS());
560  snprintf(m + strlen(m), sizeof(m), "Samples/pix:%d\n", pt->aaSamples());
561  snprintf(m + strlen(m), sizeof(m), "Threads :%d\n", pt->numThreads());
562  snprintf(m + strlen(m), sizeof(m), "---------------------------\n");
563  snprintf(m + strlen(m), sizeof(m), "Total rays :%8d (%3d%%)\n", rayTotal, 100);
564  snprintf(m + strlen(m), sizeof(m), " Reflected:%8d (%3d%%)\n", SLRay::reflectedRays, (int)((float)SLRay::reflectedRays / (float)rayTotal * 100.0f));
565  snprintf(m + strlen(m), sizeof(m), " Refracted:%8d (%3d%%)\n", SLRay::refractedRays, (int)((float)SLRay::refractedRays / (float)rayTotal * 100.0f));
566  snprintf(m + strlen(m), sizeof(m), " TIR :%8d\n", SLRay::tirRays);
567  snprintf(m + strlen(m), sizeof(m), " Shadow :%8d (%3d%%)\n", SLRay::shadowRays, (int)((float)SLRay::shadowRays / (float)rayTotal * 100.0f));
568  snprintf(m + strlen(m), sizeof(m), "---------------------------\n");
569  }
570 
571  ImGui::PushFont(ImGui::GetIO().Fonts->Fonts[1]);
572  ImGui::Begin("Timing", &showStatsTiming, ImGuiWindowFlags_NoResize | ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoNavInputs);
573  ImGui::TextUnformatted(m);
574  ImGui::End();
575  ImGui::PopFont();
576  }
577 
578  if (showStatsScene)
579  {
580  SLchar m[2550]; // message character array
581  m[0] = 0; // set zero length
582 
583  SLNodeStats& stats3D = sv->stats3D();
584  SLfloat vox = (SLfloat)stats3D.numVoxels;
585  SLfloat voxEmpty = (SLfloat)stats3D.numVoxEmpty;
586  SLfloat voxelsEmpty = vox > 0.0f ? voxEmpty / vox * 100.0f : 0.0f;
587  SLfloat numRTTria = (SLfloat)stats3D.numTriangles;
588  SLfloat avgTriPerVox = vox > 0.0f ? numRTTria / (vox - voxEmpty) : 0.0f;
589  SLint numOverdrawnNodes = (int)sv->nodesOverdrawn().size();
590  SLint numVisibleNodes = (int)(stats3D.numNodesOpaque + stats3D.numNodesBlended + numOverdrawnNodes);
591  SLint numGroupPC = stats3D.numNodes == 0 ? 0 : (SLint)((SLfloat)stats3D.numNodesGroup / (SLfloat)stats3D.numNodes * 100.0f);
592  SLint numLeafPC = stats3D.numNodes == 0 ? 0 : (SLint)((SLfloat)stats3D.numNodesLeaf / (SLfloat)stats3D.numNodes * 100.0f);
593  SLint numLightsPC = stats3D.numNodes == 0 ? 0 : (SLint)((SLfloat)stats3D.numLights / (SLfloat)stats3D.numNodes * 100.0f);
594  SLint numOpaquePC = stats3D.numNodes == 0 ? 0 : (SLint)((SLfloat)stats3D.numNodesOpaque / (SLfloat)stats3D.numNodes * 100.0f);
595  SLint numBlendedPC = stats3D.numNodes == 0 ? 0 : (SLint)((SLfloat)stats3D.numNodesBlended / (SLfloat)stats3D.numNodes * 100.0f);
596  SLint numOverdrawnPC = stats3D.numNodes == 0 ? 0 : (SLint)((SLfloat)numOverdrawnNodes / (SLfloat)stats3D.numNodes * 100.0f);
597  SLint numVisiblePC = stats3D.numNodes == 0 ? 0 : (SLint)((SLfloat)numVisibleNodes / (SLfloat)stats3D.numNodes * 100.0f);
598 
599  // Calculate total size of texture bytes on CPU
600  SLfloat cpuMBTexture = 0;
601  for (auto* t : am->textures())
602  for (auto* i : t->images())
603  cpuMBTexture += (float)i->bytesPerImage();
604  cpuMBTexture = cpuMBTexture / 1E6f;
605 
606  SLfloat cpuMBMeshes = (SLfloat)stats3D.numBytes / 1E6f;
607  SLfloat cpuMBVoxels = (SLfloat)stats3D.numBytesAccel / 1E6f;
608  SLfloat cpuMBTotal = cpuMBTexture + cpuMBMeshes + cpuMBVoxels;
609  SLint cpuMBTexturePC = std::abs(cpuMBTotal) < 1E-5f ? 0 : (SLint)(cpuMBTexture / cpuMBTotal * 100.0f);
610  SLint cpuMBMeshesPC = std::abs(cpuMBTotal) < 1E-5f ? 0 : (SLint)(cpuMBMeshes / cpuMBTotal * 100.0f);
611  SLint cpuMBVoxelsPC = std::abs(cpuMBTotal) < 1E-5f ? 0 : (SLint)(cpuMBVoxels / cpuMBTotal * 100.0f);
612  SLfloat gpuMBTexture = (SLfloat)SLGLTexture::totalNumBytesOnGPU / 1E6f;
614  SLfloat gpuMBTotal = gpuMBTexture + gpuMBVbo;
615  SLint gpuMBTexturePC = std::abs(gpuMBTotal) < 1E-5 ? 0 : (SLint)(gpuMBTexture / gpuMBTotal * 100.0f);
616  SLint gpuMBVboPC = std::abs(gpuMBTotal) < 1E-5 ? 0 : (SLint)(gpuMBVbo / gpuMBTotal * 100.0f);
617 
618  snprintf(m + strlen(m), sizeof(m), "No. of Nodes :%5d (100%%)\n", stats3D.numNodes);
619  snprintf(m + strlen(m), sizeof(m), "- Group Nodes :%5d (%3d%%)\n", stats3D.numNodesGroup, numGroupPC);
620  snprintf(m + strlen(m), sizeof(m), "- Leaf Nodes :%5d (%3d%%)\n", stats3D.numNodesLeaf, numLeafPC);
621  snprintf(m + strlen(m), sizeof(m), "- Light Nodes :%5d (%3d%%)\n", stats3D.numLights, numLightsPC);
622  snprintf(m + strlen(m), sizeof(m), "- Opaque Nodes:%5d (%3d%%)\n", stats3D.numNodesOpaque, numOpaquePC);
623  snprintf(m + strlen(m), sizeof(m), "- Blend Nodes :%5d (%3d%%)\n", stats3D.numNodesBlended, numBlendedPC);
624  snprintf(m + strlen(m), sizeof(m), "- Overdrawn N.:%5d (%3d%%)\n", numOverdrawnNodes, numOverdrawnPC);
625  snprintf(m + strlen(m), sizeof(m), "- Vis. Nodes :%5d (%3d%%)\n", numVisibleNodes, numVisiblePC);
626  snprintf(m + strlen(m), sizeof(m), "- WM Updates :%5d\n", SLNode::numWMUpdates);
627  snprintf(m + strlen(m), sizeof(m), "No. of Meshes :%5u\n", stats3D.numMeshes);
628  snprintf(m + strlen(m), sizeof(m), "No. of Tri. :%5u\n", stats3D.numTriangles);
629  snprintf(m + strlen(m), sizeof(m), "CPU MB Total :%6.2f (100%%)\n", cpuMBTotal);
630  snprintf(m + strlen(m), sizeof(m), "- MB Tex. :%6.2f (%3d%%)\n", cpuMBTexture, cpuMBTexturePC);
631  snprintf(m + strlen(m), sizeof(m), "- MB Meshes :%6.2f (%3d%%)\n", cpuMBMeshes, cpuMBMeshesPC);
632  snprintf(m + strlen(m), sizeof(m), "- MB Voxels :%6.2f (%3d%%)\n", cpuMBVoxels, cpuMBVoxelsPC);
633  snprintf(m + strlen(m), sizeof(m), "GPU MB Total :%6.2f (100%%)\n", gpuMBTotal);
634  snprintf(m + strlen(m), sizeof(m), "- MB Tex. :%6.2f (%3d%%)\n", gpuMBTexture, gpuMBTexturePC);
635  snprintf(m + strlen(m), sizeof(m), "- MB VBO :%6.2f (%3d%%)\n", gpuMBVbo, gpuMBVboPC);
636  snprintf(m + strlen(m), sizeof(m), "No. of Voxels :%d\n", stats3D.numVoxels);
637  snprintf(m + strlen(m), sizeof(m), "-empty Voxels :%4.1f%%\n", voxelsEmpty);
638  snprintf(m + strlen(m), sizeof(m), "Avg.Tri/Voxel :%4.1f\n", avgTriPerVox);
639  snprintf(m + strlen(m), sizeof(m), "Max.Tri/Voxel :%d\n", stats3D.numVoxMaxTria);
640 
641  // Switch to fixed font
642  ImGui::PushFont(ImGui::GetIO().Fonts->Fonts[1]);
643  ImGui::Begin("Scene Statistics", &showStatsScene, ImGuiWindowFlags_NoResize | ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoNavInputs);
644  ImGui::Text("%s (%d)", s->name().c_str(), AppCommon::sceneID);
645  ImGui::Separator();
646  ImGui::TextUnformatted(m);
647  ImGui::Separator();
648  ImGui::Text("Global Resources:");
649 
650  string label = "Meshes (" + std::to_string(am->meshes().size()) + ")";
651  if (am->meshes().size() && ImGui::TreeNode(label.c_str()))
652  {
653  for (SLuint i = 0; i < am->meshes().size(); ++i)
654  ImGui::Text("[%d] %s (%u v.)",
655  i,
656  am->meshes()[i]->name().c_str(),
657  (SLuint)am->meshes()[i]->P.size());
658 
659  ImGui::TreePop();
660  }
661 
662  label = "Lights (" + std::to_string(s->lights().size()) + ")";
663  if (s->lights().size() && ImGui::TreeNode(label.c_str()))
664  {
665  for (SLuint i = 0; i < s->lights().size(); ++i)
666  {
667  SLNode* light = dynamic_cast<SLNode*>(s->lights()[i]);
668  ImGui::Text("[%u] %s", i, light->name().c_str());
669  }
670 
671  ImGui::TreePop();
672  }
673 
674  label = "Materials (" + std::to_string(sv->visibleMaterials3D().size()) + ")";
675  if (sv->visibleMaterials3D().size() && ImGui::TreeNode(label.c_str()))
676  {
677  for (auto* mat : sv->visibleMaterials3D())
678  {
679  SLVNode& matNodes = mat->nodesVisible3D();
680  snprintf(m,
681  sizeof(m),
682  "%s [%u n.]",
683  mat->name().c_str(),
684  (SLuint)matNodes.size());
685 
686  if (matNodes.size())
687  {
688  if (ImGui::TreeNode(m))
689  {
690  for (auto* node : matNodes)
691  ImGui::Text(node->name().c_str());
692 
693  ImGui::TreePop();
694  }
695  }
696  else
697  ImGui::Text(m);
698  }
699 
700  ImGui::TreePop();
701  }
702 
703  label = "Meshes (" + std::to_string(am->textures().size()) + ")";
704  if (am->textures().size() && ImGui::TreeNode(label.c_str()))
705  {
706  for (SLuint i = 0; i < am->textures().size(); ++i)
707  {
708  if (am->textures()[i]->images().empty())
709  ImGui::Text("[%u] %s on GPU (%s)", i, am->textures()[i]->name().c_str(), am->textures()[i]->isTexture() ? "ok" : "not ok");
710  else
711  ImGui::Text("[%u] %s (%s)", i, am->textures()[i]->name().c_str(), am->textures()[i]->isTexture() ? "ok" : "not ok");
712  }
713 
714  ImGui::TreePop();
715  }
716 
717  label = "Programs in AM (" + std::to_string(am->programs().size()) + ")";
718  if (am->programs().size() && ImGui::TreeNode(label.c_str()))
719  {
720  for (SLuint i = 0; i < am->programs().size(); ++i)
721  {
722  SLGLProgram* p = am->programs()[i];
723  ImGui::Text("[%u] %s", i, p->name().c_str());
724  }
725  ImGui::TreePop();
726  }
727 
728  label = "Programs in app (" + std::to_string(SLGLProgramManager::size()) + ")";
729  if (ImGui::TreeNode(label.c_str()))
730  {
731  for (SLuint i = 0; i < SLGLProgramManager::size(); ++i)
732  ImGui::Text("[%u] %s", i, SLGLProgramManager::get((SLStdShaderProg)i)->name().c_str());
733 
734  ImGui::TreePop();
735  }
736 
737  ImGui::End();
738  ImGui::PopFont();
739  }
740 
741  if (showStatsVideo)
742  {
743  SLchar m[2550]; // message character array
744  m[0] = 0; // set zero length
745 
750  SLstring mirrored = "None";
751  if (c->isMirroredH() && c->isMirroredV())
752  mirrored = "horizontally & vertically";
753  else if (c->isMirroredH())
754  mirrored = "horizontally";
755  else if (c->isMirroredV())
756  mirrored = "vertically";
757 
758  snprintf(m + strlen(m), sizeof(m), "Video Type : %s\n", vt == VT_NONE ? "None" : vt == VT_MAIN ? "Main Camera"
759  : vt == VT_FILE ? "File"
760  : "Secondary Camera");
761  snprintf(m + strlen(m), sizeof(m), "Display size : %d x %d\n", CVCapture::instance()->lastFrame.cols, CVCapture::instance()->lastFrame.rows);
762  snprintf(m + strlen(m), sizeof(m), "Capture size : %d x %d\n", capSize.width, capSize.height);
763  snprintf(m + strlen(m), sizeof(m), "Size Index : %d\n", ac->camSizeIndex());
764  snprintf(m + strlen(m), sizeof(m), "Mirrored : %s\n", mirrored.c_str());
765  snprintf(m + strlen(m), sizeof(m), "Chessboard : %dx%d (%3.1fmm)\n", c->boardSize().width, c->boardSize().height, c->boardSquareMM());
766  snprintf(m + strlen(m), sizeof(m), "Undistorted : %s\n", ac->showUndistorted() ? "Yes" : "No");
767  snprintf(m + strlen(m), sizeof(m), "Calibimg size: %d x %d\n", ac->calibration.imageSizeOriginal().width, ac->calibration.imageSizeOriginal().height);
768  snprintf(m + strlen(m), sizeof(m), "FOV H/V(deg.): %4.1f/%4.1f\n", c->cameraFovHDeg(), c->cameraFovVDeg());
769  snprintf(m + strlen(m), sizeof(m), "fx,fy : %4.1f,%4.1f\n", c->fx(), c->fy());
770  snprintf(m + strlen(m), sizeof(m), "cx,cy : %4.1f,%4.1f\n", c->cx(), c->cy());
771 
772  int distortionSize = c->distortion().rows;
773  const float f = 100.f;
774  snprintf(m + strlen(m), sizeof(m), "dist.(*10e-2):\n");
775  snprintf(m + strlen(m), sizeof(m), "k1,k2 : %4.2f,%4.2f\n", c->k1() * f, c->k2() * f);
776  snprintf(m + strlen(m), sizeof(m), "p1,p2 : %4.2f,%4.2f\n", c->p1() * f, c->p2() * f);
777  if (distortionSize >= 8)
778  snprintf(m + strlen(m), sizeof(m), "k3,k4,k5,k6 : %4.2f,%4.2f,%4.2f,%4.2f\n", c->k3() * f, c->k4() * f, c->k5() * f, c->k6() * f);
779  else
780  snprintf(m + strlen(m), sizeof(m), "k3 : %4.2f\n", c->k3() * f);
781 
782  if (distortionSize >= 12)
783  snprintf(m + strlen(m), sizeof(m), "s1,s2,s3,s4 : %4.2f,%4.2f,%4.2f,%4.2f\n", c->s1() * f, c->s2() * f, c->s3() * f, c->s4() * f);
784  if (distortionSize >= 14)
785  snprintf(m + strlen(m), sizeof(m), "tauX,tauY : %4.2f,%4.2f\n", c->tauX() * f, c->tauY() * f);
786 
787  snprintf(m + strlen(m), sizeof(m), "Calib. time : %s\n", c->calibrationTime().c_str());
788  snprintf(m + strlen(m), sizeof(m), "Calib. state : %s\n", c->stateStr().c_str());
789  snprintf(m + strlen(m), sizeof(m), "Num. caps : %d\n", c->numCapturedImgs());
790 
791  if (vt != VT_NONE && gVideoTracker != nullptr && gVideoTrackedNode != nullptr)
792  {
793  snprintf(m + strlen(m), sizeof(m), "-------------:\n");
794  if (typeid(*gVideoTrackedNode) == typeid(SLCamera))
795  {
797  snprintf(m + strlen(m), sizeof(m), "Dist. to zero: %4.2f\n", cameraPos.length());
798  }
799  else
800  {
801  SLVec3f cameraPos = ((SLNode*)sv->camera())->updateAndGetWM().translation();
803  SLVec3f camToObj = objectPos - cameraPos;
804  snprintf(m + strlen(m), sizeof(m), "Dist. to obj.: %4.2f\n", camToObj.length());
805  }
806  }
807 
808  // Switch to fixed font
809  ImGui::PushFont(ImGui::GetIO().Fonts->Fonts[1]);
810  ImGui::Begin("Video", &showStatsVideo, ImGuiWindowFlags_NoResize | ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoNavInputs);
811  ImGui::TextUnformatted(m);
812  ImGui::End();
813  ImGui::PopFont();
814  }
815 #ifdef SL_BUILD_WAI
817  {
818  ImGui::PushFont(ImGui::GetIO().Fonts->Fonts[1]);
819  ImGui::Begin("WAI Statistics", &showStatsWAI, ImGuiWindowFlags_NoResize | ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoNavInputs);
820 
821  if (!AverageTiming::instance().empty())
822  {
823  SLchar m[2550]; // message character array
824  m[0] = 0; // set zero length
825 
826  AverageTiming::getTimingMessage(m);
827 
828  // define ui elements
829  ImGui::TextUnformatted(m);
830  }
831 
832  ImGui::End();
833  ImGui::PopFont();
834  }
835 #endif
836  if (showImGuiMetrics)
837  {
838  ImGui::ShowMetricsWindow();
839  }
840 
841  if (showInfosScene)
842  {
843  // Calculate window position for dynamic status bar at the bottom of the main window
844  ImGuiWindowFlags window_flags = 0;
845  window_flags |= ImGuiWindowFlags_NoTitleBar;
846  window_flags |= ImGuiWindowFlags_NoResize;
847  window_flags |= ImGuiWindowFlags_NoScrollbar;
848  window_flags |= ImGuiWindowFlags_NoNavInputs;
849  SLfloat w = (SLfloat)sv->viewportW();
850  ImVec2 size = ImGui::CalcTextSize(s->info().c_str(),
851  nullptr,
852  true,
853  w);
854  SLfloat h = size.y + SLImGui::fontPropDots * 2.0f;
855  SLstring info = "Scene Info: " + s->info();
856 
857  ImGui::SetNextWindowPos(ImVec2(0, (float)sv->scrH() - h));
858  ImGui::SetNextWindowSize(ImVec2(w, h));
859  ImGui::Begin("Scene Information", &showInfosScene, window_flags);
860  ImGui::SetCursorPosX((w - size.x) * 0.5f);
861  ImGui::TextWrapped("%s", info.c_str());
862  ImGui::End();
863  }
864 
865  if (showTransform)
866  {
867  ImGuiWindowFlags window_flags = 0;
868  window_flags |= ImGuiWindowFlags_AlwaysAutoResize;
869  ImGui::PushFont(ImGui::GetIO().Fonts->Fonts[1]);
870  ImGui::Begin("Transform Selected Node", &showTransform, window_flags);
871 
872  if (s->singleNodeSelected())
873  {
874  SLNode* selNode = s->singleNodeSelected();
875  static SLTransformSpace tSpace = TS_object;
876  SLfloat t1 = 0.1f, t2 = 1.0f, t3 = 10.0f; // Delta translations
877  SLfloat r1 = 1.0f, r2 = 5.0f, r3 = 15.0f; // Delta rotations
878  SLfloat s1 = 1.01f, s2 = 1.1f, s3 = 1.5f; // Scale factors
879 
880  // clang-format off
881  ImGui::Text("Space:");
882  ImGui::SameLine();
883  if (ImGui::RadioButton("World", (int *) &tSpace, 0)) tSpace = TS_world;
884  ImGui::SameLine();
885  if (ImGui::RadioButton("Parent", (int *) &tSpace, 1)) tSpace = TS_parent;
886  ImGui::SameLine();
887  if (ImGui::RadioButton("Object", (int *) &tSpace, 2)) tSpace = TS_object;
888  ImGui::Separator();
889 
890  ImGui::Text("Transl. X :");
891  ImGui::SameLine();
892  if (ImGui::Button("<<<##Tx")) selNode->translate(-t3, 0, 0, tSpace);
893  ImGui::SameLine();
894  if (ImGui::Button("<<##Tx")) selNode->translate(-t2, 0, 0, tSpace);
895  ImGui::SameLine();
896  if (ImGui::Button("<##Tx")) selNode->translate(-t1, 0, 0, tSpace);
897  ImGui::SameLine();
898  if (ImGui::Button(">##Tx")) selNode->translate(t1, 0, 0, tSpace);
899  ImGui::SameLine();
900  if (ImGui::Button(">>##Tx")) selNode->translate(t2, 0, 0, tSpace);
901  ImGui::SameLine();
902  if (ImGui::Button(">>>##Tx")) selNode->translate(t3, 0, 0, tSpace);
903 
904  ImGui::Text("Transl. Y :");
905  ImGui::SameLine();
906  if (ImGui::Button("<<<##Ty")) selNode->translate(0, -t3, 0, tSpace);
907  ImGui::SameLine();
908  if (ImGui::Button("<<##Ty")) selNode->translate(0, -t2, 0, tSpace);
909  ImGui::SameLine();
910  if (ImGui::Button("<##Ty")) selNode->translate(0, -t1, 0, tSpace);
911  ImGui::SameLine();
912  if (ImGui::Button(">##Ty")) selNode->translate(0, t1, 0, tSpace);
913  ImGui::SameLine();
914  if (ImGui::Button(">>##Ty")) selNode->translate(0, t2, 0, tSpace);
915  ImGui::SameLine();
916  if (ImGui::Button(">>>##Ty")) selNode->translate(0, t3, 0, tSpace);
917 
918  ImGui::Text("Transl. Z :");
919  ImGui::SameLine();
920  if (ImGui::Button("<<<##Tz")) selNode->translate(0, 0, -t3, tSpace);
921  ImGui::SameLine();
922  if (ImGui::Button("<<##Tz")) selNode->translate(0, 0, -t2, tSpace);
923  ImGui::SameLine();
924  if (ImGui::Button("<##Tz")) selNode->translate(0, 0, -t1, tSpace);
925  ImGui::SameLine();
926  if (ImGui::Button(">##Tz")) selNode->translate(0, 0, t1, tSpace);
927  ImGui::SameLine();
928  if (ImGui::Button(">>##Tz")) selNode->translate(0, 0, t2, tSpace);
929  ImGui::SameLine();
930  if (ImGui::Button(">>>##Tz")) selNode->translate(0, 0, t3, tSpace);
931 
932  ImGui::Text("Rotation X:");
933  ImGui::SameLine();
934  if (ImGui::Button("<<<##Rx")) selNode->rotate(r3, 1, 0, 0, tSpace);
935  ImGui::SameLine();
936  if (ImGui::Button("<<##Rx")) selNode->rotate(r2, 1, 0, 0, tSpace);
937  ImGui::SameLine();
938  if (ImGui::Button("<##Rx")) selNode->rotate(r1, 1, 0, 0, tSpace);
939  ImGui::SameLine();
940  if (ImGui::Button(">##Rx")) selNode->rotate(-r1, 1, 0, 0, tSpace);
941  ImGui::SameLine();
942  if (ImGui::Button(">>##Rx")) selNode->rotate(-r2, 1, 0, 0, tSpace);
943  ImGui::SameLine();
944  if (ImGui::Button(">>>##Rx")) selNode->rotate(-r3, 1, 0, 0, tSpace);
945 
946  ImGui::Text("Rotation Y:");
947  ImGui::SameLine();
948  if (ImGui::Button("<<<##Ry")) selNode->rotate(r3, 0, 1, 0, tSpace);
949  ImGui::SameLine();
950  if (ImGui::Button("<<##Ry")) selNode->rotate(r2, 0, 1, 0, tSpace);
951  ImGui::SameLine();
952  if (ImGui::Button("<##Ry")) selNode->rotate(r1, 0, 1, 0, tSpace);
953  ImGui::SameLine();
954  if (ImGui::Button(">##Ry")) selNode->rotate(-r1, 0, 1, 0, tSpace);
955  ImGui::SameLine();
956  if (ImGui::Button(">>##Ry")) selNode->rotate(-r2, 0, 1, 0, tSpace);
957  ImGui::SameLine();
958  if (ImGui::Button(">>>##Ry")) selNode->rotate(-r3, 0, 1, 0, tSpace);
959 
960  ImGui::Text("Rotation Z:");
961  ImGui::SameLine();
962  if (ImGui::Button("<<<##Rz")) selNode->rotate(r3, 0, 0, 1, tSpace);
963  ImGui::SameLine();
964  if (ImGui::Button("<<##Rz")) selNode->rotate(r2, 0, 0, 1, tSpace);
965  ImGui::SameLine();
966  if (ImGui::Button("<##Rz")) selNode->rotate(r1, 0, 0, 1, tSpace);
967  ImGui::SameLine();
968  if (ImGui::Button(">##Rz")) selNode->rotate(-r1, 0, 0, 1, tSpace);
969  ImGui::SameLine();
970  if (ImGui::Button(">>##Rz")) selNode->rotate(-r2, 0, 0, 1, tSpace);
971  ImGui::SameLine();
972  if (ImGui::Button(">>>##Rz")) selNode->rotate(-r3, 0, 0, 1, tSpace);
973 
974  ImGui::Text("Scale :");
975  ImGui::SameLine();
976  if (ImGui::Button("<<<##S")) selNode->scale(s3);
977  ImGui::SameLine();
978  if (ImGui::Button("<<##S")) selNode->scale(s2);
979  ImGui::SameLine();
980  if (ImGui::Button("<##S")) selNode->scale(s1);
981  ImGui::SameLine();
982  if (ImGui::Button(">##S")) selNode->scale(-s1);
983  ImGui::SameLine();
984  if (ImGui::Button(">>##S")) selNode->scale(-s2);
985  ImGui::SameLine();
986  if (ImGui::Button(">>>##S")) selNode->scale(-s3);
987  ImGui::Separator();
988  // clang-format on
989 
990  if (ImGui::Button("Reset"))
991  selNode->om(selNode->initialOM());
992  }
993  else
994  {
995  ImGui::Text("No node selected.");
996  ImGui::Text("Please select a node by double clicking it.");
997 
998  if (transformNode)
1000  }
1001  ImGui::End();
1002  ImGui::PopFont();
1003  }
1004 
1005  if (showInfosDevice)
1006  {
1007  SLGLState* stateGL = SLGLState::instance();
1008  SLchar m[2550]; // message character array
1009  m[0] = 0; // set zero length
1010 
1011  snprintf(m + strlen(m), sizeof(m), "SLProject Version: %s\n", AppCommon::version.c_str());
1012 #ifdef _DEBUG
1013  snprintf(m + strlen(m), sizeof(m), "Build Config. : Debug\n");
1014 #else
1015  snprintf(m + strlen(m), sizeof(m), "Build Config. : Release\n");
1016 #endif
1017  snprintf(m + strlen(m), sizeof(m), "-----------------:\n");
1018  snprintf(m + strlen(m), sizeof(m), "Computer User : %s\n", Utils::ComputerInfos::user.c_str());
1019  snprintf(m + strlen(m), sizeof(m), "Computer Name : %s\n", Utils::ComputerInfos::name.c_str());
1020  snprintf(m + strlen(m), sizeof(m), "Computer Brand : %s\n", Utils::ComputerInfos::brand.c_str());
1021  snprintf(m + strlen(m), sizeof(m), "Computer Model : %s\n", Utils::ComputerInfos::model.c_str());
1022  snprintf(m + strlen(m), sizeof(m), "Computer Arch. : %s\n", Utils::ComputerInfos::arch.c_str());
1023  snprintf(m + strlen(m), sizeof(m), "Computer OS : %s\n", Utils::ComputerInfos::os.c_str());
1024  snprintf(m + strlen(m), sizeof(m), "Computer OS Ver. : %s\n", Utils::ComputerInfos::osVer.c_str());
1025  snprintf(m + strlen(m), sizeof(m), "-----------------:\n");
1026  snprintf(m + strlen(m), sizeof(m), "OpenGL Version : %s\n", stateGL->glVersionNO().c_str());
1027  snprintf(m + strlen(m), sizeof(m), "OpenGL Vendor : %s\n", stateGL->glVendor().c_str());
1028  snprintf(m + strlen(m), sizeof(m), "OpenGL Renderer : %s\n", stateGL->glRenderer().c_str());
1029  snprintf(m + strlen(m), sizeof(m), "OpenGL GLSL Ver. : %s\n", stateGL->glSLVersionNO().c_str());
1030  snprintf(m + strlen(m), sizeof(m), "-----------------:\n");
1031  snprintf(m + strlen(m), sizeof(m), "OpenCV Version : %d.%d.%d\n", CV_MAJOR_VERSION, CV_MINOR_VERSION, CV_VERSION_REVISION);
1032  snprintf(m + strlen(m), sizeof(m), "OpenCV has OpenCL: %s\n", cv::ocl::haveOpenCL() ? "yes" : "no");
1033  snprintf(m + strlen(m), sizeof(m), "OpenCV has AVX : %s\n", cv::checkHardwareSupport(CV_AVX) ? "yes" : "no");
1034  snprintf(m + strlen(m), sizeof(m), "OpenCV has NEON : %s\n", cv::checkHardwareSupport(CV_NEON) ? "yes" : "no");
1035  snprintf(m + strlen(m), sizeof(m), "-----------------:\n");
1036 #ifdef SL_BUILD_WAI
1037  snprintf(m + strlen(m), sizeof(m), "Eigen Version : %d.%d.%d\n", EIGEN_WORLD_VERSION, EIGEN_MAJOR_VERSION, EIGEN_MINOR_VERSION);
1038 # ifdef EIGEN_VECTORIZE
1039  snprintf(m + strlen(m), sizeof(m), "Eigen vectorize : yes\n");
1040 # else
1041  snprintf(m + strlen(m), sizeof(m), "Eigen vectorize : no\n");
1042 # endif
1043 #endif
1044  snprintf(m + strlen(m), sizeof(m), "-----------------:\n");
1045  snprintf(m + strlen(m), sizeof(m), "ImGui Version : %s\n", ImGui::GetVersion());
1046 
1047  // Switch to fixed font
1048  ImGui::PushFont(ImGui::GetIO().Fonts->Fonts[1]);
1049  ImGui::Begin("Device Informations", &showInfosDevice, ImGuiWindowFlags_NoResize | ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoNavInputs);
1050  ImGui::TextUnformatted(m);
1051  ImGui::End();
1052  ImGui::PopFont();
1053  }
1054 
1055  if (showInfosSensors)
1056  {
1057  SLchar m[1024]; // message character array
1058  m[0] = 0; // set zero length
1060  snprintf(m + strlen(m), sizeof(m), "Uses IMU Senor : %s\n", AppCommon::devRot.isUsed() ? "yes" : "no");
1061  snprintf(m + strlen(m), sizeof(m), "Pitch (deg) : %3.1f\n", AppCommon::devRot.pitchDEG());
1062  snprintf(m + strlen(m), sizeof(m), "Yaw (deg) : %3.1f\n", AppCommon::devRot.yawDEG());
1063  snprintf(m + strlen(m), sizeof(m), "Roll (deg) : %3.1f\n", AppCommon::devRot.rollDEG());
1064  snprintf(m + strlen(m), sizeof(m), "No. averaged : %d\n", AppCommon::devRot.numAveraged());
1065  // snprintf(m + strlen(m), sizeof(m), "Pitch Offset(deg): %3.1f\n", AppCommon::devRot.pitchOffsetDEG());
1066  // snprintf(m + strlen(m), sizeof(m), "Yaw Offset(deg): %3.1f\n", AppCommon::devRot.yawOffsetDEG());
1067  snprintf(m + strlen(m), sizeof(m), "Rot. Offset mode : %s\n", AppCommon::devRot.offsetModeStr().c_str());
1068  snprintf(m + strlen(m), sizeof(m), "------------------\n");
1069  snprintf(m + strlen(m), sizeof(m), "Uses GPS Sensor : %s\n", AppCommon::devLoc.isUsed() ? "yes" : "no");
1070  snprintf(m + strlen(m), sizeof(m), "Latitude (deg) : %10.5f\n", AppCommon::devLoc.locLatLonAlt().lat);
1071  snprintf(m + strlen(m), sizeof(m), "Longitude (deg) : %10.5f\n", AppCommon::devLoc.locLatLonAlt().lon);
1072  snprintf(m + strlen(m), sizeof(m), "Alt. used (m) : %10.2f\n", AppCommon::devLoc.locLatLonAlt().alt);
1073  snprintf(m + strlen(m), sizeof(m), "Alt. GPS (m) : %10.2f\n", AppCommon::devLoc.altGpsM());
1074  snprintf(m + strlen(m), sizeof(m), "Alt. DEM (m) : %10.2f\n", AppCommon::devLoc.altDemM());
1075  snprintf(m + strlen(m), sizeof(m), "Alt. origin (m) : %10.2f\n", AppCommon::devLoc.altDemM());
1076  snprintf(m + strlen(m), sizeof(m), "Accuracy Rad.(m) : %6.1f\n", AppCommon::devLoc.locAccuracyM());
1077  snprintf(m + strlen(m), sizeof(m), "Dist. Origin (m) : %6.1f\n", offsetToOrigin.length());
1078  snprintf(m + strlen(m), sizeof(m), "Origin improve(s): %6.1f sec.\n", AppCommon::devLoc.improveTime());
1079  snprintf(m + strlen(m), sizeof(m), "Loc. Offset mode : %s\n", AppCommon::devLoc.offsetModeStr().c_str());
1080  snprintf(m + strlen(m), sizeof(m), "Loc. Offset (m) : %s\n", AppCommon::devLoc.offsetENU().toString(",", 1).c_str());
1081 
1082  // Switch to fixed font
1083  ImGui::PushFont(ImGui::GetIO().Fonts->Fonts[1]);
1084  ImGui::Begin("Sensor Information", &showInfosSensors, ImGuiWindowFlags_NoResize | ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoNavInputs);
1085  ImGui::TextUnformatted(m);
1086  ImGui::End();
1087  ImGui::PopFont();
1088  }
1089 
1090  if (showSceneGraph)
1091  {
1092  buildSceneGraph(s);
1093  }
1094 
1095  if (showProperties)
1096  {
1097  buildProperties(s, sv);
1098  }
1099 
1100  if (showUIPrefs)
1101  {
1102  ImGuiWindowFlags window_flags = 0;
1103  window_flags |= ImGuiWindowFlags_AlwaysAutoResize;
1104  window_flags |= ImGuiWindowFlags_NoNavInputs;
1105 
1106  ImGui::PushFont(ImGui::GetIO().Fonts->Fonts[1]);
1107  ImGui::Begin("User Interface Preferences", &showUIPrefs, window_flags);
1108  ImGui::PushItemWidth(ImGui::GetWindowWidth() * 0.66f);
1109 
1110  ImGui::SliderFloat("Prop. Font Size", &SLImGui::fontPropDots, 16.f, 70.f, "%0.0f");
1111  ImGui::SliderFloat("Fixed Font Size", &SLImGui::fontFixedDots, 13.f, 50.f, "%0.0f");
1112  ImGuiStyle& style = ImGui::GetStyle();
1113 
1114  if (ImGui::SliderFloat("Item Spacing X", &style.ItemSpacing.x, 0.0f, 20.0f, "%0.0f"))
1115  style.WindowPadding.x = style.FramePadding.x = style.ItemInnerSpacing.x = style.ItemSpacing.x;
1116 
1117  if (ImGui::SliderFloat("Item Spacing Y", &style.ItemSpacing.y, 0.0f, 20.0f, "%0.0f"))
1118  {
1119  style.FramePadding.y = style.ItemInnerSpacing.y = style.ItemSpacing.y;
1120  style.WindowPadding.y = style.ItemSpacing.y * 3;
1121  }
1122 
1123  ImGui::Separator();
1124 
1125  ImGui::Checkbox("Dock-Space enabled", &showDockSpace);
1126 
1127  ImGui::Separator();
1128 
1129  SLchar reset[255];
1130  snprintf(reset, sizeof(reset), "Reset User Interface (DPI: %d)", sv->dpi());
1131  if (ImGui::MenuItem(reset))
1132  {
1133  SLstring fullPathFilename = AppCommon::configPath + "DemoGui.yml";
1134  Utils::deleteFile(fullPathFilename);
1135  loadConfig(sv->dpi());
1136  }
1137 
1138  ImGui::PopItemWidth();
1139  ImGui::End();
1140  ImGui::PopFont();
1141  }
1142 
1143  if (showDateAndTime)
1144  {
1145  if (AppCommon::devLoc.originLatLonAlt() != SLVec3d::ZERO ||
1146  AppCommon::devLoc.defaultLatLonAlt() != SLVec3d::ZERO)
1147  {
1148  ImGuiWindowFlags window_flags = 0;
1149  window_flags |= ImGuiWindowFlags_AlwaysAutoResize;
1150  window_flags |= ImGuiWindowFlags_NoNavInputs;
1151 
1152  ImGui::PushFont(ImGui::GetIO().Fonts->Fonts[1]);
1153  ImGui::Begin("Date and Time Settings", &showDateAndTime, window_flags);
1154  ImGui::PushItemWidth(ImGui::GetWindowWidth() * 0.66f);
1155 
1156  tm lt{};
1157  if (adjustedTime)
1158  memcpy(&lt, std::localtime(&adjustedTime), sizeof(tm));
1159  else
1160  {
1161  std::time_t now = std::time(nullptr);
1162  memcpy(&lt, std::localtime(&now), sizeof(tm));
1163  }
1164 
1165  SLint month = lt.tm_mon + 1;
1166  if (ImGui::SliderInt("Month", &month, 1, 12))
1167  {
1168  lt.tm_mon = month - 1;
1169  adjustedTime = mktime(&lt);
1171  adjustedTime);
1172  }
1173 
1174  if (ImGui::SliderInt("Day", &lt.tm_mday, 1, 31))
1175  {
1176  adjustedTime = mktime(&lt);
1178  adjustedTime);
1179  }
1180 
1183  SLfloat nowF = (SLfloat)lt.tm_hour + (float)lt.tm_min / 60.0f;
1184  if (ImGui::SliderFloat("Hour", &nowF, SRh, SSh, "%.2f"))
1185  {
1186  lt.tm_hour = (int)nowF;
1187  lt.tm_min = (int)((nowF - floor(nowF)) * 60.0f);
1188  adjustedTime = mktime(&lt);
1190  adjustedTime);
1191  }
1192 
1193  SLchar strTime[100];
1194  std::time_t now = std::time(nullptr);
1195  tm tnow{};
1196  memcpy(&tnow, std::localtime(&now), sizeof(tm));
1197  snprintf(strTime, sizeof(strTime), "Set now (%02d.%02d.%02d %02d:%02d)", tnow.tm_mday, tnow.tm_mon + 1, tnow.tm_year + 1900, tnow.tm_hour, tnow.tm_min);
1198  if (ImGui::MenuItem(strTime))
1199  {
1200  adjustedTime = 0;
1201  memcpy(&lt, std::localtime(&now), sizeof(tm));
1203  }
1204 
1205  snprintf(strTime, sizeof(strTime), "Set highest noon (21.07.%02d 12:00)", lt.tm_year - 100);
1206  if (ImGui::MenuItem(strTime))
1207  {
1208  lt.tm_mon = 6;
1209  lt.tm_mday = 21;
1210  lt.tm_hour = 12;
1211  lt.tm_min = 0;
1212  lt.tm_sec = 0;
1213  adjustedTime = mktime(&lt);
1215  adjustedTime);
1216  }
1217 
1218  snprintf(strTime, sizeof(strTime), "Set lowest noon (21.12.%02d 12:00)", lt.tm_year - 100);
1219  if (ImGui::MenuItem(strTime))
1220  {
1221  lt.tm_mon = 11;
1222  lt.tm_mday = 21;
1223  lt.tm_hour = 12;
1224  lt.tm_min = 0;
1225  lt.tm_sec = 0;
1226  adjustedTime = mktime(&lt);
1228  adjustedTime);
1229  }
1230 
1231  SLNode* sunLightNode = AppCommon::devLoc.sunLightNode();
1232  if (sunLightNode &&
1233  typeid(*sunLightNode) == typeid(SLLightDirect) &&
1234  ((SLLightDirect*)sunLightNode)->doSunPowerAdaptation())
1235  {
1236  SLLight* light = (SLLight*)(SLLightDirect*)sunLightNode;
1237  float aP = light->ambientPower();
1238  float dP = light->diffusePower();
1239  float sum_aPdP = aP + dP;
1240  float ambiFraction = aP / sum_aPdP;
1241  ImGui::Separator();
1242  if (ImGui::SliderFloat("Direct-Indirect", &ambiFraction, 0.0f, 1.0f, "%.2f"))
1243  {
1244  light->ambientPower(ambiFraction * sum_aPdP);
1245  light->diffusePower((1.0f - ambiFraction) * sum_aPdP);
1246  }
1247  }
1248 
1249  ImGui::PopItemWidth();
1250  ImGui::End();
1251  ImGui::PopFont();
1252  }
1253  else
1254  showDateAndTime = false;
1255  }
1256 
1257  if (showErlebAR)
1258  {
1259  ImGui::PushFont(ImGui::GetIO().Fonts->Fonts[1]);
1260  SLint namedLocIndex = AppCommon::devLoc.activeNamedLocation();
1261  SLVec3f lookAtPoint = SLVec3f::ZERO;
1262 
1264  {
1265  ImGui::Begin("Christoffel",
1266  &showErlebAR,
1267  ImGuiWindowFlags_NoResize | ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoNavInputs);
1268 
1269  // Get scene nodes once
1270  if (!bern)
1271  {
1272  bern = s->root3D()->findChild<SLNode>("bern-christoffel.gltf");
1273  chrAlt = bern->findChild<SLNode>("Chr-Alt", true);
1274  chrNeu = bern->findChild<SLNode>("Chr-Neu", true);
1275  balda_stahl = bern->findChild<SLNode>("Baldachin-Stahl", true);
1276  balda_glas = bern->findChild<SLNode>("Baldachin-Glas", true);
1277  }
1278 
1279  SLbool chrAltIsOn = !chrAlt->drawBits()->get(SL_DB_HIDDEN);
1280  if (ImGui::Checkbox("Christoffelturm 1500-1800", &chrAltIsOn))
1281  {
1282  chrAlt->drawBits()->set(SL_DB_HIDDEN, false);
1283  chrNeu->drawBits()->set(SL_DB_HIDDEN, true);
1284  }
1285 
1286  SLbool chrNeuIsOn = !chrNeu->drawBits()->get(SL_DB_HIDDEN);
1287  if (ImGui::Checkbox("Christoffelturm 1800-1865", &chrNeuIsOn))
1288  {
1289  chrAlt->drawBits()->set(SL_DB_HIDDEN, true);
1290  chrNeu->drawBits()->set(SL_DB_HIDDEN, false);
1291  }
1292  SLbool baldachin = !balda_stahl->drawBits()->get(SL_DB_HIDDEN);
1293  if (ImGui::Checkbox("Baldachin", &baldachin))
1294  {
1295  balda_stahl->drawBits()->set(SL_DB_HIDDEN, !baldachin);
1296  balda_glas->drawBits()->set(SL_DB_HIDDEN, !baldachin);
1297  }
1298 
1299  ImGui::Separator();
1300 
1301 #if defined(SL_OS_MACIOS) || defined(SL_OS_ANDROID)
1302  bool devLocIsUsed = AppCommon::devLoc.isUsed();
1303  if (ImGui::Checkbox("Use GPS Location", &devLocIsUsed))
1304  AppCommon::devLoc.isUsed(true);
1305 #endif
1306  lookAtPoint.set(-21, 18, 6);
1307  for (int i = 1; i < AppCommon::devLoc.nameLocations().size(); ++i)
1308  {
1309  bool namedLocIsActive = namedLocIndex == i;
1310  if (ImGui::Checkbox(AppCommon::devLoc.nameLocations()[i].name.c_str(), &namedLocIsActive))
1311  setActiveNamedLocation(i, sv, lookAtPoint);
1312  }
1313 
1314  ImGui::End();
1315  }
1316  else
1317  {
1318  bern = nullptr;
1319  chrAlt = nullptr;
1320  chrNeu = nullptr;
1321  balda_stahl = nullptr;
1322  balda_glas = nullptr;
1323  }
1325  {
1326  ImGui::Begin("Biel Campus Biel/Bienne",
1327  &showErlebAR,
1328  ImGuiWindowFlags_NoResize | ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoNavInputs);
1329 
1330 #if defined(SL_OS_MACIOS) || defined(SL_OS_ANDROID)
1331  bool devLocIsUsed = AppCommon::devLoc.isUsed();
1332  if (ImGui::Checkbox("Use GPS Location", &devLocIsUsed))
1333  AppCommon::devLoc.isUsed(true);
1334 #endif
1335  for (int i = 1; i < AppCommon::devLoc.nameLocations().size(); ++i)
1336  {
1337  bool namedLocIsActive = namedLocIndex == i;
1338  if (ImGui::Checkbox(AppCommon::devLoc.nameLocations()[i].name.c_str(), &namedLocIsActive))
1340  }
1341 
1342  ImGui::End();
1343  }
1345  {
1346  ImGui::Begin("Augst-Theatre-Temple",
1347  &showErlebAR,
1348  ImGuiWindowFlags_NoResize | ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoNavInputs);
1349 
1350 #if defined(SL_OS_MACIOS) || defined(SL_OS_ANDROID)
1351  bool devLocIsUsed = AppCommon::devLoc.isUsed();
1352  if (ImGui::Checkbox("Use GPS Location", &devLocIsUsed))
1353  AppCommon::devLoc.isUsed(true);
1354 #endif
1355  for (int i = 1; i < AppCommon::devLoc.nameLocations().size(); ++i)
1356  {
1357  bool namedLocIsActive = namedLocIndex == i;
1358  if (ImGui::Checkbox(AppCommon::devLoc.nameLocations()[i].name.c_str(), &namedLocIsActive))
1360  }
1361 
1362  ImGui::End();
1363  }
1365  {
1366  ImGui::Begin("Avenche-Amphitheatre",
1367  &showErlebAR,
1368  ImGuiWindowFlags_NoResize | ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoNavInputs);
1369 
1370 #if defined(SL_OS_MACIOS) || defined(SL_OS_ANDROID)
1371  bool devLocIsUsed = AppCommon::devLoc.isUsed();
1372  if (ImGui::Checkbox("Use GPS Location", &devLocIsUsed))
1373  AppCommon::devLoc.isUsed(true);
1374 #endif
1375  for (int i = 1; i < AppCommon::devLoc.nameLocations().size(); ++i)
1376  {
1377  bool namedLocIsActive = namedLocIndex == i;
1378  if (ImGui::Checkbox(AppCommon::devLoc.nameLocations()[i].name.c_str(), &namedLocIsActive))
1380  }
1381 
1382  ImGui::End();
1383  }
1385  {
1386  ImGui::Begin("Avenche-Cigognier",
1387  &showErlebAR,
1388  ImGuiWindowFlags_NoResize | ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoNavInputs);
1389 
1390 #if defined(SL_OS_MACIOS) || defined(SL_OS_ANDROID)
1391  bool devLocIsUsed = AppCommon::devLoc.isUsed();
1392  if (ImGui::Checkbox("Use GPS Location", &devLocIsUsed))
1393  AppCommon::devLoc.isUsed(true);
1394 #endif
1395  for (int i = 1; i < AppCommon::devLoc.nameLocations().size(); ++i)
1396  {
1397  bool namedLocIsActive = namedLocIndex == i;
1398  if (ImGui::Checkbox(AppCommon::devLoc.nameLocations()[i].name.c_str(), &namedLocIsActive))
1399  setActiveNamedLocation(i, sv, lookAtPoint);
1400  }
1401  ImGui::End();
1402  }
1404  {
1405  ImGui::Begin("Avenche-Theatre",
1406  &showErlebAR,
1407  ImGuiWindowFlags_NoResize | ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoNavInputs);
1408 
1409 #if defined(SL_OS_MACIOS) || defined(SL_OS_ANDROID)
1410  bool devLocIsUsed = AppCommon::devLoc.isUsed();
1411  if (ImGui::Checkbox("Use GPS Location", &devLocIsUsed))
1412  AppCommon::devLoc.isUsed(true);
1413 #endif
1414  for (int i = 1; i < AppCommon::devLoc.nameLocations().size(); ++i)
1415  {
1416  bool namedLocIsActive = namedLocIndex == i;
1417  if (ImGui::Checkbox(AppCommon::devLoc.nameLocations()[i].name.c_str(), &namedLocIsActive))
1419  }
1420 
1421  ImGui::End();
1422  }
1424  {
1425  ImGui::Begin("Sutz-Kirchrain18",
1426  &showErlebAR,
1427  ImGuiWindowFlags_NoResize | ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoNavInputs);
1428 
1429 #if defined(SL_OS_MACIOS) || defined(SL_OS_ANDROID)
1430  bool devLocIsUsed = AppCommon::devLoc.isUsed();
1431  if (ImGui::Checkbox("Use GPS Location", &devLocIsUsed))
1432  AppCommon::devLoc.isUsed(true);
1433 #endif
1434  for (int i = 1; i < AppCommon::devLoc.nameLocations().size(); ++i)
1435  {
1436  bool namedLocIsActive = namedLocIndex == i;
1437  if (ImGui::Checkbox(AppCommon::devLoc.nameLocations()[i].name.c_str(), &namedLocIsActive))
1439  }
1440 
1441  ImGui::End();
1442  }
1443 
1444  ImGui::PopFont();
1445  }
1446  }
1447  }
1448 }
1449 
1450 //-----------------------------------------------------------------------------
1452  bool mirroredV,
1453  CVCameraType camType)
1454 {
1455 #ifndef SL_EMSCRIPTEN
1456  // Try to read device lens and sensor information
1457  string strF = AppCommon::deviceParameter["DeviceLensFocalLength"];
1458  string strW = AppCommon::deviceParameter["DeviceSensorPhysicalSizeW"];
1459  string strH = AppCommon::deviceParameter["DeviceSensorPhysicalSizeH"];
1460  if (!strF.empty() && !strW.empty() && !strH.empty())
1461  {
1462  float devF = strF.empty() ? 0.0f : stof(strF);
1463  float devW = strW.empty() ? 0.0f : stof(strW);
1464  float devH = strH.empty() ? 0.0f : stof(strH);
1465 
1466  // Changes the state to CS_guessed
1467  return CVCalibration(devW,
1468  devH,
1469  devF,
1470  cv::Size(CVCapture::instance()->lastFrame.cols,
1471  CVCapture::instance()->lastFrame.rows),
1472  mirroredH,
1473  mirroredV,
1474  camType,
1476  }
1477  else
1478  {
1479  // make a guess using frame size and a guessed field of view
1480  return CVCalibration(cv::Size(CVCapture::instance()->lastFrame.cols,
1481  CVCapture::instance()->lastFrame.rows),
1482  60.0,
1483  mirroredH,
1484  mirroredV,
1485  camType,
1487  }
1488 #else
1489  return CVCalibration(cv::Size(0, 0),
1490  60.0,
1491  mirroredH,
1492  mirroredV,
1493  camType,
1495 #endif
1496 }
1497 
1498 //-----------------------------------------------------------------------------
1499 //! Builds the entire menu bar once per frame
1501 {
1502  PROFILE_FUNCTION();
1503 
1504  // assert(s->assetManager() && "No asset manager assigned to scene!");
1506 
1508  SLGLState* stateGL = SLGLState::instance();
1509  CVCapture* capture = CVCapture::instance();
1510  SLRenderType rType = sv->renderType();
1511  SLbool hasAnimations = (!s->animManager().animationNames().empty());
1512  static SLint curAnimIx = -1;
1513  if (!hasAnimations) curAnimIx = -1;
1514 
1515  // Remove transform node if no or the wrong one is selected
1518 
1519  if (ImGui::BeginMainMenuBar())
1520  {
1521  if (ImGui::BeginMenu("File"))
1522  {
1523  if (ImGui::BeginMenu("Load Test Scene"))
1524  {
1525  if (ImGui::BeginMenu("General"))
1526  {
1527  if (ImGui::MenuItem("Minimal Scene", nullptr, sid == SID_Minimal))
1529  if (ImGui::MenuItem("Figure Scene", nullptr, sid == SID_Figure))
1531  if (ImGui::MenuItem("Mesh Loader", nullptr, sid == SID_MeshLoad))
1533  if (ImGui::MenuItem("Revolver Meshes", nullptr, sid == SID_Revolver))
1535  if (ImGui::MenuItem("Texture Blending", nullptr, sid == SID_TextureBlend))
1537  if (ImGui::MenuItem("Texture Filters", nullptr, sid == SID_TextureFilter))
1539 #ifdef SL_BUILD_WITH_KTX
1540  if (ImGui::MenuItem("Texture Compression", nullptr, sid == SID_TextureCompression))
1542 #endif
1543  if (ImGui::MenuItem("Frustum Culling", nullptr, sid == SID_FrustumCull))
1545  if (ImGui::MenuItem("2D and 3D Text", nullptr, sid == SID_2Dand3DText))
1547  if (ImGui::MenuItem("Point Clouds", nullptr, sid == SID_PointClouds))
1549  if (ImGui::MenuItem("Z-Fighting", nullptr, sid == SID_ZFighting))
1551 
1552  ImGui::EndMenu();
1553  }
1554 
1555  if (ImGui::BeginMenu("Shader"))
1556  {
1557  if (ImGui::MenuItem("Per Vertex Blinn-Phong", nullptr, sid == SID_ShaderPerVertexBlinn))
1559  if (ImGui::MenuItem("Per Pixel Blinn-Phong", nullptr, sid == SID_ShaderPerPixelBlinn))
1561  if (ImGui::MenuItem("Per Pixel Cook-Torrance", nullptr, sid == SID_ShaderPerPixelCook))
1563  if (ImGui::MenuItem("Image Based Lighting", nullptr, sid == SID_ShaderIBL))
1565  if (ImGui::MenuItem("Per Vertex Wave", nullptr, sid == SID_ShaderWave))
1567  if (ImGui::MenuItem("Bump Mapping", nullptr, sid == SID_ShaderBumpNormal))
1569  if (ImGui::MenuItem("Parallax Mapping", nullptr, sid == SID_ShaderBumpParallax))
1571  if (ImGui::MenuItem("Skybox Shader", nullptr, sid == SID_ShaderSkybox))
1573  if (ImGui::MenuItem("Earth Shader", nullptr, sid == SID_ShaderEarth))
1575  ImGui::EndMenu();
1576  }
1577 
1578  if (ImGui::BeginMenu("Shadow Mapping"))
1579  {
1580  if (ImGui::MenuItem("Basic Scene", nullptr, sid == SID_ShadowMappingBasicScene))
1582  if (ImGui::MenuItem("Light Types", nullptr, sid == SID_ShadowMappingLightTypes))
1584  if (ImGui::MenuItem("8 Spot Lights", nullptr, sid == SID_ShadowMappingSpotLights))
1586  if (ImGui::MenuItem("3 Point Lights", nullptr, sid == SID_ShadowMappingPointLights))
1588  if (ImGui::MenuItem("RT Soft Shadows", nullptr, sid == SID_RTSoftShadows))
1590  if (ImGui::MenuItem("Cascaded Shadows", nullptr, sid == SID_ShadowMappingCascaded))
1592  if (ImGui::MenuItem("Columns with Cascaded Sh.", nullptr, sid == SID_Benchmark_ColumnsLOD))
1594 
1595  ImGui::EndMenu();
1596  }
1597 
1598  if (ImGui::BeginMenu("Suzanne Lighting"))
1599  {
1600  if (ImGui::MenuItem("w. per Pixel Lighting (PL)", nullptr, sid == SID_SuzannePerPixBlinn))
1602  if (ImGui::MenuItem("w. PL and Texture Mapping (TM)", nullptr, sid == SID_SuzannePerPixBlinnTm))
1604  if (ImGui::MenuItem("w. PL and Normal Mapping (NM)", nullptr, sid == SID_SuzannePerPixBlinnNm))
1606  if (ImGui::MenuItem("w. PL and Ambient Occlusion (AO)", nullptr, sid == SID_SuzannePerPixBlinnAo))
1608  if (ImGui::MenuItem("w. PL and Shadow Mapping (SM)", nullptr, sid == SID_SuzannePerPixBlinnSm))
1610  if (ImGui::MenuItem("w. PL, TM, NM", nullptr, sid == SID_SuzannePerPixBlinnTmNm))
1612  if (ImGui::MenuItem("w. PL, TM, AO", nullptr, sid == SID_SuzannePerPixBlinnTmAo))
1614  if (ImGui::MenuItem("w. PL, NM, AO", nullptr, sid == SID_SuzannePerPixBlinnNmAo))
1616  if (ImGui::MenuItem("w. PL, NM, SM", nullptr, sid == SID_SuzannePerPixBlinnNmSm))
1618  if (ImGui::MenuItem("w. PL, TM, SM", nullptr, sid == SID_SuzannePerPixBlinnTmSm))
1620  if (ImGui::MenuItem("w. PL, AO, SM", nullptr, sid == SID_SuzannePerPixBlinnAoSm))
1622  if (ImGui::MenuItem("w. PL, TM, NM, AO", nullptr, sid == SID_SuzannePerPixBlinnTmNmAo))
1624  if (ImGui::MenuItem("w. PL, TM, NM, SM", nullptr, sid == SID_SuzannePerPixBlinnTmNmSm))
1626  if (ImGui::MenuItem("w. PL, TM, NM, AO, SM", nullptr, sid == SID_SuzannePerPixBlinnTmNmAoSm))
1628  if (ImGui::MenuItem("w. PL, TM, NM, AO, SM, EM", nullptr, sid == SID_SuzannePerPixCookTmNmAoSmEm))
1630  ImGui::EndMenu();
1631  }
1632 
1633  if (ImGui::BeginMenu("glTF Sample Models"))
1634  {
1635  SLstring zip = "glTF-Sample-Models.zip";
1636 
1637  if (ImGui::MenuItem("Damaged Helmet", nullptr, sid == SID_glTF_DamagedHelmet))
1639  if (ImGui::MenuItem("Flight Helmet", nullptr, sid == SID_glTF_FlightHelmet))
1641  if (ImGui::MenuItem("Sponza Palace", nullptr, sid == SID_glTF_Sponza))
1643  if (ImGui::MenuItem("Water Bottle", nullptr, sid == SID_glTF_WaterBottle))
1645 
1646  ImGui::EndMenu();
1647  }
1648 
1649  if (ImGui::BeginMenu("Robotics"))
1650  {
1651  SLstring zip = "GLTF-FanucCRX.zip";
1652 
1653  if (ImGui::MenuItem("Fanuc-CRX", nullptr, sid == SID_Robotics_FanucCRX_FK))
1655 
1656  ImGui::EndMenu();
1657  }
1658 
1659  if (ImGui::BeginMenu("Volume Rendering"))
1660  {
1661  if (ImGui::MenuItem("Head MRI Ray Cast", nullptr, sid == SID_VolumeRayCast))
1663  if (ImGui::MenuItem("Head MRI Ray Cast Lighted", nullptr, sid == SID_VolumeRayCastLighted))
1665  /*
1666  {
1667  auto loadMRIImages = []() {
1668  AppCommon::jobProgressMsg("Load MRI Images");
1669  AppCommon::jobProgressMax(100);
1670 
1671  // Load volume data into 3D texture
1672  SLVstring mriImages;
1673  for (SLint i = 0; i < 207; ++i)
1674  mriImages.push_back(AppCommon::texturePath + Utils::formatString("i%04u_0000b.png", i));
1675 
1676  gTexMRI3D = new SLGLTexture(nullptr,
1677  mriImages,
1678  GL_LINEAR,
1679  GL_LINEAR,
1680 #ifndef SL_EMSCRIPTEN
1681  0x812D, // GL_CLAMP_TO_BORDER (GLSL 320)
1682  0x812D, // GL_CLAMP_TO_BORDER (GLSL 320)
1683 #else
1684  GL_CLAMP_TO_EDGE,
1685  GL_CLAMP_TO_EDGE,
1686 #endif
1687  "mri_head_front_to_back",
1688  true);
1689  AppCommon::jobIsRunning = false;
1690  };
1691 
1692  auto calculateGradients = []() {
1693  AppCommon::jobProgressMsg("Calculate MRI Volume Gradients");
1694  AppCommon::jobProgressMax(100);
1695  gTexMRI3D->calc3DGradients(1,
1696  [](int progress) { AppCommon::jobProgressNum(progress); });
1697  AppCommon::jobIsRunning = false;
1698  };
1699 
1700  auto smoothGradients = []() {
1701  AppCommon::jobProgressMsg("Smooth MRI Volume Gradients");
1702  AppCommon::jobProgressMax(100);
1703  gTexMRI3D->smooth3DGradients(1,
1704  [](int progress) { AppCommon::jobProgressNum(progress); });
1705  AppCommon::jobIsRunning = false;
1706  };
1707 
1708  auto followUpJob1 = [](SLAssetManager* am, SLScene* s, SLSceneView* sv) {
1709  AppCommon::sceneToLoad = SID_VolumeRayCastLighted;
1710  };
1711  function<void(void)> onLoadScene = bind(followUpJob1, am, s, sv);
1712 
1713  AppCommon::jobsToBeThreaded.emplace_back(loadMRIImages);
1714  AppCommon::jobsToBeThreaded.emplace_back(calculateGradients);
1715  // AppCommon::jobsToBeThreaded.emplace_back(smoothGradients); // very slow
1716  AppCommon::jobsToFollowInMain.push_back(onLoadScene);
1717  }
1718  */
1719  ImGui::EndMenu();
1720  }
1721 
1722  if (ImGui::BeginMenu("Animation"))
1723  {
1724  if (ImGui::MenuItem("Node Animation", nullptr, sid == SID_AnimationNode))
1726  if (ImGui::MenuItem("Mass Node Animation", nullptr, sid == SID_AnimationNodeMass))
1728  if (ImGui::MenuItem("Skinned Animation", nullptr, sid == SID_AnimationSkinned))
1730  if (ImGui::MenuItem("Mass Skinned Animation", nullptr, sid == SID_AnimationSkinnedMass))
1732  if (ImGui::MenuItem("Fanuc-CRX", nullptr, sid == SID_Robotics_FanucCRX_FK))
1734 
1735  ImGui::EndMenu();
1736  }
1737 
1738  if (ImGui::BeginMenu("Video"))
1739  {
1740  if (ImGui::MenuItem("Texture from Video Live", nullptr, sid == SID_VideoTextureLive))
1742 #ifndef SL_EMSCRIPTEN
1743  if (ImGui::MenuItem("Texture from Video File", nullptr, sid == SID_VideoTextureFile))
1745 #endif
1746  if (ImGui::MenuItem("Track ArUco Marker (Main)", nullptr, sid == SID_VideoTrackArucoMain))
1748  if (ImGui::MenuItem("Track ArUco Marker (Scnd)", nullptr, sid == SID_VideoTrackArucoScnd, capture->hasSecondaryCamera))
1750  if (ImGui::MenuItem("Track Chessboard (Main)", nullptr, sid == SID_VideoTrackChessMain))
1752  if (ImGui::MenuItem("Track Chessboard (Scnd)", nullptr, sid == SID_VideoTrackChessScnd, capture->hasSecondaryCamera))
1754  if (ImGui::MenuItem("Track Features (Main)", nullptr, sid == SID_VideoTrackFeature2DMain))
1756 #ifndef SL_EMSCRIPTEN
1757  if (ImGui::MenuItem("Track Face (Main)", nullptr, sid == SID_VideoTrackFaceMain))
1759  if (ImGui::MenuItem("Track Face (Scnd)", nullptr, sid == SID_VideoTrackFaceScnd, capture->hasSecondaryCamera))
1761 #endif
1762 #ifdef SL_BUILD_WITH_MEDIAPIPE
1763  if (ImGui::MenuItem("Track Hands w. Mediapipe (Main)", nullptr, sid == SID_VideoTrackMediaPipeHandsMain))
1765 #endif
1766  if (ImGui::MenuItem("Sensor AR (Main)", nullptr, sid == SID_VideoSensorAR))
1768 #ifdef SL_BUILD_WAI
1769  if (ImGui::MenuItem("Track WAI (Main)", nullptr, sid == SID_VideoTrackWAI))
1771 #endif
1772  ImGui::EndMenu();
1773  }
1774 
1775  if (ImGui::BeginMenu("Ray Tracing"))
1776  {
1777  if (ImGui::MenuItem("Spheres", nullptr, sid == SID_RTSpheres))
1779  if (ImGui::MenuItem("Muttenzer Box", nullptr, sid == SID_RTMuttenzerBox))
1781  if (ImGui::MenuItem("Soft Shadows", nullptr, sid == SID_RTSoftShadows))
1783  if (ImGui::MenuItem("Depth of Field", nullptr, sid == SID_RTDoF))
1785  if (ImGui::MenuItem("Lens Test", nullptr, sid == SID_RTLens))
1787 
1788  ImGui::EndMenu();
1789  }
1790 
1791  if (ImGui::BeginMenu("Path Tracing"))
1792  {
1793  if (ImGui::MenuItem("Muttenzer Box", nullptr, sid == SID_RTMuttenzerBox))
1795 
1796  ImGui::EndMenu();
1797  }
1798 
1799  if (ImGui::BeginMenu("Particle Systems"))
1800  {
1801  if (ImGui::MenuItem("First Particle System", nullptr, sid == SID_ParticleSystem_Simple))
1803  if (ImGui::MenuItem("Dust Storm Particle System", nullptr, sid == SID_ParticleSystem_DustStorm))
1805  if (ImGui::MenuItem("Fountain Particle System", nullptr, sid == SID_ParticleSystem_Fountain))
1807  if (ImGui::MenuItem("Sun Particle System", nullptr, sid == SID_ParticleSystem_Sun))
1809  if (ImGui::MenuItem("Ring of Fire Particle System", nullptr, sid == SID_ParticleSystem_RingOfFire))
1811  if (ImGui::MenuItem("Complex Fire Particle System", nullptr, sid == SID_ParticleSystem_ComplexFire))
1813  if (ImGui::MenuItem("Particle system w. 1 mio. particles", nullptr, sid == SID_ParticleSystem_Many))
1815 
1816  ImGui::EndMenu();
1817  }
1818 
1819  // Download content from pallas/home/private/projects/2020.Erleb-AR/erleb-AR-data/productive/models_for_SLProject
1820  // and copy it into AppCommon::dataPath + "erleb-AR/models/
1821  // This data is copyright protected and can only be accessed with user and password
1822  SLstring erlebarPath = AppCommon::dataPath + "erleb-AR/models/";
1823  SLstring modelBR2 = erlebarPath + "bern/bern-christoffel.gltf";
1824  SLstring modelBFH = erlebarPath + "biel/Biel-BFH-Rolex.gltf";
1825  SLstring modelCBB = erlebarPath + "biel/Biel-CBB-AR.gltf";
1826  SLstring modelAR1 = erlebarPath + "augst/augst-thtL1-tmpL2.gltf";
1827  SLstring modelAR2 = erlebarPath + "augst/augst-thtL2-tmpL1.gltf";
1828  SLstring modelAR3 = erlebarPath + "augst/augst-thtL1L2-tmpL1L2.gltf";
1829  SLstring modelAV1_AO = erlebarPath + "avenches/avenches-amphitheater.gltf";
1830  SLstring modelAV2_AO = erlebarPath + "avenches/avenches-cigognier.gltf";
1831  SLstring modelAV3 = erlebarPath + "avenches/avenches-theater.gltf";
1832  SLstring modelSU1 = erlebarPath + "sutz/Sutz-Kirchrain18.gltf";
1833 
1834  if (Utils::fileExists(modelAR1) ||
1835  Utils::fileExists(modelAR2) ||
1836  Utils::fileExists(modelAR3) ||
1837  Utils::fileExists(modelAV3) ||
1838  Utils::fileExists(modelBR2) ||
1839  Utils::fileExists(modelCBB) ||
1840  Utils::fileExists(modelSU1))
1841  {
1842  if (ImGui::BeginMenu("Erleb-AR"))
1843  {
1844  if (Utils::fileExists(modelBR2))
1845  if (ImGui::MenuItem("Bern: Christoffel Tower", nullptr, sid == SID_ErlebAR_BernChristoffel))
1847 
1848  if (Utils::fileExists(modelBFH))
1849  if (ImGui::MenuItem("Biel: BFH", nullptr, sid == SID_ErlebAR_BielBFH))
1851 
1852  if (Utils::fileExists(modelCBB))
1853  if (ImGui::MenuItem("Biel: CBB", nullptr, sid == SID_ErlebAR_BielCBB))
1855 
1856  if (Utils::fileExists(modelAR3))
1857  if (ImGui::MenuItem("Augusta Raurica Temple & Theater", nullptr, sid == SID_ErlebAR_AugustaRauricaTmpTht))
1859 
1860  if (Utils::fileExists(modelAV1_AO))
1861  if (ImGui::MenuItem("Aventicum: Amphitheatre", nullptr, sid == SID_ErlebAR_AventicumAmphiteatre))
1863 
1864  if (Utils::fileExists(modelAV2_AO))
1865  if (ImGui::MenuItem("Aventicum: Cigognier", nullptr, sid == SID_ErlebAR_AventicumCigognier))
1867 
1868  if (Utils::fileExists(modelAV3))
1869  if (ImGui::MenuItem("Aventicum: Theatre", nullptr, sid == SID_ErlebAR_AventicumTheatre))
1871 
1872  if (Utils::fileExists(modelSU1))
1873  if (ImGui::MenuItem("Sutz: Kirchrain 18", nullptr, sid == SID_ErlebAR_SutzKirchrain18))
1875 
1876  ImGui::EndMenu();
1877  }
1878  }
1879 
1880  if (ImGui::BeginMenu("Benchmarks"))
1881  {
1882 #ifndef SL_EMSCRIPTEN
1883  /* The large models are too large for emscripten
1884  if (ImGui::MenuItem("Large Model (via FTP)", nullptr, sid == SID_Benchmark_LargeModel))
1885  {
1886  SLstring largeFile = AppCommon::configPath + "models/xyzrgb_dragon/xyzrgb_dragon.ply";
1887  if (Utils::fileExists(largeFile))
1888  AppCommon::sceneToLoad = SID_Benchmark_LargeModel;
1889  else
1890  {
1891  auto downloadJobFTP = []() {
1892  AppCommon::jobProgressMsg("Downloading large dragon file via FTP:");
1893  AppCommon::jobProgressMax(100);
1894  ftplib ftp;
1895  ftp.SetConnmode(ftplib::connmode::port); // enable active mode
1896 
1897  if (ftp.Connect("pallas.ti.bfh.ch:21"))
1898  {
1899  if (ftp.Login("guest", "g2Q7Z7OkDP4!"))
1900  {
1901  ftp.SetCallbackXferFunction(ftpCallbackXfer);
1902  ftp.SetCallbackBytes(1024000);
1903  if (ftp.Chdir("data/SLProject/models"))
1904  {
1905  int remoteSize = 0;
1906  ftp.Size("xyzrgb_dragon.zip",
1907  &remoteSize,
1908  ftplib::transfermode::image);
1909  ftpXferSizeMax = remoteSize;
1910  SLstring dstDir = AppCommon::configPath;
1911  if (Utils::dirExists(dstDir))
1912  {
1913  SLstring outFile = AppCommon::configPath + "models/xyzrgb_dragon.zip";
1914  if (!ftp.Get(outFile.c_str(),
1915  "xyzrgb_dragon.zip",
1916  ftplib::transfermode::image))
1917  SL_LOG("*** ERROR: ftp.Get failed. ***");
1918  }
1919  else
1920  SL_LOG("*** ERROR: Destination directory does not exist: %s ***", dstDir.c_str());
1921  }
1922  else
1923  SL_LOG("*** ERROR: ftp.Chdir failed. ***");
1924  }
1925  else
1926  SL_LOG("*** ERROR: ftp.Login failed. ***");
1927  }
1928  else
1929  SL_LOG("*** ERROR: ftp.Connect failed. ***");
1930 
1931  ftp.Quit();
1932  AppCommon::jobIsRunning = false;
1933  };
1934 
1935  auto unzipJob = [largeFile]() {
1936  AppCommon::jobProgressMsg("Decompress dragon file:");
1937  AppCommon::jobProgressMax(-1);
1938  string zipFile = AppCommon::configPath + "models/xyzrgb_dragon.zip";
1939  if (Utils::fileExists(zipFile))
1940  {
1941  ZipUtils::unzip(zipFile, Utils::getPath(zipFile));
1942  Utils::deleteFile(zipFile);
1943  }
1944  AppCommon::jobIsRunning = false;
1945  };
1946 
1947  auto followUpJob1 = [am, s, sv, largeFile]() {
1948  if (Utils::fileExists(largeFile))
1949  AppCommon::sceneToLoad = SID_Benchmark_LargeModel;
1950  };
1951 
1952  AppCommon::jobsToBeThreaded.emplace_back(downloadJobFTP);
1953  AppCommon::jobsToBeThreaded.emplace_back(unzipJob);
1954  AppCommon::jobsToFollowInMain.emplace_back(followUpJob1);
1955  }
1956  }
1957  if (ImGui::MenuItem("Large Model (via HTTPS)", nullptr, sid == SID_Benchmark_LargeModel))
1958  {
1959  SLstring largeFile = AppCommon::configPath + "models/xyzrgb_dragon/xyzrgb_dragon.ply";
1960  loadSceneWithLargeModel(s, sv, "xyzrgb_dragon.zip", largeFile, SID_Benchmark_LargeModel);
1961  }*/
1962 #endif
1963  if (ImGui::MenuItem("Large Model", nullptr, sid == SID_Benchmark_LargeModel))
1965  if (ImGui::MenuItem("Massive Nodes", nullptr, sid == SID_Benchmark_LotsOfNodes))
1967  if (ImGui::MenuItem("Massive Node Animations", nullptr, sid == SID_Benchmark_NodeAnimations))
1969  if (ImGui::MenuItem("Jan's Universe", nullptr, sid == SID_Benchmark_JansUniverse))
1971  if (ImGui::MenuItem("Massive Skinned Animations", nullptr, sid == SID_Benchmark_SkinnedAnimations))
1973  if (ImGui::MenuItem("Columns without LOD", nullptr, sid == SID_Benchmark_ColumnsNoLOD))
1975  if (ImGui::MenuItem("Columns with LOD", nullptr, sid == SID_Benchmark_ColumnsLOD))
1977  if (ImGui::MenuItem("Particle System lot of fire complex", nullptr, sid == SID_Benchmark_ParticleSystemComplexFire))
1979  if (ImGui::MenuItem("Particle System w. 1 mio. particle", nullptr, sid == SID_ParticleSystem_Many))
1981  ImGui::EndMenu();
1982  }
1983 
1984  ImGui::EndMenu();
1985  }
1986 
1987  if (ImGui::MenuItem("Empty Scene", "Shift-Alt-0", sid == SID_Empty))
1989 
1990  if (ImGui::MenuItem("Next Scene",
1991  "Shift-Alt->",
1992  nullptr,
1995 
1996  if (ImGui::MenuItem("Previous Scene",
1997  "Shift-Alt-<",
1998  nullptr,
2001 
2002 #ifndef SL_EMSCRIPTEN
2003  ImGui::Separator();
2004 
2005  if (ImGui::MenuItem("Multi-threaded Jobs"))
2006  {
2007  auto job1 = []()
2008  {
2009  PROFILE_THREAD("Worker Thread 1");
2010  PROFILE_SCOPE("Parallel Job 1");
2011 
2012  uint maxIter = 100000;
2013  AppCommon::jobProgressMsg("Super long job 1");
2015  for (uint i = 0; i < maxIter; ++i)
2016  {
2017  SL_LOG("%u", i);
2018  int progressPC = (int)((float)i / (float)maxIter * 100.0f);
2019  AppCommon::jobProgressNum(progressPC);
2020  }
2021  AppCommon::jobIsRunning = false;
2022  };
2023 
2024  auto job2 = []()
2025  {
2026  PROFILE_THREAD("Worker Thread 2");
2027  PROFILE_SCOPE("Parallel Job 2");
2028 
2029  uint maxIter = 100000;
2030  AppCommon::jobProgressMsg("Super long job 2");
2032  for (uint i = 0; i < maxIter; ++i)
2033  {
2034  SL_LOG("%u", i);
2035  int progressPC = (int)((float)i / (float)maxIter * 100.0f);
2036  AppCommon::jobProgressNum(progressPC);
2037  }
2038  AppCommon::jobIsRunning = false;
2039  };
2040 
2041  auto followUpJob1 = []()
2042  { SL_LOG("followUpJob1"); };
2043  auto jobToFollow2 = []()
2044  { SL_LOG("JobToFollow2"); };
2045 
2046  AppCommon::jobsToBeThreaded.emplace_back(job1);
2047  AppCommon::jobsToBeThreaded.emplace_back(job2);
2048  AppCommon::jobsToFollowInMain.emplace_back(followUpJob1);
2049  AppCommon::jobsToFollowInMain.emplace_back(jobToFollow2);
2050  }
2051 #endif
2052 
2053 #if !defined(SL_OS_ANDROID) && !defined(SL_EMSCRIPTEN)
2054  ImGui::Separator();
2055 
2056  if (ImGui::MenuItem("Quit & Save"))
2057  slShouldClose(true);
2058 #endif
2059 
2060  ImGui::EndMenu();
2061  }
2062 
2063  if (ImGui::BeginMenu("Preferences"))
2064  {
2065  if (ImGui::MenuItem("Do Wait on Idle", "I", sv->doWaitOnIdle()))
2067 
2068  if (ImGui::MenuItem("Do Multi Sampling", "L", sv->doMultiSampling()))
2070 
2071  if (ImGui::MenuItem("Do Frustum Culling", "F", sv->doFrustumCulling()))
2073 
2074  if (ImGui::MenuItem("Do Alpha Sorting", "J", sv->doAlphaSorting()))
2076 
2077  if (ImGui::MenuItem("Do Depth Test", "T", sv->doDepthTest()))
2078  sv->doDepthTest(!sv->doDepthTest());
2079 
2080  if (ImGui::MenuItem("Animation off", "Space", s->stopAnimations()))
2082 
2083  ImGui::Separator();
2084 
2085  if (ImGui::BeginMenu("Viewport Aspect"))
2086  {
2087  SLVec2i videoAspect(0, 0);
2088  if (capture->videoType() != VT_NONE)
2089  {
2090  videoAspect.x = capture->captureSize.width;
2091  videoAspect.y = capture->captureSize.height;
2092  }
2093  SLchar strSameAsVideo[256];
2094  snprintf(strSameAsVideo, sizeof(strSameAsVideo), "Same as Video (%d:%d)", videoAspect.x, videoAspect.y);
2095 
2096  if (ImGui::MenuItem("Same as window", nullptr, sv->viewportRatio() == SLVec2i::ZERO))
2097  sv->setViewportFromRatio(SLVec2i(0, 0), sv->viewportAlign(), false);
2098  if (ImGui::MenuItem(strSameAsVideo, nullptr, sv->viewportSameAsVideo()))
2099  sv->setViewportFromRatio(videoAspect, sv->viewportAlign(), true);
2100  if (ImGui::MenuItem("16:9", nullptr, sv->viewportRatio() == SLVec2i(16, 9)))
2101  sv->setViewportFromRatio(SLVec2i(16, 9), sv->viewportAlign(), false);
2102  if (ImGui::MenuItem("4:3", nullptr, sv->viewportRatio() == SLVec2i(4, 3)))
2103  sv->setViewportFromRatio(SLVec2i(4, 3), sv->viewportAlign(), false);
2104  if (ImGui::MenuItem("2:1", nullptr, sv->viewportRatio() == SLVec2i(2, 1)))
2105  sv->setViewportFromRatio(SLVec2i(2, 1), sv->viewportAlign(), false);
2106  if (ImGui::MenuItem("1:1", nullptr, sv->viewportRatio() == SLVec2i(1, 1)))
2107  sv->setViewportFromRatio(SLVec2i(1, 1), sv->viewportAlign(), false);
2108 
2109  if (ImGui::BeginMenu("Alignment", sv->viewportRatio() != SLVec2i::ZERO))
2110  {
2111  if (ImGui::MenuItem("Center", nullptr, sv->viewportAlign() == VA_center))
2113  if (ImGui::MenuItem("Left or bottom", nullptr, sv->viewportAlign() == VA_leftOrBottom))
2115 
2116  ImGui::EndMenu();
2117  }
2118  ImGui::EndMenu();
2119  }
2120 
2121  ImGui::Separator();
2122 
2123  // Rotation and Location Sensor
2124 #if defined(SL_OS_ANDROID) || defined(SL_OS_MACIOS)
2125  if (ImGui::BeginMenu("Rotation Sensor"))
2126  {
2128 
2129  if (ImGui::MenuItem("Use Device Rotation (IMU)", nullptr, devRot.isUsed()))
2130  devRot.isUsed(!AppCommon::devRot.isUsed());
2131 
2132  if (devRot.isUsed())
2133  {
2134  SLint numAveraged = devRot.numAveraged();
2135  if (ImGui::SliderInt("Average length", &numAveraged, 1, 10))
2136  devRot.numAveraged(numAveraged);
2137 
2138  if (ImGui::BeginMenu("Offset Mode"))
2139  {
2140  SLRotOffsetMode om = devRot.offsetMode();
2141  if (ImGui::MenuItem("None", nullptr, om == ROM_none))
2142  devRot.offsetMode(ROM_none);
2143  if (ImGui::MenuItem("Finger rot. X", nullptr, om == ROM_oneFingerX))
2144  devRot.offsetMode(ROM_oneFingerX);
2145  if (ImGui::MenuItem("Finger rot. X and Y", nullptr, om == ROM_oneFingerXY))
2146  devRot.offsetMode(ROM_oneFingerXY);
2147 
2148  ImGui::EndMenu();
2149  }
2150 
2151  if (ImGui::MenuItem("Zero Yaw at Start", nullptr, devRot.zeroYawAtStart()))
2152  devRot.zeroYawAtStart(!devRot.zeroYawAtStart());
2153 
2154  if (ImGui::MenuItem("Reset Zero Yaw"))
2155  devRot.hasStarted(true);
2156 
2157  if (ImGui::MenuItem("Show Horizon", nullptr, _horizonVisuEnabled))
2158  {
2159  if (_horizonVisuEnabled)
2160  hideHorizon(s);
2161  else
2162  showHorizon(s, sv);
2163  }
2164  }
2165 
2166  ImGui::EndMenu();
2167  }
2168 
2169  if (ImGui::BeginMenu("Location Sensor"))
2170  {
2172 
2173  if (ImGui::MenuItem("Use Device Location (GPS)", nullptr, AppCommon::devLoc.isUsed()))
2175 
2176  if (!AppCommon::devLoc.geoTiffIsAvailableAndValid())
2177  if (ImGui::MenuItem("Use Origin Altitude", nullptr, AppCommon::devLoc.useOriginAltitude()))
2179 
2180  if (ImGui::MenuItem("Reset Origin to here"))
2182 
2183  if (ImGui::BeginMenu("Offset Mode"))
2184  {
2185  SLLocOffsetMode om = devLoc.offsetMode();
2186  if (ImGui::MenuItem("None", nullptr, om == LOM_none))
2187  devLoc.offsetMode(LOM_none);
2188  if (ImGui::MenuItem("Two Finger Y", nullptr, om == LOM_twoFingerY))
2189  devLoc.offsetMode(LOM_twoFingerY);
2190 
2191  ImGui::EndMenu();
2192  }
2193 
2194  ImGui::EndMenu();
2195  }
2196 #endif
2197 
2198  if (ImGui::BeginMenu("Video Sensor"))
2199  {
2200  CVCamera* ac = capture->activeCamera;
2201  if (ImGui::BeginMenu("Mirror Camera"))
2202  {
2203  if (ImGui::MenuItem("Horizontally", nullptr, ac->mirrorH()))
2204  {
2205  ac->toggleMirrorH();
2206  // make a guessed calibration, if there was a calibrated camera it is not valid anymore
2207  ac->calibration = guessCalibration(ac->mirrorH(), ac->mirrorV(), ac->type());
2208  }
2209 
2210  if (ImGui::MenuItem("Vertically", nullptr, ac->mirrorV()))
2211  {
2212  ac->toggleMirrorV();
2213  // make a guessed calibration, if there was a calibrated camera it is not valid anymore
2214  ac->calibration = guessCalibration(ac->mirrorH(), ac->mirrorV(), ac->type());
2215  }
2216 
2217  ImGui::EndMenu();
2218  }
2219 
2220  if (ImGui::BeginMenu("Resolution",
2221  (capture->videoType() == VT_MAIN ||
2222  capture->videoType() == VT_SCND)))
2223  {
2224  for (int i = 0; i < (int)capture->camSizes.size(); ++i)
2225  {
2226  SLchar menuStr[256];
2227  snprintf(menuStr,
2228  sizeof(menuStr),
2229  "%d x %d",
2230  capture->camSizes[(uint)i].width,
2231  capture->camSizes[(uint)i].height);
2232  if (ImGui::MenuItem(menuStr, nullptr, i == capture->activeCamSizeIndex))
2233  if (i != capture->activeCamSizeIndex)
2234  ac->camSizeIndex(i);
2235  }
2236  ImGui::EndMenu();
2237  }
2238 
2239 #ifndef SL_EMSCRIPTEN
2240  if (ImGui::BeginMenu("Calibration"))
2241  {
2242  if (ImGui::MenuItem("Start Calibration (Main Camera)"))
2243  {
2245  showHelpCalibration = false;
2246  showInfosScene = true;
2247  }
2248 
2249  if (ImGui::MenuItem("Start Calibration (Scnd. Camera)", nullptr, false, capture->hasSecondaryCamera))
2250  {
2252  showHelpCalibration = false;
2253  showInfosScene = true;
2254  }
2255 
2256  if (ImGui::MenuItem("Undistort Image", nullptr, ac->showUndistorted(), ac->calibration.state() == CS_calibrated))
2257  ac->showUndistorted(!ac->showUndistorted());
2258 
2259  if (ImGui::MenuItem("No Tangent Distortion", nullptr, AppCommon::calibrationEstimatorParams.zeroTangentDistortion))
2261 
2262  if (ImGui::MenuItem("Fix Aspect Ratio", nullptr, AppCommon::calibrationEstimatorParams.fixAspectRatio))
2264 
2265  if (ImGui::MenuItem("Fix Principal Point", nullptr, AppCommon::calibrationEstimatorParams.fixPrincipalPoint))
2267 
2268  if (ImGui::MenuItem("Use rational model", nullptr, AppCommon::calibrationEstimatorParams.calibRationalModel))
2270 
2271  if (ImGui::MenuItem("Use tilted model", nullptr, AppCommon::calibrationEstimatorParams.calibTiltedModel))
2273 
2274  if (ImGui::MenuItem("Use thin prism model", nullptr, AppCommon::calibrationEstimatorParams.calibThinPrismModel))
2276 
2277  ImGui::EndMenu();
2278  }
2279 
2280  CVTrackedFeatures* featureTracker = nullptr;
2281  if (gVideoTracker != nullptr && typeid(*gVideoTracker) == typeid(CVTrackedFeatures))
2282  featureTracker = (CVTrackedFeatures*)gVideoTracker;
2283 
2284  if (gVideoTracker != nullptr)
2285  if (ImGui::MenuItem("Draw Detection", nullptr, gVideoTracker->drawDetection()))
2287 
2288  if (ImGui::BeginMenu("Feature Tracking", featureTracker != nullptr) && featureTracker != nullptr)
2289  {
2290  if (ImGui::MenuItem("Force Relocation", nullptr, featureTracker->forceRelocation()))
2291  featureTracker->forceRelocation(!featureTracker->forceRelocation());
2292 
2293  if (ImGui::BeginMenu("Detector/Descriptor", featureTracker != nullptr))
2294  {
2295  CVDetectDescribeType type = featureTracker->type();
2296 
2297  if (ImGui::MenuItem("RAUL/RAUL", nullptr, type == DDT_RAUL_RAUL))
2298  featureTracker->type(DDT_RAUL_RAUL);
2299  if (ImGui::MenuItem("ORB/ORB", nullptr, type == DDT_ORB_ORB))
2300  featureTracker->type(DDT_ORB_ORB);
2301  if (ImGui::MenuItem("FAST/BRIEF", nullptr, type == DDT_FAST_BRIEF))
2302  featureTracker->type(DDT_FAST_BRIEF);
2303  if (ImGui::MenuItem("SURF/SURF", nullptr, type == DDT_SURF_SURF))
2304  featureTracker->type(DDT_SURF_SURF);
2305  if (ImGui::MenuItem("SIFT/SIFT", nullptr, type == DDT_SIFT_SIFT))
2306  featureTracker->type(DDT_SIFT_SIFT);
2307 
2308  ImGui::EndMenu();
2309  }
2310 
2311  ImGui::EndMenu();
2312  }
2313 #endif
2314 
2315  ImGui::EndMenu();
2316  }
2317 
2318  ImGui::Separator();
2319 
2320  ImGui::MenuItem("UI Preferences", nullptr, &showUIPrefs);
2321 
2322  ImGui::EndMenu();
2323  }
2324 
2325  if (ImGui::BeginMenu("Edit", s->singleNodeSelected() != nullptr || !sv->camera()->selectRect().isZero()))
2326  {
2327  if (s->singleNodeSelected())
2328  {
2329  buildMenuEdit(s, sv);
2330  }
2331  else
2332  {
2333  if (ImGui::MenuItem("Clear selection"))
2334  {
2335  sv->camera()->selectRect().setZero();
2336  sv->camera()->deselectRect().setZero();
2337  }
2338  }
2339 
2340  ImGui::EndMenu();
2341  }
2342 
2343  if (ImGui::BeginMenu("Renderer"))
2344  {
2345  if (ImGui::MenuItem("OpenGL", "ESC", rType == RT_gl))
2346  sv->renderType(RT_gl);
2347 
2348  if (ImGui::MenuItem("Ray Tracing", "R", rType == RT_rt))
2349  sv->startRaytracing(5);
2350 
2351  if (ImGui::MenuItem("Path Tracing", "P", rType == RT_pt))
2352  sv->startPathtracing(5, 10);
2353 
2354 #ifdef SL_HAS_OPTIX
2355  if (ImGui::MenuItem("Ray Tracing with OptiX", "Shift-R", rType == RT_optix_rt))
2356  sv->startOptixRaytracing(5);
2357 
2358  if (ImGui::MenuItem("Path Tracing with OptiX", "Shift-P", rType == RT_optix_pt))
2359  sv->startOptixPathtracing(5, 10);
2360 #else
2361  ImGui::MenuItem("Ray Tracing with OptiX", nullptr, false, false);
2362  ImGui::MenuItem("Path Tracing with OptiX", nullptr, false, false);
2363 #endif
2364  ImGui::EndMenu();
2365  }
2366 
2367  if (rType == RT_gl)
2368  {
2369  if (ImGui::BeginMenu("GL"))
2370  {
2371  if (ImGui::MenuItem("Mesh Wired", "M", sv->drawBits()->get(SL_DB_MESHWIRED)))
2373 
2374  if (ImGui::MenuItem("With hard edges", "H", sv->drawBits()->get(SL_DB_WITHEDGES)))
2376 
2377  if (ImGui::MenuItem("Only hard edges", "O", sv->drawBits()->get(SL_DB_ONLYEDGES)))
2379 
2380  if (ImGui::MenuItem("Normals", "N", sv->drawBits()->get(SL_DB_NORMALS)))
2382 
2383  if (ImGui::MenuItem("Bounding Rectangles", "U", sv->drawBits()->get(SL_DB_BRECT)))
2385 
2386  if (ImGui::MenuItem("Bounding Boxes", "B", sv->drawBits()->get(SL_DB_BBOX)))
2388 
2389  if (ImGui::MenuItem("Voxels", "V", sv->drawBits()->get(SL_DB_VOXELS)))
2391 
2392  if (ImGui::MenuItem("Axis", "X", sv->drawBits()->get(SL_DB_AXIS)))
2394 
2395  if (ImGui::MenuItem("Back Faces", "C", sv->drawBits()->get(SL_DB_CULLOFF)))
2397 
2398  if (ImGui::MenuItem("Skeleton", "K", sv->drawBits()->get(SL_DB_SKELETON)))
2400 
2401  if (ImGui::MenuItem("GPU Skinning", nullptr, sv->drawBits()->get(SL_DB_GPU_SKINNING)))
2403 
2404  if (ImGui::MenuItem("All off"))
2405  sv->drawBits()->allOff();
2406 
2407  if (ImGui::MenuItem("All on"))
2408  {
2412  sv->drawBits()->on(SL_DB_NORMALS);
2413  sv->drawBits()->on(SL_DB_VOXELS);
2414  sv->drawBits()->on(SL_DB_AXIS);
2415  sv->drawBits()->on(SL_DB_BBOX);
2417  sv->drawBits()->on(SL_DB_CULLOFF);
2419  }
2420 
2421  ImGui::PushItemWidth(ImGui::GetWindowWidth() * 0.65f);
2422  SLfloat gamma = SLLight::gamma;
2423  if (ImGui::SliderFloat("Gamma", &gamma, 0.1f, 3.0f, "%.1f"))
2424  SLLight::gamma = gamma;
2425  ImGui::PopItemWidth();
2426 
2427  ImGui::EndMenu();
2428  }
2429  }
2430  else if (rType == RT_rt)
2431  {
2432  if (ImGui::BeginMenu("RT"))
2433  {
2434  SLRaytracer* rt = sv->raytracer();
2435 
2436  if (ImGui::BeginMenu("Resolution Factor"))
2437  {
2438  if (ImGui::MenuItem("1.00", nullptr, rt->resolutionFactorPC() == 100))
2439  {
2440  rt->resolutionFactor(1.0f);
2441  sv->startRaytracing(rt->maxDepth());
2442  }
2443  if (ImGui::MenuItem("0.50", nullptr, rt->resolutionFactorPC() == 50))
2444  {
2445  rt->resolutionFactor(0.5f);
2446  sv->startRaytracing(rt->maxDepth());
2447  }
2448  if (ImGui::MenuItem("0.25", nullptr, rt->resolutionFactorPC() == 25))
2449  {
2450  rt->resolutionFactor(0.25f);
2451  sv->startRaytracing(rt->maxDepth());
2452  }
2453 
2454  ImGui::EndMenu();
2455  }
2456 
2457  if (ImGui::MenuItem("Parallel distributed", nullptr, rt->doDistributed()))
2458  {
2459  rt->doDistributed(!rt->doDistributed());
2460  sv->startRaytracing(rt->maxDepth());
2461  }
2462 
2463  if (ImGui::MenuItem("Continuously", nullptr, rt->doContinuous()))
2464  {
2465  rt->doContinuous(!rt->doContinuous());
2466  sv->doWaitOnIdle(!rt->doContinuous());
2467  }
2468 
2469  if (ImGui::MenuItem("Fresnel Reflection", nullptr, rt->doFresnel()))
2470  {
2471  rt->doFresnel(!rt->doFresnel());
2472  sv->startRaytracing(rt->maxDepth());
2473  }
2474 
2475  if (ImGui::BeginMenu("Max. Depth"))
2476  {
2477  if (ImGui::MenuItem("1", nullptr, rt->maxDepth() == 1)) sv->startRaytracing(1);
2478  if (ImGui::MenuItem("2", nullptr, rt->maxDepth() == 2)) sv->startRaytracing(2);
2479  if (ImGui::MenuItem("3", nullptr, rt->maxDepth() == 3)) sv->startRaytracing(3);
2480  if (ImGui::MenuItem("5", nullptr, rt->maxDepth() == 5)) sv->startRaytracing(5);
2481  if (ImGui::MenuItem("Max. Contribution", nullptr, rt->maxDepth() == 0)) sv->startRaytracing(0);
2482 
2483  ImGui::EndMenu();
2484  }
2485 
2486  if (ImGui::BeginMenu("Anti-Aliasing Samples"))
2487  {
2488  if (ImGui::MenuItem("Off", nullptr, rt->aaSamples() == 1)) rt->aaSamples(1);
2489  if (ImGui::MenuItem("3x3", nullptr, rt->aaSamples() == 3)) rt->aaSamples(3);
2490  if (ImGui::MenuItem("5x5", nullptr, rt->aaSamples() == 5)) rt->aaSamples(5);
2491  if (ImGui::MenuItem("7x7", nullptr, rt->aaSamples() == 7)) rt->aaSamples(7);
2492  if (ImGui::MenuItem("9x9", nullptr, rt->aaSamples() == 9)) rt->aaSamples(9);
2493 
2494  ImGui::EndMenu();
2495  }
2496 
2497  if (ImGui::MenuItem("Save Rendered Image"))
2498  rt->saveImage();
2499 
2500  ImGui::PushItemWidth(ImGui::GetWindowWidth() * 0.65f);
2501  SLfloat gamma = rt->gamma();
2502  if (ImGui::SliderFloat("Gamma", &gamma, 0.1f, 3.0f, "%.1f"))
2503  {
2504  rt->gamma(gamma);
2505  sv->startRaytracing(5);
2506  }
2507  ImGui::PopItemWidth();
2508 
2509  ImGui::EndMenu();
2510  }
2511  }
2512 
2513 #ifdef SL_HAS_OPTIX
2514  else if (rType == RT_optix_rt)
2515  {
2516  if (ImGui::BeginMenu("RT"))
2517  {
2518  SLOptixRaytracer* rt_optix = sv->optixRaytracer();
2519 
2520  if (ImGui::MenuItem("Parallel distributed", nullptr, rt_optix->doDistributed()))
2521  {
2522  rt_optix->doDistributed(!rt_optix->doDistributed());
2523  sv->startOptixRaytracing(rt_optix->maxDepth());
2524  }
2525 
2526  // if (ImGui::MenuItem("Fresnel Reflection", nullptr, rt->doFresnel()))
2527  // {
2528  // rt->doFresnel(!rt->doFresnel());
2529  // sv->startRaytracing(rt->maxDepth());
2530  // }
2531 
2532  if (ImGui::BeginMenu("Max. Depth"))
2533  {
2534  if (ImGui::MenuItem("1", nullptr, rt_optix->maxDepth() == 1))
2535  sv->startOptixRaytracing(1);
2536  if (ImGui::MenuItem("2", nullptr, rt_optix->maxDepth() == 2))
2537  sv->startOptixRaytracing(2);
2538  if (ImGui::MenuItem("3", nullptr, rt_optix->maxDepth() == 3))
2539  sv->startOptixRaytracing(3);
2540  if (ImGui::MenuItem("5", nullptr, rt_optix->maxDepth() == 5))
2541  sv->startOptixRaytracing(5);
2542  if (ImGui::MenuItem("Max. Contribution", nullptr, rt_optix->maxDepth() == 0))
2543  sv->startOptixRaytracing(0);
2544 
2545  ImGui::EndMenu();
2546  }
2547 
2548  // if (ImGui::BeginMenu("Anti-Aliasing Samples"))
2549  // {
2550  // if (ImGui::MenuItem("Off", nullptr, rt->aaSamples() == 1))
2551  // rt->aaSamples(1);
2552  // if (ImGui::MenuItem("3x3", nullptr, rt->aaSamples() == 3))
2553  // rt->aaSamples(3);
2554  // if (ImGui::MenuItem("5x5", nullptr, rt->aaSamples() == 5))
2555  // rt->aaSamples(5);
2556  // if (ImGui::MenuItem("7x7", nullptr, rt->aaSamples() == 7))
2557  // rt->aaSamples(7);
2558  // if (ImGui::MenuItem("9x9", nullptr, rt->aaSamples() == 9))
2559  // rt->aaSamples(9);
2560  //
2561  // ImGui::EndMenu();
2562  // }
2563 
2564  if (ImGui::MenuItem("Save Rendered Image"))
2565  rt_optix->saveImage();
2566 
2567  ImGui::EndMenu();
2568  }
2569  }
2570 #endif
2571  else if (rType == RT_pt)
2572  {
2573  if (ImGui::BeginMenu("PT"))
2574  {
2575  SLPathtracer* pt = sv->pathtracer();
2576 
2577  if (ImGui::BeginMenu("Resolution Factor"))
2578  {
2579  if (ImGui::MenuItem("1.00", nullptr, pt->resolutionFactorPC() == 100))
2580  {
2581  pt->resolutionFactor(1.0f);
2582  sv->startPathtracing(5, pt->aaSamples());
2583  }
2584  if (ImGui::MenuItem("0.50", nullptr, pt->resolutionFactorPC() == 50))
2585  {
2586  pt->resolutionFactor(0.5f);
2587  sv->startPathtracing(5, pt->aaSamples());
2588  }
2589  if (ImGui::MenuItem("0.25", nullptr, pt->resolutionFactorPC() == 25))
2590  {
2591  pt->resolutionFactor(0.25f);
2592  sv->startPathtracing(5, pt->aaSamples());
2593  }
2594 
2595  ImGui::EndMenu();
2596  }
2597 
2598  if (ImGui::BeginMenu("NO. of Samples"))
2599  {
2600  if (ImGui::MenuItem("1", nullptr, pt->aaSamples() == 1)) sv->startPathtracing(5, 1);
2601  if (ImGui::MenuItem("10", nullptr, pt->aaSamples() == 10)) sv->startPathtracing(5, 10);
2602  if (ImGui::MenuItem("100", nullptr, pt->aaSamples() == 100)) sv->startPathtracing(5, 100);
2603  if (ImGui::MenuItem("1000", nullptr, pt->aaSamples() == 1000)) sv->startPathtracing(5, 1000);
2604  if (ImGui::MenuItem("10000", nullptr, pt->aaSamples() == 10000)) sv->startPathtracing(5, 10000);
2605 
2606  ImGui::EndMenu();
2607  }
2608 
2609  if (ImGui::MenuItem("Direct illumination", nullptr, pt->calcDirect()))
2610  {
2611  pt->calcDirect(!pt->calcDirect());
2612  sv->startPathtracing(5, 10);
2613  }
2614 
2615  if (ImGui::MenuItem("Indirect illumination", nullptr, pt->calcIndirect()))
2616  {
2617  pt->calcIndirect(!pt->calcIndirect());
2618  sv->startPathtracing(5, 10);
2619  }
2620 
2621  if (ImGui::MenuItem("Save Rendered Image"))
2622  pt->saveImage();
2623 
2624  ImGui::PushItemWidth(ImGui::GetWindowWidth() * 0.65f);
2625  SLfloat gamma = pt->gamma();
2626  if (ImGui::SliderFloat("Gamma", &gamma, 0.1f, 3.0f, "%.1f"))
2627  {
2628  pt->gamma(gamma);
2629  sv->startPathtracing(5, 1);
2630  }
2631  ImGui::PopItemWidth();
2632 
2633  ImGui::EndMenu();
2634  }
2635  }
2636 
2637 #ifdef SL_HAS_OPTIX
2638  else if (rType == RT_optix_pt)
2639  {
2640  if (ImGui::BeginMenu("PT"))
2641  {
2642  SLOptixPathtracer* pt = sv->optixPathtracer();
2643 
2644  if (ImGui::BeginMenu("NO. of Samples"))
2645  {
2646  if (ImGui::MenuItem("1", nullptr, pt->samples() == 1))
2647  sv->startOptixPathtracing(5, 1);
2648  if (ImGui::MenuItem("10", nullptr, pt->samples() == 10))
2649  sv->startOptixPathtracing(5, 10);
2650  if (ImGui::MenuItem("100", nullptr, pt->samples() == 100))
2651  sv->startOptixPathtracing(5, 100);
2652  if (ImGui::MenuItem("1000", nullptr, pt->samples() == 1000))
2653  sv->startOptixPathtracing(5, 1000);
2654  if (ImGui::MenuItem("10000", nullptr, pt->samples() == 10000))
2655  sv->startOptixPathtracing(5, 10000);
2656 
2657  ImGui::EndMenu();
2658  }
2659 
2660  if (ImGui::MenuItem("Denoiser", nullptr, pt->getDenoiserEnabled()))
2661  {
2662  pt->setDenoiserEnabled(!pt->getDenoiserEnabled());
2663  sv->startOptixPathtracing(5, pt->samples());
2664  }
2665 
2666  if (ImGui::MenuItem("Save Rendered Image"))
2667  pt->saveImage();
2668 
2669  ImGui::EndMenu();
2670  }
2671  }
2672 #endif
2673 
2674  if (ImGui::BeginMenu("Camera"))
2675  {
2676  SLCamera* cam = sv->camera();
2677  SLProjType proj = cam->projType();
2678 
2679  if (ImGui::MenuItem("Reset"))
2680  {
2681  cam->resetToInitialState();
2682  float dist = cam->translationOS().length();
2683  cam->focalDist(dist);
2684  }
2685 
2686  if (ImGui::BeginMenu("Look from"))
2687  {
2688  if (ImGui::MenuItem("Left (+X)", "3")) cam->lookFrom(SLVec3f::AXISX);
2689  if (ImGui::MenuItem("Right (-X)", "CTRL-3")) cam->lookFrom(-SLVec3f::AXISX);
2690  if (ImGui::MenuItem("Top (+Y)", "7")) cam->lookFrom(SLVec3f::AXISY, -SLVec3f::AXISZ);
2691  if (ImGui::MenuItem("Bottom (-Y)", "CTRL-7")) cam->lookFrom(-SLVec3f::AXISY, SLVec3f::AXISZ);
2692  if (ImGui::MenuItem("Front (+Z)", "1")) cam->lookFrom(SLVec3f::AXISZ);
2693  if (ImGui::MenuItem("Back (-Z)", "CTRL-1")) cam->lookFrom(-SLVec3f::AXISZ);
2694 
2695  if (s->numSceneCameras())
2696  {
2697  if (ImGui::MenuItem("Next camera in Scene", "TAB"))
2699 
2700  if (ImGui::MenuItem("Sceneview Camera", "TAB"))
2702  }
2703 
2704  ImGui::EndMenu();
2705  }
2706 
2707  if (ImGui::BeginMenu("Projection"))
2708  {
2709  static SLfloat clipN = cam->clipNear();
2710  static SLfloat clipF = cam->clipFar();
2711  static SLfloat focalDist = cam->focalDist();
2712  static SLfloat fov = cam->fovV();
2713 
2714  ImGui::PushItemWidth(ImGui::GetWindowWidth() * 0.66f);
2715 
2716  if (ImGui::MenuItem("Perspective", "5", proj == P_monoPerspective))
2717  {
2719  if (sv->renderType() == RT_rt && !sv->raytracer()->doContinuous() &&
2720  sv->raytracer()->state() == rtFinished)
2721  sv->raytracer()->state(rtReady);
2722  }
2723 
2724  if (ImGui::MenuItem("Orthographic", "5", proj == P_monoOrthographic))
2725  {
2727  if (sv->renderType() == RT_rt && !sv->raytracer()->doContinuous() &&
2728  sv->raytracer()->state() == rtFinished)
2729  sv->raytracer()->state(rtReady);
2730  }
2731 
2732  if (ImGui::BeginMenu("Stereo"))
2733  {
2734  for (SLint p = P_stereoSideBySide; p <= P_stereoColorYB; ++p)
2735  {
2737  if (ImGui::MenuItem(pStr.c_str(), nullptr, proj == (SLProjType)p))
2738  cam->projType((SLProjType)p);
2739  }
2740 
2741  if (proj >= P_stereoSideBySide)
2742  {
2743  ImGui::Separator();
2744  static SLfloat eyeSepar = cam->stereoEyeSeparation();
2745  if (ImGui::SliderFloat("Eye Sep.", &eyeSepar, 0.0f, focalDist / 10.f))
2746  cam->stereoEyeSeparation(eyeSepar);
2747  }
2748 
2749  ImGui::EndMenu();
2750  }
2751 
2752  ImGui::Separator();
2753 
2754  if (ImGui::SliderFloat("FOV (V)", &fov, 1.f, 179.f))
2755  cam->fov(fov);
2756 
2757  ImGui::Text("FOV (H): %3.1f ", cam->fovH());
2758 
2759  if (ImGui::SliderFloat("Near Clip", &clipN, 0.001f, 10.f))
2760  cam->clipNear(clipN);
2761 
2762  if (ImGui::SliderFloat("Focal Dist.", &focalDist, clipN, clipF))
2763  cam->focalDist(focalDist);
2764 
2765  if (ImGui::SliderFloat("Far Clip", &clipF, clipN, std::min(clipF * 1.1f, 1000000.f)))
2766  cam->clipFar(clipF);
2767 
2768  ImGui::PopItemWidth();
2769  ImGui::EndMenu();
2770  }
2771 
2772  if (ImGui::BeginMenu("Animation"))
2773  {
2774  SLCamAnim ca = cam->camAnim();
2775 
2776  ImGui::PushItemWidth(ImGui::GetWindowWidth() * 0.66f);
2777 
2778  if (ImGui::MenuItem("Turntable Y up", nullptr, ca == CA_turntableYUp))
2779  sv->camera()->camAnim(CA_turntableYUp);
2780 
2781  if (ImGui::MenuItem("Turntable Z up", nullptr, ca == CA_turntableZUp))
2782  sv->camera()->camAnim(CA_turntableZUp);
2783 
2784  if (ImGui::MenuItem("Trackball", nullptr, ca == CA_trackball))
2785  sv->camera()->camAnim(CA_trackball);
2786 
2787  if (ImGui::MenuItem("Walk Y up", nullptr, ca == CA_walkingYUp))
2788  sv->camera()->camAnim(CA_walkingYUp);
2789 
2790  if (ImGui::MenuItem("Walk Z up", nullptr, ca == CA_walkingZUp))
2791  sv->camera()->camAnim(CA_walkingZUp);
2792 
2793  float mouseRotFactor = sv->camera()->mouseRotationFactor();
2794  if (ImGui::SliderFloat("Mouse Sensibility", &mouseRotFactor, 0.1f, 2.0f, "%2.1f"))
2795  sv->camera()->mouseRotationFactor(mouseRotFactor);
2796 
2797  ImGui::Separator();
2798 
2799  if (ImGui::MenuItem("IMU rotated", nullptr, ca == CA_deviceRotYUp))
2800  sv->camera()->camAnim(CA_deviceRotYUp);
2801 
2802  if (ImGui::MenuItem("IMU rotated & GPS located", nullptr, ca == CA_deviceRotLocYUp))
2803  sv->camera()->camAnim(CA_deviceRotLocYUp);
2804 
2805  if (ca == CA_walkingZUp || ca == CA_walkingYUp || ca == CA_deviceRotYUp)
2806  {
2807  static SLfloat ms = cam->maxSpeed();
2808  if (ImGui::SliderFloat("Walk Speed", &ms, 0.01f, std::min(ms * 1.1f, 10000.f)))
2809  cam->maxSpeed(ms);
2810  }
2811 
2812  ImGui::PopItemWidth();
2813  ImGui::EndMenu();
2814  }
2815 
2816  if (ImGui::BeginMenu("Fog"))
2817  {
2818  ImGui::PushItemWidth(ImGui::GetWindowWidth() * 0.66f);
2819 
2820  if (ImGui::MenuItem("Fog is on", nullptr, cam->fogIsOn()))
2821  cam->fogIsOn(!cam->fogIsOn());
2822 
2823  if (ImGui::BeginMenu("Mode"))
2824  {
2825  if (ImGui::MenuItem("linear", nullptr, cam->fogMode() == FM_linear))
2826  cam->fogMode(FM_linear);
2827  if (ImGui::MenuItem("exp", nullptr, cam->fogMode() == FM_exp))
2828  cam->fogMode(FM_exp);
2829  if (ImGui::MenuItem("exp2", nullptr, cam->fogMode() == FM_exp2))
2830  cam->fogMode(FM_exp2);
2831  ImGui::EndMenu();
2832  }
2833 
2834  if (cam->fogMode() == FM_exp || cam->fogMode() == FM_exp2)
2835  {
2836  static SLfloat fogDensity = cam->fogDensity();
2837  if (ImGui::SliderFloat("Density", &fogDensity, 0.0f, 0.2f))
2838  cam->fogDensity(fogDensity);
2839  }
2840 
2841  ImGui::PopItemWidth();
2842  ImGui::EndMenu();
2843  }
2844 
2845  ImGui::EndMenu();
2846  }
2847 
2848  if (ImGui::BeginMenu("Animation", hasAnimations))
2849  {
2850 
2851  if (ImGui::MenuItem("Stop all", "Space", s->stopAnimations()))
2853 
2854  ImGui::Separator();
2855 
2856  SLVstring animations = s->animManager().animationNames();
2857  if (curAnimIx == -1) curAnimIx = 0;
2858  SLAnimPlayback* anim = s->animManager().animPlaybackByIndex((SLuint)curAnimIx);
2859 
2860  ImGui::PushItemWidth(ImGui::GetWindowWidth() * 0.8f);
2861  if (myComboBox("##", &curAnimIx, animations))
2862  anim = s->animManager().animPlaybackByIndex((SLuint)curAnimIx);
2863  ImGui::PopItemWidth();
2864 
2865  if (ImGui::MenuItem("Play forward", nullptr, anim->isPlayingForward()))
2866  anim->playForward();
2867 
2868  if (ImGui::MenuItem("Play backward", nullptr, anim->isPlayingBackward()))
2869  anim->playBackward();
2870 
2871  if (ImGui::MenuItem("Pause", nullptr, anim->isPaused()))
2872  anim->pause();
2873 
2874  if (ImGui::MenuItem("Stop", nullptr, anim->isStopped()))
2875  anim->enabled(false);
2876 
2877  if (ImGui::MenuItem("Skip to next keyfr.", nullptr, false))
2878  anim->skipToNextKeyframe();
2879 
2880  if (ImGui::MenuItem("Skip to prev. keyfr.", nullptr, false))
2881  anim->skipToPrevKeyframe();
2882 
2883  if (ImGui::MenuItem("Skip to start", nullptr, false))
2884  anim->skipToStart();
2885 
2886  if (ImGui::MenuItem("Skip to end", nullptr, false))
2887  anim->skipToEnd();
2888 
2889  ImGui::PushItemWidth(ImGui::GetWindowWidth() * 0.6f);
2890 
2891  SLfloat speed = anim->playbackRate();
2892  if (ImGui::SliderFloat("Speed", &speed, 0.f, 4.f))
2893  anim->playbackRate(speed);
2894 
2895  SLfloat lenSec = anim->parentAnimation()->lengthSec();
2896  SLfloat localTimeSec = anim->localTime();
2897  if (ImGui::SliderFloat("Time", &localTimeSec, 0.f, lenSec))
2898  anim->localTime(localTimeSec);
2899 
2900  SLint curEasing = (SLint)anim->easing();
2901  const char* easings[] = {"linear",
2902  "in quad",
2903  "out quad",
2904  "in out quad",
2905  "out in quad",
2906  "in cubic",
2907  "out cubic",
2908  "in out cubic",
2909  "out in cubic",
2910  "in quart",
2911  "out quart",
2912  "in out quart",
2913  "out in quart",
2914  "in quint",
2915  "out quint",
2916  "in out quint",
2917  "out in quint",
2918  "in sine",
2919  "out sine",
2920  "in out sine",
2921  "out in sine"};
2922  if (ImGui::Combo("Easing", &curEasing, easings, IM_ARRAYSIZE(easings)))
2923  anim->easing((SLEasingCurve)curEasing);
2924 
2925  ImGui::PopItemWidth();
2926  ImGui::EndMenu();
2927  }
2928 
2929  if (ImGui::BeginMenu("Infos"))
2930  {
2931  ImGui::MenuItem("Infos on Scene", nullptr, &showInfosScene);
2932 
2933  if (ImGui::BeginMenu("Statistics"))
2934  {
2935  ImGui::MenuItem("Stats on Timing", nullptr, &showStatsTiming);
2936  ImGui::MenuItem("Stats on Scene", nullptr, &showStatsScene);
2937  ImGui::MenuItem("Stats on Video", nullptr, &showStatsVideo);
2938 #ifdef SL_BUILD_WAI
2940  ImGui::MenuItem("Stats on WAI", nullptr, &showStatsWAI);
2941 #endif
2942  ImGui::MenuItem("Stats on ImGui", nullptr, &showImGuiMetrics);
2943  ImGui::EndMenu();
2944  }
2945 
2946  ImGui::MenuItem("Scenegraph", nullptr, &showSceneGraph);
2947  ImGui::MenuItem("Properties", nullptr, &showProperties);
2948  ImGui::MenuItem("Transform", nullptr, &showTransform);
2949  if (AppCommon::devLoc.originLatLonAlt() != SLVec3d::ZERO ||
2950  AppCommon::devLoc.defaultLatLonAlt() != SLVec3d::ZERO)
2951  ImGui::MenuItem("Date-Time", nullptr, &showDateAndTime);
2952  ImGui::MenuItem("UI-Preferences", nullptr, &showUIPrefs);
2953  ImGui::Separator();
2954  ImGui::MenuItem("Infos on Device", nullptr, &showInfosDevice);
2955  ImGui::MenuItem("Infos on Sensors", nullptr, &showInfosSensors);
2958  {
2959  ImGui::Separator();
2960  ImGui::MenuItem("ErlebAR Settings", nullptr, &showErlebAR);
2961  }
2962  ImGui::Separator();
2963  ImGui::MenuItem("Help on Interaction", nullptr, &showHelp);
2964  ImGui::MenuItem("Help on Calibration", nullptr, &showHelpCalibration);
2965  ImGui::Separator();
2966  ImGui::MenuItem("Credits", nullptr, &showCredits);
2967  ImGui::MenuItem("About SLProject", nullptr, &showAbout);
2968 
2969  ImGui::EndMenu();
2970  }
2971 
2972  ImGui::EndMainMenuBar();
2973  }
2974 }
2975 //-----------------------------------------------------------------------------
2976 //! Builds the edit menu that can be in the menu bar and the context menu
2978 {
2979  if (ImGui::MenuItem("Deselect Node", "ESC"))
2981 
2982  ImGui::Separator();
2983 
2984  if (ImGui::MenuItem("Translate Node", nullptr, transformNode && transformNode->editMode() == NodeEditMode_Translate))
2985  {
2988  else
2990  }
2991  if (ImGui::MenuItem("Rotate Node", nullptr, transformNode && transformNode->editMode() == NodeEditMode_Rotate))
2992  {
2995  else
2997  }
2998  if (ImGui::MenuItem("Scale Node", nullptr, transformNode && transformNode->editMode() == NodeEditMode_Scale))
2999  {
3002  else
3004  }
3005 
3006  ImGui::Separator();
3007 
3008  if (ImGui::BeginMenu("Node Flags"))
3009  {
3010  SLNode* selN = s->singleNodeSelected();
3011 
3012  if (ImGui::MenuItem("Wired Mesh", nullptr, selN->drawBits()->get(SL_DB_MESHWIRED)))
3013  selN->drawBits()->toggle(SL_DB_MESHWIRED);
3014 
3015  if (ImGui::MenuItem("With hard edges", nullptr, selN->drawBits()->get(SL_DB_WITHEDGES)))
3016  selN->drawBits()->toggle(SL_DB_WITHEDGES);
3017 
3018  if (ImGui::MenuItem("Only hard edges", nullptr, selN->drawBits()->get(SL_DB_ONLYEDGES)))
3019  selN->drawBits()->toggle(SL_DB_ONLYEDGES);
3020 
3021  if (ImGui::MenuItem("Normals", nullptr, selN->drawBits()->get(SL_DB_NORMALS)))
3022  selN->drawBits()->toggle(SL_DB_NORMALS);
3023 
3024  if (ImGui::MenuItem("Bounding Rectangles", nullptr, selN->drawBits()->get(SL_DB_BRECT)))
3025  selN->drawBits()->toggle(SL_DB_BRECT);
3026 
3027  if (ImGui::MenuItem("Bounding Boxes", nullptr, selN->drawBits()->get(SL_DB_BBOX)))
3028  selN->drawBits()->toggle(SL_DB_BBOX);
3029 
3030  if (ImGui::MenuItem("Voxels", nullptr, selN->drawBits()->get(SL_DB_VOXELS)))
3031  selN->drawBits()->toggle(SL_DB_VOXELS);
3032 
3033  if (ImGui::MenuItem("Axis", nullptr, selN->drawBits()->get(SL_DB_AXIS)))
3034  selN->drawBits()->toggle(SL_DB_AXIS);
3035 
3036  if (ImGui::MenuItem("Back Faces", nullptr, selN->drawBits()->get(SL_DB_CULLOFF)))
3037  selN->drawBits()->toggle(SL_DB_CULLOFF);
3038 
3039  if (ImGui::MenuItem("Skeleton", nullptr, selN->drawBits()->get(SL_DB_SKELETON)))
3040  selN->drawBits()->toggle(SL_DB_SKELETON);
3041 
3042  if (ImGui::MenuItem("All off"))
3043  selN->drawBits()->allOff();
3044 
3045  ImGui::EndMenu();
3046  }
3047 }
3048 //-----------------------------------------------------------------------------
3049 //! Builds context menu if right mouse click is over non-imgui area
3051 {
3052  // assert(s->assetManager() && "No asset manager assigned to scene!");
3053 
3054  if (!ImGui::IsWindowHovered(ImGuiHoveredFlags_AnyWindow) &&
3055  ImGui::IsMouseReleased(1))
3056  {
3057  ImGui::OpenPopup("Context Menu");
3058  }
3059 
3060  if (ImGui::BeginPopup("Context Menu"))
3061  {
3062  if (s->singleNodeSelected() != nullptr || !sv->camera()->selectRect().isZero())
3063  {
3064  if (s->singleNodeSelected())
3065  {
3066  buildMenuEdit(s, sv);
3067  ImGui::Separator();
3068 
3069  if (!showProperties)
3070  if (ImGui::MenuItem("Show Properties"))
3071  showProperties = true;
3072  }
3073  }
3074 
3075  if (AppDemoGui::hideUI)
3076  if (ImGui::MenuItem("Show user interface"))
3077  AppDemoGui::hideUI = false;
3078 
3079  if (!AppDemoGui::hideUI)
3080  if (ImGui::MenuItem("Hide user interface"))
3081  AppDemoGui::hideUI = true;
3082 
3083  if (s->root3D()->drawBits()->get(SL_DB_HIDDEN))
3084  if (ImGui::MenuItem("Show root node"))
3085  s->root3D()->drawBits()->toggle(SL_DB_HIDDEN);
3086 
3087  if (!s->root3D()->drawBits()->get(SL_DB_HIDDEN))
3088  if (ImGui::MenuItem("Hide root node"))
3089  s->root3D()->drawBits()->toggle(SL_DB_HIDDEN);
3090 
3091  if (ImGui::MenuItem("Capture Screen"))
3093 
3094  ImGui::EndPopup();
3095  }
3096 }
3097 //-----------------------------------------------------------------------------
3098 //! Builds the scenegraph dialog once per frame
3100 {
3101  PROFILE_FUNCTION();
3102 
3103  // assert(s->assetManager() && "No asset manager assigned to scene!");
3104 
3105  ImGui::PushFont(ImGui::GetIO().Fonts->Fonts[1]);
3106  ImGui::Begin("Scenegraph", &showSceneGraph, ImGuiWindowFlags_NoNavInputs);
3107 
3108  if (s->root3D())
3109  addSceneGraphNode(s, s->root3D());
3110 
3111  if (s->root2D())
3112  addSceneGraphNode(s, s->root2D());
3113 
3114  ImGui::End();
3115  ImGui::PopFont();
3116 }
3117 //-----------------------------------------------------------------------------
3118 //! Builds the node information once per frame
3120 {
3121  PROFILE_FUNCTION();
3122 
3123  // assert(s->assetManager() && "No asset manager assigned to scene!");
3124 
3125  SLbool isSelectedNode = s->singleNodeSelected() == node;
3126  SLbool isLeafNode = node->children().empty() && !node->mesh();
3127  SLbool isHidden = node->drawBit(SL_DB_HIDDEN);
3128  bool nodeIsOpen;
3129 
3130  ImGuiTreeNodeFlags nodeFlags = 0;
3131  if (isLeafNode)
3132  nodeFlags |= ImGuiTreeNodeFlags_Leaf;
3133  else
3134  nodeFlags |= ImGuiTreeNodeFlags_OpenOnArrow;
3135 
3136  if (isSelectedNode)
3137  nodeFlags |= ImGuiTreeNodeFlags_Selected;
3138 
3139  if (isHidden)
3140  {
3141  ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(1.0f, 0.0f, 1.0f, 1.0f));
3142  nodeIsOpen = ImGui::TreeNodeEx(node->name().c_str(), nodeFlags);
3143  ImGui::PopStyleColor();
3144  }
3145  else
3146  {
3147  ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(0.0f, 1.0f, 0.0f, 1.0f));
3148  nodeIsOpen = ImGui::TreeNodeEx(node->name().c_str(), nodeFlags);
3149  ImGui::PopStyleColor();
3150  }
3151 
3152  if (ImGui::IsItemClicked())
3153  {
3155  s->selectNodeMesh(node, nullptr);
3156  }
3157 
3158  if (nodeIsOpen)
3159  {
3160  if (node->mesh())
3161  {
3162  SLMesh* mesh = node->mesh();
3163  ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(1.0f, 1.0f, 0.0f, 1.0f));
3164 
3165  ImGuiTreeNodeFlags meshFlags = ImGuiTreeNodeFlags_Leaf;
3166  if (s->singleMeshFullSelected() == mesh)
3167  meshFlags |= ImGuiTreeNodeFlags_Selected;
3168 
3169  ImGui::TreeNodeEx(mesh, meshFlags, "%s", mesh->name().c_str());
3170 
3171  if (ImGui::IsItemClicked())
3172  {
3174  s->selectNodeMesh(node, mesh);
3175  }
3176 
3177  ImGui::TreePop();
3178  ImGui::PopStyleColor();
3179  }
3180 
3181  for (auto* child : node->children())
3182  addSceneGraphNode(s, child);
3183 
3184  ImGui::TreePop();
3185  }
3186 }
3187 //-----------------------------------------------------------------------------
3188 //! Builds the properties dialog once per frame
3190 {
3191  PROFILE_FUNCTION();
3192 
3193  // assert(s->assetManager() && "No asset manager assigned to scene!");
3194 
3195  SLNode* singleNode = s->singleNodeSelected();
3196  SLMesh* singleFullMesh = s->singleMeshFullSelected();
3197  bool partialSelection = !s->selectedMeshes().empty() && !s->selectedMeshes()[0]->IS32.empty();
3198 
3199  ImGui::PushFont(ImGui::GetIO().Fonts->Fonts[1]);
3200  ImGui::Begin("Properties", &showProperties, ImGuiWindowFlags_AlwaysVerticalScrollbar | ImGuiWindowFlags_NoNavInputs);
3201  ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(0.0f, 1.0f, 1.0f, 1.0f));
3202 
3203  if (ImGui::TreeNode("Scene Properties"))
3204  {
3205  if (s->lights().size() > 0)
3206  {
3207  ImGuiColorEditFlags cef = ImGuiColorEditFlags_NoInputs;
3208  SLCol4f gAC = s->lights()[0]->globalAmbient;
3209  if (ImGui::ColorEdit3("Global Ambient Color", (float*)&gAC, cef))
3210  s->lights()[0]->globalAmbient = gAC;
3211  }
3212 
3213  if (ImGui::TreeNode("Sky", "Skybox"))
3214  {
3215  if (s->skybox())
3216  {
3217  SLSkybox* sky = s->skybox();
3218 
3219  if (sky->isHDR())
3220  {
3221  float exposure = sky->exposure();
3222  if (ImGui::SliderFloat("Exposure", &exposure, 0.05f, 5.0f))
3223  sky->exposure(exposure);
3224 
3225  if (sky->environmentCubemap())
3227  if (sky->irradianceCubemap())
3229  if (sky->roughnessCubemap())
3231  if (sky->brdfLutTexture())
3232  showTexInfos(sky->brdfLutTexture());
3233  }
3234  else
3235  {
3236  ImGui::Text("No properties for skyboxes that are not used for lighting (HDR)");
3237  }
3238  }
3239  else
3240  {
3241  ImGui::Text("Skybox: None");
3242  }
3243  ImGui::TreePop();
3244  }
3245  ImGui::TreePop();
3246  }
3247 
3248  ImGui::PopStyleColor();
3249  ImGui::Separator();
3250 
3251  // Node and Mesh Properties
3252  if (sv->renderType() == RT_gl)
3253  {
3254  // Only single node and no partial mesh selection
3255  if (singleNode && !partialSelection)
3256  {
3257  if (ImGui::TreeNode("Node Properties"))
3258  {
3259  if (singleNode)
3260  {
3261  SLuint c = (SLuint)singleNode->children().size();
3262  SLuint m = singleNode->mesh() ? 1 : 0;
3263  ImGui::Text("Node name : %s", singleNode->name().c_str());
3264  ImGui::Text("# children : %u", c);
3265  ImGui::Text("# meshes : %u", m);
3266  if (ImGui::TreeNode("Drawing flags"))
3267  {
3268  SLbool db = singleNode->drawBit(SL_DB_HIDDEN);
3269  if (ImGui::Checkbox("Hide", &db))
3270  singleNode->drawBits()->set(SL_DB_HIDDEN, db);
3271 
3272  db = singleNode->drawBit(SL_DB_NOTSELECTABLE);
3273  if (ImGui::Checkbox("Not selectable", &db))
3274  singleNode->drawBits()->set(SL_DB_NOTSELECTABLE, db);
3275 
3276  db = singleNode->drawBit(SL_DB_MESHWIRED);
3277  if (ImGui::Checkbox("Show wireframe", &db))
3278  singleNode->drawBits()->set(SL_DB_MESHWIRED, db);
3279 
3280  db = singleNode->drawBit(SL_DB_WITHEDGES);
3281  if (ImGui::Checkbox("Show with hard edges", &db))
3282  singleNode->drawBits()->set(SL_DB_WITHEDGES, db);
3283 
3284  db = singleNode->drawBit(SL_DB_ONLYEDGES);
3285  if (ImGui::Checkbox("Show only hard edges", &db))
3286  singleNode->drawBits()->set(SL_DB_ONLYEDGES, db);
3287 
3288  db = singleNode->drawBit(SL_DB_NORMALS);
3289  if (ImGui::Checkbox("Show normals", &db))
3290  singleNode->drawBits()->set(SL_DB_NORMALS, db);
3291 
3292  db = singleNode->drawBit(SL_DB_VOXELS);
3293  if (ImGui::Checkbox("Show voxels", &db))
3294  singleNode->drawBits()->set(SL_DB_VOXELS, db);
3295 
3296  db = singleNode->drawBit(SL_DB_BBOX);
3297  if (ImGui::Checkbox("Show bounding boxes", &db))
3298  singleNode->drawBits()->set(SL_DB_BBOX, db);
3299 
3300  db = singleNode->drawBit(SL_DB_BRECT);
3301  if (ImGui::Checkbox("Show bounding rects", &db))
3302  singleNode->drawBits()->set(SL_DB_BRECT, db);
3303 
3304  db = singleNode->drawBit(SL_DB_AXIS);
3305  if (ImGui::Checkbox("Show axis", &db))
3306  singleNode->drawBits()->set(SL_DB_AXIS, db);
3307 
3308  db = singleNode->drawBit(SL_DB_CULLOFF);
3309  if (ImGui::Checkbox("Show back faces", &db))
3310  singleNode->drawBits()->set(SL_DB_CULLOFF, db);
3311 
3312  ImGui::TreePop();
3313  }
3314 
3315  if (ImGui::TreeNode("Local transform"))
3316  {
3317  SLMat4f om(singleNode->om());
3318  SLVec3f trn, rot, scl;
3319  om.decompose(trn, rot, scl);
3320  rot *= Utils::RAD2DEG;
3321 
3322  ImGui::Text("Translation : %s", trn.toString().c_str());
3323  ImGui::Text("Rotation : %s", rot.toString().c_str());
3324  ImGui::Text("Scaling : %s", scl.toString().c_str());
3325  ImGui::TreePop();
3326  }
3327 
3328  // Properties related to shadow mapping
3329  if (ImGui::TreeNode("Shadow mapping"))
3330  {
3331  SLbool castsShadows = singleNode->castsShadows();
3332  if (ImGui::Checkbox("Casts shadows", &castsShadows))
3333  singleNode->castsShadows(castsShadows);
3334 
3335  if (auto* light = dynamic_cast<SLLight*>(singleNode))
3336  {
3337  SLbool createsShadows = light->createsShadows();
3338  if (ImGui::Checkbox("Creates shadows", &createsShadows))
3339  light->createsShadows(createsShadows);
3340 
3341  if (createsShadows)
3342  {
3343  SLShadowMap* shadowMap = light->shadowMap();
3344 
3345  if (shadowMap != nullptr)
3346  {
3347  if (shadowMap->projection() == P_monoPerspective &&
3348  light->spotCutOffDEG() < 90.0f)
3349  {
3350  SLbool useCubemap = shadowMap->useCubemap();
3351  if (ImGui::Checkbox("Uses Cubemap", &useCubemap))
3352  shadowMap->useCubemap(useCubemap);
3353  }
3354 
3355  SLfloat clipNear = shadowMap->lightClipNear();
3356  SLfloat clipFar = shadowMap->lightClipFar();
3357  SLfloat factor = shadowMap->cascadesFactor();
3358 
3359  if (!shadowMap->useCascaded())
3360  {
3361  if (ImGui::SliderFloat("Near clipping plane", &clipNear, 0.01f, clipFar))
3362  shadowMap->clipNear(clipNear);
3363 
3364  if (ImGui::SliderFloat("Far clipping plane", &clipFar, clipNear, 200.0f))
3365  shadowMap->clipFar(clipFar);
3366  }
3367  else
3368  {
3369  SLint numCascades = shadowMap->numCascades();
3370  SLint maxCascades = shadowMap->maxCascades();
3371  if (ImGui::SliderInt("Number of cascades", &numCascades, 1, maxCascades))
3372  shadowMap->numCascades(numCascades);
3373  if (ImGui::SliderFloat("Cascades factor", &factor, 1.0, 500.0f))
3374  shadowMap->cascadesFactor(factor);
3375  }
3376 
3377  SLVec2i texSize = shadowMap->textureSize();
3378  if (ImGui::SliderInt2("Texture resolution", (int*)&texSize, 32, 4096))
3379  shadowMap->textureSize(
3380  SLVec2i((int)Utils::closestPowerOf2((unsigned)texSize.x),
3381  (int)Utils::closestPowerOf2((unsigned)texSize.y)));
3382 
3383  SLfloat shadowMinBias = light->shadowMinBias();
3384  SLfloat shadowMaxBias = light->shadowMaxBias();
3385  if (ImGui::SliderFloat("Min. shadow bias", &shadowMinBias, 0.0f, shadowMaxBias, "%.03f"))
3386  light->shadowMinBias(shadowMinBias);
3387  if (ImGui::SliderFloat("Max. shadow bias", &shadowMaxBias, shadowMinBias, 0.02f, "%.03f"))
3388  light->shadowMaxBias(shadowMaxBias);
3389 
3390  if (typeid(*singleNode) == typeid(SLLightDirect) && !shadowMap->useCascaded())
3391  {
3392  SLVec2f size = shadowMap->size();
3393  if (ImGui::InputFloat2("Size", (float*)&size))
3394  shadowMap->size(size);
3395  }
3396 
3397  if (!shadowMap->useCubemap())
3398  {
3399  SLbool doSmoothShadows = light->doSoftShadows();
3400  if (ImGui::Checkbox("Do smooth shadows", &doSmoothShadows))
3401  light->doSmoothShadows(doSmoothShadows);
3402 
3403  SLuint pcfLevel = light->softShadowLevel();
3404  if (ImGui::SliderInt("Smoothing level", (SLint*)&pcfLevel, 1, 3))
3405  light->smoothShadowLevel(pcfLevel);
3406  }
3407 
3408  SLbool doColoredShadows = SLLight::doColoredShadows;
3409  if (ImGui::Checkbox("Do colored shadows", &doColoredShadows))
3410  SLLight::doColoredShadows = doColoredShadows;
3411 #ifndef SL_GLES
3412  SLVec2i rayCount = shadowMap->rayCount();
3413  if (ImGui::InputInt2("Visualization rays", (int*)&rayCount))
3414  shadowMap->rayCount(rayCount);
3415 #endif
3416 
3417  if (shadowMap->useCascaded())
3418  {
3419  if (ImGui::TreeNode("Light cascade space matrices"))
3420  {
3421  for (SLint i = 0; i < shadowMap->numCascades(); ++i)
3422  ImGui::Text("Matrix %i:\n%s", i + 1, shadowMap->lightSpace()[i].toString().c_str());
3423 
3424  ImGui::TreePop();
3425  }
3426  }
3427  else
3428  {
3429  if (ImGui::TreeNode(shadowMap->useCubemap() ? "Light space matrices" : "Light space matrix"))
3430  {
3431  if (shadowMap->useCubemap())
3432  for (SLint i = 0; i < 6; ++i)
3433  ImGui::Text("Matrix %i:\n%s", i + 1, shadowMap->lightSpace()[i].toString().c_str());
3434  else
3435  ImGui::Text(shadowMap->lightSpace()[0].toString().c_str());
3436 
3437  ImGui::TreePop();
3438  }
3439  }
3440 
3441  if (!shadowMap->useCubemap())
3442  {
3443  if (shadowMap->useCascaded())
3444  {
3445  for (int i = 0; i < shadowMap->depthBuffers().size(); i++)
3446  {
3447  ImGui::Text(("Depth Buffer " + std::to_string(i) + ":").c_str());
3448  ImGui::Image((void*)(intptr_t)shadowMap->depthBuffers().at(i)->texID(),
3449  ImVec2(200, 200));
3450  }
3451  }
3452  else
3453  {
3454  ImGui::Text("Depth Buffer:");
3455  ImGui::Image((void*)(intptr_t)shadowMap->depthBuffer()->texID(),
3456  ImVec2(200, 200));
3457  }
3458  }
3459  }
3460  }
3461  }
3462 
3463  ImGui::TreePop();
3464  }
3465 
3466  // Show special camera properties
3467  if (typeid(*singleNode) == typeid(SLCamera))
3468  {
3469  auto* cam = (SLCamera*)singleNode;
3470 
3471  if (ImGui::TreeNode("Camera"))
3472  {
3473  SLfloat clipN = cam->clipNear();
3474  SLfloat clipF = cam->clipFar();
3475  SLfloat focalDist = cam->focalDist();
3476  SLfloat fov = cam->fovV();
3477 
3478  const char* projections[] = {"Mono Perspective",
3479  "Mono Intrinsic Calibrated",
3480  "Mono Orthographic",
3481  "Stereo Side By Side",
3482  "Stereo Side By Side Prop.",
3483  "Stereo Side By Side Dist.",
3484  "Stereo Line By Line",
3485  "Stereo Column By Column",
3486  "Stereo Pixel By Pixel",
3487  "Stereo Color Red-Cyan",
3488  "Stereo Color Red-Green",
3489  "Stereo Color Red-Blue",
3490  "Stereo Color Yellow-Blue"};
3491 
3492  int proj = cam->projType();
3493  if (ImGui::Combo("Projection", &proj, projections, IM_ARRAYSIZE(projections)))
3494  cam->projType((SLProjType)proj);
3495 
3496  if (cam->projType() > P_monoOrthographic)
3497  {
3498  SLfloat eyeSepar = cam->stereoEyeSeparation();
3499  if (ImGui::SliderFloat("Eye Sep.", &eyeSepar, 0.0f, focalDist / 10.f))
3500  cam->stereoEyeSeparation(eyeSepar);
3501  }
3502 
3503  if (ImGui::SliderFloat("FOV", &fov, 1.f, 179.f))
3504  cam->fov(fov);
3505 
3506  if (ImGui::SliderFloat("Near Clip", &clipN, 0.001f, 10.f))
3507  cam->clipNear(clipN);
3508 
3509  if (ImGui::SliderFloat("Far Clip", &clipF, clipN, std::min(clipF * 1.1f, 1000000.f)))
3510  cam->clipFar(clipF);
3511 
3512  if (ImGui::SliderFloat("Focal Dist.", &focalDist, clipN, clipF))
3513  cam->focalDist(focalDist);
3514 
3515  ImGui::TreePop();
3516  }
3517  }
3518 
3519  // Show special light properties
3520  if (typeid(*singleNode) == typeid(SLLightSpot) ||
3521  typeid(*singleNode) == typeid(SLLightRect) ||
3522  typeid(*singleNode) == typeid(SLLightDirect))
3523  {
3524  SLLight* light = nullptr;
3525  SLstring typeName;
3526  SLbool doSunPowerAdaptation = false;
3527  if (typeid(*singleNode) == typeid(SLLightSpot))
3528  {
3529  light = (SLLight*)(SLLightSpot*)singleNode;
3530  typeName = "Light (spot):";
3531  }
3532  if (typeid(*singleNode) == typeid(SLLightRect))
3533  {
3534  light = (SLLight*)(SLLightRect*)singleNode;
3535  typeName = "Light (rectangular):";
3536  }
3537  if (typeid(*singleNode) == typeid(SLLightDirect))
3538  {
3539  light = (SLLight*)(SLLightDirect*)singleNode;
3540  typeName = "Light (directional):";
3541  doSunPowerAdaptation = ((SLLightDirect*)singleNode)->doSunPowerAdaptation();
3542  }
3543 
3544  if (light && ImGui::TreeNode(typeName.c_str()))
3545  {
3546  SLbool on = light->isOn();
3547  if (ImGui::Checkbox("Is on", &on))
3548  light->isOn(on);
3549 
3550  ImGuiColorEditFlags cef = ImGuiColorEditFlags_NoInputs;
3551  SLCol4f aC = light->ambientColor();
3552  if (ImGui::ColorEdit3("Ambient color", (float*)&aC, cef))
3553  light->ambientColor(aC);
3554 
3555  float aP = light->ambientPower();
3556  float dP = light->diffusePower();
3557  if (doSunPowerAdaptation)
3558  {
3559  float sum_aPdP = aP + dP;
3560  float ambiFraction = aP / sum_aPdP;
3561  if (ImGui::SliderFloat("Diffuse-Ambient-Mix", &ambiFraction, 0.0f, 1.0f, "%.2f"))
3562  {
3563  light->ambientPower(ambiFraction * sum_aPdP);
3564  light->diffusePower((1.0f - ambiFraction) * sum_aPdP);
3565  }
3566  }
3567  else
3568  {
3569  SLCol4f dC = light->diffuseColor();
3570  if (ImGui::ColorEdit3("Diffuse color", (float*)&dC, cef))
3571  light->diffuseColor(dC);
3572 
3573  SLCol4f sC = light->specularColor();
3574  if (ImGui::ColorEdit3("Specular color", (float*)&sC, cef))
3575  light->specularColor(sC);
3576  }
3577 
3578  if (ImGui::SliderFloat("Ambient power", &aP, 0.0f, 10.0f, "%.2f"))
3579  light->ambientPower(aP);
3580 
3581  if (ImGui::SliderFloat("Diffuse power", &dP, 0.0f, 10.0f, "%.2f"))
3582  light->diffusePower(dP);
3583 
3584  float sP = light->specularPower();
3585  if (ImGui::SliderFloat("Specular power", &sP, 0.0f, 10.0f, "%.2f"))
3586  light->specularPower(sP);
3587 
3588  float cutoff = light->spotCutOffDEG();
3589  if (ImGui::SliderFloat("Spot cut off angle", &cutoff, 0.0f, 180.0f, "%.2f"))
3590  light->spotCutOffDEG(cutoff);
3591 
3592  float spotExp = light->spotExponent();
3593  if (ImGui::SliderFloat("Spot attenuation", &spotExp, 0.0f, 128.0f, "%.2f"))
3594  light->spotExponent(spotExp);
3595 
3596  float kc = light->kc();
3597  if (ImGui::SliderFloat("Constant attenuation", &kc, 0.0f, 1.0f, "%.2f"))
3598  light->kc(kc);
3599 
3600  float kl = light->kl();
3601  if (ImGui::SliderFloat("Linear attenuation", &kl, 0.0f, 1.0f, "%.2f"))
3602  light->kl(kl);
3603 
3604  float kq = light->kq();
3605  if (ImGui::SliderFloat("Quadratic attenuation", &kq, 0.0f, 1.0f, "%.2f"))
3606  light->kq(kq);
3607 
3608  if (typeid(*singleNode) == typeid(SLLightDirect))
3609  {
3610  SLLightDirect* dirLight = (SLLightDirect*)singleNode;
3611  if (ImGui::Checkbox("Do Sun Power Adaptation", &doSunPowerAdaptation))
3612  dirLight->doSunPowerAdaptation(doSunPowerAdaptation);
3613 
3614  if (doSunPowerAdaptation)
3615  {
3616  SLTexColorLUT* lut = dirLight->sunLightColorLUT();
3617  if (ImGui::TreeNode("Sun Color LUT"))
3618  {
3619  showLUTColors(lut);
3620  ImGui::TreePop();
3621  }
3622 
3623  lut->bindActive(); // This texture is not an scenegraph texture
3624  SLfloat texW =
3625  ImGui::GetWindowWidth() - 4 * ImGui::GetTreeNodeToLabelSpacing() - 10;
3626  void* tid = (ImTextureID)(uintptr_t)lut->texID();
3627  ImGui::Image(tid,
3628  ImVec2(texW, texW * 0.15f),
3629  ImVec2(0, 1),
3630  ImVec2(1, 0),
3631  ImVec4(1, 1, 1, 1),
3632  ImVec4(1, 1, 1, 1));
3633  }
3634  }
3635 
3636  ImGui::TreePop();
3637  }
3638  }
3639  }
3640  else
3641  {
3642  ImGui::Text("No single node selected.");
3643  }
3644  ImGui::TreePop();
3645  }
3646 
3647  ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(1.0f, 1.0f, 0.0f, 1.0f));
3648  ImGui::Separator();
3649 
3650  if (singleFullMesh)
3651  {
3652  // See also SLScene::selectNodeMesh
3653  if (ImGui::TreeNode("Mesh Properties"))
3654  {
3655  SLuint v = (SLuint)singleFullMesh->P.size();
3656  SLuint t = (SLuint)(!singleFullMesh->I16.empty() ? singleFullMesh->I16.size() / 3 : singleFullMesh->I32.size() / 3);
3657  SLuint e = (SLuint)(!singleFullMesh->IE16.empty() ? singleFullMesh->IE16.size() / 2 : singleFullMesh->IE32.size() / 2);
3658  SLMaterial* m = singleFullMesh->mat();
3659  ImGui::Text("Mesh name : %s", singleFullMesh->name().c_str());
3660  if (m->reflectionModel() == RM_Particle)
3661  {
3662  SLParticleSystem* ps = dynamic_cast<SLParticleSystem*>(singleFullMesh);
3663  ImGui::Text("# vertices : %u", ps->amount() * 4);
3664  ImGui::Text("# triangles : %u", ps->amount() * 2);
3665  }
3666  else
3667  {
3668  ImGui::Text("# vertices : %u", v);
3669  ImGui::Text("# triangles : %u", t);
3670  ImGui::Text("# hard edges : %u", e);
3671  }
3672  ImGui::Text("Material Name: %s", m->name().c_str());
3673 
3674  if (m->reflectionModel() == RM_BlinnPhong)
3675  {
3676  if (ImGui::TreeNode("Reflection Model: Blinn-Phong"))
3677  {
3678  ImGui::PushItemWidth(ImGui::GetWindowWidth() * 0.5f);
3679 
3680  ImGuiColorEditFlags cef = ImGuiColorEditFlags_NoInputs;
3681  SLCol4f ac = m->ambient();
3682  if (ImGui::ColorEdit3("Ambient color", (float*)&ac, cef))
3683  m->ambient(ac);
3684 
3685  SLCol4f dc = m->diffuse();
3686  if (ImGui::ColorEdit3("Diffuse color", (float*)&dc, cef))
3687  m->diffuse(dc);
3688 
3689  SLCol4f sc = m->specular();
3690  if (ImGui::ColorEdit3("Specular color", (float*)&sc, cef))
3691  m->specular(sc);
3692 
3693  SLCol4f ec = m->emissive();
3694  if (ImGui::ColorEdit3("Emissive color", (float*)&ec, cef))
3695  m->emissive(ec);
3696 
3697  SLfloat shine = m->shininess();
3698  if (ImGui::SliderFloat("Shininess", &shine, 0.0f, 1000.0f))
3699  m->shininess(shine);
3700 
3701  SLfloat kr = m->kr();
3702  if (ImGui::SliderFloat("kr", &kr, 0.0f, 1.0f))
3703  m->kr(kr);
3704 
3705  SLfloat kt = m->kt();
3706  if (ImGui::SliderFloat("kt", &kt, 0.0f, 1.0f))
3707  m->kt(kt);
3708 
3709  SLfloat kn = m->kn();
3710  if (ImGui::SliderFloat("kn", &kn, 1.0f, 2.5f))
3711  m->kn(kn);
3712 
3713  SLbool receivesShadows = m->getsShadows();
3714  if (ImGui::Checkbox("Receives shadows", &receivesShadows))
3715  m->getsShadows(receivesShadows);
3716 
3717  ImGui::PopItemWidth();
3718  ImGui::TreePop();
3719  }
3720  }
3721  else if (m->reflectionModel() == RM_CookTorrance)
3722  {
3723  if (ImGui::TreeNode("Reflection Model: Cook-Torrance"))
3724  {
3725  if (m->numTextures())
3726  {
3727  ImGui::Text("Controlled by textures");
3728  }
3729  else
3730  {
3731  ImGui::PushItemWidth(ImGui::GetWindowWidth() * 0.5f);
3732 
3733  ImGuiColorEditFlags cef = ImGuiColorEditFlags_NoInputs;
3734  SLCol4f dc = m->diffuse();
3735  if (ImGui::ColorEdit3("Diffuse color", (float*)&dc, cef))
3736  m->diffuse(dc);
3737 
3738  SLfloat rough = m->roughness();
3739  if (ImGui::SliderFloat("Roughness", &rough, 0.0f, 1.0f))
3740  m->roughness(rough);
3741 
3742  SLfloat metal = m->metalness();
3743  if (ImGui::SliderFloat("Metalness", &metal, 0.0f, 1.0f))
3744  m->metalness(metal);
3745 
3746  ImGui::PopItemWidth();
3747  }
3748  ImGui::TreePop();
3749  }
3750  }
3751  else if (m->reflectionModel() == RM_Particle)
3752  {
3753  if (ImGui::TreeNode("Particle System"))
3754  {
3755  SLParticleSystem* ps = dynamic_cast<SLParticleSystem*>(singleFullMesh); // Need to check if good practice
3756  ImGui::PushItemWidth(ImGui::GetWindowWidth() * 0.5f);
3757  int item_current;
3758 
3759  if (SLGLState::instance()->glHasGeometryShaders())
3760  {
3761  bool drawInstanced = ps->doInstancedDrawing();
3762  if (ImGui::Checkbox("Instanced draw", &drawInstanced))
3763  {
3764  ps->doInstancedDrawing(drawInstanced);
3765  ps->isGenerated(false);
3766  }
3767  }
3768 
3769  // Pause and Resume
3770  bool isPaused = ps->isPaused();
3771  if (isPaused)
3772  {
3773  if (ImGui::Button("Resume"))
3774  ps->pauseOrResume();
3775  }
3776  else
3777  {
3778  if (ImGui::Button("Pause"))
3779  ps->pauseOrResume();
3780  }
3781  ImGui::SameLine();
3782  if (ImGui::Button("Reset"))
3783  ps->isGenerated(false);
3784 
3785  if (ImGui::CollapsingHeader("Emission"))
3786  {
3787  ImGui::Indent();
3788 
3789  // Amount
3790  int amount = ps->amount();
3791  if (ImGui::InputInt("Amount of particles", &amount))
3792  {
3793  if (amount <= 0)
3794  amount = 1;
3795  ps->amount(amount);
3796  ps->isGenerated(false);
3797  }
3798 
3799  // TTL (Time to live)
3800  if (ImGui::CollapsingHeader("Time to live"))
3801  {
3802  ImGui::Indent();
3803 
3804  float timeToLive = ps->timeToLive();
3805  if (ImGui::InputFloat("Time to live (s)", &timeToLive))
3806  {
3807  ps->timeToLive(timeToLive);
3808  ps->isGenerated(false);
3809  singleNode->needAABBUpdate();
3810  }
3811  // Counter bug lag/gap
3812  bool doCounterGap = ps->doCounterGap();
3813  if (ImGui::Checkbox("Counter lag/gap", &doCounterGap))
3814  {
3815  ps->doCounterGap(doCounterGap);
3816  m->programTF(nullptr);
3817  ps->isGenerated(false);
3818  }
3819  ImGui::TextWrapped("Need to be enable by default but can create flickering with few particles, recommend to disable if few particles with no velocity ");
3820 
3821  ImGui::Unindent();
3822  }
3823 
3824  // Billboard
3825  item_current = ps->billboardType();
3826  if (ImGui::Combo("Billboard Type",
3827  &item_current,
3828  "Camera Billboard\0Vertical Billboard\0Horizontal Billboard\0"))
3829  {
3830  ps->billboardType((SLBillboardType)item_current);
3831  m->program(nullptr);
3832  if (item_current == 2)
3833  {
3834  if (!sv->drawBits()->get(SL_DB_CULLOFF))
3836  }
3837  else
3838  {
3839  if (sv->drawBits()->get(SL_DB_CULLOFF))
3841  }
3842  }
3843 
3844  // Shape
3845  SLbool shape_group = ps->doShape();
3846  if (ImGui::Checkbox("Shape", &shape_group))
3847  {
3848  ps->doShape(shape_group);
3849  m->programTF(nullptr);
3850  ps->isGenerated(false);
3851  singleNode->needAABBUpdate();
3852  }
3853  if (ImGui::CollapsingHeader("Shape", &shape_group))
3854  {
3855  ImGui::Indent();
3856  item_current = ps->shapeType();
3857  if (ImGui::Combo("Shape type",
3858  &item_current,
3859  "Sphere\0Box\0Cone\0Pyramid\0"))
3860  {
3861  ps->shapeType((SLShapeType)item_current);
3862  m->programTF(nullptr);
3863  ps->isGenerated(false);
3864  singleNode->needAABBUpdate();
3865  }
3866  if (item_current == ST_Sphere)
3867  {
3868  float radiusSphere = ps->shapeRadius();
3869  if (ImGui::InputFloat("Radius of the sphere", &radiusSphere))
3870  {
3871  ps->shapeRadius(radiusSphere);
3872  ps->isGenerated(false);
3873  singleNode->needAABBUpdate();
3874  }
3875  }
3876  if (item_current == ST_Box)
3877  {
3878  float vec3fScaleBox[3] = {ps->shapeScale().x, ps->shapeScale().y, ps->shapeScale().z};
3879  if (ImGui::InputFloat3("Scale box XYZ", vec3fScaleBox))
3880  {
3881  ps->shapeScale(vec3fScaleBox[0], vec3fScaleBox[1], vec3fScaleBox[2]);
3882  ps->isGenerated(false);
3883  singleNode->needAABBUpdate();
3884  }
3885  }
3886  if (item_current == ST_Cone)
3887  {
3888  float radius = ps->shapeRadius();
3889  if (ImGui::InputFloat("Radius", &radius))
3890  {
3891  ps->shapeRadius(radius);
3892  ps->isGenerated(false);
3893  singleNode->needAABBUpdate();
3894  }
3895  float angle = ps->shapeAngle();
3896  if (ImGui::InputFloat("Angle", &angle))
3897  {
3898  ps->shapeAngle(angle);
3899  ps->isGenerated(false);
3900  singleNode->needAABBUpdate();
3901  }
3902  float height = ps->shapeHeight();
3903  if (ImGui::InputFloat("Height", &height))
3904  {
3905  ps->shapeHeight(height);
3906  ps->isGenerated(false);
3907  singleNode->needAABBUpdate();
3908  }
3909  }
3910  if (item_current == ST_Pyramid)
3911  {
3912  float halfSide = ps->shapeWidth();
3913  if (ImGui::InputFloat("Half side", &halfSide))
3914  {
3915  ps->shapeWidth(halfSide);
3916  ps->isGenerated(false);
3917  singleNode->needAABBUpdate();
3918  }
3919  float angle = ps->shapeAngle();
3920  if (ImGui::InputFloat("Angle", &angle))
3921  {
3922  ps->shapeAngle(angle);
3923  ps->isGenerated(false);
3924  singleNode->needAABBUpdate();
3925  }
3926  float height = ps->shapeHeight();
3927  if (ImGui::InputFloat("Height", &height))
3928  {
3929  ps->shapeHeight(height);
3930  ps->isGenerated(false);
3931  singleNode->needAABBUpdate();
3932  }
3933  }
3934  // Add surface spawning check box
3935  SLbool shapeSurf = ps->doShapeSurface();
3936  if (ImGui::Checkbox("Spawn surface", &shapeSurf))
3937  {
3938  ps->doShapeSurface(shapeSurf);
3939  ps->isGenerated(false);
3940  }
3941  if (item_current == 2 || item_current == 3)
3942  {
3943  SLbool shapeSpawnBase = ps->doShapeSpawnBase();
3944  if (ImGui::Checkbox("Spawn base volume", &shapeSpawnBase))
3945  {
3946  ps->doShapeSpawnBase(shapeSpawnBase);
3947  ps->isGenerated(false);
3948  singleNode->needAABBUpdate();
3949  }
3950  }
3951 
3952  if (!ps->doDirectionSpeed())
3953  ImGui::BeginDisabled();
3954  ImGui::LabelText("Condition", "Need to have direction and speed enabled");
3955  if (item_current == 2 || item_current == 3)
3956  {
3957  SLbool shapeOverride = ps->doShapeOverride();
3958  if (ImGui::Checkbox("Follow shape direction (Override direction)",
3959  &shapeOverride))
3960  {
3961  ps->doShapeOverride(shapeOverride);
3962  ps->isGenerated(false);
3963  singleNode->needAABBUpdate();
3964  }
3965  }
3966  else if (item_current == 0 || item_current == 1)
3967  {
3968  SLbool shapeOverride = ps->doShapeOverride();
3969  if (ImGui::Checkbox("Inverse center direction (Override direction)", &shapeOverride))
3970  {
3971  ps->doShapeOverride(shapeOverride);
3972  ps->isGenerated(false);
3973  singleNode->needAABBUpdate();
3974  }
3975  }
3976 
3977  if (!ps->doDirectionSpeed())
3978  ImGui::EndDisabled();
3979  ImGui::Unindent();
3980  }
3981 
3982  // Flipbook texture
3983  if (ps->texFlipbook())
3984  {
3985  SLbool flipbookTex_group = ps->doFlipBookTexture();
3986  if (ImGui::Checkbox("Flipbook texture", &flipbookTex_group))
3987  {
3988  ps->doFlipBookTexture(flipbookTex_group);
3989  m->program(nullptr);
3990  m->programTF(nullptr);
3991  ps->changeTexture(); // Switch texture
3992  ps->isGenerated(false);
3993  }
3994  if (ImGui::CollapsingHeader("Flipbook texture", &flipbookTex_group))
3995  {
3996  ImGui::Indent();
3997  int fR = ps->frameRateFB();
3998  if (ImGui::InputInt("Frame rate (num update by s)", &fR))
3999  {
4000  ps->frameRateFB(fR);
4001  }
4002  ImGui::Unindent();
4003  }
4004  }
4005 
4006  ImGui::Unindent();
4007  }
4008 
4009  if (ImGui::CollapsingHeader("Size"))
4010  {
4011  ImGui::Indent();
4012 
4013  // Radius and Scale
4014  float radiusW = ps->radiusW();
4015  if (ImGui::InputFloat("Radius width", &radiusW))
4016  {
4017  ps->radiusW(radiusW);
4018  singleNode->needAABBUpdate();
4019  }
4020  float radiusH = ps->radiusH();
4021  if (ImGui::InputFloat("Radius height", &radiusH))
4022  {
4023  ps->radiusH(radiusH);
4024  singleNode->needAABBUpdate();
4025  }
4026  float scale = ps->scale();
4027  if (ImGui::InputFloat("Scale", &scale))
4028  {
4029  ps->scale(scale);
4030  singleNode->needAABBUpdate();
4031  }
4032 
4033  // Size over lifetime
4034  SLbool doSizeOverLT_group = ps->doSizeOverLT();
4035  if (ImGui::Checkbox("Size over lifetime", &doSizeOverLT_group))
4036  {
4037  ps->doSizeOverLT(doSizeOverLT_group);
4038  m->program(nullptr);
4039  singleNode->needAABBUpdate();
4040  }
4041  if (ImGui::CollapsingHeader("Size over lifetime", &doSizeOverLT_group))
4042  {
4043  ImGui::Indent();
4044  SLbool doSizeOverLTCurve_group = ps->doSizeOverLTCurve();
4045  if (ImGui::Checkbox("Custom curve (Unchecked --> Linear function)2", &doSizeOverLTCurve_group))
4046  {
4047  ps->doSizeOverLTCurve(doSizeOverLTCurve_group);
4048  m->program(nullptr);
4049  }
4050  if (ImGui::CollapsingHeader("Bezier curve size", &doSizeOverLTCurve_group))
4051  {
4052  ImGui::Indent();
4053  float* vSize = ps->bezierControlPointSize();
4054  float* staEndSize = ps->bezierStartEndPointSize();
4055  if (ImGui::Bezier("easeInExpo", vSize, staEndSize))
4056  ps->generateBernsteinPSize();
4057  ImGui::Unindent();
4058  }
4059  ImGui::Unindent();
4060  }
4061 
4062  ImGui::Unindent();
4063  }
4064 
4065  if (ImGui::CollapsingHeader("Movement"))
4066  {
4067  ImGui::Indent();
4068 
4069  // World space
4070  SLbool doWorldSpace = ps->doWorldSpace();
4071  if (ImGui::Checkbox("World space", &doWorldSpace))
4072  ps->doWorldSpace(doWorldSpace);
4073 
4074  // Gravity
4075  SLbool doGravity = ps->doGravity();
4076  if (ImGui::Checkbox("Gravity", &doGravity))
4077  {
4078  ps->doGravity(doGravity);
4079  m->programTF(nullptr);
4080  ps->isGenerated(false);
4081  singleNode->needAABBUpdate();
4082  }
4083  if (ImGui::CollapsingHeader("Gravity", &doGravity))
4084  {
4085  ImGui::Indent();
4086  float vec3Gravity[3] = {ps->gravity().x, ps->gravity().y, ps->gravity().z};
4087  if (ImGui::InputFloat3("Gravity XYZ", vec3Gravity))
4088  {
4089  ps->gravity(vec3Gravity[0], vec3Gravity[1], vec3Gravity[2]);
4090  singleNode->needAABBUpdate();
4091  }
4092  ImGui::Unindent();
4093  }
4094 
4095  // Acceleration
4096  SLbool acc_group = ps->doAcc();
4097  if (ImGui::Checkbox("Acceleration", &acc_group))
4098  {
4099  ps->doAcceleration(acc_group);
4100  m->programTF(nullptr);
4101  singleNode->needAABBUpdate();
4102  ps->isGenerated(false);
4103  }
4104  if (ImGui::CollapsingHeader("Acceleration", &acc_group))
4105  {
4106  ImGui::Indent();
4107  if (ps->doAccDiffDir())
4108  ImGui::BeginDisabled();
4109  float accConst = ps->accelerationConst();
4110  if (ImGui::InputFloat("Accelaration constant", &accConst))
4111  {
4112  ps->accConst(accConst);
4113  singleNode->needAABBUpdate();
4114  }
4115  if (ps->doAccDiffDir())
4116  ImGui::EndDisabled();
4117  SLbool accDiffDirection_group = ps->doAccDiffDir();
4118  if (ImGui::Checkbox("Direction vector", &accDiffDirection_group))
4119  {
4120  ps->doAccDiffDir(accDiffDirection_group);
4121  m->programTF(nullptr);
4122  singleNode->needAABBUpdate();
4123  }
4124  if (ImGui::CollapsingHeader("Direction vector", &accDiffDirection_group))
4125  {
4126  float vec3fAcc[3] = {ps->acceleration().x, ps->acceleration().y, ps->acceleration().z};
4127  ImGui::InputFloat3("input float3", vec3fAcc);
4128  ps->acceleration(vec3fAcc[0], vec3fAcc[1], vec3fAcc[2]);
4129  singleNode->needAABBUpdate();
4130  }
4131  ImGui::Unindent();
4132  }
4133 
4134  // Velocity
4135  if (ps->doDirectionSpeed())
4136  ImGui::BeginDisabled();
4137  if (ImGui::CollapsingHeader("Velocity"))
4138  {
4139  ImGui::Indent();
4140  item_current = ps->velocityType();
4141  if (ImGui::Combo("Velocity type", &item_current, "Random axes\0Constant axes\0"))
4142  {
4143  ps->velocityType(item_current);
4144  ps->isGenerated(false);
4145  singleNode->needAABBUpdate();
4146  }
4147  if (item_current == 0)
4148  {
4149  float vec3fVstart[3] = {ps->velocityRndMin().x, ps->velocityRndMin().y, ps->velocityRndMin().z};
4150  if (ImGui::InputFloat3("Min. random XYZ", vec3fVstart))
4151  {
4152  ps->velocityRndMin(vec3fVstart[0], vec3fVstart[1], vec3fVstart[2]);
4153  ps->isGenerated(false);
4154  singleNode->needAABBUpdate();
4155  }
4156  float vec3fVend[3] = {ps->velocityRndMax().x, ps->velocityRndMax().y, ps->velocityRndMax().z};
4157  if (ImGui::InputFloat3("Max. random XYZ", vec3fVend))
4158  {
4159  ps->velocityRndMax(vec3fVend[0], vec3fVend[1], vec3fVend[2]);
4160  ps->isGenerated(false);
4161  singleNode->needAABBUpdate();
4162  }
4163  }
4164  else if (item_current == 1)
4165  {
4166  float vec3fVelocity[3] = {ps->velocityConst().x, ps->velocityConst().y, ps->velocityConst().z};
4167  if (ImGui::InputFloat3("Constant XYZ", vec3fVelocity))
4168  {
4169  ps->velocityConst(vec3fVelocity[0], vec3fVelocity[1], vec3fVelocity[2]);
4170  ps->isGenerated(false);
4171  singleNode->needAABBUpdate();
4172  }
4173  }
4174  ImGui::Unindent();
4175  }
4176  if (ps->doDirectionSpeed())
4177  ImGui::EndDisabled();
4178 
4179  // Direction and speed: Add maybe later mix with velocity
4180  SLbool directionSpeed_group = ps->doDirectionSpeed();
4181  if (ImGui::Checkbox("Direction and Speed", &directionSpeed_group))
4182  {
4183  ps->doDirectionSpeed(directionSpeed_group);
4184  ps->isGenerated(false);
4185  singleNode->needAABBUpdate();
4186  }
4187 
4188  if (ImGui::CollapsingHeader("Direction and Speed", &directionSpeed_group))
4189  {
4190  ImGui::Indent();
4191  float vec3fDirection[3] = {ps->direction().x, ps->direction().y, ps->direction().z}; // Direction
4192  if (ImGui::InputFloat3("Constant XYZ", vec3fDirection))
4193  {
4194  ps->direction(vec3fDirection[0], vec3fDirection[1], vec3fDirection[2]);
4195  ps->isGenerated(false);
4196  singleNode->needAABBUpdate();
4197  }
4198  // Speed
4199  item_current = ps->doSpeedRange() ? 1 : 0;
4200  if (ImGui::Combo("Speed value",
4201  &item_current,
4202  "Constant\0Random between two constants\0"))
4203  {
4204  if (item_current == 1)
4205  ps->doSpeedRange(true);
4206  else
4207  ps->doSpeedRange(false);
4208 
4209  ps->isGenerated(false);
4210  singleNode->needAABBUpdate();
4211  }
4212  if (!ps->doSpeedRange())
4213  {
4214  float speed = ps->speed();
4215  if (ImGui::InputFloat("Constant", &speed))
4216  {
4217  ps->speed(speed);
4218  ps->isGenerated(false);
4219  singleNode->needAABBUpdate();
4220  }
4221  }
4222  else
4223  {
4224  float vec2fRange[2] = {ps->speedRange().x, ps->speedRange().y};
4225  if (ImGui::InputFloat2("Random range Speed", vec2fRange))
4226  {
4227  ps->speedRange(vec2fRange[0], vec2fRange[1]);
4228  ps->isGenerated(false);
4229  singleNode->needAABBUpdate();
4230  }
4231  }
4232 
4233  // Rotation
4234  SLbool rot_group = ps->doRotation();
4235  if (ImGui::Checkbox("Rotation", &rot_group))
4236  {
4237  ps->doRotation(rot_group);
4238  m->program(nullptr);
4239  m->programTF(nullptr);
4240  ps->isGenerated(false);
4241  }
4242  if (ImGui::CollapsingHeader("Rotation", &rot_group))
4243  {
4244  ImGui::Indent();
4245  item_current = ps->doRotRange() ? 1 : 0;
4246  if (ImGui::Combo("Angular velocity value", &item_current, "Constant\0Random between two constants\0"))
4247  {
4248  if (item_current == 1)
4249  ps->doRotRange(true);
4250  else
4251  ps->doRotRange(false);
4252 
4253  m->programTF(nullptr);
4254  ps->isGenerated(false);
4255  }
4256  if (!ps->doRotRange())
4257  {
4258  float angularVelocityConst = ps->angularVelocityConst();
4259  if (ImGui::InputFloat("Constant", &angularVelocityConst))
4260  {
4261  ps->angularVelocityConst(angularVelocityConst);
4262  }
4263  }
4264  else
4265  {
4266  float vec2fRange[2] = {ps->angularVelocityRange().x, ps->angularVelocityRange().y};
4267  if (ImGui::InputFloat2("Random range A.V", vec2fRange))
4268  {
4269  ps->angularVelocityRange(vec2fRange[0], vec2fRange[1]);
4270  ps->isGenerated(false);
4271  }
4272  }
4273  ImGui::Unindent();
4274  }
4275 
4276  ImGui::Unindent();
4277  }
4278 
4279  ImGui::Unindent();
4280  }
4281 
4282  if (ImGui::CollapsingHeader("Color"))
4283  {
4284  ImGui::Indent();
4285 
4286  // Color checkbox
4287  SLbool color_group = ps->doColor();
4288  if (ImGui::Checkbox("Color", &color_group))
4289  {
4290  ps->doColor(color_group);
4291  m->program(nullptr);
4292  }
4293  if (ImGui::CollapsingHeader("Color", &color_group))
4294  {
4295  ImGui::Indent();
4296  // Color blending brightness/glow
4297  SLbool color_bright = ps->doBlendBrightness();
4298  if (ImGui::Checkbox("Glow/Bright (blending effect)", &color_bright))
4299  {
4300  ps->doBlendBrightness(color_bright);
4301  }
4302 
4303  // Color
4304  if (ps->doColorOverLT())
4305  ImGui::BeginDisabled();
4306  ImGuiColorEditFlags cef = ImGuiColorEditFlags_NoInputs;
4307  SLCol4f c = ps->color();
4308  if (ImGui::ColorEdit4("Particle color", (float*)&c, cef))
4309  ps->color(c);
4310  if (ps->doColorOverLT())
4311  ImGui::EndDisabled();
4312 
4313  // Color over lifetime
4314  SLbool doColorOverLT_group = ps->doColorOverLT();
4315 
4316  if (ImGui::Checkbox("Color over lifetime", &doColorOverLT_group))
4317  {
4318  ps->doColorOverLT(doColorOverLT_group);
4319  //ps->colorArr(gradient.cachedValues());
4320  m->program(nullptr);
4321  }
4322 
4323  if (ImGui::CollapsingHeader("Color over lifetime", &doColorOverLT_group))
4324  {
4325  ImGui::Text("Edit gradient colors in the texture section.");
4326  }
4327  ImGui::Unindent();
4328  }
4329 
4330  // Alpha over lifetime
4331  SLbool doAlphaOverL_group = ps->doAlphaOverLT();
4332  if (ImGui::Checkbox("Alpha over lifetime", &doAlphaOverL_group))
4333  {
4334  ps->doAlphaOverLT(doAlphaOverL_group);
4335  m->program(nullptr);
4336  }
4337  if (ImGui::CollapsingHeader("Alpha over lifetime", &doAlphaOverL_group))
4338  {
4339  ImGui::Indent();
4340  SLbool doAlphaOverLCurve_group = ps->doAlphaOverLTCurve();
4341  if (ImGui::Checkbox("Custom curve (Unchecked --> Linear function)", &doAlphaOverLCurve_group))
4342  {
4343  ps->doAlphaOverLTCurve(doAlphaOverLCurve_group);
4344  m->program(nullptr);
4345  }
4346  if (ImGui::CollapsingHeader("Bezier curve alpha", &doAlphaOverLCurve_group))
4347  {
4348  ImGui::Indent();
4349  float* vAlpha = ps->bezierControlPointAlpha();
4350  float* staEndAlpha = ps->bezierStartEndPointAlpha();
4351  if (ImGui::Bezier("easeInExpo", vAlpha, staEndAlpha))
4353  ImGui::Unindent();
4354  }
4355  ImGui::Unindent();
4356  }
4357 
4358  ImGui::Unindent();
4359  }
4360 
4361  ImGui::PopItemWidth();
4362  ImGui::TreePop();
4363  }
4364  }
4365 
4366  // Textures
4367  if (m->numTextures() > 0 && ImGui::TreeNode("Tex", "Textures (%d)", m->numTextures()))
4368  {
4369  for (int tt = 0; tt < TT_numTextureType; ++tt)
4370  for (auto& tex : m->textures((SLTextureType)tt))
4371  showTexInfos(tex);
4372 
4373  ImGui::TreePop();
4374  }
4375 
4376  // Shaders
4377  size_t numShaders = m->program() ? m->program()->shaders().size() : 0;
4378  numShaders += m->programTF() ? m->programTF()->shaders().size() : 0;
4379 
4380  if (numShaders > 0 && ImGui::TreeNode("Shd", "Shaders (%d)", (int)numShaders))
4381  {
4382  if (m->program() != nullptr)
4383  {
4384  for (auto* shd : m->program()->shaders())
4385  {
4386  if (ImGui::TreeNode(shd->name().c_str()))
4387  {
4388  SLchar* text = new char[shd->code().length() + 1];
4389  strcpy(text, shd->code().c_str());
4390  ImGui::InputTextMultiline(shd->name().c_str(),
4391  text,
4392  shd->code().length() + 1,
4393  ImVec2(-1.0f, -1.0f));
4394  ImGui::TreePop();
4395  delete[] text;
4396  }
4397  }
4398  }
4399  if (m->programTF() != nullptr)
4400  {
4401  for (auto* shd : m->programTF()->shaders())
4402  {
4403  if (ImGui::TreeNode(shd->name().c_str()))
4404  {
4405  SLchar* text = new char[shd->code().length() + 1];
4406  strcpy(text, shd->code().c_str());
4407  ImGui::InputTextMultiline(shd->name().c_str(),
4408  text,
4409  shd->code().length() + 1,
4410  ImVec2(-1.0f, -1.0f));
4411  ImGui::TreePop();
4412  delete[] text;
4413  }
4414  }
4415  }
4416 
4417  ImGui::TreePop();
4418  }
4419 
4420  ImGui::TreePop();
4421  }
4422  }
4423  else
4424  {
4425  ImGui::Text("No single single mesh selected.");
4426  }
4427 
4428  ImGui::PopStyleColor();
4429  }
4430  else if (!singleFullMesh && !s->selectedMeshes().empty())
4431  {
4432  // See also SLMesh::handleRectangleSelection
4433  ImGui::Begin("Properties of Selection", &showProperties, ImGuiWindowFlags_AlwaysVerticalScrollbar | ImGuiWindowFlags_NoNavInputs);
4434 
4435  for (auto* selectedNode : s->selectedNodes())
4436  {
4437  if (selectedNode->mesh())
4438  {
4439  ImGui::Text("Node: %s", selectedNode->name().c_str());
4440  SLMesh* selectedMesh = selectedNode->mesh();
4441 
4442  if (!selectedMesh->IS32.empty())
4443  {
4444  ImGui::Text(" Mesh: %s {%u v.}",
4445  selectedMesh->name().c_str(),
4446  (SLuint)selectedMesh->IS32.size());
4447  ImGui::SameLine();
4448  SLstring delBtn = "DEL##" + selectedMesh->name();
4449  if (ImGui::Button(delBtn.c_str()))
4450  {
4451  selectedMesh->deleteSelected(selectedNode);
4452  }
4453  }
4454  }
4455  }
4456 
4457  ImGui::End();
4458  }
4459  else
4460  {
4461  // Nothing is selected
4462  ImGui::Text("There is nothing selected.");
4463  ImGui::Text("");
4464  ImGui::Text("Select a single node by");
4465  ImGui::Text("double-clicking it or");
4466  ImGui::Text("select multiple nodes by");
4467  ImGui::Text("SHIFT-double-clicking them.");
4468  ImGui::Text("");
4469  ImGui::Text("Select partial meshes by");
4470  ImGui::Text("CTRL-LMB rectangle drawing.");
4471  ImGui::Text("");
4472  ImGui::Text("Press ESC to deselect all.");
4473  ImGui::Text("");
4474  ImGui::Text("Be aware that a node may be");
4475  ImGui::Text("flagged as not selectable.");
4476  }
4477  }
4478  else
4479  {
4480  ImGui::Text("Node selection and the");
4481  ImGui::Text("properties of it can only");
4482  ImGui::Text("be shown in the OpenGL");
4483  ImGui::Text("renderer.");
4484  }
4485 
4486  ImGui::End();
4487  ImGui::PopFont();
4488 }
4489 //-----------------------------------------------------------------------------
4490 //! Shows UI infos for a texture
4492 {
4493  // SLfloat lineH = ImGui::GetTextLineHeightWithSpacing();
4494  SLfloat texW = ImGui::GetWindowWidth() - 4 * ImGui::GetTreeNodeToLabelSpacing() - 10;
4495  void* tid = (ImTextureID)(intptr_t)tex->texID();
4496  SLfloat w = (SLfloat)tex->width();
4497  SLfloat h = (SLfloat)tex->height();
4498  SLfloat h_to_w = h / w;
4499 
4500  if (ImGui::TreeNode(tex->name().c_str()))
4501  {
4502  float mbCPU = 0.0f;
4503  for (auto img : tex->images())
4504  mbCPU += (float)img->bytesPerImage();
4505  float mbGPU = (float)tex->bytesOnGPU();
4506  float mbDSK = (float)tex->bytesInFile();
4507 
4508  mbDSK /= 1E6f;
4509  mbCPU /= 1E6f;
4510  mbGPU /= 1E6f;
4511 
4512  ImGui::Text("Size(PX): %dx%dx%d", tex->width(), tex->height(), tex->depth());
4513  ImGui::Text("Size(MB): GPU:%4.2f, CPU:%4.2f, DSK:%4.2f", mbGPU, mbCPU, mbDSK);
4514  ImGui::Text("TexID : %u (%s)", tex->texID(), tex->isTexture() ? "ok" : "not ok");
4515  ImGui::Text("Type : %s", tex->typeName().c_str());
4516  if (!tex->images().empty() && tex->images()[0])
4517  ImGui::Text("Format : %s", tex->images()[0]->formatString().c_str());
4518  else
4519  ImGui::Text("Format : %s", "n/a (GPU only)");
4520 #ifdef SL_BUILD_WITH_KTX
4521  ImGui::Text("Compr. : %s", tex->compressionFormatStr(tex->compressionFormat()).c_str());
4522 #endif
4523  ImGui::Text("Min.Flt : %s", tex->minificationFilterName().c_str());
4524  ImGui::Text("Mag.Flt : %s", tex->magnificationFilterName().c_str());
4525 
4526  if (tex->target() == GL_TEXTURE_2D)
4527  {
4528  if (typeid(*tex) == typeid(SLTexColorLUT))
4529  {
4530  SLTexColorLUT* lut = (SLTexColorLUT*)tex;
4531  if (ImGui::TreeNode("Color Points in Gradient"))
4532  {
4533  showLUTColors(lut);
4534  ImGui::TreePop();
4535  }
4536 
4537  if (ImGui::TreeNode("Alpha Points in Gradient"))
4538  {
4539  for (SLulong a = 0; a < lut->alphas().size(); ++a)
4540  {
4541  ImGui::PushItemWidth(ImGui::GetWindowWidth() * 0.25f);
4542  SLfloat alpha = lut->alphas()[a].alpha;
4543  SLchar label[20];
4544  snprintf(label, sizeof(label), "Alpha %lu", a);
4545  if (ImGui::SliderFloat(label, &alpha, 0.0f, 1.0f, "%3.2f"))
4546  {
4547  lut->alphas()[a].alpha = alpha;
4548  lut->generateTexture();
4549  }
4550  ImGui::SameLine();
4551  snprintf(label, sizeof(label), "Pos. %lu", a);
4552  SLfloat pos = lut->alphas()[a].pos;
4553  if (a > 0 && a < lut->alphas().size() - 1)
4554  {
4555  SLfloat min = lut->alphas()[a - 1].pos +
4556  2.0f / (SLfloat)lut->length();
4557  SLfloat max = lut->alphas()[a + 1].pos -
4558  2.0f / (SLfloat)lut->length();
4559  if (ImGui::SliderFloat(label, &pos, min, max, "%3.2f"))
4560  {
4561  lut->alphas()[a].pos = pos;
4562  lut->generateTexture();
4563  }
4564  }
4565  else
4566  ImGui::Text("%3.2f Pos. %lu", pos, a);
4567 
4568  ImGui::PopItemWidth();
4569  }
4570 
4571  ImGui::TreePop();
4572  }
4573 
4574  ImGui::Image(tid,
4575  ImVec2(texW, texW * 0.15f),
4576  ImVec2(0, 1),
4577  ImVec2(1, 0),
4578  ImVec4(1, 1, 1, 1),
4579  ImVec4(1, 1, 1, 1));
4580 
4581  SLVfloat allAlpha = lut->allAlphas();
4582  ImGui::PlotLines("",
4583  allAlpha.data(),
4584  (SLint)allAlpha.size(),
4585  0,
4586  nullptr,
4587  0.0f,
4588  1.0f,
4589  ImVec2(texW, texW * 0.25f));
4590  }
4591  else
4592  {
4593  ImGui::Image(tid,
4594  ImVec2(texW, texW * h_to_w),
4595  ImVec2(0, 1),
4596  ImVec2(1, 0),
4597  ImVec4(1, 1, 1, 1),
4598  ImVec4(1, 1, 1, 1));
4599  }
4600  }
4601  else
4602  {
4603  if (tex->target() == GL_TEXTURE_CUBE_MAP)
4604  ImGui::Text("Cube maps can not be displayed.");
4605  else if (tex->target() == GL_TEXTURE_3D)
4606  ImGui::Text("3D textures can not be displayed.");
4607  }
4608 
4609  ImGui::TreePop();
4610  }
4611 }
4612 //-----------------------------------------------------------------------------
4613 //! Loads the UI configuration
4615 {
4616  ImGuiStyle& style = ImGui::GetStyle();
4617  SLstring fullPathAndFilename = AppCommon::configPath +
4618  AppCommon::name + ".yml";
4619 
4620  if (!SLFileStorage::exists(fullPathAndFilename, IOK_config))
4621  {
4622  SL_LOG("No config file %s: ", fullPathAndFilename.c_str());
4623 
4624  // Scale for proportional and fixed size fonts
4625  SLfloat dpiScaleProp = (float)dotsPerInch / 142.0f;
4626  SLfloat dpiScaleFixed = (float)dotsPerInch / 142.0f;
4627 
4628  // Default settings for the first time
4629  SLImGui::fontPropDots = std::max(16.0f * dpiScaleProp, 16.0f);
4630  SLImGui::fontFixedDots = std::max(13.0f * dpiScaleFixed, 13.0f);
4631 
4632  // Store dialog show states
4633  AppDemoGui::showAbout = true;
4644 
4645  // Adjust UI padding on DPI
4646  style.WindowPadding.x = style.FramePadding.x = style.ItemInnerSpacing.x = std::max(8.0f * dpiScaleFixed, 8.0f);
4647  style.FramePadding.y = style.ItemInnerSpacing.y = std::max(4.0f * dpiScaleFixed, 4.0f);
4648  style.WindowPadding.y = style.ItemSpacing.y * 3;
4649  style.ScrollbarSize = std::max(16.0f * dpiScaleFixed, 16.0f);
4650 
4651  // HSM4: Bugfix in some unknown cases ScrollbarSize gets INT::MIN
4652  if (style.ScrollbarSize < 0.0f)
4653  style.ScrollbarSize = 16.0f;
4654 
4655  style.ScrollbarRounding = std::floor(style.ScrollbarSize / 2);
4656  }
4657  else
4658  {
4659  try
4660  {
4661  SLstring configString = SLFileStorage::readIntoString(fullPathAndFilename, IOK_config);
4662  CVFileStorage fs(configString, CVFileStorage::READ | CVFileStorage::MEMORY);
4663 
4664  if (fs.isOpened())
4665  {
4666  // clang-format off
4667  SLint i = 0;
4668  SLbool b = false;
4669  fs["configTime"] >> AppDemoGui::configTime;
4670  fs["fontPropDots"] >> i; SLImGui::fontPropDots = (SLfloat) i;
4671  fs["fontFixedDots"] >> i; SLImGui::fontFixedDots = (SLfloat) i;
4672  fs["ItemSpacingX"] >> i; style.ItemSpacing.x = (SLfloat) i;
4673  fs["ItemSpacingY"] >> i; style.ItemSpacing.y = (SLfloat) i;
4674  style.WindowPadding.x = style.FramePadding.x = style.ItemInnerSpacing.x = style.ItemSpacing.x;
4675  style.FramePadding.y = style.ItemInnerSpacing.y = style.ItemSpacing.y;
4676  style.WindowPadding.y = style.ItemSpacing.y * 3;
4677  fs["ScrollbarSize"] >> i; style.ScrollbarSize = (SLfloat) i;
4678  // HSM4: Bugfix in some unknown cases ScrollbarSize gets INT::MIN
4679  if (style.ScrollbarSize < 0.0f)
4680  style.ScrollbarSize = 16.0f;
4681 
4682  fs["ScrollbarRounding"] >> i; style.ScrollbarRounding = (SLfloat) i;
4683  fs["sceneID"] >> i; AppCommon::sceneID = (SLSceneID) i;
4684  fs["showInfosScene"] >> b; AppDemoGui::showInfosScene = b;
4685  fs["showStatsTiming"] >> b; AppDemoGui::showStatsTiming = b;
4686  fs["showStatsMemory"] >> b; AppDemoGui::showStatsScene = b;
4687  fs["showStatsVideo"] >> b; AppDemoGui::showStatsVideo = b;
4688  fs["showStatsWAI"] >> b; AppDemoGui::showStatsWAI = b;
4689  fs["showInfosFrameworks"] >> b; AppDemoGui::showInfosDevice = b;
4690  fs["showInfosSensors"] >> b; AppDemoGui::showInfosSensors = b;
4691  fs["showSceneGraph"] >> b; AppDemoGui::showSceneGraph = b;
4692  fs["showProperties"] >> b; AppDemoGui::showProperties = b;
4693  fs["showErlebAR"] >> b; AppDemoGui::showErlebAR = b;
4694  fs["showTransform"] >> b; AppDemoGui::showTransform = b;
4695  fs["showUIPrefs"] >> b; AppDemoGui::showUIPrefs = b;
4696  fs["showDateAndTime"] >> b; AppDemoGui::showDateAndTime = b;
4697  fs["showDockSpace"] >> b; AppDemoGui::showDockSpace = b;
4698  // clang-format on
4699 
4700  fs.release();
4701  SL_LOG("Config. loaded : %s", fullPathAndFilename.c_str());
4702  SL_LOG("Config. date : %s", AppDemoGui::configTime.c_str());
4703  SL_LOG("fontPropDots : %f", SLImGui::fontPropDots);
4704  SL_LOG("fontFixedDots : %f", SLImGui::fontFixedDots);
4705  }
4706  else
4707  {
4708  SL_LOG("****** Failed to open file for reading: %s", fullPathAndFilename.c_str());
4709  }
4710  }
4711  catch (...)
4712  {
4713  SL_LOG("****** Parsing of file failed: %s", fullPathAndFilename.c_str());
4714  }
4715 
4716  // check font sizes for HDPI displays
4717  if (dotsPerInch > 300)
4718  {
4719  if (SLImGui::fontPropDots < 16.1f &&
4720  SLImGui::fontFixedDots < 13.1)
4721  {
4722  // Scale for proportional and fixed size fonts
4723  SLfloat dpiScaleProp = (float)dotsPerInch / 120.0f;
4724  SLfloat dpiScaleFixed = (float)dotsPerInch / 142.0f;
4725 
4726  // Default settings for the first time
4727  SLImGui::fontPropDots = std::max(16.0f * dpiScaleProp, 16.0f);
4728  SLImGui::fontFixedDots = std::max(13.0f * dpiScaleFixed, 13.0f);
4729  }
4730  }
4731  }
4732 
4733 #ifdef SL_EMSCRIPTEN
4734  // Overwrite config with URL parameters
4735  // clang-format off
4736  int sceneId = EM_ASM_INT(
4737  let params = new URL(window.location).searchParams;
4738  return params.get("scene") ?? -1;
4739  );
4740  // clang-format on
4741 
4742  if (sceneId != -1)
4743  AppCommon::sceneID = (SLSceneID)sceneId;
4744 #endif
4745 }
4746 //-----------------------------------------------------------------------------
4747 //! Stores the UI configuration
4749 {
4750  ImGuiStyle& style = ImGui::GetStyle();
4751  SLstring fullPathAndFilename = AppCommon::configPath +
4752  AppCommon::name + ".yml";
4753 
4754  if (!SLFileStorage::exists(fullPathAndFilename, IOK_config))
4755  SL_LOG("New config file will be written: %s",
4756  fullPathAndFilename.c_str());
4757 
4758  CVFileStorage fs(fullPathAndFilename,
4759  CVFileStorage::WRITE | CVFileStorage::MEMORY);
4760 
4761  if (!fs.isOpened())
4762  {
4763  SL_LOG("Failed to open file for writing: %s",
4764  fullPathAndFilename.c_str());
4765  SL_EXIT_MSG("Exit in AppDemoGui::saveConfig");
4766  }
4767 
4768  fs << "configTime" << Utils::getLocalTimeString();
4769  fs << "fontPropDots" << (SLint)SLImGui::fontPropDots;
4770  fs << "fontFixedDots" << (SLint)SLImGui::fontFixedDots;
4773  fs << "sceneID" << (SLint)SID_Minimal;
4774  else
4775  fs << "sceneID" << (SLint)AppCommon::sceneID;
4776  fs << "ItemSpacingX" << (SLint)style.ItemSpacing.x;
4777  fs << "ItemSpacingY" << (SLint)style.ItemSpacing.y;
4778  fs << "ScrollbarSize" << (SLfloat)style.ScrollbarSize;
4779  fs << "ScrollbarRounding" << (SLfloat)style.ScrollbarRounding;
4780  fs << "showStatsTiming" << AppDemoGui::showStatsTiming;
4781  fs << "showStatsMemory" << AppDemoGui::showStatsScene;
4782  fs << "showStatsVideo" << AppDemoGui::showStatsVideo;
4783  fs << "showStatsWAI" << AppDemoGui::showStatsWAI;
4784  fs << "showInfosFrameworks" << AppDemoGui::showInfosDevice;
4785  fs << "showInfosScene" << AppDemoGui::showInfosScene;
4786  fs << "showInfosSensors" << AppDemoGui::showInfosSensors;
4787  fs << "showSceneGraph" << AppDemoGui::showSceneGraph;
4788  fs << "showProperties" << AppDemoGui::showProperties;
4789  fs << "showErlebAR" << AppDemoGui::showErlebAR;
4790  fs << "showTransform" << AppDemoGui::showTransform;
4791  fs << "showUIPrefs" << AppDemoGui::showUIPrefs;
4792  fs << "showDateAndTime" << AppDemoGui::showDateAndTime;
4793  fs << "showDockSpace" << AppDemoGui::showDockSpace;
4794 
4795  std::string configString = fs.releaseAndGetString();
4796  SLFileStorage::writeString(fullPathAndFilename,
4797  IOK_config,
4798  configString);
4799  SL_LOG("Config. saved : %s", fullPathAndFilename.c_str());
4800 }
4801 //-----------------------------------------------------------------------------
4802 //! Adds a transform node for the selected node and toggles the edit mode
4804  SLSceneView* sv,
4805  SLNodeEditMode editMode)
4806 {
4807  SLTransformNode* tN = s->root3D()->findChild<SLTransformNode>("Edit Gizmos");
4808 
4809  if (!tN)
4810  {
4811  tN = new SLTransformNode(sv,
4812  s->singleNodeSelected(),
4814  s->root3D()->addChild(tN);
4815  }
4816 
4817  tN->editMode(editMode);
4818  transformNode = tN;
4819 }
4820 //-----------------------------------------------------------------------------
4821 //! Searches and removes the transform node
4823 {
4824  SLTransformNode* tN = s->root3D()->findChild<SLTransformNode>("Edit Gizmos");
4825  if (tN)
4826  {
4827  auto it = find(s->eventHandlers().begin(),
4828  s->eventHandlers().end(),
4829  tN);
4830  if (it != s->eventHandlers().end())
4831  s->eventHandlers().erase(it);
4832 
4833  s->root3D()->deleteChild(tN);
4834 
4835  // Reset currentMaterial pointer that have pointed to temp. materials of transform nodes
4837  }
4838  transformNode = nullptr;
4839 }
4840 //-----------------------------------------------------------------------------
4841 //! Enables calculation and visualization of horizon line (using rotation sensors)
4843 {
4844  assert(s->assetManager() && "No asset manager assigned to scene!");
4845  SLAssetManager* am = s->assetManager();
4846 
4847  // todo: why is root2D not always valid?
4848  if (!s->root2D())
4849  {
4850  SLNode* scene2D = new SLNode("root2D");
4851  s->root2D(scene2D);
4852  }
4853 
4854  SLstring horizonName = "Horizon";
4855  SLHorizonNode* horizonNode = s->root2D()->findChild<SLHorizonNode>(horizonName);
4856 
4857  if (!horizonNode)
4858  {
4859  horizonNode = new SLHorizonNode(horizonName,
4861  am->font16,
4863  sv->scrW(),
4864  sv->scrH());
4865  s->root2D()->addChild(horizonNode);
4866  _horizonVisuEnabled = true;
4867  }
4868 }
4869 //-----------------------------------------------------------------------------
4870 //! Disables calculation and visualization of horizon line
4872 {
4873  if (s->root2D())
4874  {
4875  SLstring horizonName = "Horizon";
4876  SLHorizonNode* horizonNode = s->root2D()->findChild<SLHorizonNode>(horizonName);
4877  if (horizonNode)
4878  {
4879  s->root2D()->deleteChild(horizonNode);
4880  }
4881  }
4882  _horizonVisuEnabled = false;
4883 }
4884 //-----------------------------------------------------------------------------
4885 //! Displays a editable color lookup table wit ImGui widgets
4887 {
4888  ImGuiColorEditFlags cef = ImGuiColorEditFlags_NoInputs;
4889  for (SLulong c = 0; c < lut->colors().size(); ++c)
4890  {
4891  SLCol3f color = lut->colors()[c].color;
4892  SLchar label[20];
4893  snprintf(label, sizeof(label), "Color %lu", c);
4894  if (ImGui::ColorEdit3(label, (float*)&color, cef))
4895  {
4896  lut->colors()[c].color = color;
4897  lut->generateTexture();
4898  }
4899  ImGui::SameLine();
4900  ImGui::PushItemWidth(ImGui::GetWindowWidth() * 0.5f);
4901  snprintf(label, sizeof(label), "Pos. %lu", c);
4902  SLfloat pos = lut->colors()[c].pos;
4903  if (c > 0 && c < lut->colors().size() - 1)
4904  {
4905  SLfloat min = lut->colors()[c - 1].pos + 2.0f / (SLfloat)lut->length();
4906  SLfloat max = lut->colors()[c + 1].pos - 2.0f / (SLfloat)lut->length();
4907  if (ImGui::SliderFloat(label, &pos, min, max, "%3.2f"))
4908  {
4909  lut->colors()[c].pos = pos;
4910  lut->generateTexture();
4911  }
4912  }
4913  else
4914  ImGui::Text("%3.2f Pos. %lu", pos, c);
4915  ImGui::PopItemWidth();
4916  }
4917 }
4918 //-----------------------------------------------------------------------------
4920  SLSceneView* sv,
4921  string downloadFilename,
4922  string filenameToLoad,
4923  SLSceneID sceneIDToLoad)
4924 {
4925  SLstring pathSrc = "https://pallas.ti.bfh.ch/data/SLProject/models/";
4926  SLstring pathDst = AppCommon::configPath + "models/";
4927 
4928 #ifndef SL_EMSCRIPTEN
4929  if (Utils::fileExists(filenameToLoad))
4930  AppCommon::sceneToLoad = sceneIDToLoad;
4931  else
4932  downloadModelAndLoadScene(s, sv, downloadFilename, pathSrc, pathDst, filenameToLoad, sceneIDToLoad);
4933 #else
4934  AppCommon::sceneToLoad = sceneIDToLoad;
4935 #endif
4936 }
4937 //-----------------------------------------------------------------------------
4938 //! Parallel HTTP download, unzip and load scene job scheduling
4940  SLSceneView* sv,
4941  string downloadFilename,
4942  string urlFolder,
4943  string dstFolder,
4944  string pathAndFileToLoad,
4945  SLSceneID sceneIDToLoad)
4946 {
4947 #ifndef SL_EMSCRIPTEN
4948  assert(s->assetManager() && "No asset manager assigned to scene!");
4949  SLAssetManager* am = s->assetManager();
4950 
4951  auto progressCallback = [](size_t curr, size_t filesize)
4952  {
4953  if (filesize > 0)
4954  {
4955  int transferredPC = (int)((float)curr / (float)filesize * 100.0f);
4956  AppCommon::jobProgressNum(transferredPC);
4957  }
4958  else
4959  cout << "Bytes transferred: " << curr << endl;
4960 
4961  return 0; // Return Non-Zero to cancel
4962  };
4963 
4964  auto downloadJobHTTP = [=]()
4965  {
4966  PROFILE_FUNCTION();
4967  string jobMsg = "Downloading file via HTTPS: " + downloadFilename;
4968  AppCommon::jobProgressMsg(jobMsg);
4970  string fileToDownload = urlFolder + downloadFilename;
4971  if (HttpUtils::download(fileToDownload, dstFolder, progressCallback) != 0)
4972  {
4973  SL_LOG("*** Nothing downloaded from: %s ***", fileToDownload.c_str());
4974  SL_LOG("*** PLEASE RETRY DOWNLOAD ***", fileToDownload.c_str());
4975  }
4976  AppCommon::jobIsRunning = false;
4977  };
4978 
4979  auto unzipJob = [=]()
4980  {
4981  string jobMsg = "Decompressing file: " + downloadFilename;
4982  AppCommon::jobProgressMsg(jobMsg);
4984  string zipFile = dstFolder + downloadFilename;
4985  if (Utils::fileExists(zipFile))
4986  {
4987  string extension = Utils::getFileExt(zipFile);
4988  if (extension == "zip")
4989  {
4990  ZipUtils::unzip(zipFile, Utils::getPath(zipFile));
4991  Utils::deleteFile(zipFile);
4992  }
4993  }
4994  else
4995  SL_LOG("*** File do decompress doesn't exist: %s ***",
4996  zipFile.c_str());
4997  AppCommon::jobIsRunning = false;
4998  };
4999 
5000  auto followUpJob1 = [=]()
5001  {
5002  if (Utils::fileExists(pathAndFileToLoad))
5003  AppCommon::sceneToLoad = sceneIDToLoad;
5004  else
5005  SL_LOG("*** File do load doesn't exist: %s ***",
5006  pathAndFileToLoad.c_str());
5007  };
5008 
5009  AppCommon::jobsToBeThreaded.emplace_back(downloadJobHTTP);
5010  AppCommon::jobsToBeThreaded.emplace_back(unzipJob);
5011  AppCommon::jobsToFollowInMain.push_back(followUpJob1);
5012 #endif
5013 }
5014 //-----------------------------------------------------------------------------
5015 //! Set the a new active named location from SLDeviceLocation
5017  SLSceneView* sv,
5018  SLVec3f lookAtPoint)
5019 {
5021 
5022 #if !defined(SL_OS_MACIOS) && !defined(SL_OS_ANDROID)
5024  SLVec3f pos_f((SLfloat)pos_d.x, (SLfloat)pos_d.y + 1.7f, (SLfloat)pos_d.z);
5025  SLCamera* cam = sv->camera();
5026  cam->translation(pos_f);
5027  SLVec3f camToLookAt = pos_f - lookAtPoint;
5028  cam->focalDist(camToLookAt.length());
5029  cam->lookAt(lookAtPoint);
5031 #endif
5032 }
5033 //-----------------------------------------------------------------------------
The AppCommon class holds the top-level instances of the app-demo.
static SLNode * chrAlt
Definition: AppDemoGui.cpp:138
void centerNextWindow(SLSceneView *sv, SLfloat widthPC=0.9f, SLfloat heightPC=0.9f)
Centers the next ImGui window in the parent.
Definition: AppDemoGui.cpp:95
bool myComboBox(const char *label, int *currIndex, SLVstring &values)
Combobox that allows to pass the items as a string vector.
Definition: AppDemoGui.cpp:82
CVCalibration guessCalibration(bool mirroredH, bool mirroredV, CVCameraType camType)
int ftpCallbackXfer(off64_t xfered, void *arg)
Definition: AppDemoGui.cpp:204
SLGLTexture * gTexMRI3D
static SLNode * balda_stahl
Definition: AppDemoGui.cpp:136
static SLNode * bern
Definition: AppDemoGui.cpp:135
static auto vectorGetter
Vector getter callback for combo and listbox with std::vector<std::string>
Definition: AppDemoGui.cpp:69
SLNode * gDragonModel
static SLNode * balda_glas
Definition: AppDemoGui.cpp:137
SLNode * gVideoTrackedNode
static SLTransformNode * transformNode
Definition: AppDemoGui.cpp:142
static SLNode * chrNeu
Definition: AppDemoGui.cpp:139
off64_t ftpXferSizeMax
Definition: AppDemoGui.cpp:200
CVTracked * gVideoTracker
C++ Header file for the class AppDemoGui.h.
Definition of scene IDs in the demo app.
@ SID_SuzannePerPixBlinnNmSm
@ SID_Benchmark_SkinnedAnimations
@ SID_TextureBlend
@ SID_Minimal
@ SID_glTF_Sponza
@ SID_VideoTrackChessScnd
@ SID_ParticleSystem_Many
@ SID_SuzannePerPixBlinnTmAo
@ SID_VideoTrackMediaPipeHandsMain
@ SID_Benchmark_LargeModel
@ SID_SuzannePerPixBlinnTmSm
@ SID_SuzannePerPixBlinnAoSm
@ SID_ErlebAR_BielCBB
@ SID_ParticleSystem_ComplexFire
@ SID_ParticleSystem_RingOfFire
@ SID_ShaderSkybox
@ SID_RTSoftShadows
@ SID_Figure
@ SID_SuzannePerPixBlinnNm
@ SID_ShadowMappingSpotLights
@ SID_VideoTrackFaceScnd
@ SID_RTSpheres
@ SID_VideoSensorAR
@ SID_ErlebAR_BielBFH
@ SID_ErlebAR_BernChristoffel
@ SID_PointClouds
@ SID_ParticleSystem_DustStorm
@ SID_Revolver
@ SID_SuzannePerPixBlinnNmAo
@ SID_ShaderEarth
@ SID_VolumeRayCast
@ SID_VideoTextureLive
@ SID_AnimationNode
@ SID_ParticleSystem_Simple
@ SID_VideoCalibrateScnd
@ SID_Benchmark_JansUniverse
@ SID_Benchmark_ColumnsNoLOD
@ SID_MeshLoad
@ SID_ParticleSystem_Fountain
@ SID_SuzannePerPixBlinnSm
@ SID_ShadowMappingLightTypes
@ SID_AnimationSkinnedMass
@ SID_VideoTextureFile
@ SID_SuzannePerPixBlinnTmNmSm
@ SID_ShaderPerPixelBlinn
@ SID_ZFighting
@ SID_SuzannePerPixBlinnTm
@ SID_ErlebAR_AventicumAmphiteatre
@ SID_Empty
@ SID_Benchmark_NodeAnimations
@ SID_Benchmark_ColumnsLOD
@ SID_ShadowMappingCascaded
@ SID_SuzannePerPixBlinnTmNmAoSm
@ SID_SuzannePerPixCookTmNmAoSmEm
@ SID_ErlebAR_AventicumCigognier
@ SID_glTF_DamagedHelmet
@ SID_SuzannePerPixBlinn
@ SID_ShaderIBL
@ SID_ShadowMappingPointLights
@ SID_VideoTrackArucoMain
@ SID_glTF_FlightHelmet
@ SID_TextureFilter
@ SID_RTLens
@ SID_Benchmark_ParticleSystemComplexFire
@ SID_Benchmark_LotsOfNodes
@ SID_VideoTrackArucoScnd
@ SID_SuzannePerPixBlinnTmNmAo
@ SID_VideoTrackFeature2DMain
@ SID_ParticleSystem_Sun
@ SID_MaxPublicAssets
@ SID_VolumeRayCastLighted
@ SID_ErlebAR_AventicumTheatre
@ SID_ShadowMappingBasicScene
@ SID_2Dand3DText
@ SID_VideoTrackFaceMain
@ SID_VideoCalibrateMain
@ SID_VideoTrackChessMain
@ SID_ShaderBumpParallax
@ SID_ShaderPerPixelCook
@ SID_ShaderWave
@ SID_SuzannePerPixBlinnAo
@ SID_SuzannePerPixBlinnTmNm
@ SID_ErlebAR_AugustaRauricaTmpTht
@ SID_ErlebAR_SutzKirchrain18
@ SID_TextureCompression
@ SID_ShaderBumpNormal
@ SID_Robotics_FanucCRX_FK
@ SID_glTF_WaterBottle
@ SID_FrustumCull
@ SID_VideoTrackWAI
@ SID_ShaderPerVertexBlinn
@ SID_RTMuttenzerBox
@ SID_AnimationNodeMass
@ SID_AnimationSkinned
@ SID_RTDoF
static GLFWwindow * window
The global glfw window handle.
Definition: AppGLFW.cpp:35
static SLbool fixAspectRatio
Flag if wnd aspect ratio should be fixed.
Definition: AppGLFW.cpp:42
@ CS_calibrated
The camera is calibrated.
Definition: CVCalibration.h:33
CVVideoType
Video type if multiple exist on mobile devices.
Definition: CVCapture.h:40
@ VT_SCND
Selfie camera on mobile devices.
Definition: CVCapture.h:43
@ VT_FILE
Loads a video from file with OpenCV.
Definition: CVCapture.h:44
@ VT_NONE
No camera needed.
Definition: CVCapture.h:41
@ VT_MAIN
Main camera on all on all all devices.
Definition: CVCapture.h:42
CVDetectDescribeType
Feature detector-decriptor types.
@ DDT_ORB_ORB
@ DDT_SURF_SURF
@ DDT_FAST_BRIEF
@ DDT_SIFT_SIFT
@ DDT_RAUL_RAUL
cv::FileStorage CVFileStorage
Definition: CVTypedefs.h:61
cv::Size CVSize
Definition: CVTypedefs.h:55
CVCameraType
Definition: CVTypes.h:62
#define PROFILE_SCOPE(name)
Definition: Instrumentor.h:40
#define PROFILE_FUNCTION()
Definition: Instrumentor.h:41
#define PROFILE_THREAD(name)
Definition: Profiler.h:38
float SLfloat
Definition: SL.h:173
#define SL_LOG(...)
Definition: SL.h:233
unsigned long SLulong
Definition: SL.h:165
unsigned int SLuint
Definition: SL.h:171
char SLchar
Definition: SL.h:162
bool SLbool
Definition: SL.h:175
vector< SLfloat > SLVfloat
Definition: SL.h:200
vector< SLstring > SLVstring
Definition: SL.h:201
#define SL_EXIT_MSG(message)
Definition: SL.h:240
string SLstring
Definition: SL.h:158
int SLint
Definition: SL.h:170
SLLocOffsetMode
Device location offset mode.
@ LOM_none
@ LOM_twoFingerY
Mobile device rotation class declaration.
SLRotOffsetMode
Device rotation offset mode.
@ ROM_oneFingerX
@ ROM_none
@ ROM_oneFingerXY
#define SL_DB_ONLYEDGES
Draw only hard edges.
Definition: SLDrawBits.h:31
#define SL_DB_NORMALS
Draw the vertex normals.
Definition: SLDrawBits.h:23
#define SL_DB_SKELETON
Draw the skeletons joints.
Definition: SLDrawBits.h:27
#define SL_DB_WITHEDGES
Draw faces with hard edges.
Definition: SLDrawBits.h:30
#define SL_DB_AXIS
Draw the coordinate axis of a node.
Definition: SLDrawBits.h:25
#define SL_DB_NOTSELECTABLE
Flags an object as selected.
Definition: SLDrawBits.h:21
#define SL_DB_BRECT
Draw the bounding rectangle of a node.
Definition: SLDrawBits.h:32
#define SL_DB_VOXELS
Draw the voxels of the uniform grid.
Definition: SLDrawBits.h:26
#define SL_DB_GPU_SKINNING
Perform skinning on the GPU.
Definition: SLDrawBits.h:33
#define SL_DB_CULLOFF
Turn off face culling.
Definition: SLDrawBits.h:28
#define SL_DB_MESHWIRED
Draw polygons as wired mesh.
Definition: SLDrawBits.h:22
#define SL_DB_BBOX
Draw the bounding boxes of a node.
Definition: SLDrawBits.h:24
#define SL_DB_HIDDEN
Flags an object as hidden.
Definition: SLDrawBits.h:20
SLCamAnim
Enumeration for available camera animation types.
Definition: SLEnums.h:121
@ CA_turntableYUp
Orbiting around central object w. turntable rotation around y & right axis.
Definition: SLEnums.h:122
@ CA_walkingYUp
Walk translation with AWSD and look around rotation around y & right axis.
Definition: SLEnums.h:125
@ CA_deviceRotLocYUp
The device rotation controls the camera rotation and the GPS controls the Camera Translation.
Definition: SLEnums.h:128
@ CA_trackball
Orbiting around central object w. one rotation around one axis.
Definition: SLEnums.h:124
@ CA_deviceRotYUp
The device rotation controls the camera rotation.
Definition: SLEnums.h:127
@ CA_turntableZUp
Orbiting around central object w. turntable rotation around z & right axis.
Definition: SLEnums.h:123
@ CA_walkingZUp
Walk translation with AWSD and look around rotation around z & right axis.
Definition: SLEnums.h:126
SLProjType
Enumeration for different camera projections.
Definition: SLEnums.h:134
@ P_monoPerspective
standard mono pinhole perspective projection
Definition: SLEnums.h:135
@ P_stereoSideBySideD
side-by-side distorted for Oculus Rift like glasses
Definition: SLEnums.h:140
@ P_stereoSideBySide
side-by-side
Definition: SLEnums.h:138
@ P_stereoColorYB
color masking for yellow-blue anaglyphs (ColorCode 3D)
Definition: SLEnums.h:147
@ P_monoOrthographic
standard mono orthographic projection
Definition: SLEnums.h:137
int SLSceneID
Scene identifier.
Definition: SLEnums.h:91
SLRenderType
Rendering type enumeration.
Definition: SLEnums.h:69
@ RT_rt
Ray Tracing.
Definition: SLEnums.h:71
@ RT_pt
Path Tracing.
Definition: SLEnums.h:72
@ RT_gl
OpenGL.
Definition: SLEnums.h:70
@ RT_optix_pt
Path Tracing with OptiX.
Definition: SLEnums.h:74
@ RT_optix_rt
Ray Tracing with OptiX.
Definition: SLEnums.h:73
SLEasingCurve
Enumeration for animation easing curves.
Definition: SLEnums.h:180
SLTransformSpace
Describes the relative space a transformation is applied in.
Definition: SLEnums.h:206
@ TS_world
Definition: SLEnums.h:208
@ TS_parent
Definition: SLEnums.h:209
@ TS_object
Definition: SLEnums.h:210
SLShapeType
Particle system shape type.
Definition: SLEnums.h:279
@ ST_Sphere
Definition: SLEnums.h:280
@ ST_Pyramid
Definition: SLEnums.h:283
@ ST_Box
Definition: SLEnums.h:281
@ ST_Cone
Definition: SLEnums.h:282
@ RM_BlinnPhong
Definition: SLEnums.h:289
@ RM_Particle
Definition: SLEnums.h:291
@ RM_CookTorrance
Definition: SLEnums.h:290
@ FM_exp
Definition: SLEnums.h:265
@ FM_exp2
Definition: SLEnums.h:266
@ FM_linear
Definition: SLEnums.h:264
@ VA_leftOrBottom
Definition: SLEnums.h:256
@ VA_center
Definition: SLEnums.h:255
SLBillboardType
Billboard type for its orientation used in SLParticleSystem.
Definition: SLEnums.h:271
@ IOK_config
Definition: SLFileStorage.h:44
Uses an OpenGL framebuffer object as a depth-buffer.
SLStdShaderProg
Enumeration for standard shader programs.
SLTextureType
Texture type enumeration & their filename appendix for auto type detection.
Definition: SLGLTexture.h:76
@ TT_numTextureType
Definition: SLGLTexture.h:95
Wrapper Class around the external ImGui GUI-framework.
bool slShouldClose()
Declaration of the main Scene Library C-Interface.
deque< SLNode * > SLVNode
SLVNode typedef for a vector of SLNodes.
Definition: SLNode.h:27
@ rtFinished
Definition: SLRaytracer.h:31
@ rtReady
Definition: SLRaytracer.h:29
Declares a color look up table functionality.
SLNodeEditMode
@ NodeEditMode_Translate
@ NodeEditMode_Scale
@ NodeEditMode_Rotate
SLVec2< SLint > SLVec2i
Definition: SLVec2.h:140
static SLstring version
SLProject version string.
Definition: AppCommon.h:74
static SLDeviceRotation devRot
Mobile device rotation from IMU.
Definition: AppCommon.h:64
static int jobProgressMax()
Definition: AppCommon.h:99
static SLstring name
Application name.
Definition: AppCommon.h:72
static deque< function< void(void)> > jobsToBeThreaded
Queue of functions to be executed in a thread.
Definition: AppCommon.h:102
static SLstring configPath
Default path for calibration files.
Definition: AppCommon.h:81
static optional< SLSceneID > sceneToLoad
Scene id to load at start up.
Definition: AppCommon.h:90
static string jobProgressMsg()
Thread-safe getter of the progress message.
Definition: AppCommon.cpp:392
static SLAssetManager * assetManager
asset manager is the owner of all assets
Definition: AppCommon.h:59
static SLstring gitCommit
Current GIT commit short hash id.
Definition: AppCommon.h:78
static atomic< bool > jobIsRunning
True if a parallel job is running.
Definition: AppCommon.h:104
static SLDeviceLocation devLoc
Mobile device location from GPS.
Definition: AppCommon.h:65
static SLstring gitBranch
Current GIT branch.
Definition: AppCommon.h:77
static int jobProgressNum()
Definition: AppCommon.h:98
static deque< function< void(void)> > jobsToFollowInMain
Queue of function to follow in the main thread.
Definition: AppCommon.h:103
static CVCalibrationEstimatorParams calibrationEstimatorParams
Definition: AppCommon.h:106
static SLstring gitDate
Current GIT commit date.
Definition: AppCommon.h:79
static SLstring configuration
Debug or Release configuration.
Definition: AppCommon.h:76
static SLstring shaderPath
Path to GLSL shader programs.
Definition: AppCommon.h:84
static SLSceneID sceneID
ID of currently loaded scene.
Definition: AppCommon.h:89
static SLScene * scene
Pointer to the one and only SLScene instance.
Definition: AppCommon.h:61
static map< string, string > deviceParameter
Generic device parameter.
Definition: AppCommon.h:101
static SLstring dataPath
Path to data directory (it is set platform dependent)
Definition: AppCommon.h:83
static void loadConfig(SLint dotsPerInch)
Loads the UI configuration.
static SLbool showImGuiMetrics
Flag if imgui metrics infor should be shown.
Definition: AppDemoGui.h:67
static SLstring infoCalibrate
Calibration info string.
Definition: AppDemoGui.h:55
static void showTexInfos(SLGLTexture *tex)
Shows UI infos for a texture.
static void downloadModelAndLoadScene(SLScene *s, SLSceneView *sv, string downloadFilename, string urlFolder, string dstFolder, string filenameToLoad, SLSceneID sceneIDToLoad)
Parallel HTTP download, unzip and load scene job scheduling.
static SLbool hideUI
Flag if menubar should be shown.
Definition: AppDemoGui.h:56
static SLbool showHelpCalibration
Flag if calibration info should be shown.
Definition: AppDemoGui.h:61
static void saveConfig()
Stores the UI configuration.
static void loadSceneWithLargeModel(SLScene *s, SLSceneView *sv, string downloadFilename, string filenameToLoad, SLSceneID sceneIDToLoad)
static SLbool showCredits
Flag if credits info should be shown.
Definition: AppDemoGui.h:62
static SLbool showDateAndTime
Flag if date-time dialog should be shown.
Definition: AppDemoGui.h:76
static SLbool showStatsTiming
Flag if timing info should be shown.
Definition: AppDemoGui.h:63
static SLbool showSceneGraph
Flag if scene graph should be shown.
Definition: AppDemoGui.h:71
static SLbool _horizonVisuEnabled
Definition: AppDemoGui.h:88
static SLbool showUIPrefs
Flag if UI preferences.
Definition: AppDemoGui.h:74
static void showHorizon(SLScene *s, SLSceneView *sv)
Enables calculation and visualization of horizon line (using rotation sensors)
static SLbool showProperties
Flag if properties should be shown.
Definition: AppDemoGui.h:72
static SLbool showErlebAR
Flag if Christoffel infos should be shown.
Definition: AppDemoGui.h:73
static void build(SLScene *s, SLSceneView *sv)
This is the main building function for the GUI of the Demo apps.
Definition: AppDemoGui.cpp:229
static void addSceneGraphNode(SLScene *s, SLNode *node)
Builds the node information once per frame.
static SLbool showTransform
Flag if transform dialog should be shown.
Definition: AppDemoGui.h:75
static void buildSceneGraph(SLScene *s)
Builds the scenegraph dialog once per frame.
static SLstring infoCredits
Credits info string.
Definition: AppDemoGui.h:53
static void setActiveNamedLocation(int locIndex, SLSceneView *sv, SLVec3f lookAtPoint=SLVec3f::ZERO)
Set the a new active named location from SLDeviceLocation.
static void removeTransformNode(SLScene *s)
Searches and removes the transform node.
static void buildMenuEdit(SLScene *s, SLSceneView *sv)
Builds the edit menu that can be in the menu bar and the context menu.
static SLstring loadingString
String shown during loading screens.
Definition: AppDemoGui.h:78
static SLbool showProgress
Flag if about info should be shown.
Definition: AppDemoGui.h:57
static SLbool showInfosSensors
Flag if device sensors info should be shown.
Definition: AppDemoGui.h:68
static SLbool showInfosDevice
Flag if device info should be shown.
Definition: AppDemoGui.h:69
static SLbool showStatsScene
Flag if scene info should be shown.
Definition: AppDemoGui.h:64
static void buildMenuBar(SLScene *s, SLSceneView *sv)
Builds the entire menu bar once per frame.
static void showLUTColors(SLTexColorLUT *lut)
Displays a editable color lookup table wit ImGui widgets.
static SLbool showInfosScene
Flag if scene info should be shown.
Definition: AppDemoGui.h:70
static void clear()
Definition: AppDemoGui.cpp:218
static SLstring infoHelp
Help info string.
Definition: AppDemoGui.h:54
static void hideHorizon(SLScene *s)
Disables calculation and visualization of horizon line.
static void buildProperties(SLScene *s, SLSceneView *sv)
Builds the properties dialog once per frame.
static SLstring configTime
Time of stored configuration.
Definition: AppDemoGui.h:51
static SLstring infoAbout
About info string.
Definition: AppDemoGui.h:52
static std::time_t adjustedTime
Adjusted GUI time for sun setting (default 0)
Definition: AppDemoGui.h:77
static void setTransformEditMode(SLScene *s, SLSceneView *sv, SLNodeEditMode editMode)
Adds a transform node for the selected node and toggles the edit mode.
static SLbool showStatsWAI
Flag if WAI info should be shown.
Definition: AppDemoGui.h:66
static SLbool showHelp
Flag if help info should be shown.
Definition: AppDemoGui.h:60
static SLbool showStatsVideo
Flag if video info should be shown.
Definition: AppDemoGui.h:65
static void buildMenuContext(SLScene *s, SLSceneView *sv)
Builds context menu if right mouse click is over non-imgui area.
static SLbool showAbout
Flag if about info should be shown.
Definition: AppDemoGui.h:59
static SLbool showDockSpace
Flag if dock space should be enabled.
Definition: AppDemoGui.h:58
Live video camera calibration class with OpenCV an OpenCV calibration.
Definition: CVCalibration.h:71
float tauY() const
float s3() const
float fx() const
CVSize boardSize() const
float s4() const
float k4() const
float boardSquareMM() const
const CVMat & distortion() const
CVSize imageSizeOriginal() const
float s2() const
float fy() const
bool isMirroredH()
float k3() const
bool isMirroredV()
float p1() const
float cx() const
int numCapturedImgs() const
float p2() const
float cameraFovHDeg() const
float cameraFovVDeg() const
float k2() const
string stateStr() const
float k6() const
float s1() const
float k5() const
float tauX() const
float k1() const
float cy() const
string calibrationTime() const
CVCalibState state() const
bool mirrorH()
Definition: CVCamera.h:22
void toggleMirrorV()
Definition: CVCamera.h:34
int camSizeIndex()
Definition: CVCamera.h:27
CVCalibration calibration
Definition: CVCamera.h:36
CVCameraType type()
Definition: CVCamera.h:24
void toggleMirrorH()
Definition: CVCamera.h:33
void showUndistorted(bool su)
Definition: CVCamera.h:25
bool mirrorV()
Definition: CVCamera.h:23
Encapsulation of the OpenCV Capture Device and holder of the last frame.
Definition: CVCapture.h:63
bool hasSecondaryCamera
flag if device has secondary camera
Definition: CVCapture.h:125
CVVSize camSizes
All possible camera sizes.
Definition: CVCapture.h:133
CVCamera * activeCamera
Pointer to the active camera.
Definition: CVCapture.h:136
CVSize captureSize
size of captured frame
Definition: CVCapture.h:123
void videoType(CVVideoType vt)
Setter for video type also sets the active calibration.
Definition: CVCapture.cpp:866
CVMat lastFrame
last frame grabbed in BGR
Definition: CVCapture.h:119
int activeCamSizeIndex
Currently active camera size index.
Definition: CVCapture.h:134
static CVCapture * instance()
Public static instance getter for singleton pattern.
Definition: CVCapture.h:65
AvgFloat & captureTimesMS()
get number of frames in video
Definition: CVCapture.h:109
CVTrackedFeatures is the main part of the AR Christoffelturm scene.
CVDetectDescribeType type()
CVTracked is the pure virtual base class for tracking features in video.
Definition: CVTracked.h:50
static AvgFloat trackingTimesMS
Averaged time for video tracking in ms.
Definition: CVTracked.h:82
static AvgFloat optFlowTimesMS
Averaged time for video feature optical flow tracking in ms.
Definition: CVTracked.h:87
static AvgFloat detectTimesMS
Averaged time for video feature detection & description in ms.
Definition: CVTracked.h:83
static AvgFloat detect1TimesMS
Averaged time for video feature detection subpart 1 in ms.
Definition: CVTracked.h:84
static AvgFloat detect2TimesMS
Averaged time for video feature detection subpart 2 in ms.
Definition: CVTracked.h:85
static AvgFloat matchTimesMS
Averaged time for video feature matching in ms.
Definition: CVTracked.h:86
static AvgFloat poseTimesMS
Averaged time for video feature pose estimation in ms.
Definition: CVTracked.h:88
void drawDetection(bool draw)
Definition: CVTracked.h:60
SLVstring & animationNames()
Definition: SLAnimManager.h:46
SLAnimPlayback * animPlaybackByIndex(SLuint ix)
Definition: SLAnimManager.h:49
Manages the playback of an SLAnimation.
SLbool isPaused() const
SLbool enabled() const
SLfloat localTime() const
SLbool isPlayingBackward() const
SLbool isPlayingForward() const
SLbool isStopped() const
SLEasingCurve easing() const
SLfloat playbackRate() const
SLAnimation * parentAnimation()
SLfloat lengthSec() const
Definition: SLAnimation.h:72
Toplevel holder of the assets meshes, materials, textures and shaders.
SLVMesh & meshes()
SLVGLProgram & programs()
static SLTexFont * font16
16 pixel high fixed size font
SLVGLTexture & textures()
Active or visible camera node class.
Definition: SLCamera.h:54
void stereoEyeSeparation(const SLfloat es)
Definition: SLCamera.h:119
SLfloat fovV() const
Vertical field of view.
Definition: SLCamera.h:135
void clipFar(const SLfloat cFar)
Definition: SLCamera.h:109
SLfloat fovH() const
Horizontal field of view.
Definition: SLCamera.cpp:1504
void clipNear(const SLfloat cNear)
Definition: SLCamera.h:108
void focalDist(const SLfloat f)
Definition: SLCamera.h:116
void maxSpeed(const SLfloat ms)
Definition: SLCamera.h:112
void fogMode(const SLFogMode mode)
Definition: SLCamera.h:126
void projType(SLProjType p)
Definition: SLCamera.h:92
static SLstring projTypeToStr(SLProjType pt)
Returns the projection type as string.
Definition: SLCamera.cpp:419
void fogIsOn(const bool isOn)
Definition: SLCamera.h:125
void fov(const SLfloat fov)
vertical field of view
Definition: SLCamera.h:98
void lookFrom(const SLVec3f &fromDir, const SLVec3f &upDir=SLVec3f::AXISY)
Sets the view to look from a direction towards the current focal point.
Definition: SLCamera.cpp:974
void fogDensity(const float density)
Definition: SLCamera.h:127
void camAnim(SLCamAnim ca)
Definition: SLCamera.h:103
Encapsulation of a mobile device location set by the device's GPS sensor.
void useOriginAltitude(SLbool useGLA)
SLbool calculateSolarAngles(SLVec3d locationLatLonAlt, std::time_t time)
Calculates the solar angles at origin at local time.
SLfloat originSolarSunset() const
SLVec3d defaultENU() const
void activeNamedLocation(SLint locIndex)
void sunLightNode(SLLightDirect *sln)
void isUsed(SLbool isUsed)
Setter that turns on the device rotation sensor.
SLVec3d originENU() const
SLVLocation & nameLocations()
void offsetMode(SLLocOffsetMode lom)
SLfloat originSolarSunrise() const
void hasOrigin(SLbool hasOL)
SLVec3d locENU() const
Encapsulation of a mobile device rotation set by the device's IMU sensor.
void hasStarted(SLbool started)
void numAveraged(SLint numAvg)
Returns the device rotation averaged over multple frames.
void offsetMode(SLRotOffsetMode rom)
void zeroYawAtStart(SLbool zeroYaw)
void isUsed(SLbool isUsed)
Setter that turns on the device rotation sensor.
SLbool get(SLuint bit)
Returns the specified bit.
Definition: SLDrawBits.h:69
void set(SLuint bit, SLbool state)
Sets the specified bit to the passed state.
Definition: SLDrawBits.h:57
void toggle(SLuint bit)
Toggles the specified bit.
Definition: SLDrawBits.h:66
void allOff()
Turns all bits off.
Definition: SLDrawBits.h:48
void on(SLuint bit)
Turns the specified bit on.
Definition: SLDrawBits.h:51
Encapsulation of an OpenGL shader program object.
Definition: SLGLProgram.h:56
static size_t size()
Returns the size of the program map.
static SLGLProgramGeneric * get(SLStdShaderProg id)
Get program reference for given id.
Singleton class holding all OpenGL states.
Definition: SLGLState.h:71
SLstring glVersionNO()
Definition: SLGLState.h:128
static SLGLState * instance()
Public static instance getter for singleton pattern.
Definition: SLGLState.h:74
SLstring glRenderer()
Definition: SLGLState.h:131
SLstring glVendor()
Definition: SLGLState.h:130
SLstring glSLVersionNO()
Definition: SLGLState.h:133
void currentMaterial(SLMaterial *mat)
Definition: SLGLState.h:120
Texture object for OpenGL texturing.
Definition: SLGLTexture.h:110
SLuint height()
Definition: SLGLTexture.h:219
CVVImage & images()
Definition: SLGLTexture.h:225
SLint bytesOnGPU()
Definition: SLGLTexture.h:223
SLenum target() const
Definition: SLGLTexture.h:226
SLuint width()
Definition: SLGLTexture.h:218
SLint bytesInFile()
Definition: SLGLTexture.h:224
SLstring minificationFilterName()
Definition: SLGLTexture.h:242
SLstring typeName()
Returns the texture type as string.
SLuint depth()
Definition: SLGLTexture.h:220
SLuint texID() const
Definition: SLGLTexture.h:227
SLstring magnificationFilterName()
Definition: SLGLTexture.h:243
static SLuint totalNumBytesOnGPU
Total NO. of bytes used for textures on GPU.
Definition: SLGLTexture.h:293
void bindActive(SLuint texUnit=0)
bool isTexture()
Definition: SLGLTexture.h:241
static SLuint totalDrawCalls
static SLuint totalPrimitivesRendered
static total no. of draw calls
static SLuint totalBufferSize
static total no. of buffers in use
static SLfloat fontPropDots
Default font size of proportional font.
Definition: SLImGui.h:91
static SLfloat fontFixedDots
Default font size of fixed size font.
Definition: SLImGui.h:92
SLLightDirect class for a directional light source.
Definition: SLLightDirect.h:40
void doSunPowerAdaptation(SLbool enabled)
Definition: SLLightDirect.h:82
SLTexColorLUT * sunLightColorLUT()
Definition: SLLightDirect.h:90
Abstract Light class for OpenGL light sources.
Definition: SLLight.h:61
void ambientColor(const SLCol4f &ambi)
Definition: SLLight.h:105
static SLfloat gamma
final output gamma value
Definition: SLLight.h:204
static SLbool doColoredShadows
flag if shadows should be displayed with colors for debugging
Definition: SLLight.h:205
void ambientPower(const SLfloat ambPow)
Definition: SLLight.h:106
void kl(SLfloat kl)
Definition: SLLight.cpp:80
void specularPower(const SLfloat specPow)
Definition: SLLight.h:110
void isOn(const SLbool on)
Definition: SLLight.h:71
void spotCutOffDEG(SLfloat cutOffAngleDEG)
Definition: SLLight.cpp:92
void diffusePower(const SLfloat diffPow)
Definition: SLLight.h:108
void diffuseColor(const SLCol4f &diff)
Definition: SLLight.h:107
void specularColor(const SLCol4f &spec)
Definition: SLLight.h:109
void kc(SLfloat kc)
Definition: SLLight.cpp:74
void kq(SLfloat kq)
Definition: SLLight.cpp:86
void spotExponent(const SLfloat exp)
Definition: SLLight.h:111
Light node class for a rectangular light source.
Definition: SLLightRect.h:39
SLLightSpot class for a spot light source.
Definition: SLLightSpot.h:36
SLVec3< T > translation() const
Definition: SLMat4.h:184
void decompose(SLVec3f &trans, SLVec4f &rotQuat, SLVec3f &scale)
Definition: SLMat4.h:1483
SLstring toString() const
Definition: SLMat4.h:1567
Defines a standard CG material with textures and a shader program.
Definition: SLMaterial.h:56
void reflectionModel(SLReflectionModel rm)
Definition: SLMaterial.h:169
void specular(const SLCol4f &spec)
Definition: SLMaterial.h:173
void programTF(SLGLProgram *sp)
Definition: SLMaterial.h:206
void diffuse(const SLCol4f &diff)
Definition: SLMaterial.h:171
SLuint numTextures()
Definition: SLMaterial.h:226
void kt(SLfloat kt)
Definition: SLMaterial.h:190
void shininess(SLfloat shin)
Definition: SLMaterial.h:177
void ambient(const SLCol4f &ambi)
Definition: SLMaterial.h:170
SLVGLTexture & textures(SLTextureType type)
Definition: SLMaterial.h:233
void kr(SLfloat kr)
Definition: SLMaterial.h:184
void roughness(SLfloat r)
Definition: SLMaterial.h:182
void emissive(const SLCol4f &emis)
Definition: SLMaterial.h:174
void kn(SLfloat kn)
Definition: SLMaterial.h:199
void metalness(SLfloat m)
Definition: SLMaterial.h:183
void program(SLGLProgram *sp)
Definition: SLMaterial.h:205
void getsShadows(SLbool receivesShadows)
Definition: SLMaterial.h:204
An SLMesh object is a triangulated mesh, drawn with one draw call.
Definition: SLMesh.h:134
SLVuint IS32
Vector of rectangle selected vertex indices 32 bit.
Definition: SLMesh.h:216
SLVuint I32
Vector of vertex indices 32 bit.
Definition: SLMesh.h:215
SLVushort I16
Vector of vertex indices 16 bit.
Definition: SLMesh.h:214
SLVuint IE32
Vector of hard edges vertex indices 32 bit (see computeHardEdgesIndices)
Definition: SLMesh.h:218
void deleteSelected(SLNode *node)
Deletes the rectangle selected vertices and the dependent triangles.
Definition: SLMesh.cpp:148
SLVushort IE16
Vector of hard edges vertex indices 16 bit (see computeHardEdgesIndices)
Definition: SLMesh.h:217
SLVVec3f P
Vector for vertex positions layout (location = 0)
Definition: SLMesh.h:203
SLMaterial * mat() const
Definition: SLMesh.h:177
SLNode represents a node in a hierarchical scene graph.
Definition: SLNode.h:148
void resetToInitialState()
Definition: SLNode.cpp:1092
SLVNode & children()
Definition: SLNode.h:306
SLbool drawBit(SLuint bit)
Definition: SLNode.h:301
void translation(const SLVec3f &pos, SLTransformSpace relativeTo=TS_parent)
Definition: SLNode.cpp:828
void rotate(const SLQuat4f &rot, SLTransformSpace relativeTo=TS_object)
Definition: SLNode.cpp:945
const SLMat4f & updateAndGetWM() const
Definition: SLNode.cpp:703
void scale(SLfloat s)
Definition: SLNode.h:641
SLMesh * mesh()
Definition: SLNode.h:305
static SLuint numWMUpdates
NO. of calls to updateWMRec per frame.
Definition: SLNode.h:320
void castsShadows(SLbool castsShadows)
Definition: SLNode.h:283
void needAABBUpdate()
Definition: SLNode.cpp:665
T * findChild(const SLstring &name="", SLbool findRecursive=true)
Definition: SLNode.h:389
SLVec3f translationOS() const
Definition: SLNode.h:469
SLDrawBits * drawBits()
Definition: SLNode.h:300
void om(const SLMat4f &mat)
Definition: SLNode.h:277
void lookAt(SLfloat targetX, SLfloat targetY, SLfloat targetZ, SLfloat upX=0, SLfloat upY=1, SLfloat upZ=0, SLTransformSpace relativeTo=TS_world)
Definition: SLNode.h:653
const SLMat4f & initialOM()
Definition: SLNode.h:297
void translate(const SLVec3f &vec, SLTransformSpace relativeTo=TS_object)
Definition: SLNode.cpp:906
void name(const SLstring &Name)
Definition: SLObject.h:34
SLParticleSystem creates a particle meshes from a point primitive buffer.
SLbool doShapeSpawnBase()
SLbool doShapeOverride()
SLGLTexture * texFlipbook()
float * bezierControlPointSize()
float * bezierControlPointAlpha()
SLbool doFlipBookTexture()
SLbool doDirectionSpeed()
SLVec3f velocityRndMax()
SLShapeType shapeType()
SLfloat angularVelocityConst()
float * bezierStartEndPointSize()
SLBillboardType billboardType()
float * bezierStartEndPointAlpha()
SLbool doAlphaOverLTCurve()
SLbool doBlendBrightness()
void doAcceleration(SLbool b)
SLbool doSizeOverLTCurve()
SLVec2f angularVelocityRange()
SLVec3f velocityRndMin()
SLfloat accelerationConst()
SLVec3f acceleration()
void accConst(SLfloat f)
SLbool doInstancedDrawing()
Classic Monte Carlo Pathtracing algorithm for real global illumination.
Definition: SLPathtracer.h:18
void calcDirect(SLbool di)
Definition: SLPathtracer.h:33
void calcIndirect(SLbool ii)
Definition: SLPathtracer.h:34
void saveImage()
Saves the current PT image as PNG image.
static SLuint tirRays
NO. of TIR refraction rays.
Definition: SLRay.h:131
static SLuint reflectedRays
NO. of reflected rays.
Definition: SLRay.h:127
static SLint maxDepthReached
max. depth reached for all rays
Definition: SLRay.h:135
static SLuint refractedRays
NO. of refracted rays.
Definition: SLRay.h:128
static SLuint subsampledPixels
NO. of of subsampled pixels.
Definition: SLRay.h:138
static SLuint totalNumRays()
Total NO. of rays shot during RT.
Definition: SLRay.h:84
static SLfloat avgDepth
average depth reached
Definition: SLRay.h:136
static SLuint subsampledRays
NO. of of subsampled rays.
Definition: SLRay.h:137
static SLuint shadowRays
NO. of shadow rays.
Definition: SLRay.h:130
SLRaytracer hold all the methods for Whitted style Ray Tracing.
Definition: SLRaytracer.h:57
void gamma(SLfloat g)
Definition: SLRaytracer.h:106
SLint resolutionFactorPC() const
Definition: SLRaytracer.h:126
SLfloat renderSec() const
Definition: SLRaytracer.h:122
void doContinuous(SLbool cont)
Definition: SLRaytracer.h:91
void state(SLRTState state)
Definition: SLRaytracer.h:80
static SLuint numThreads()
Definition: SLRaytracer.h:119
void doFresnel(SLbool fresnel)
Definition: SLRaytracer.h:96
void maxDepth(SLint depth)
Definition: SLRaytracer.h:84
SLint progressPC() const
Definition: SLRaytracer.h:120
void resolutionFactor(SLfloat rf)
Definition: SLRaytracer.h:89
void aaSamples(SLint samples)
Definition: SLRaytracer.h:101
SLfloat raysPerMS()
Definition: SLRaytracer.h:127
virtual void saveImage()
Saves the current RT image as PNG image.
void doDistributed(SLbool distrib)
Definition: SLRaytracer.h:90
The SLScene class represents the top level instance holding the scene structure.
Definition: SLScene.h:47
AvgFloat & frameTimesMS()
Definition: SLScene.h:109
void deselectAllNodesAndMeshes()
Deselects all nodes and its meshes.
Definition: SLScene.cpp:338
AvgFloat & updateAABBTimesMS()
Definition: SLScene.h:112
SLMesh * singleMeshFullSelected()
Returns the node if only one is selected. See also SLMesh::selectNodeMesh.
Definition: SLScene.h:119
SLVEventHandler & eventHandlers()
Definition: SLScene.h:105
AvgFloat & updateAnimTimesMS()
Definition: SLScene.h:111
SLAssetManager * assetManager()
Definition: SLScene.h:98
SLint numSceneCameras()
Returns the number of camera nodes in the scene.
Definition: SLScene.cpp:353
AvgFloat & updateTimesMS()
Definition: SLScene.h:110
SLVMesh & selectedMeshes()
Definition: SLScene.h:125
SLVLight & lights()
Definition: SLScene.h:107
void root2D(SLNode *root2D)
Definition: SLScene.h:90
SLAnimManager & animManager()
Definition: SLScene.h:97
void selectNodeMesh(SLNode *nodeToSelect, SLMesh *meshToSelect)
Handles the full mesh selection from double-clicks.
Definition: SLScene.cpp:234
void skybox(SLSkybox *skybox)
Definition: SLScene.h:91
SLfloat fps() const
Definition: SLScene.h:108
void root3D(SLNode *root3D)
Definition: SLScene.h:78
SLNode * singleNodeSelected()
Returns the node if only one is selected. See also SLMesh::selectNodeMesh.
Definition: SLScene.h:116
SLVNode & selectedNodes()
Definition: SLScene.h:124
void info(SLstring i)
Definition: SLScene.h:93
AvgFloat & updateDODTimesMS()
Definition: SLScene.h:113
void loadTimeMS(SLfloat loadTimeMS)
Definition: SLScene.h:94
void stopAnimations(SLbool stop)
Definition: SLScene.h:92
SceneView class represents a dynamic real time 3D view onto the scene.
Definition: SLSceneView.h:69
AvgFloat & shadowMapTimeMS()
Definition: SLSceneView.h:200
SLDrawBits * drawBits()
Definition: SLSceneView.h:198
void switchToNextCameraInScene()
Sets the active camera to the next in the scene.
AvgFloat & draw3DTimesMS()
Definition: SLSceneView.h:203
void doMultiSampling(SLbool doMS)
Definition: SLSceneView.h:150
SLint viewportH() const
Definition: SLSceneView.h:180
void doDepthTest(SLbool doDT)
Definition: SLSceneView.h:151
void startPathtracing(SLint maxDepth, SLint samples)
SLNodeStats & stats3D()
Definition: SLSceneView.h:205
void switchToSceneViewCamera()
std::unordered_set< SLMaterial * > & visibleMaterials3D()
Definition: SLSceneView.h:209
AvgFloat & draw2DTimesMS()
Definition: SLSceneView.h:202
void camera(SLCamera *camera)
Definition: SLSceneView.h:145
SLint viewportW() const
Definition: SLSceneView.h:179
SLPathtracer * pathtracer()
Definition: SLSceneView.h:195
void viewportSameAsVideo(bool sameAsVideo)
Definition: SLSceneView.h:155
void startRaytracing(SLint maxDepth)
void renderType(SLRenderType rt)
Definition: SLSceneView.h:154
AvgFloat & cullTimesMS()
Definition: SLSceneView.h:201
SLint dpi() const
Definition: SLSceneView.h:175
void doAlphaSorting(SLbool doAS)
Definition: SLSceneView.h:153
SLVec2i viewportRatio() const
Definition: SLSceneView.h:177
SLRaytracer * raytracer()
Definition: SLSceneView.h:194
SLVNode & nodesOverdrawn()
Definition: SLSceneView.h:193
void setViewportFromRatio(const SLVec2i &vpRatio, SLViewportAlign vpAlignment, SLbool vpSameAsVideo)
Sets the viewport ratio and the viewport rectangle.
void scrW(SLint scrW)
Definition: SLSceneView.h:147
SLViewportAlign viewportAlign() const
Definition: SLSceneView.h:181
void doFrustumCulling(SLbool doFC)
Definition: SLSceneView.h:152
void doWaitOnIdle(SLbool doWI)
Definition: SLSceneView.h:149
void screenCaptureIsRequested(bool doScreenCap)
Definition: SLSceneView.h:156
void scrH(SLint scrH)
Definition: SLSceneView.h:148
Class for standard and cascaded shadow mapping.
Definition: SLShadowMap.h:39
void numCascades(int numCascades)
Definition: SLShadowMap.h:72
int maxCascades()
Definition: SLShadowMap.h:88
SLbool useCascaded() const
Definition: SLShadowMap.h:78
SLGLVDepthBuffer depthBuffers()
Definition: SLShadowMap.h:81
SLGLDepthBuffer * depthBuffer()
Definition: SLShadowMap.h:80
SLProjType projection()
Definition: SLShadowMap.h:76
void rayCount(const SLVec2i &rayCount)
Definition: SLShadowMap.h:63
static SLuint drawCalls
NO. of draw calls for shadow mapping.
Definition: SLShadowMap.h:92
void useCubemap(SLbool useCubemap)
Definition: SLShadowMap.h:62
void clipNear(SLfloat clipNear)
Definition: SLShadowMap.h:64
void size(const SLVec2f &size)
Definition: SLShadowMap.h:66
SLfloat lightClipNear()
Definition: SLShadowMap.h:83
void textureSize(const SLVec2i &textureSize)
Definition: SLShadowMap.h:71
void clipFar(SLfloat clipFar)
Definition: SLShadowMap.h:65
SLfloat lightClipFar()
Definition: SLShadowMap.h:84
void cascadesFactor(float factor)
Definition: SLShadowMap.h:73
SLMat4f * lightSpace()
Definition: SLShadowMap.h:79
Skybox node class with a SLBox mesh.
Definition: SLSkybox.h:29
SLfloat exposure()
Definition: SLSkybox.h:54
SLGLTexture * irradianceCubemap()
Definition: SLSkybox.h:51
SLGLTexture * brdfLutTexture()
Definition: SLSkybox.h:53
SLGLTexture * roughnessCubemap()
Definition: SLSkybox.h:52
SLbool isHDR()
Definition: SLSkybox.h:55
SLGLTexture * environmentCubemap()
Definition: SLSkybox.h:50
SLTexColorLUT defines a lookup table as an 1D texture of (256) RGBA values.
Definition: SLTexColorLUT.h:70
void colors(SLColorLUTType lut)
Colors setter function by predefined color LUT.
SLVfloat allAlphas()
Returns all alpha values of the transfer function as a float vector.
SLuint length()
Definition: SLTexColorLUT.h:93
void generateTexture()
Generates the full 256 value LUT as 1x256 RGBA texture.
SLVAlphaLUTPoint & alphas()
Definition: SLTexColorLUT.h:95
Class that holds all visible gizmo node during mouse transforms.
SLNode * targetNode()
virtual void editMode(SLNodeEditMode editMode)
static SLVec2 ZERO
Definition: SLVec2.h:135
T y
Definition: SLVec2.h:30
T x
Definition: SLVec2.h:30
SLstring toString(SLstring delimiter=", ", int decimals=2)
Conversion to string.
Definition: SLVec3.h:199
T y
Definition: SLVec3.h:43
static SLVec3 AXISY
Definition: SLVec3.h:298
T x
Definition: SLVec3.h:43
T length() const
Definition: SLVec3.h:122
static SLVec3 AXISX
Definition: SLVec3.h:297
void set(const T X, const T Y, const T Z)
Definition: SLVec3.h:59
T z
Definition: SLVec3.h:43
static SLVec3 AXISZ
Definition: SLVec3.h:299
static SLVec3 ZERO
Definition: SLVec3.h:285
static std::string model
Definition: Utils.h:293
static std::string get()
Definition: Utils.cpp:1261
static std::string brand
Definition: Utils.h:292
static std::string user
Definition: Utils.h:290
static std::string os
Definition: Utils.h:294
static std::string osVer
Definition: Utils.h:295
static std::string arch
Definition: Utils.h:296
static std::string name
Definition: Utils.h:291
bool exists(std::string path, SLIOStreamKind kind)
Checks whether a given file exists.
std::string readIntoString(std::string path, SLIOStreamKind kind)
Reads an entire file into a string.
void writeString(std::string path, SLIOStreamKind kind, const std::string &string)
Writes a string to a file.
bool fileExists(const string &pathfilename)
Returns true if a file exists.
Definition: Utils.cpp:897
T abs(T a)
Definition: Utils.h:249
T clamp(T a, T min, T max)
Definition: Utils.h:253
string getPath(const string &pathFilename)
Returns the path w. '\' of path-filename string.
Definition: Utils.cpp:392
T floor(T a)
Definition: Utils.h:246
static const float RAD2DEG
Definition: Utils.h:238
unsigned closestPowerOf2(unsigned num)
Returns the closest power of 2 to a passed number.
Definition: Utils.cpp:1221
string getLocalTimeString()
Returns local time as string like "Wed Feb 13 15:46:11 2019".
Definition: Utils.cpp:258
static const float PI
Definition: Utils.h:237
string toString(float f, int roundedDecimals)
Returns a string from a float with max. one trailing zero.
Definition: Utils.cpp:92
bool deleteFile(string &pathfilename)
Deletes a file on the filesystem.
Definition: Utils.cpp:1008
string getFileExt(const string &filename)
Returns the file extension without dot in lower case.
Definition: Utils.cpp:629
bool zip(string path, string zipname)
Definition: ZipUtils.cpp:255
bool unzip(string zipfile, function< bool(string path, string filename)> processFile, function< bool(const char *data, size_t len)> writeChunk, function< bool(string path)> processDir, function< int(int currentFile, int totalFiles)> progress=nullptr)
Definition: ZipUtils.cpp:150
Struct for scene graph statistics.
Definition: SLNode.h:38
SLuint numVoxMaxTria
Max. no. of triangles per voxel.
Definition: SLNode.h:52
SLuint numBytesAccel
NO. of bytes in accel. structs.
Definition: SLNode.h:41
SLuint numNodesOpaque
NO. of visible opaque nodes.
Definition: SLNode.h:44
SLuint numMeshes
NO. of meshes in node.
Definition: SLNode.h:46
SLuint numNodes
NO. of children nodes.
Definition: SLNode.h:39
SLuint numLights
NO. of lights in mesh.
Definition: SLNode.h:47
SLuint numTriangles
NO. of triangles in mesh.
Definition: SLNode.h:48
SLuint numNodesBlended
NO. of visible blended nodes.
Definition: SLNode.h:45
SLuint numNodesLeaf
NO. of leaf nodes.
Definition: SLNode.h:43
SLuint numVoxels
NO. of voxels.
Definition: SLNode.h:50
SLuint numNodesGroup
NO. of group nodes.
Definition: SLNode.h:42
SLuint numBytes
NO. of bytes allocated.
Definition: SLNode.h:40
SLfloat numVoxEmpty
NO. of empty voxels.
Definition: SLNode.h:51