2023-06-05 10:36:55 +00:00
|
|
|
mod avm1;
|
2023-06-07 13:27:02 +00:00
|
|
|
mod avm2;
|
2023-05-31 09:32:58 +00:00
|
|
|
mod display_object;
|
|
|
|
mod handle;
|
2023-06-04 20:38:43 +00:00
|
|
|
mod movie;
|
2023-05-31 09:32:58 +00:00
|
|
|
|
2023-06-01 22:28:27 +00:00
|
|
|
use crate::context::{RenderContext, UpdateContext};
|
2023-06-05 10:36:55 +00:00
|
|
|
use crate::debug_ui::avm1::Avm1ObjectWindow;
|
2023-06-07 13:27:02 +00:00
|
|
|
use crate::debug_ui::avm2::Avm2ObjectWindow;
|
2023-05-31 09:32:58 +00:00
|
|
|
use crate::debug_ui::display_object::DisplayObjectWindow;
|
2023-06-07 13:27:02 +00:00
|
|
|
use crate::debug_ui::handle::{AVM1ObjectHandle, AVM2ObjectHandle, DisplayObjectHandle};
|
2023-06-04 20:38:43 +00:00
|
|
|
use crate::debug_ui::movie::MovieWindow;
|
2023-06-01 22:28:27 +00:00
|
|
|
use crate::display_object::TDisplayObject;
|
2023-06-04 20:38:43 +00:00
|
|
|
use crate::tag_utils::SwfMovie;
|
2023-06-01 22:28:27 +00:00
|
|
|
use gc_arena::DynamicRootSet;
|
2023-05-31 09:32:58 +00:00
|
|
|
use hashbrown::HashMap;
|
2023-06-01 22:28:27 +00:00
|
|
|
use ruffle_render::commands::CommandHandler;
|
|
|
|
use ruffle_render::matrix::Matrix;
|
2023-06-07 21:31:44 +00:00
|
|
|
use std::fmt::{Debug, Formatter};
|
2023-06-04 20:38:43 +00:00
|
|
|
use std::sync::{Arc, Weak};
|
2023-06-01 23:07:53 +00:00
|
|
|
use swf::{Color, Rectangle, Twips};
|
2023-06-04 20:38:43 +00:00
|
|
|
use weak_table::PtrWeakKeyHashMap;
|
2023-05-31 09:32:58 +00:00
|
|
|
|
|
|
|
#[derive(Default)]
|
|
|
|
pub struct DebugUi {
|
|
|
|
display_objects: HashMap<DisplayObjectHandle, DisplayObjectWindow>,
|
2023-06-04 20:38:43 +00:00
|
|
|
movies: PtrWeakKeyHashMap<Weak<SwfMovie>, MovieWindow>,
|
2023-06-05 10:36:55 +00:00
|
|
|
avm1_objects: HashMap<AVM1ObjectHandle, Avm1ObjectWindow>,
|
2023-06-07 13:27:02 +00:00
|
|
|
avm2_objects: HashMap<AVM2ObjectHandle, Avm2ObjectWindow>,
|
2023-05-31 09:32:58 +00:00
|
|
|
queued_messages: Vec<Message>,
|
2023-06-07 21:31:44 +00:00
|
|
|
items_to_save: Vec<ItemToSave>,
|
2023-05-31 09:32:58 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Debug)]
|
|
|
|
pub enum Message {
|
|
|
|
TrackDisplayObject(DisplayObjectHandle),
|
2023-06-04 20:38:43 +00:00
|
|
|
TrackMovie(Arc<SwfMovie>),
|
2023-06-05 10:36:55 +00:00
|
|
|
TrackAVM1Object(AVM1ObjectHandle),
|
2023-06-07 13:27:02 +00:00
|
|
|
TrackAVM2Object(AVM2ObjectHandle),
|
2023-05-31 09:32:58 +00:00
|
|
|
TrackStage,
|
2023-06-04 20:38:43 +00:00
|
|
|
TrackTopLevelMovie,
|
2023-06-07 21:31:44 +00:00
|
|
|
SaveFile(ItemToSave),
|
2023-05-31 09:32:58 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
impl DebugUi {
|
2023-06-07 21:31:44 +00:00
|
|
|
pub(crate) fn show(&mut self, egui_ctx: &egui::Context, context: &mut UpdateContext) {
|
2023-05-31 09:32:58 +00:00
|
|
|
let mut messages = std::mem::take(&mut self.queued_messages);
|
2023-06-04 20:38:43 +00:00
|
|
|
|
2023-05-31 09:32:58 +00:00
|
|
|
self.display_objects.retain(|object, window| {
|
2023-06-01 22:28:27 +00:00
|
|
|
let object = object.fetch(context.dynamic_root);
|
2023-05-31 09:32:58 +00:00
|
|
|
window.show(egui_ctx, context, object, &mut messages)
|
|
|
|
});
|
2023-06-04 20:38:43 +00:00
|
|
|
|
2023-06-05 10:36:55 +00:00
|
|
|
self.avm1_objects.retain(|object, window| {
|
|
|
|
let object = object.fetch(context.dynamic_root);
|
|
|
|
window.show(egui_ctx, context, object, &mut messages)
|
|
|
|
});
|
|
|
|
|
2023-06-07 13:27:02 +00:00
|
|
|
self.avm2_objects.retain(|object, window| {
|
|
|
|
let object = object.fetch(context.dynamic_root);
|
|
|
|
window.show(egui_ctx, context, object, &mut messages)
|
|
|
|
});
|
|
|
|
|
2023-06-04 20:38:43 +00:00
|
|
|
self.movies
|
2023-06-07 21:31:44 +00:00
|
|
|
.retain(|movie, window| window.show(egui_ctx, context, movie, &mut messages));
|
2023-06-04 20:38:43 +00:00
|
|
|
|
2023-05-31 09:32:58 +00:00
|
|
|
for message in messages {
|
|
|
|
match message {
|
2023-06-07 21:31:44 +00:00
|
|
|
Message::TrackDisplayObject(object) => {
|
|
|
|
self.track_display_object(object);
|
|
|
|
}
|
2023-05-31 09:32:58 +00:00
|
|
|
Message::TrackStage => {
|
2023-06-07 21:31:44 +00:00
|
|
|
self.track_display_object(DisplayObjectHandle::new(context, context.stage));
|
2023-05-31 09:32:58 +00:00
|
|
|
}
|
2023-06-04 20:38:43 +00:00
|
|
|
Message::TrackMovie(movie) => {
|
|
|
|
self.movies.insert(movie, Default::default());
|
|
|
|
}
|
|
|
|
Message::TrackTopLevelMovie => {
|
|
|
|
self.movies.insert(context.swf.clone(), Default::default());
|
|
|
|
}
|
2023-06-05 10:36:55 +00:00
|
|
|
Message::TrackAVM1Object(object) => {
|
|
|
|
self.avm1_objects.insert(object, Default::default());
|
|
|
|
}
|
2023-06-07 13:27:02 +00:00
|
|
|
Message::TrackAVM2Object(object) => {
|
|
|
|
self.avm2_objects.insert(object, Default::default());
|
|
|
|
}
|
2023-06-07 21:31:44 +00:00
|
|
|
Message::SaveFile(file) => {
|
|
|
|
self.items_to_save.push(file);
|
|
|
|
}
|
2023-05-31 09:32:58 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-06-07 21:31:44 +00:00
|
|
|
pub fn items_to_save(&mut self) -> Vec<ItemToSave> {
|
|
|
|
std::mem::take(&mut self.items_to_save)
|
|
|
|
}
|
|
|
|
|
2023-05-31 09:32:58 +00:00
|
|
|
pub fn queue_message(&mut self, message: Message) {
|
|
|
|
self.queued_messages.push(message);
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn track_display_object(&mut self, handle: DisplayObjectHandle) {
|
|
|
|
self.display_objects.insert(handle, Default::default());
|
|
|
|
}
|
2023-06-01 22:28:27 +00:00
|
|
|
|
|
|
|
pub fn draw_debug_rects<'gc>(
|
|
|
|
&self,
|
|
|
|
context: &mut RenderContext<'_, 'gc>,
|
|
|
|
dynamic_root_set: DynamicRootSet<'gc>,
|
|
|
|
) {
|
|
|
|
let world_matrix = context.stage.view_matrix() * *context.stage.base().matrix();
|
|
|
|
|
|
|
|
for (object, window) in self.display_objects.iter() {
|
|
|
|
if let Some(color) = window.debug_rect_color() {
|
|
|
|
let object = object.fetch(dynamic_root_set);
|
|
|
|
let bounds = world_matrix * object.world_bounds();
|
|
|
|
|
2023-06-01 23:07:53 +00:00
|
|
|
draw_debug_rect(context, color, bounds, 3.0);
|
|
|
|
}
|
|
|
|
|
|
|
|
if let Some(object) = window.hovered_debug_rect() {
|
|
|
|
let object = object.fetch(dynamic_root_set);
|
|
|
|
let bounds = world_matrix * object.world_bounds();
|
|
|
|
|
|
|
|
draw_debug_rect(context, swf::Color::RED, bounds, 5.0);
|
2023-06-01 22:28:27 +00:00
|
|
|
}
|
|
|
|
}
|
2023-06-05 10:36:55 +00:00
|
|
|
|
|
|
|
for (_object, window) in self.avm1_objects.iter() {
|
|
|
|
if let Some(object) = window.hovered_debug_rect() {
|
|
|
|
let object = object.fetch(dynamic_root_set);
|
|
|
|
let bounds = world_matrix * object.world_bounds();
|
|
|
|
|
|
|
|
draw_debug_rect(context, swf::Color::RED, bounds, 5.0);
|
|
|
|
}
|
|
|
|
}
|
2023-06-07 13:27:02 +00:00
|
|
|
|
|
|
|
for (_object, window) in self.avm2_objects.iter() {
|
|
|
|
if let Some(object) = window.hovered_debug_rect() {
|
|
|
|
let object = object.fetch(dynamic_root_set);
|
|
|
|
let bounds = world_matrix * object.world_bounds();
|
|
|
|
|
|
|
|
draw_debug_rect(context, swf::Color::RED, bounds, 5.0);
|
|
|
|
}
|
|
|
|
}
|
2023-06-01 22:28:27 +00:00
|
|
|
}
|
2023-05-31 09:32:58 +00:00
|
|
|
}
|
2023-06-01 23:07:53 +00:00
|
|
|
|
2023-06-07 21:31:44 +00:00
|
|
|
pub struct ItemToSave {
|
|
|
|
pub suggested_name: String,
|
|
|
|
pub data: Vec<u8>,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Debug for ItemToSave {
|
|
|
|
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
|
|
|
f.debug_struct("ItemToSave")
|
|
|
|
.field("suggested_name", &self.suggested_name)
|
|
|
|
.field("data", &self.data.len())
|
|
|
|
.finish()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-06-01 23:07:53 +00:00
|
|
|
fn draw_debug_rect(
|
|
|
|
context: &mut RenderContext,
|
|
|
|
color: Color,
|
|
|
|
bounds: Rectangle<Twips>,
|
|
|
|
thickness: f32,
|
|
|
|
) {
|
|
|
|
let width = bounds.width().to_pixels() as f32;
|
|
|
|
let height = bounds.height().to_pixels() as f32;
|
|
|
|
let thickness_twips = Twips::from_pixels(thickness as f64);
|
|
|
|
|
|
|
|
// Top
|
|
|
|
context.commands.draw_rect(
|
|
|
|
color.clone(),
|
|
|
|
Matrix::create_box(
|
|
|
|
width,
|
|
|
|
thickness,
|
|
|
|
0.0,
|
|
|
|
bounds.x_min,
|
|
|
|
bounds.y_min - thickness_twips,
|
|
|
|
),
|
|
|
|
);
|
|
|
|
// Bottom
|
|
|
|
context.commands.draw_rect(
|
|
|
|
color.clone(),
|
|
|
|
Matrix::create_box(width, thickness, 0.0, bounds.x_min, bounds.y_max),
|
|
|
|
);
|
|
|
|
// Left
|
|
|
|
context.commands.draw_rect(
|
|
|
|
color.clone(),
|
|
|
|
Matrix::create_box(
|
|
|
|
thickness,
|
|
|
|
height,
|
|
|
|
0.0,
|
|
|
|
bounds.x_min - thickness_twips,
|
|
|
|
bounds.y_min,
|
|
|
|
),
|
|
|
|
);
|
|
|
|
// Right
|
|
|
|
context.commands.draw_rect(
|
|
|
|
color,
|
|
|
|
Matrix::create_box(thickness, height, 0.0, bounds.x_max, bounds.y_min),
|
|
|
|
);
|
|
|
|
}
|