From 88fa73f922ffc3b70da7b837ace2a31475e141f4 Mon Sep 17 00:00:00 2001 From: Evgeny Demchenko Date: Thu, 4 Jun 2026 10:19:29 +0100 Subject: [PATCH] =?UTF-8?q?Phase=2011b:=20=D0=BF=D0=BE=D0=B4=D0=BB=D0=BE?= =?UTF-8?q?=D0=B6=D0=BA=D0=B0=20=D0=B4=D0=BB=D1=8F=20text=20overlay=20+=20?= =?UTF-8?q?=D1=81=D1=80=D0=B0=D0=B7=D1=83-=D0=B2=D0=B8=D0=B4=D0=B8=D0=BC?= =?UTF-8?q?=D1=8B=D0=B9=20placeholder?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit User: "у него есть полупрозрачная подложка? у него правильный z-order?" Z-order был ок (overlays draw'аются после layout.render). Но без bg текст плохо читался на пёстром кадре — и до прихода MQTT overlay был visible=0 (не виден вообще). Изменения: - overlay.h: cfc_overlay_text_config_t расширена bg_alpha / bg_y/u/v / bg_pad. bg_alpha=0 — фон отключён (default). - overlay.c draw_text: если bg_alpha>0, перед blit'ом текста рисуем fill rect (atlas_w+2*pad) × (atlas_h+2*pad) с заданным цветом и alpha. - overlay.c update_text: пробрасывает bg-поля при апдейте. - mqtt_overlay: MqttOverlayCfg + JSON loader научились читать bg_alpha, bg_y/u/v, bg_pad, placeholder. Default bg = чёрный 160 alpha, pad 10. - MqttOverlayItem::start: overlay сразу visible=1 с placeholder (default "—"), reposition_overlay вызывается до получения MQTT — placeholder позиционируется в anchor сразу. User'у теперь видна тёмная подложка с текстом в правом-нижнем углу даже если sensor молчит. Co-Authored-By: Claude Opus 4.7 --- .../cuframes_composer/cpp/mqtt_overlay.hpp | 10 +++++++ include/cuframes_composer/overlay.h | 8 ++++++ src/cpp/mqtt_overlay.cpp | 28 ++++++++++++++++--- src/overlay.c | 27 ++++++++++++++++++ 4 files changed, 69 insertions(+), 4 deletions(-) diff --git a/include/cuframes_composer/cpp/mqtt_overlay.hpp b/include/cuframes_composer/cpp/mqtt_overlay.hpp index 77f8847..b90df9d 100644 --- a/include/cuframes_composer/cpp/mqtt_overlay.hpp +++ b/include/cuframes_composer/cpp/mqtt_overlay.hpp @@ -50,6 +50,16 @@ struct MqttOverlayCfg { int r = 255, g = 255, b = 255; int alpha = 230; std::string font_path = "/fonts/DejaVuSans-Bold.ttf"; + + /* Полупрозрачная подложка. bg_alpha=0 → отключено. */ + int bg_alpha = 160; + int bg_y = 16, bg_u = 128, bg_v = 128; /* по умолчанию чёрный */ + int bg_pad = 10; + + /* Что показывать пока нет MQTT-данных. Пусто → overlay невидим до + * первого сообщения. По умолчанию "—" чтобы было видно что overlay + * жив, но данные ещё не пришли. */ + std::string placeholder = "—"; }; struct MqttBrokerCfg { diff --git a/include/cuframes_composer/overlay.h b/include/cuframes_composer/overlay.h index 5221bf2..3f74584 100644 --- a/include/cuframes_composer/overlay.h +++ b/include/cuframes_composer/overlay.h @@ -105,6 +105,14 @@ typedef struct cfc_overlay_text_config { int r, g, b; /* sRGB цвет 0..255 */ int extra_alpha; /* 0..255 общий множитель прозрачности */ int visible; /* 0/1 — выводить ли */ + /* Опциональный полупрозрачный фон (подложка) под текстом. + * bg_alpha = 0 → без фона (default) + * bg_alpha > 0 → fill rect (atlas_w + 2*bg_pad) × (atlas_h + 2*bg_pad) + * с цветом bg_y/u/v перед blit'ом текста. + * bg_pad чётный, default 8 если bg_alpha>0 и bg_pad==0. */ + int bg_alpha; /* 0..255 (0 = отключено) */ + int bg_y, bg_u, bg_v; /* BT.709 limited (Y=16..235, UV=16..240) */ + int bg_pad; /* px padding вокруг текста */ } cfc_overlay_text_config_t; /* Создать TEXT overlay. Открывает font через FreeType, рендерит строку diff --git a/src/cpp/mqtt_overlay.cpp b/src/cpp/mqtt_overlay.cpp index ba40c0d..6784720 100644 --- a/src/cpp/mqtt_overlay.cpp +++ b/src/cpp/mqtt_overlay.cpp @@ -105,6 +105,9 @@ void MqttOverlayItem::update_text(const std::string& text) tc.r = cfg_.r; tc.g = cfg_.g; tc.b = cfg_.b; tc.extra_alpha = cfg_.alpha; tc.visible = 1; + tc.bg_alpha = cfg_.bg_alpha; + tc.bg_y = cfg_.bg_y; tc.bg_u = cfg_.bg_u; tc.bg_v = cfg_.bg_v; + tc.bg_pad = cfg_.bg_pad; cfc_overlay_update_text(overlay_, &tc); reposition_overlay(); std::fprintf(stderr, "[cfc/mqtt-overlay/%s] '%s'\n", @@ -149,26 +152,36 @@ void MqttOverlayItem::reposition_overlay() tc.r = cfg_.r; tc.g = cfg_.g; tc.b = cfg_.b; tc.extra_alpha = cfg_.alpha; tc.visible = 1; + tc.bg_alpha = cfg_.bg_alpha; + tc.bg_y = cfg_.bg_y; tc.bg_u = cfg_.bg_u; tc.bg_v = cfg_.bg_v; + tc.bg_pad = cfg_.bg_pad; cfc_overlay_update_text(overlay_, &tc); } bool MqttOverlayItem::start() { - /* Persistent text overlay. */ + /* Persistent text overlay — сразу visible=1 с placeholder, чтобы было + * видно (с подложкой) даже без MQTT-сообщения. */ + const std::string ph = cfg_.placeholder.empty() ? std::string("—") : cfg_.placeholder; cfc_overlay_text_config_t tc{}; tc.font_path = cfg_.font_path.c_str(); - tc.text = "—"; + tc.text = ph.c_str(); tc.pixel_size = cfg_.pixel_size; - tc.x = 0; tc.y = 0; + tc.x = cfg_.margin_x; tc.y = cfg_.margin_y; tc.r = cfg_.r; tc.g = cfg_.g; tc.b = cfg_.b; tc.extra_alpha = cfg_.alpha; - tc.visible = 0; + tc.visible = 1; + tc.bg_alpha = cfg_.bg_alpha; + tc.bg_y = cfg_.bg_y; tc.bg_u = cfg_.bg_u; tc.bg_v = cfg_.bg_v; + tc.bg_pad = cfg_.bg_pad; if (cfc_overlay_create_text(&tc, &overlay_) != 0) { std::fprintf(stderr, "[cfc/mqtt-overlay/%s] create_text failed (font '%s')\n", cfg_.id.c_str(), cfg_.font_path.c_str()); return false; } cfc_overlay_set_id(overlay_, cfg_.id.c_str()); + last_text_ = ph; + reposition_overlay(); /* поставить в anchor сразу */ /* MQTT subscriber. */ char cid[64]; @@ -255,6 +268,13 @@ int MqttOverlayManager::load_from_file(const std::string& path, int W, int H) cfg.margin_y = jint(jo, "margin_y", 24); cfg.pixel_size = jint(jo, "pixel_size", 32); cfg.alpha = jint(jo, "alpha", 230); + cfg.bg_alpha = jint(jo, "bg_alpha", 160); + cfg.bg_y = jint(jo, "bg_y", 16); + cfg.bg_u = jint(jo, "bg_u", 128); + cfg.bg_v = jint(jo, "bg_v", 128); + cfg.bg_pad = jint(jo, "bg_pad", 10); + const char* ph = jstr(jo, "placeholder", ""); + if (*ph) cfg.placeholder = ph; const char* fp = jstr(jo, "font_path", ""); if (*fp) cfg.font_path = fp; diff --git a/src/overlay.c b/src/overlay.c index 2127220..52a3d26 100644 --- a/src/overlay.c +++ b/src/overlay.c @@ -537,6 +537,11 @@ int cfc_overlay_update_text(cfc_overlay_t *ov, td->cfg.y = cfg->y; td->cfg.extra_alpha = cfg->extra_alpha ? cfg->extra_alpha : 255; td->cfg.visible = cfg->visible; + td->cfg.bg_alpha = cfg->bg_alpha; + td->cfg.bg_y = cfg->bg_y; + td->cfg.bg_u = cfg->bg_u; + td->cfg.bg_v = cfg->bg_v; + td->cfg.bg_pad = cfg->bg_pad; if (need_rebuild) return text_rebuild_atlas(td); return 0; @@ -563,6 +568,28 @@ static int draw_text(cfc_overlay_t *ov, CUstream stream, int x = t->cfg.x & ~1; int y = t->cfg.y & ~1; + + /* Опциональный фон-подложка (для читаемости текста на любом фоне). */ + if (t->cfg.bg_alpha > 0) { + int pad = t->cfg.bg_pad > 0 ? t->cfg.bg_pad : 8; + pad &= ~1; + int bx = x - pad, by = y - pad; + int bw = t->width + 2 * pad, bh = t->height + 2 * pad; + if (bx < 0) { bw += bx; bx = 0; } + if (by < 0) { bh += by; by = 0; } + if (bx + bw > frame_w) bw = frame_w - bx; + if (by + bh > frame_h) bh = frame_h - by; + bx &= ~1; by &= ~1; bw &= ~1; bh &= ~1; + if (bw > 0 && bh > 0) { + int by_v = t->cfg.bg_y ? t->cfg.bg_y : 16; + int bu_v = t->cfg.bg_u ? t->cfg.bg_u : 128; + int bv_v = t->cfg.bg_v ? t->cfg.bg_v : 128; + cfc_cugrid_fill_nv12(stream, dst_y, pitch_y, dst_uv, pitch_uv, + bx, by, bw, bh, + by_v, bu_v, bv_v, t->cfg.bg_alpha); + } + } + return cfc_cugrid_blit_rgba_nv12( stream, dst_y, pitch_y, dst_uv, pitch_uv,