git.lucas.co / cce-ui
GPU-accelerated UI toolkit (Vulkan)
git clone https://git.lucas.co/cce-ui.git

examples/probe/scene.rs (6.4K)

  1 //! The renderer probe's scene: one app drawn by both renderers, natively in
  2 //! the Wayland runner (`probe_native`) and in a browser through the WebGPU
  3 //! renderer (`probe_web`), so the two can be compared pixel for pixel.
  4 //!
  5 //! It reaches every path a frame takes: the root plate and its roll, flat
  6 //! fills, a checker under frosted plates in all three frost recipes (the
  7 //! blur snapshot), raised / flush / flat control plates, fields in each form,
  8 //! recesses, bevels, a sphere, grooves, circles and capped vectors, text in
  9 //! two families at four sizes, and an uploaded image drawn at two sizes.
 10 
 11 use cce_ui::engine::{AppSender, Application, LogicalPosition, LogicalSize, WindowSettings};
 12 use cce_ui::scene::layout::Rect;
 13 use cce_ui::scene::paint::{Cap, ControlPlate, DisplayList, Field, PaintCtx, PlateSpec, PlateStance};
 14 use cce_ui::scene::{Frost, Material};
 15 use cce_ui::widget::{ElementState, KeyEvent, MouseButton, MouseScrollDelta};
 16 
 17 pub const W: u32 = 1280;
 18 pub const H: u32 = 800;
 19 
 20 pub struct ProbeApp {
 21     image: u32,
 22 }
 23 
 24 fn r(x: f32, y: f32, w: f32, h: f32) -> Rect {
 25     Rect { x, y, width: w, height: h }
 26 }
 27 
 28 const SANS: &str = "DejaVu Sans";
 29 const MONO: &str = "DejaVu Sans Mono";
 30 
 31 impl Application for ProbeApp {
 32     type Message = ();
 33 
 34     fn create(_sender: AppSender<()>) -> Self {
 35         cce_ui::scale::set_scale_factor(1.0);
 36         let (iw, ih) = (64u32, 40u32);
 37         let mut px = Vec::with_capacity((iw * ih * 4) as usize);
 38         for y in 0..ih {
 39             for x in 0..iw {
 40                 px.extend([(x * 255 / (iw - 1)) as u8, (y * 255 / (ih - 1)) as u8, 160, 255]);
 41             }
 42         }
 43         ProbeApp { image: cce_ui::draw::upload_rgba(px, iw, ih) }
 44     }
 45 
 46     fn settings(&self) -> WindowSettings {
 47         WindowSettings { title: "probe".into(), app_id: "cce-probe".into(), width: W, height: H, fullscreen: false, min_size: None }
 48     }
 49 
 50     fn load_system_fonts(&self) -> bool {
 51         true
 52     }
 53 
 54     fn display_list_text(&self) -> bool {
 55         true
 56     }
 57 
 58     fn update(&mut self, _: (), _: &mut bool, _: &mut bool) {}
 59     fn tick(&mut self, _: f32, _: &mut bool) {}
 60 
 61     fn display_list(&mut self, size: LogicalSize, scale: f64) -> Option<DisplayList> {
 62         cce_ui::scale::set_scale_factor(scale as f32);
 63         let (w, h) = (size.width, size.height);
 64         let mut pc = PaintCtx::new();
 65         pc.root_plate(w, h);
 66 
 67         // A checker under three frosted plates: unfrosted-compression,
 68         // compressed, and clear (frost_pair's recipes).
 69         for i in 0..16 {
 70             let c = if i % 2 == 0 { [1.0, 1.0, 1.0, 1.0] } else { [0.02, 0.02, 0.03, 1.0] };
 71             pc.quad(r(30.0 + i as f32 * 30.0, 30.0, 30.0, 220.0), c);
 72         }
 73         let tint = [0.0015, 0.0015, 0.0024, 0.25];
 74         for (i, (k, radius)) in [(0.0, Frost::DEFAULT_RADIUS), (0.85, Frost::DEFAULT_RADIUS), (0.0, 0.0)].iter().enumerate() {
 75             let m = Material::opaque(tint).with_frost(Frost::Frosted { compression: *k, refraction: 0.0, radius: *radius });
 76             pc.plate_spec(&PlateSpec {
 77                 rect: r(40.0 + i as f32 * 155.0, 60.0, 140.0, 160.0),
 78                 material: m,
 79                 window_corners: (false, false, false, false),
 80                 depth: 6.0,
 81             });
 82         }
 83 
 84         // A pane plate with the control vocabulary on it.
 85         pc.plate_spec(&PlateSpec {
 86             rect: r(540.0, 30.0, 700.0, 330.0),
 87             material: Material::pane(),
 88             window_corners: (false, false, false, false),
 89             depth: cce_ui::layout::bevel_width(),
 90         });
 91         let face = Some(Material::opaque([0.18, 0.22, 0.32, 1.0]));
 92         pc.control_plate(&ControlPlate::control(r(570.0, 60.0, 140.0, 36.0), 8.0, PlateStance::Raised, face));
 93         pc.control_plate(&ControlPlate::control(r(730.0, 60.0, 140.0, 36.0), 8.0, PlateStance::Raised, None));
 94         pc.control_plate(&ControlPlate::control(r(890.0, 60.0, 140.0, 36.0), 8.0, PlateStance::Flush, None));
 95         pc.control_plate(&ControlPlate::control(r(1050.0, 60.0, 140.0, 36.0), 8.0, PlateStance::Flat, face));
 96         let radii = (8.0, 8.0, 8.0, 8.0);
 97         pc.field(&Field::well(r(570.0, 120.0, 300.0, 34.0), radii, 6.0));
 98         pc.field(&Field::ending_in_run(r(890.0, 120.0, 300.0, 34.0), radii, 6.0, 1150.0));
 99         pc.field(&Field::sliding_run(r(570.0, 180.0, 90.0, 34.0), (17.0, 17.0, 17.0, 17.0), 6.0, 45.0, 0.0));
100         pc.field(&Field::sliding_run(r(680.0, 180.0, 90.0, 34.0), (17.0, 17.0, 17.0, 17.0), 6.0, 45.0, 1.0));
101         pc.recess(r(800.0, 180.0, 120.0, 60.0), (12.0, 12.0, 12.0, 12.0), 8.0);
102         pc.bevel(r(950.0, 180.0, 120.0, 60.0), (12.0, 12.0, 12.0, 12.0), &Material::opaque([0.35, 0.30, 0.42, 1.0]), 8.0);
103         pc.sphere(1140.0, 210.0, 30.0, &Material::opaque([0.55, 0.25, 0.25, 1.0]));
104         let host = r(540.0, 30.0, 700.0, 330.0);
105         pc.groove((570.0, 280.0), (1210.0, 280.0), 4.0, 3.0, host);
106         pc.groove((600.0, 300.0), (760.0, 340.0), 4.0, 3.0, host);
107 
108         // Flat geometry: circles and capped vectors.
109         for (i, cap) in [Cap::Flat, Cap::Round, Cap::Arrow].into_iter().enumerate() {
110             let y = 300.0 + i as f32 * 25.0;
111             pc.vector(820.0, y, 1000.0, y + 10.0, 5.0, [0.9, 0.6, 0.2, 1.0], cap);
112         }
113         pc.circle(1080.0, 320.0, 22.0, [0.2, 0.7, 0.5, 1.0]);
114         pc.circle(1150.0, 320.0, 22.0, [0.2, 0.5, 0.9, 0.6]);
115 
116         // Text, two families at four sizes.
117         let mut y = 400.0;
118         for (i, size) in [11.0, 14.0, 20.0, 28.0].into_iter().enumerate() {
119             let family = if i % 2 == 0 { SANS } else { MONO };
120             pc.text_with(
121                 format!("The quick brown fox jumps over the lazy dog — {size}px {family}"),
122                 40.0,
123                 y,
124                 size,
125                 [230, 230, 236],
126                 Some(family.to_string()),
127                 None,
128             );
129             y += size * 1.8;
130         }
131 
132         // The image, at its size and scaled up.
133         pc.image(self.image, r(40.0, 620.0, 64.0, 40.0), 1.0);
134         pc.image(self.image, r(130.0, 600.0, 256.0, 160.0), 0.85);
135 
136         Some(pc.finish())
137     }
138 
139     fn handle_pointer_move(&mut self, _: LogicalPosition, _: &mut bool) {}
140     fn handle_mouse_input(&mut self, _: MouseButton, _: ElementState, _: LogicalPosition, _: &mut bool) -> Option<()> {
141         None
142     }
143     fn handle_mouse_wheel(&mut self, _: &MouseScrollDelta, _: LogicalPosition, _: &mut bool) {}
144     fn handle_key_input(&mut self, _: &KeyEvent, _: &mut bool) -> Option<()> {
145         None
146     }
147 }