blob: b998c03b952403bc0f2b3454bed5865f13ec9065 [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
15namespace aos {
16namespace vision {
17
18template <typename T, gboolean (T::*DrawMethod)(cairo_t *cr)>
19gboolean DrawCallback(GtkWidget *, cairo_t *cr, gpointer data) {
20 return ((*((T *)data)).*DrawMethod)(cr);
21}
22
23template <typename T, gboolean (T::*DrawMethod)(cairo_t *cr)>
24void g_draw_signal_connect(GtkWidget *widget, T *obj) {
25 gboolean (*fnptr)(GtkWidget *, cairo_t *, gpointer) =
26 DrawCallback<T, DrawMethod>;
27 g_signal_connect(widget, "draw", G_CALLBACK(fnptr), obj);
28}
29
Parker Schuhef47dbf2017-03-04 16:59:30 -080030struct DebugWindow::Internals {
Parker Schuh2cd173d2017-01-28 00:12:01 -080031 Internals(bool flip) : flip_(flip) {}
32
33 gboolean Draw(cairo_t *cr) {
34 needs_draw = false;
35 cairo_scale(cr, scale_factor, scale_factor);
36 if (pixbuf != nullptr) {
37 cairo_save(cr);
38 if (flip_) {
39 cairo_translate(cr, ptr.fmt().w, ptr.fmt().h);
40 cairo_scale(cr, -1, -1);
41 }
42 gdk_cairo_set_source_pixbuf(cr, pixbuf, 0.0, 0.0);
43 cairo_paint(cr);
44 cairo_restore(cr);
45 }
46
47 int w = ptr.fmt().w;
48 int h = ptr.fmt().h;
49 if (overlays) {
50 for (const auto &ov : *overlays) {
51 cairo_save(cr);
Parker Schuhcd258b82017-04-09 16:28:29 -070052 CairoRender render(cr, 1.0 / scale_factor);
Parker Schuh2cd173d2017-01-28 00:12:01 -080053 ov->Draw(&render, w, h);
54 cairo_restore(cr);
55 }
56 }
57
Parker Schuhcd258b82017-04-09 16:28:29 -070058 for (const auto &ov : overlays_internal_) {
59 cairo_save(cr);
60 CairoRender render(cr, 1.0 / scale_factor);
61 ov->Draw(&render, w, h);
62 cairo_restore(cr);
63 }
64
Parker Schuh2cd173d2017-01-28 00:12:01 -080065 return FALSE;
66 }
67
68 GdkPixbuf *pixbuf = nullptr;
69 GtkWidget *drawing_area = nullptr;
70 ImagePtr ptr;
71 bool needs_draw = true;
72 GtkWidget *window;
73 std::vector<OverlayBase *> *overlays = nullptr;
Parker Schuhcd258b82017-04-09 16:28:29 -070074 std::vector<OverlayBase *> overlays_internal_;
Parker Schuh2cd173d2017-01-28 00:12:01 -080075 double scale_factor;
76
77 // flip the image rows on drawing
78 bool flip_ = false;
79
80 // clear per frame
81 bool clear_per_frame_ = true;
82};
83
Parker Schuhef47dbf2017-03-04 16:59:30 -080084void DebugWindow::SetOverlays(std::vector<OverlayBase *> *overlays) {
Parker Schuh2cd173d2017-01-28 00:12:01 -080085 self->overlays = overlays;
86}
87
Parker Schuhcd258b82017-04-09 16:28:29 -070088void DebugWindow::AddOverlay(OverlayBase *overlay) {
89 self->overlays_internal_.push_back(overlay);
90}
91
Parker Schuhef47dbf2017-03-04 16:59:30 -080092void DebugWindow::Redraw() {
Parker Schuh2cd173d2017-01-28 00:12:01 -080093 if (!self->needs_draw) {
94 gtk_widget_queue_draw(self->drawing_area);
95 self->needs_draw = true;
96 }
97}
98
Parker Schuhef47dbf2017-03-04 16:59:30 -080099void DebugWindow::UpdateImage(ImagePtr ptr) {
Parker Schuh2cd173d2017-01-28 00:12:01 -0800100 if (ptr.data() != self->ptr.data()) {
101 int w = ptr.fmt().w;
102 int h = ptr.fmt().h;
103 self->pixbuf = gdk_pixbuf_new_from_data(
104 (const unsigned char *)ptr.data(), GDK_COLORSPACE_RGB, FALSE, 8,
105 ptr.fmt().w, ptr.fmt().h, 3 * ptr.fmt().w, NULL, NULL);
106 self->ptr = ptr;
107
108 gtk_window_set_default_size(GTK_WINDOW(self->window), w * scale_factor,
109 h * scale_factor);
110
111 gtk_widget_set_size_request(self->drawing_area, w * scale_factor,
112 h * scale_factor);
113 window_height_ = h;
114 window_width_ = w;
115 }
Parker Schuh309dd722017-02-25 11:31:18 -0800116 if (!shown_yet_) {
117 gtk_widget_show_all(self->window);
118 shown_yet_ = true;
119 }
Parker Schuh2cd173d2017-01-28 00:12:01 -0800120}
121
Parker Schuhef47dbf2017-03-04 16:59:30 -0800122void DebugWindow::MoveTo(int x, int y) {
Parker Schuh2cd173d2017-01-28 00:12:01 -0800123 gtk_window_move(GTK_WINDOW(self->window), x, y);
124}
125
Parker Schuhef47dbf2017-03-04 16:59:30 -0800126void DebugWindow::SetScale(double scale_factor_inp) {
Parker Schuh2cd173d2017-01-28 00:12:01 -0800127 int w = window_width_;
128 int h = window_height_;
129
130 scale_factor = scale_factor_inp;
131 self->scale_factor = scale_factor;
132
133 gtk_window_resize(GTK_WINDOW(self->window), w * scale_factor,
134 h * scale_factor);
135
136 gtk_widget_set_size_request(self->drawing_area, w * scale_factor,
137 h * scale_factor);
138}
139
140gboolean debug_viewer_key_press_event(GtkWidget * /*widget*/,
141 GdkEventKey *event, gpointer user_data) {
142 auto &key_press_cb =
Parker Schuhef47dbf2017-03-04 16:59:30 -0800143 reinterpret_cast<DebugWindow *>(user_data)->key_press_event;
Parker Schuh2cd173d2017-01-28 00:12:01 -0800144 if (key_press_cb) key_press_cb(event->keyval);
145 return FALSE;
146}
147
Parker Schuhef47dbf2017-03-04 16:59:30 -0800148DebugWindow::DebugWindow(bool flip) : self(new Internals(flip)) {
Parker Schuh2cd173d2017-01-28 00:12:01 -0800149 self->scale_factor = scale_factor;
150 GtkWidget *window;
151 auto drawing_area = self->drawing_area = gtk_drawing_area_new();
152 gtk_widget_set_size_request(drawing_area, window_width_ * scale_factor,
153 window_height_ * scale_factor);
154 gtk_widget_add_events(drawing_area, GDK_KEY_PRESS_MASK);
155
Parker Schuhef47dbf2017-03-04 16:59:30 -0800156 g_draw_signal_connect<DebugWindow::Internals, &DebugWindow::Internals::Draw>(
Parker Schuh2cd173d2017-01-28 00:12:01 -0800157 drawing_area, self.get());
158
159 window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
160 self->window = window;
161 g_signal_connect(window, "key-press-event",
162 G_CALLBACK(debug_viewer_key_press_event), this);
163 gtk_window_set_title(GTK_WINDOW(window), "Window");
164 gtk_window_set_default_size(GTK_WINDOW(window), window_width_ * scale_factor,
165 window_height_ * scale_factor);
166
167 gtk_container_add(GTK_CONTAINER(window), drawing_area);
Parker Schuh2cd173d2017-01-28 00:12:01 -0800168}
Parker Schuhef47dbf2017-03-04 16:59:30 -0800169DebugWindow::~DebugWindow() {}
Parker Schuh2cd173d2017-01-28 00:12:01 -0800170
171void CairoRender::Text(int x, int y, int /*text_x*/, int /*text_y*/,
172 const std::string &text) {
Parker Schuhcd258b82017-04-09 16:28:29 -0700173 cairo_save(cr_);
Parker Schuh2cd173d2017-01-28 00:12:01 -0800174 cairo_move_to(cr_, x, y);
Parker Schuhcd258b82017-04-09 16:28:29 -0700175 cairo_scale(cr_, text_scale_, text_scale_);
176
177 auto *pango_lay = pango_cairo_create_layout(cr_);
Parker Schuh2cd173d2017-01-28 00:12:01 -0800178 pango_layout_set_text(pango_lay, text.data(), text.size());
179 pango_cairo_show_layout(cr_, pango_lay);
180 g_object_unref(pango_lay);
Parker Schuhcd258b82017-04-09 16:28:29 -0700181 cairo_restore(cr_);
Parker Schuh2cd173d2017-01-28 00:12:01 -0800182}
183
184} // namespace vision
185} // namespace aos