core: Move most of the player rendering code into the `Stage`'s render method.
This commit is contained in:
parent
44af21b398
commit
67724bfc71
|
@ -877,7 +877,6 @@ mod tests {
|
|||
audio: &mut NullAudioBackend::new(),
|
||||
audio_manager: &mut AudioManager::new(),
|
||||
ui: &mut NullUiBackend::new(),
|
||||
background_color: &mut None,
|
||||
library: &mut Library::empty(gc_context),
|
||||
navigator: &mut NullNavigatorBackend::new(),
|
||||
renderer: &mut NullRenderer::new(),
|
||||
|
@ -888,6 +887,7 @@ mod tests {
|
|||
mouse_position: &(Twips::zero(), Twips::zero()),
|
||||
drag_object: &mut None,
|
||||
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,
|
||||
load_manager: &mut LoadManager::new(),
|
||||
system: &mut SystemProperties::default(),
|
||||
|
|
|
@ -52,7 +52,6 @@ where
|
|||
audio: &mut NullAudioBackend::new(),
|
||||
ui: &mut NullUiBackend::new(),
|
||||
action_queue: &mut ActionQueue::new(),
|
||||
background_color: &mut None,
|
||||
library: &mut Library::empty(gc_context),
|
||||
navigator: &mut NullNavigatorBackend::new(),
|
||||
renderer: &mut NullRenderer::new(),
|
||||
|
@ -63,6 +62,7 @@ where
|
|||
mouse_position: &(Twips::zero(), Twips::zero()),
|
||||
drag_object: &mut None,
|
||||
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,
|
||||
load_manager: &mut LoadManager::new(),
|
||||
system: &mut SystemProperties::default(),
|
||||
|
|
|
@ -38,10 +38,6 @@ pub struct UpdateContext<'a, 'gc, 'gc_context> {
|
|||
/// Display objects and actions can push actions onto the queue.
|
||||
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.
|
||||
pub gc_context: MutationContext<'gc, 'gc_context>,
|
||||
|
||||
|
@ -107,6 +103,9 @@ pub struct UpdateContext<'a, 'gc, 'gc_context> {
|
|||
/// The dimensions of the stage.
|
||||
pub stage_size: (Twips, Twips),
|
||||
|
||||
/// The dimensions of the stage's containing viewport.
|
||||
pub viewport_size: (Twips, Twips),
|
||||
|
||||
/// Weak reference to the player.
|
||||
///
|
||||
/// 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 {
|
||||
action_queue: self.action_queue,
|
||||
background_color: self.background_color,
|
||||
gc_context: self.gc_context,
|
||||
library: self.library,
|
||||
player_version: self.player_version,
|
||||
|
@ -271,6 +269,7 @@ impl<'a, 'gc, 'gc_context> UpdateContext<'a, 'gc, 'gc_context> {
|
|||
mouse_position: self.mouse_position,
|
||||
drag_object: self.drag_object,
|
||||
stage_size: self.stage_size,
|
||||
viewport_size: self.viewport_size,
|
||||
player: self.player.clone(),
|
||||
load_manager: self.load_manager,
|
||||
system: self.system,
|
||||
|
@ -370,11 +369,18 @@ pub struct RenderContext<'a, 'gc> {
|
|||
/// The renderer, used by the display objects to draw themselves.
|
||||
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.
|
||||
pub library: &'a Library<'gc>,
|
||||
|
||||
/// The transform stack controls the matrix and color transform as we traverse the display hierarchy.
|
||||
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.
|
||||
pub view_bounds: BoundingBox,
|
||||
|
||||
|
|
|
@ -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(
|
||||
#[derive(Clone, Collect, Debug, Copy)]
|
||||
#[collect(no_drop)]
|
||||
|
@ -933,36 +966,7 @@ pub trait TDisplayObject<'gc>:
|
|||
fn render_self(&self, _context: &mut RenderContext<'_, 'gc>) {}
|
||||
|
||||
fn render(&self, context: &mut RenderContext<'_, 'gc>) {
|
||||
if self.maskee().is_some() {
|
||||
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();
|
||||
render_base((*self).into(), context)
|
||||
}
|
||||
|
||||
fn unload(&self, context: &mut UpdateContext<'_, 'gc, '_>) {
|
||||
|
|
|
@ -3197,8 +3197,10 @@ impl<'gc, 'a> MovieClip<'gc> {
|
|||
// Also note that a loaded child SWF could change background color only
|
||||
// if parent SWF is missing SetBackgroundColor tag.
|
||||
let background_color = reader.read_rgb()?;
|
||||
if context.background_color.is_none() {
|
||||
*context.background_color = Some(background_color);
|
||||
if context.stage.background_color().is_none() {
|
||||
context
|
||||
.stage
|
||||
.set_background_color(context.gc_context, Some(background_color));
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
@ -1,10 +1,13 @@
|
|||
//! 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::{
|
||||
ChildContainer, DisplayObjectContainer, TDisplayObjectContainer,
|
||||
};
|
||||
use crate::display_object::{DisplayObject, DisplayObjectBase, TDisplayObject};
|
||||
use crate::display_object::{render_base, DisplayObject, DisplayObjectBase, TDisplayObject};
|
||||
use crate::prelude::*;
|
||||
use crate::types::{Degrees, Percent};
|
||||
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.
|
||||
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> {
|
||||
|
@ -38,9 +52,149 @@ impl<'gc> Stage<'gc> {
|
|||
StageData {
|
||||
base: 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> {
|
||||
|
@ -61,6 +215,24 @@ impl<'gc> TDisplayObject<'gc> for Stage<'gc> {
|
|||
fn as_stage(&self) -> Option<Stage<'gc>> {
|
||||
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> {
|
||||
|
|
|
@ -174,14 +174,10 @@ pub struct Player {
|
|||
video: Video,
|
||||
|
||||
transform_stack: TransformStack,
|
||||
view_matrix: Matrix,
|
||||
inverse_view_matrix: Matrix,
|
||||
view_bounds: BoundingBox,
|
||||
|
||||
rng: SmallRng,
|
||||
|
||||
gc_arena: GcArena,
|
||||
background_color: Option<Color>,
|
||||
|
||||
frame_rate: f64,
|
||||
|
||||
|
@ -199,7 +195,6 @@ pub struct Player {
|
|||
viewport_height: u32,
|
||||
movie_width: u32,
|
||||
movie_height: u32,
|
||||
letterbox: Letterbox,
|
||||
|
||||
mouse_pos: (Twips, Twips),
|
||||
is_mouse_down: bool,
|
||||
|
@ -261,11 +256,7 @@ impl Player {
|
|||
is_playing: false,
|
||||
needs_render: true,
|
||||
|
||||
background_color: None,
|
||||
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),
|
||||
|
||||
|
@ -300,7 +291,6 @@ impl Player {
|
|||
movie_height,
|
||||
viewport_width: movie_width,
|
||||
viewport_height: movie_height,
|
||||
letterbox: Letterbox::Fullscreen,
|
||||
|
||||
mouse_pos: (Twips::zero(), Twips::zero()),
|
||||
is_mouse_down: false,
|
||||
|
@ -334,10 +324,14 @@ impl Player {
|
|||
);
|
||||
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);
|
||||
let player_box = Arc::new(Mutex::new(player));
|
||||
let mut player_lock = player_box.lock().unwrap();
|
||||
|
@ -447,9 +441,11 @@ impl Player {
|
|||
AvmString::new(activation.context.gc_context, version_string).into(),
|
||||
Attribute::empty(),
|
||||
);
|
||||
|
||||
let mut stage = activation.context.stage;
|
||||
stage.build_matrices(&mut activation.context);
|
||||
});
|
||||
|
||||
self.build_matrices();
|
||||
self.preload();
|
||||
self.audio.set_frame_rate(self.frame_rate);
|
||||
}
|
||||
|
@ -580,25 +576,26 @@ impl Player {
|
|||
self.needs_render
|
||||
}
|
||||
|
||||
pub fn background_color(&self) -> Option<Color> {
|
||||
self.background_color.clone()
|
||||
pub fn background_color(&mut self) -> Option<Color> {
|
||||
self.mutate_with_update_context(|context| context.stage.background_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 {
|
||||
self.letterbox
|
||||
pub fn letterbox(&mut self) -> Letterbox {
|
||||
self.mutate_with_update_context(|context| context.stage.letterbox())
|
||||
}
|
||||
|
||||
pub fn set_letterbox(&mut self, letterbox: Letterbox) {
|
||||
self.letterbox = letterbox
|
||||
}
|
||||
|
||||
fn should_letterbox(&self) -> bool {
|
||||
self.letterbox == Letterbox::On
|
||||
|| (self.letterbox == Letterbox::Fullscreen && self.ui.is_fullscreen())
|
||||
self.mutate_with_update_context(|context| {
|
||||
context.stage.set_letterbox(context.gc_context, letterbox)
|
||||
})
|
||||
}
|
||||
|
||||
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) {
|
||||
self.viewport_width = width;
|
||||
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) {
|
||||
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 let PlayerEvent::KeyDown {
|
||||
|
@ -695,8 +698,7 @@ impl Player {
|
|||
| PlayerEvent::MouseDown { x, y }
|
||||
| PlayerEvent::MouseUp { x, y } = event
|
||||
{
|
||||
self.mouse_pos =
|
||||
self.inverse_view_matrix * (Twips::from_pixels(x), Twips::from_pixels(y));
|
||||
self.mouse_pos = inverse_view_matrix * (Twips::from_pixels(x), Twips::from_pixels(y));
|
||||
if self.update_roll_over() {
|
||||
needs_render = true;
|
||||
}
|
||||
|
@ -984,40 +986,30 @@ impl Player {
|
|||
}
|
||||
|
||||
pub fn render(&mut self) {
|
||||
let background_color = self
|
||||
.background_color
|
||||
.clone()
|
||||
.unwrap_or_else(|| Color::from_rgb(0xffffff, 255));
|
||||
self.renderer.begin_frame(background_color);
|
||||
let (renderer, ui, transform_stack) =
|
||||
(&mut self.renderer, &mut self.ui, &mut self.transform_stack);
|
||||
|
||||
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| {
|
||||
let root_data = gc_root.0.read();
|
||||
let mut render_context = RenderContext {
|
||||
renderer: renderer.deref_mut(),
|
||||
ui: ui.deref_mut(),
|
||||
library: &root_data.library,
|
||||
transform_stack,
|
||||
view_bounds,
|
||||
viewport_bounds,
|
||||
view_bounds: Default::default(), // filled in by stage
|
||||
clip_depth_stack: vec![],
|
||||
allow_mask: true,
|
||||
};
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -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`.
|
||||
/// This takes cares of populating the `UpdateContext` struct, avoiding borrow issues.
|
||||
fn mutate_with_update_context<F, R>(&mut self, f: F) -> R
|
||||
|
@ -1241,7 +1185,6 @@ impl Player {
|
|||
let (
|
||||
player_version,
|
||||
swf,
|
||||
background_color,
|
||||
renderer,
|
||||
audio,
|
||||
navigator,
|
||||
|
@ -1250,6 +1193,8 @@ impl Player {
|
|||
mouse_position,
|
||||
stage_width,
|
||||
stage_height,
|
||||
viewport_width,
|
||||
viewport_height,
|
||||
player,
|
||||
system_properties,
|
||||
instance_counter,
|
||||
|
@ -1264,7 +1209,6 @@ impl Player {
|
|||
) = (
|
||||
self.player_version,
|
||||
&self.swf,
|
||||
&mut self.background_color,
|
||||
self.renderer.deref_mut(),
|
||||
self.audio.deref_mut(),
|
||||
self.navigator.deref_mut(),
|
||||
|
@ -1273,6 +1217,8 @@ impl Player {
|
|||
&self.mouse_pos,
|
||||
Twips::from_pixels(self.movie_width.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(),
|
||||
&mut self.system,
|
||||
&mut self.instance_counter,
|
||||
|
@ -1309,7 +1255,6 @@ impl Player {
|
|||
player_version,
|
||||
swf,
|
||||
library,
|
||||
background_color,
|
||||
rng,
|
||||
renderer,
|
||||
audio,
|
||||
|
@ -1322,6 +1267,7 @@ impl Player {
|
|||
mouse_position,
|
||||
drag_object,
|
||||
stage_size: (stage_width, stage_height),
|
||||
viewport_size: (viewport_width, viewport_height),
|
||||
player,
|
||||
load_manager,
|
||||
system: system_properties,
|
||||
|
@ -1464,58 +1410,6 @@ impl Player {
|
|||
pub fn set_max_execution_duration(&mut self, max_execution_duration: 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)]
|
||||
|
|
Loading…
Reference in New Issue