From 8f2d66d0e5d35daf93670269e336047627eaa745 Mon Sep 17 00:00:00 2001 From: Trey Moen <50057480+greatgitsby@users.noreply.github.com> Date: Mon, 7 Sep 2026 21:26:53 -0700 Subject: [PATCH] cabana: round only the outer video frame (#38808) * cabana: remove video frame corner rounding * cabana: round the outer video frame including letterboxing --- .../tools/cabana/ui/widgets/cameraview.cc | 19 ++++++++++++++++++- .../tools/cabana/ui/widgets/cameraview.h | 2 ++ .../tools/cabana/ui/widgets/videowidget.cc | 2 +- 3 files changed, 21 insertions(+), 2 deletions(-) diff --git a/openpilot/tools/cabana/ui/widgets/cameraview.cc b/openpilot/tools/cabana/ui/widgets/cameraview.cc index 460ef47c25..b771717c22 100644 --- a/openpilot/tools/cabana/ui/widgets/cameraview.cc +++ b/openpilot/tools/cabana/ui/widgets/cameraview.cc @@ -21,6 +21,23 @@ void generateMipmap() { } } // namespace +void drawVideoFrame(ImDrawList *draw_list, ImTextureRef texture, const ImRect &rect, const VideoPlacement &placement) { + const ImVec2 size(placement.max.x - placement.min.x, placement.max.y - placement.min.y); + if (size.x <= 0 || size.y <= 0) return; + + // Round the full frame, then clip to the square video bounds so letterboxing + // doesn't introduce a second set of rounded corners around the image. + const ImVec2 uv_scale((placement.uv1.x - placement.uv0.x) / size.x, + (placement.uv1.y - placement.uv0.y) / size.y); + const ImVec2 uv0(placement.uv0.x + (rect.Min.x - placement.min.x) * uv_scale.x, + placement.uv0.y + (rect.Min.y - placement.min.y) * uv_scale.y); + const ImVec2 uv1(placement.uv1.x + (rect.Max.x - placement.max.x) * uv_scale.x, + placement.uv1.y + (rect.Max.y - placement.max.y) * uv_scale.y); + draw_list->PushClipRect(placement.min, placement.max, true); + draw_list->AddImageRounded(texture, rect.Min, rect.Max, uv0, uv1, IM_COL32_WHITE, ImGui::GetStyle().ChildRounding); + draw_list->PopClipRect(); +} + void GlTexture::upload(const RgbImage &image) { if (id == 0) { glGenTextures(1, &id); @@ -114,7 +131,7 @@ void CameraWidget::paint() { // mirror cabin camera horizontally std::swap(placement.uv0.x, placement.uv1.x); } - p->AddImageRounded(frame_texture_.ref(), placement.min, placement.max, placement.uv0, placement.uv1, IM_COL32_WHITE, ImGui::GetStyle().ChildRounding); + drawVideoFrame(p, frame_texture_.ref(), rect_, placement); } void CameraWidget::vipcThread() { diff --git a/openpilot/tools/cabana/ui/widgets/cameraview.h b/openpilot/tools/cabana/ui/widgets/cameraview.h index 000e745f66..db4e04f63c 100644 --- a/openpilot/tools/cabana/ui/widgets/cameraview.h +++ b/openpilot/tools/cabana/ui/widgets/cameraview.h @@ -50,6 +50,8 @@ inline VideoPlacement videoPlacement(const ImRect &rect, float source_aspect_rat return placement; } +void drawVideoFrame(ImDrawList *draw_list, ImTextureRef texture, const ImRect &rect, const VideoPlacement &placement); + // tightly packed RGBA pixels struct RgbImage { int width = 0; diff --git a/openpilot/tools/cabana/ui/widgets/videowidget.cc b/openpilot/tools/cabana/ui/widgets/videowidget.cc index 3149619d71..5122ca96fa 100644 --- a/openpilot/tools/cabana/ui/widgets/videowidget.cc +++ b/openpilot/tools/cabana/ui/widgets/videowidget.cc @@ -550,7 +550,7 @@ void StreamCameraView::drawScrubThumbnail(ImDrawList *p, double sec) { p->AddRectFilled(rect().Min, rect().Max, IM_COL32(0, 0, 0, 255), ImGui::GetStyle().ChildRounding); if (const RgbImage *image = thumbnailAt(sec)) { const VideoPlacement placement = videoPlacement(rect(), (float)image->width / image->height, settings.crop_video); - p->AddImageRounded(big_thumbnail_texture_.ref(), placement.min, placement.max, placement.uv0, placement.uv1, IM_COL32_WHITE, ImGui::GetStyle().ChildRounding); + drawVideoFrame(p, big_thumbnail_texture_.ref(), rect(), placement); drawTime(p, rect(), sec); } }