You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

803 lines
31 KiB

// License: Apache 2.0. See LICENSE file in root directory.
// Copyright(c) 2017 Intel Corporation. All Rights Reserved.
#include <librealsense2/rs.hpp>
#include "viewer.h"
#include "os.h"
#include "ux-window.h"
#include "fw-update-helper.h"
#include <rsutils/os/ensure-console.h>
#include <tclap/CmdLine.h>
#include <cstdarg>
#include <thread>
#include <iostream>
#include <algorithm>
#include <iomanip>
#include <map>
#include <sstream>
#include <array>
#include <mutex>
#include <set>
#include <regex>
#include <imgui_internal.h>
#ifdef INTERNAL_FW
#include "common/fw/D4XX_FW_Image.h"
#else
#define FW_D4XX_FW_IMAGE_VERSION ""
#endif // INTERNAL_FW
using namespace rs2;
using namespace rs400;
void update_viewer_configuration(viewer_model& viewer_model)
{
// Hide options from the Viewer application
viewer_model._hidden_options.emplace(RS2_OPTION_ENABLE_IR_REFLECTIVITY);
}
bool add_remote_device(context& ctx, std::string address)
{
// Return true if a network device exists at the given address; throw an error otherwise
// For now, this is unsupported!
return false;
}
void add_playback_device( context & ctx,
std::shared_ptr< device_models_list > device_models,
std::string & error_message,
viewer_model & viewer_model,
const std::string & file )
{
bool was_loaded = false;
bool failed = false;
try
{
auto dev = ctx.load_device(file);
was_loaded = true;
device_models->emplace_back( // Will cause the new device to appear in the left panel
new device_model( dev, error_message, viewer_model ) );
if (auto p = dev.as<playback>())
{
auto filename = p.file_name();
p.set_status_changed_callback(
[&viewer_model, weak_device_models = std::weak_ptr< device_models_list >( device_models ), filename](
rs2_playback_status status )
{
auto device_models = weak_device_models.lock();
if( ! device_models )
return;
if( status == RS2_PLAYBACK_STATUS_STOPPED )
{
auto it = std::find_if( device_models->begin(),
device_models->end(),
[&]( const std::unique_ptr< device_model > & dm )
{
if( auto p = dm->dev.as< playback >() )
return p.file_name() == filename;
return false;
} );
if( it != device_models->end() )
{
auto subs = ( *it )->subdevices;
if( ( *it )->_playback_repeat )
{
// Calling from different since playback callback is from reading thread
std::thread{ [subs, &viewer_model, it]()
{
if( ! ( *it )->dev_syncer )
( *it )->dev_syncer = viewer_model.syncer->create_syncer();
for( auto && sub : subs )
{
if( sub->streaming )
{
auto profiles = sub->get_selected_profiles();
sub->play( profiles, viewer_model, ( *it )->dev_syncer );
}
}
} }
.detach();
}
else
{
for( auto && sub : subs )
{
if( sub->streaming )
{
sub->stop( viewer_model.not_model );
}
}
}
}
}
} );
}
}
catch (const error& e)
{
error_message = rsutils::string::from() << "Failed to load file " << file << ". Reason: " << error_to_string(e);
failed = true;
}
catch (const std::exception& e)
{
error_message = rsutils::string::from() << "Failed to load file " << file << ". Reason: " << e.what();
failed = true;
}
if (failed && was_loaded)
{
try { ctx.unload_device(file); }
catch (...) {}
}
}
// This function is called every frame
// If between the frames there was an asyncronous connect/disconnect event
// the function will pick up on this and add the device to the viewer
bool refresh_devices(std::mutex& m,
context& ctx,
device_changes& devices_connection_changes,
std::vector<device>& current_connected_devices,
std::vector<std::pair<std::string, std::string>>& device_names,
device_models_list& device_models,
viewer_model& viewer_model,
std::string& error_message)
{
event_information info({}, {});
if (!devices_connection_changes.try_get_next_changes(info))
return false;
try
{
//Remove disconnected
auto dev_itr = begin(current_connected_devices);
while (dev_itr != end(current_connected_devices))
{
auto dev = *dev_itr;
if (info.was_removed(dev))
{
//Notify change
viewer_model.not_model->add_notification({ get_device_name(dev).first + " Disconnected\n",
RS2_LOG_SEVERITY_INFO, RS2_NOTIFICATION_CATEGORY_UNKNOWN_ERROR });
//Remove from devices
auto dev_model_itr = std::find_if(begin(device_models), end(device_models),
[&](const std::unique_ptr<device_model>& other) { return get_device_name(other->dev) == get_device_name(dev); });
if (dev_model_itr != end(device_models))
{
for (auto&& s : (*dev_model_itr)->subdevices)
s->streaming = false;
dev_model_itr->reset();
device_models.erase(dev_model_itr);
if (device_models.size() == 0)
{
viewer_model.ppf.depth_stream_active = false;
// Stopping post processing filter rendering thread in case of disconnection
viewer_model.ppf.stop();
}
}
auto dev_name_itr = std::find(begin(device_names), end(device_names), get_device_name(dev));
if (dev_name_itr != end(device_names))
device_names.erase(dev_name_itr);
dev_itr = current_connected_devices.erase(dev_itr);
continue;
}
++dev_itr;
}
//Add connected
static bool initial_refresh = true;
try
{
for (auto dev : info.get_new_devices())
{
auto dev_descriptor = get_device_name(dev);
device_names.push_back(dev_descriptor);
bool added = false;
if (device_models.size() == 0 &&
dev.supports(RS2_CAMERA_INFO_NAME) && std::string(dev.get_info(RS2_CAMERA_INFO_NAME)) != "Platform Camera" && std::string(dev.get_info(RS2_CAMERA_INFO_NAME)).find("IP Device") == std::string::npos)
{
device_models.emplace_back(new device_model(dev, error_message, viewer_model));
viewer_model.not_model->add_log(
rsutils::string::from() << ( *device_models.rbegin() )->dev.get_info( RS2_CAMERA_INFO_NAME )
<< " was selected as a default device" );
added = true;
}
if (!initial_refresh)
{
if (added || dev.is<playback>())
viewer_model.not_model->add_notification({ dev_descriptor.first + " Connected\n",
RS2_LOG_SEVERITY_INFO, RS2_NOTIFICATION_CATEGORY_UNKNOWN_ERROR });
else if (added || dev.supports(RS2_CAMERA_INFO_IP_ADDRESS))
viewer_model.not_model->add_notification({ dev_descriptor.first + " Connected\n",
RS2_LOG_SEVERITY_INFO, RS2_NOTIFICATION_CATEGORY_UNKNOWN_ERROR });
else
viewer_model.not_model->add_notification({ dev_descriptor.first + " Connected\n",
RS2_LOG_SEVERITY_INFO, RS2_NOTIFICATION_CATEGORY_UNKNOWN_ERROR },
[&device_models, &viewer_model, &error_message, dev] {
auto device = dev;
device_models.emplace_back(
new device_model(device, error_message, viewer_model));
});
}
current_connected_devices.push_back(dev);
for (auto&& s : dev.query_sensors())
{
s.set_notifications_callback([&, dev_descriptor](const notification& n)
{
if (n.get_category() == RS2_NOTIFICATION_CATEGORY_HARDWARE_EVENT)
{
auto data = n.get_serialized_data();
if (!data.empty())
{
auto dev_model_itr = std::find_if(begin(device_models), end(device_models),
[&](const std::unique_ptr<device_model>& other)
{ return get_device_name(other->dev) == dev_descriptor; });
if (dev_model_itr == end(device_models))
return;
(*dev_model_itr)->handle_hardware_events(data);
}
}
viewer_model.not_model->add_notification({ n.get_description(), n.get_severity(), n.get_category() });
});
}
}
}
catch (std::exception& e) {
std::stringstream s;
s << "Couldn't refresh devices - " << e.what();
log(RS2_LOG_SEVERITY_WARN, s.str().c_str());
}
initial_refresh = false;
}
catch (const error& e)
{
error_message = error_to_string(e);
}
catch (const std::exception& e)
{
error_message = e.what();
}
catch (...)
{
error_message = "Unknown error";
}
return true;
}
int main(int argc, const char** argv) try
{
TCLAP::CmdLine cmd( "realsense-viewer", ' ', RS2_API_FULL_VERSION_STR );
#ifdef BUILD_EASYLOGGINGPP
TCLAP::SwitchArg debug_arg( "", "debug", "Turn on LibRS debug logs" );
cmd.add( debug_arg );
#endif
TCLAP::SwitchArg only_sw_arg( "", "sw-only", "Show only software devices (playback, DDS, etc. -- but not USB/HID/etc.)" );
cmd.add( only_sw_arg );
// There isn't always a console... so if we need to show an error/usage, we need to enable it:
class cmdline_output : public TCLAP::StdOutput
{
typedef TCLAP::StdOutput super;
public:
void usage( TCLAP::CmdLineInterface & c ) override
{
rsutils::os::ensure_console();
super::usage( c );
}
void version( TCLAP::CmdLineInterface & c ) override
{
rsutils::os::ensure_console();
super::version( c );
}
void failure( TCLAP::CmdLineInterface & c, TCLAP::ArgException & e ) override
{
rsutils::os::ensure_console();
super::failure( c, e );
}
} our_cmdline_output;
cmd.setOutput( &our_cmdline_output );
cmd.parse( argc, argv );
#ifdef BUILD_EASYLOGGINGPP
if( debug_arg.getValue() )
rsutils::os::ensure_console();
#if defined( WIN32 )
// In Windows, we have no console unless we start the viewer from one; without one, calling log_to_console will
// ensure a console, so we want to avoid it by default!
if( GetStdHandle( STD_OUTPUT_HANDLE ) )
#endif
rs2::log_to_console( debug_arg.getValue() ? RS2_LOG_SEVERITY_DEBUG : RS2_LOG_SEVERITY_INFO );
#endif
std::shared_ptr<device_models_list> device_models = std::make_shared<device_models_list>();
rsutils::json settings = rsutils::json::object();
if( only_sw_arg.getValue() )
{
#if defined( BUILD_WITH_DDS )
settings["dds"]["enabled"]; // null: remove global dds:false or dds/enabled:false, if any
#endif
settings["device-mask"] = RS2_PRODUCT_LINE_SW_ONLY | RS2_PRODUCT_LINE_ANY;
}
context ctx( settings.dump() );
ux_window window("Intel RealSense Viewer", ctx);
// Create RealSense Context
device_changes devices_connection_changes(ctx);
std::vector<std::pair<std::string, std::string>> device_names;
std::string error_message;
std::string label;
device_model* device_to_remove = nullptr;
bool is_ip_device_connected = false;
std::string ip_address;
#ifdef BUILD_EASYLOGGINGPP
bool const disable_log_to_console = debug_arg.getValue();
#else
bool const disable_log_to_console = false;
#endif
viewer_model viewer_model( ctx, disable_log_to_console );
update_viewer_configuration(viewer_model);
std::vector<device> connected_devs;
std::mutex m;
#ifdef BUILD_EASYLOGGINGPP
std::weak_ptr<notifications_model> notifications = viewer_model.not_model;
rs2::log_to_callback( RS2_LOG_SEVERITY_INFO,
[notifications]( rs2_log_severity severity, rs2::log_message const& msg )
{
if (auto not_model = notifications.lock())
{
not_model->output.add_log(severity, msg.filename(), (int)(msg.line_number()), msg.raw());
}
});
#endif
window.on_file_drop = [&](std::string filename)
{
add_playback_device(ctx, device_models, error_message, viewer_model, filename);
if (!error_message.empty())
{
viewer_model.not_model->add_notification({ error_message,
RS2_LOG_SEVERITY_ERROR, RS2_NOTIFICATION_CATEGORY_UNKNOWN_ERROR });
}
};
for (int i = 1; i < argc; i++)
{
try
{
const char* arg = argv[i];
std::ifstream file(arg);
if (!file.good())
continue;
add_playback_device(ctx, device_models, error_message, viewer_model, arg);
}
catch (const rs2::error& e)
{
error_message = error_to_string(e);
}
catch (const std::exception& e)
{
error_message = e.what();
}
}
window.on_load = [&]()
{
refresh_devices(m, ctx, devices_connection_changes, connected_devs,
device_names, *device_models, viewer_model, error_message);
return true;
};
if (argc == 2)
{
try
{
is_ip_device_connected = add_remote_device(ctx, argv[1]);
}
catch (std::runtime_error e)
{
error_message = e.what();
}
}
// Closing the window
while (window)
{
auto device_changed = refresh_devices(m, ctx, devices_connection_changes, connected_devs,
device_names, *device_models, viewer_model, error_message);
auto output_height = viewer_model.get_output_height();
rect viewer_rect = { viewer_model.panel_width,
viewer_model.panel_y, window.width() -
viewer_model.panel_width,
window.height() - viewer_model.panel_y - output_height };
// Flags for pop-up window - no window resize, move or collaps
auto flags = ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove |
ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoTitleBar |
ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_NoBringToFrontOnFocus;
ImGui::SetNextWindowPos({ 0, 0 });
ImGui::SetNextWindowSize({ viewer_model.panel_width, viewer_model.panel_y });
ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(0, 0));
ImGui::Begin("Add Device Panel", nullptr, flags);
ImGui::PushFont(window.get_large_font());
ImGui::PushStyleColor(ImGuiCol_PopupBg, from_rgba(230, 230, 230, 255));
ImGui::PushStyleColor(ImGuiCol_HeaderHovered, from_rgba(0, 0xae, 0xff, 255));
ImGui::PushStyleColor(ImGuiCol_TextSelectedBg, from_rgba(255, 255, 255, 255));
ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(5, 5));
ImGui::SetNextWindowPos({ 0, viewer_model.panel_y });
std::string add_source_button_text = rsutils::string::from()
<< " " << textual_icons::plus_circle << " Add Source\t\t\t\t\t\t\t\t\t\t\t";
if (ImGui::Button(add_source_button_text.c_str(), { viewer_model.panel_width - 1, viewer_model.panel_y }))
ImGui::OpenPopup("select");
auto new_devices_count = device_names.size() + 1;
for (auto&& dev_model : *device_models)
{
auto connected_devs_itr = std::find_if(begin(connected_devs), end(connected_devs),
[&](const device& d) { return get_device_name(d) == get_device_name(dev_model->dev); });
if (connected_devs_itr != end(connected_devs) || dev_model->dev.is<playback>())
new_devices_count--;
}
ImGui::PushFont(window.get_font());
int multiline_devices_names = 0;
for (size_t i = 0; i < device_names.size(); i++)
{
if (device_names[i].first.find("\n") != std::string::npos)
{
bool show_device_in_list = true;
for (auto&& dev_model : *device_models)
{
if (get_device_name(dev_model->dev) == device_names[i])
{
show_device_in_list = false;
break;
}
}
if (show_device_in_list)
{
multiline_devices_names++;
}
}
}
float line_h = ImGui::GetTextLineHeightWithSpacing() + 2;
float separator_h = new_devices_count > 1 ? ImGui::GetStyle().ItemSpacing.y : 0;
float popup_select_h = line_h * ( new_devices_count + multiline_devices_names ) + separator_h + ( is_ip_device_connected ? 0 : line_h );
ImVec2 popup_select_size = { viewer_model.panel_width, popup_select_h };
ImGui::SetNextWindowSize( popup_select_size );
if (ImGui::BeginPopup("select"))
{
ImGui::PushStyleColor(ImGuiCol_Text, dark_grey);
ImGui::Columns(1, "DevicesList", false);
for (int i = 0; i < device_names.size(); i++)
{
bool skip = false;
for (auto&& dev_model : *device_models)
if (get_device_name(dev_model->dev) == device_names[i]) skip = true;
if (skip) continue;
auto dev = connected_devs[i];
std::string dev_type;
if( dev.supports( RS2_CAMERA_INFO_USB_TYPE_DESCRIPTOR ) )
{
dev_type = "USB";
dev_type += dev.get_info( RS2_CAMERA_INFO_USB_TYPE_DESCRIPTOR );
}
else if( dev.supports( RS2_CAMERA_INFO_PRODUCT_ID ) )
{
dev_type = dev.get_info( RS2_CAMERA_INFO_PRODUCT_ID );
if( dev_type == "ABCD" ) // Specific for D457
dev_type = "GMSL";
}
std::string line = rsutils::string::from() << dev.get_info( RS2_CAMERA_INFO_NAME ) << " (" << dev_type
<< ") S/N " << device_names[i].second.c_str();
ImGui::PushID(static_cast<int>(i));
if (ImGui::Selectable(line.c_str(), false, ImGuiSelectableFlags_SpanAllColumns)/* || switch_to_newly_loaded_device*/)
{
try
{
device_models->emplace_back(new device_model(dev, error_message, viewer_model));
}
catch (const error& e)
{
error_message = error_to_string(e);
}
catch (const std::exception& e)
{
error_message = e.what();
}
}
ImGui::PopID();
}
if (new_devices_count > 1) ImGui::Separator();
if (ImGui::Selectable("Load Recorded Sequence", false, ImGuiSelectableFlags_SpanAllColumns))
{
if (auto ret = file_dialog_open(open_file, "ROS-bag\0*.bag\0", NULL, NULL))
{
add_playback_device(ctx, device_models, error_message, viewer_model, ret);
}
}
ImGui::NextColumn();
bool close_ip_popup = false;
if (!is_ip_device_connected)
{
if (ImGui::Selectable("Add Network Device", false, ImGuiSelectableFlags_SpanAllColumns | ImGuiSelectableFlags_DontClosePopups))
{
error_message = "RealSense Network Devices are unsupported at this time";
}
float width = 300;
float height = 125;
float posx = window.width() * 0.5f - width * 0.5f;
float posy = window.height() * 0.5f - height * 0.5f;
ImGui::SetNextWindowPos({ posx, posy });
ImGui::SetNextWindowSize({ width, height });
ImGui::PushStyleColor(ImGuiCol_PopupBg, sensor_bg);
ImGui::PushStyleColor(ImGuiCol_TextSelectedBg, white);
ImGui::PushStyleColor(ImGuiCol_Text, light_grey);
ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, 0);
if (ImGui::BeginPopupModal("Network Device", nullptr, ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove))
{
ImGui::SetCursorPosY(ImGui::GetCursorPosY() + 3);
ImGui::SetCursorPosX(10);
ImGui::Text("Connect to a Linux system running rs-server");
ImGui::SetCursorPosY(ImGui::GetCursorPosY() + 5);
static char ip_input[255];
std::copy(ip_address.begin(), ip_address.end(), ip_input);
ip_input[ip_address.size()] = '\0';
ImGui::SetCursorPosY(ImGui::GetCursorPosY() + 5);
ImGui::SetCursorPosX(10);
ImGui::Text("Device IP: ");
ImGui::SameLine();
//ImGui::SetCursorPosY(ImGui::GetCursorPosY() - 1);
ImGui::PushItemWidth(width - ImGui::GetCursorPosX() - 10);
if (ImGui::GetWindowIsFocused() && !ImGui::IsAnyItemActive())
{
ImGui::SetKeyboardFocusHere();
}
ImGui::PushStyleColor(ImGuiCol_TextSelectedBg, light_blue);
ImGui::SetCursorPosY(ImGui::GetCursorPosY() - 3);
if (ImGui::InputText("##ip", ip_input, 255))
{
ip_address = ip_input;
}
ImGui::PopStyleColor();
ImGui::SetCursorPosY(ImGui::GetCursorPosY() + 6);
ImGui::PopItemWidth();
ImGui::SetCursorPosX(width / 2 - 105);
if (ImGui::ButtonEx("OK", { 100.f, 25.f }) || ImGui::IsKeyDown(GLFW_KEY_ENTER) || ImGui::IsKeyDown(GLFW_KEY_KP_ENTER))
{
try
{
is_ip_device_connected = add_remote_device(ctx, ip_address);
refresh_devices(m, ctx, devices_connection_changes, connected_devs, device_names, *device_models, viewer_model, error_message);
auto dev = connected_devs[connected_devs.size() - 1];
device_models->emplace_back(new device_model(dev, error_message, viewer_model));
config_file::instance().set(configurations::viewer::last_ip, ip_address);
}
catch (std::runtime_error e)
{
error_message = e.what();
}
ip_address = "";
close_ip_popup = true;
ImGui::CloseCurrentPopup();
}
ImGui::SameLine();
ImGui::SetCursorPosX(width / 2 + 5);
if (ImGui::Button("Cancel", { 100.f, 25.f }) || ImGui::IsKeyDown(GLFW_KEY_ESCAPE))
{
ip_address = "";
close_ip_popup = true;
ImGui::CloseCurrentPopup();
}
ImGui::EndPopup();
}
ImGui::PopStyleColor(3);
ImGui::PopStyleVar(1);
}
if (close_ip_popup)
{
ImGui::CloseCurrentPopup();
close_ip_popup = false;
}
ImGui::PopStyleColor();
ImGui::EndPopup();
}
ImGui::PopFont();
ImGui::PopStyleVar();
ImGui::PopStyleColor();
ImGui::PopStyleColor();
ImGui::PopStyleColor();
ImGui::PopFont();
ImGui::End();
ImGui::PopStyleVar();
viewer_model.show_top_bar(window, viewer_rect, *device_models);
auto output_rect = rect{ viewer_model.panel_width,
window.height() - viewer_model.get_output_height(),
window.width() - viewer_model.panel_width, float(viewer_model.get_output_height()) };
viewer_model.not_model->output.draw(window, output_rect, *device_models);
// Set window position and size
ImGui::SetNextWindowPos({ 0, viewer_model.panel_y });
ImGui::SetNextWindowSize({ viewer_model.panel_width, window.height() - viewer_model.panel_y });
ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(0, 0));
ImGui::PushStyleColor(ImGuiCol_WindowBg, sensor_bg);
// *********************
// Creating window menus
// *********************
ImGui::Begin("Control Panel", nullptr, flags | ImGuiWindowFlags_AlwaysVerticalScrollbar);
if (device_models->size() > 0)
{
std::vector<std::function<void()>> draw_later;
auto windows_width = ImGui::GetContentRegionMax().x;
for (auto&& dev_model : *device_models)
{
dev_model->draw_controls(viewer_model.panel_width, viewer_model.panel_y,
window, error_message, device_to_remove, viewer_model, windows_width, draw_later);
}
if (viewer_model.ppf.is_rendering())
{
if (!std::any_of(device_models->begin(), device_models->end(),
[](const std::unique_ptr<device_model>& dm)
{
return dm->is_streaming();
}))
{
// Stopping post processing filter rendering thread
viewer_model.ppf.stop();
}
}
ImGui::SetContentRegionWidth(windows_width);
auto pos = ImGui::GetCursorScreenPos();
auto h = ImGui::GetWindowHeight();
if (h > pos.y - viewer_model.panel_y)
{
ImGui::GetWindowDrawList()->AddLine({ pos.x,pos.y }, { pos.x + viewer_model.panel_width,pos.y }, ImColor(from_rgba(0, 0, 0, 0xff)));
ImRect bb(pos, ImVec2(pos.x + ImGui::GetContentRegionAvail().x, pos.y + ImGui::GetContentRegionAvail().y));
ImGui::GetWindowDrawList()->AddRectFilled(bb.GetTL(), bb.GetBR(), ImColor(dark_window_background));
}
for (auto&& lambda : draw_later)
{
try
{
lambda();
}
catch (const error& e)
{
error_message = error_to_string(e);
}
catch (const std::exception& e)
{
error_message = e.what();
}
}
if (device_to_remove)
{
if (auto p = device_to_remove->dev.as<playback>())
{
ctx.unload_device(p.file_name());
}
viewer_model.syncer->remove_syncer(device_to_remove->dev_syncer);
auto it = std::find_if(begin(*device_models), end(*device_models),
[&](const std::unique_ptr<device_model>& other)
{ return get_device_name(other->dev) == get_device_name(device_to_remove->dev); });
if (it != device_models->end())
{
it->reset();
device_models->erase(it);
}
device_to_remove = nullptr;
}
}
else
{
const ImVec2 pos = ImGui::GetCursorScreenPos();
ImRect bb(pos, ImVec2(pos.x + ImGui::GetContentRegionAvail().x, pos.y + ImGui::GetContentRegionAvail().y));
ImGui::GetWindowDrawList()->AddRectFilled(bb.GetTL(), bb.GetBR(), ImColor(dark_window_background));
viewer_model.show_no_device_overlay(window.get_large_font(), 50, static_cast<int>(viewer_model.panel_y + 50));
}
ImGui::End();
ImGui::PopStyleVar();
ImGui::PopStyleColor();
// Fetch and process frames from queue
viewer_model.handle_ready_frames(viewer_rect, window, static_cast<int>(device_models->size()), error_message);
}
// Stopping post processing filter rendering thread
viewer_model.ppf.stop();
// Stop all subdevices
for (auto&& device_model : *device_models)
for (auto&& sub : device_model->subdevices)
{
if (sub->streaming)
sub->stop(viewer_model.not_model);
}
return EXIT_SUCCESS;
}
catch (const error & e)
{
std::cerr << "RealSense error calling " << e.get_failed_function() << "(" << e.get_failed_args() << "):\n " << e.what() << std::endl;
return EXIT_FAILURE;
}
catch (const std::exception& e)
{
std::cerr << e.what() << std::endl;
return EXIT_FAILURE;
}