epaint/shapes/paint_callback.rs
1use std::{any::Any, sync::Arc};
2
3use crate::*;
4
5/// Information passed along with [`PaintCallback`] ([`Shape::Callback`]).
6pub struct PaintCallbackInfo {
7 /// Viewport in points.
8 ///
9 /// This specifies where on the screen to paint, and the borders of this
10 /// Rect is the [-1, +1] of the Normalized Device Coordinates.
11 ///
12 /// Note than only a portion of this may be visible due to [`Self::clip_rect`].
13 ///
14 /// This comes from [`PaintCallback::rect`].
15 pub viewport: Rect,
16
17 /// Clip rectangle in points.
18 pub clip_rect: Rect,
19
20 /// Pixels per point.
21 pub pixels_per_point: f32,
22
23 /// Full size of the screen, in pixels.
24 pub screen_size_px: [u32; 2],
25}
26
27#[test]
28fn test_viewport_rounding() {
29 for i in 0..=10_000 {
30 // Two adjacent viewports should never overlap:
31 let x = i as f32 / 97.0;
32 let left = Rect::from_min_max(pos2(0.0, 0.0), pos2(100.0, 100.0)).with_max_x(x);
33 let right = Rect::from_min_max(pos2(0.0, 0.0), pos2(100.0, 100.0)).with_min_x(x);
34
35 for pixels_per_point in [0.618, 1.0, std::f32::consts::PI] {
36 let left = ViewportInPixels::from_points(&left, pixels_per_point, [100, 100]);
37 let right = ViewportInPixels::from_points(&right, pixels_per_point, [100, 100]);
38 assert_eq!(left.left_px + left.width_px, right.left_px);
39 }
40 }
41}
42
43impl PaintCallbackInfo {
44 /// The viewport rectangle. This is what you would use in e.g. `glViewport`.
45 pub fn viewport_in_pixels(&self) -> ViewportInPixels {
46 ViewportInPixels::from_points(&self.viewport, self.pixels_per_point, self.screen_size_px)
47 }
48
49 /// The "scissor" or "clip" rectangle. This is what you would use in e.g. `glScissor`.
50 pub fn clip_rect_in_pixels(&self) -> ViewportInPixels {
51 ViewportInPixels::from_points(&self.clip_rect, self.pixels_per_point, self.screen_size_px)
52 }
53}
54
55/// If you want to paint some 3D shapes inside an egui region, you can use this.
56///
57/// This is advanced usage, and is backend specific.
58#[derive(Clone)]
59pub struct PaintCallback {
60 /// Where to paint.
61 ///
62 /// This will become [`PaintCallbackInfo::viewport`].
63 pub rect: Rect,
64
65 /// Paint something custom (e.g. 3D stuff).
66 ///
67 /// The concrete value of `callback` depends on the rendering backend used. For instance, the
68 /// `glow` backend requires that callback be an `egui_glow::CallbackFn` while the `wgpu`
69 /// backend requires a `egui_wgpu::Callback`.
70 ///
71 /// If the type cannot be downcast to the type expected by the current backend the callback
72 /// will not be drawn.
73 ///
74 /// The rendering backend is responsible for first setting the active viewport to
75 /// [`Self::rect`].
76 ///
77 /// The rendering backend is also responsible for restoring any state, such as the bound shader
78 /// program, vertex array, etc.
79 ///
80 /// Shape has to be clone, therefore this has to be an `Arc` instead of a `Box`.
81 pub callback: Arc<dyn Any + Send + Sync>,
82}
83
84impl std::fmt::Debug for PaintCallback {
85 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
86 f.debug_struct("CustomShape")
87 .field("rect", &self.rect)
88 .finish_non_exhaustive()
89 }
90}
91
92impl std::cmp::PartialEq for PaintCallback {
93 fn eq(&self, other: &Self) -> bool {
94 self.rect.eq(&other.rect) && Arc::ptr_eq(&self.callback, &other.callback)
95 }
96}
97
98impl From<PaintCallback> for Shape {
99 #[inline(always)]
100 fn from(shape: PaintCallback) -> Self {
101 Self::Callback(shape)
102 }
103}