core: Move most of the player rendering code into the `Stage`'s render method.

This commit is contained in:
David Wendt 2021-04-16 17:55:57 -04:00 committed by Mike Welsh
parent 44af21b398
commit 67724bfc71
7 changed files with 268 additions and 190 deletions

View File

@ -877,7 +877,6 @@ mod tests {
audio: &mut NullAudioBackend::new(), audio: &mut NullAudioBackend::new(),
audio_manager: &mut AudioManager::new(), audio_manager: &mut AudioManager::new(),
ui: &mut NullUiBackend::new(), ui: &mut NullUiBackend::new(),
background_color: &mut None,
library: &mut Library::empty(gc_context), library: &mut Library::empty(gc_context),
navigator: &mut NullNavigatorBackend::new(), navigator: &mut NullNavigatorBackend::new(),
renderer: &mut NullRenderer::new(), renderer: &mut NullRenderer::new(),
@ -888,6 +887,7 @@ mod tests {
mouse_position: &(Twips::zero(), Twips::zero()), mouse_position: &(Twips::zero(), Twips::zero()),
drag_object: &mut None, drag_object: &mut None,
stage_size: (Twips::from_pixels(550.0), Twips::from_pixels(400.0)), stage_size: (Twips::from_pixels(550.0), Twips::from_pixels(400.0)),
viewport_size: (Twips::from_pixels(550.0), Twips::from_pixels(400.0)),
player: None, player: None,
load_manager: &mut LoadManager::new(), load_manager: &mut LoadManager::new(),
system: &mut SystemProperties::default(), system: &mut SystemProperties::default(),

View File

@ -52,7 +52,6 @@ where
audio: &mut NullAudioBackend::new(), audio: &mut NullAudioBackend::new(),
ui: &mut NullUiBackend::new(), ui: &mut NullUiBackend::new(),
action_queue: &mut ActionQueue::new(), action_queue: &mut ActionQueue::new(),
background_color: &mut None,
library: &mut Library::empty(gc_context), library: &mut Library::empty(gc_context),
navigator: &mut NullNavigatorBackend::new(), navigator: &mut NullNavigatorBackend::new(),
renderer: &mut NullRenderer::new(), renderer: &mut NullRenderer::new(),
@ -63,6 +62,7 @@ where
mouse_position: &(Twips::zero(), Twips::zero()), mouse_position: &(Twips::zero(), Twips::zero()),
drag_object: &mut None, drag_object: &mut None,
stage_size: (Twips::from_pixels(550.0), Twips::from_pixels(400.0)), stage_size: (Twips::from_pixels(550.0), Twips::from_pixels(400.0)),
viewport_size: (Twips::from_pixels(550.0), Twips::from_pixels(400.0)),
player: None, player: None,
load_manager: &mut LoadManager::new(), load_manager: &mut LoadManager::new(),
system: &mut SystemProperties::default(), system: &mut SystemProperties::default(),

View File

@ -38,10 +38,6 @@ pub struct UpdateContext<'a, 'gc, 'gc_context> {
/// Display objects and actions can push actions onto the queue. /// Display objects and actions can push actions onto the queue.
pub action_queue: &'a mut ActionQueue<'gc>, pub action_queue: &'a mut ActionQueue<'gc>,
/// The background color of the Stage. Changed by the `SetBackgroundColor` SWF tag.
/// TODO: Move this into a `Stage` display object.
pub background_color: &'a mut Option<Color>,
/// The mutation context to allocate and mutate `GcCell` types. /// The mutation context to allocate and mutate `GcCell` types.
pub gc_context: MutationContext<'gc, 'gc_context>, pub gc_context: MutationContext<'gc, 'gc_context>,
@ -107,6 +103,9 @@ pub struct UpdateContext<'a, 'gc, 'gc_context> {
/// The dimensions of the stage. /// The dimensions of the stage.
pub stage_size: (Twips, Twips), pub stage_size: (Twips, Twips),
/// The dimensions of the stage's containing viewport.
pub viewport_size: (Twips, Twips),
/// Weak reference to the player. /// Weak reference to the player.
/// ///
/// Recipients of an update context may upgrade the reference to ensure /// Recipients of an update context may upgrade the reference to ensure
@ -250,7 +249,6 @@ impl<'a, 'gc, 'gc_context> UpdateContext<'a, 'gc, 'gc_context> {
{ {
UpdateContext { UpdateContext {
action_queue: self.action_queue, action_queue: self.action_queue,
background_color: self.background_color,
gc_context: self.gc_context, gc_context: self.gc_context,
library: self.library, library: self.library,
player_version: self.player_version, player_version: self.player_version,
@ -271,6 +269,7 @@ impl<'a, 'gc, 'gc_context> UpdateContext<'a, 'gc, 'gc_context> {
mouse_position: self.mouse_position, mouse_position: self.mouse_position,
drag_object: self.drag_object, drag_object: self.drag_object,
stage_size: self.stage_size, stage_size: self.stage_size,
viewport_size: self.viewport_size,
player: self.player.clone(), player: self.player.clone(),
load_manager: self.load_manager, load_manager: self.load_manager,
system: self.system, system: self.system,
@ -370,11 +369,18 @@ pub struct RenderContext<'a, 'gc> {
/// The renderer, used by the display objects to draw themselves. /// The renderer, used by the display objects to draw themselves.
pub renderer: &'a mut dyn RenderBackend, pub renderer: &'a mut dyn RenderBackend,
/// The UI backend, used to detect user interactions.
pub ui: &'a mut dyn UiBackend,
/// The library, which provides access to fonts and other definitions when rendering. /// The library, which provides access to fonts and other definitions when rendering.
pub library: &'a Library<'gc>, pub library: &'a Library<'gc>,
/// The transform stack controls the matrix and color transform as we traverse the display hierarchy. /// The transform stack controls the matrix and color transform as we traverse the display hierarchy.
pub transform_stack: &'a mut TransformStack, pub transform_stack: &'a mut TransformStack,
/// The dimensions of the stage's containing viewport.
pub viewport_bounds: (Twips, Twips),
/// The bounds of the current viewport in twips. Used for culling. /// The bounds of the current viewport in twips. Used for culling.
pub view_bounds: BoundingBox, pub view_bounds: BoundingBox,

View File

@ -427,6 +427,39 @@ impl<'gc> DisplayObjectBase<'gc> {
} }
} }
pub fn render_base<'gc>(this: DisplayObject<'gc>, context: &mut RenderContext<'_, 'gc>) {
if this.maskee().is_some() {
return;
}
context.transform_stack.push(&*this.transform());
let mask = this.masker();
let mut mask_transform = crate::transform::Transform::default();
if let Some(m) = mask {
mask_transform.matrix = this.global_to_local_matrix();
mask_transform.matrix *= m.local_to_global_matrix();
context.renderer.push_mask();
context.allow_mask = false;
context.transform_stack.push(&mask_transform);
m.render_self(context);
context.transform_stack.pop();
context.allow_mask = true;
context.renderer.activate_mask();
}
this.render_self(context);
if let Some(m) = mask {
context.renderer.deactivate_mask();
context.allow_mask = false;
context.transform_stack.push(&mask_transform);
m.render_self(context);
context.transform_stack.pop();
context.allow_mask = true;
context.renderer.pop_mask();
}
context.transform_stack.pop();
}
#[enum_trait_object( #[enum_trait_object(
#[derive(Clone, Collect, Debug, Copy)] #[derive(Clone, Collect, Debug, Copy)]
#[collect(no_drop)] #[collect(no_drop)]
@ -933,36 +966,7 @@ pub trait TDisplayObject<'gc>:
fn render_self(&self, _context: &mut RenderContext<'_, 'gc>) {} fn render_self(&self, _context: &mut RenderContext<'_, 'gc>) {}
fn render(&self, context: &mut RenderContext<'_, 'gc>) { fn render(&self, context: &mut RenderContext<'_, 'gc>) {
if self.maskee().is_some() { render_base((*self).into(), context)
return;
}
context.transform_stack.push(&*self.transform());
let mask = self.masker();
let mut mask_transform = crate::transform::Transform::default();
if let Some(m) = mask {
mask_transform.matrix = self.global_to_local_matrix();
mask_transform.matrix *= m.local_to_global_matrix();
context.renderer.push_mask();
context.allow_mask = false;
context.transform_stack.push(&mask_transform);
m.render_self(context);
context.transform_stack.pop();
context.allow_mask = true;
context.renderer.activate_mask();
}
self.render_self(context);
if let Some(m) = mask {
context.renderer.deactivate_mask();
context.allow_mask = false;
context.transform_stack.push(&mask_transform);
m.render_self(context);
context.transform_stack.pop();
context.allow_mask = true;
context.renderer.pop_mask();
}
context.transform_stack.pop();
} }
fn unload(&self, context: &mut UpdateContext<'_, 'gc, '_>) { fn unload(&self, context: &mut UpdateContext<'_, 'gc, '_>) {

View File

@ -3197,8 +3197,10 @@ impl<'gc, 'a> MovieClip<'gc> {
// Also note that a loaded child SWF could change background color only // Also note that a loaded child SWF could change background color only
// if parent SWF is missing SetBackgroundColor tag. // if parent SWF is missing SetBackgroundColor tag.
let background_color = reader.read_rgb()?; let background_color = reader.read_rgb()?;
if context.background_color.is_none() { if context.stage.background_color().is_none() {
*context.background_color = Some(background_color); context
.stage
.set_background_color(context.gc_context, Some(background_color));
} }
Ok(()) Ok(())
} }

View File

@ -1,10 +1,13 @@
//! Root stage impl //! Root stage impl
use crate::context::UpdateContext; use crate::backend::ui::UiBackend;
use crate::collect::CollectWrapper;
use crate::config::Letterbox;
use crate::context::{RenderContext, UpdateContext};
use crate::display_object::container::{ use crate::display_object::container::{
ChildContainer, DisplayObjectContainer, TDisplayObjectContainer, ChildContainer, DisplayObjectContainer, TDisplayObjectContainer,
}; };
use crate::display_object::{DisplayObject, DisplayObjectBase, TDisplayObject}; use crate::display_object::{render_base, DisplayObject, DisplayObjectBase, TDisplayObject};
use crate::prelude::*; use crate::prelude::*;
use crate::types::{Degrees, Percent}; use crate::types::{Degrees, Percent};
use gc_arena::{Collect, GcCell, MutationContext}; use gc_arena::{Collect, GcCell, MutationContext};
@ -29,6 +32,17 @@ pub struct StageData<'gc> {
/// ///
/// Stage children are exposed to AVM1 as `_level*n*` on all stage objects. /// Stage children are exposed to AVM1 as `_level*n*` on all stage objects.
child: ChildContainer<'gc>, child: ChildContainer<'gc>,
/// The stage background.
///
/// If the background color is not specified, it should be white.
background_color: CollectWrapper<Option<Color>>,
/// Determines how player content is resized to fit the stage.
letterbox: Letterbox,
/// The bounds of the current viewport in twips, used for culling.
view_bounds: BoundingBox,
} }
impl<'gc> Stage<'gc> { impl<'gc> Stage<'gc> {
@ -38,9 +52,149 @@ impl<'gc> Stage<'gc> {
StageData { StageData {
base: Default::default(), base: Default::default(),
child: Default::default(), child: Default::default(),
background_color: CollectWrapper(None),
letterbox: Letterbox::Fullscreen,
view_bounds: Default::default(),
}, },
)) ))
} }
pub fn background_color(self) -> Option<Color> {
self.0.read().background_color.0.clone()
}
pub fn set_background_color(self, gc_context: MutationContext<'gc, '_>, color: Option<Color>) {
self.0.write(gc_context).background_color.0 = color;
}
pub fn inverse_view_matrix(self) -> Matrix {
let mut inverse_view_matrix = *(self.matrix());
inverse_view_matrix.invert();
inverse_view_matrix
}
pub fn letterbox(self) -> Letterbox {
self.0.read().letterbox
}
pub fn set_letterbox(self, gc_context: MutationContext<'gc, '_>, letterbox: Letterbox) {
self.0.write(gc_context).letterbox = letterbox
}
/// Determine if we should letterbox the stage content.
fn should_letterbox(self, ui: &mut dyn UiBackend) -> bool {
let letterbox = self.letterbox();
letterbox == Letterbox::On || (letterbox == Letterbox::Fullscreen && ui.is_fullscreen())
}
/// Update the stage's transform matrix in response to a root movie change.
pub fn build_matrices(&mut self, context: &mut UpdateContext<'_, 'gc, '_>) {
// Create view matrix to scale stage into viewport area.
let (movie_width, movie_height) = (
context.stage_size.0.to_pixels(),
context.stage_size.1.to_pixels(),
);
let (viewport_width, viewport_height) = (
context.viewport_size.0.to_pixels(),
context.viewport_size.1.to_pixels(),
);
let movie_aspect = movie_width / movie_height;
let viewport_aspect = viewport_width / viewport_height;
let (scale, margin_width, margin_height) = if viewport_aspect > movie_aspect {
let scale = viewport_height / movie_height;
(scale, (viewport_width - movie_width * scale) / 2.0, 0.0)
} else {
let scale = viewport_width / movie_width;
(scale, 0.0, (viewport_height - movie_height * scale) / 2.0)
};
*self.matrix_mut(context.gc_context) = Matrix {
a: scale as f32,
b: 0.0,
c: 0.0,
d: scale as f32,
tx: Twips::from_pixels(margin_width),
ty: Twips::from_pixels(margin_height),
};
self.0.write(context.gc_context).view_bounds = if self.should_letterbox(context.ui) {
// No letterbox: movie area
BoundingBox {
x_min: Twips::zero(),
y_min: Twips::zero(),
x_max: Twips::from_pixels(movie_width),
y_max: Twips::from_pixels(movie_height),
valid: true,
}
} else {
// No letterbox: full visible stage area
let margin_width = margin_width / scale;
let margin_height = margin_height / scale;
BoundingBox {
x_min: Twips::from_pixels(-margin_width),
y_min: Twips::from_pixels(-margin_height),
x_max: Twips::from_pixels(movie_width + margin_width),
y_max: Twips::from_pixels(movie_height + margin_height),
valid: true,
}
};
}
/// Draw the stage's letterbox.
fn draw_letterbox(&self, context: &mut RenderContext<'_, 'gc>) {
let black = Color::from_rgb(0, 255);
let viewport_width = context.viewport_bounds.0.to_pixels() as f32;
let viewport_height = context.viewport_bounds.1.to_pixels() as f32;
let view_matrix = self.matrix();
let margin_width = view_matrix.tx.to_pixels() as f32;
let margin_height = view_matrix.ty.to_pixels() as f32;
if margin_height > 0.0 {
context.renderer.draw_rect(
black.clone(),
&Matrix::create_box(
viewport_width,
margin_height,
0.0,
Twips::default(),
Twips::default(),
),
);
context.renderer.draw_rect(
black,
&Matrix::create_box(
viewport_width,
margin_height,
0.0,
Twips::default(),
Twips::from_pixels((viewport_height - margin_height) as f64),
),
);
} else if margin_width > 0.0 {
context.renderer.draw_rect(
black.clone(),
&Matrix::create_box(
margin_width,
viewport_height,
0.0,
Twips::default(),
Twips::default(),
),
);
context.renderer.draw_rect(
black,
&Matrix::create_box(
margin_width,
viewport_height,
0.0,
Twips::from_pixels((viewport_width - margin_width) as f64),
Twips::default(),
),
);
}
}
} }
impl<'gc> TDisplayObject<'gc> for Stage<'gc> { impl<'gc> TDisplayObject<'gc> for Stage<'gc> {
@ -61,6 +215,24 @@ impl<'gc> TDisplayObject<'gc> for Stage<'gc> {
fn as_stage(&self) -> Option<Stage<'gc>> { fn as_stage(&self) -> Option<Stage<'gc>> {
Some(*self) Some(*self)
} }
fn render(&self, context: &mut RenderContext<'_, 'gc>) {
let background_color = self
.background_color()
.unwrap_or_else(|| Color::from_rgb(0xffffff, 255));
let view_bounds = self.0.read().view_bounds.clone();
context.view_bounds = view_bounds;
context.renderer.begin_frame(background_color);
render_base((*self).into(), context);
if self.should_letterbox(context.ui) {
self.draw_letterbox(context);
}
context.renderer.end_frame();
}
} }
impl<'gc> TDisplayObjectContainer<'gc> for Stage<'gc> { impl<'gc> TDisplayObjectContainer<'gc> for Stage<'gc> {

View File

@ -174,14 +174,10 @@ pub struct Player {
video: Video, video: Video,
transform_stack: TransformStack, transform_stack: TransformStack,
view_matrix: Matrix,
inverse_view_matrix: Matrix,
view_bounds: BoundingBox,
rng: SmallRng, rng: SmallRng,
gc_arena: GcArena, gc_arena: GcArena,
background_color: Option<Color>,
frame_rate: f64, frame_rate: f64,
@ -199,7 +195,6 @@ pub struct Player {
viewport_height: u32, viewport_height: u32,
movie_width: u32, movie_width: u32,
movie_height: u32, movie_height: u32,
letterbox: Letterbox,
mouse_pos: (Twips, Twips), mouse_pos: (Twips, Twips),
is_mouse_down: bool, is_mouse_down: bool,
@ -261,11 +256,7 @@ impl Player {
is_playing: false, is_playing: false,
needs_render: true, needs_render: true,
background_color: None,
transform_stack: TransformStack::new(), transform_stack: TransformStack::new(),
view_matrix: Default::default(),
inverse_view_matrix: Default::default(),
view_bounds: Default::default(),
rng: SmallRng::seed_from_u64(chrono::Utc::now().timestamp_millis() as u64), rng: SmallRng::seed_from_u64(chrono::Utc::now().timestamp_millis() as u64),
@ -300,7 +291,6 @@ impl Player {
movie_height, movie_height,
viewport_width: movie_width, viewport_width: movie_width,
viewport_height: movie_height, viewport_height: movie_height,
letterbox: Letterbox::Fullscreen,
mouse_pos: (Twips::zero(), Twips::zero()), mouse_pos: (Twips::zero(), Twips::zero()),
is_mouse_down: false, is_mouse_down: false,
@ -334,10 +324,14 @@ impl Player {
); );
context.stage.replace_at_depth(context, fake_root.into(), 0); context.stage.replace_at_depth(context, fake_root.into(), 0);
Avm2::load_player_globals(context) let result = Avm2::load_player_globals(context);
let mut stage = context.stage;
stage.build_matrices(context);
result
})?; })?;
player.build_matrices();
player.audio.set_frame_rate(frame_rate); player.audio.set_frame_rate(frame_rate);
let player_box = Arc::new(Mutex::new(player)); let player_box = Arc::new(Mutex::new(player));
let mut player_lock = player_box.lock().unwrap(); let mut player_lock = player_box.lock().unwrap();
@ -447,9 +441,11 @@ impl Player {
AvmString::new(activation.context.gc_context, version_string).into(), AvmString::new(activation.context.gc_context, version_string).into(),
Attribute::empty(), Attribute::empty(),
); );
let mut stage = activation.context.stage;
stage.build_matrices(&mut activation.context);
}); });
self.build_matrices();
self.preload(); self.preload();
self.audio.set_frame_rate(self.frame_rate); self.audio.set_frame_rate(self.frame_rate);
} }
@ -580,25 +576,26 @@ impl Player {
self.needs_render self.needs_render
} }
pub fn background_color(&self) -> Option<Color> { pub fn background_color(&mut self) -> Option<Color> {
self.background_color.clone() self.mutate_with_update_context(|context| context.stage.background_color())
} }
pub fn set_background_color(&mut self, color: Option<Color>) { pub fn set_background_color(&mut self, color: Option<Color>) {
self.background_color = color self.mutate_with_update_context(|context| {
context
.stage
.set_background_color(context.gc_context, color)
})
} }
pub fn letterbox(&self) -> Letterbox { pub fn letterbox(&mut self) -> Letterbox {
self.letterbox self.mutate_with_update_context(|context| context.stage.letterbox())
} }
pub fn set_letterbox(&mut self, letterbox: Letterbox) { pub fn set_letterbox(&mut self, letterbox: Letterbox) {
self.letterbox = letterbox self.mutate_with_update_context(|context| {
} context.stage.set_letterbox(context.gc_context, letterbox)
})
fn should_letterbox(&self) -> bool {
self.letterbox == Letterbox::On
|| (self.letterbox == Letterbox::Fullscreen && self.ui.is_fullscreen())
} }
pub fn warn_on_unsupported_content(&self) -> bool { pub fn warn_on_unsupported_content(&self) -> bool {
@ -624,11 +621,17 @@ impl Player {
pub fn set_viewport_dimensions(&mut self, width: u32, height: u32) { pub fn set_viewport_dimensions(&mut self, width: u32, height: u32) {
self.viewport_width = width; self.viewport_width = width;
self.viewport_height = height; self.viewport_height = height;
self.build_matrices();
self.mutate_with_update_context(|context| {
let mut stage = context.stage;
stage.build_matrices(context);
})
} }
pub fn handle_event(&mut self, event: PlayerEvent) { pub fn handle_event(&mut self, event: PlayerEvent) {
let mut needs_render = self.needs_render; let mut needs_render = self.needs_render;
let inverse_view_matrix =
self.mutate_with_update_context(|context| context.stage.inverse_view_matrix());
if cfg!(feature = "avm_debug") { if cfg!(feature = "avm_debug") {
if let PlayerEvent::KeyDown { if let PlayerEvent::KeyDown {
@ -695,8 +698,7 @@ impl Player {
| PlayerEvent::MouseDown { x, y } | PlayerEvent::MouseDown { x, y }
| PlayerEvent::MouseUp { x, y } = event | PlayerEvent::MouseUp { x, y } = event
{ {
self.mouse_pos = self.mouse_pos = inverse_view_matrix * (Twips::from_pixels(x), Twips::from_pixels(y));
self.inverse_view_matrix * (Twips::from_pixels(x), Twips::from_pixels(y));
if self.update_roll_over() { if self.update_roll_over() {
needs_render = true; needs_render = true;
} }
@ -984,40 +986,30 @@ impl Player {
} }
pub fn render(&mut self) { pub fn render(&mut self) {
let background_color = self let (renderer, ui, transform_stack) =
.background_color (&mut self.renderer, &mut self.ui, &mut self.transform_stack);
.clone()
.unwrap_or_else(|| Color::from_rgb(0xffffff, 255));
self.renderer.begin_frame(background_color);
let (renderer, transform_stack) = (&mut self.renderer, &mut self.transform_stack); let viewport_bounds = (
Twips::from_pixels(self.viewport_height as f64),
Twips::from_pixels(self.viewport_width as f64),
);
transform_stack.push(&crate::transform::Transform {
matrix: self.view_matrix,
..Default::default()
});
let view_bounds = self.view_bounds.clone();
self.gc_arena.mutate(|_gc_context, gc_root| { self.gc_arena.mutate(|_gc_context, gc_root| {
let root_data = gc_root.0.read(); let root_data = gc_root.0.read();
let mut render_context = RenderContext { let mut render_context = RenderContext {
renderer: renderer.deref_mut(), renderer: renderer.deref_mut(),
ui: ui.deref_mut(),
library: &root_data.library, library: &root_data.library,
transform_stack, transform_stack,
view_bounds, viewport_bounds,
view_bounds: Default::default(), // filled in by stage
clip_depth_stack: vec![], clip_depth_stack: vec![],
allow_mask: true, allow_mask: true,
}; };
root_data.stage.render(&mut render_context); root_data.stage.render(&mut render_context);
}); });
transform_stack.pop();
if self.should_letterbox() {
self.draw_letterbox();
}
self.renderer.end_frame();
self.needs_render = false; self.needs_render = false;
} }
@ -1182,54 +1174,6 @@ impl Player {
} }
} }
fn build_matrices(&mut self) {
// Create view matrix to scale stage into viewport area.
let (movie_width, movie_height) = (self.movie_width as f32, self.movie_height as f32);
let (viewport_width, viewport_height) =
(self.viewport_width as f32, self.viewport_height as f32);
let movie_aspect = movie_width / movie_height;
let viewport_aspect = viewport_width / viewport_height;
let (scale, margin_width, margin_height) = if viewport_aspect > movie_aspect {
let scale = viewport_height / movie_height;
(scale, (viewport_width - movie_width * scale) / 2.0, 0.0)
} else {
let scale = viewport_width / movie_width;
(scale, 0.0, (viewport_height - movie_height * scale) / 2.0)
};
self.view_matrix = Matrix {
a: scale,
b: 0.0,
c: 0.0,
d: scale,
tx: Twips::from_pixels(margin_width.into()),
ty: Twips::from_pixels(margin_height.into()),
};
self.inverse_view_matrix = self.view_matrix;
self.inverse_view_matrix.invert();
self.view_bounds = if self.should_letterbox() {
// No letterbox: movie area
BoundingBox {
x_min: Twips::zero(),
y_min: Twips::zero(),
x_max: Twips::from_pixels(f64::from(self.movie_width)),
y_max: Twips::from_pixels(f64::from(self.movie_height)),
valid: true,
}
} else {
// No letterbox: full visible stage area
let margin_width = f64::from(margin_width / scale);
let margin_height = f64::from(margin_height / scale);
BoundingBox {
x_min: Twips::from_pixels(-margin_width),
y_min: Twips::from_pixels(-margin_height),
x_max: Twips::from_pixels(f64::from(self.movie_width) + margin_width),
y_max: Twips::from_pixels(f64::from(self.movie_height) + margin_height),
valid: true,
}
};
}
/// Runs the closure `f` with an `UpdateContext`. /// Runs the closure `f` with an `UpdateContext`.
/// This takes cares of populating the `UpdateContext` struct, avoiding borrow issues. /// This takes cares of populating the `UpdateContext` struct, avoiding borrow issues.
fn mutate_with_update_context<F, R>(&mut self, f: F) -> R fn mutate_with_update_context<F, R>(&mut self, f: F) -> R
@ -1241,7 +1185,6 @@ impl Player {
let ( let (
player_version, player_version,
swf, swf,
background_color,
renderer, renderer,
audio, audio,
navigator, navigator,
@ -1250,6 +1193,8 @@ impl Player {
mouse_position, mouse_position,
stage_width, stage_width,
stage_height, stage_height,
viewport_width,
viewport_height,
player, player,
system_properties, system_properties,
instance_counter, instance_counter,
@ -1264,7 +1209,6 @@ impl Player {
) = ( ) = (
self.player_version, self.player_version,
&self.swf, &self.swf,
&mut self.background_color,
self.renderer.deref_mut(), self.renderer.deref_mut(),
self.audio.deref_mut(), self.audio.deref_mut(),
self.navigator.deref_mut(), self.navigator.deref_mut(),
@ -1273,6 +1217,8 @@ impl Player {
&self.mouse_pos, &self.mouse_pos,
Twips::from_pixels(self.movie_width.into()), Twips::from_pixels(self.movie_width.into()),
Twips::from_pixels(self.movie_height.into()), Twips::from_pixels(self.movie_height.into()),
Twips::from_pixels(self.viewport_width.into()),
Twips::from_pixels(self.viewport_height.into()),
self.self_reference.clone(), self.self_reference.clone(),
&mut self.system, &mut self.system,
&mut self.instance_counter, &mut self.instance_counter,
@ -1309,7 +1255,6 @@ impl Player {
player_version, player_version,
swf, swf,
library, library,
background_color,
rng, rng,
renderer, renderer,
audio, audio,
@ -1322,6 +1267,7 @@ impl Player {
mouse_position, mouse_position,
drag_object, drag_object,
stage_size: (stage_width, stage_height), stage_size: (stage_width, stage_height),
viewport_size: (viewport_width, viewport_height),
player, player,
load_manager, load_manager,
system: system_properties, system: system_properties,
@ -1464,58 +1410,6 @@ impl Player {
pub fn set_max_execution_duration(&mut self, max_execution_duration: Duration) { pub fn set_max_execution_duration(&mut self, max_execution_duration: Duration) {
self.max_execution_duration = max_execution_duration self.max_execution_duration = max_execution_duration
} }
fn draw_letterbox(&mut self) {
let black = Color::from_rgb(0, 255);
let viewport_width = self.viewport_width as f32;
let viewport_height = self.viewport_height as f32;
let margin_width = self.view_matrix.tx.to_pixels() as f32;
let margin_height = self.view_matrix.ty.to_pixels() as f32;
if margin_height > 0.0 {
self.renderer.draw_rect(
black.clone(),
&Matrix::create_box(
viewport_width,
margin_height,
0.0,
Twips::default(),
Twips::default(),
),
);
self.renderer.draw_rect(
black,
&Matrix::create_box(
viewport_width,
margin_height,
0.0,
Twips::default(),
Twips::from_pixels((viewport_height - margin_height) as f64),
),
);
} else if margin_width > 0.0 {
self.renderer.draw_rect(
black.clone(),
&Matrix::create_box(
margin_width,
viewport_height,
0.0,
Twips::default(),
Twips::default(),
),
);
self.renderer.draw_rect(
black,
&Matrix::create_box(
margin_width,
viewport_height,
0.0,
Twips::from_pixels((viewport_width - margin_width) as f64),
Twips::default(),
),
);
}
}
} }
#[derive(Collect)] #[derive(Collect)]