diff --git a/Cargo.toml b/Cargo.toml index 8d9b730..b01ba3a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -18,8 +18,8 @@ include = ["../LICENSE-APACHE", "../LICENSE-MIT", "**/*.rs", "Cargo.toml"] [dependencies] bytemuck = "1.9" -egui = { version = "0.22.0", features = ["bytemuck"] } -miniquad = { version = "0.3.12" } +egui = { version = "0.25", features = ["bytemuck"] } +miniquad = { version = "=0.4.0" } quad-url = "0.1" [target.'cfg(target_arch = "wasm32")'.dependencies] @@ -31,7 +31,7 @@ quad-rand = "0.2.1" copypasta = "0.8.1" [dev-dependencies] -egui_demo_lib = { version = "0.22.0", default-features = false } +egui_demo_lib = { version = "0.25", default-features = false } glam = "0.22.0" [profile.release] diff --git a/examples/demo.rs b/examples/demo.rs index 37cdbcb..a15cb82 100644 --- a/examples/demo.rs +++ b/examples/demo.rs @@ -5,37 +5,54 @@ struct Stage { show_egui_demo_windows: bool, egui_demo_windows: egui_demo_lib::DemoWindows, color_test: egui_demo_lib::ColorTest, - pixels_per_point: f32, + prev_egui_zoom_factor: f32, + zoom_factor: f32, + mq_ctx: Box, } impl Stage { - fn new(ctx: &mut mq::Context) -> Self { + fn new() -> Self { + let mut mq_ctx = mq::window::new_rendering_backend(); + Self { - egui_mq: egui_mq::EguiMq::new(ctx), + egui_mq: egui_mq::EguiMq::new(&mut *mq_ctx), show_egui_demo_windows: true, egui_demo_windows: Default::default(), color_test: Default::default(), - pixels_per_point: ctx.dpi_scale(), + prev_egui_zoom_factor: 1.0, + zoom_factor: 1.0, + mq_ctx, } } } impl mq::EventHandler for Stage { - fn update(&mut self, _ctx: &mut mq::Context) {} + fn update(&mut self) {} - fn draw(&mut self, mq_ctx: &mut mq::Context) { - mq_ctx.clear(Some((1., 1., 1., 1.)), None, None); - mq_ctx.begin_default_pass(mq::PassAction::clear_color(0.0, 0.0, 0.0, 1.0)); - mq_ctx.end_render_pass(); + fn draw(&mut self) { + self.mq_ctx.clear(Some((1., 1., 1., 1.)), None, None); + self.mq_ctx + .begin_default_pass(mq::PassAction::clear_color(0.0, 0.0, 0.0, 1.0)); + self.mq_ctx.end_render_pass(); - let dpi_scale = mq_ctx.dpi_scale(); + let dpi_scale = mq::window::dpi_scale(); // Run the UI code: - self.egui_mq.run(mq_ctx, |_mq_ctx, egui_ctx| { + self.egui_mq.run(&mut *self.mq_ctx, |_mq_ctx, egui_ctx| { if self.show_egui_demo_windows { self.egui_demo_windows.ui(egui_ctx); } + // zoom factor could have been changed by the user in egui using Ctrl/Cmd and -/+/0, + // but it could also be in the middle of being changed by us using the slider. So we + // only allow egui's zoom to override our zoom if the egui zoom is different from what + // we saw last time (meaning the user has changed it). + let curr_egui_zoom = egui_ctx.zoom_factor(); + if self.prev_egui_zoom_factor != curr_egui_zoom { + self.zoom_factor = curr_egui_zoom; + } + self.prev_egui_zoom_factor = curr_egui_zoom; + egui::Window::new("egui ❤ miniquad").show(egui_ctx, |ui| { egui::widgets::global_dark_light_mode_buttons(ui); ui.checkbox(&mut self.show_egui_demo_windows, "Show egui demo windows"); @@ -44,13 +61,24 @@ impl mq::EventHandler for Stage { ui.label("Physical pixels per each logical 'point':"); ui.label(format!("native: {:.2}", dpi_scale)); ui.label(format!("egui: {:.2}", ui.ctx().pixels_per_point())); + ui.label("Current zoom factor:"); ui.add( - egui::Slider::new(&mut self.pixels_per_point, 0.75..=3.0).logarithmic(true), + egui::Slider::new(&mut self.zoom_factor, 0.75..=3.0).logarithmic(true), ) - .on_hover_text("Physical pixels per logical point"); + .on_hover_text("Override egui zoom factor manually (changes effective pixels per point)"); if ui.button("Reset").clicked() { - self.pixels_per_point = dpi_scale; + self.zoom_factor = 1.0; } + + ui.label("By default, egui allows zooming with\nCtrl/Cmd and +/-/0"); + // Creating a checkbox that directly mutates the egui context's options causes a + // freeze so we copy the state out, possibly mutate it with the checkbox, and + // then copy it back in. + let mut zoom_with_keyboard = egui_ctx.options(|o| o.zoom_with_keyboard); + ui.checkbox(&mut zoom_with_keyboard, "Allow egui zoom with keyboard"); + egui_ctx.options_mut(|o| + o.zoom_with_keyboard = zoom_with_keyboard + ); }); #[cfg(not(target_arch = "wasm32"))] @@ -61,9 +89,9 @@ impl mq::EventHandler for Stage { } }); - // Don't change scale while dragging the slider + // Don't change zoom while dragging the slider if !egui_ctx.is_using_pointer() { - egui_ctx.set_pixels_per_point(self.pixels_per_point); + egui_ctx.set_zoom_factor(self.zoom_factor); } egui::Window::new("Color Test").show(egui_ctx, |ui| { @@ -77,62 +105,38 @@ impl mq::EventHandler for Stage { // Draw things behind egui here - self.egui_mq.draw(mq_ctx); + self.egui_mq.draw(&mut *self.mq_ctx); // Draw things in front of egui here - mq_ctx.commit_frame(); + self.mq_ctx.commit_frame(); } - fn mouse_motion_event(&mut self, _: &mut mq::Context, x: f32, y: f32) { + fn mouse_motion_event(&mut self, x: f32, y: f32) { self.egui_mq.mouse_motion_event(x, y); } - fn mouse_wheel_event(&mut self, _: &mut mq::Context, dx: f32, dy: f32) { + fn mouse_wheel_event(&mut self, dx: f32, dy: f32) { self.egui_mq.mouse_wheel_event(dx, dy); } - fn mouse_button_down_event( - &mut self, - ctx: &mut mq::Context, - mb: mq::MouseButton, - x: f32, - y: f32, - ) { - self.egui_mq.mouse_button_down_event(ctx, mb, x, y); + fn mouse_button_down_event(&mut self, mb: mq::MouseButton, x: f32, y: f32) { + self.egui_mq.mouse_button_down_event(mb, x, y); } - fn mouse_button_up_event( - &mut self, - ctx: &mut mq::Context, - mb: mq::MouseButton, - x: f32, - y: f32, - ) { - self.egui_mq.mouse_button_up_event(ctx, mb, x, y); + fn mouse_button_up_event(&mut self, mb: mq::MouseButton, x: f32, y: f32) { + self.egui_mq.mouse_button_up_event(mb, x, y); } - fn char_event( - &mut self, - _ctx: &mut mq::Context, - character: char, - _keymods: mq::KeyMods, - _repeat: bool, - ) { + fn char_event(&mut self, character: char, _keymods: mq::KeyMods, _repeat: bool) { self.egui_mq.char_event(character); } - fn key_down_event( - &mut self, - ctx: &mut mq::Context, - keycode: mq::KeyCode, - keymods: mq::KeyMods, - _repeat: bool, - ) { - self.egui_mq.key_down_event(ctx, keycode, keymods); + fn key_down_event(&mut self, keycode: mq::KeyCode, keymods: mq::KeyMods, _repeat: bool) { + self.egui_mq.key_down_event(keycode, keymods); } - fn key_up_event(&mut self, _ctx: &mut mq::Context, keycode: mq::KeyCode, keymods: mq::KeyMods) { + fn key_up_event(&mut self, keycode: mq::KeyCode, keymods: mq::KeyMods) { self.egui_mq.key_up_event(keycode, keymods); } } @@ -150,5 +154,5 @@ fn main() { window_height: 1024, ..Default::default() }; - mq::start(conf, |mut ctx| Box::new(Stage::new(&mut ctx))); + mq::start(conf, || Box::new(Stage::new())); } diff --git a/examples/render_to_egui_image.rs b/examples/render_to_egui_image.rs index 2359d36..e0e75c4 100644 --- a/examples/render_to_egui_image.rs +++ b/examples/render_to_egui_image.rs @@ -1,3 +1,4 @@ +use egui::load::SizedTexture; use glam::{vec3, EulerRot, Mat4}; use {egui_miniquad as egui_mq, miniquad as mq}; @@ -8,30 +9,27 @@ struct Stage { offscreen_pass: mq::RenderPass, rx: f32, ry: f32, + mq_ctx: Box, } impl Stage { - pub fn new(ctx: &mut mq::Context) -> Stage { - let color_img = mq::Texture::new_render_texture( - ctx, - mq::TextureParams { - width: 256, - height: 256, - format: mq::TextureFormat::RGBA8, - ..Default::default() - }, - ); - let depth_img = mq::Texture::new_render_texture( - ctx, - mq::TextureParams { - width: 256, - height: 256, - format: mq::TextureFormat::Depth, - ..Default::default() - }, - ); + pub fn new() -> Stage { + let mut mq_ctx = mq::window::new_rendering_backend(); + + let color_img = mq_ctx.new_render_texture(mq::TextureParams { + width: 256, + height: 256, + format: mq::TextureFormat::RGBA8, + ..Default::default() + }); + let depth_img = mq_ctx.new_render_texture(mq::TextureParams { + width: 256, + height: 256, + format: mq::TextureFormat::Depth, + ..Default::default() + }); - let offscreen_pass = mq::RenderPass::new(ctx, color_img, depth_img); + let offscreen_pass = mq_ctx.new_render_pass(color_img, Some(depth_img)); #[rustfmt::skip] let vertices: &[f32] = &[ @@ -67,7 +65,11 @@ impl Stage { 1.0, 1.0, -1.0, 1.0, 0.0, 0.5, 1.0, 0.0, 1.0 ]; - let vertex_buffer = mq::Buffer::immutable(ctx, mq::BufferType::VertexBuffer, vertices); + let vertex_buffer = mq_ctx.new_buffer( + mq::BufferType::VertexBuffer, + mq::BufferUsage::Immutable, + mq::BufferSource::slice(vertices), + ); #[rustfmt::skip] let indices: &[u16] = &[ @@ -79,7 +81,11 @@ impl Stage { 22, 21, 20, 23, 22, 20 ]; - let index_buffer = mq::Buffer::immutable(ctx, mq::BufferType::IndexBuffer, indices); + let index_buffer = mq_ctx.new_buffer( + mq::BufferType::IndexBuffer, + mq::BufferUsage::Immutable, + mq::BufferSource::slice(indices), + ); let offscreen_bind = mq::Bindings { vertex_buffers: vec![vertex_buffer], @@ -87,16 +93,17 @@ impl Stage { images: vec![], }; - let offscreen_shader = mq::Shader::new( - ctx, - offscreen_shader::VERTEX, - offscreen_shader::FRAGMENT, - offscreen_shader::meta(), - ) - .unwrap(); - - let offscreen_pipeline = mq::Pipeline::with_params( - ctx, + let offscreen_shader = mq_ctx + .new_shader( + mq::ShaderSource::Glsl { + vertex: offscreen_shader::VERTEX, + fragment: offscreen_shader::FRAGMENT, + }, + offscreen_shader::meta(), + ) + .unwrap(); + + let offscreen_pipeline = mq_ctx.new_pipeline( &[mq::BufferLayout { stride: 36, ..Default::default() @@ -114,21 +121,22 @@ impl Stage { ); Stage { - egui_mq: egui_mq::EguiMq::new(ctx), + egui_mq: egui_mq::EguiMq::new(&mut *mq_ctx), offscreen_pipeline, offscreen_bind, offscreen_pass, rx: 0., ry: 0., + mq_ctx, } } } impl mq::EventHandler for Stage { - fn update(&mut self, _ctx: &mut mq::Context) {} + fn update(&mut self) {} - fn draw(&mut self, ctx: &mut mq::Context) { - let (width, height) = ctx.screen_size(); + fn draw(&mut self) { + let (width, height) = mq::window::screen_size(); let proj = Mat4::perspective_rh_gl(60.0f32.to_radians(), width / height, 0.01, 10.0); let view = Mat4::look_at_rh( vec3(0.0, 1.5, 3.0), @@ -146,30 +154,36 @@ impl mq::EventHandler for Stage { }; // the offscreen pass, rendering an rotating, untextured cube into a render target image - ctx.begin_pass( - self.offscreen_pass, + self.mq_ctx.begin_pass( + Some(self.offscreen_pass), mq::PassAction::clear_color(1.0, 1.0, 1.0, 1.), ); - ctx.apply_pipeline(&self.offscreen_pipeline); - ctx.apply_bindings(&self.offscreen_bind); - ctx.apply_uniforms(&vs_params); - ctx.draw(0, 36, 1); - ctx.end_render_pass(); + self.mq_ctx.apply_pipeline(&self.offscreen_pipeline); + self.mq_ctx.apply_bindings(&self.offscreen_bind); + self.mq_ctx + .apply_uniforms(mq::UniformsSource::table(&vs_params)); + self.mq_ctx.draw(0, 36, 1); + self.mq_ctx.end_render_pass(); // Extract texture from offscreen render pass - let mq_texture = self.offscreen_pass.texture(ctx); + let mq_texture = self.mq_ctx.render_pass_texture(self.offscreen_pass); // create egui TextureId from Miniquad GL texture Id - let egui_texture_id = egui::TextureId::User(mq_texture.gl_internal_id() as u64); + let raw_id = match unsafe { self.mq_ctx.texture_raw_id(mq_texture) } { + mq::RawId::OpenGl(id) => id as u64, + }; + let egui_texture_id = egui::TextureId::User(raw_id); - ctx.clear(Some((1., 1., 1., 1.)), None, None); - ctx.begin_default_pass(mq::PassAction::clear_color(0.0, 0.0, 0.0, 1.0)); - ctx.end_render_pass(); + self.mq_ctx + .begin_default_pass(mq::PassAction::clear_color(0.0, 0.0, 0.0, 1.0)); + self.mq_ctx.end_render_pass(); // Run the UI code: - self.egui_mq.run(ctx, |_mq_ctx, egui_ctx| { + self.egui_mq.run(&mut *self.mq_ctx, |_mq_ctx, egui_ctx| { egui::Window::new("egui ❤ miniquad").show(egui_ctx, |ui| { - ui.image(egui_texture_id, egui::Vec2::new(140.0, 140.0)); + let img = + egui::Image::from_texture(SizedTexture::new(egui_texture_id, [140.0, 140.0])); + ui.add(img); #[cfg(not(target_arch = "wasm32"))] { if ui.button("Quit").clicked() { @@ -181,62 +195,38 @@ impl mq::EventHandler for Stage { // Draw things behind egui here - self.egui_mq.draw(ctx); + self.egui_mq.draw(&mut *self.mq_ctx); // Draw things in front of egui here - ctx.commit_frame(); + self.mq_ctx.commit_frame(); } - fn mouse_motion_event(&mut self, _: &mut mq::Context, x: f32, y: f32) { + fn mouse_motion_event(&mut self, x: f32, y: f32) { self.egui_mq.mouse_motion_event(x, y); } - fn mouse_wheel_event(&mut self, _: &mut mq::Context, dx: f32, dy: f32) { + fn mouse_wheel_event(&mut self, dx: f32, dy: f32) { self.egui_mq.mouse_wheel_event(dx, dy); } - fn mouse_button_down_event( - &mut self, - ctx: &mut mq::Context, - mb: mq::MouseButton, - x: f32, - y: f32, - ) { - self.egui_mq.mouse_button_down_event(ctx, mb, x, y); + fn mouse_button_down_event(&mut self, mb: mq::MouseButton, x: f32, y: f32) { + self.egui_mq.mouse_button_down_event(mb, x, y); } - fn mouse_button_up_event( - &mut self, - ctx: &mut mq::Context, - mb: mq::MouseButton, - x: f32, - y: f32, - ) { - self.egui_mq.mouse_button_up_event(ctx, mb, x, y); + fn mouse_button_up_event(&mut self, mb: mq::MouseButton, x: f32, y: f32) { + self.egui_mq.mouse_button_up_event(mb, x, y); } - fn char_event( - &mut self, - _ctx: &mut mq::Context, - character: char, - _keymods: mq::KeyMods, - _repeat: bool, - ) { + fn char_event(&mut self, character: char, _keymods: mq::KeyMods, _repeat: bool) { self.egui_mq.char_event(character); } - fn key_down_event( - &mut self, - ctx: &mut mq::Context, - keycode: mq::KeyCode, - keymods: mq::KeyMods, - _repeat: bool, - ) { - self.egui_mq.key_down_event(ctx, keycode, keymods); + fn key_down_event(&mut self, keycode: mq::KeyCode, keymods: mq::KeyMods, _repeat: bool) { + self.egui_mq.key_down_event(keycode, keymods); } - fn key_up_event(&mut self, _ctx: &mut mq::Context, keycode: mq::KeyCode, keymods: mq::KeyMods) { + fn key_up_event(&mut self, keycode: mq::KeyCode, keymods: mq::KeyMods) { self.egui_mq.key_up_event(keycode, keymods); } } @@ -246,7 +236,7 @@ fn main() { high_dpi: true, ..Default::default() }; - mq::start(conf, |mut ctx| Box::new(Stage::new(&mut ctx))); + mq::start(conf, || Box::new(Stage::new())); } mod offscreen_shader { diff --git a/src/input.rs b/src/input.rs index f09506d..a1344b2 100644 --- a/src/input.rs +++ b/src/input.rs @@ -1,11 +1,7 @@ use miniquad as mq; -pub fn on_frame_start( - egui_input: &mut egui::RawInput, - equi_ctx: &egui::Context, - mq_ctx: &mq::Context, -) { - let screen_size_in_pixels = mq_ctx.screen_size(); +pub fn on_frame_start(egui_input: &mut egui::RawInput, equi_ctx: &egui::Context) { + let screen_size_in_pixels = mq::window::screen_size(); let screen_size_in_points = egui::vec2(screen_size_in_pixels.0, screen_size_in_pixels.1) / equi_ctx.pixels_per_point(); egui_input.screen_rect = Some(egui::Rect::from_min_size( @@ -101,6 +97,19 @@ pub fn egui_key_from_mq_key(key: mq::KeyCode) -> Option { mq::KeyCode::Y => egui::Key::Y, mq::KeyCode::Z => egui::Key::Z, - _ => return None, + mq::KeyCode::Comma => egui::Key::Comma, + mq::KeyCode::Backslash => egui::Key::Backslash, + mq::KeyCode::LeftBracket => egui::Key::OpenBracket, + mq::KeyCode::RightBracket => egui::Key::CloseBracket, + mq::KeyCode::GraveAccent => egui::Key::Backtick, + mq::KeyCode::Minus => egui::Key::Minus, + mq::KeyCode::Period => egui::Key::Period, + mq::KeyCode::Equal => egui::Key::Equals, + mq::KeyCode::Semicolon => egui::Key::Semicolon, + + _other => { + // mq::trace!("egui-miniquad: Unhandled key: {:?}", _other); + return None; + } }) } diff --git a/src/lib.rs b/src/lib.rs index 5ec2911..946ad31 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -11,25 +11,27 @@ //! //! struct MyMiniquadApp { //! egui_mq: egui_miniquad::EguiMq, +//! mq_ctx: Box //! } //! //! impl MyMiniquadApp { -//! fn new(ctx: &mut mq::Context) -> Self { +//! fn new() -> Self { +//! let mut mq_ctx = mq::window::new_rendering_backend(); //! Self { -//! egui_mq: egui_miniquad::EguiMq::new(ctx), +//! egui_mq: egui_miniquad::EguiMq::new(&mut *mq_ctx), +//! mq_ctx, //! } //! } //! } //! //! impl mq::EventHandler for MyMiniquadApp { -//! fn update(&mut self, _: &mut mq::Context) {} +//! fn update(&mut self) {} //! -//! fn draw(&mut self, mq_ctx: &mut mq::Context) { -//! mq_ctx.clear(Some((1., 1., 1., 1.)), None, None); -//! mq_ctx.begin_default_pass(mq::PassAction::clear_color(0.0, 0.0, 0.0, 1.0)); -//! mq_ctx.end_render_pass(); +//! fn draw(&mut self) { +//! self.mq_ctx.begin_default_pass(mq::PassAction::clear_color(0.0, 0.0, 0.0, 1.0)); +//! self.mq_ctx.end_render_pass(); //! -//! self.egui_mq.run(mq_ctx, |_mq_ctx, egui_ctx|{ +//! self.egui_mq.run(&mut *self.mq_ctx, |_mq_ctx, egui_ctx|{ //! egui::Window::new("Egui Window").show(egui_ctx, |ui| { //! ui.heading("Hello World!"); //! }); @@ -37,44 +39,41 @@ //! //! // Draw things behind egui here //! -//! self.egui_mq.draw(mq_ctx); +//! self.egui_mq.draw(&mut *self.mq_ctx); //! //! // Draw things in front of egui here //! -//! mq_ctx.commit_frame(); +//! self.mq_ctx.commit_frame(); //! } //! -//! fn mouse_motion_event(&mut self, _: &mut mq::Context, x: f32, y: f32) { +//! fn mouse_motion_event(&mut self, x: f32, y: f32) { //! self.egui_mq.mouse_motion_event(x, y); //! } //! -//! fn mouse_wheel_event(&mut self, _: &mut mq::Context, dx: f32, dy: f32) { +//! fn mouse_wheel_event(&mut self, dx: f32, dy: f32) { //! self.egui_mq.mouse_wheel_event(dx, dy); //! } //! //! fn mouse_button_down_event( //! &mut self, -//! ctx: &mut mq::Context, //! mb: mq::MouseButton, //! x: f32, //! y: f32, //! ) { -//! self.egui_mq.mouse_button_down_event(ctx, mb, x, y); +//! self.egui_mq.mouse_button_down_event(mb, x, y); //! } //! //! fn mouse_button_up_event( //! &mut self, -//! ctx: &mut mq::Context, //! mb: mq::MouseButton, //! x: f32, //! y: f32, //! ) { -//! self.egui_mq.mouse_button_up_event(ctx, mb, x, y); +//! self.egui_mq.mouse_button_up_event(mb, x, y); //! } //! //! fn char_event( //! &mut self, -//! _ctx: &mut mq::Context, //! character: char, //! _keymods: mq::KeyMods, //! _repeat: bool, @@ -84,15 +83,14 @@ //! //! fn key_down_event( //! &mut self, -//! ctx: &mut mq::Context, //! keycode: mq::KeyCode, //! keymods: mq::KeyMods, //! _repeat: bool, //! ) { -//! self.egui_mq.key_down_event(ctx, keycode, keymods); +//! self.egui_mq.key_down_event(keycode, keymods); //! } //! -//! fn key_up_event(&mut self, _ctx: &mut mq::Context, keycode: mq::KeyCode, keymods: mq::KeyMods) { +//! fn key_up_event(&mut self, keycode: mq::KeyCode, keymods: mq::KeyMods) { //! self.egui_mq.key_up_event(keycode, keymods); //! } //! } @@ -129,7 +127,10 @@ use copypasta::ClipboardProvider; /// /// pub struct EguiMq { + /// The DPI as reported by miniquad. native_dpi_scale: f32, + /// Pixels per point from egui. Can differ from native DPI because egui allows zooming. + pixels_per_point: f32, egui_ctx: egui::Context, egui_input: egui::RawInput, painter: painter::Painter, @@ -140,16 +141,15 @@ pub struct EguiMq { } impl EguiMq { - pub fn new(mq_ctx: &mut mq::Context) -> Self { - let native_dpi_scale = mq_ctx.dpi_scale(); + pub fn new(mq_ctx: &mut dyn mq::RenderingBackend) -> Self { + let native_dpi_scale = miniquad::window::dpi_scale(); + Self { native_dpi_scale, + pixels_per_point: native_dpi_scale, egui_ctx: egui::Context::default(), painter: painter::Painter::new(mq_ctx), - egui_input: egui::RawInput { - pixels_per_point: Some(native_dpi_scale), - ..Default::default() - }, + egui_input: egui::RawInput::default(), #[cfg(target_os = "macos")] clipboard: init_clipboard(), shapes: None, @@ -167,15 +167,19 @@ impl EguiMq { /// Run the ui code for one frame. pub fn run( &mut self, - mq_ctx: &mut mq::Context, - run_ui: impl FnOnce(&mut mq::Context, &egui::Context), + mq_ctx: &mut dyn mq::RenderingBackend, + run_ui: impl FnOnce(&mut dyn mq::RenderingBackend, &egui::Context), ) { - input::on_frame_start(&mut self.egui_input, &self.egui_ctx, mq_ctx); + input::on_frame_start(&mut self.egui_input, &self.egui_ctx); - if self.native_dpi_scale != mq_ctx.dpi_scale() { + if self.native_dpi_scale != miniquad::window::dpi_scale() { // DPI scale change (maybe new monitor?). Tell egui to change: - self.native_dpi_scale = mq_ctx.dpi_scale(); - self.egui_input.pixels_per_point = Some(self.native_dpi_scale); + self.native_dpi_scale = miniquad::window::dpi_scale(); + self.egui_input + .viewports + .get_mut(&self.egui_input.viewport_id) + .unwrap() + .native_pixels_per_point = Some(self.native_dpi_scale); } let full_output = self @@ -184,15 +188,17 @@ impl EguiMq { let egui::FullOutput { platform_output, - repaint_after: _, // miniquad always runs at full framerate textures_delta, shapes, + pixels_per_point, + viewport_output: _viewport_output, // we only support one viewport } = full_output; if self.shapes.is_some() { eprintln!("Egui contents not drawn. You need to call `draw` after calling `run`"); } self.shapes = Some(shapes); + self.pixels_per_point = pixels_per_point; self.textures_delta.append(textures_delta); let egui::PlatformOutput { @@ -200,7 +206,7 @@ impl EguiMq { open_url, copied_text, events: _, // no screen reader - text_cursor_pos: _, // no IME + ime: _, // no IME mutable_text_under_cursor: _, // no IME .. } = platform_output; @@ -210,25 +216,25 @@ impl EguiMq { } if cursor_icon == egui::CursorIcon::None { - mq_ctx.show_mouse(false); + miniquad::window::show_mouse(false); } else { - mq_ctx.show_mouse(true); + miniquad::window::show_mouse(true); let mq_cursor_icon = to_mq_cursor_icon(cursor_icon); let mq_cursor_icon = mq_cursor_icon.unwrap_or(mq::CursorIcon::Default); - mq_ctx.set_mouse_cursor(mq_cursor_icon); + miniquad::window::set_mouse_cursor(mq_cursor_icon); } if !copied_text.is_empty() { - self.set_clipboard(mq_ctx, copied_text); + self.set_clipboard(copied_text); } } /// Call this when you need to draw egui. /// Must be called after `end_frame`. - pub fn draw(&mut self, mq_ctx: &mut mq::Context) { + pub fn draw(&mut self, mq_ctx: &mut dyn mq::RenderingBackend) { if let Some(shapes) = self.shapes.take() { - let meshes = self.egui_ctx.tessellate(shapes); + let meshes = self.egui_ctx.tessellate(shapes, self.pixels_per_point); self.painter.paint_and_update_textures( mq_ctx, meshes, @@ -264,13 +270,7 @@ impl EguiMq { } /// Call from your [`miniquad::EventHandler`]. - pub fn mouse_button_down_event( - &mut self, - _: &mut mq::Context, - mb: mq::MouseButton, - x: f32, - y: f32, - ) { + pub fn mouse_button_down_event(&mut self, mb: mq::MouseButton, x: f32, y: f32) { let pos = egui::pos2( x / self.egui_ctx.pixels_per_point(), y / self.egui_ctx.pixels_per_point(), @@ -285,13 +285,7 @@ impl EguiMq { } /// Call from your [`miniquad::EventHandler`]. - pub fn mouse_button_up_event( - &mut self, - _: &mut mq::Context, - mb: mq::MouseButton, - x: f32, - y: f32, - ) { + pub fn mouse_button_up_event(&mut self, mb: mq::MouseButton, x: f32, y: f32) { let pos = egui::pos2( x / self.egui_ctx.pixels_per_point(), y / self.egui_ctx.pixels_per_point(), @@ -319,12 +313,7 @@ impl EguiMq { } /// Call from your [`miniquad::EventHandler`]. - pub fn key_down_event( - &mut self, - mq_ctx: &mut mq::Context, - keycode: mq::KeyCode, - keymods: mq::KeyMods, - ) { + pub fn key_down_event(&mut self, keycode: mq::KeyCode, keymods: mq::KeyMods) { let modifiers = input::egui_modifiers_from_mq_modifiers(keymods); self.egui_input.modifiers = modifiers; @@ -333,7 +322,7 @@ impl EguiMq { } else if modifiers.command && keycode == mq::KeyCode::C { self.egui_input.events.push(egui::Event::Copy); } else if modifiers.command && keycode == mq::KeyCode::V { - if let Some(text) = self.get_clipboard(mq_ctx) { + if let Some(text) = self.get_clipboard() { self.egui_input.events.push(egui::Event::Text(text)); } } else if let Some(key) = input::egui_key_from_mq_key(keycode) { @@ -341,7 +330,8 @@ impl EguiMq { key, pressed: true, modifiers, - repeat: false, // egui will set this for us + repeat: false, // egui will set this for us + physical_key: None, // unsupported }) } } @@ -355,19 +345,20 @@ impl EguiMq { key, pressed: false, modifiers, - repeat: false, // egui will set this for us + repeat: false, // egui will set this for us + physical_key: None, // unsupported }) } } #[cfg(not(target_os = "macos"))] - fn set_clipboard(&mut self, mq_ctx: &mut mq::Context, text: String) { - mq_ctx.clipboard_set(&text); + fn set_clipboard(&mut self, text: String) { + mq::window::clipboard_set(&text); } #[cfg(not(target_os = "macos"))] - fn get_clipboard(&mut self, mq_ctx: &mut mq::Context) -> Option { - mq_ctx.clipboard_get() + fn get_clipboard(&mut self) -> Option { + mq::window::clipboard_get() } #[cfg(target_os = "macos")] diff --git a/src/painter.rs b/src/painter.rs index 8cdce79..b52280e 100644 --- a/src/painter.rs +++ b/src/painter.rs @@ -1,7 +1,8 @@ use egui::epaint::Vertex; use miniquad::{ - Bindings, BlendFactor, BlendState, BlendValue, Buffer, BufferLayout, BufferType, Context, - Equation, GraphicsContext, Pipeline, PipelineParams, Shader, VertexAttribute, VertexFormat, + Backend, Bindings, BlendFactor, BlendState, BlendValue, BufferLayout, BufferSource, BufferType, + BufferUsage, Equation, Pipeline, PipelineParams, RawId, RenderingBackend, ShaderSource, + TextureId, UniformsSource, VertexAttribute, VertexFormat, }; /// A callback function that can be used to compose an [`egui::PaintCallback`] for custom rendering @@ -15,12 +16,12 @@ use miniquad::{ /// See the [`custom3d_glow`](https://github.com/emilk/egui/blob/master/crates/egui_demo_app/src/apps/custom3d_wgpu.rs) demo source for a detailed usage example. pub struct CallbackFn { #[allow(clippy::type_complexity)] - f: Box, + f: Box, } impl CallbackFn { pub fn new( - callback: impl Fn(egui::PaintCallbackInfo, &mut GraphicsContext) + Sync + Send + 'static, + callback: impl Fn(egui::PaintCallbackInfo, &mut dyn RenderingBackend) + Sync + Send + 'static, ) -> Self { let f = Box::new(callback); CallbackFn { f } @@ -30,15 +31,21 @@ impl CallbackFn { pub struct Painter { pipeline: Pipeline, bindings: Bindings, - textures: std::collections::HashMap, + textures: std::collections::HashMap, } impl Painter { - pub fn new(ctx: &mut Context) -> Painter { - let shader = Shader::new(ctx, shader::VERTEX, shader::FRAGMENT, shader::meta()); + pub fn new(ctx: &mut dyn RenderingBackend) -> Painter { + let source = match ctx.info().backend { + Backend::Metal => unimplemented!(), + Backend::OpenGl => ShaderSource::Glsl { + vertex: shader::VERTEX, + fragment: shader::FRAGMENT, + }, + }; + let shader = ctx.new_shader(source, shader::meta()); - let pipeline = Pipeline::with_params( - ctx, + let pipeline = ctx.new_pipeline( &[BufferLayout::default()], &[ VertexAttribute::new("a_pos", VertexFormat::Float2), @@ -57,21 +64,23 @@ impl Painter { }, ); - let vertex_buffer = Buffer::stream( - ctx, + let vertex_buffer = ctx.new_buffer( BufferType::VertexBuffer, - 32 * 1024 * std::mem::size_of::(), + BufferUsage::Stream, + BufferSource::empty::(32 * 1024), ); - let index_buffer = Buffer::stream( - ctx, + let index_buffer = ctx.new_buffer( BufferType::IndexBuffer, - 32 * 1024 * std::mem::size_of::(), + BufferUsage::Stream, + BufferSource::empty::(32 * 1024), ); + let white_texture = ctx.new_texture_from_rgba8(1, 1, &[255, 255, 255, 255]); + let bindings = Bindings { vertex_buffers: vec![vertex_buffer], index_buffer, - images: vec![miniquad::Texture::empty()], + images: vec![white_texture], }; Painter { @@ -83,7 +92,7 @@ impl Painter { pub fn set_texture( &mut self, - ctx: &mut Context, + ctx: &mut dyn RenderingBackend, tex_id: egui::TextureId, delta: &egui::epaint::ImageDelta, ) { @@ -104,7 +113,7 @@ impl Painter { "Mismatch between texture size and texel count" ); let data: &[u8] = bytemuck::cast_slice(image.pixels.as_ref()); - texture.update_texture_part(ctx, x as _, y as _, w as _, h as _, data); + ctx.texture_update_part(*texture, x as _, y as _, w as _, h as _, data); } egui::ImageData::Font(image) => { assert_eq!( @@ -118,7 +127,7 @@ impl Painter { .flat_map(|a| a.to_array()) .collect(); - texture.update_texture_part(ctx, x as _, y as _, w as _, h as _, &data); + ctx.texture_update_part(*texture, x as _, y as _, w as _, h as _, &data); } } } else { @@ -129,9 +138,11 @@ impl Painter { let params = miniquad::TextureParams { format: miniquad::TextureFormat::RGBA8, wrap: miniquad::TextureWrap::Clamp, - filter, + min_filter: filter, + mag_filter: filter, width: w as _, height: h as _, + ..Default::default() }; let texture = match &delta.image { @@ -142,7 +153,7 @@ impl Painter { "Mismatch between texture size and texel count" ); let data: &[u8] = bytemuck::cast_slice(image.pixels.as_ref()); - miniquad::Texture::from_data_and_format(ctx, data, params) + ctx.new_texture_from_data_and_format(data, params) } egui::ImageData::Font(image) => { assert_eq!( @@ -156,26 +167,26 @@ impl Painter { .flat_map(|a| a.to_array()) .collect(); - miniquad::Texture::from_data_and_format(ctx, &data, params) + ctx.new_texture_from_data_and_format(&data, params) } }; let previous = self.textures.insert(tex_id, texture); if let Some(previous) = previous { - previous.delete(); + ctx.delete_texture(previous); } } } - pub fn free_texture(&mut self, tex_id: egui::TextureId) { + pub fn free_texture(&mut self, ctx: &mut dyn RenderingBackend, tex_id: egui::TextureId) { if let Some(old_tex) = self.textures.remove(&tex_id) { - old_tex.delete(); + ctx.delete_texture(old_tex); } } pub fn paint_and_update_textures( &mut self, - ctx: &mut Context, + ctx: &mut dyn RenderingBackend, primtives: Vec, textures_delta: &egui::TexturesDelta, egui_ctx: &egui::Context, @@ -187,27 +198,27 @@ impl Painter { self.paint(ctx, primtives, egui_ctx); for &id in &textures_delta.free { - self.free_texture(id); + self.free_texture(ctx, id); } } pub fn paint( &mut self, - ctx: &mut Context, + ctx: &mut dyn RenderingBackend, primtives: Vec, egui_ctx: &egui::Context, ) { ctx.begin_default_pass(miniquad::PassAction::Nothing); ctx.apply_pipeline(&self.pipeline); - let screen_size_in_pixels = ctx.screen_size(); + let screen_size_in_pixels = miniquad::window::screen_size(); let screen_size_in_points = ( screen_size_in_pixels.0 / egui_ctx.pixels_per_point(), screen_size_in_pixels.1 / egui_ctx.pixels_per_point(), ); - ctx.apply_uniforms(&shader::Uniforms { + ctx.apply_uniforms(UniformsSource::table(&shader::Uniforms { u_screen_size: screen_size_in_points, - }); + })); for egui::ClippedPrimitive { clip_rect, @@ -245,12 +256,12 @@ impl Painter { pub fn paint_job( &mut self, - ctx: &mut Context, + ctx: &mut dyn RenderingBackend, clip_rect: egui::Rect, mesh: egui::epaint::Mesh, egui_ctx: &egui::Context, ) { - let screen_size_in_pixels = ctx.screen_size(); + let screen_size_in_pixels = miniquad::window::screen_size(); let pixels_per_point = egui_ctx.pixels_per_point(); // TODO: support u32 indices in miniquad and just use "mesh.indices" without a need for `split_to_u16` @@ -258,20 +269,32 @@ impl Painter { for mesh in meshes { assert!(mesh.is_valid()); let vertices_size_bytes = mesh.vertices.len() * std::mem::size_of::(); - if self.bindings.vertex_buffers[0].size() < vertices_size_bytes { - self.bindings.vertex_buffers[0].delete(); - self.bindings.vertex_buffers[0] = - Buffer::stream(ctx, BufferType::VertexBuffer, vertices_size_bytes); + if ctx.buffer_size(self.bindings.vertex_buffers[0]) < vertices_size_bytes { + ctx.delete_buffer(self.bindings.vertex_buffers[0]); + self.bindings.vertex_buffers[0] = ctx.new_buffer( + BufferType::VertexBuffer, + BufferUsage::Stream, + BufferSource::empty::(mesh.vertices.len()), + ); } - self.bindings.vertex_buffers[0].update(ctx, &mesh.vertices); + ctx.buffer_update( + self.bindings.vertex_buffers[0], + BufferSource::slice(&mesh.vertices), + ); let indices_size_bytes = mesh.indices.len() * std::mem::size_of::(); - if self.bindings.index_buffer.size() < indices_size_bytes { - self.bindings.index_buffer.delete(); - self.bindings.index_buffer = - Buffer::stream(ctx, BufferType::IndexBuffer, indices_size_bytes); + if ctx.buffer_size(self.bindings.index_buffer) < indices_size_bytes { + ctx.delete_buffer(self.bindings.index_buffer); + self.bindings.index_buffer = ctx.new_buffer( + BufferType::IndexBuffer, + BufferUsage::Stream, + BufferSource::empty::(mesh.indices.len()), + ); } - self.bindings.index_buffer.update(ctx, &mesh.indices); + ctx.buffer_update( + self.bindings.index_buffer, + BufferSource::slice(&mesh.indices), + ); self.bindings.images[0] = match mesh.texture_id { egui::TextureId::Managed(id) => { @@ -282,7 +305,7 @@ impl Painter { continue; } } - egui::TextureId::User(id) => unsafe { miniquad::Texture::from_raw_id(id as u32) }, + egui::TextureId::User(id) => TextureId::from_raw_id(RawId::OpenGl(id as _)), }; let (width_in_pixels, height_in_pixels) = screen_size_in_pixels;