diff --git a/core/src/bitmap/bitmap_data.rs b/core/src/bitmap/bitmap_data.rs index f0c5e0f9f..715ffa02a 100644 --- a/core/src/bitmap/bitmap_data.rs +++ b/core/src/bitmap/bitmap_data.rs @@ -226,6 +226,12 @@ pub struct BitmapData<'gc> { #[collect(require_static)] dirty_state: DirtyState, + + /// Holds an egui texture handle, used for rendering this Bitmap in the debug ui. + /// This is automatically set to `None` when the texture is updated (either from + /// marking the CPU side dirty, or from performing a GPU -> CPU sync). + #[cfg(feature = "egui")] + pub egui_texture: std::cell::RefCell>, } #[derive(Clone, Debug)] @@ -306,6 +312,8 @@ mod wrapper { avm2_object: None, display_objects: vec![], dirty_state: DirtyState::Clean, + #[cfg(feature = "egui")] + egui_texture: Default::default(), }, )) } @@ -328,6 +336,8 @@ mod wrapper { display_objects: vec![], // We have no GPU texture, so there's no need to mark as dirty dirty_state: DirtyState::Clean, + #[cfg(feature = "egui")] + egui_texture: Default::default(), } } @@ -349,7 +359,9 @@ mod wrapper { }), ) .expect("Failed to sync BitmapData"); - write.dirty_state = DirtyState::Clean + write.dirty_state = DirtyState::Clean; + #[cfg(feature = "egui")] + write.egui_texture.borrow_mut().take(); } old_state => write.dirty_state = old_state, } @@ -389,6 +401,8 @@ mod wrapper { } DirtyState::CpuModified(_) | DirtyState::Clean => None, }; + #[cfg(feature = "egui")] + write.egui_texture.borrow_mut().take(); (self.0, dirty_rect) } @@ -561,6 +575,8 @@ impl<'gc> BitmapData<'gc> { avm2_object: None, display_objects: vec![], dirty_state: DirtyState::Clean, + #[cfg(feature = "egui")] + egui_texture: Default::default(), } } @@ -580,6 +596,8 @@ impl<'gc> BitmapData<'gc> { disposed: false, dirty_state: DirtyState::Clean, display_objects: vec![], + #[cfg(feature = "egui")] + egui_texture: Default::default(), } } @@ -632,6 +650,10 @@ impl<'gc> BitmapData<'gc> { pub fn set_cpu_dirty(&mut self, gc_context: &Mutation<'gc>, region: PixelRegion) { debug_assert!(region.x_max <= self.width); debug_assert!(region.y_max <= self.height); + + #[cfg(feature = "egui")] + self.egui_texture.borrow_mut().take(); + let inform_changes = match &mut self.dirty_state { DirtyState::CpuModified(old_region) => { old_region.union(region); diff --git a/core/src/debug_ui/display_object.rs b/core/src/debug_ui/display_object.rs index 28e7ef8a9..125dd5c69 100644 --- a/core/src/debug_ui/display_object.rs +++ b/core/src/debug_ui/display_object.rs @@ -10,7 +10,7 @@ use crate::debug_ui::handle::{AVM1ObjectHandle, AVM2ObjectHandle, DisplayObjectH use crate::debug_ui::movie::open_movie_button; use crate::debug_ui::Message; use crate::display_object::{ - DisplayObject, EditText, InteractiveObject, MovieClip, Stage, TDisplayObject, + Bitmap, DisplayObject, EditText, InteractiveObject, MovieClip, Stage, TDisplayObject, TDisplayObjectContainer, TInteractiveObject, }; use crate::focus_tracker::Highlight; @@ -160,6 +160,8 @@ impl DisplayObjectWindow { self.show_movieclip(ui, context, object) } else if let DisplayObject::EditText(object) = object { self.show_edit_text(ui, object) + } else if let DisplayObject::Bitmap(object) = object { + self.show_bitmap(ui, context, object) } else if let DisplayObject::Stage(object) = object { self.show_stage(ui, context, object, messages) } @@ -346,6 +348,29 @@ impl DisplayObjectWindow { }); } + pub fn show_bitmap<'gc>( + &mut self, + ui: &mut Ui, + context: &mut UpdateContext<'_, 'gc>, + object: Bitmap<'gc>, + ) { + let bitmap_data = object.bitmap_data(context.renderer); + let bitmap_data = bitmap_data.read(); + let mut egui_texture = bitmap_data.egui_texture.borrow_mut(); + let texture = egui_texture.get_or_insert_with(|| { + let image = egui::ColorImage::from_rgba_premultiplied( + [bitmap_data.width() as usize, bitmap_data.height() as usize], + &bitmap_data.pixels_rgba(), + ); + ui.ctx().load_texture( + format!("bitmap-{:?}", object.as_ptr()), + image, + Default::default(), + ) + }); + ui.image((texture.id(), texture.size_vec2())); + } + pub fn show_movieclip<'gc>( &mut self, ui: &mut Ui, @@ -979,7 +1004,10 @@ fn summary_color_transform_entry(name: &str, mult: Fixed8, add: i16) -> Option bool { matches!( object, - DisplayObject::MovieClip(_) | DisplayObject::EditText(_) | DisplayObject::Stage(_) + DisplayObject::MovieClip(_) + | DisplayObject::EditText(_) + | DisplayObject::Bitmap(_) + | DisplayObject::Stage(_) ) }