1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
pub use egui_wgpu as renderer;
pub use egui_winit as platform;

pub use platform::egui; // same as renderer::egui
pub use platform::winit;
pub use renderer::wgpu;

use platform::{Platform, PlatformDescriptor};
use renderer::{Renderer, RendererDescriptor};

use winit::window;

/// Egui backend with winit platform and wgpu renderer
pub struct Backend {
    platform: Platform,
    renderer: Renderer,
}

impl Backend {
    pub fn new(desc: BackendDescriptor) -> Self {
        let BackendDescriptor {
            window,
            device,
            rt_format,
            style,
            font_definitions,
        } = desc;

        let platform = Platform::new(PlatformDescriptor {
            window,
            style,
            font_definitions,
        });

        let renderer = Renderer::new(RendererDescriptor { device, rt_format });

        Self { platform, renderer }
    }

    pub fn handle_event<T>(&mut self, event: &winit::event::Event<T>) {
        self.platform.handle_event(event);
    }

    // TODO: is this better than Self::render() taking a closure?
    // It would be interesting if you could continue building the ui after ending (pausing) a frame.
    //pub fn begin_frame(&mut self) {

    //}

    //pub fn end_frame(&mut self) {
    //}

    pub fn render<F>(&mut self, desc: RenderDescriptor, build_ui: F)
    where
        F: FnOnce(egui::CtxRef),
    {
        let RenderDescriptor {
            textures_to_update,
            window,
            device,
            queue,
            encoder,
            render_target,
            load_operation,
        } = desc;

        let screen_descriptor = {
            let size = window.inner_size();
            renderer::ScreenDescriptor {
                physical_width: size.width,
                physical_height: size.height,
                scale_factor: window.scale_factor() as f32,
            }
        };

        self.platform.begin_frame();
        build_ui(self.ctx());
        let (shapes, needs_redraw) = self.platform.end_frame(window);

        let _ = needs_redraw; // TODO use

        let meshes = &self.ctx().tessellate(shapes);

        // this is a mess.
        // TODO: use iterators in the first place instead of slices
        let textures_to_update = textures_to_update.iter().copied();
        let egui_texture = self.ctx().texture();
        let egui_texture = std::iter::once(egui_texture.as_ref());
        let textures_to_update: Vec<&egui::Texture> =
            textures_to_update.chain(egui_texture).collect();

        self.renderer.render(renderer::RenderDescriptor {
            meshes,
            textures_to_update: &textures_to_update,
            device,
            queue,
            encoder,
            render_target,
            screen_descriptor,
            load_operation,
        });
    }

    pub fn ctx(&self) -> egui::CtxRef {
        self.platform.ctx()
    }

    pub fn platform(&self) -> &Platform {
        &self.platform
    }

    pub fn platform_mut(&mut self) -> &mut Platform {
        &mut self.platform
    }

    pub fn renderer(&self) -> &Renderer {
        &self.renderer
    }

    pub fn renderer_mut(&mut self) -> &mut Renderer {
        &mut self.renderer
    }
}

/// Backend creation descriptor
pub struct BackendDescriptor<'a> {
    /// Winit window
    pub window: &'a window::Window,
    /// Wgpu device
    pub device: &'a wgpu::Device,
    /// Render target format
    pub rt_format: wgpu::TextureFormat,
    /// Egui style configuration.
    pub style: egui::Style,
    /// Egui font configuration.
    pub font_definitions: egui::FontDefinitions,
}

pub struct RenderDescriptor<'a> {
    // TODO: turn into iterator
    pub textures_to_update: &'a [&'a egui::Texture],
    pub window: &'a window::Window,
    pub device: &'a wgpu::Device,
    pub queue: &'a wgpu::Queue,
    pub encoder: &'a mut wgpu::CommandEncoder,
    pub render_target: &'a wgpu::TextureView,
    pub load_operation: wgpu::LoadOp<wgpu::Color>,
}