blob: 40d1468cdb07287272ebcc17369b8cb7f07bf252 [file] [log] [blame]
Parker Schuhef47dbf2017-03-04 16:59:30 -08001#include "aos/vision/debug/debug_window.h"
Parker Schuh2cd173d2017-01-28 00:12:01 -08002
3#include <gdk-pixbuf/gdk-pixbuf.h>
4#include <gtk/gtk.h>
5#include <poll.h>
Tyler Chatowbf0609c2021-07-31 16:13:27 -07006
7#include <cstdio>
8#include <cstdlib>
Parker Schuh2cd173d2017-01-28 00:12:01 -08009#include <functional>
10#include <memory>
11#include <vector>
12
13#include "aos/vision/image/image_types.h"
14
Stephan Pleinesf63bde82024-01-13 15:59:33 -080015namespace aos::vision {
Parker Schuh2cd173d2017-01-28 00:12:01 -080016
17template <typename T, gboolean (T::*DrawMethod)(cairo_t *cr)>
18gboolean DrawCallback(GtkWidget *, cairo_t *cr, gpointer data) {
19 return ((*((T *)data)).*DrawMethod)(cr);
20}
21
22template <typename T, gboolean (T::*DrawMethod)(cairo_t *cr)>
23void g_draw_signal_connect(GtkWidget *widget, T *obj) {
24 gboolean (*fnptr)(GtkWidget *, cairo_t *, gpointer) =
25 DrawCallback<T, DrawMethod>;
26 g_signal_connect(widget, "draw", G_CALLBACK(fnptr), obj);
27}
28
Parker Schuhef47dbf2017-03-04 16:59:30 -080029struct DebugWindow::Internals {
Parker Schuh2cd173d2017-01-28 00:12:01 -080030 Internals(bool flip) : flip_(flip) {}
31
32 gboolean Draw(cairo_t *cr) {
33 needs_draw = false;
34 cairo_scale(cr, scale_factor, scale_factor);
35 if (pixbuf != nullptr) {
36 cairo_save(cr);
37 if (flip_) {
38 cairo_translate(cr, ptr.fmt().w, ptr.fmt().h);
39 cairo_scale(cr, -1, -1);
40 }
41 gdk_cairo_set_source_pixbuf(cr, pixbuf, 0.0, 0.0);
42 cairo_paint(cr);
43 cairo_restore(cr);
44 }
45
46 int w = ptr.fmt().w;
47 int h = ptr.fmt().h;
48 if (overlays) {
49 for (const auto &ov : *overlays) {
50 cairo_save(cr);
Parker Schuhcd258b82017-04-09 16:28:29 -070051 CairoRender render(cr, 1.0 / scale_factor);
Parker Schuh2cd173d2017-01-28 00:12:01 -080052 ov->Draw(&render, w, h);
53 cairo_restore(cr);
54 }
55 }
56
Parker Schuhcd258b82017-04-09 16:28:29 -070057 for (const auto &ov : overlays_internal_) {
58 cairo_save(cr);
59 CairoRender render(cr, 1.0 / scale_factor);
60 ov->Draw(&render, w, h);
61 cairo_restore(cr);
62 }
63
Parker Schuh2cd173d2017-01-28 00:12:01 -080064 return FALSE;
65 }
66
67 GdkPixbuf *pixbuf = nullptr;
68 GtkWidget *drawing_area = nullptr;
69 ImagePtr ptr;
70 bool needs_draw = true;
71 GtkWidget *window;
72 std::vector<OverlayBase *> *overlays = nullptr;
Parker Schuhcd258b82017-04-09 16:28:29 -070073 std::vector<OverlayBase *> overlays_internal_;
Parker Schuh2cd173d2017-01-28 00:12:01 -080074 double scale_factor;
75
76 // flip the image rows on drawing
77 bool flip_ = false;
78
79 // clear per frame
80 bool clear_per_frame_ = true;
81};
82
Parker Schuhef47dbf2017-03-04 16:59:30 -080083void DebugWindow::SetOverlays(std::vector<OverlayBase *> *overlays) {
Parker Schuh2cd173d2017-01-28 00:12:01 -080084 self->overlays = overlays;
85}
86
Parker Schuhcd258b82017-04-09 16:28:29 -070087void DebugWindow::AddOverlay(OverlayBase *overlay) {
88 self->overlays_internal_.push_back(overlay);
89}
90
Parker Schuhef47dbf2017-03-04 16:59:30 -080091void DebugWindow::Redraw() {
Parker Schuh2cd173d2017-01-28 00:12:01 -080092 if (!self->needs_draw) {
93 gtk_widget_queue_draw(self->drawing_area);
94 self->needs_draw = true;
95 }
96}
97
Parker Schuhef47dbf2017-03-04 16:59:30 -080098void DebugWindow::UpdateImage(ImagePtr ptr) {
Parker Schuh2cd173d2017-01-28 00:12:01 -080099 if (ptr.data() != self->ptr.data()) {
100 int w = ptr.fmt().w;
101 int h = ptr.fmt().h;
102 self->pixbuf = gdk_pixbuf_new_from_data(
103 (const unsigned char *)ptr.data(), GDK_COLORSPACE_RGB, FALSE, 8,
104 ptr.fmt().w, ptr.fmt().h, 3 * ptr.fmt().w, NULL, NULL);
105 self->ptr = ptr;
106
107 gtk_window_set_default_size(GTK_WINDOW(self->window), w * scale_factor,
108 h * scale_factor);
109
110 gtk_widget_set_size_request(self->drawing_area, w * scale_factor,
111 h * scale_factor);
112 window_height_ = h;
113 window_width_ = w;
114 }
Parker Schuh309dd722017-02-25 11:31:18 -0800115 if (!shown_yet_) {
116 gtk_widget_show_all(self->window);
117 shown_yet_ = true;
118 }
Parker Schuh2cd173d2017-01-28 00:12:01 -0800119}
120
Parker Schuhef47dbf2017-03-04 16:59:30 -0800121void DebugWindow::MoveTo(int x, int y) {
Parker Schuh2cd173d2017-01-28 00:12:01 -0800122 gtk_window_move(GTK_WINDOW(self->window), x, y);
123}
124
Parker Schuhef47dbf2017-03-04 16:59:30 -0800125void DebugWindow::SetScale(double scale_factor_inp) {
Parker Schuh2cd173d2017-01-28 00:12:01 -0800126 int w = window_width_;
127 int h = window_height_;
128
129 scale_factor = scale_factor_inp;
130 self->scale_factor = scale_factor;
131
132 gtk_window_resize(GTK_WINDOW(self->window), w * scale_factor,
133 h * scale_factor);
134
135 gtk_widget_set_size_request(self->drawing_area, w * scale_factor,
136 h * scale_factor);
137}
138
139gboolean debug_viewer_key_press_event(GtkWidget * /*widget*/,
140 GdkEventKey *event, gpointer user_data) {
141 auto &key_press_cb =
Parker Schuhef47dbf2017-03-04 16:59:30 -0800142 reinterpret_cast<DebugWindow *>(user_data)->key_press_event;
Parker Schuh2cd173d2017-01-28 00:12:01 -0800143 if (key_press_cb) key_press_cb(event->keyval);
144 return FALSE;
145}
146
Parker Schuhef47dbf2017-03-04 16:59:30 -0800147DebugWindow::DebugWindow(bool flip) : self(new Internals(flip)) {
Parker Schuh2cd173d2017-01-28 00:12:01 -0800148 self->scale_factor = scale_factor;
149 GtkWidget *window;
150 auto drawing_area = self->drawing_area = gtk_drawing_area_new();
151 gtk_widget_set_size_request(drawing_area, window_width_ * scale_factor,
152 window_height_ * scale_factor);
153 gtk_widget_add_events(drawing_area, GDK_KEY_PRESS_MASK);
154
Parker Schuhef47dbf2017-03-04 16:59:30 -0800155 g_draw_signal_connect<DebugWindow::Internals, &DebugWindow::Internals::Draw>(
Parker Schuh2cd173d2017-01-28 00:12:01 -0800156 drawing_area, self.get());
157
158 window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
159 self->window = window;
160 g_signal_connect(window, "key-press-event",
161 G_CALLBACK(debug_viewer_key_press_event), this);
162 gtk_window_set_title(GTK_WINDOW(window), "Window");
163 gtk_window_set_default_size(GTK_WINDOW(window), window_width_ * scale_factor,
164 window_height_ * scale_factor);
165
166 gtk_container_add(GTK_CONTAINER(window), drawing_area);
Parker Schuh2cd173d2017-01-28 00:12:01 -0800167}
Parker Schuhef47dbf2017-03-04 16:59:30 -0800168DebugWindow::~DebugWindow() {}
Parker Schuh2cd173d2017-01-28 00:12:01 -0800169
170void CairoRender::Text(int x, int y, int /*text_x*/, int /*text_y*/,
171 const std::string &text) {
Parker Schuhcd258b82017-04-09 16:28:29 -0700172 cairo_save(cr_);
Parker Schuh2cd173d2017-01-28 00:12:01 -0800173 cairo_move_to(cr_, x, y);
Parker Schuhcd258b82017-04-09 16:28:29 -0700174 cairo_scale(cr_, text_scale_, text_scale_);
175
176 auto *pango_lay = pango_cairo_create_layout(cr_);
Parker Schuh2cd173d2017-01-28 00:12:01 -0800177 pango_layout_set_text(pango_lay, text.data(), text.size());
178 pango_cairo_show_layout(cr_, pango_lay);
179 g_object_unref(pango_lay);
Parker Schuhcd258b82017-04-09 16:28:29 -0700180 cairo_restore(cr_);
Parker Schuh2cd173d2017-01-28 00:12:01 -0800181}
182
Stephan Pleinesf63bde82024-01-13 15:59:33 -0800183} // namespace aos::vision