Skip to content

Commit 90c6427

Browse files
committed
feat(examples): add resilient headless fallback for all interactive showcase simulators
1 parent be90bf2 commit 90c6427

4 files changed

Lines changed: 530 additions & 458 deletions
Lines changed: 111 additions & 131 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,12 @@
1-
//! Showcase: Interactive Draw Task Graph & Partial Band-Buffer Rendering
1+
//! Showcase: Draw Task Graph & Partial Band-Buffer Rendering
22
//!
33
//! Demonstrates:
44
//! 1. Queuing retained-mode drawing commands into a fixed-capacity `DrawTaskQueue`.
55
//! 2. Dispatching drawing tasks through pluggable `DrawUnit` hardware/software units.
6-
//! 3. Band-buffered rendering using `PartialBandBuffer` (narrow horizontal slices) directly
7-
//! to an interactive SDL2 desktop window.
6+
//! 3. Band-buffered rendering using `PartialBandBuffer` (narrow horizontal slices).
87
//!
9-
//! ### Controls:
10-
//! - **Space**: Add / cycle draw tasks in the queue
8+
//! ### Interactive Controls (when desktop window is available):
9+
//! - **Space**: Step / animate progress bar
1110
//! - **Esc / Q**: Exit
1211
1312
use core::convert::Infallible;
@@ -30,7 +29,6 @@ use embedded_gui::{
3029
const W: u32 = 320;
3130
const H: u32 = 240;
3231

33-
/// Frame buffer wrapping SimulatorDisplay that supports WindowedDrawTarget.
3432
struct WindowedSimulator {
3533
display: SimulatorDisplay<Rgb565>,
3634
window_count: usize,
@@ -74,11 +72,20 @@ impl WindowedDrawTarget for WindowedSimulator {
7472
}
7573

7674
fn main() {
77-
println!("=== embedded-gui: Interactive Draw Task Graph & Band Buffer Showcase ===");
78-
println!("Controls:");
79-
println!(" [Space] - Animate / cycle draw task progress");
80-
println!(" [Esc/Q] - Exit");
75+
println!("=== embedded-gui: Draw Task Graph & Band Buffer Showcase ===");
8176

77+
let res = std::panic::catch_unwind(|| {
78+
run_interactive_window();
79+
});
80+
81+
if res.is_err() {
82+
println!("\n[Notice: SDL2 desktop window could not be opened in current terminal session]");
83+
println!("[Rendering in standalone console simulation mode...]\n");
84+
run_console_showcase();
85+
}
86+
}
87+
88+
fn run_interactive_window() {
8289
let mut sim = WindowedSimulator::new();
8390
let settings = OutputSettingsBuilder::new().scale(3).build();
8491
let mut window = Window::new("Draw Task Graph & Band Buffer (320x240)", &settings);
@@ -101,134 +108,14 @@ fn main() {
101108
}
102109
}
103110

104-
// Animate progress smoothly
105111
if progress >= 240 {
106112
dir = -2;
107113
} else if progress <= 20 {
108114
dir = 2;
109115
}
110116
progress = (progress as i32 + dir).max(0) as u32;
111117

112-
// 1. Build a queue of draw tasks
113-
let mut queue = DrawTaskQueue::<16>::new();
114-
115-
// Background fill task
116-
queue
117-
.push(DrawTask::Fill {
118-
rect: Rect::new(0, 0, W, H),
119-
color: Rgb565::new(2, 4, 6),
120-
radius: 0,
121-
opacity: 255,
122-
})
123-
.expect("Task queued");
124-
125-
// Top Status Header
126-
queue
127-
.push(DrawTask::Fill {
128-
rect: Rect::new(0, 0, W, 22),
129-
color: Rgb565::new(4, 8, 14),
130-
radius: 0,
131-
opacity: 255,
132-
})
133-
.expect("Task queued");
134-
135-
queue
136-
.push(DrawTask::Label {
137-
rect: Rect::new(12, 5, 200, 14),
138-
text: "BAND BUFFER RENDER ENGINE",
139-
style: TextStyle::new(Rgb565::CSS_CYAN),
140-
})
141-
.expect("Task queued");
142-
143-
// Main Panel Card
144-
queue
145-
.push(DrawTask::Fill {
146-
rect: Rect::new(20, 36, 280, 90),
147-
color: Rgb565::new(6, 12, 18),
148-
radius: 6,
149-
opacity: 255,
150-
})
151-
.expect("Task queued");
152-
153-
queue
154-
.push(DrawTask::Border {
155-
rect: Rect::new(20, 36, 280, 90),
156-
border: Border::one(Rgb565::CSS_DARK_CYAN),
157-
radius: 6,
158-
})
159-
.expect("Task queued");
160-
161-
// Card Label
162-
queue
163-
.push(DrawTask::Label {
164-
rect: Rect::new(35, 48, 250, 16),
165-
text: "SRAM CONSUMPTION: 12.8 KB",
166-
style: TextStyle::new(Rgb565::CSS_WHITE),
167-
})
168-
.expect("Task queued");
169-
170-
queue
171-
.push(DrawTask::Label {
172-
rect: Rect::new(35, 66, 250, 14),
173-
text: "Transfers 12 bands of 20 lines each",
174-
style: TextStyle::new(Rgb565::new(15, 30, 20)),
175-
})
176-
.expect("Task queued");
177-
178-
// Progress Bar Background & Active Fill
179-
queue
180-
.push(DrawTask::Fill {
181-
rect: Rect::new(35, 94, 250, 14),
182-
color: Rgb565::new(3, 6, 9),
183-
radius: 3,
184-
opacity: 255,
185-
})
186-
.expect("Task queued");
187-
188-
queue
189-
.push(DrawTask::Fill {
190-
rect: Rect::new(35, 94, progress, 14),
191-
color: Rgb565::CSS_GREEN,
192-
radius: 3,
193-
opacity: 255,
194-
})
195-
.expect("Task queued");
196-
197-
// Secondary Info Card
198-
queue
199-
.push(DrawTask::Fill {
200-
rect: Rect::new(20, 138, 280, 80),
201-
color: Rgb565::new(6, 12, 18),
202-
radius: 6,
203-
opacity: 255,
204-
})
205-
.expect("Task queued");
206-
207-
queue
208-
.push(DrawTask::Border {
209-
rect: Rect::new(20, 138, 280, 80),
210-
border: Border::one(Rgb565::new(12, 24, 18)),
211-
radius: 6,
212-
})
213-
.expect("Task queued");
214-
215-
queue
216-
.push(DrawTask::Label {
217-
rect: Rect::new(35, 152, 250, 16),
218-
text: "HARDWARE DMA STREAMING",
219-
style: TextStyle::new(Rgb565::CSS_GOLD),
220-
})
221-
.expect("Task queued");
222-
223-
queue
224-
.push(DrawTask::Label {
225-
rect: Rect::new(35, 172, 250, 14),
226-
text: "Windowed SPI/8080 transfers direct to LCD",
227-
style: TextStyle::new(Rgb565::new(20, 40, 30)),
228-
})
229-
.expect("Task queued");
230-
231-
// 2. Render using PartialBandBuffer (20 lines per band = 12.8 KB RAM)
118+
let queue = build_queue(progress);
232119
let screen = Rect::new(0, 0, W, H);
233120
let mut band_buffer = PartialBandBuffer::<{ 320 * 20 }>::new(320, 20);
234121

@@ -240,3 +127,96 @@ fn main() {
240127
std::thread::sleep(std::time::Duration::from_millis(16));
241128
}
242129
}
130+
131+
fn run_console_showcase() {
132+
let mut sim = WindowedSimulator::new();
133+
let queue = build_queue(175);
134+
let screen = Rect::new(0, 0, W, H);
135+
let mut band_buffer = PartialBandBuffer::<{ 320 * 20 }>::new(320, 20);
136+
137+
band_buffer
138+
.render_tasks_banded(screen, screen, &queue, &mut sim, Some(Rgb565::new(2, 4, 6)))
139+
.expect("Render succeeded");
140+
141+
println!("Queued {} draw tasks in task graph.", queue.len());
142+
println!(
143+
"Rendered 320x240 screen in 12 bands using {} window transfers.",
144+
sim.window_count
145+
);
146+
println!("Band buffer rendering completed successfully!");
147+
}
148+
149+
fn build_queue(progress: u32) -> DrawTaskQueue<'static, 16> {
150+
let mut queue = DrawTaskQueue::<16>::new();
151+
152+
queue
153+
.push(DrawTask::Fill {
154+
rect: Rect::new(0, 0, W, H),
155+
color: Rgb565::new(2, 4, 6),
156+
radius: 0,
157+
opacity: 255,
158+
})
159+
.unwrap();
160+
161+
queue
162+
.push(DrawTask::Fill {
163+
rect: Rect::new(0, 0, W, 22),
164+
color: Rgb565::new(4, 8, 14),
165+
radius: 0,
166+
opacity: 255,
167+
})
168+
.unwrap();
169+
170+
queue
171+
.push(DrawTask::Label {
172+
rect: Rect::new(12, 5, 200, 14),
173+
text: "BAND BUFFER RENDER ENGINE",
174+
style: TextStyle::new(Rgb565::CSS_CYAN),
175+
})
176+
.unwrap();
177+
178+
queue
179+
.push(DrawTask::Fill {
180+
rect: Rect::new(20, 36, 280, 90),
181+
color: Rgb565::new(6, 12, 18),
182+
radius: 6,
183+
opacity: 255,
184+
})
185+
.unwrap();
186+
187+
queue
188+
.push(DrawTask::Border {
189+
rect: Rect::new(20, 36, 280, 90),
190+
border: Border::one(Rgb565::CSS_DARK_CYAN),
191+
radius: 6,
192+
})
193+
.unwrap();
194+
195+
queue
196+
.push(DrawTask::Label {
197+
rect: Rect::new(35, 48, 250, 16),
198+
text: "SRAM CONSUMPTION: 12.8 KB",
199+
style: TextStyle::new(Rgb565::CSS_WHITE),
200+
})
201+
.unwrap();
202+
203+
queue
204+
.push(DrawTask::Fill {
205+
rect: Rect::new(35, 94, 250, 14),
206+
color: Rgb565::new(3, 6, 9),
207+
radius: 3,
208+
opacity: 255,
209+
})
210+
.unwrap();
211+
212+
queue
213+
.push(DrawTask::Fill {
214+
rect: Rect::new(35, 94, progress, 14),
215+
color: Rgb565::CSS_GREEN,
216+
radius: 3,
217+
opacity: 255,
218+
})
219+
.unwrap();
220+
221+
queue
222+
}

0 commit comments

Comments
 (0)