Skip to content

Commit

Permalink
Update to egui 0.17.0
Browse files Browse the repository at this point in the history
  • Loading branch information
emilk committed Feb 23, 2022
1 parent 58d3ffd commit 3e09e1c
Show file tree
Hide file tree
Showing 4 changed files with 132 additions and 43 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
# Unreleased
* Update egui to `0.17.0`

# 0.8.0 - 2021-12-29
* Update egui to `0.16.0`
Expand Down
5 changes: 3 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@ include = [
]

[dependencies]
egui = "0.16.0"
bytemuck = "1.7"
egui = { version = "0.17.0", features = ["convert_bytemuck"] }
miniquad = { version = "=0.3.0-alpha.43" }
quad-url = "0.1.0"

Expand All @@ -28,7 +29,7 @@ quad-url = "0.1.0"
copypasta = "0.7"

[dev-dependencies]
egui_demo_lib = { version = "0.16.0", default-features = false }
egui_demo_lib = { version = "0.17.0", default-features = false }
glam = "0.20"

[profile.release]
Expand Down
32 changes: 21 additions & 11 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -113,51 +113,60 @@ use copypasta::ClipboardProvider;
///
///
pub struct EguiMq {
egui_ctx: egui::CtxRef,
egui_ctx: egui::Context,
egui_input: egui::RawInput,
painter: painter::Painter,
#[cfg(target_os = "macos")]
clipboard: Option<copypasta::ClipboardContext>,
shapes: Option<Vec<egui::epaint::ClippedShape>>,
textures_delta: egui::TexturesDelta,
}

impl EguiMq {
pub fn new(mq_ctx: &mut mq::Context) -> Self {
Self {
egui_ctx: egui::CtxRef::default(),
egui_ctx: egui::Context::default(),
painter: painter::Painter::new(mq_ctx),
egui_input: Default::default(),
#[cfg(target_os = "macos")]
clipboard: init_clipboard(),
shapes: None,
textures_delta: Default::default(),
}
}

/// Use this to open egui windows, panels etc.
/// Can only be used between [`Self::begin_frame`] and [`Self::end_frame`].
pub fn egui_ctx(&self) -> &egui::CtxRef {
pub fn egui_ctx(&self) -> &egui::Context {
&self.egui_ctx
}

/// Run the ui code for one frame.
pub fn run(&mut self, mq_ctx: &mut mq::Context, run_ui: impl FnOnce(&egui::CtxRef)) {
pub fn run(&mut self, mq_ctx: &mut mq::Context, run_ui: impl FnOnce(&egui::Context)) {
input::on_frame_start(&mut self.egui_input, mq_ctx);
let (output, shapes) = self.egui_ctx.run(self.egui_input.take(), run_ui);
let full_output = self.egui_ctx.run(self.egui_input.take(), run_ui);

let egui::FullOutput {
platform_output,
needs_repaint: _, // miniquad always runs at full framerate
textures_delta,
shapes,
} = full_output;

if self.shapes.is_some() {
eprintln!("Egui contents not drawed. You need to call `draw` after calling `run`");
eprintln!("Egui contents not drawn. You need to call `draw` after calling `run`");
}
self.shapes = Some(shapes);
self.textures_delta.append(textures_delta);

let egui::Output {
let egui::PlatformOutput {
cursor_icon,
open_url,
copied_text,
needs_repaint: _, // miniquad always runs at full framerate
events: _, // no screen reader
text_cursor_pos: _, // no IME
mutable_text_under_cursor: _, // no IME
} = output;
} = platform_output;

if let Some(url) = open_url {
quad_url::link_open(&url.url, url.new_tab);
Expand All @@ -182,9 +191,10 @@ impl EguiMq {
/// Must be called after `end_frame`.
pub fn draw(&mut self, mq_ctx: &mut mq::Context) {
if let Some(shapes) = self.shapes.take() {
let paint_jobs = self.egui_ctx.tessellate(shapes);
let meshes = self.egui_ctx.tessellate(shapes);
self.painter
.paint(mq_ctx, paint_jobs, &self.egui_ctx.font_image());
.paint_and_update_textures(mq_ctx, meshes, &self.textures_delta);
self.textures_delta.clear();
} else {
eprintln!("Failed to draw egui. You need to call `end_frame` before calling `draw`");
}
Expand Down
137 changes: 107 additions & 30 deletions src/painter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,7 @@ use miniquad::{
pub struct Painter {
pipeline: Pipeline,
bindings: Bindings,
egui_texture_version: u64,
egui_texture: miniquad::Texture,
textures: std::collections::HashMap<egui::TextureId, miniquad::Texture>,
}

impl Painter {
Expand Down Expand Up @@ -54,47 +53,118 @@ impl Painter {
Painter {
pipeline,
bindings,
egui_texture_version: 0,
egui_texture: miniquad::Texture::empty(),
textures: Default::default(),
}
}

fn rebuild_egui_texture(&mut self, ctx: &mut Context, font_image: &egui::FontImage) {
self.egui_texture.delete();

let mut texture_data = Vec::new();
let gamma = 1.0;
for pixel in font_image.srgba_pixels(gamma) {
texture_data.push(pixel.r());
texture_data.push(pixel.g());
texture_data.push(pixel.b());
texture_data.push(pixel.a());
}
assert_eq!(texture_data.len(), font_image.width * font_image.height * 4);
self.egui_texture = miniquad::Texture::from_data_and_format(
ctx,
&texture_data,
miniquad::TextureParams {
pub fn set_texture(
&mut self,
ctx: &mut Context,
tex_id: egui::TextureId,
delta: &egui::epaint::ImageDelta,
) {
let [w, h] = delta.image.size();

if let Some([x, y]) = delta.pos {
// Partial update
if let Some(texture) = self.textures.get(&tex_id) {
match &delta.image {
egui::ImageData::Color(image) => {
assert_eq!(
image.width() * image.height(),
image.pixels.len(),
"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);
}
egui::ImageData::Alpha(image) => {
assert_eq!(
image.width() * image.height(),
image.pixels.len(),
"Mismatch between texture size and texel count"
);

let gamma = 1.0;
let data: Vec<u8> = image
.srgba_pixels(gamma)
.flat_map(|a| a.to_array())
.collect();

texture.update_texture_part(ctx, x as _, y as _, w as _, h as _, &data);
}
}
} else {
eprintln!("Failed to find egui texture {:?}", tex_id);
}
} else {
// New texture (or full update).
let params = miniquad::TextureParams {
format: miniquad::TextureFormat::RGBA8,
wrap: miniquad::TextureWrap::Clamp,
filter: miniquad::FilterMode::Linear,
width: font_image.width as _,
height: font_image.height as _,
},
);
width: w as _,
height: h as _,
};

let texture = match &delta.image {
egui::ImageData::Color(image) => {
assert_eq!(
image.width() * image.height(),
image.pixels.len(),
"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)
}
egui::ImageData::Alpha(image) => {
assert_eq!(
image.width() * image.height(),
image.pixels.len(),
"Mismatch between texture size and texel count"
);

let gamma = 1.0;
let data: Vec<u8> = image
.srgba_pixels(gamma)
.flat_map(|a| a.to_array())
.collect();

miniquad::Texture::from_data_and_format(ctx, &data, params)
}
};

let previous = self.textures.insert(tex_id, texture);
if let Some(previous) = previous {
previous.delete();
}
}
}

pub fn paint(
pub fn free_texture(&mut self, tex_id: egui::TextureId) {
if let Some(old_tex) = self.textures.remove(&tex_id) {
old_tex.delete();
}
}

pub fn paint_and_update_textures(
&mut self,
ctx: &mut Context,
meshes: Vec<egui::ClippedMesh>,
font_image: &egui::FontImage,
textures_delta: &egui::TexturesDelta,
) {
if font_image.version != self.egui_texture_version {
self.rebuild_egui_texture(ctx, font_image);
self.egui_texture_version = font_image.version;
for (id, image_delta) in &textures_delta.set {
self.set_texture(ctx, *id, image_delta);
}

self.paint(ctx, meshes);

for &id in &textures_delta.free {
self.free_texture(id);
}
}

pub fn paint(&mut self, ctx: &mut Context, meshes: Vec<egui::ClippedMesh>) {
ctx.begin_default_pass(miniquad::PassAction::Nothing);
ctx.apply_pipeline(&self.pipeline);

Expand Down Expand Up @@ -144,7 +214,14 @@ impl Painter {
self.bindings.index_buffer.update(ctx, &mesh.indices);

self.bindings.images[0] = match mesh.texture_id {
egui::TextureId::Egui => self.egui_texture,
egui::TextureId::Managed(id) => {
if let Some(tex) = self.textures.get(&mesh.texture_id) {
*tex
} else {
eprintln!("Texture {:?} not found", id);
continue;
}
}
egui::TextureId::User(id) => unsafe { miniquad::Texture::from_raw_id(id as u32) },
};

Expand Down

0 comments on commit 3e09e1c

Please sign in to comment.