1use super::{SceneControl, SceneDef, SceneOptions, TEST_SIZE};
10use unlit3d::prelude::*;
11use unlit3d::ui::egui;
12
13const CLEAR_COLOR: wgpu::Color = wgpu::Color {
15 r: 0.02,
16 g: 0.02,
17 b: 0.02,
18 a: 1.0,
19};
20
21pub static SCENE: SceneDef = SceneDef {
23 id: "ui_only",
24 title: "UI only",
25 description: "a rich egui panel, no mesh source and no camera",
26 size: TEST_SIZE,
27 baseline: None,
28 clear: Some(CLEAR_COLOR),
29 frames: 2,
30 step_seconds: None,
31 samples: 1,
32 depth: false,
33 ui: true,
34 reproducible_ui: false,
35 build,
36};
37
38fn build(
40 world: &mut World,
41 _context: RenderContext,
42 _pass: Entity,
43 ui: Option<Entity>,
44 _size: (u32, u32),
45 options: SceneOptions,
46) -> SceneControl {
47 if options.ui {
48 super::spawn_in(
49 world,
50 ui.expect("the UI source was mounted"),
51 bundle![rich_panel()],
52 );
53 }
54
55 SceneControl {
56 advance: Box::new(|_world, _frame, _delta, _size| {}),
60 snapshot: Box::new(|frame| (frame == 1).then(|| "ui_only.webp".to_owned())),
62 }
63}
64
65pub(crate) const WIDGETS: Rect = Rect::new(8.0, 8.0, 112.0, 128.0);
67pub(crate) const PICTURE: Rect = Rect::new(136.0, 8.0, 112.0, 72.0);
68pub(crate) const BAND: Rect = Rect::new(8.0, 136.0, 240.0, 40.0);
69
70pub(crate) const LIGHT_GREEN: egui::Color32 = egui::Color32::from_rgb(96, 255, 96);
72
73pub(crate) fn rich_panel() -> UiPanel {
84 let mut image: Option<egui::TextureHandle> = None;
89 let mut spin = true;
90 let mut blend = 0.5f32;
91
92 UiPanel::new(move |_world, _entity, ui| {
93 let image = image.get_or_insert_with(|| {
94 ui.ctx().load_texture(
95 "unlit3d::test-image",
96 test_image(),
97 egui::TextureOptions::NEAREST,
98 )
99 });
100
101 ui.scope_builder(
104 egui::UiBuilder::new()
105 .max_rect(WIDGETS.egui())
106 .layout(egui::Layout::top_down(egui::Align::Min)),
107 |ui| {
108 ui.heading("unlit3d");
109 ui.label("frame source UI");
110 ui.separator();
111 ui.checkbox(&mut spin, "spin");
112 ui.add(egui::Slider::new(&mut blend, 0.0..=1.0));
113 ui.add(
114 egui::ProgressBar::new(blend)
115 .desired_width(104.0)
116 .text("load"),
117 );
118 },
119 );
120
121 let painter = ui.painter();
122 painter.image(
126 image.id(),
127 PICTURE.egui(),
128 egui::Rect::from_min_max(egui::Pos2::ZERO, egui::pos2(1.0, 1.0)),
129 egui::Color32::WHITE,
130 );
131 painter.line_segment(
132 [
133 egui::pos2(PICTURE.min.x, 86.0),
134 egui::pos2(PICTURE.egui().max.x, 86.0),
135 ],
136 egui::Stroke::new(1.0, egui::Color32::from_gray(120)),
137 );
138 painter.circle_filled(egui::pos2(190.0, 112.0), 15.0, LIGHT_GREEN);
141 painter.circle_stroke(
142 egui::pos2(190.0, 112.0),
143 15.0,
144 egui::Stroke::new(3.0, egui::Color32::WHITE),
145 );
146 painter.rect_stroke(
147 egui::Rect::from_min_size(egui::pos2(212.0, 96.0), egui::Vec2::new(36.0, 32.0)),
148 3.0,
149 egui::Stroke::new(2.0, egui::Color32::from_rgb(255, 0, 0)),
150 egui::StrokeKind::Inside,
151 );
152 painter.rect_filled(
153 BAND.egui(),
154 0.0,
155 egui::Color32::from_rgba_premultiplied(128, 0, 0, 128),
156 );
157 })
158}
159
160pub(crate) fn test_image() -> egui::ColorImage {
163 const SIZE: usize = 8;
164 const QUADRANT: usize = SIZE / 2;
165
166 fn shades(x: usize, y: usize) -> ((u8, u8, u8), (u8, u8, u8)) {
167 match (x / QUADRANT, y / QUADRANT) {
168 (0, 0) => ((255, 96, 96), (160, 0, 0)),
169 (1, 0) => ((96, 255, 96), (0, 160, 0)),
170 (0, 1) => ((96, 96, 255), (0, 0, 160)),
171 _ => ((255, 255, 96), (160, 160, 0)),
172 }
173 }
174
175 let pixels = (0..SIZE)
176 .flat_map(|y| {
177 (0..SIZE).map(move |x| {
178 let (light, dark) = shades(x, y);
179 let (r, g, b) = if (x + y) % 2 == 0 { light } else { dark };
180 egui::Color32::from_rgb(r, g, b)
181 })
182 })
183 .collect();
184 egui::ColorImage::new([SIZE, SIZE], pixels)
185}
186
187#[derive(Clone, Copy)]
189pub(crate) struct Rect {
190 pub(crate) min: egui::Pos2,
191 pub(crate) size: egui::Vec2,
192}
193
194impl Rect {
195 pub(crate) const fn new(x: f32, y: f32, w: f32, h: f32) -> Self {
196 Self {
197 min: egui::Pos2::new(x, y),
198 size: egui::Vec2::new(w, h),
199 }
200 }
201
202 pub(crate) fn egui(self) -> egui::Rect {
203 egui::Rect::from_min_size(self.min, self.size)
204 }
205}