From 0143d9716ea7ffc85338ae1282c0f7e1d7609390 Mon Sep 17 00:00:00 2001 From: Mike Welsh Date: Mon, 19 Aug 2019 07:53:12 -0700 Subject: [PATCH] core: Button work --- core/src/avm1.rs | 22 ++- core/src/button.rs | 99 ++++++++----- core/src/display_object.rs | 22 +-- core/src/event.rs | 21 --- core/src/events.rs | 31 ++++ core/src/lib.rs | 4 +- core/src/movie_clip.rs | 106 ++++++++----- core/src/player.rs | 296 ++++++++++++++++--------------------- desktop/src/main.rs | 8 +- 9 files changed, 318 insertions(+), 291 deletions(-) delete mode 100644 core/src/event.rs create mode 100644 core/src/events.rs diff --git a/core/src/avm1.rs b/core/src/avm1.rs index 845d46701..81f1bf262 100644 --- a/core/src/avm1.rs +++ b/core/src/avm1.rs @@ -162,6 +162,9 @@ impl Avm1 { root: DisplayNode<'gc>, mut path: &str, ) -> Option> { + if path == "/" { + log::warn!("ROOT"); + } let mut cur_clip = if path.bytes().nth(0).unwrap_or(0) == b'/' { path = &path[1..]; root @@ -771,8 +774,11 @@ impl Avm1 { fn play(&mut self, context: &mut ActionContext) -> Result<(), Error> { let mut display_object = context.active_clip.write(context.gc_context); - let clip = display_object.as_movie_clip_mut().unwrap(); - clip.play(); + if let Some(clip) = display_object.as_movie_clip_mut() { + clip.play() + } else { + log::warn!("Play failed: Not a MovieClip"); + } Ok(()) } @@ -909,6 +915,7 @@ impl Avm1 { } else if let Some(clip) = Avm1::resolve_slash_path(context.start_clip, context.root, target) { + log::warn!("Path: {}", target); context.active_clip = clip; } else { log::warn!("SetTarget failed: {} not found", target); @@ -931,8 +938,15 @@ impl Avm1 { fn action_stop(&mut self, context: &mut ActionContext) -> Result<(), Error> { let mut display_object = context.active_clip.write(context.gc_context); - let clip = display_object.as_movie_clip_mut().unwrap(); - clip.stop(); + if let None = display_object.as_movie_clip_mut() { + log::warn!("NO"); + } + + if let Some(clip) = display_object.as_movie_clip_mut() { + clip.stop(); + } else { + log::warn!("Stop failed: Not a MovieClip"); + } Ok(()) } diff --git a/core/src/button.rs b/core/src/button.rs index 228fec904..cc8b8755c 100644 --- a/core/src/button.rs +++ b/core/src/button.rs @@ -1,5 +1,5 @@ use crate::display_object::{DisplayObject, DisplayObjectBase}; -use crate::event::ClipEvent; +use crate::events::ButtonEvent; use crate::player::{RenderContext, UpdateContext}; use crate::prelude::*; use std::collections::BTreeMap; @@ -113,18 +113,53 @@ impl<'gc> Button<'gc> { self.children[i].values_mut() } + pub fn handle_button_event( + &mut self, + context: &mut crate::player::UpdateContext<'_, 'gc, '_>, + event: ButtonEvent, + ) { + let new_state = match event { + ButtonEvent::RollOut => ButtonState::Up, + ButtonEvent::RollOver => ButtonState::Over, + ButtonEvent::Press => ButtonState::Down, + ButtonEvent::Release => ButtonState::Over, + ButtonEvent::KeyPress(key) => { + self.run_actions(context, swf::ButtonActionCondition::KeyPress, Some(key)); + self.state + } + }; + + match (self.state, new_state) { + (ButtonState::Up, ButtonState::Over) => { + self.run_actions(context, swf::ButtonActionCondition::IdleToOverUp, None); + } + (ButtonState::Over, ButtonState::Up) => { + self.run_actions(context, swf::ButtonActionCondition::OverUpToIdle, None); + } + (ButtonState::Over, ButtonState::Down) => { + self.run_actions(context, swf::ButtonActionCondition::OverUpToOverDown, None); + } + (ButtonState::Down, ButtonState::Over) => { + self.run_actions(context, swf::ButtonActionCondition::OverDownToOverUp, None); + } + _ => (), + } + + self.state = new_state; + } + fn run_actions( &mut self, context: &mut UpdateContext<'_, 'gc, '_>, condition: swf::ButtonActionCondition, key_code: Option, ) { - for action in &self.static_data.actions { - if action.condition == condition && action.key_code == key_code { - // Note that AVM1 buttons run actions relative to their parent, not themselves. - context - .actions - .push((self.parent().unwrap(), action.action_data.clone())); + if let Some(parent) = self.parent() { + for action in &self.static_data.actions { + if action.condition == condition && action.key_code == key_code { + // Note that AVM1 buttons run actions relative to their parent, not themselves. + context.actions.push((parent, action.action_data.clone())); + } } } } @@ -180,45 +215,29 @@ impl<'gc> DisplayObject<'gc> for Button<'gc> { return true; } } - //} false } - fn handle_event( - &mut self, - context: &mut crate::player::UpdateContext<'_, 'gc, '_>, - event: ClipEvent, - ) { - let new_state = match event { - ClipEvent::RollOut => ButtonState::Up, - ClipEvent::RollOver => ButtonState::Over, - ClipEvent::Press => ButtonState::Down, - ClipEvent::Release => ButtonState::Over, - ClipEvent::KeyPress(key) => { - self.run_actions(context, swf::ButtonActionCondition::KeyPress, Some(key)); - self.state - } - _ => self.state, - }; - - match (self.state, new_state) { - (ButtonState::Up, ButtonState::Over) => { - self.run_actions(context, swf::ButtonActionCondition::IdleToOverUp, None); - } - (ButtonState::Over, ButtonState::Up) => { - self.run_actions(context, swf::ButtonActionCondition::OverUpToIdle, None); - } - (ButtonState::Over, ButtonState::Down) => { - self.run_actions(context, swf::ButtonActionCondition::OverUpToOverDown, None); - } - (ButtonState::Down, ButtonState::Over) => { - self.run_actions(context, swf::ButtonActionCondition::OverDownToOverUp, None); - } - _ => (), + fn mouse_pick( + &self, + self_node: DisplayNode<'gc>, + point: (Twips, Twips), + ) -> Option> { + // The button is hovered if the mouse is over any child nodes. + if self.hit_test(point) { + Some(self_node) + } else { + None } + } - self.state = new_state; + fn as_button(&self) -> Option<&Self> { + Some(self) + } + + fn as_button_mut(&mut self) -> Option<&mut Self> { + Some(self) } } diff --git a/core/src/display_object.rs b/core/src/display_object.rs index 317f2d469..020bfda4b 100644 --- a/core/src/display_object.rs +++ b/core/src/display_object.rs @@ -95,7 +95,12 @@ pub trait DisplayObject<'gc>: 'gc + Collect { fn run_post_frame(&mut self, _context: &mut UpdateContext<'_, 'gc, '_>) {} fn render(&self, _context: &mut RenderContext<'_, 'gc>) {} - fn handle_click(&mut self, _pos: (f32, f32)) {} + fn as_button(&self) -> Option<&crate::button::Button<'gc>> { + None + } + fn as_button_mut(&mut self) -> Option<&mut crate::button::Button<'gc>> { + None + } fn as_movie_clip(&self) -> Option<&crate::movie_clip::MovieClip<'gc>> { None } @@ -110,19 +115,16 @@ pub trait DisplayObject<'gc>: 'gc + Collect { } fn box_clone(&self) -> Box>; - fn pick(&self, _: (Twips, Twips)) -> Option> { - None - } - fn hit_test(&self, _: (Twips, Twips)) -> bool { false } - fn handle_event( - &mut self, - _context: &mut crate::player::UpdateContext<'_, 'gc, '_>, - _event: crate::event::ClipEvent, - ) { + fn mouse_pick( + &self, + _self_node: DisplayNode<'gc>, + _: (Twips, Twips), + ) -> Option> { + None } } diff --git a/core/src/event.rs b/core/src/event.rs deleted file mode 100644 index 99b7073c4..000000000 --- a/core/src/event.rs +++ /dev/null @@ -1,21 +0,0 @@ -use swf::Twips; - -#[allow(clippy::enum_variant_names)] -#[derive(Debug)] -pub enum Event { - MouseMove { x: Twips, y: Twips }, - MouseUp { x: Twips, y: Twips }, - MouseDown { x: Twips, y: Twips }, - MouseLeft, -} - -#[derive(Debug)] -pub enum ClipEvent { - Press, - Release, - RollOut, - RollOver, - KeyPress(KeyCode), -} - -type KeyCode = u8; \ No newline at end of file diff --git a/core/src/events.rs b/core/src/events.rs new file mode 100644 index 000000000..ad65f72d9 --- /dev/null +++ b/core/src/events.rs @@ -0,0 +1,31 @@ +use swf::Twips; + +#[allow(clippy::enum_variant_names)] +#[derive(Debug)] +pub enum PlayerEvent { + MouseMove { x: Twips, y: Twips }, + MouseUp { x: Twips, y: Twips }, + MouseDown { x: Twips, y: Twips }, + MouseLeft, +} + +/// The events that an AVM1 button can fire. +/// +/// In Flash, these are created using `on` code on the button instance: +/// ```ignore +/// on(release) { +/// trace("Button clicked"); +/// } +/// ``` +#[derive(Debug)] +pub enum ButtonEvent { + Press, + Release, + RollOut, + RollOver, + KeyPress(KeyCode), +} + +/// Flash virtual keycode. +/// TODO: This will eventually move to a separate module. +pub type KeyCode = u8; diff --git a/core/src/lib.rs b/core/src/lib.rs index 4af88ffcd..311fb8431 100644 --- a/core/src/lib.rs +++ b/core/src/lib.rs @@ -6,7 +6,7 @@ mod bounding_box; mod button; mod character; mod color_transform; -mod event; +mod events; mod font; mod graphic; mod library; @@ -22,7 +22,7 @@ mod transform; pub mod backend; -pub use event::Event; +pub use events::PlayerEvent; pub use player::Player; pub use swf; pub use swf::Color; diff --git a/core/src/movie_clip.rs b/core/src/movie_clip.rs index b2d1a0805..afa068bf5 100644 --- a/core/src/movie_clip.rs +++ b/core/src/movie_clip.rs @@ -55,14 +55,17 @@ impl<'gc> MovieClip<'gc> { ) -> Self { Self { base: Default::default(), - static_data: Gc::allocate(gc_context, MovieClipStatic { - id, - tag_stream_start, - tag_stream_len, - total_frames: num_frames, - audio_stream_info: None, - frame_labels: HashMap::new(), - }), + static_data: Gc::allocate( + gc_context, + MovieClipStatic { + id, + tag_stream_start, + tag_stream_len, + total_frames: num_frames, + audio_stream_info: None, + frame_labels: HashMap::new(), + }, + ), tag_stream_pos: 0, is_playing: true, goto_queue: Vec::new(), @@ -170,7 +173,7 @@ impl<'gc> MovieClip<'gc> { c: scale_y * cos, d: -scale_y * sin, tx: matrix.tx, - ty: matrix.ty, + ty: matrix.ty, }; } @@ -186,10 +189,7 @@ impl<'gc> MovieClip<'gc> { .find(|child| child.read().name() == name) } - pub fn frame_label_to_number( - &self, - frame_label: &str, - ) -> Option { + pub fn frame_label_to_number(&self, frame_label: &str) -> Option { self.static_data.frame_labels.get(frame_label).copied() } @@ -224,7 +224,10 @@ impl<'gc> MovieClip<'gc> { pub fn get_variable(&self, var_name: &str) -> avm1::Value { // TODO: Value should be Copy (and contain a Cow/GcCell for big objects) - self.variables.get(var_name).unwrap_or(&avm1::Value::Undefined).clone() + self.variables + .get(var_name) + .unwrap_or(&avm1::Value::Undefined) + .clone() } pub fn set_variable(&mut self, var_name: &str, value: avm1::Value) { @@ -338,17 +341,31 @@ impl<'gc> DisplayObject<'gc> for MovieClip<'gc> { TagCode::DefineSound => self.define_sound(context, reader, tag_len), TagCode::DefineSprite => self.define_sprite(context, reader, tag_len), TagCode::DefineText => self.define_text(context, reader), - TagCode::FrameLabel => self.frame_label(context, reader, tag_len, cur_frame, &mut static_data), + TagCode::FrameLabel => { + self.frame_label(context, reader, tag_len, cur_frame, &mut static_data) + } TagCode::JpegTables => self.jpeg_tables(context, reader, tag_len), - TagCode::PlaceObject => self.preload_place_object(context, reader, tag_len, &mut ids, 1), - TagCode::PlaceObject2 => self.preload_place_object(context, reader, tag_len, &mut ids, 2), - TagCode::PlaceObject3 => self.preload_place_object(context, reader, tag_len, &mut ids, 3), - TagCode::PlaceObject4 => self.preload_place_object(context, reader, tag_len, &mut ids, 4), + TagCode::PlaceObject => { + self.preload_place_object(context, reader, tag_len, &mut ids, 1) + } + TagCode::PlaceObject2 => { + self.preload_place_object(context, reader, tag_len, &mut ids, 2) + } + TagCode::PlaceObject3 => { + self.preload_place_object(context, reader, tag_len, &mut ids, 3) + } + TagCode::PlaceObject4 => { + self.preload_place_object(context, reader, tag_len, &mut ids, 4) + } TagCode::RemoveObject => self.preload_remove_object(context, reader, &mut ids, 1), TagCode::RemoveObject2 => self.preload_remove_object(context, reader, &mut ids, 2), TagCode::ShowFrame => self.preload_show_frame(context, reader, &mut cur_frame), - TagCode::SoundStreamHead => self.preload_sound_stream_head(context, reader, &mut static_data, 1), - TagCode::SoundStreamHead2 => self.preload_sound_stream_head(context, reader, &mut static_data, 2), + TagCode::SoundStreamHead => { + self.preload_sound_stream_head(context, reader, &mut static_data, 1) + } + TagCode::SoundStreamHead2 => { + self.preload_sound_stream_head(context, reader, &mut static_data, 2) + } TagCode::SoundStreamBlock => self.preload_sound_stream_block(context, reader, tag_len), _ => Ok(()), }; @@ -391,19 +408,17 @@ impl<'gc> DisplayObject<'gc> for MovieClip<'gc> { context.transform_stack.pop(); } - fn pick(&self, point: (Twips, Twips)) -> Option> { - //if self.world_bounds().contains(point) { - for child in self.children.values().rev() { - if child.read().hit_test(point) { - return Some(*child); - } - - let button = child.read().pick(point); - if button.is_some() { - return button; + fn mouse_pick( + &self, + _self_node: DisplayNode<'gc>, + point: (Twips, Twips), + ) -> Option> { + for child in self.children.values() { + let result = child.read().mouse_pick(*child, point); + if result.is_some() { + return result; } } - //} None } @@ -794,8 +809,13 @@ impl<'gc, 'a> MovieClip<'gc> { ) -> DecodeResult { let id = reader.read_character_id()?; let num_frames = reader.read_u16()?; - let mut movie_clip = - MovieClip::new_with_data(context.gc_context, id, reader.get_ref().position(), tag_len - 4, num_frames); + let mut movie_clip = MovieClip::new_with_data( + context.gc_context, + id, + reader.get_ref().position(), + tag_len - 4, + num_frames, + ); movie_clip.preload(context); @@ -830,7 +850,11 @@ impl<'gc, 'a> MovieClip<'gc> { static_data: &mut MovieClipStatic, ) -> DecodeResult { let frame_label = reader.read_frame_label(tag_len)?; - if static_data.frame_labels.insert(frame_label.label, cur_frame).is_some() { + if static_data + .frame_labels + .insert(frame_label.label, cur_frame) + .is_some() + { log::warn!("Movie clip {}: Duplicated frame label", self.id()); } Ok(()) @@ -910,7 +934,7 @@ impl<'gc, 'a> MovieClip<'gc> { &mut self, context: &mut UpdateContext<'_, 'gc, '_>, reader: &mut SwfStream<&'a [u8]>, - tag_len: usize, + tag_len: usize, version: u8, ) -> DecodeResult { let place_object = if version == 1 { @@ -1007,7 +1031,7 @@ impl<'gc, 'a> MovieClip<'gc> { #[inline] fn remove_object( &mut self, - _context: &mut UpdateContext<'_, 'gc, '_>, + context: &mut UpdateContext<'_, 'gc, '_>, reader: &mut SwfStream<&'a [u8]>, version: u8, ) -> DecodeResult { @@ -1016,7 +1040,9 @@ impl<'gc, 'a> MovieClip<'gc> { } else { reader.read_remove_object_2() }?; - self.children.remove(&remove_object.depth); + if let Some(child) = self.children.remove(&remove_object.depth) { + child.write(context.gc_context).set_parent(None); + } Ok(()) } @@ -1036,7 +1062,8 @@ impl<'gc, 'a> MovieClip<'gc> { context: &mut UpdateContext<'_, 'gc, '_>, _reader: &mut SwfStream<&'a [u8]>, ) -> DecodeResult { - if let (Some(stream_info), None) = (&self.static_data.audio_stream_info, &self.audio_stream) { + if let (Some(stream_info), None) = (&self.static_data.audio_stream_info, &self.audio_stream) + { let slice = crate::tag_utils::SwfSlice { data: std::sync::Arc::clone(context.swf_data), start: self.tag_stream_start() as usize, @@ -1063,7 +1090,6 @@ impl<'gc, 'a> MovieClip<'gc> { } } - /// Static data shared between all instances of a movie clip. #[allow(dead_code)] #[derive(Clone)] diff --git a/core/src/player.rs b/core/src/player.rs index eb0531fa3..a8c41b2f7 100644 --- a/core/src/player.rs +++ b/core/src/player.rs @@ -1,6 +1,6 @@ use crate::avm1::Avm1; use crate::backend::{audio::AudioBackend, render::RenderBackend}; -use crate::event::{ClipEvent, Event}; +use crate::events::{ButtonEvent, PlayerEvent}; use crate::library::Library; use crate::movie_clip::MovieClip; use crate::prelude::*; @@ -155,9 +155,20 @@ impl Player { self.movie_height } - pub fn handle_event(&mut self, event: Event) { + pub fn handle_event(&mut self, event: PlayerEvent) { let mut needs_render = false; + // Update mouse position from mouse events. + if let PlayerEvent::MouseMove { x, y } + | PlayerEvent::MouseDown { x, y } + | PlayerEvent::MouseUp { x, y } = event + { + self.mouse_pos = (x, y); + if self.update_roll_over() { + needs_render = true; + } + } + let ( global_time, swf_data, @@ -166,7 +177,6 @@ impl Player { renderer, audio, avm, - mouse_pos, is_mouse_down, ) = ( self.global_time, @@ -176,101 +186,62 @@ impl Player { &mut self.renderer, &mut self.audio, &mut self.avm, - &mut self.mouse_pos, &mut self.is_mouse_down, ); - let mut needs_mouse_update = false; self.gc_arena.mutate(|gc_context, gc_root| { - let actions = { - let mut update_context = UpdateContext { - global_time, - swf_data, - swf_version, - library: gc_root.library.write(gc_context), - background_color, - avm, - renderer, - audio, - actions: vec![], - gc_context, - active_clip: gc_root.root, - }; - - match event { - Event::MouseMove { x, y } => { - *mouse_pos = (x, y); - needs_mouse_update = true; - } - Event::MouseLeft => { - // TODO: Just setting to a bogus value for now. - *mouse_pos = (Twips::new(std::i32::MAX), Twips::new(std::i32::MAX)); - needs_mouse_update = true; - } - Event::MouseDown { x, y } => { - *mouse_pos = (x, y); - *is_mouse_down = true; - needs_render = true; - if let Some(node) = &*gc_root.mouse_hover_node.read() { - update_context.active_clip = *node; - node.write(gc_context) - .handle_event(&mut update_context, ClipEvent::Press); - } - } - Event::MouseUp { x, y } => { - *mouse_pos = (x, y); - *is_mouse_down = false; - needs_render = true; - if let Some(node) = &*gc_root.mouse_hover_node.read() { - if gc_root.root.read().pick(*mouse_pos).map(GcCell::as_ptr) - == Some(node.as_ptr()) - { - update_context.active_clip = *node; - node.write(gc_context) - .handle_event(&mut update_context, ClipEvent::Release); - } - } - needs_mouse_update = true; - } - _ => (), - } - update_context.actions + let mut update_context = UpdateContext { + global_time, + swf_data, + swf_version, + library: gc_root.library.write(gc_context), + background_color, + avm, + renderer, + audio, + actions: vec![], + gc_context, + active_clip: gc_root.root, }; - if !actions.is_empty() { - let mut action_context = crate::avm1::ActionContext { - gc_context, - global_time, - root: gc_root.root, - start_clip: gc_root.root, - active_clip: gc_root.root, - audio, - }; - for (active_clip, action) in actions { - action_context.start_clip = active_clip; - action_context.active_clip = active_clip; - let _ = avm.do_action(&mut action_context, action.as_ref()); + if let Some(node) = &*gc_root.mouse_hover_node.read() { + if let Some(button) = node.write(gc_context).as_button_mut() { + match event { + PlayerEvent::MouseDown { .. } => { + *is_mouse_down = true; + needs_render = true; + update_context.active_clip = *node; + button.handle_button_event(&mut update_context, ButtonEvent::Press); + } + + PlayerEvent::MouseUp { .. } => { + *is_mouse_down = false; + needs_render = true; + update_context.active_clip = *node; + button.handle_button_event(&mut update_context, ButtonEvent::Release); + } + + _ => (), + } } } + + Self::run_actions(&mut update_context, gc_root.root); }); - if needs_mouse_update && self.update_mouse() { - needs_render = true; - } - if needs_render { + // Update display after mouse events. self.render(); } } - fn update_mouse(&mut self) -> bool { - // Don't update roll-over state when mouse is down. - // TODO: This depends on button tracking. + fn update_roll_over(&mut self) -> bool { + // TODO: While the mouse is down, maintain the hovered node. if self.is_mouse_down { return false; } - let (global_time, swf_data, swf_version, background_color, renderer, audio, avm, mouse_pos) = ( + let (global_time, swf_data, swf_version, background_color, renderer, audio, avm) = ( self.global_time, &mut self.swf_data, self.swf_version, @@ -278,17 +249,17 @@ impl Player { &mut self.renderer, &mut self.audio, &mut self.avm, - self.mouse_pos, ); - let hover_changed = self.gc_arena.mutate(|gc_context, gc_root| { - // Updare hovered display object. - let new_hover_node = gc_root.root.read().pick(mouse_pos); - // Check if the hovered object has changed. - // TODO: Yuck... what's the best way to determine if the pointers are the same? - if gc_root.mouse_hover_node.read().map(GcCell::as_ptr) - != new_hover_node.map(GcCell::as_ptr) - { + let mouse_pos = &self.mouse_pos; + // Check hovered object. + self.gc_arena.mutate(|gc_context, gc_root| { + let new_hover_node = gc_root + .root + .read() + .mouse_pick(gc_root.root, (mouse_pos.0, mouse_pos.1)); + let mut cur_hover_node = gc_root.mouse_hover_node.write(gc_context); + if cur_hover_node.map(GcCell::as_ptr) != new_hover_node.map(GcCell::as_ptr) { let mut update_context = UpdateContext { global_time, swf_data, @@ -303,30 +274,30 @@ impl Player { active_clip: gc_root.root, }; - // Fire rollOut event for previous object. - if let Some(node) = &*gc_root.mouse_hover_node.write(gc_context) { - update_context.active_clip = *node; - node.write(gc_context) - .handle_event(&mut update_context, ClipEvent::RollOut); + // RollOut of previous node. + if let Some(node) = &*cur_hover_node { + if let Some(button) = node.write(gc_context).as_button_mut() { + update_context.active_clip = *node; + button.handle_button_event(&mut update_context, ButtonEvent::RollOut); + } } - *gc_root.mouse_hover_node.write(gc_context) = new_hover_node; - - // Fire rollOver event for new object. + // RollOver on new node. if let Some(node) = new_hover_node { - update_context.active_clip = node; - node.write(gc_context) - .handle_event(&mut update_context, ClipEvent::RollOver); + if let Some(button) = node.write(gc_context).as_button_mut() { + update_context.active_clip = node; + button.handle_button_event(&mut update_context, ButtonEvent::RollOver); + } } + *cur_hover_node = new_hover_node; + + Self::run_actions(&mut update_context, gc_root.root); true } else { false } - }); - - // TODO: render - hover_changed + }) } fn preload(&mut self) { @@ -371,79 +342,30 @@ impl Player { ); self.gc_arena.mutate(|gc_context, gc_root| { - let mut actions = { - let mut update_context = UpdateContext { - global_time, - swf_data, - swf_version, - library: gc_root.library.write(gc_context), - background_color, - avm, - renderer, - audio, - actions: vec![], - gc_context, - active_clip: gc_root.root, - }; - - gc_root - .root - .write(gc_context) - .run_frame(&mut update_context); - update_context.actions + let mut update_context = UpdateContext { + global_time, + swf_data, + swf_version, + library: gc_root.library.write(gc_context), + background_color, + avm, + renderer, + audio, + actions: vec![], + gc_context, + active_clip: gc_root.root, }; - // TODO: Loop here because goto-ing a frame can queue up for actions. - // Need to figure out the proper order of operations between ticking a clip - // and running the actions. - loop { - { - let mut action_context = crate::avm1::ActionContext { - gc_context, - global_time, - root: gc_root.root, - start_clip: gc_root.root, - active_clip: gc_root.root, - audio, - }; - for (active_clip, action) in actions { - action_context.start_clip = active_clip; - action_context.active_clip = active_clip; - let _ = avm.do_action(&mut action_context, action.as_ref()); - } - } + gc_root + .root + .write(gc_context) + .run_frame(&mut update_context); - actions = { - let mut update_context = UpdateContext { - global_time, - swf_data, - swf_version, - library: gc_root.library.write(gc_context), - background_color, - avm, - renderer, - audio, - actions: vec![], - gc_context, - active_clip: gc_root.root, - }; - - gc_root - .root - .write(gc_context) - .run_post_frame(&mut update_context); - - update_context.actions - }; - - if actions.is_empty() { - break; - } - } + Self::run_actions(&mut update_context, gc_root.root); }); // Update mouse state (check for new hovered button, etc.) - self.update_mouse(); + self.update_roll_over(); } pub fn render(&mut self) { @@ -484,6 +406,40 @@ impl Player { pub fn renderer_mut(&mut self) -> &mut Renderer { &mut self.renderer } + + fn run_actions<'gc>(update_context: &mut UpdateContext<'_, 'gc, '_>, root: DisplayNode<'gc>) { + // TODO: Loop here because goto-ing a frame can queue up for actions. + // I think this will eventually be cleaned up; + // Need to figure out the proper order of operations between ticking a clip + // and running the actions. + let mut actions = std::mem::replace(&mut update_context.actions, vec![]); + while !actions.is_empty() { + { + let mut action_context = crate::avm1::ActionContext { + gc_context: update_context.gc_context, + global_time: update_context.global_time, + root, + start_clip: root, + active_clip: root, + audio: update_context.audio, + }; + for (active_clip, action) in actions { + action_context.start_clip = active_clip; + action_context.active_clip = active_clip; + let _ = update_context + .avm + .do_action(&mut action_context, action.as_ref()); + } + } + + // Run goto queues. + update_context.active_clip = root; + root.write(update_context.gc_context) + .run_post_frame(update_context); + + actions = std::mem::replace(&mut update_context.actions, vec![]); + } + } } pub struct UpdateContext<'a, 'gc, 'gc_context> { diff --git a/desktop/src/main.rs b/desktop/src/main.rs index 8284ae795..4f5feec3f 100644 --- a/desktop/src/main.rs +++ b/desktop/src/main.rs @@ -75,7 +75,7 @@ fn run_player(input_path: PathBuf) -> Result<(), Box> { } WindowEvent::CursorMoved { position, .. } => { mouse_pos = position; - let event = ruffle_core::Event::MouseMove { + let event = ruffle_core::PlayerEvent::MouseMove { x: Twips::from_pixels(position.x), y: Twips::from_pixels(position.y), }; @@ -87,12 +87,12 @@ fn run_player(input_path: PathBuf) -> Result<(), Box> { .. } => { let event = if pressed == ElementState::Pressed { - ruffle_core::Event::MouseDown { + ruffle_core::PlayerEvent::MouseDown { x: Twips::from_pixels(mouse_pos.x), y: Twips::from_pixels(mouse_pos.y), } } else { - ruffle_core::Event::MouseUp { + ruffle_core::PlayerEvent::MouseUp { x: Twips::from_pixels(mouse_pos.x), y: Twips::from_pixels(mouse_pos.y), } @@ -100,7 +100,7 @@ fn run_player(input_path: PathBuf) -> Result<(), Box> { player.handle_event(event); } WindowEvent::CursorLeft { .. } => { - player.handle_event(ruffle_core::Event::MouseLeft) + player.handle_event(ruffle_core::PlayerEvent::MouseLeft) } WindowEvent::CloseRequested => request_close = true, _ => (),