From a8434b76d4dd7b66df158a8a382782c88325214d Mon Sep 17 00:00:00 2001 From: Jannik Beyerstedt Date: Mon, 7 Sep 2026 12:34:58 +0200 Subject: [PATCH] WIP Add graphics --- Cargo.lock | 11 ++++ Cargo.toml | 3 +- Readme.md | 13 ++++ ...innbild_Radfahrer_StVO_1992-25px-black.tga | Bin 0 -> 1068 bytes ...innbild_Radfahrer_StVO_1992-25px-white.tga | Bin 0 -> 1068 bytes src/screen.rs | 58 ++++++++++++++---- 6 files changed, 72 insertions(+), 13 deletions(-) create mode 100644 graphics/Sinnbild_Radfahrer_StVO_1992-25px-black.tga create mode 100644 graphics/Sinnbild_Radfahrer_StVO_1992-25px-white.tga diff --git a/Cargo.lock b/Cargo.lock index 4d9cb80..72f63c0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1216,6 +1216,7 @@ dependencies = [ "prost", "prost-build", "static_cell", + "tinytga", "trouble-host", "ublox", ] @@ -2529,6 +2530,16 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "tinytga" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "477839bd612acb4d0551915eaf6eef8cc1b3a9dd58e18e9c2b746c78614a25d5" +dependencies = [ + "embedded-graphics", + "nom", +] + [[package]] name = "toml_datetime" version = "1.1.1+spec-1.1.0" diff --git a/Cargo.toml b/Cargo.toml index 6dc5d8e..eaa2c22 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -53,7 +53,7 @@ spat = ["c-its-parser/spatem", "c-its-parser/mapem"] # enable some debug printing (without enabling debug logging of the ESP RTOS) spat_debug = [] # enable ST7789 based display -screen = ["dep:mipidsi", "dep:embedded-graphics", "dep:embedded-hal-bus", "dep:profont"] +screen = ["dep:mipidsi", "dep:embedded-graphics", "dep:embedded-hal-bus", "dep:profont", "dep:tinytga"] # enable I/O via UART uart = ["_uart", "_gnss"] # enable I/O via BLE @@ -123,6 +123,7 @@ mipidsi = { version = "0.10.0", optional = true } num-traits = { version = "0.2.19", default-features = false, features = ["libm"] } profont = { version = "0.7.0", optional = true } prost = { version = "0.14", default-features = false, features = ["derive"] } +tinytga = { version = "0.5.0", optional = true } ublox = { version = "0.10", optional = true, default-features = false, features = ["alloc", "ubx_proto27"] } [dev-dependencies] diff --git a/Readme.md b/Readme.md index 97dfd2b..2b8ed56 100644 --- a/Readme.md +++ b/Readme.md @@ -119,3 +119,16 @@ The unit tests in this project are meant to be run on the host: ``` cargo test --target host-tuple --bin test --no-default-features -F std,spat ``` + +## Tips and Tricks + +### Create TGA Assets + +Images are loaded as TGA assets, but shall not have an alpha channel. +You can convert them using [ImageMagick](https://imagemagick.org) like this: +```shell +# resize to 25px height, adding a black background to the white symbol and vice versa +magick Sinnbild_Radfahrer_StVO_1992-200px-white.png -resize x25 -background black -alpha background -flatten -alpha off -verbose Sinnbild_Radfahrer_StVO_1992-25px-white.tga +magick Sinnbild_Radfahrer_StVO_1992-200px-black.png -resize x25 -background white -alpha background -flatten -alpha off -verbose Sinnbild_Radfahrer_StVO_1992-25px-black.tga +``` + diff --git a/graphics/Sinnbild_Radfahrer_StVO_1992-25px-black.tga b/graphics/Sinnbild_Radfahrer_StVO_1992-25px-black.tga new file mode 100644 index 0000000000000000000000000000000000000000..e458e96a321189d730c6f40f80521c7825955033 GIT binary patch literal 1068 zcmZQzU}k^;Ee1&j4u${7;LF~5Q|5g@7Qw;(mdDG>t9c(J`|soX4<9~!`1}vV!Ni+5 z6ZRfC^8+ODrNYk0$VeyjBZz~6|Hew(feXGmJXM{=x8^fk0GV-5*5T317cZVafBx** zv*)jFXj|fP@(N}?RTULwWo0ELB}GL=IR+bCD$^K@Vxpp=qN8JCVq)VW1R2=ZBU_1J zztCndy7K=Y2!I67i|PpZgMA0$q2QgIX8bny;6klTi&MA{!nsh!pKD9nI{Y|x%wYF; z3Ke>9rt$JHpZ~<1wE8V?p<@64-$)Z}8YVP}^L?oCpc*OzvYRb(k5vE?nPNA<5nQ2c-0>rofDE|NpnJtywCj zd^m?O|J(on{~s#4UNYqGvsQZW|Ns9}rkqRv|Ns9hmUZ_3|NlSRsz3j~j5GLY7*ox! z|Nj>-Pbp%W_+erLxt;P3pZ-7B z)qMd{+RZrk|Nm)>OF--%=GFiI|KGse@&B40$E>qLnH!jU{{R2q%{&(*dr2_q|NnBX zlmGw!{}Z6_=>Px!mjyEZ|354*=)~Gz$JBe};*||T4j>=CRCWLHzm)6L|NsC0O`QTt zidO{E{{R2KO@V=dmxF;vKtND{ffr=Zb7jw;|0gr81ep)PTUlB_j7u{oPRM4l?(Xbp zYn=rO;8Q%A|No!hjrt9e1>t|`9D6}D2tQXdeFvh!xC&(4_YltIVBY`#|2Oe^Ad+q) zLj}x;UBXr%lg}tfEC&ny-5@7<7^dm}|Cg?;m9IhEU+WY^cYzrHw<>T(uReQjT_TV4 z8n6JAxarDZ+O~P;oDfcFm{-n*@w4*rv+@QUhpK^6FB{d^SlL-bB0-@85&M3yIU&Ab T?^g&9iM+qExpu~xpI{LHdJFsY literal 0 HcmV?d00001 diff --git a/graphics/Sinnbild_Radfahrer_StVO_1992-25px-white.tga b/graphics/Sinnbild_Radfahrer_StVO_1992-25px-white.tga new file mode 100644 index 0000000000000000000000000000000000000000..e3005bd0be1f999338fe24ecfaa135ea45376306 GIT binary patch literal 1068 zcmZQzU}k^;Ee1&j4h0wwOmjOWW+(E4nfM9LiJv}wx(3$F$S1(h&(F`ph+T*8xA{)i z#_S+T?)HOc&z`-!iVwuWz)XvtE5ijvZL)6s-qg$k7eHnxKH4uUCN3@^At5O#DIuzU z-OzCckbN1d-vYGdk_B~#-(!R|FesiE?v50$>PO}7cE@=?*ESfWGfMD z@hkt&YBMl`07%f_)#bMvz`g_VP_Wy#lOGN%!iB2-#?1a=2j@Z=%$m`aN8*d{rU6%-=+HHzgG)Ggx!90GZ^0g|NFz+AHR+V zGC>4wul(McW>@s{;rE+9&41=W0(;sQOS8*={%_USaBP3}r3jn|w648R=VV~0{uvzg z@{Y~qe-k(v7#QU4?b1E>q43CEc?Jds(^KD~7#J8>7yU|MU|`@mbVGt6^4l7zm4BOA z85rXKWcU8fV@Up62C~=S{#6+U2BY_DL1AI?aTWsu^TMxI5_^A_GO=xZ==NYgFN4IT zOX47xR|DR$828NP9Ng!F>cXJsSI=-4Q zFfcH$zc0(cz@YPfIs=2vgLiv>6*T@W($>@Vf4d*#L$O;s*crOMnldmjFlJ?glA`we znG6gJp7;O%|MdO;=lAd5z5o9SWRS$2ZEOrVf5SlLL$KHHY7j#=EiZq{?;|B;<&{;b zpa3@gJdJ_D{L@kvkSqu@&iL*GqCr^V<|#oC4aTh?<2Y7-ivaT&7#Ms%ZAT>Cy8rDk zBV6Ac1(|Go|9J#hh{^xqGaHyD1_rTRzuH7VT-Lz*uUtV42Cw_ymV_7?2G0BZBp56J zCDeBPKUL}Dmc07g6PQn)&app;nM&7Z%1{C>R*6gm(w4!fH93+kP? RAUq^eA*`k;-Ixt50sx7?8vFnN literal 0 HcmV?d00001 diff --git a/src/screen.rs b/src/screen.rs index d860e6d..625c574 100644 --- a/src/screen.rs +++ b/src/screen.rs @@ -23,6 +23,10 @@ where prev_state: ScreenState, hb_state: bool, gnss_hb_state: bool, + + // assets + #[cfg(feature = "spat")] + bike_image: tinytga::Tga<'static, pixelcolor::Rgb565>, } #[derive(Debug, Default, PartialEq, Eq)] @@ -94,12 +98,19 @@ where const BIG_HEIGHT_THLD: u16 = 172; pub fn new(target: D, display_size: DisplaySize) -> Self { + #[cfg(feature = "spat")] + let data = include_bytes!("../graphics/Sinnbild_Radfahrer_StVO_1992-25px-white.tga"); + #[cfg(feature = "spat")] + let bike_image = tinytga::Tga::from_slice(data).expect("Failed to parse TGA image"); + Self { target, size: display_size, prev_state: ScreenState::Uninitialized, hb_state: false, gnss_hb_state: false, + #[cfg(feature = "spat")] + bike_image, } } @@ -356,22 +367,38 @@ where .draw(&mut self.target)?; // mark bike lanes which are not a vehicle lane, too - let lane_type_symbol = if sig.usages.contains(&applogic::v2x::map::UsageType::Vehicle) { - " " + let lane_symbol_y_pos = 75; + if sig.usages.contains(&applogic::v2x::map::UsageType::Vehicle) { + // clear area + primitives::Rectangle::new( + geometry::Point::new( + centerline - (45 / 2), + lane_symbol_y_pos + self.size.offset_top, + ), // TODO: check correct position + geometry::Size::new(45, 25), + ) + .into_styled(Self::BK_STYLE) + .draw(&mut self.target)?; } else if sig.usages.contains(&applogic::v2x::map::UsageType::Bike) { - "B" // TODO: rather do a bike symbol? + // bike symbol (45x25px) + embedded_graphics::image::Image::new( + &self.bike_image, + geometry::Point::new( + centerline - (45 / 2) + 2, + lane_symbol_y_pos + self.size.offset_top, + ), + ) + .draw(&mut self.target)?; } else { - "?" + text::Text::with_alignment( + "?", + geometry::Point::new(centerline, lane_symbol_y_pos + 24 + self.size.offset_top), + Self::DEFAULT_TEXT_STYLE, + text::Alignment::Center, + ) + .draw(&mut self.target)?; }; - text::Text::with_alignment( - &lane_type_symbol, - geometry::Point::new(centerline, 100 + self.size.offset_top), - Self::DEFAULT_TEXT_STYLE, - text::Alignment::Center, - ) - .draw(&mut self.target)?; - // draw maneuver text::Text::with_alignment( &maneuver_to_str(sig.maneuver), @@ -449,6 +476,13 @@ where // draw welcome text let centerline = i32::from(self.size.width) / 2; + + embedded_graphics::image::Image::new( + &self.bike_image, + geometry::Point::new(centerline - (45 / 2) + 2, 75 + self.size.offset_top), + ) + .draw(&mut self.target)?; + text::Text::with_alignment( "C-ITS Signal Phase\nWaiting for GNSS...", geometry::Point::new(centerline, 130 + self.size.offset_top),