Skip to content

Commit 5ef5cb6

Browse files
Evgeni Raikhelclaude
andcommitted
feat(realsense-viewer): viewport grid and metadata overlay
Adds an optional 2D viewport grid overlay to the realsense-viewer, compiled under the BUILD_VIEWPORT_GRID_OVERLAY CMake flag (default OFF). Feature summary - Grid lines rendered over each 2D stream viewport using OpenGL (glBegin/GL_LINES) with glPushAttrib(GL_CURRENT_BIT) to prevent color-state bleed into PiP thumbnails - Two new toggle buttons in each stream header: - Grid icon (fa-th ): show/hide the grid overlay - Info icon: show/hide viewport metadata overlay Both buttons start OFF at every launch (state is not persisted) - Per-stream grid config: horizontal lines [1-5], vertical lines [1-5], line width (>=1), RGB color [0-255 each]; out-of-range values fall back to defaults (not clamped) Configuration (realsense-config.json) - Grid settings stored under viewer_model.grid.* using dot-path nested JSON API (get_nested / set_nested / set_nested_default) - Defaults are written only in two cases: 1. New file: config_file tracks _is_new_file (set in the file-based constructor when load_from_file returns nothing); ux_window writes defaults on startup when is_new_file() is true 2. Restore Defaults button: viewer.cpp injects grid defaults into temp_cfg immediately after the reset, so they are saved on OK/Apply - Existing configs without the grid section are left untouched Files changed - CMake/lrs_options.cmake: add BUILD_VIEWPORT_GRID_OVERLAY option (OFF) - common/device-model.h: configurations::viewer::viewport_grid namespace with the six JSON key constants - common/textual-icons.h: textual_icons::grid icon (, fa-th) - common/rs-config.h / rs-config.cpp: is_new_file() accessor backed by _is_new_file member set in the filename constructor - common/stream-model.h / stream-model.cpp: grid state members, toggle buttons, draw_2d_grid() helper; constructor reads grid config from JSON - common/ux-window.cpp: write grid defaults on new-file startup - common/viewer.cpp: write grid defaults when Restore Defaults is pressed - tools/realsense-viewer/CMakeLists.txt: target_compile_definitions for BUILD_VIEWPORT_GRID_OVERLAY Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent 8c53a92 commit 5ef5cb6

10 files changed

Lines changed: 142 additions & 2 deletions

File tree

CMake/lrs_options.cmake

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,3 +63,4 @@ option(USE_EXTERNAL_LZ4 "Use externally build LZ4 library instead of building an
6363
option(BUILD_ASAN "Enable AddressSanitizer" OFF)
6464
option(BUILD_ROSBAG2 "Build and use rosbag2 recording system" ON) # temporary flag, should be removed when deprecated ROSBAG1 recording system is removed
6565
mark_as_advanced(BUILD_ASAN)
66+
option(BUILD_VIEWPORT_GRID_OVERLAY "Build 2D viewport grid overlay for realsense-viewer (configurable via config-settings.xml)" OFF)

common/device-model.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,17 @@ namespace rs2
150150
static const char* lpc_point_size{ "viewer_model.lpc_point_size" };
151151
static const char* show_safety_zones_3d{ "viewer_model.show_safety_zones_3d" };
152152
static const char* show_safety_zones_2d{ "viewer_model.show_safety_zones_2d" };
153+
#ifdef BUILD_VIEWPORT_GRID_OVERLAY
154+
namespace viewport_grid
155+
{
156+
static const char* horizontal_lines{ "viewer_model.grid.horizontal_lines" };
157+
static const char* vertical_lines { "viewer_model.grid.vertical_lines" };
158+
static const char* line_width { "viewer_model.grid.line_width" };
159+
static const char* line_color_r { "viewer_model.grid.line_color_r" };
160+
static const char* line_color_g { "viewer_model.grid.line_color_g" };
161+
static const char* line_color_b { "viewer_model.grid.line_color_b" };
162+
}
163+
#endif
153164
}
154165
namespace window
155166
{

common/rs-config.cpp

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,6 @@ config_file::config_file( std::string const & filename )
9696
}
9797
catch(...)
9898
{
99-
10099
}
101100
}
102101

common/rs-config.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,13 +78,15 @@ namespace rs2
7878
}
7979

8080
bool contains(const char* key) const;
81-
81+
8282
void save(const char* filename);
8383

8484
void reset();
8585

8686
void remove(const char* key);
8787

88+
bool is_new_file() const { return _j.empty(); }
89+
8890
static config_file& instance();
8991

9092
// Retrieves a value from a nested JSON structure using dot notation

common/stream-model.cpp

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,10 @@
77
#include "os.h"
88
#include <imgui_internal.h>
99
#include <realsense_imgui.h>
10+
#ifdef BUILD_VIEWPORT_GRID_OVERLAY
11+
#include <iomanip>
12+
#include <sstream>
13+
#endif
1014

1115
struct attribute
1216
{
@@ -28,6 +32,23 @@ namespace rs2
2832
configurations::viewer::show_stream_details, false);
2933
show_safety_zones_2d = config_file::instance().get_or_default(
3034
configurations::viewer::show_safety_zones_2d, true);
35+
#ifdef BUILD_VIEWPORT_GRID_OVERLAY
36+
{
37+
namespace cfg = configurations::viewer::viewport_grid;
38+
auto& cf = config_file::instance();
39+
40+
auto valid_lines = []( int v ) { return ( v >= 1 && v <= 5 ) ? v : 1; };
41+
grid_h_lines = valid_lines( cf.get_nested<int>( cfg::horizontal_lines, 1 ) );
42+
grid_v_lines = valid_lines( cf.get_nested<int>( cfg::vertical_lines, 1 ) );
43+
int w = cf.get_nested<int>( cfg::line_width, 1 );
44+
if ( w >= 1 ) grid_line_width = w;
45+
int r = cf.get_nested<int>( cfg::line_color_r, 255 );
46+
int g = cf.get_nested<int>( cfg::line_color_g, 255 );
47+
int b = cf.get_nested<int>( cfg::line_color_b, 255 );
48+
if ( r >= 0 && r <= 255 && g >= 0 && g <= 255 && b >= 0 && b <= 255 )
49+
{ grid_color_r = r; grid_color_g = g; grid_color_b = b; }
50+
}
51+
#endif
3152
}
3253

3354
std::shared_ptr<texture_buffer> stream_model::upload_frame(frame&& f)
@@ -131,6 +152,34 @@ namespace rs2
131152
glPopAttrib();
132153
}
133154

155+
#ifdef BUILD_VIEWPORT_GRID_OVERLAY
156+
static void draw_2d_grid(const rect& r, int h_lines, int v_lines, int line_width,
157+
int cr, int cg, int cb)
158+
{
159+
glPushAttrib(GL_ENABLE_BIT | GL_LINE_BIT | GL_COLOR_BUFFER_BIT | GL_CURRENT_BIT);
160+
glLineWidth(static_cast<GLfloat>(line_width));
161+
glEnable(GL_BLEND);
162+
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
163+
glColor4f(cr / 255.f, cg / 255.f, cb / 255.f, 0.7f);
164+
glBegin(GL_LINES);
165+
for (int c = 1; c <= v_lines; ++c)
166+
{
167+
float x = r.x + r.w * c / static_cast<float>(v_lines + 1);
168+
glVertex2f(x, r.y);
169+
glVertex2f(x, r.y + r.h);
170+
}
171+
for (int row = 1; row <= h_lines; ++row)
172+
{
173+
float y = r.y + r.h * row / static_cast<float>(h_lines + 1);
174+
glVertex2f(r.x, y);
175+
glVertex2f(r.x + r.w, y);
176+
}
177+
glEnd();
178+
glPopAttrib();
179+
}
180+
181+
#endif
182+
134183
bool stream_model::is_stream_visible() const
135184
{
136185
if (dev &&
@@ -413,6 +462,9 @@ namespace rs2
413462
if (RS2_STREAM_DEPTH == profile.stream_type()) ++num_of_buttons; // Color map ruler button
414463
if (RS2_FORMAT_MOTION_XYZ32F == profile.format()) ++num_of_buttons; // Motion graph button
415464
if (RS2_STREAM_OCCUPANCY == profile.stream_type() && _normalized_zoom.w == 1) ++num_of_buttons; // Safety zones button
465+
#ifdef BUILD_VIEWPORT_GRID_OVERLAY
466+
++num_of_buttons; // Grid overlay button
467+
#endif
416468

417469
RsImGui_ScopePushFont(font);
418470
ImGui::PushStyleColor(ImGuiCol_Text, light_grey);
@@ -548,6 +600,33 @@ namespace rs2
548600
}
549601
ImGui::SameLine();
550602

603+
#ifdef BUILD_VIEWPORT_GRID_OVERLAY
604+
label = rsutils::string::from() << textual_icons::grid << "##Grid " << profile.unique_id();
605+
if (show_grid)
606+
{
607+
ImGui::PushStyleColor(ImGuiCol_Text, light_blue);
608+
ImGui::PushStyleColor(ImGuiCol_TextSelectedBg, light_blue);
609+
if (ImGui::Button(label.c_str(), { 24, top_bar_height }))
610+
{
611+
show_grid = false;
612+
}
613+
if (ImGui::IsItemHovered())
614+
RsImGui::CustomTooltip("Hide grid overlay");
615+
ImGui::PopStyleColor(2);
616+
}
617+
else
618+
{
619+
if (ImGui::Button(label.c_str(), { 24, top_bar_height }))
620+
{
621+
show_grid = true;
622+
}
623+
if (ImGui::IsItemHovered())
624+
RsImGui::CustomTooltip("Show grid overlay");
625+
}
626+
ImGui::SameLine();
627+
#endif
628+
629+
551630
if (RS2_STREAM_DEPTH == profile.stream_type())
552631
{
553632
label = rsutils::string::from() << textual_icons::bar_chart << "##Color map";
@@ -2036,6 +2115,13 @@ namespace rs2
20362115
}
20372116

20382117
update_ae_roi_rect(stream_rect, g, error_message);
2118+
2119+
#ifdef BUILD_VIEWPORT_GRID_OVERLAY
2120+
if (show_grid)
2121+
draw_2d_grid(stream_rect, grid_h_lines, grid_v_lines, grid_line_width,
2122+
grid_color_r, grid_color_g, grid_color_b);
2123+
#endif
2124+
20392125
}
20402126
texture->show_preview(stream_rect, _normalized_zoom);
20412127

common/stream-model.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,16 @@ namespace rs2
106106
bool show_metadata = false;
107107
bool show_safety_zones_2d = true;
108108

109+
#ifdef BUILD_VIEWPORT_GRID_OVERLAY
110+
bool show_grid = false;
111+
int grid_h_lines = 1;
112+
int grid_v_lines = 1;
113+
int grid_line_width = 1;
114+
int grid_color_r = 255;
115+
int grid_color_g = 255;
116+
int grid_color_b = 255;
117+
#endif
118+
109119
std::shared_ptr<graph_model> graph;
110120
bool show_graph = false;
111121
bool graph_initialized = false;

common/textual-icons.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ namespace rs2
3434
// A note to a maintainer - preserve order when adding values to avoid duplicates
3535
static const textual_icon search{ u8"\uf002" };
3636
static const textual_icon file_movie{ u8"\uf008" };
37+
static const textual_icon grid{ u8"\uf00a" }; // fa-th: 3x3 grid of squares (viewport grid overlay)
3738
static const textual_icon check{ u8"\uf00c" };
3839
static const textual_icon times{ u8"\uf00d" };
3940
static const textual_icon power_off{ u8"\uf011" };

common/ux-window.cpp

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,20 @@ namespace rs2
8787
config_file::instance().set_default(configurations::viewer::commands_xml, "./Commands.xml");
8888
config_file::instance().set_default(configurations::viewer::hwlogger_xml, "./HWLoggerEvents.xml");
8989

90+
#ifdef BUILD_VIEWPORT_GRID_OVERLAY
91+
if( config_file::instance().is_new_file() )
92+
{
93+
namespace cfg = configurations::viewer::viewport_grid;
94+
auto& cf = config_file::instance();
95+
cf.set_nested( cfg::horizontal_lines, 1 );
96+
cf.set_nested( cfg::vertical_lines, 1 );
97+
cf.set_nested( cfg::line_width, 1 );
98+
cf.set_nested( cfg::line_color_r, 255 );
99+
cf.set_nested( cfg::line_color_g, 255 );
100+
cf.set_nested( cfg::line_color_b, 255 );
101+
}
102+
#endif
103+
90104
std::string path;
91105
try
92106
{

common/viewer.cpp

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2983,6 +2983,17 @@ namespace rs2
29832983
{
29842984
reload_required = true;
29852985
temp_cfg = config_file();
2986+
#ifdef BUILD_VIEWPORT_GRID_OVERLAY
2987+
{
2988+
namespace cfg = configurations::viewer::viewport_grid;
2989+
temp_cfg.set_nested( cfg::horizontal_lines, 1 );
2990+
temp_cfg.set_nested( cfg::vertical_lines, 1 );
2991+
temp_cfg.set_nested( cfg::line_width, 1 );
2992+
temp_cfg.set_nested( cfg::line_color_r, 255 );
2993+
temp_cfg.set_nested( cfg::line_color_g, 255 );
2994+
temp_cfg.set_nested( cfg::line_color_b, 255 );
2995+
}
2996+
#endif
29862997
}
29872998
ImGui::SameLine();
29882999
if (ImGui::Button(" Export Settings "))

tools/realsense-viewer/CMakeLists.txt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -256,6 +256,11 @@ if(OPENVINO_NGRAPH)
256256
target_compile_definitions(realsense-viewer PRIVATE OPENVINO_NGRAPH)
257257
endif()
258258

259+
if(BUILD_VIEWPORT_GRID_OVERLAY)
260+
message(STATUS "Viewport grid overlay enabled for realsense-viewer")
261+
target_compile_definitions(realsense-viewer PRIVATE BUILD_VIEWPORT_GRID_OVERLAY)
262+
endif()
263+
259264
source_group("SW-Update" FILES ${SW_UPDATE_FILES})
260265

261266
include_directories(

0 commit comments

Comments
 (0)