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: &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(),
|
||||||
|
|
|
@ -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(),
|
||||||
|
|
|
@ -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,
|
||||||
|
|
||||||
|
|
|
@ -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, '_>) {
|
||||||
|
|
|
@ -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(())
|
||||||
}
|
}
|
||||||
|
|
|
@ -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> {
|
||||||
|
|
|
@ -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)]
|
||||||
|
|
Loading…
Reference in New Issue