viewer.cpp
Go to the documentation of this file.
1 // License: Apache 2.0. See LICENSE file in root directory.
2 // Copyright(c) 2017 Intel Corporation. All Rights Reserved.
3 
4 #ifdef _MSC_VER
5 #ifndef NOMINMAX
6 #define NOMINMAX
7 #endif
8 #endif
9 
10 #include <regex>
11 
12 #include "viewer.h"
13 #include "os.h"
14 
15 #include "udev-rules.h"
16 
17 #include <opengl3.h>
18 
19 #include <imgui_internal.h>
20 #include <librealsense2/rsutil.h>
21 
22 #define ARCBALL_CAMERA_IMPLEMENTATION
23 #include <arcball_camera.h>
24 #include "../common/utilities/string/trim-newlines.h"
25 #include "../common/utilities/imgui/wrap.h"
26 
27 namespace rs2
28 {
29  template <typename T>
31  {
32  return std::max(static_cast<T>(0), input);
33  }
34 
35  // Allocates a frameset from points and texture frames
37  filter([this](frame f, frame_source& s)
38  {
39  std::vector<rs2::frame> frame_vec;
40  auto tex = owner->get_last_texture()->get_last_frame(true);
41  if (tex)
42  {
43  frame_vec.push_back(tex);
44  frame_vec.push_back(f);
45  auto frame = s.allocate_composite_frame(frame_vec);
46  if (frame)
47  s.frame_ready(std::move(frame));
48  }
49  else
50  s.frame_ready(std::move(f));
51  }) {}
52 
53  void viewer_model::render_pose(rs2::rect stream_rect, float buttons_heights)
54  {
55  int num_of_pose_buttons = 2; // trajectory, info
56 
57  // Draw selection buttons on the pose header, the buttons are global to all the streaming devices
58  ImGui::SetCursorPos({ stream_rect.w - 32 * num_of_pose_buttons - 5, buttons_heights });
59 
60  bool color_icon = pose_info_object_button.is_pressed(); //draw trajectory is on - color the icon
61  if (color_icon)
62  {
65  }
66 
67  // Draw info object button (is not synchronized with the info buttons in the 2D view)
68  if (ImGui::Button(pose_info_object_button.get_icon().c_str(), { 24, buttons_heights }))
69  {
70  pose_info_object_button.toggle_button();
71  }
73  {
74  ImGui::SetTooltip("%s", pose_info_object_button.get_tooltip().c_str());
75  }
76  if (color_icon)
77  {
79  }
80 
81  // Draw grid object button
83 
84  color_icon = trajectory_button.is_pressed(); //draw trajectory is on - color the icon
85  if (color_icon)
86  {
89  }
90  if (ImGui::Button(trajectory_button.get_icon().c_str(), { 24, buttons_heights }))
91  {
92  trajectory_button.toggle_button();
93  for (auto&& s : streams)
94  {
95  if (s.second.profile.stream_type() == RS2_STREAM_POSE)
96  streams[s.second.profile.unique_id()].dev->tm2.record_trajectory(trajectory_button.is_pressed());
97  }
98  }
99  if (color_icon)
100  {
102  }
103  if (ImGui::IsItemHovered())
104  {
105  ImGui::SetTooltip("%s", trajectory_button.get_tooltip().c_str());
106  }
107 
108  //ImGui::End();
109  }
110 
111  // Need out of class declaration to take reference
116 
117  void viewer_model::set_export_popup(ImFont* large_font, ImFont* font, rect stream_rect, std::string& error_message, config_file& temp_cfg)
118  {
119  float w = 520; // hardcoded size to keep popup layout
120  float h = 325;
121  float x0 = stream_rect.x + stream_rect.w / 3;
122  float y0 = stream_rect.y + stream_rect.h / 3;
123  ImGui::SetNextWindowPos({ x0, y0 });
124  ImGui::SetNextWindowSize({ w, h });
125 
128 
129  ImGui_ScopePushFont(font);
135 
136  static export_type tab = export_type::ply;
137  if (ImGui::BeginPopupModal("Export", nullptr, flags))
138  {
139  ImGui::SetCursorScreenPos({ (float)(x0), (float)(y0 + 30) });
142  ImGui::PushFont(large_font);
143  for (auto& exporter : exporters)
144  {
145  ImGui::PushStyleColor(ImGuiCol_Text, tab != exporter.first ? light_grey : light_blue);
146  ImGui::PushStyleColor(ImGuiCol_TextSelectedBg, tab != exporter.first ? light_grey : light_blue);
147  ImGui::SameLine();
148  if (ImGui::Button(exporter.second.name.c_str(), { w / exporters.size() - 50, 30 }))
149  {
152  tab = exporter.first;
153  }
155  }
156 
157  ImGui::PopFont();
158  if (tab == export_type::ply)
159  {
160  bool mesh = temp_cfg.get(configurations::ply::mesh);
162  if (!mesh) use_normals = false;
164 
166  ImGui::Text("Polygon File Format defines a flexible systematic scheme for storing 3D data");
168  ImGui::NewLine();
169  ImGui::SetCursorScreenPos({ (float)(x0 + 15), (float)(y0 + 90) });
171  if (ImGui::Checkbox("Meshing", &mesh))
172  {
173  temp_cfg.set(configurations::ply::mesh, mesh);
174  }
176  ImGui::Text(" Use faces for meshing by connecting each group of 3 adjacent points");
179 
180  if (!mesh)
181  {
185  }
186  if (ImGui::Checkbox("Normals", &use_normals))
187  {
188  if (!mesh)
189  use_normals = false;
190  else
191  temp_cfg.set(configurations::ply::use_normals, use_normals);
192  }
193  if (!mesh)
194  {
195  if (ImGui::IsItemHovered())
196  {
197  ImGui::SetTooltip("Enable meshing to allow vertex normals calculation");
198  }
201  }
202 
204  ImGui::Text(" Calculate vertex normals and add them to the PLY");
207 
208  ImGui::Text("Encoding:");
210  ImGui::Text("Save PLY as binary, or as a larger textual human-readable file");
212  if (ImGui::RadioButton("Textual", encoding == configurations::ply::textual))
213  {
214  encoding = configurations::ply::textual;
215  temp_cfg.set(configurations::ply::encoding, encoding);
216  }
217  if (ImGui::RadioButton("Binary", encoding == configurations::ply::binary))
218  {
219  encoding = configurations::ply::binary;
220  temp_cfg.set(configurations::ply::encoding, encoding);
221  }
222 
223  auto curr_exporter = exporters.find(tab);
224  if (curr_exporter == exporters.end()) // every tab should have a corresponding exporter
225  error_message = "Exporter not implemented";
226  else
227  {
228  curr_exporter->second.options[rs2::save_to_ply::OPTION_PLY_MESH] = mesh;
229  curr_exporter->second.options[rs2::save_to_ply::OPTION_PLY_NORMALS] = use_normals;
230  curr_exporter->second.options[rs2::save_to_ply::OPTION_PLY_BINARY] = encoding;
231  }
232  }
233 
234  ImGui::PopStyleColor(2); // button color
235 
236  auto apply = [&]() {
237  config_file::instance() = temp_cfg;
238  update_configuration();
239  };
240 
244 
245  ImGui::SetCursorScreenPos({ (float)(x0 + w / 2), (float)(y0 + h - 30) });
246 
247  if (ImGui::Button("Export", ImVec2(120, 0)))
248  {
249  apply();
250  if (!last_points)
251  error_message = "No depth data available";
252  else
253  {
254  auto curr_exporter = exporters.find(tab);
255  if (curr_exporter == exporters.end()) // every tab should have a corresponding exporter
256  error_message = "Exporter not implemented";
257  else if (auto ret = file_dialog_open(save_file, curr_exporter->second.filters.data(), NULL, NULL))
258  {
259  auto model = ppf.get_points();
260  frame tex;
261  if (selected_tex_source_uid >= 0 && streams.find(selected_tex_source_uid) != streams.end())
262  {
263  tex = streams[selected_tex_source_uid].texture->get_last_frame(true);
264  if (tex) ppf.update_texture(tex);
265  }
266 
267  std::string fname(ret);
268  if (!ends_with(to_lower(fname), curr_exporter->second.extension)) fname += curr_exporter->second.extension;
269 
270  std::unique_ptr<rs2::filter> exporter;
271  if (tab == export_type::ply)
272  exporter = std::unique_ptr<rs2::filter>(new rs2::save_to_ply(fname));
273  auto data = frameset_alloc.process(last_points);
274 
275  for (auto& option : curr_exporter->second.options)
276  {
277  exporter->set_option(option.first, option.second);
278  }
279 
280  export_frame(fname, std::move(exporter), *not_model, data);
281  }
282  }
284  }
285  if (ImGui::IsItemHovered())
286  {
287  ImGui::SetTooltip("%s", "Save settings and export file");
288  }
289  ImGui::SameLine();
290  if (ImGui::Button("Cancel", ImVec2(120, 0)))
291  {
293  }
294  if (ImGui::IsItemHovered())
295  {
296  ImGui::SetTooltip("%s", "Close window without saving any changes to the settings");
297  }
298 
300  ImGui::EndPopup();
301  }
304  }
305 
306  bool big_button(bool* status,
307  ux_window& win,
308  int x, int y,
309  const char* icon,
310  const char* label,
311  bool dropdown,
312  bool enabled,
313  const char* description,
314  ImVec4 text_color = light_grey
315  )
316  {
317  auto disabled = !enabled;
318  auto font = win.get_font();
319  auto large_font = win.get_large_font();
320 
321  bool hovered = false;
322  bool clicked = false;
323 
324  if (!disabled)
325  {
326  if (*status)
327  {
330  }
331  else
332  {
335  }
336  }
337  else
338  {
341  }
342 
343  ImGui::SetCursorPos({float(x), float(y)});
344  ImGui::PushFont(large_font);
345  clicked = clicked || ImGui::Button(icon, { 60, 50 });
346  ImGui::PopFont();
347  hovered = hovered || ImGui::IsItemHovered();
348 
349  ImGui::SetCursorPos({float(x + 45), float(y)});
351  if (dropdown)
352  {
353  clicked = clicked || ImGui::Button(u8"\uf078", { 20, 55 });
354  hovered = hovered || ImGui::IsItemHovered();
355  }
356 
357  ImGui::SetCursorPos({ float(x), float(y + 35)});
358  clicked = clicked || ImGui::Button(label, { 60, 20 });
359  ImGui::PopFont();
360  hovered = hovered || ImGui::IsItemHovered();
361 
362  if (hovered && !disabled)
363  {
364  win.link_hovered();
365  ImGui::SetTooltip("%s", description);
366  }
367 
368  if (clicked && !disabled)
369  {
370  *status = !(*status);
371  }
372 
374 
375  return clicked && !disabled;
376  }
377 
378  // Get both font and large_font for the export pop-up
379  void viewer_model::show_3dviewer_header(ux_window& win, rs2::rect stream_rect, bool& paused, std::string& error_message)
380  {
381  auto font = win.get_font();
382  auto large_font = win.get_large_font();
383 
384  // Draw pose header if pose stream exists
385  bool pose_render = false;
386 
387  for (auto&& s : streams)
388  {
389  if (s.second.is_stream_visible() &&
390  s.second.profile.stream_type() == RS2_STREAM_POSE)
391  {
392  pose_render = true;
393  break;
394  }
395  }
396 
397  // Initialize and prepare depth and texture sources
398  int selected_depth_source = -1;
399  std::vector<std::string> depth_sources_str;
400  std::vector<int> depth_sources;
401  int i = 0;
402  for (auto&& s : streams)
403  {
404  if (s.second.is_stream_visible() &&
405  s.second.profile.stream_type() == RS2_STREAM_DEPTH)
406  {
407  if (selected_depth_source_uid == -1)
408  {
409  if (streams_origin.find(s.second.profile.unique_id()) != streams_origin.end() &&
410  streams.find(streams_origin[s.second.profile.unique_id()]) != streams.end())
411  {
412  selected_depth_source_uid = streams_origin[s.second.profile.unique_id()];
413  }
414  }
415  if (streams_origin.find(s.second.profile.unique_id()) != streams_origin.end() && streams_origin[s.second.profile.unique_id()] == selected_depth_source_uid)
416  {
417  selected_depth_source = i;
418  }
419 
420  depth_sources.push_back(s.second.profile.unique_id());
421 
422  auto dev_name = s.second.dev ? s.second.dev->dev.get_info(RS2_CAMERA_INFO_NAME) : "Unknown";
423  auto stream_name = rs2_stream_to_string(s.second.profile.stream_type());
424 
425  depth_sources_str.push_back(to_string() << dev_name << " " << stream_name);
426 
427  i++;
428  }
429  }
430 
431  int selected_tex_source = 0;
432  std::vector<std::string> tex_sources_str;
433  std::vector<int> tex_sources;
434  std::vector<rs2::stream_profile> tex_profiles;
435  i = 0;
436  for (auto&& s : streams)
437  {
438  if (s.second.is_stream_visible() &&
439  (s.second.profile.stream_type() == RS2_STREAM_COLOR ||
440  s.second.profile.stream_type() == RS2_STREAM_INFRARED ||
441  s.second.profile.stream_type() == RS2_STREAM_CONFIDENCE ||
442  s.second.profile.stream_type() == RS2_STREAM_DEPTH ||
443  s.second.profile.stream_type() == RS2_STREAM_FISHEYE))
444  {
445  if (selected_tex_source_uid == -1 && selected_depth_source_uid != -1)
446  {
447  if (streams_origin.find(s.second.profile.unique_id()) != streams_origin.end() &&
448  streams.find(streams_origin[s.second.profile.unique_id()]) != streams.end())
449  {
450  selected_tex_source_uid = streams_origin[s.second.profile.unique_id()];
451  }
452  }
453  if ((streams_origin.find(s.second.profile.unique_id()) != streams_origin.end() &&streams_origin[s.second.profile.unique_id()] == selected_tex_source_uid))
454  {
455  selected_tex_source = i;
456  }
457 
458  // The texture source shall always refer to the raw (original) streams
459  tex_sources.push_back(streams_origin[s.second.profile.unique_id()]);
460  tex_profiles.push_back(s.second.profile);
461 
462  auto dev_name = s.second.dev ? s.second.dev->dev.get_info(RS2_CAMERA_INFO_NAME) : "Unknown";
463  std::string stream_name = rs2_stream_to_string(s.second.profile.stream_type());
464  if (s.second.profile.stream_index())
465  stream_name += "_" + std::to_string(s.second.profile.stream_index());
466  tex_sources_str.push_back(to_string() << dev_name << " " << stream_name);
467 
468  i++;
469  }
470  }
471 
472  for (int i = 0; i < tex_sources.size(); i++)
473  {
474  auto id = tex_sources[i];
475  auto it = std::find(begin(last_tex_sources), end(last_tex_sources), id);
476  if (it == last_tex_sources.end())
477  {
478  // Don't auto-switch to IR stream
479  if (tex_profiles[i].format() != RS2_FORMAT_Y8)
480  selected_tex_source_uid = id;
481  texture_update_time = glfwGetTime();
482  }
483  }
484  last_tex_sources = tex_sources;
485 
486  const auto top_bar_height = 60.f;
487 
494 
495  std::string label = to_string() << "header of 3dviewer";
496 
497  ImGui::GetWindowDrawList()->AddRectFilled({ stream_rect.x, stream_rect.y },
498  { stream_rect.x + stream_rect.w, stream_rect.y + top_bar_height }, ImColor(sensor_bg));
499 
500  ImGui::SetCursorPos({ 0, 0 });
501  auto cursor = ImGui::GetCursorScreenPos();
502 
503  auto left = 5;
504 
505  const auto has_stream = tex_sources_str.size() && depth_sources_str.size();
506 
507  // ------------ Pause Stream --------------
508 
509  if (paused)
510  {
511  bool active = true;
512  if (big_button(&active, win, 5 + left, 0, textual_icons::play, "Resume", false, has_stream, "Resume streaming"))
513  {
514  for(auto&& s : streams)
515  if (s.second.dev) s.second.dev->resume();
516  paused = false;
517  }
518  }
519  else
520  {
521  bool active = false;
522  if (big_button(&active, win, 5 + left, 0, textual_icons::pause, "Pause", false, has_stream, "Pause streaming"))
523  {
524  for(auto&& s : streams)
525  if (s.second.dev) s.second.dev->pause();
526  paused = true;
527  }
528  }
529  left += 60;
530 
531  // ------------ Reset Viewport ---------------
532 
533  bool default_view = (pos - float3{ 0.f, 0.f, -1.f }).length() < 0.001f &&
534  (target - float3{ 0.f, 0.f, 0.f }).length() < 0.001f;
535  bool active = false;
536  if (big_button(&active, win, 5 + left, 0, u8"\uf01e", "Reset", false, !default_view, "Reset 3D viewport to initial state"))
537  {
538  reset_camera();
539  }
540 
541  left += 60;
542 
543  // ------------ Lock Mode ---------------
544 
545  if (synchronization_enable)
546  {
547  bool active = true;
548  if (big_button(&active, win, 5 + left, 0, textual_icons::lock, "Unlock", false,
549  support_non_syncronized_mode && has_stream, "Unlock texture data from pointcloud"))
550  {
551  synchronization_enable = false;
552  }
553  }
554  else
555  {
556  bool active = false;
557  if (big_button(&active, win, 5 + left, 0, textual_icons::unlock, "Lock", false,
558  support_non_syncronized_mode && has_stream, "Lock pointcloud and texture data together"))
559  {
560  synchronization_enable = true;
561  }
562  }
563  left += 70;
564 
565  ImGui::GetWindowDrawList()->AddLine({ cursor.x + left - 1, cursor.y + 5 },
566  { cursor.x + left - 1, cursor.y + top_bar_height - 5 }, ImColor(grey));
567 
568  // ------------ Depth Selection --------------
569 
570  const auto source_selection_popup = "Source Selection";
571 
572  if (big_button(&select_3d_source, win, left, 0, u8"\uf1b2",
573  "Source", true,
574  has_stream,
575  "List of available 3D data sources"))
576  {
577  ImGui::OpenPopup(source_selection_popup);
578  }
579 
584  ImGui::SetNextWindowPos({ cursor.x + left + 5, cursor.y + 60 });
585  if (ImGui::BeginPopup(source_selection_popup))
586  {
587  select_3d_source = true;
588 
589  i = 0;
590  for (auto&& s : streams)
591  {
592  if (s.second.is_stream_visible() &&
593  s.second.texture->get_last_frame() &&
594  s.second.profile.stream_type() == RS2_STREAM_DEPTH)
595  {
596  std::string id = to_string() << depth_sources_str[i] << "##DepthSource-" << i;
597 
598  bool selected = i == selected_depth_source;
599  if (ImGui::MenuItem(id.c_str(), nullptr, &selected))
600  {
601  if (selected)
602  {
603  selected_depth_source_uid = streams_origin[s.second.profile.unique_id()];
604  }
605  }
606  i++;
607  }
608  }
609 
610  ImGui::EndPopup();
611  }
612  else
613  {
614  select_3d_source = false;
615  }
616  left += 80;
617 
618  // ------------ Texture Selection --------------
619 
620  auto t = single_wave(float(glfwGetTime() - texture_update_time) * 2);
621  ImVec4 text_color = light_grey * (1.f - t) + light_blue * t;
622 
623  const auto tex_selection_popup = "Tex Selection";
624  if (big_button(&select_tex_source, win, left, 0, u8"\uf576",
625  "Texture", true,
626  has_stream,
627  "List of available texture sources", text_color))
628  {
629  ImGui::OpenPopup(tex_selection_popup);
630  }
631 
632  ImGui::SetNextWindowPos({ cursor.x + left + 5, cursor.y + 60 });
633  if (ImGui::BeginPopup(tex_selection_popup))
634  {
635  select_tex_source = true;
636 
637  for (int i = 0; i < tex_sources_str.size(); i++)
638  {
639  std::string id = to_string() << tex_sources_str[i] << "##TexSource-" << i;
640 
641  bool selected = i == selected_tex_source;
642  if (ImGui::MenuItem(id.c_str(), nullptr, &selected))
643  {
644  if (selected)
645  {
646  selected_tex_source_uid = tex_sources[i];
647  }
648  }
649  }
650 
651  ImGui::EndPopup();
652  }
653  else
654  {
655  select_tex_source = false;
656  }
657 
658  left += 80;
659 
660  // ------------ Shader Selection --------------
661  const auto shader_selection_popup = "Shading Selection";
662  if (big_button(&select_shader_source, win, left, 0, u8"\uf5aa",
663  "Shading", true, true,
664  "List of available shading modes"))
665  {
666  ImGui::OpenPopup(shader_selection_popup);
667  }
668 
669  ImGui::SetNextWindowPos({ cursor.x + left + 5, cursor.y + 60 });
670  if (ImGui::BeginPopup(shader_selection_popup))
671  {
672  select_shader_source = true;
673 
674  bool selected = selected_shader == shader_type::points;
675  if (ImGui::MenuItem("Raw Point-Cloud", nullptr, &selected))
676  {
677  if (selected) selected_shader = shader_type::points;
678  }
679 
680  selected = selected_shader == shader_type::flat;
681  if (ImGui::MenuItem("Flat-Shaded Mesh", nullptr, &selected))
682  {
683  if (selected) selected_shader = shader_type::flat;
684  }
685 
686  selected = selected_shader == shader_type::diffuse;
687  if (ImGui::MenuItem("With Diffuse Lighting", nullptr, &selected, glsl_available))
688  {
689  if (selected) selected_shader = shader_type::diffuse;
690  }
691 
692  ImGui::EndPopup();
693  }
694  else
695  {
696  select_shader_source = false;
697  }
698  left += 80;
699 
700  //-----------------------------
701 
703 
704  ImGui::GetWindowDrawList()->AddLine({ cursor.x + left - 1, cursor.y + 5 },
705  { cursor.x + left - 1, cursor.y + top_bar_height - 5 }, ImColor(grey));
706 
707  // -------------------- Measure ----------------
708 
709  std::string measure_tooltip = "Measure distance between points";
710  if (!glsl_available) measure_tooltip += "\nRequires GLSL acceleration!";
711  if (_measurements.is_enabled())
712  {
713  bool active = true;
714  if (big_button(&active, win, 5 + left, 0, textual_icons::measure, "Measure", false, glsl_available, measure_tooltip.c_str()))
715  {
716  _measurements.disable();
717  }
718  }
719  else
720  {
721  bool active = false;
722  if (big_button(&active, win, 5 + left, 0, textual_icons::measure, "Measure", false, glsl_available, measure_tooltip.c_str()))
723  {
724  _measurements.enable();
725  }
726  }
727  left += 60;
728 
729  // -------------------- Trajectory (T265) -------------------
730 
731  active = trajectory_button.is_pressed();
732  if (big_button(&active, win, 5 + left, 0, u8"\uf1b0",
733  "Route", false, pose_render, "Show 6-dof Pose Trajectory\nRequires T265 tracking device"))
734  {
735  trajectory_button.toggle_button();
736  for (auto&& s : streams)
737  {
738  if (s.second.profile.stream_type() == RS2_STREAM_POSE)
739  streams[s.second.profile.unique_id()].dev->tm2.record_trajectory(trajectory_button.is_pressed());
740  }
741  }
742 
743  left += 60;
744 
745  // -------------------- Export ------------------
746 
747  static config_file temp_cfg;
748  set_export_popup(large_font, font, stream_rect, error_message, temp_cfg);
749 
750  active = false;
751  if (big_button(&active, win, 5 + left, 0, textual_icons::floppy, "Export", false, last_points, "Export 3D model to 3rd-party application"))
752  {
753  temp_cfg = config_file::instance();
754  ImGui::OpenPopup("Export");
755  }
756 
757  left += 60;
758 
759 
761 
762 
763  ImGui::PopFont();
764  }
765 
767  {
768 #ifdef __linux__
769 
770  if (directory_exists("/etc/udev/rules.d") || directory_exists("/lib/udev/rules.d/"))
771  {
772  const std::string udev_rules_man("/etc/udev/rules.d/99-realsense-libusb.rules");
773  const std::string udev_rules_deb("/lib/udev/rules.d/60-librealsense2-udev-rules.rules");
774  std::ifstream f_man(udev_rules_man);
775  std::ifstream f_deb(udev_rules_deb);
776 
777  std::string message = "UDEV-Rules permissions configuration \n for RealSense devices.`\n"
778  "Missing/outdated UDEV-Rules will cause 'Permissions Denied' errors\nunless the application is running under 'sudo' (not recommended)\n"
779  "In case of Debians use: \n"
780  "sudo apt-get upgrade/install librealsense2-udev-rules\n"
781  "To manually install UDEV-Rules in terminal run:\n"
782  "$ sudo cp ~/.99-realsense-libusb.rules /etc/udev/rules.d/99-realsense-libusb.rules && sudo udevadm control --reload-rules && udevadm trigger\n";
783 
784  bool create_file = false;
785 
786  if(!(f_man.good() || f_deb.good()))
787  {
788  message = "RealSense UDEV-Rules are missing!\n" + message;
789  auto n = not_model->add_notification({ message,
792  create_file = true;
793 
794  n->enable_complex_dismiss = true;
795  n->delay_id = "missing-udev";
796  if (n->is_delayed()) n->dismiss(true);
797  }
798  else
799  {
800  std::ifstream f;
801  std::string udev_fname;
802  if(f_man.good())
803  {
804  if (f_deb.good())
805  {
806  std::string duplicates = "Multiple realsense udev-rules were found! :\n1:" + udev_rules_man
807  + "\n2: " + udev_rules_deb+ "\nMake sure to remove redundancies!";
808  auto n = not_model->add_notification({ duplicates,
811  n->enable_complex_dismiss = true;
812  n->delay_id = "multiple-udev";
813  if (n->is_delayed()) n->dismiss(true);
814  }
815  f.swap(f_man);
816  udev_fname = udev_rules_man;
817  create_file = true;
818  }
819  else
820  {
821  f.swap(f_deb);
822  udev_fname = udev_rules_deb;
823  }
824 
825  const std::string str((std::istreambuf_iterator<char>(f)),
826  std::istreambuf_iterator<char>());
827 
828  std::string tmp = realsense_udev_rules;
829  tmp.erase(tmp.find_last_of("\n") + 1);
830  const std::string udev = tmp;
831  float udev_file_ver{}, built_in_file_ver{};
832 
833  // The udev-rules file shall start with version token expressed as ##Version=xx.yy##
834  std::regex udev_ver_regex("^##Version=(\\d+\\.\\d+)##");
835  std::smatch match;
836 
837  if (std::regex_search(udev.begin(), udev.end(), match, udev_ver_regex))
838  built_in_file_ver = std::stof(std::string(match[1]));
839 
840  if (std::regex_search(str.begin(), str.end(), match, udev_ver_regex))
841  udev_file_ver = std::stof(std::string(match[1]));
842 
843  if (built_in_file_ver > udev_file_ver)
844  {
845  std::stringstream s;
846  s << "RealSense UDEV-Rules file:\n " << udev_fname <<"\n is not up-to date! Version " << built_in_file_ver << " can be applied\n";
847  auto n = not_model->add_notification({
848  s.str() + message,
851 
852  n->enable_complex_dismiss = true;
853  n->delay_id = "udev-version";
854  if (n->is_delayed()) n->dismiss(true);
855  }
856  }
857 
858  if (create_file)
859  {
860  std::string tmp_filename = to_string() << get_folder_path(special_folder::app_data) << "/.99-realsense-libusb.rules";
861 
862  std::ofstream out(tmp_filename.c_str());
863  out << realsense_udev_rules;
864  out.close();
865  }
866  }
867 
868 #endif
869  }
870 
871  // Hide options from both the DQT and Viewer applications
873  {
874  _hidden_options.emplace(RS2_OPTION_STREAM_FILTER);
875  _hidden_options.emplace(RS2_OPTION_STREAM_FORMAT_FILTER);
876  _hidden_options.emplace(RS2_OPTION_STREAM_INDEX_FILTER);
877  _hidden_options.emplace(RS2_OPTION_FRAMES_QUEUE_SIZE);
878  _hidden_options.emplace(RS2_OPTION_SENSOR_MODE);
879  _hidden_options.emplace(RS2_OPTION_TRIGGER_CAMERA_ACCURACY_HEALTH);
880  _hidden_options.emplace(RS2_OPTION_RESET_CAMERA_ACCURACY_HEALTH);
881  _hidden_options.emplace(RS2_OPTION_NOISE_ESTIMATION);
882  }
883 
885  {
886  rs2_error* e = nullptr;
887  auto version = rs2_get_api_version(&e);
888  if (e) rs2::error::handle(e);
889 
890  int saved_version = config_file::instance().get_or_default(
892 
893  // Great the user once upon upgrading to a new version
894  if (version > saved_version)
895  {
896  auto n = std::make_shared<version_upgrade_model>(version);
897  not_model->add_notification(n);
898 
900  }
901 
904 
907 
908  if (bool measurement_enabled = config_file::instance().get_or_default(
910  _measurements.enable();
911 
912  _measurements.log_function = [this](std::string message) { not_model->add_log(message); };
913  _measurements.is_metric = [this]() { return metric_system; };
914 
915  glsl_available = config_file::instance().get(
917 
920 
923 
924  selected_shader = (shader_type)config_file::instance().get_or_default(
926 
927 #ifdef BUILD_EASYLOGGINGPP
930 
931  if (config_file::instance().get_or_default(
933  {
934  rs2::log_to_console(min_severity);
935  }
936  if (config_file::instance().get_or_default(
938  {
941 
942  rs2::log_to_file(min_severity, filename.c_str());
943  }
944 #endif
945 
948  }
949 
950 
951 
953  : ppf( *this )
954  , ctx( ctx_ )
955  , frameset_alloc( this )
956  , synchronization_enable( true )
957  , synchronization_enable_prev_state(true)
958  , zo_sensors( 0 )
959  , _support_ir_reflectivity( false )
960  {
961 
962  syncer = std::make_shared<syncer_model>();
963  updates = std::make_shared<updates_model>();
964  reset_camera();
965  rs2_error* e = nullptr;
966  not_model->add_log(to_string() << "librealsense version: " << api_version_to_string(rs2_get_api_version(&e)) << "\n");
967 
969 
971  export_model exp_model = export_model::make_exporter("PLY", ".ply", "Polygon File Format (PLY)\0*.ply\0");
972  exporters.insert(std::pair<export_type, export_model>(export_type::ply, exp_model));
973 
974  hide_common_options(); // hide this options from both Viewer and DQT applications
975  }
976 
978  {
979  std::lock_guard<std::mutex> lock(streams_mutex);
980  std::vector<int> streams_to_remove;
981  for (auto&& kvp : streams)
982  {
983  if (!kvp.second.is_stream_visible() &&
984  (!kvp.second.dev || (!kvp.second.dev->is_paused() && !kvp.second.dev->streaming)))
985  {
986  if (kvp.first == selected_depth_source_uid)
987  {
988  ppf.depth_stream_active = false;
989  }
990  streams_to_remove.push_back(kvp.first);
991  }
992  }
993  for (auto&& i : streams_to_remove) {
995  {
996  last_points = points();
998  }
999 
1000  if (selected_tex_source_uid == i)
1001  {
1002  last_texture.reset();
1004  }
1005  streams.erase(i);
1006 
1007  if(ppf.frames_queue.find(i) != ppf.frames_queue.end())
1008  {
1009  ppf.frames_queue.erase(i);
1010  }
1011  }
1012  }
1013 
1015  {
1016  return (_hidden_options.find(opt) != _hidden_options.end());
1017  }
1018 
1020  {
1021  auto font_14 = window.get_font();
1022 
1023  ImGui_ScopePushFont(font_14);
1029 
1030  ImGui::SetNextWindowSize({520, 180});
1031 
1032  ImGui::OpenPopup(p.header.c_str());
1033 
1035  {
1041 
1042  p.custom_command();
1043 
1044  ImGui::EndPopup();
1045  }
1046 
1048  ImGui::PopStyleVar(2);
1049  }
1050 
1052  {
1053  if (message == "")
1054  return;
1055 
1056  // The list of errors the user asked not to show again:
1057  static std::set<std::string> errors_not_to_show;
1058  static bool dont_show_this_error = false;
1059  auto simplify_error_message = [](const std::string& s) {
1060  std::regex e("\\b(0x)([^ ,]*)");
1061  return std::regex_replace(s, e, "address");
1062  };
1063 
1064  auto it = std::find_if(_active_popups.begin(), _active_popups.end(), [&](const popup& p) { return message == p.message; });
1065  if (it != _active_popups.end())
1066  return;
1067 
1068  auto simplified_error_message = simplify_error_message(message);
1069  if (errors_not_to_show.count(simplified_error_message))
1070  {
1071  not_model->add_notification({ message,
1074  return;
1075  }
1076 
1077  std::string header = std::string(textual_icons::exclamation_triangle) + " Oops, something went wrong!";
1078 
1079  auto custom_command = [&]()
1080  {
1081  auto msg = _active_popups.front().message;
1082 
1083  // Wrap the text to feet the error pop-up window
1084  std::string wrapped_msg;
1085  try
1086  {
1087  auto trimmed_msg = utilities::string::trim_newlines(msg);
1088  wrapped_msg = utilities::imgui::wrap(trimmed_msg, 500);
1089  }
1090  catch (...)
1091  {
1092  wrapped_msg = msg; // Revert to original text on wrapping failure
1093  not_model->output.add_log(RS2_LOG_SEVERITY_WARN, __FILE__, __LINE__,
1094  to_string() << "Wrapping of error message text failed!");
1095  }
1096 
1097  ImGui::Text("RealSense error calling:");
1099  ImGui::InputTextMultiline("##error", const_cast<char*>(wrapped_msg.c_str()),
1100  msg.size() + 1, { 500,95 }, ImGuiInputTextFlags_AutoSelectAll | ImGuiInputTextFlags_ReadOnly);
1102 
1103  //ImGui::SetCursorPos({ 10, 130 });
1105 
1106  if (ImGui::Button("OK", ImVec2(120, 0)))
1107  {
1108  if (dont_show_this_error)
1109  {
1110  errors_not_to_show.insert(simplify_error_message(msg));
1111  }
1113  _active_popups.erase(_active_popups.begin());
1114  dont_show_this_error = false;
1115  }
1116 
1117  ImGui::SameLine();
1118  ImGui::Checkbox("Don't show this error again", &dont_show_this_error);
1119  };
1120 
1121  popup p = {header, message, custom_command };
1122  _active_popups.push_back(p);
1123  }
1124 
1125  std::vector<uint8_t> read_fw_file(std::string file_path)
1126  {
1127  std::vector<uint8_t> rv;
1128 
1129  std::ifstream file(file_path, std::ios::in | std::ios::binary | std::ios::ate);
1130  if (file.is_open())
1131  {
1132  rv.resize(file.tellg());
1133 
1134  file.seekg(0, std::ios::beg);
1135  file.read((char*)rv.data(), rv.size());
1136  file.close();
1137  }
1138 
1139  return rv;
1140  }
1141 
1143  {
1144  std::string header = "Firmware update in progress";
1145  std::stringstream message;
1146  message << std::endl << "Progress: " << (int)(progress * 100.0) << " [%]";
1147 
1148  auto custom_command = [&]()
1149  {
1150  ImGui::SetCursorPos({ 10, 100 });
1152 
1153 
1154  ImGui::ProgressBar(progress, { 300 , 25 }, "Firmware update");
1155  };
1156 
1157  popup p = { header, message.str(), custom_command };
1158  _active_popups.push_back(p);
1159  }
1160 
1161  void viewer_model::show_icon(ImFont* font_18, const char* label_str, const char* text, int x, int y, int id,
1162  const ImVec4& text_color, const std::string& tooltip)
1163  {
1164  ImGui_ScopePushFont(font_18);
1165 
1166  std::string label = to_string() << label_str << id;
1167 
1168  ImGui::SetCursorScreenPos({(float)x, (float)y});
1169  ImGui::PushStyleColor(ImGuiCol_Text, text_color);
1170  ImGui::Text("%s", text);
1172  if (ImGui::IsItemHovered() && tooltip != "")
1173  ImGui::SetTooltip("%s", tooltip.c_str());
1174 
1175  }
1176  void viewer_model::show_paused_icon(ImFont* font_18, int x, int y, int id)
1177  {
1178  show_icon(font_18, "paused_icon", textual_icons::pause, x, y, id, white);
1179  }
1180  void viewer_model::show_recording_icon(ImFont* font_18, int x, int y, int id, float alpha_delta)
1181  {
1182  show_icon(font_18, "recording_icon", textual_icons::circle, x, y, id, from_rgba(255, 46, 54, static_cast<uint8_t>(alpha_delta * 255)));
1183  }
1184 
1185  void viewer_model::show_no_stream_overlay(ImFont* font_18, int min_x, int min_y, int max_x, int max_y)
1186  {
1187  ImGui::PushFont(font_18);
1188 
1189  auto pos = ImGui::GetCursorScreenPos();
1190  ImGui::SetCursorScreenPos({ (min_x + max_x) / 2.f - 150, (min_y + max_y) / 2.f - 20 });
1191 
1193  std::string text = to_string() << "Nothing is streaming! Toggle " << textual_icons::toggle_off << " to start";
1194  ImGui::Text("%s", text.c_str());
1196 
1198 
1199  ImGui::PopFont();
1200  }
1201 
1202  void viewer_model::show_rendering_not_supported(ImFont* font_18, int min_x, int min_y, int max_x, int max_y, rs2_format format)
1203  {
1204  static utilities::time::periodic_timer update_string(std::chrono::milliseconds(200));
1205  static int counter = 0;
1206  static std::string to_print;
1207  auto pos = ImGui::GetCursorScreenPos();
1208 
1209  ImGui::PushFont(font_18);
1210  ImGui::SetCursorScreenPos({ min_x + max_x / 2.f - 210, min_y + max_y / 2.f - 20 });
1213  ImGui::Text("%s", text.c_str());
1214  ImGui::SetCursorScreenPos({ min_x + max_x / 2.f - 180, min_y + max_y / 2.f - 20 });
1215  text = to_string() << " The requested format " << format << " is not supported for rendering ";
1216 
1217  if (update_string)
1218  {
1219  to_print.clear();
1220  for (int i = 0; i < text.size(); i++)
1221  to_print += text[(i + counter) % text.size()];
1222  counter++;
1223  }
1224 
1225  ImGui::Text("%s", to_print.c_str());
1227 
1229 
1230  ImGui::PopFont();
1231  }
1232 
1234  {
1235  auto pos = ImGui::GetCursorScreenPos();
1236  ImGui::SetCursorScreenPos({ float(x), float(y) });
1237 
1238  ImGui::PushFont(font_18);
1239  ImGui::PushStyleColor(ImGuiCol_Text, from_rgba(0x70, 0x8f, 0xa8, 0xff));
1240  ImGui::Text("Connect a RealSense Camera\nor Add Source");
1242  ImGui::PopFont();
1243 
1245  }
1246 
1247  // Generate streams layout, creates a grid-like layout with factor amount of columns
1248  std::map<int, rect> generate_layout(const rect& r,
1249  int top_bar_height, size_t factor,
1250  const std::set<stream_model*>& active_streams,
1251  std::map<stream_model*, int>& stream_index
1252  )
1253  {
1254  std::map<int, rect> results;
1255  if (factor == 0) return results;
1256 
1257  // Calc the number of rows
1258  auto complement = ceil((float)active_streams.size() / factor);
1259 
1260  auto cell_width = static_cast<float>(r.w / factor);
1261  auto cell_height = static_cast<float>(r.h / complement);
1262 
1263  auto it = active_streams.begin();
1264  for (auto x = 0; x < factor; x++)
1265  {
1266  for (auto y = 0; y < complement; y++)
1267  {
1268  // There might be spare boxes at the end (3 streams in 2x2 array for example)
1269  if (it == active_streams.end()) break;
1270 
1271  rect rxy = { r.x + x * cell_width, r.y + y * cell_height + top_bar_height,
1272  cell_width, cell_height - top_bar_height };
1273  // Generate box to display the stream in
1274  results[stream_index[*it]] = rxy.adjust_ratio((*it)->size);
1275  ++it;
1276  }
1277  }
1278 
1279  return results;
1280  }
1281 
1282  // Return the total display area of the layout
1283  // The bigger it is, the more details we can see
1284  float evaluate_layout(const std::map<int, rect>& l)
1285  {
1286  float res = 0.f;
1287  for (auto&& kvp : l) res += kvp.second.area();
1288  return res;
1289  }
1290 
1291  std::map<int, rect> viewer_model::calc_layout(const rect& r)
1292  {
1293  const int top_bar_height = 32;
1294 
1295  std::set<stream_model*> active_streams;
1296  std::map<stream_model*, int> stream_index;
1297  for (auto&& stream : streams)
1298  {
1299  if (stream.second.is_stream_visible())
1300  {
1301  active_streams.insert(&stream.second);
1302  stream_index[&stream.second] = stream.first;
1303  }
1304  }
1305 
1306  if (fullscreen)
1307  {
1308  if (active_streams.count(selected_stream) == 0) fullscreen = false;
1309  }
1310 
1311  std::map<int, rect> results;
1312 
1313  if (fullscreen)
1314  {
1315  results[stream_index[selected_stream]] = { r.x, r.y + top_bar_height,
1316  r.w, r.h - top_bar_height };
1317  }
1318  else
1319  {
1320  // Go over all available fx(something) layouts
1321  for (size_t f = 1; f <= active_streams.size(); f++)
1322  {
1323  auto l = generate_layout(r, top_bar_height, f,
1324  active_streams, stream_index);
1325 
1326  // Keep the "best" layout in result
1327  if (evaluate_layout(l) > evaluate_layout(results))
1328  results = l;
1329  }
1330  }
1331 
1332  return get_interpolated_layout(results);
1333  }
1334 
1336  {
1337  std::shared_ptr<texture_buffer> texture_frame = nullptr;
1338  points p;
1339  frame f{};
1340  gc_streams();
1341 
1342  std::map<int, frame> last_frames;
1343  try
1344  {
1345  size_t index = 0;
1347  {
1348  if (streams.find(f.get_profile().unique_id()) != streams.end() ||
1349  streams.find(streams_origin[f.get_profile().unique_id()]) != streams.end())
1350  last_frames[f.get_profile().unique_id()] = f;
1351  }
1352 
1353  for(auto&& f : last_frames)
1354  not_model->output.update_dashboards(f.second);
1355 
1356  for(auto&& frame : last_frames)
1357  {
1358  auto f = frame.second;
1359  frameset frames;
1360  if ((frames = f.as<frameset>()))
1361  {
1362  for (auto&& frame : frames)
1363  {
1364  if (frame.is<points>() && !paused) // find and store the 3d points frame for later use
1365  {
1366  p = frame.as<points>();
1367  continue;
1368  }
1369 
1370  if (frame.is<pose_frame>()) // Aggregate the trajectory in pause mode to make the path consistent
1371  {
1372  auto dev = streams[frame.get_profile().unique_id()].dev;
1373  if (dev)
1374  {
1375  dev->tm2.update_model_trajectory(frame.as<pose_frame>(), !paused);
1376  }
1377  }
1378 
1380 
1383  {
1384  texture_frame = texture;
1385  }
1386  }
1387  }
1388  else if (!p)
1389  {
1391  }
1392  }
1393  }
1394  catch (const error& ex)
1395  {
1396  error_message = error_to_string(ex);
1397  }
1398  catch (const std::exception& ex)
1399  {
1400  error_message = ex.what();
1401  }
1402 
1403  window.begin_viewport();
1404 
1409 
1412 
1413  ImGui::SetNextWindowPos({ viewer_rect.x, viewer_rect.y });
1414  ImGui::SetNextWindowSize({ viewer_rect.w, viewer_rect.h });
1415 
1416  ImGui::Begin("Viewport", nullptr, { viewer_rect.w, viewer_rect.h }, 0.f, flags);
1417 
1418  try
1419  {
1420  draw_viewport( viewer_rect, window, devices, error_message, texture_frame, p );
1421 
1422  modal_notification_on = not_model->draw( window,
1423  static_cast< int >( window.width() ),
1424  static_cast< int >( window.height() ),
1425  error_message );
1426  }
1427  catch( const error & e )
1428  {
1429  error_message = error_to_string( e );
1430  }
1431  catch( const std::exception & e )
1432  {
1433  error_message = e.what();
1434  }
1435 
1436  popup_if_error(window, error_message);
1437 
1438  if (!_active_popups.empty())
1439  show_popup(window, _active_popups.front());
1440 
1441  ImGui::End();
1442  ImGui::PopStyleVar(2);
1443 
1444  error_message = "";
1445 
1446  return f;
1447  }
1448 
1450  {
1451  target = { 0.0f, 0.0f, 0.0f };
1452  pos = p;
1453 
1454  // initialize "up" to be tangent to the sphere!
1455  // up = cross(cross(look, world_up), look)
1456  {
1457  float3 look = { target.x - pos.x, target.y - pos.y, target.z - pos.z };
1458  look = look.normalize();
1459 
1460  float world_up[3] = { 0.0f, 1.0f, 0.0f };
1461 
1462  float across[3] = {
1463  look.y * world_up[2] - look.z * world_up[1],
1464  look.z * world_up[0] - look.x * world_up[2],
1465  look.x * world_up[1] - look.y * world_up[0],
1466  };
1467 
1468  up.x = across[1] * look.z - across[2] * look.y;
1469  up.y = across[2] * look.x - across[0] * look.z;
1470  up.z = across[0] * look.y - across[1] * look.x;
1471 
1472  float up_len = up.length();
1473  up.x /= -up_len;
1474  up.y /= -up_len;
1475  up.z /= -up_len;
1476  }
1477  }
1478 
1480  const stream_model& s_model,
1481  const rect& stream_rect,
1482  std::vector<rgb_per_distance> rgb_per_distance_vec,
1483  float ruler_length,
1484  const std::string& ruler_units)
1485  {
1486  if (rgb_per_distance_vec.empty() || (ruler_length <= 0.f))
1487  return;
1488 
1489  ruler_length = std::ceil(ruler_length);
1490  std::sort(rgb_per_distance_vec.begin(), rgb_per_distance_vec.end(), [](const rgb_per_distance& a,
1491  const rgb_per_distance& b) {
1492  return a.depth_val < b.depth_val;
1493  });
1494 
1495  const auto stream_height = stream_rect.y + stream_rect.h;
1496  const auto stream_width = stream_rect.x + stream_rect.w;
1497 
1498  static const auto ruler_distance_offset = 10;
1499  auto bottom_y_ruler = stream_height - ruler_distance_offset;
1500  if (s_model.texture->zoom_preview)
1501  {
1502  bottom_y_ruler = s_model.texture->curr_preview_rect.y - ruler_distance_offset;
1503  }
1504 
1505  static const auto top_y_offset = 50;
1506  auto top_y_ruler = stream_rect.y + top_y_offset;
1507  if (s_model.show_stream_details)
1508  {
1509  top_y_ruler = s_model.curr_info_rect.y + s_model.curr_info_rect.h + ruler_distance_offset;
1510  }
1511 
1512  static const auto left_x_colored_ruler_offset = 50;
1513  static const auto colored_ruler_width = 20;
1514  const auto left_x_colored_ruler = stream_width - left_x_colored_ruler_offset;
1515  const auto right_x_colored_ruler = stream_width - (left_x_colored_ruler_offset - colored_ruler_width);
1516  assert((bottom_y_ruler - top_y_ruler) != 0.f);
1517  const auto ratio = (bottom_y_ruler - top_y_ruler) / ruler_length;
1518 
1519  // Draw numbered ruler
1520  float y_ruler_val = top_y_ruler;
1521  static const auto numbered_ruler_width = 20.f;
1522 
1523  const auto right_x_numbered_ruler = right_x_colored_ruler + numbered_ruler_width;
1524  static const auto hovered_numbered_ruler_opac = 0.8f;
1525  static const auto unhovered_numbered_ruler_opac = 0.6f;
1526  float colored_ruler_opac = unhovered_numbered_ruler_opac;
1527  float numbered_ruler_background_opac = unhovered_numbered_ruler_opac;
1528  bool is_ruler_hovered = false;
1529  if (mouse.cursor.x >= left_x_colored_ruler &&
1530  mouse.cursor.x <= right_x_numbered_ruler &&
1531  mouse.cursor.y >= top_y_ruler &&
1532  mouse.cursor.y <= bottom_y_ruler)
1533  is_ruler_hovered = true;
1534 
1535  if (is_ruler_hovered)
1536  {
1537  std::stringstream ss;
1538  auto relative_mouse_y = ImGui::GetMousePos().y - top_y_ruler;
1539  auto y = (bottom_y_ruler - top_y_ruler) - relative_mouse_y;
1540  ss << std::fixed << std::setprecision(2) << (y / ratio) << ruler_units;
1541  ImGui::SetTooltip("%s", ss.str().c_str());
1542  colored_ruler_opac = 1.f;
1543  numbered_ruler_background_opac = hovered_numbered_ruler_opac;
1544  }
1545 
1546  // Draw a background to the numbered ruler
1547  glEnable(GL_BLEND);
1549  glColor4f(0.0, 0.0, 0.0, numbered_ruler_background_opac);
1551  glVertex2f(right_x_colored_ruler, top_y_ruler);
1552  glVertex2f(right_x_numbered_ruler , top_y_ruler);
1553  glVertex2f(right_x_numbered_ruler , bottom_y_ruler);
1554  glVertex2f(right_x_colored_ruler, bottom_y_ruler);
1555  glEnd();
1556 
1557 
1558  const float x_ruler_val = right_x_colored_ruler + 4.0f;
1559  ImGui::SetCursorScreenPos({ x_ruler_val, y_ruler_val });
1560  const auto font_size = ImGui::GetFontSize();
1561  ImGui::TextUnformatted(std::to_string(static_cast<int>(ruler_length)).c_str());
1562  const auto skip_numbers = ((ruler_length / 10.f) - 1.f);
1563  auto to_skip = (skip_numbers < 0.f)?0.f: skip_numbers;
1564  for (int i = static_cast<int>(ruler_length - 1); i > 0; --i)
1565  {
1566  y_ruler_val += ((bottom_y_ruler - top_y_ruler) / ruler_length);
1567  ImGui::SetCursorScreenPos({ x_ruler_val, y_ruler_val - font_size / 2 });
1568  if (((to_skip--) > 0))
1569  continue;
1570 
1572  to_skip = skip_numbers;
1573  }
1574  y_ruler_val += ((bottom_y_ruler - top_y_ruler) / ruler_length);
1575  ImGui::SetCursorScreenPos({ x_ruler_val, y_ruler_val - font_size });
1576  ImGui::Text("0");
1577 
1578  auto total_depth_scale = rgb_per_distance_vec.back().depth_val - rgb_per_distance_vec.front().depth_val;
1579  static const auto sensitivity_factor = 0.01f;
1580  auto sensitivity = sensitivity_factor * total_depth_scale;
1581 
1582  // Draw colored ruler
1583  auto last_y = bottom_y_ruler;
1584  auto last_depth_value = 0.f;
1585  size_t last_index = 0;
1586  for (size_t i = 1; i < rgb_per_distance_vec.size(); ++i)
1587  {
1588  auto curr_depth = rgb_per_distance_vec[i].depth_val;
1589  if ((((curr_depth - last_depth_value) < sensitivity) && (i != rgb_per_distance_vec.size() - 1)))
1590  continue;
1591 
1592  glEnable(GL_BLEND);
1594  glBegin(GL_QUADS);
1595  glColor4f(rgb_per_distance_vec[last_index].rgb_val.r / 255.f,
1596  rgb_per_distance_vec[last_index].rgb_val.g / 255.f,
1597  rgb_per_distance_vec[last_index].rgb_val.b / 255.f,
1598  colored_ruler_opac);
1599  glVertex2f(left_x_colored_ruler, last_y);
1600  glVertex2f(right_x_colored_ruler, last_y);
1601 
1602  last_depth_value = curr_depth;
1603  last_index = i;
1604 
1605  auto y = bottom_y_ruler - ((rgb_per_distance_vec[i].depth_val) * ratio);
1606  if ((i == (rgb_per_distance_vec.size() - 1)) || (std::ceil(curr_depth) > ruler_length))
1607  y = top_y_ruler;
1608 
1609  glColor4f(rgb_per_distance_vec[i].rgb_val.r / 255.f,
1610  rgb_per_distance_vec[i].rgb_val.g / 255.f,
1611  rgb_per_distance_vec[i].rgb_val.b / 255.f,
1612  colored_ruler_opac);
1613 
1614  glVertex2f(right_x_colored_ruler, y);
1615  glVertex2f(left_x_colored_ruler, y);
1616  last_y = y;
1617  glEnd();
1618  }
1619 
1620  // Draw ruler border
1621  static const auto top_line_offset = 0.5f;
1622  static const auto right_line_offset = top_line_offset / 2;
1623  glColor4f(0.0, 0.0, 0.0, colored_ruler_opac);
1625  glVertex2f(left_x_colored_ruler - top_line_offset, top_y_ruler - top_line_offset);
1626  glVertex2f(right_x_numbered_ruler + right_line_offset / 2, top_y_ruler - top_line_offset);
1627  glVertex2f(right_x_numbered_ruler + right_line_offset / 2, bottom_y_ruler + top_line_offset);
1628  glVertex2f(left_x_colored_ruler - top_line_offset, bottom_y_ruler + top_line_offset);
1629  glEnd();
1630  }
1631 
1632  float viewer_model::calculate_ruler_max_distance(const std::vector<float>& distances) const
1633  {
1634  assert(!distances.empty());
1635 
1636  float mean = std::accumulate(distances.begin(),
1637  distances.end(), 0.0f) / distances.size();
1638 
1639  float e = 0;
1640  float inverse = 1.f / distances.size();
1641  for (auto elem : distances)
1642  {
1643  e += static_cast<float>(pow(elem - mean, 2));
1644  }
1645 
1646  auto standard_deviation = sqrt(inverse * e);
1647  static const auto length_jump = 4.f;
1648  return std::ceil((mean + 1.5f * standard_deviation) / length_jump) * length_jump;
1649  }
1650 
1651  void viewer_model::render_2d_view(const rect& view_rect,
1652  ux_window& win, int output_height,
1653  ImFont *font1, ImFont *font2, size_t dev_model_num,
1654  const mouse_info &mouse, std::string& error_message)
1655  {
1656  static utilities::time::periodic_timer every_sec(std::chrono::seconds(1));
1657  static bool icon_visible = false;
1658  if (every_sec) icon_visible = !icon_visible;
1659  float alpha = icon_visible ? 1.f : 0.2f;
1660 
1661  glViewport(0, 0,
1662  static_cast<GLsizei>(win.framebuf_width()), static_cast<GLsizei>(win.framebuf_height()));
1663  glLoadIdentity();
1664  glOrtho(0, win.width(), win.height(), 0, -1, +1);
1665 
1666  auto layout = calc_layout(view_rect);
1667 
1668  if ((layout.size() == 0) && (dev_model_num > 0))
1669  {
1670  show_no_stream_overlay(font2, static_cast<int>(view_rect.x), static_cast<int>(view_rect.y), static_cast<int>(win.width()), static_cast<int>(win.height() - output_height));
1671  }
1672  for (auto &&kvp : layout)
1673  {
1674  auto&& view_rect = kvp.second;
1675  auto stream = kvp.first;
1676  auto&& stream_mv = streams[stream];
1677  auto&& stream_size = stream_mv.size;
1678  auto stream_rect = view_rect.adjust_ratio(stream_size).grow(-3);
1679 
1680  stream_mv.show_frame(stream_rect, mouse, error_message);
1681 
1682  auto p = stream_mv.dev->dev.as<playback>();
1683  float posX = stream_rect.x + 9;
1684  float posY = stream_rect.y - 26;
1685 
1686  if (!stream_mv.is_stream_alive())
1687  {
1688  std::string message = to_string() << textual_icons::exclamation_triangle << " No Frames Received!";
1689  show_icon(font2, "warning_icon", message.c_str(),
1690  static_cast<int>(stream_rect.center().x - 100),
1691  static_cast<int>(stream_rect.center().y - 25),
1692  stream_mv.profile.unique_id(),
1693  blend(dark_red, alpha),
1694  "Did not receive frames from the platform within a reasonable time window,\nplease try reducing the FPS or the resolution");
1695  }
1696 
1697  stream_mv.show_stream_header(font1, stream_rect, *this);
1698  stream_mv.show_stream_footer(font1, stream_rect, mouse, streams, *this);
1699 
1700 
1701  if (val_in_range(stream_mv.profile.format(), { RS2_FORMAT_RAW10 , RS2_FORMAT_RAW16, RS2_FORMAT_MJPEG }))
1702  {
1703  show_rendering_not_supported(font2, static_cast<int>(stream_rect.x), static_cast<int>(stream_rect.y), static_cast<int>(stream_rect.w),
1704  static_cast<int>(stream_rect.h), stream_mv.profile.format());
1705  }
1706 
1707  if (stream_mv.dev->_is_being_recorded)
1708  {
1709  show_recording_icon(font2, static_cast<int>(posX), static_cast<int>(posY), stream_mv.profile.unique_id(), alpha);
1710  posX += 23;
1711  }
1712  if (stream_mv.dev->is_paused() || (p && p.current_status() == RS2_PLAYBACK_STATUS_PAUSED))
1713  show_paused_icon(font2, static_cast<int>(posX), static_cast<int>(posY), stream_mv.profile.unique_id());
1714 
1715  auto stream_type = stream_mv.profile.stream_type();
1716 
1717  if (streams[stream].is_stream_visible())
1718  switch (stream_type)
1719  {
1720  {
1721  case RS2_STREAM_GYRO: /* Fall Through */
1722  case RS2_STREAM_ACCEL:
1723  {
1724  auto motion = streams[stream].texture->get_last_frame().as<motion_frame>();
1725  if (motion.get())
1726  {
1727  auto axis = motion.get_motion_data();
1728  stream_mv.show_stream_imu(font1, stream_rect, axis, mouse);
1729  }
1730  break;
1731  }
1732  case RS2_STREAM_POSE:
1733  {
1735  {
1736  auto pose = streams[stream].texture->get_last_frame().as<pose_frame>();
1737  if (pose.get())
1738  {
1739  auto pose_data = pose.get_pose_data();
1740  if (stream_rect.contains(win.get_mouse().cursor))
1741  stream_mv.show_stream_pose(font1,
1742  stream_rect, pose_data,
1743  stream_type, (*this).fullscreen, 30.0f, *this);
1744  }
1745  }
1746 
1747  break;
1748  }
1749  }
1750  }
1751 
1752  //switch( stream_mv.profile.stream_type() )
1753  {
1754  static std::vector< std::pair< ImColor, bool > > colors =
1755  {
1756  { ImColor( 1.f, 1.f, 1.f, 1.f ), false }, // the default color
1757  { ImColor( 1.f, 0.f, 0.f, 1.f ), false },
1758  { ImColor( 0.f, 1.f, 0.f, 1.f ), false },
1759  { ImColor( 0.f, 0.f, 1.f, 1.f ), false },
1760  { ImColor( 1.f, 0.f, 1.f, 1.f ), false },
1761  { ImColor( 1.f, 1.f, 0.f, 1.f ), false },
1762  };
1763  typedef size_t ColorIdx;
1764  static std::map< size_t, ColorIdx > id2color;
1765 
1766  // Returns the color (from those pre-defined above) for the given object, based on its ID
1767  auto get_color = [&]( object_in_frame const & object ) -> ImColor
1768  {
1769  ColorIdx & color = id2color[object.id]; // Creates it with 0 as default if not already there
1770  if( color < int( colors.size() ))
1771  {
1772  if( color > 0 )
1773  return colors[color].first; // Return an already-assigned color
1774  // Find the next available color
1775  size_t x = 0;
1776  for( auto & p : colors )
1777  {
1778  bool & in_use = p.second;
1779  if( !in_use )
1780  {
1781  in_use = true;
1782  color = x;
1783  return p.first;
1784  }
1785  ++x;
1786  }
1787  // No available color; use the default and mark the object so we don't do this again
1788  color = 100;
1789  }
1790  // If we're here it's because there're more objects than colors
1791  return colors[0].first;
1792  };
1793 
1794  glColor3f( 1, 1, 1 );
1795  auto p_objects = stream_mv.dev->detected_objects;
1796  std::lock_guard< std::mutex > lock( p_objects->mutex );
1797 
1798  // Mark colors that are no longer in use
1799  for( auto it = id2color.begin(); it != id2color.end(); )
1800  {
1801  size_t id = it->first;
1802  bool found = false;
1803  for( object_in_frame & object : *p_objects )
1804  {
1805  if( object.id == id )
1806  {
1807  found = true;
1808  break;
1809  }
1810  }
1811  if( !found )
1812  {
1813  colors[it->second].second = false; // no longer in use
1814  auto it_to_erase = it++;
1815  id2color.erase( it_to_erase );
1816  }
1817  else
1818  {
1819  ++it;
1820  }
1821  }
1822 
1823 
1824  for( object_in_frame & object : *p_objects )
1825  {
1826  rect const & normalized_bbox = stream_mv.profile.stream_type() == RS2_STREAM_DEPTH
1827  ? object.normalized_depth_bbox
1828  : object.normalized_color_bbox;
1829  rect bbox = normalized_bbox.unnormalize( stream_rect );
1830  bbox.grow( 10, 5 ); // Allow more text, and easier identification of the face
1831 
1832  float const max_depth = 2.f;
1833  float const min_depth = 0.8f;
1834  float const depth_range = max_depth - min_depth;
1835  float usable_depth = std::min( object.mean_depth, max_depth );
1836  float a = 0.75f * (max_depth - usable_depth) / depth_range + 0.25f;
1837 
1838  // Don't draw text in boxes that are too small...
1839  auto h = bbox.h;
1840  ImGui::PushStyleColor( ImGuiCol_Text, ImColor( 1.f, 1.f, 1.f, a ) );
1842 
1843  if( fabs(object.mean_depth) > 0.f )
1844  {
1845  std::string str = to_string() << std::setprecision( 2 ) << object.mean_depth << " m";
1846  auto size = ImGui::CalcTextSize( str.c_str() );
1847  if( size.y < h && size.x < bbox.w )
1848  {
1850  { bbox.x + 1, bbox.y + 1 },
1851  { bbox.x + size.x + 20, bbox.y + size.y + 6 },
1852  bg );
1853  ImGui::SetCursorScreenPos( { bbox.x + 10, bbox.y + 3 } );
1854  ImGui::Text("%s", str.c_str() );
1855  h -= size.y;
1856  }
1857  }
1858  if( ! object.name.empty() )
1859  {
1860  auto size = ImGui::CalcTextSize( object.name.c_str() );
1861  if( size.y < h && size.x < bbox.w )
1862  {
1864  { bbox.x + bbox.w - size.x - 20, bbox.y + bbox.h - size.y - 6 },
1865  { bbox.x + bbox.w - 1, bbox.y + bbox.h - 1 },
1866  bg );
1867  ImGui::SetCursorScreenPos( { bbox.x + bbox.w - size.x - 10, bbox.y + bbox.h - size.y - 4 } );
1868  ImGui::Text("%s", object.name.c_str() );
1869  h -= size.y;
1870  }
1871  }
1872 
1874 
1875  // The rectangle itself is always drawn, in the same color as the text
1876  auto frame_color = get_color( object );
1877  glColor3f( a * frame_color.Value.x, a * frame_color.Value.y, a * frame_color.Value.z );
1878  draw_rect( bbox );
1879  }
1880  }
1881 
1883  stream_rect.y -= 32;
1884  stream_rect.h += 32;
1885  stream_rect.w += 1;
1886  draw_rect(stream_rect);
1887 
1888  auto frame = streams[stream].texture->get_last_frame().as<video_frame>();
1889  auto textured_frame = streams[stream].texture->get_last_frame(true).as<video_frame>();
1890  if (streams[stream].show_map_ruler && frame && textured_frame &&
1891  RS2_STREAM_DEPTH == stream_mv.profile.stream_type() &&
1892  RS2_FORMAT_Z16 == stream_mv.profile.format())
1893  {
1894  if(RS2_FORMAT_RGB8 == textured_frame.get_profile().format())
1895  {
1896  static const std::string depth_units = "m";
1897  float ruler_length = 0.f;
1898  auto depth_vid_profile = stream_mv.profile.as<video_stream_profile>();
1899  auto depth_width = depth_vid_profile.width();
1900  auto depth_height = depth_vid_profile.height();
1901  auto depth_data = static_cast<const uint16_t*>(frame.get_data());
1902  auto textured_depth_data = static_cast<const uint8_t*>(textured_frame.get_data());
1903  static const auto skip_pixels_factor = 30;
1904  std::vector<rgb_per_distance> rgb_per_distance_vec;
1905  std::vector<float> distances;
1906  for (uint64_t i = 0; i < depth_height; i+= skip_pixels_factor)
1907  {
1908  for (uint64_t j = 0; j < depth_width; j+= skip_pixels_factor)
1909  {
1910  auto depth_index = i*depth_width + j;
1911  auto length = depth_data[depth_index] * stream_mv.dev->depth_units;
1912  if (length > 0.f)
1913  {
1914  auto textured_depth_index = depth_index * 3;
1915  auto r = textured_depth_data[textured_depth_index];
1916  auto g = textured_depth_data[textured_depth_index + 1];
1917  auto b = textured_depth_data[textured_depth_index + 2];
1918  rgb_per_distance_vec.push_back({ length, { r, g, b } });
1919  distances.push_back(length);
1920  }
1921  }
1922  }
1923 
1924  if (!distances.empty())
1925  {
1926  ruler_length = calculate_ruler_max_distance(distances);
1927  draw_color_ruler(mouse, streams[stream], stream_rect, rgb_per_distance_vec, ruler_length, depth_units);
1928  }
1929  }
1930  }
1931  }
1932  }
1933 
1934  void viewer_model::render_3d_view(const rect& viewer_rect, ux_window& win,
1935  std::shared_ptr<texture_buffer> texture, rs2::points points)
1936  {
1937  auto top_bar_height = 60.f;
1938 
1939  if (points)
1940  {
1941  last_points = points;
1942  }
1943  if (texture)
1944  {
1946  }
1947 
1948  auto bottom_y = win.framebuf_height() - viewer_rect.y - viewer_rect.h;
1949 
1950  glViewport(static_cast<GLint>(non_negative(viewer_rect.x)), static_cast<GLint>(non_negative(bottom_y)),
1951  static_cast<GLsizei>(non_negative(viewer_rect.w)), static_cast<GLsizei>(non_negative(viewer_rect.h - top_bar_height)));
1952 
1953  glClearColor(0, 0, 0, 1);
1955 
1956  glLoadIdentity();
1957 
1959  glPushMatrix();
1960  gluPerspective(45, non_negative(viewer_rect.w / win.framebuf_height()), 0.001f, 100.0f);
1961  matrix4 perspective_mat;
1962  glGetFloatv(GL_PROJECTION_MATRIX, perspective_mat);
1963  glPopMatrix();
1964 
1965  check_gl_error();
1966 
1968  glPushMatrix();
1969  glLoadMatrixf((float*)perspective_mat.mat);
1970 
1972  glPushMatrix();
1974 
1975  matrix4 view_mat;
1976  memcpy(&view_mat, view, sizeof(matrix4));
1977 
1979 
1981 
1983  if (show_skybox) _skybox.render(pos);
1985 
1986  auto r1 = matrix4::identity();
1987  auto r2 = matrix4::identity();
1988 
1989  if (draw_plane && !paused)
1990  {
1992  glLineWidth(2);
1993  glBegin(GL_LINES);
1994 
1995  if (is_valid(roi_rect))
1996  {
1997  glColor4f(yellow.x, yellow.y, yellow.z, 1.f);
1998 
1999  auto rects = subdivide(roi_rect);
2000  for (auto&& r : rects)
2001  {
2002  for (int i = 0; i < 4; i++)
2003  {
2004  auto j = (i + 1) % 4;
2005  glVertex3f(r[i].x, r[i].y, r[i].z);
2006  glVertex3f(r[j].x, r[j].y, r[j].z);
2007  }
2008  }
2009  }
2010 
2011  glEnd();
2012  glPopAttrib();
2013  }
2014 
2015  auto x = static_cast<float>(-M_PI / 2);
2016  float _rx[4][4] = {
2017  { 1 , 0, 0, 0 },
2018  { 0, static_cast<float>(cos(x)), static_cast<float>(-sin(x)), 0 },
2019  { 0, static_cast<float>(sin(x)), static_cast<float>(cos(x)), 0 },
2020  { 0, 0, 0, 1 }
2021  };
2022  static const double z = M_PI;
2023  static float _rz[4][4] = {
2024  { float(cos(z)), float(-sin(z)),0, 0 },
2025  { float(sin(z)), float(cos(z)), 0, 0 },
2026  { 0 , 0, 1, 0 },
2027  { 0, 0, 0, 1 }
2028  };
2029  rs2::matrix4 rx(_rx);
2030  rs2::matrix4 rz(_rz);
2031 
2032  int stream_num = 0; // counter to locate the pose info window correctly (currently works for up to 3 streaming devices)
2033  pose_frame pose = frame{};
2034  for (auto&& stream : streams)
2035  {
2036  if (stream.second.profile.stream_type() == RS2_STREAM_POSE)
2037  {
2038  auto f = stream.second.texture->get_last_frame();
2039  if (!f.is<pose_frame>())
2040  {
2041  continue;
2042  }
2043 
2044  pose = f;
2045  rs2_pose pose_data = pose.get_pose_data();
2046 
2047  auto t = tm2_pose_to_world_transformation(pose_data);
2048  float model[4][4];
2049  t.to_column_major((float*)model);
2050  auto m = model;
2051 
2052  r1 = m * rx;
2053  r2 = rz * m * rx;
2054 
2055  // set the pose transformation as the model matrix to draw the axis
2057  glPushMatrix();
2059 
2060  glMultMatrixf((float*)_rx);
2061 
2062  streams[f.get_profile().unique_id()].dev->tm2.draw_trajectory(trajectory_button.is_pressed());
2063 
2064  // remove model matrix from the rest of the render
2065  glPopMatrix();
2066 
2069 
2070  if (f)
2071  {
2073  glEnable(GL_BLEND);
2074 
2076 
2077  // Render camera model (based on source_frame camera type)
2078  f.apply_filter(_cam_renderer);
2079 
2082  }
2083 
2084  stream_num++;
2085  }
2086  }
2087 
2088 
2089  check_gl_error();
2090 
2091  {
2092  float tiles = 24;
2093  if (!metric_system) tiles *= 1.f / FEET_TO_METER;
2094 
2095  glTranslatef(0, 0, -1);
2096  glLineWidth(1);
2097 
2098  // Render "floor" grid
2099  glBegin(GL_LINES);
2100 
2101  auto T = tiles * 0.5f;
2102 
2103  if (!metric_system) T *= FEET_TO_METER;
2104 
2105  for (int i = 0; i <= ceil(tiles); i++)
2106  {
2107  float I = float(i);
2108  if (!metric_system) I *= FEET_TO_METER;
2109 
2110  if (i == tiles / 2) glColor4f(0.7f, 0.7f, 0.7f, 1.f);
2111  else glColor4f(0.4f, 0.4f, 0.4f, 1.f);
2112 
2113  glVertex3f(I - T, 1, -T);
2114  glVertex3f(I - T, 1, T);
2115  glVertex3f(-T, 1, I - T);
2116  glVertex3f(T, 1, I - T);
2117  }
2118  glEnd();
2119  }
2120 
2121  check_gl_error();
2122 
2123  if (!pose && !_pc_selected)
2124  {
2126  glPushMatrix();
2127  glLoadMatrixf(r1 * view_mat);
2129  glPopMatrix();
2130  }
2131 
2132  check_gl_error();
2133 
2134  glColor4f(1.f, 1.f, 1.f, 1.f);
2135 
2137  glPushMatrix();
2138  glLoadMatrixf(r1 * view_mat);
2139  if (draw_frustrum && last_points)
2140  {
2141  glLineWidth(1.f);
2142  glBegin(GL_LINES);
2143 
2144  auto intrin = last_points.get_profile().as<video_stream_profile>().get_intrinsics();
2145 
2147  else glColor4f(sensor_bg.x, sensor_bg.y, sensor_bg.z, 0.5f);
2148 
2149  for (float d = 1; d < 6; d += 2)
2150  {
2151  auto get_point = [&](float x, float y) -> float3
2152  {
2153  float point[3];
2154  float pixel[2]{ x, y };
2156  glVertex3f(0.f, 0.f, 0.f);
2157  glVertex3fv(point);
2158  return{ point[0], point[1], point[2] };
2159  };
2160 
2161  auto top_left = get_point(0, 0);
2162  auto top_right = get_point(static_cast<float>(intrin.width), 0);
2163  auto bottom_right = get_point(static_cast<float>(intrin.width), static_cast<float>(intrin.height));
2164  auto bottom_left = get_point(0, static_cast<float>(intrin.height));
2165 
2166  glVertex3fv(&top_left.x); glVertex3fv(&top_right.x);
2167  glVertex3fv(&top_right.x); glVertex3fv(&bottom_right.x);
2168  glVertex3fv(&bottom_right.x); glVertex3fv(&bottom_left.x);
2169  glVertex3fv(&bottom_left.x); glVertex3fv(&top_left.x);
2170  }
2171 
2172  glEnd();
2173 
2174  glColor4f(1.f, 1.f, 1.f, 1.f);
2175  }
2176 
2177  check_gl_error();
2178 
2179  if (last_points && last_texture)
2180  {
2181  auto vf_profile = last_points.get_profile().as<video_stream_profile>();
2182  // Non-linear correspondence customized for non-flat surface exploration
2183  glPointSize(std::sqrt(viewer_rect.w / vf_profile.width()));
2184 
2185  auto tex = last_texture->get_gl_handle();
2188 
2191 
2194 
2197 
2199 
2200  auto viewport_rect = viewer_rect;
2201 
2202  auto cursor = win.get_mouse().cursor;
2203  auto scaled_cursor = cursor;
2204  scaled_cursor.x *= win.get_scale_factor();
2205  scaled_cursor.y *= win.get_scale_factor();
2206  if (viewport_rect.contains(scaled_cursor))
2207  {
2210 
2213  }
2214 
2215  // Render Point-Cloud
2217 
2219  {
2220  float3 p {
2224  };
2225  float3 normal {
2229  };
2231 
2232  // Adjust track-ball controller based on picked position
2233  // 1. Place target at the closest point to p, along (pos, target) interval
2234  // 2. When zooming-in, move camera target and position toward p
2235  if (!win.get_mouse().mouse_down[0])
2236  {
2237  auto x1x2 = target - pos;
2238  auto x1x0 = p - pos;
2239  auto t = (x1x2 * x1x0) / (x1x2 * x1x2);
2240  auto p1 = pos + x1x2* t;
2241 
2242  if (t > 0) { // Don't adjust if pointcloud is behind us
2243  target = lerp(p1, target, 0.9f);
2244 
2245  if (win.get_mouse().mouse_wheel > 0)
2246  {
2247  pos = lerp(p, pos, 0.9f);
2248  target = lerp(p, target, 0.9f);
2249  }
2250  }
2251  }
2252 
2253  //try_select_pointcloud(win);
2254  }
2255 
2257 
2260 
2261  if (streams.find(selected_depth_source_uid) != streams.end())
2262  {
2263  auto source_frame = streams[selected_depth_source_uid].texture->get_last_frame();
2264  if (source_frame)
2265  {
2267  glEnable(GL_BLEND);
2268 
2270 
2271  // _cam_renderer.set_option(gl::camera_renderer::OPTION_SELECTED, _pc_selected ? 1.f : 0.f);
2272 
2273  // if (viewer_rect.contains(cursor))
2274  // {
2275  // _cam_renderer.set_option(gl::camera_renderer::OPTION_MOUSE_PICK, 1.f);
2276  // _cam_renderer.set_option(gl::camera_renderer::OPTION_MOUSE_X, cursor.x);
2277  // _cam_renderer.set_option(gl::camera_renderer::OPTION_MOUSE_Y, cursor.y);
2278  // }
2279 
2280  // only display camera when it does not occlude point cloud
2283  source_frame.apply_filter(_cam_renderer);
2284 
2285  // if (_cam_renderer.get_option(gl::camera_renderer::OPTION_WAS_PICKED) > 0.f)
2286  // {
2287  // try_select_pointcloud(win);
2288  // }
2289 
2292  }
2293  }
2294  }
2295 
2296  check_gl_error();
2297 
2298  _measurements.draw(win);
2299 
2300  glPopMatrix();
2301 
2302  glPopMatrix();
2304  glPopMatrix();
2305 
2307 
2308  if (ImGui::IsKeyPressed('R') || ImGui::IsKeyPressed('r'))
2309  {
2310  reset_camera();
2311  }
2312  }
2313 
2315  {
2319 
2322 
2325  ImGui::Begin("Toolbar Panel", nullptr, flags);
2326 
2327  ImGui::PushFont(window.get_large_font());
2329 
2330  int buttons = window.is_fullscreen() ? 4 : 3;
2331 
2332  ImGui::SetCursorPosX(window.width() - panel_width - panel_y * (buttons));
2335  if (ImGui::Button("2D", { panel_y, panel_y }))
2336  {
2337  is_3d_view = false;
2339  }
2341  ImGui::SameLine();
2342 
2343  ImGui::SetCursorPosX(window.width() - panel_width - panel_y * (buttons - 1));
2344  auto pos1 = ImGui::GetCursorScreenPos();
2345 
2348  if (ImGui::Button("3D", { panel_y,panel_y }))
2349  {
2350  is_3d_view = true;
2352  update_3d_camera(window, viewer_rect, true);
2353  }
2354 
2356  ImGui::SameLine();
2357 
2358  ImGui::SetCursorPosX(window.width() - panel_width - panel_y * (buttons - 2));
2359 
2360  static bool settings_open = false;
2361  ImGui::PushStyleColor(ImGuiCol_Text, !settings_open ? light_grey : light_blue);
2362  ImGui::PushStyleColor(ImGuiCol_TextSelectedBg, !settings_open ? light_grey : light_blue);
2363 
2364  if (ImGui::Button(u8"\uf013", { panel_y,panel_y }))
2365  {
2366  ImGui::OpenPopup("More Options");
2367  }
2368 
2369  if (ImGui::IsItemHovered())
2370  {
2371  ImGui::SetTooltip("%s", "More Options...");
2372  }
2373 
2374  if (window.is_fullscreen())
2375  {
2376  ImGui::SameLine();
2377  ImGui::SetCursorPosX(window.width() - panel_width - panel_y * (buttons - 4));
2378 
2383  {
2384  exit(0);
2385  }
2386  if (ImGui::IsItemHovered())
2387  {
2388  ImGui::SetTooltip("Exit the App");
2389  window.link_hovered();
2390  }
2392  }
2393 
2394  ImGui::PopFont();
2395 
2401 
2402  ImGui::PushFont(window.get_font());
2403 
2404  auto settings = "Settings";
2405  auto about = "About";
2406  bool open_settings_popup = false;
2407  bool open_about_popup = false;
2408 
2409  ImGui::SetNextWindowPos({ window.width() - 100, panel_y });
2410  ImGui::SetNextWindowSize({ 100, 90 });
2411 
2412  if (ImGui::BeginPopup("More Options"))
2413  {
2414  settings_open = true;
2415 
2416  if (ImGui::Selectable("Report Issue"))
2417  {
2418  open_issue(devices);
2419  }
2420 
2421  if (ImGui::Selectable("Intel Store"))
2422  {
2423  open_url("https://store.intelrealsense.com/");
2424  }
2425 
2426  if (ImGui::Selectable(settings))
2427  {
2428  open_settings_popup = true;
2429  }
2430 
2431  ImGui::Separator();
2432 
2433  if (ImGui::Selectable(about))
2434  {
2435  open_about_popup = true;
2436  }
2437 
2438  ImGui::EndPopup();
2439  }
2440  else
2441  {
2442  settings_open = false;
2443  }
2444 
2445  static config_file temp_cfg;
2446  static bool reload_required = false;
2447  static bool refresh_required = false;
2448  static bool refresh_updates = false;
2449 
2450  static int tab = 0;
2451 
2452  if (open_settings_popup)
2453  {
2454  temp_cfg = config_file::instance();
2455  ImGui::OpenPopup(settings);
2456  reload_required = false;
2457  refresh_required = false;
2459  }
2460 
2461  {
2462  float w = window.width() * 0.6f;
2463  float h = window.height() * 0.6f;
2464  float x0 = window.width() * 0.2f;
2465  float y0 = window.height() * 0.2f;
2466  ImGui::SetNextWindowPos({ x0, y0 });
2467  ImGui::SetNextWindowSize({ w, h });
2468 
2471 
2472  ImGui_ScopePushFont(window.get_font());
2478 
2479  if (ImGui::BeginPopupModal(settings, nullptr, flags))
2480  {
2482 
2483  ImGui::SetCursorScreenPos({ (float)(x0 + w / 2 - 280), (float)(y0 + 27) });
2486  ImGui::PushFont(window.get_large_font());
2487 
2488  ImGui::PushStyleColor(ImGuiCol_Text, tab != 0 ? light_grey : light_blue);
2489  ImGui::PushStyleColor(ImGuiCol_TextSelectedBg, tab != 0 ? light_grey : light_blue);
2490  if (ImGui::Button("Playback & Record", { 170, 30}))
2491  {
2492  tab = 0;
2495  }
2497  ImGui::SameLine();
2498 
2499  ImGui::PushStyleColor(ImGuiCol_Text, tab != 1 ? light_grey : light_blue);
2500  ImGui::PushStyleColor(ImGuiCol_TextSelectedBg, tab != 1 ? light_grey : light_blue);
2501  if (ImGui::Button("Performance", { 150, 30}))
2502  {
2503  tab = 1;
2506  }
2508  ImGui::SameLine();
2509 
2510  ImGui::PushStyleColor(ImGuiCol_Text, tab != 2 ? light_grey : light_blue);
2511  ImGui::PushStyleColor(ImGuiCol_TextSelectedBg, tab != 2 ? light_grey : light_blue);
2512  if (ImGui::Button("General", { 100, 30}))
2513  {
2514  tab = 2;
2517  }
2519  ImGui::SameLine();
2520 
2521  ImGui::PushStyleColor(ImGuiCol_Text, tab != 3 ? light_grey : light_blue);
2522  ImGui::PushStyleColor(ImGuiCol_TextSelectedBg, tab != 3 ? light_grey : light_blue);
2523 
2524  if (ImGui::Button("Updates", { 120, 30 }))
2525  {
2526  tab = 3;
2529  }
2530 
2532  ImGui::PopFont();
2533  ImGui::PopStyleColor(2); // button color
2534 
2535  ImGui::SetCursorScreenPos({ (float)(x0 + 15), (float)(y0 + 65) });
2536  ImGui::Separator();
2537 
2538  if (tab == 0)
2539  {
2540  int recording_setting = temp_cfg.get(configurations::record::file_save_mode);
2541  ImGui::Text("When starting a new recording:");
2542  if (ImGui::RadioButton("Select filename automatically", recording_setting == 0))
2543  {
2544  recording_setting = 0;
2545  temp_cfg.set(configurations::record::file_save_mode, recording_setting);
2546  }
2547  if (ImGui::RadioButton("Ask me every time", recording_setting == 1))
2548  {
2549  recording_setting = 1;
2550  temp_cfg.set(configurations::record::file_save_mode, recording_setting);
2551  }
2552  ImGui::Text("Default recording folder: ");
2553  ImGui::SameLine();
2554  static char path[256];
2555  memset(path, 0, 256);
2557  memcpy(path, path_str.c_str(), std::min(255, (int)path_str.size()));
2558 
2559  if (ImGui::InputText("##default_record_path", path, 255))
2560  {
2561  path_str = path;
2562  temp_cfg.set(configurations::record::default_path, path_str);
2563  }
2564 
2565  ImGui::Separator();
2566 
2567  ImGui::Text("ROS-bag Compression:");
2568  int recording_compression = temp_cfg.get(configurations::record::compression_mode);
2569  if (ImGui::RadioButton("Always Compress (might cause frame drops)", recording_compression == 0))
2570  {
2571  recording_compression = 0;
2572  temp_cfg.set(configurations::record::compression_mode, recording_compression);
2573  }
2574  if (ImGui::RadioButton("Never Compress (larger .bag file size)", recording_compression == 1))
2575  {
2576  recording_compression = 1;
2577  temp_cfg.set(configurations::record::compression_mode, recording_compression);
2578  }
2579  if (ImGui::RadioButton("Use device defaults", recording_compression == 2))
2580  {
2581  recording_compression = 2;
2582  temp_cfg.set(configurations::record::compression_mode, recording_compression);
2583  }
2584  }
2585 
2586  if (tab == 1)
2587  {
2588  int font_samples = temp_cfg.get(configurations::performance::font_oversample);
2589  ImGui::Text("Font Samples: ");
2590  if (ImGui::IsItemHovered())
2591  ImGui::SetTooltip("Increased font samples produce nicer text, but require more GPU memory, sometimes resulting in boxes instead of font characters");
2592  ImGui::SameLine();
2594  if (ImGui::SliderInt("##font_samples", &font_samples, 1, 8))
2595  {
2596  reload_required = true;
2597  temp_cfg.set(configurations::performance::font_oversample, font_samples);
2598  }
2600 
2601 #ifndef __APPLE__ // Not available at the moment on Mac
2602  bool gpu_rendering = temp_cfg.get(configurations::performance::glsl_for_rendering);
2603  if (ImGui::Checkbox("Use GLSL for Rendering", &gpu_rendering))
2604  {
2605  refresh_required = true;
2606  temp_cfg.set(configurations::performance::glsl_for_rendering, gpu_rendering);
2607  }
2608  if (ImGui::IsItemHovered())
2609  ImGui::SetTooltip("Using OpenGL 3 shaders is a widely supported way to boost rendering speeds on modern GPUs.");
2610 
2611  bool gpu_processing = temp_cfg.get(configurations::performance::glsl_for_processing);
2612  if (ImGui::Checkbox("Use GLSL for Processing", &gpu_processing))
2613  {
2614  refresh_required = true;
2615  temp_cfg.set(configurations::performance::glsl_for_processing, gpu_processing);
2616  }
2617  if (ImGui::IsItemHovered())
2618  ImGui::SetTooltip("Using OpenGL 3 shaders for depth data processing can reduce CPU utilisation.");
2619 
2620  if (gpu_processing && !gpu_rendering)
2621  {
2623  ImGui::Text(u8"\uf071 Using GLSL for processing but not for rendering can reduce CPU utilisation, but is likely to hurt overall performance!");
2625  }
2626 #endif
2627  bool msaa = temp_cfg.get(configurations::performance::enable_msaa);
2628  if (ImGui::Checkbox("Enable Multisample Anti-Aliasing (MSAA)", &msaa))
2629  {
2630  reload_required = true;
2632  }
2633  if (ImGui::IsItemHovered())
2634  ImGui::SetTooltip("MSAA will improve the rendering quality of edges at expense of greater GPU memory utilisation.");
2635 
2636  if (msaa)
2637  {
2639  ImGui::Text("MSAA Samples: "); ImGui::SameLine();
2640  ImGui::PushItemWidth(160);
2641  if (ImGui::SliderInt("##samples", &samples, 2, 16))
2642  {
2643  reload_required = true;
2645  }
2647  }
2648 
2650  if (ImGui::Checkbox("Show Application FPS (rendering FPS)", &show_fps))
2651  {
2652  reload_required = true;
2653  temp_cfg.set(configurations::performance::show_fps, show_fps);
2654  }
2655  if (ImGui::IsItemHovered())
2656  ImGui::SetTooltip("Show application refresh rate in window title\nThis rate is unrelated to camera FPS and measures application responsivness");
2657 
2658 
2659  bool vsync = temp_cfg.get(configurations::performance::vsync);
2660  if (ImGui::Checkbox("Enable VSync", &vsync))
2661  {
2662  reload_required = true;
2663  temp_cfg.set(configurations::performance::vsync, vsync);
2664  }
2665  if (ImGui::IsItemHovered())
2666  ImGui::SetTooltip("Vertical sync will try to synchronize application framerate to the monitor refresh-rate (usually limiting the framerate to 60)");
2667 
2669  if (ImGui::Checkbox("Fullscreen (F8)", &fullscreen))
2670  {
2671  reload_required = true;
2672  temp_cfg.set(configurations::window::is_fullscreen, fullscreen);
2673  }
2674 
2676  if (ImGui::Checkbox("Show Skybox in 3D View", &show_skybox))
2677  {
2678  temp_cfg.set(configurations::performance::show_skybox, show_skybox);
2679  }
2680  if (ImGui::IsItemHovered())
2681  ImGui::SetTooltip("When enabled, this option provides background to the 3D view, instead of leaving it blank.\nThis is purely cosmetic");
2682 
2683  bool enable_occlusion_invalidation = temp_cfg.get(configurations::performance::occlusion_invalidation);
2684  if (ImGui::Checkbox("Perform Occlusion Invalidation", &enable_occlusion_invalidation))
2685  {
2686  temp_cfg.set(configurations::performance::occlusion_invalidation, enable_occlusion_invalidation);
2687  }
2688  if (ImGui::IsItemHovered())
2689  ImGui::SetTooltip("Occlusions are a natural side-effect of having multiple sensors\nWhen this option is enabled, the SDK will filter out occluded pixels");
2690  }
2691 
2692  if (tab == 2)
2693  {
2694  ImGui::Text("Units of Measurement: ");
2695  ImGui::SameLine();
2696 
2698  std::vector<std::string> unit_systems;
2699  unit_systems.push_back("Imperial System");
2700  unit_systems.push_back("Metric System");
2701 
2702  ImGui::PushItemWidth(150);
2703  if (draw_combo_box("##units_system", unit_systems, metric_system))
2704  {
2705  temp_cfg.set(configurations::viewer::metric_system, metric_system);
2706  }
2708 
2709  ImGui::Separator();
2710 
2711  ImGui::Text("librealsense has built-in logging capabilities.");
2712  ImGui::Text("Logs may contain API calls, timing of frames, OS error messages and file-system links, but no actual frame content.");
2713 
2715  if (ImGui::Checkbox("Output librealsense log to console", &log_to_console))
2716  {
2717  temp_cfg.set(configurations::viewer::log_to_console, log_to_console);
2718  }
2720  if (ImGui::Checkbox("Output librealsense log to file", &log_to_file))
2721  {
2722  temp_cfg.set(configurations::viewer::log_to_file, log_to_file);
2723  }
2724  if (log_to_file)
2725  {
2726  ImGui::Text("Log file name:");
2727  ImGui::SameLine();
2728  static char logpath[256];
2729  memset(logpath, 0, 256);
2731  memcpy(logpath, path_str.c_str(), std::min(255, (int)path_str.size()));
2732 
2733  if (ImGui::InputText("##default_log_path", logpath, 255))
2734  {
2735  path_str = logpath;
2736  temp_cfg.set(configurations::viewer::log_filename, path_str);
2737  }
2738  }
2739  if (log_to_console || log_to_file)
2740  {
2741  int new_severity = temp_cfg.get(configurations::viewer::log_severity);
2742 
2743  std::vector<std::string> severities;
2744  for (int i = 0; i < RS2_LOG_SEVERITY_COUNT; i++)
2745  severities.push_back(rs2_log_severity_to_string((rs2_log_severity)i));
2746 
2747  ImGui::Text("Minimal log severity:");
2748  ImGui::SameLine();
2749 
2750  ImGui::PushItemWidth(150);
2751  if (draw_combo_box("##log_severity", severities, new_severity))
2752  {
2753  temp_cfg.set(configurations::viewer::log_severity, new_severity);
2754  }
2756  }
2757 
2758 
2759  ImGui::Separator();
2760 
2761  {
2762  ImGui::Text("Commands.xml Path:");
2763  ImGui::SameLine();
2764  static char logpath[256];
2765  memset(logpath, 0, 256);
2767  memcpy(logpath, path_str.c_str(), std::min(255, (int)path_str.size()));
2768 
2769  if (ImGui::InputText("##commands_xml_path", logpath, 255))
2770  {
2771  path_str = logpath;
2772  temp_cfg.set(configurations::viewer::commands_xml, path_str);
2773  }
2774  }
2775 
2776  {
2777  ImGui::Text("HWLoggerEvents.xml Path:");
2778  ImGui::SameLine();
2779  static char logpath[256];
2780  memset(logpath, 0, 256);
2782  memcpy(logpath, path_str.c_str(), std::min(255, (int)path_str.size()));
2783 
2784  if (ImGui::InputText("##fw_log_xml_path", logpath, 255))
2785  {
2786  path_str = logpath;
2787  temp_cfg.set(configurations::viewer::hwlogger_xml, path_str);
2788  }
2789  }
2790 
2791  ImGui::Separator();
2792 
2793  ImGui::Text("RealSense tools settings capture the state of UI, and not of the hardware:");
2794 
2795  if (ImGui::Button(" Restore Defaults "))
2796  {
2797  reload_required = true;
2798  temp_cfg = config_file();
2799  }
2800  ImGui::SameLine();
2801  if (ImGui::Button(" Export Settings "))
2802  {
2803  auto ret = file_dialog_open(save_file, "JavaScript Object Notation (JSON)\0*.json\0", NULL, NULL);
2804  if (ret)
2805  {
2806  try
2807  {
2808  std::string filename = ret;
2809  filename = to_lower(filename);
2810  if (!ends_with(filename, ".json")) filename += ".json";
2811  temp_cfg.save(filename.c_str());
2812  }
2813  catch (...){}
2814  }
2815  }
2816  ImGui::SameLine();
2817  if (ImGui::Button(" Import Settings "))
2818  {
2819  auto ret = file_dialog_open(open_file, "JavaScript Object Notation (JSON)\0*.json\0", NULL, NULL);
2820  if (ret)
2821  {
2822  try
2823  {
2824  config_file file(ret);
2825  temp_cfg = file;
2826  reload_required = true;
2827  }
2828  catch (...){}
2829  }
2830  }
2831  }
2832 
2833  if (tab == 3)
2834  {
2835  bool recommend_fw_updates = temp_cfg.get(configurations::update::recommend_updates);
2836  if (ImGui::Checkbox("Recommend Bundled Firmware", &recommend_fw_updates))
2837  {
2838  temp_cfg.set(configurations::update::recommend_updates, recommend_fw_updates);
2839  refresh_updates = true;
2840  }
2841  if (ImGui::IsItemHovered())
2842  {
2843  ImGui::SetTooltip("%s", "When firmware of the device is below the version bundled with this software release\nsuggest firmware update");
2844  }
2845 #ifdef CHECK_FOR_UPDATES
2846  ImGui::Separator();
2847 
2848  ImGui::Text("%s", "SW/FW Updates From Server:");
2849  if (ImGui::IsItemHovered())
2850  {
2851  ImGui::SetTooltip("%s", "Select the server URL of the SW/FW updates information");
2852  }
2853  ImGui::SameLine();
2854 
2855  static bool official_url(temp_cfg.get(configurations::update::sw_updates_official_server));
2856  static char custom_url[256] = { 0 };
2857  static std::string url_str = (temp_cfg.get(configurations::update::sw_updates_url));
2858  memcpy(custom_url, url_str.c_str(), std::min(255, (int)url_str.size()));
2859  if (ImGui::RadioButton("Official Server", official_url))
2860  {
2861  official_url = true;
2864  }
2865  ImGui::SameLine();
2866  if (ImGui::RadioButton("Custom Server", !official_url))
2867  {
2868  official_url = false;
2869  }
2870  if (ImGui::IsItemHovered())
2871  {
2872  ImGui::SetTooltip("%s", "Add file:// prefix to use a local DB file ");
2873  }
2874 
2875  if (!official_url)
2876  {
2877  if (ImGui::InputText("##custom_server_url", custom_url, 255))
2878  {
2879  url_str = custom_url;
2880  }
2881  ImGui::SameLine();
2882  if (ImGui::Button("Update URL", ImVec2(80, 20)))
2883  {
2884  temp_cfg.set(configurations::update::sw_updates_url, url_str);
2886  }
2887  }
2888 #endif
2889  }
2890 
2891  ImGui::Separator();
2892 
2893  ImGui::GetWindowDrawList()->AddRectFilled({ (float)x0, (float)(y0 + h - 60) },
2894  { (float)(x0 + w), (float)(y0 + h) }, ImColor(sensor_bg));
2895 
2896  ImGui::SetCursorScreenPos({ (float)(x0 + 15), (float)(y0 + h - 60) });
2897  if (reload_required)
2898  {
2900  ImGui::Text(u8"\uf071 The application will be restarted in order for new settings to take effect");
2902  }
2903 
2904  auto apply = [&](){
2905  config_file::instance() = temp_cfg;
2906  window.on_reload_complete = [this](){
2907  _skybox.reset();
2908  };
2909  if (reload_required) window.reload();
2910  else if (refresh_required) window.refresh();
2912 
2913  if (refresh_updates)
2914  for (auto&& dev : devices)
2915  dev->refresh_notifications(*this);
2916  };
2917 
2918  ImGui::SetCursorScreenPos({ (float)(x0 + w / 2 - 190), (float)(y0 + h - 30) });
2919  if (ImGui::Button("OK", ImVec2(120, 0)))
2920  {
2922  apply();
2923  }
2924  if (ImGui::IsItemHovered())
2925  {
2926  ImGui::SetTooltip("%s", "Save settings and close");
2927  }
2928  ImGui::SameLine();
2929 
2930  auto configs_same = temp_cfg == config_file::instance();
2931  ImGui::PushStyleColor(ImGuiCol_Text, configs_same ? light_grey : light_blue);
2932  ImGui::PushStyleColor(ImGuiCol_TextSelectedBg, configs_same ? light_grey : light_blue);
2933  if (ImGui::Button("Apply", ImVec2(120, 0)))
2934  {
2935  apply();
2936  }
2938  if (ImGui::IsItemHovered())
2939  {
2940  ImGui::SetTooltip("%s", "Save settings");
2941  }
2942  ImGui::SameLine();
2943  if (ImGui::Button("Cancel", ImVec2(120, 0)))
2944  {
2946  }
2947  if (ImGui::IsItemHovered())
2948  {
2949  ImGui::SetTooltip("%s", "Close window without saving any changes to the settings");
2950  }
2951 
2952  ImGui::EndPopup();
2953  }
2954 
2956  ImGui::PopStyleVar(2);
2957  }
2958 
2959  if (open_about_popup)
2960  {
2961  ImGui::OpenPopup(about);
2962  }
2963 
2964  {
2965  float w = 590.f;
2966  float h = 300.f;
2967  float x0 = (window.width() - w) / 2.f;
2968  float y0 = (window.height() - h) / 2.f;
2969  ImGui::SetNextWindowPos({ x0, y0 });
2970  ImGui::SetNextWindowSize({ w, h });
2971 
2974 
2975  ImGui_ScopePushFont(window.get_font());
2981 
2982  if (ImGui::BeginPopupModal(about, nullptr, flags))
2983  {
2984  ImGui::Image((void*)(intptr_t)window.get_splash().get_gl_handle(),
2985  ImVec2(w - 30, 100), {0.20f, 0.38f}, {0.80f, 0.56f});
2986 
2987  auto realsense_pos = ImGui::GetCursorPos();
2988  ImGui::Text("Intel RealSense is a suite of depth-sensing and motion-tracking technologies.");
2989 
2990  ImGui::Text("librealsense is an open-source cross-platform SDK for working with RealSense devices.");
2991 
2992  ImGui::Text("Full source code is available at"); ImGui::SameLine();
2993  auto github_pos = ImGui::GetCursorPos();
2994  ImGui::Text("github.com/IntelRealSense/librealsense.");
2995 
2996  ImGui::Text("This software is distributed under the"); ImGui::SameLine();
2997  auto license_pos = ImGui::GetCursorPos();
2998  ImGui::Text("Apache License, Version 2.0.");
2999 
3000  ImGui::Text("RealSense is a registered trademark of Intel Corporation.");
3001 
3002  ImGui::Text("Copyright 2018 Intel Corporation.");
3003 
3004  if( RS2_API_BUILD_VERSION )
3005  {
3006  ImGui::Text( "---" );
3007  ImGui::Text( "Full version: " );
3008  ImGui::SameLine();
3010  }
3011 
3015  ImGui::PushStyleColor(ImGuiCol_Text, light_blue);
3016 
3017  ImGui::SetCursorPos({ realsense_pos.x - 4, realsense_pos.y - 3 });
3018 
3019  hyperlink(window, "Intel RealSense", "https://realsense.intel.com/");
3020 
3021  ImGui::SetCursorPos({ github_pos.x - 4, github_pos.y - 3 });
3022  hyperlink(window, "github.com/IntelRealSense/librealsense", "https://github.com/IntelRealSense/librealsense/");
3023 
3024  ImGui::SetCursorPos({ license_pos.x - 4, license_pos.y - 3 });
3025 
3026  hyperlink(window, "Apache License, Version 2.0", "https://raw.githubusercontent.com/IntelRealSense/librealsense/master/LICENSE");
3027 
3029 
3030 
3031  ImGui::SetCursorScreenPos({ (float)(x0 + w / 2 - 60), (float)(y0 + h - 30) });
3032  if (ImGui::Button("OK", ImVec2(120, 0))) ImGui::CloseCurrentPopup();
3033 
3034  ImGui::EndPopup();
3035  }
3036 
3038  ImGui::PopStyleVar(2);
3039  }
3040 
3043 
3044  ImGui::GetWindowDrawList()->AddLine({ pos1.x, pos1.y + 10 }, { pos1.x,pos1.y + panel_y - 10 }, ImColor(light_grey));
3045 
3046 
3047  ImGui::SameLine();
3049 
3054 
3056 
3059  ImGui::PopFont();
3060 
3061  ImGui::End();
3064  }
3065 
3067  ux_window& win,
3068  const rect& viewer_rect, bool force)
3069  {
3070  if (_measurements.manipulating()) return;
3071  if (win.get_hovered_over_input()) return;
3072 
3073  mouse_info& mouse = win.get_mouse();
3075  static auto view_clock = std::chrono::high_resolution_clock::now();
3076  auto sec_since_update = std::chrono::duration<float, std::milli>(now - view_clock).count() / 1000;
3077  view_clock = now;
3078 
3079  if (fixed_up)
3080  up = { 0.f, -1.f, 0.f };
3081 
3082  auto dir = target - pos;
3083  auto x_axis = cross(dir, up);
3084  auto step = sec_since_update * 0.3f;
3085 
3086  if (ImGui::IsKeyPressed('w') || ImGui::IsKeyPressed('W'))
3087  {
3088  pos = pos + dir * step;
3089  target = target + dir * step;
3090  }
3091  if (ImGui::IsKeyPressed('s') || ImGui::IsKeyPressed('S'))
3092  {
3093  pos = pos - dir * step;
3094  target = target - dir * step;
3095  }
3096  if (ImGui::IsKeyPressed('d') || ImGui::IsKeyPressed('D'))
3097  {
3098  pos = pos + x_axis * step;
3099  target = target + x_axis * step;
3100  }
3101  if (ImGui::IsKeyPressed('a') || ImGui::IsKeyPressed('A'))
3102  {
3103  pos = pos - x_axis * step;
3104  target = target - x_axis * step;
3105  }
3106 
3107  if (viewer_rect.contains(mouse.cursor) || force)
3108  {
3109  // Whenever the mouse reaches the end of the window
3110  // and jump back to the start, it will add to the overflow
3111  // counter, so by adding the overflow value
3112  // we essentially emulate an infinite display
3113  auto cx = mouse.cursor.x + overflow.x;
3114  auto px = mouse.prev_cursor.x + overflow.x;
3115  auto cy = mouse.cursor.y + overflow.y;
3116  auto py = mouse.prev_cursor.y + overflow.y;
3117 
3118  auto dragging = ImGui::IsKeyDown(GLFW_KEY_LEFT_CONTROL);
3119 
3120  // Limit how much user mouse can jump between frames
3121  // This can work poorly when the app FPS is really terrible (< 10)
3122  // but overall works resonably well
3123  const auto MAX_MOUSE_JUMP = 200;
3124  const auto SCROLL_SLOW_MAX_TIME_MS = 50;
3125  const auto SCROLL_FAST_MIN_TIME_MS = 500;
3126  float zoom_per_tick = 0.2f;
3127  static auto prev_scroll_time = std::chrono::high_resolution_clock::now();
3128  if (mouse.mouse_wheel != 0)
3129  {
3130  auto scroll_time = std::chrono::high_resolution_clock::now();
3131  auto delta_scroll_time = std::chrono::duration_cast<std::chrono::milliseconds>(scroll_time - prev_scroll_time).count();
3132  prev_scroll_time = scroll_time;
3133 
3134  // scrolling impact is scaled up / down if the scrolling speed is fast / slow
3135  if (delta_scroll_time < SCROLL_SLOW_MAX_TIME_MS)
3136  zoom_per_tick *= 2.f;
3137  else if (delta_scroll_time > SCROLL_FAST_MIN_TIME_MS)
3138  zoom_per_tick *= 0.5f;
3139  }
3140 
3141 
3142  if (std::abs(cx - px) < MAX_MOUSE_JUMP &&
3143  std::abs(cy - py) < MAX_MOUSE_JUMP )
3145  (float*)&pos, (float*)&target, (float*)&up, view,
3146  sec_since_update,
3147  zoom_per_tick,
3148  -0.1f, // pan speed
3149  3.0f, // rotation multiplier
3150  static_cast<int>(viewer_rect.w), static_cast<int>(viewer_rect.h), // screen (window) size
3151  static_cast<int>(px), static_cast<int>(cx),
3152  static_cast<int>(py), static_cast<int>(cy),
3153  (ImGui::GetIO().MouseDown[2] ||
3154  ImGui::GetIO().MouseDown[1] ||
3155  (ImGui::GetIO().MouseDown[0] && dragging)) ? 1 : 0,
3156  (ImGui::GetIO().MouseDown[0] && !dragging) ? 1 : 0,
3157  mouse.mouse_wheel,
3158  0);
3159 
3160  // If we are pressing mouse button
3161  // inside the 3D viewport
3162  // we should remember that we
3163  // are in the middle of manipulation
3164  // and adjust when mouse leaves the area
3165  if (ImGui::GetIO().MouseDown[0] ||
3166  ImGui::GetIO().MouseDown[1] ||
3167  ImGui::GetIO().MouseDown[2])
3168  {
3169  manipulating = true;
3170  }
3171  }
3172 
3173  auto rect = viewer_rect;
3174  rect.w -= 10;
3175 
3176  // If we started manipulating the camera
3177  // and left the viewport
3178  if (manipulating && !rect.contains(mouse.cursor))
3179  {
3180  // If mouse is no longer pressed,
3181  // abort the manipulation
3182  if (!ImGui::GetIO().MouseDown[0] &&
3183  !ImGui::GetIO().MouseDown[1] &&
3184  !ImGui::GetIO().MouseDown[2])
3185  {
3186  manipulating = false;
3187  overflow = float2{ 0.f, 0.f };
3188  }
3189  else
3190  {
3191  // Wrap-around the mouse in X direction
3192  auto startx = (mouse.cursor.x - rect.x);
3193  if (startx < 0)
3194  {
3195  overflow.x -= rect.w;
3196  startx += rect.w;
3197  }
3198  if (startx > rect.w)
3199  {
3200  overflow.x += rect.w;
3201  startx -= rect.w;
3202  }
3203  startx += rect.x;
3204 
3205  // Wrap-around the mouse in Y direction
3206  auto starty = (mouse.cursor.y - rect.y);
3207  if (starty < 0)
3208  {
3209  overflow.y -= rect.h;
3210  starty += rect.h;
3211  }
3212  if (starty > rect.h)
3213  {
3214  overflow.y += rect.h;
3215  starty -= rect.h;
3216  }
3217  starty += rect.y;
3218 
3219  // Set new cursor position
3220  glfwSetCursorPos(win, startx, starty);
3221  }
3222  }
3223  else overflow = float2{ 0.f, 0.f };
3224 
3225  mouse.prev_cursor = mouse.cursor;
3226  }
3227 
3228  void viewer_model::begin_stream(std::shared_ptr<subdevice_model> d, rs2::stream_profile p)
3229  {
3230  // Starting post processing filter rendering thread
3231  ppf.start();
3232  streams[p.unique_id()].begin_stream(d, p, *this);
3233  ppf.frames_queue.emplace(p.unique_id(), rs2::frame_queue(5));
3234  }
3235 
3237  {
3239  auto index = profile.unique_id();
3240  auto mapped_index = streams_origin.at(index);
3241 
3243  return false;
3244 
3245  if (index == selected_tex_source_uid || mapped_index == selected_tex_source_uid || selected_tex_source_uid == -1)
3246  return true;
3247  return false;
3248  }
3249 
3250  std::shared_ptr<texture_buffer> viewer_model::get_last_texture()
3251  {
3252  return last_texture;
3253  }
3254 
3256  {
3257  std::vector<rs2::frame> res;
3258 
3259  if (auto set = frame.as<frameset>())
3260  for (auto&& f : set)
3261  res.push_back(f);
3262 
3263  else
3264  res.push_back(frame);
3265 
3266  return res;
3267  }
3268 
3270  {
3271  auto frames = get_frames(f);
3272 
3273  for (auto&& f : frames)
3274  {
3275  if (is_3d_depth_source(f))
3276  return f;
3277  }
3278  return nullptr;
3279  }
3280 
3282  {
3283  auto frames = get_frames(f);
3284 
3285  for (auto&& f : frames)
3286  {
3287  if (is_3d_texture_source(f))
3288  return f;
3289  }
3290  return nullptr;
3291  }
3292 
3294  {
3295 
3296  auto index = f.get_profile().unique_id();
3297  auto mapped_index = streams_origin[index];
3298 
3301  return true;
3302  return false;
3303  }
3304 
3305  std::shared_ptr<texture_buffer> viewer_model::upload_frame(frame&& f)
3306  {
3307  if (f.get_profile().stream_type() == RS2_STREAM_DEPTH)
3308  ppf.depth_stream_active = true;
3309 
3310  auto index = f.get_profile().unique_id();
3311 
3312  std::lock_guard<std::mutex> lock(streams_mutex);
3313  if (streams.find(streams_origin[index]) != streams.end())
3314  return streams[streams_origin[index]].upload_frame(std::move(f));
3315  else return nullptr;
3316  }
3317 
3318  void viewer_model::draw_viewport(const rect& viewer_rect,
3319  ux_window& window, int devices, std::string& error_message,
3320  std::shared_ptr<texture_buffer> texture, points points)
3321  {
3322  if (!modal_notification_on)
3323  updates->draw(not_model, window, error_message);
3324 
3325  static bool first = true;
3326  if (first)
3327  {
3328  update_3d_camera(window, viewer_rect, true);
3329  first = false;
3330  }
3331 
3332  if (!is_3d_view)
3333  {
3334  render_2d_view(viewer_rect, window,
3335  static_cast<int>(get_output_height()), window.get_font(), window.get_large_font(),
3336  devices, window.get_mouse(), error_message);
3337  }
3338  else
3339  {
3340  if (paused)
3341  show_paused_icon(window.get_large_font(), static_cast<int>(panel_width + 15), static_cast<int>(panel_y + 15 + 60), 0);
3342 
3343  show_3dviewer_header(window, viewer_rect, paused, error_message);
3344 
3345  update_3d_camera(window, viewer_rect);
3346 
3347  _measurements.update_input(window, viewer_rect);
3348 
3349  rect window_size{ 0, 0, (float)window.width(), (float)window.height() };
3350  rect fb_size{ 0, 0, (float)window.framebuf_width(), (float)window.framebuf_height() };
3351  rect new_rect = viewer_rect.normalize(window_size).unnormalize(fb_size);
3352 
3353  render_3d_view(new_rect, window, texture, points);
3354 
3355  auto rect_copy = viewer_rect;
3356  rect_copy.y += 60;
3357  rect_copy.h -= 60;
3358 
3359  if (rect_copy.contains(window.get_mouse().cursor))
3360  _measurements.show_tooltip(window);
3361  }
3362 
3363  if (ImGui::IsKeyPressed(' '))
3364  {
3365  if (paused)
3366  {
3367  for (auto&& s : streams)
3368  {
3369  if (s.second.dev)
3370  {
3371  s.second.dev->resume();
3372  if (auto p = s.second.dev->dev.as<playback>())
3373  {
3374  p.resume();
3375  }
3376  }
3377  }
3378  }
3379  else
3380  {
3381  for (auto&& s : streams)
3382  {
3383  if (s.second.dev)
3384  {
3385  s.second.dev->pause();
3386  if (s.second.dev->dev.is<playback>())
3387  {
3388  auto p = s.second.dev->dev.as<playback>();
3389  p.pause();
3390  }
3391  }
3392  }
3393  }
3394  paused = !paused;
3395  }
3396  }
3397 
3398  std::map<int, rect> viewer_model::get_interpolated_layout(const std::map<int, rect>& l)
3399  {
3400  using namespace std::chrono;
3402  if (l != _layout) // detect layout change
3403  {
3405  _old_layout = _layout;
3406  _layout = l;
3407  }
3408 
3409  //if (_old_layout.size() == 0 && l.size() == 1) return l;
3410 
3411  auto diff = now - _transition_start_time;
3412  auto ms = duration_cast<milliseconds>(diff).count();
3413  auto t = smoothstep(static_cast<float>(ms), 0, 100);
3414 
3415  std::map<int, rect> results;
3416  for (auto&& kvp : l)
3417  {
3418  auto stream = kvp.first;
3419  if (_old_layout.find(stream) == _old_layout.end())
3420  {
3421  _old_layout[stream] = _layout[stream].center();
3422  }
3423  results[stream] = _old_layout[stream].lerp(t, _layout[stream]);
3424  }
3425 
3426  return results;
3427  }
3428 }
viewer_model(context &ctx_)
Definition: viewer.cpp:952
float y
Definition: rendering.h:499
float smoothstep(float x, float min, float max)
Definition: rendering.h:108
float3 cross(const float3 &a, const float3 &b)
Definition: rendering.h:153
static const auto OPTION_IGNORE_COLOR
Definition: rs_export.hpp:37
static const textual_icon lock
Definition: model-views.h:218
IMGUI_API void PushStyleVar(ImGuiStyleVar idx, float val)
Definition: imgui.cpp:4650
int selected_tex_source_uid
Definition: viewer.h:163
frame apply_filter(filter_interface &filter)
Definition: rs_frame.hpp:593
static const ImVec4 transparent
Definition: model-views.h:44
float lerp(float a, float b, float t)
Definition: rendering.h:122
GLenum GLuint GLenum GLsizei const GLchar * message
rs2::gl::pointcloud_renderer _pc_renderer
Definition: viewer.h:247
GLuint get_gl_handle() const
Definition: rendering.h:893
IMGUI_API void Image(ImTextureID user_texture_id, const ImVec2 &size, const ImVec2 &uv0=ImVec2(0, 0), const ImVec2 &uv1=ImVec2(1, 1), const ImVec4 &tint_col=ImVec4(1, 1, 1, 1), const ImVec4 &border_col=ImVec4(0, 0, 0, 0))
Definition: imgui.cpp:5635
bool metric_system
Definition: viewer.h:136
static const ImVec4 white
Definition: model-views.h:45
static const textual_icon floppy
Definition: model-views.h:238
IMGUI_API void AddRectFilled(const ImVec2 &a, const ImVec2 &b, ImU32 col, float rounding=0.0f, int rounding_corners=0x0F)
Definition: imgui_draw.cpp:814
float stof(const std::string &value)
IMGUI_API bool IsKeyPressed(int key_index, bool repeat=true)
Definition: imgui.cpp:3068
#define GL_LINE_LOOP
streams_layout _old_layout
Definition: viewer.h:227
GLuint GLuint end
GLboolean GLboolean GLboolean b
void draw_color_ruler(const mouse_info &mouse, const stream_model &s_model, const rect &stream_rect, std::vector< rgb_per_distance > rgb_per_distance_vec, float ruler_length, const std::string &ruler_units)
Definition: viewer.cpp:1479
GLboolean GLboolean g
GLint y
static const ImVec4 light_red
Definition: model-views.h:53
IMGUI_API bool RadioButton(const char *label, bool active)
Definition: imgui.cpp:7332
static const textual_icon circle
Definition: model-views.h:243
IMGUI_API ImVec2 GetCursorPos()
Definition: imgui.cpp:5076
rs2::frame handle_ready_frames(const rect &viewer_rect, ux_window &window, int devices, std::string &error_message)
Definition: viewer.cpp:1335
static matrix4 identity()
Definition: rendering.h:281
static const char * is_measuring
Definition: model-views.h:156
skybox _skybox
Definition: viewer.h:256
float3 normalize() const
Definition: rendering.h:142
std::map< int, int > streams_origin
Definition: viewer.h:126
IMGUI_API void SetTooltip(const char *fmt,...) IM_PRINTFARGS(1)
Definition: imgui.cpp:3288
std::string to_lower(std::string x)
Definition: parser.hpp:217
static const textual_icon unlock
Definition: model-views.h:237
GLFWAPI void glfwSetCursorPos(GLFWwindow *window, double xpos, double ypos)
Sets the position of the cursor, relative to the client area of the window.
Definition: input.c:660
GLuint const GLchar * name
static const ImVec4 almost_white_bg
Definition: model-views.h:42
IMGUI_API float GetFontSize()
Definition: imgui.cpp:5056
static const ImVec4 header_window_bg
Definition: model-views.h:56
int rs2_get_api_version(rs2_error **error)
Definition: rs.cpp:1184
std::map< int, rect > calc_layout(const rect &r)
Definition: viewer.cpp:1291
static const auto OPTION_ORIGIN_PICKED
ImVec4 from_rgba(uint8_t r, uint8_t g, uint8_t b, uint8_t a, bool consistent_color)
IMGUI_API void ProgressBar(float fraction, const ImVec2 &size_arg=ImVec2(-1, 0), const char *overlay=NULL)
Definition: imgui.cpp:7234
static export_model make_exporter(std::string name, std::string extension, T(&filters_str)[sz])
Definition: viewer.h:41
rs2_option
Defines general configuration controls. These can generally be mapped to camera UVC controls...
Definition: rs_option.h:22
std::atomic< bool > depth_stream_active
Definition: model-views.h:930
#define GL_ONE
GLdouble s
#define GL_TEXTURE_2D
IMGUI_API bool InputTextMultiline(const char *label, char *buf, size_t buf_size, const ImVec2 &size=ImVec2(0, 0), ImGuiInputTextFlags flags=0, ImGuiTextEditCallback callback=NULL, void *user_data=NULL)
Definition: imgui.cpp:8223
#define glOrtho
#define glBegin
IMGUI_API void SetCursorPos(const ImVec2 &local_pos)
Definition: imgui.cpp:5094
GLfloat GLfloat p
Definition: glext.h:12687
const GLfloat * m
Definition: glext.h:6814
void popup_firmware_update_progress(const ux_window &window, const float progress)
Definition: viewer.cpp:1142
#define ImGui_ScopePushFont(f)
Definition: imgui.h:125
static const ImVec4 light_grey
Definition: model-views.h:40
Definition: imgui.h:88
#define glDepthMask
std::vector< uint8_t > read_fw_file(std::string file_path)
Definition: viewer.cpp:1125
static config_file & instance()
Definition: rs-config.cpp:80
#define glPopMatrix
constexpr const char * server_versions_db_url
Definition: model-views.h:84
static const char * commands_xml
Definition: model-views.h:169
void draw_rect(const rect &r, int line_width)
#define GL_PROJECTION
static const ImVec4 light_blue
Definition: model-views.h:38
GLsizei const GLchar *const * path
Definition: glext.h:4276
std::enable_if< std::is_base_of< rs2::frame, T >::value, bool >::type poll_for_frame(T *output) const
float get_output_height() const
Definition: viewer.h:66
stream_profile get_profile() const
Definition: rs_frame.hpp:557
std::map< int, stream_model > streams
Definition: viewer.h:125
#define glPushAttrib
void render_pose(rs2::rect stream_rect, float buttons_heights)
Definition: viewer.cpp:53
std::unordered_set< int > _hidden_options
Definition: viewer.h:195
IMGUI_API void SetNextWindowPos(const ImVec2 &pos, ImGuiSetCond cond=0)
Definition: imgui.cpp:4923
void update_input(ux_window &win, const rs2::rect &viewer_rect)
#define glPointSize
UINT8_TYPE u8
Definition: sqlite3.c:11450
std::shared_ptr< texture_buffer > texture
Definition: model-views.h:712
static const char * log_to_file
Definition: model-views.h:161
std::string get_folder_path(special_folder f)
Definition: os.cpp:247
void reset_camera(float3 pos={0.0f, 0.0f,-1.0f})
Definition: viewer.cpp:1449
rs2::frame_queue resulting_queue
Definition: model-views.h:934
rs2_intrinsics intrin
#define glVertex3fv
def progress(args)
Definition: log.py:43
#define GL_POLYGON
const void * get_data() const
Definition: rs_frame.hpp:545
unsigned short uint16_t
Definition: stdint.h:79
frame get_3d_texture_source(frame f)
Definition: viewer.cpp:3281
Definition: cah-model.h:10
void hyperlink(ux_window &window, const char *title, const char *link)
GLdouble GLdouble GLdouble w
GLsizei const GLchar *const * string
std::vector< plane_3d > subdivide(const plane_3d &rect, int parts=4)
Definition: rendering.h:219
#define GL_BLEND
std_msgs::Header * header(M &m)
returns Header<M>::pointer(m);
d
Definition: rmse.py:171
static const char * log_filename
Definition: model-views.h:162
const std::string header
Definition: viewer.h:18
void reset()
Definition: skybox.h:13
std::array< point3d, 4 > object
IMGUI_API bool IsWindowHovered()
Definition: imgui.cpp:4743
GLuint GLuint stream
Definition: glext.h:1790
#define glLoadIdentity
GLfloat GLfloat GLfloat GLfloat h
Definition: glext.h:1960
GLdouble GLdouble z
GLdouble n
Definition: glext.h:1966
unsigned char uint8_t
Definition: stdint.h:78
rect unnormalize(const rect &unnormalize_to) const
Definition: rendering.h:533
normal
Definition: rmse.py:164
#define glColor4f
#define glVertex3f
void show_no_device_overlay(ImFont *font, int min_x, int min_y)
Definition: viewer.cpp:1233
#define GL_SRC_ALPHA
e
Definition: rmse.py:177
static const char * hwlogger_xml
Definition: model-views.h:170
point
Definition: rmse.py:166
static const ImVec4 grey
Definition: model-views.h:48
IMGUI_API void AddLine(const ImVec2 &a, const ImVec2 &b, ImU32 col, float thickness=1.0f)
Definition: imgui_draw.cpp:796
#define glEnable
void sort(sort_type m_sort_type, const std::string &in, const std::string &out)
IMGUI_API bool InputText(const char *label, char *buf, size_t buf_size, ImGuiInputTextFlags flags=0, ImGuiTextEditCallback callback=NULL, void *user_data=NULL)
Definition: imgui.cpp:8216
void hide_common_options()
Definition: viewer.cpp:872
float evaluate_layout(const std::map< int, rect > &l)
Definition: viewer.cpp:1284
rs2_pose get_pose_data() const
Definition: rs_frame.hpp:933
The texture class.
Definition: example.hpp:402
#define glGetFloatv
static const char * mesh
Definition: model-views.h:199
rs2::gl::camera_renderer _cam_renderer
Definition: viewer.h:246
void update_3d_camera(ux_window &win, const rect &viewer_rect, bool force=false)
Definition: viewer.cpp:3066
bool ends_with(const std::string &s, const std::string &suffix)
Definition: os.cpp:335
frame get_3d_depth_source(frame f)
Definition: viewer.cpp:3269
IMGUI_API bool SliderInt(const char *label, int *v, int v_min, int v_max, const char *display_format="%.0f", bool render_bg=false)
Definition: imgui.cpp:6687
::realsense_legacy_msgs::pose_< std::allocator< void > > pose
Definition: pose.h:88
GLenum GLuint id
void set_matrix(rs2_gl_matrix_type type, float *m4x4)
std::chrono::high_resolution_clock::time_point _transition_start_time
Definition: viewer.h:228
#define GL_TEXTURE_WRAP_T
bool is_valid(const plane_3d &p)
Definition: rendering.h:243
void gc_streams()
Definition: viewer.cpp:977
status
Defines return codes that SDK interfaces use. Negative values indicate errors, a zero value indicates...
std::shared_ptr< notifications_model > not_model
Definition: viewer.h:133
static const char * show_fps
Definition: model-views.h:191
GLuint index
bool directory_exists(const char *dir)
Definition: os.cpp:157
const float panel_y
Definition: viewer.h:64
bool _pc_selected
Definition: viewer.h:250
bool manipulating() const
Definition: measurement.cpp:26
GLdouble t
GLboolean GLboolean GLboolean GLboolean a
ImFont * get_font() const
Definition: ux-window.h:64
std::shared_ptr< texture_buffer > get_last_texture()
Definition: viewer.cpp:3250
IMGUI_API ImVec2 GetMousePos()
Definition: imgui.cpp:3146
void open_issue(std::string body)
T get_or_default(const char *key, T def) const
Definition: rs-config.h:65
float calculate_ruler_max_distance(const std::vector< float > &distances) const
Definition: viewer.cpp:1632
Definition: parser.hpp:154
float x
Definition: rendering.h:499
static const auto OPTION_PLY_NORMALS
Definition: rs_export.hpp:40
static const char * log_to_console
Definition: model-views.h:160
IMGUI_API bool BeginPopup(const char *str_id)
Definition: imgui.cpp:3455
static const char * msaa_samples
Definition: model-views.h:190
not_this_one begin(...)
IMGUI_API void SameLine(float pos_x=0.0f, float spacing_w=-1.0f)
Definition: imgui.cpp:9246
std::string error_to_string(const error &e)
Definition: rendering.h:1583
GLdouble f
bool is() const
Definition: rs_frame.hpp:570
bool draw_combo_box(const std::string &id, const std::vector< std::string > &device_names, int &new_index)
std::map< int, rect > get_interpolated_layout(const std::map< int, rect > &l)
Definition: viewer.cpp:3398
std::map< int, rect > generate_layout(const rect &r, int top_bar_height, size_t factor, const std::set< stream_model * > &active_streams, std::map< stream_model *, int > &stream_index)
Definition: viewer.cpp:1248
void check_permissions()
Definition: viewer.cpp:766
float3 colors[]
Definition: rs-pcl.cpp:44
void show_no_stream_overlay(ImFont *font, int min_x, int min_y, int max_x, int max_y)
Definition: viewer.cpp:1185
static const char * glsl_for_processing
Definition: model-views.h:188
GLfloat GLfloat GLfloat alpha
IMGUI_API ImDrawList * GetWindowDrawList()
Definition: imgui.cpp:5045
static const char * metric_system
Definition: model-views.h:167
IMGUI_API bool Begin(const char *name, bool *p_open=NULL, ImGuiWindowFlags flags=0)
Definition: imgui.cpp:3772
IMGUI_API void PopStyleVar(int count=1)
Definition: imgui.cpp:4675
Definition: getopt.h:41
dictionary streams
Definition: t265_stereo.py:140
GLsizeiptr size
IMGUI_API ImVec2 CalcTextSize(const char *text, const char *text_end=NULL, bool hide_text_after_double_hash=false, float wrap_width=-1.0f)
Definition: test-wrap.cpp:15
void set_matrix(rs2_gl_matrix_type type, float *m4x4)
static const float FEET_TO_METER
Definition: model-views.h:123
float h
Definition: rendering.h:500
static void rs2_deproject_pixel_to_point(float point[3], const struct rs2_intrinsics *intrin, const float pixel[2], float depth)
Definition: rsutil.h:83
#define GL_COLOR_BUFFER_BIT
static const char * show_stream_details
Definition: model-views.h:166
static const char * continue_with_current_fw
Definition: model-views.h:152
const float panel_width
Definition: viewer.h:63
static const ImVec4 regular_blue
Definition: model-views.h:39
void show_popup(const ux_window &window, const popup &p)
Definition: viewer.cpp:1019
#define glTexParameteri
float w
Definition: imgui.h:100
GLuint counter
Definition: glext.h:5684
GLdouble GLdouble r
#define GL_LINES
GLint texture_border_mode
Definition: viewer.h:237
IMGUI_API void TextUnformatted(const char *text, const char *text_end=NULL)
Definition: imgui.cpp:5276
static const textual_icon play
Definition: model-views.h:223
GLdouble x
void open_url(const char *url)
Definition: os.cpp:58
#define glLineWidth
float framebuf_width() const
Definition: ux-window.h:44
#define glPushMatrix
devices
Definition: test-fg.py:9
std::string get(const char *key, const char *def) const
Definition: rs-config.cpp:32
#define glLoadMatrixf
#define GL_PROJECTION_MATRIX
bool is_option_skipped(rs2_option opt) const
Definition: viewer.cpp:1014
#define glClear
void render(rs2::float3 cam_position)
Definition: skybox.cpp:26
IMGUI_API ImGuiIO & GetIO()
Definition: imgui.cpp:2014
float single_wave(float x)
Definition: rendering.h:1643
static const char * sw_updates_url
Definition: model-views.h:138
IMGUI_API void SetNextWindowSize(const ImVec2 &size, ImGuiSetCond cond=0)
Definition: imgui.cpp:4937
std::shared_ptr< texture_buffer > upload_frame(frame &&f)
Definition: viewer.cpp:3305
GLint GLint GLsizei GLint GLenum format
float z
Definition: imgui.h:100
#define glTranslatef
void set_export_popup(ImFont *large_font, ImFont *font, rect stream_rect, std::string &error_message, config_file &temp_cfg)
Definition: viewer.cpp:117
static const char * compression_mode
Definition: model-views.h:131
static const ImVec4 sensor_bg
Definition: model-views.h:51
GLenum target
Definition: glext.h:1565
std::function< void()> on_reload_complete
Definition: ux-window.h:37
#define GL_QUADS
GLbitfield flags
std::string trim_newlines(std::string text)
Definition: trim-newlines.h:29
def find(dir, mask)
Definition: file.py:25
frameset_allocator(viewer_model *viewer)
Definition: viewer.cpp:36
stream_model * selected_stream
Definition: viewer.h:128
void export_frame(const std::string &fname, std::unique_ptr< rs2::filter > exporter, notifications_model &ns, frame data, bool notify)
unsigned __int64 uint64_t
Definition: stdint.h:90
IMGUI_API void SetCursorPosX(float x)
Definition: imgui.cpp:5101
GLenum GLenum GLsizei const GLuint GLboolean enabled
void mouse_pick(ux_window &win, float3 picked, float3 normal)
GLuint GLfloat x0
Definition: glext.h:9721
std::shared_ptr< updates_model > updates
Definition: viewer.h:193
static const char * use_normals
Definition: model-views.h:200
#define glEnd
GLint j
rect grow(int pixels) const
Definition: rendering.h:626
static const ImVec4 sensor_header_light_blue
Definition: model-views.h:50
IMGUI_API void PushItemWidth(float item_width)
Definition: imgui.cpp:4486
IMGUI_API void Text(const char *fmt,...) IM_PRINTFARGS(1)
Definition: imgui.cpp:5223
#define RS2_API_BUILD_VERSION
Definition: rs.h:28
GLint left
Definition: glext.h:1963
IMGUI_API bool Button(const char *label, const ImVec2 &size=ImVec2(0, 0))
Definition: imgui.cpp:5573
rs2_format
A stream&#39;s format identifies how binary data is encoded within a frame.
Definition: rs_sensor.h:59
const char * file_dialog_open(file_dialog_mode flags, const char *filters, const char *default_path, const char *default_name)
Definition: os.cpp:169
GLint first
IMGUI_API void Separator()
Definition: imgui.cpp:9127
void show_paused_icon(ImFont *font, int x, int y, int id)
Definition: viewer.cpp:1176
IMGUI_API void End()
Definition: imgui.cpp:4330
std::vector< frame > get_frames(frame set)
Definition: viewer.cpp:3255
static const ImVec4 button_color
Definition: model-views.h:55
void begin_stream(std::shared_ptr< subdevice_model > d, rs2::stream_profile p)
Definition: viewer.cpp:3228
bool big_button(bool *status, ux_window &win, int x, int y, const char *icon, const char *label, bool dropdown, bool enabled, const char *description, ImVec4 text_color=light_grey)
Definition: viewer.cpp:306
Definition: imgui.h:98
std::array< float3, 4 > roi_rect
Definition: viewer.h:153
void begin_viewport()
Definition: ux-window.cpp:732
float mat[4][4]
Definition: rendering.h:274
bool get_hovered_over_input() const
Definition: ux-window.h:83
bool MouseDown[5]
Definition: imgui.h:841
shader_type
Definition: opengl3.h:28
#define GL_TRUE
void log_to_file(rs2_log_severity min_severity, const char *file_path=nullptr)
Definition: rs.hpp:26
float2 prev_cursor
Definition: rendering.h:477
IMGUI_API void EndPopup()
Definition: imgui.cpp:3489
#define glViewport
static const ImVec4 header_color
Definition: model-views.h:57
static const ImVec4 dark_red
Definition: model-views.h:54
float w
Definition: rendering.h:500
void show_recording_icon(ImFont *font_18, int x, int y, int id, float alpha_delta)
Definition: viewer.cpp:1180
#define GL_DEPTH_BUFFER_BIT
bool mouse_down[2]
Definition: rendering.h:478
bool draw_frustrum
Definition: viewer.h:156
static void handle(rs2_error *e)
Definition: rs_types.hpp:144
ImVec4 alpha(const ImVec4 &v, float a)
float x
Definition: imgui.h:100
#define GL_MODELVIEW
static const textual_icon exit
Definition: model-views.h:254
#define GL_ONE_MINUS_SRC_ALPHA
void add_value(bool val)
Definition: rendering.h:818
static const auto OPTION_SCALE_FACTOR
std::map< export_type, export_model > exporters
Definition: viewer.h:143
IMGUI_API void PushStyleColor(ImGuiCol idx, const ImVec4 &col)
Definition: imgui.cpp:4599
static const ImVec4 black
Definition: model-views.h:43
void arcball_camera_update(float eye[3], float target[3], float up[3], float view[16], float delta_time_seconds, float zoom_per_tick, float pan_speed, float rotation_multiplier, int screen_width, int screen_height, int x0, int x1, int y0, int y1, int midclick_held, int rclick_held, int delta_scroll_ticks, unsigned int flags)
measurement _measurements
Definition: viewer.h:258
void show_3dviewer_header(ux_window &window, rs2::rect stream_rect, bool &paused, std::string &error_message)
Definition: viewer.cpp:379
bool is_rasterizeable(rs2_format format)
Definition: rendering.h:1609
streams_layout _layout
Definition: viewer.h:226
IMGUI_API void PushFont(ImFont *font)
Definition: imgui.cpp:4539
post_processing_filters ppf
Definition: viewer.h:130
float y
Definition: imgui.h:90
void save(const char *filename)
Definition: rs-config.cpp:61
static const char * glsl_for_rendering
Definition: model-views.h:187
static const char * font_oversample
Definition: model-views.h:193
static const textual_icon toggle_off
Definition: model-views.h:246
void show_icon(ImFont *font_18, const char *label_str, const char *text, int x, int y, int id, const ImVec4 &color, const std::string &tooltip="")
Definition: viewer.cpp:1161
void log_to_console(rs2_log_severity min_severity)
Definition: rs.hpp:19
float framebuf_height() const
Definition: ux-window.h:45
T non_negative(const T &input)
Definition: viewer.cpp:30
rs2_format format() const
Definition: rs_frame.hpp:44
#define GL_FALSE
IMGUI_API ImVec2 GetCursorScreenPos()
Definition: imgui.cpp:5121
ImVec4 blend(const ImVec4 &c, float a)
Definition: model-views.h:77
fname
Definition: rmse.py:13
GLFWAPI double glfwGetTime(void)
Returns the value of the GLFW timer.
Definition: input.c:1275
#define glColor3f
bool val_in_range(const T &val, const std::initializer_list< T > &list)
Definition: rendering.h:1599
static const char * is_fullscreen
Definition: model-views.h:176
std::mutex streams_mutex
Definition: viewer.h:124
bool modal_notification_on
Definition: viewer.h:185
void set(const char *key, const char *value)
Definition: rs-config.cpp:15
static const char * settings_tab
Definition: model-views.h:153
void update_configuration()
Definition: viewer.cpp:884
IMGUI_API void PopItemWidth()
Definition: imgui.cpp:4507
static const char * show_skybox
Definition: model-views.h:194
static const char * log_severity
Definition: model-views.h:163
const char * rs2_stream_to_string(rs2_stream stream)
Definition: rs.cpp:1262
GLsizei GLenum GLenum GLuint GLenum * severities
float length() const
Definition: rendering.h:140
#define GL_LINE_BIT
static auto it
GLenum GLenum GLenum input
Definition: glext.h:10805
void render_3d_view(const rect &view_rect, ux_window &win, std::shared_ptr< texture_buffer > texture, rs2::points points)
Definition: viewer.cpp:1934
void draw(ux_window &win)
GLuint in
Definition: glext.h:8859
void set_hovered_over_input()
Definition: ux-window.h:82
Definition: imgui.h:1392
int min(int a, int b)
Definition: lz4s.c:73
GLuint GLsizei const GLchar * label
const GLuint GLenum const void * binary
Definition: glext.h:1882
GLsizei samples
std::function< void()> custom_command
Definition: viewer.h:20
static GLuint mesh
Definition: heightmap.c:113
#define glPopAttrib
#define RS2_API_FULL_VERSION_STR
Definition: rs.h:44
#define glBindTexture
static const ImVec4 yellowish
Definition: model-views.h:61
IMGUI_API bool MenuItem(const char *label, const char *shortcut=NULL, bool selected=false, bool enabled=true)
Definition: imgui.cpp:8733
GLint GLsizei count
static const char * ground_truth_r
Definition: model-views.h:148
#define GLFW_KEY_LEFT_CONTROL
Definition: glfw3.h:474
bool contains(const float2 &p) const
Definition: rendering.h:583
static const char * enable_msaa
Definition: model-views.h:189
IMGUI_API bool BeginPopupModal(const char *name, bool *p_open=NULL, ImGuiWindowFlags extra_flags=0)
Definition: imgui.cpp:3465
IMGUI_API bool Selectable(const char *label, bool selected=false, ImGuiSelectableFlags flags=0, const ImVec2 &size=ImVec2(0, 0))
Definition: imgui.cpp:8550
GLuint GLfloat GLfloat y0
Definition: glext.h:9721
bool is_3d_depth_source(frame f)
Definition: viewer.cpp:3293
float2 overflow
Definition: viewer.h:244
IMGUI_API bool Checkbox(const char *label, bool *v)
Definition: imgui.cpp:7269
float width() const
Definition: ux-window.h:41
typename::boost::move_detail::remove_reference< T >::type && move(T &&t) BOOST_NOEXCEPT
std::vector< std::unique_ptr< device_model > > device_models_list
Definition: model-views.h:96
#define glClearColor
std::string api_version_to_string(int version)
Definition: rendering.h:1590
float rs2_vector::* pos
static const char * shading_mode
Definition: model-views.h:168
rect normalize(const rect &normalize_to) const
Definition: rendering.h:525
IMGUI_API void SetCursorScreenPos(const ImVec2 &pos)
Definition: imgui.cpp:5127
static const char * encoding
Definition: model-views.h:201
shader_type selected_shader
Definition: viewer.h:173
static void draw_axes(float axis_size=1.f, float axisWidth=4.f)
Definition: rendering.h:1148
texture_buffer & get_splash()
Definition: ux-window.h:74
bool is_3d_texture_source(frame f) const
Definition: viewer.cpp:3236
#define NULL
Definition: tinycthread.c:47
std::map< int, rs2::frame_queue > frames_queue
Definition: model-views.h:933
bool show_skybox
Definition: viewer.h:255
GLuint texture
int i
rect adjust_ratio(float2 size) const
Definition: rendering.h:606
GLenum GLuint GLenum GLsizei length
static const char * sw_updates_official_server
Definition: model-views.h:139
GLuint res
Definition: glext.h:8856
std::vector< popup > _active_popups
Definition: viewer.h:201
bool is_fullscreen()
Definition: ux-window.h:72
int selected_depth_source_uid
Definition: viewer.h:162
viewer_model * owner
Definition: viewer.h:35
std::array< float, 3 > color
Definition: model-views.h:449
std::string wrap(const std::string &text, int wrap_pixels_width)
Definition: wrap.cpp:98
static const char * is_3d_view
Definition: model-views.h:147
static const char * show_map_ruler
Definition: model-views.h:165
static const textual_icon pause
Definition: model-views.h:224
IMGUI_API ImGuiStyle & GetStyle()
Definition: imgui.cpp:2019
#define glVertex2f
void popup_if_error(const ux_window &window, std::string &error_message)
Definition: viewer.cpp:1051
static const textual_icon exclamation_triangle
Definition: model-views.h:232
temporal_event origin_occluded
Definition: viewer.h:253
IMGUI_API void CloseCurrentPopup()
Definition: imgui.cpp:3408
int unique_id() const
Definition: rs_frame.hpp:54
static const ImVec4 yellow
Definition: model-views.h:60
IMGUI_API bool IsKeyDown(int key_index)
Definition: imgui.cpp:3061
rs2_format format
const char * rs2_log_severity_to_string(rs2_log_severity info)
Definition: rs.cpp:1271
ImFont * get_large_font() const
Definition: ux-window.h:62
static const textual_icon measure
Definition: model-views.h:263
void show_rendering_not_supported(ImFont *font_18, int min_x, int min_y, int max_x, int max_y, rs2_format format)
Definition: viewer.cpp:1202
void show_top_bar(ux_window &window, const rect &viewer_rect, const device_models_list &devices)
Definition: viewer.cpp:2314
IMGUI_API void OpenPopup(const char *str_id)
Definition: imgui.cpp:3343
bool manipulating
Definition: viewer.h:243
#define glBlendFunc
#define glMultMatrixf
#define check_gl_error()
Definition: opengl3.h:17
static const char * recommend_updates
Definition: model-views.h:136
float get_scale_factor() const
Definition: ux-window.h:67
matrix4 tm2_pose_to_world_transformation(const rs2_pose &pose)
Definition: rendering.h:441
static const auto OPTION_PLY_BINARY
Definition: rs_export.hpp:39
rs2_log_severity
Severity of the librealsense logger.
Definition: rs_types.h:153
static const auto OPTION_PLY_MESH
Definition: rs_export.hpp:38
rs2_stream stream_type() const
Definition: rs_frame.hpp:39
void set_option(rs2_option option, float value) const
Definition: rs_options.hpp:99
_W64 signed int intptr_t
Definition: stdint.h:118
rs2::points last_points
Definition: viewer.h:239
float get_option(rs2_option option) const
Definition: rs_options.hpp:72
void link_hovered()
Definition: ux-window.cpp:166
#define GL_TEXTURE_WRAP_S
static const char * sdk_version
Definition: model-views.h:154
void show_tooltip(ux_window &win)
static const char * occlusion_invalidation
Definition: model-views.h:195
static const char * default_path
Definition: model-views.h:130
static const ImVec4 dark_sensor_bg
Definition: model-views.h:63
IMGUI_API bool IsItemHovered()
Definition: imgui.cpp:3200
#define glMatrixMode
press_button_model trajectory_button
Definition: viewer.h:187
Definition: parser.hpp:150
static const char * file_save_mode
Definition: model-views.h:129
std::shared_ptr< texture_buffer > last_texture
Definition: viewer.h:240
const size_t resulting_queue_max_size
Definition: model-views.h:932
GLdouble GLdouble GLint GLint const GLdouble * points
IMGUI_API void PopFont()
Definition: imgui.cpp:4549
#define GL_DEPTH_TEST
float y
Definition: imgui.h:100
IMGUI_API void PopStyleColor(int count=1)
Definition: imgui.cpp:4609
float height() const
Definition: ux-window.h:42
rs2::mouse_info & get_mouse()
Definition: ux-window.h:66
#define glDisable
T as() const
Definition: rs_frame.hpp:580
IMGUI_API void NewLine()
Definition: imgui.cpp:9269
std::string to_string(T value)
void draw_viewport(const rect &viewer_rect, ux_window &window, int devices, std::string &error_message, std::shared_ptr< texture_buffer > texture, rs2::points f=rs2::points())
Definition: viewer.cpp:3318
void render_2d_view(const rect &view_rect, ux_window &win, int output_height, ImFont *font1, ImFont *font2, size_t dev_model_num, const mouse_info &mouse, std::string &error_message)
Definition: viewer.cpp:1651


librealsense2
Author(s): Sergey Dorodnicov , Doron Hirshberg , Mark Horn , Reagan Lopez , Itay Carpis
autogenerated on Mon May 3 2021 02:50:14