Skip to content

Commit 2647ef3

Browse files
Evgeni Raikhelclaude
andcommitted
feat(realsense-viewer): viewport grid and metadata overlay
Adds an optional 2D viewport crosshair overlay to the realsense-viewer. 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 - refactor(viewer): make viewport grid overlay a built-in capability - Drop BUILD_VIEWPORT_GRID_OVERLAY cmake option and remove all #ifdef guards — the feature is now always compiled into realsense-viewer. - Rename draw_2d_grid to draw_crosshair per review request. - Update grid overlay button tooltips - Align hover hint text with draw_crosshair rename. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent 1350278 commit 2647ef3

8 files changed

Lines changed: 115 additions & 2 deletions

File tree

common/device-model.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,15 @@ 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+
namespace viewport_grid
154+
{
155+
static const char* horizontal_lines{ "viewer_model.grid.horizontal_lines" };
156+
static const char* vertical_lines { "viewer_model.grid.vertical_lines" };
157+
static const char* line_width { "viewer_model.grid.line_width" };
158+
static const char* line_color_r { "viewer_model.grid.line_color_r" };
159+
static const char* line_color_g { "viewer_model.grid.line_color_g" };
160+
static const char* line_color_b { "viewer_model.grid.line_color_b" };
161+
}
153162
}
154163
namespace window
155164
{

common/rs-config.cpp

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,6 @@ config_file::config_file( std::string const & filename )
111111
}
112112
catch(...)
113113
{
114-
115114
}
116115
}
117116

common/rs-config.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,13 +80,15 @@ namespace rs2
8080
}
8181

8282
bool contains(const char* key) const;
83-
83+
8484
void save(const char* filename);
8585

8686
void reset();
8787

8888
void remove(const char* key);
8989

90+
bool is_empty() const { return _j.empty(); }
91+
9092
static config_file& instance();
9193

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

common/stream-model.cpp

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@
77
#include "os.h"
88
#include <imgui_internal.h>
99
#include <realsense_imgui.h>
10+
#include <iomanip>
11+
#include <sstream>
1012

1113
struct attribute
1214
{
@@ -28,6 +30,21 @@ namespace rs2
2830
configurations::viewer::show_stream_details, false);
2931
show_safety_zones_2d = config_file::instance().get_or_default(
3032
configurations::viewer::show_safety_zones_2d, true);
33+
{
34+
namespace cfg = configurations::viewer::viewport_grid;
35+
auto& cf = config_file::instance();
36+
37+
auto valid_lines = []( int v ) { return ( v >= 1 && v <= 5 ) ? v : 1; };
38+
grid_h_lines = valid_lines( cf.get_nested<int>( cfg::horizontal_lines, 1 ) );
39+
grid_v_lines = valid_lines( cf.get_nested<int>( cfg::vertical_lines, 1 ) );
40+
int w = cf.get_nested<int>( cfg::line_width, 1 );
41+
if ( w >= 1 ) grid_line_width = w;
42+
int r = cf.get_nested<int>( cfg::line_color_r, 255 );
43+
int g = cf.get_nested<int>( cfg::line_color_g, 255 );
44+
int b = cf.get_nested<int>( cfg::line_color_b, 255 );
45+
if ( r >= 0 && r <= 255 && g >= 0 && g <= 255 && b >= 0 && b <= 255 )
46+
{ grid_color_r = r; grid_color_g = g; grid_color_b = b; }
47+
}
3148
}
3249

3350
std::shared_ptr<texture_buffer> stream_model::upload_frame(frame&& f)
@@ -131,6 +148,31 @@ namespace rs2
131148
glPopAttrib();
132149
}
133150

151+
static void draw_crosshair(const rect& r, int h_lines, int v_lines, int line_width,
152+
int cr, int cg, int cb)
153+
{
154+
glPushAttrib(GL_ENABLE_BIT | GL_LINE_BIT | GL_COLOR_BUFFER_BIT | GL_CURRENT_BIT);
155+
glLineWidth(static_cast<GLfloat>(line_width));
156+
glEnable(GL_BLEND);
157+
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
158+
glColor4f(cr / 255.f, cg / 255.f, cb / 255.f, 0.7f);
159+
glBegin(GL_LINES);
160+
for (int c = 1; c <= v_lines; ++c)
161+
{
162+
float x = r.x + r.w * c / static_cast<float>(v_lines + 1);
163+
glVertex2f(x, r.y);
164+
glVertex2f(x, r.y + r.h);
165+
}
166+
for (int row = 1; row <= h_lines; ++row)
167+
{
168+
float y = r.y + r.h * row / static_cast<float>(h_lines + 1);
169+
glVertex2f(r.x, y);
170+
glVertex2f(r.x + r.w, y);
171+
}
172+
glEnd();
173+
glPopAttrib();
174+
}
175+
134176
bool stream_model::is_stream_visible() const
135177
{
136178
if (dev &&
@@ -413,6 +455,7 @@ namespace rs2
413455
if (RS2_STREAM_DEPTH == profile.stream_type()) ++num_of_buttons; // Color map ruler button
414456
if (RS2_FORMAT_MOTION_XYZ32F == profile.format()) ++num_of_buttons; // Motion graph button
415457
if (RS2_STREAM_OCCUPANCY == profile.stream_type() && _normalized_zoom.w == 1) ++num_of_buttons; // Safety zones button
458+
++num_of_buttons; // Grid overlay button
416459

417460
RsImGui_ScopePushFont(font);
418461
ImGui::PushStyleColor(ImGuiCol_Text, light_grey);
@@ -548,6 +591,31 @@ namespace rs2
548591
}
549592
ImGui::SameLine();
550593

594+
label = rsutils::string::from() << textual_icons::grid << "##Grid " << profile.unique_id();
595+
if (show_grid)
596+
{
597+
ImGui::PushStyleColor(ImGuiCol_Text, light_blue);
598+
ImGui::PushStyleColor(ImGuiCol_TextSelectedBg, light_blue);
599+
if (ImGui::Button(label.c_str(), { 24, top_bar_height }))
600+
{
601+
show_grid = false;
602+
}
603+
if (ImGui::IsItemHovered())
604+
RsImGui::CustomTooltip("Hide crosshair/grid overlay");
605+
ImGui::PopStyleColor(2);
606+
}
607+
else
608+
{
609+
if (ImGui::Button(label.c_str(), { 24, top_bar_height }))
610+
{
611+
show_grid = true;
612+
}
613+
if (ImGui::IsItemHovered())
614+
RsImGui::CustomTooltip("Show crosshair/grid overlay");
615+
}
616+
ImGui::SameLine();
617+
618+
551619
if (RS2_STREAM_DEPTH == profile.stream_type())
552620
{
553621
label = rsutils::string::from() << textual_icons::bar_chart << "##Color map";
@@ -2036,6 +2104,11 @@ namespace rs2
20362104
}
20372105

20382106
update_ae_roi_rect(stream_rect, g, error_message);
2107+
2108+
if (show_grid)
2109+
draw_crosshair(stream_rect, grid_h_lines, grid_v_lines, grid_line_width,
2110+
grid_color_r, grid_color_g, grid_color_b);
2111+
20392112
}
20402113
texture->show_preview(stream_rect, _normalized_zoom);
20412114

common/stream-model.h

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

109+
bool show_grid = false;
110+
int grid_h_lines = 1;
111+
int grid_v_lines = 1;
112+
int grid_line_width = 1;
113+
int grid_color_r = 255;
114+
int grid_color_g = 255;
115+
int grid_color_b = 255;
116+
109117
std::shared_ptr<graph_model> graph;
110118
bool show_graph = false;
111119
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: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,18 @@ 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+
if( config_file::instance().is_empty() )
91+
{
92+
namespace cfg = configurations::viewer::viewport_grid;
93+
auto& cf = config_file::instance();
94+
cf.set_nested_default( cfg::horizontal_lines, 1 );
95+
cf.set_nested_default( cfg::vertical_lines, 1 );
96+
cf.set_nested_default( cfg::line_width, 1 );
97+
cf.set_nested_default( cfg::line_color_r, 255 );
98+
cf.set_nested_default( cfg::line_color_g, 255 );
99+
cf.set_nested_default( cfg::line_color_b, 255 );
100+
}
101+
90102
std::string path;
91103
try
92104
{

common/viewer.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2983,6 +2983,15 @@ namespace rs2
29832983
{
29842984
reload_required = true;
29852985
temp_cfg = config_file();
2986+
{
2987+
namespace cfg = configurations::viewer::viewport_grid;
2988+
temp_cfg.set_nested_default( cfg::horizontal_lines, 1 );
2989+
temp_cfg.set_nested_default( cfg::vertical_lines, 1 );
2990+
temp_cfg.set_nested_default( cfg::line_width, 1 );
2991+
temp_cfg.set_nested_default( cfg::line_color_r, 255 );
2992+
temp_cfg.set_nested_default( cfg::line_color_g, 255 );
2993+
temp_cfg.set_nested_default( cfg::line_color_b, 255 );
2994+
}
29862995
}
29872996
ImGui::SameLine();
29882997
if (ImGui::Button(" Export Settings "))

0 commit comments

Comments
 (0)