ruffle/core/src/display_object.rs

245 lines
7.5 KiB
Rust
Raw Normal View History

use crate::avm1::Value;
2019-04-27 01:55:06 +00:00
use crate::player::{RenderContext, UpdateContext};
2019-04-29 05:55:44 +00:00
use crate::prelude::*;
use crate::transform::Transform;
use gc_arena::{Collect, GcCell, MutationContext};
use std::fmt::Debug;
2019-04-25 17:52:22 +00:00
#[derive(Clone, Collect, Debug)]
2019-05-24 17:25:03 +00:00
#[collect(empty_drop)]
2019-08-13 02:00:12 +00:00
pub struct DisplayObjectBase<'gc> {
parent: Option<DisplayNode<'gc>>,
2019-04-29 05:55:44 +00:00
depth: Depth,
transform: Transform,
name: String,
2019-05-12 17:48:00 +00:00
clip_depth: Depth,
2019-04-25 17:52:22 +00:00
}
2019-08-13 02:00:12 +00:00
impl<'gc> Default for DisplayObjectBase<'gc> {
2019-04-29 05:55:44 +00:00
fn default() -> Self {
Self {
2019-08-13 02:00:12 +00:00
parent: Default::default(),
2019-04-29 05:55:44 +00:00
depth: Default::default(),
transform: Default::default(),
name: Default::default(),
2019-05-12 17:48:00 +00:00
clip_depth: Default::default(),
2019-04-26 03:27:44 +00:00
}
}
2019-04-29 05:55:44 +00:00
}
2019-04-26 03:27:44 +00:00
2019-08-13 02:00:12 +00:00
impl<'gc> DisplayObject<'gc> for DisplayObjectBase<'gc> {
2019-09-15 18:34:30 +00:00
fn id(&self) -> CharacterId {
0
}
2019-09-08 02:33:06 +00:00
fn depth(&self) -> Depth {
self.depth
}
2019-05-01 16:55:54 +00:00
fn transform(&self) -> &Transform {
&self.transform
}
fn matrix(&self) -> &Matrix {
2019-04-29 05:55:44 +00:00
&self.transform.matrix
2019-04-25 17:52:22 +00:00
}
fn matrix_mut(&mut self) -> &mut Matrix {
&mut self.transform.matrix
}
2019-04-29 05:55:44 +00:00
fn set_matrix(&mut self, matrix: &Matrix) {
2019-05-03 18:44:12 +00:00
self.transform.matrix = *matrix;
2019-04-26 03:27:44 +00:00
}
fn color_transform(&self) -> &ColorTransform {
2019-04-29 05:55:44 +00:00
&self.transform.color_transform
}
fn set_color_transform(&mut self, color_transform: &ColorTransform) {
2019-05-03 18:44:12 +00:00
self.transform.color_transform = *color_transform;
2019-04-25 17:52:22 +00:00
}
fn name(&self) -> &str {
&self.name
}
fn set_name(&mut self, name: &str) {
self.name = name.to_string();
}
2019-05-12 17:48:00 +00:00
fn clip_depth(&self) -> Depth {
self.clip_depth
}
fn set_clip_depth(&mut self, depth: Depth) {
self.clip_depth = depth;
}
2019-08-13 02:00:12 +00:00
fn parent(&self) -> Option<DisplayNode<'gc>> {
self.parent
}
fn set_parent(&mut self, parent: Option<DisplayNode<'gc>>) {
self.parent = parent;
}
2019-08-15 21:12:41 +00:00
fn box_clone(&self) -> Box<dyn DisplayObject<'gc>> {
2019-05-09 01:10:43 +00:00
Box::new(self.clone())
}
2019-04-29 05:55:44 +00:00
}
pub trait DisplayObject<'gc>: 'gc + Collect + Debug {
2019-09-15 18:34:30 +00:00
fn id(&self) -> CharacterId;
2019-09-08 02:33:06 +00:00
fn depth(&self) -> Depth;
fn local_bounds(&self) -> BoundingBox {
BoundingBox::default()
}
fn world_bounds(&self) -> BoundingBox {
BoundingBox::default()
}
2019-05-01 16:55:54 +00:00
fn transform(&self) -> &Transform;
fn matrix(&self) -> &Matrix;
fn matrix_mut(&mut self) -> &mut Matrix;
2019-04-29 05:55:44 +00:00
fn set_matrix(&mut self, matrix: &Matrix);
fn color_transform(&self) -> &ColorTransform;
2019-04-29 05:55:44 +00:00
fn set_color_transform(&mut self, color_transform: &ColorTransform);
fn name(&self) -> &str;
fn set_name(&mut self, name: &str);
2019-05-12 17:48:00 +00:00
fn clip_depth(&self) -> Depth;
fn set_clip_depth(&mut self, depth: Depth);
2019-08-13 02:00:12 +00:00
fn parent(&self) -> Option<DisplayNode<'gc>>;
fn set_parent(&mut self, parent: Option<DisplayNode<'gc>>);
2019-04-26 21:11:29 +00:00
2019-05-24 17:25:03 +00:00
fn run_frame(&mut self, _context: &mut UpdateContext<'_, 'gc, '_>) {}
fn run_post_frame(&mut self, _context: &mut UpdateContext<'_, 'gc, '_>) {}
fn render(&self, _context: &mut RenderContext<'_, 'gc>) {}
2019-05-03 18:44:12 +00:00
2019-08-19 14:53:12 +00:00
fn as_button(&self) -> Option<&crate::button::Button<'gc>> {
None
}
fn as_button_mut(&mut self) -> Option<&mut crate::button::Button<'gc>> {
None
}
2019-05-24 17:25:03 +00:00
fn as_movie_clip(&self) -> Option<&crate::movie_clip::MovieClip<'gc>> {
2019-05-07 06:31:34 +00:00
None
}
2019-05-24 17:25:03 +00:00
fn as_movie_clip_mut(&mut self) -> Option<&mut crate::movie_clip::MovieClip<'gc>> {
2019-05-07 06:31:34 +00:00
None
}
2019-08-13 02:00:12 +00:00
fn as_morph_shape(&self) -> Option<&crate::morph_shape::MorphShape<'gc>> {
None
}
2019-08-13 02:00:12 +00:00
fn as_morph_shape_mut(&mut self) -> Option<&mut crate::morph_shape::MorphShape<'gc>> {
None
}
fn box_clone(&self) -> Box<dyn DisplayObject<'gc>>;
2019-08-14 19:39:26 +00:00
fn object(&self) -> Value<'gc> {
Value::Undefined // todo: impl for every type and delete this fallback
}
2019-08-14 19:39:26 +00:00
fn hit_test(&self, _: (Twips, Twips)) -> bool {
false
}
2019-08-19 14:53:12 +00:00
fn mouse_pick(
&self,
_self_node: DisplayNode<'gc>,
_: (Twips, Twips),
) -> Option<DisplayNode<'gc>> {
None
2019-08-14 19:39:26 +00:00
}
fn post_instantiation(
&mut self,
_gc_context: MutationContext<'gc, '_>,
_display_object: DisplayNode<'gc>,
) {
}
2019-05-09 01:10:43 +00:00
}
impl<'gc> Clone for Box<dyn DisplayObject<'gc>> {
fn clone(&self) -> Box<dyn DisplayObject<'gc>> {
2019-05-09 01:10:43 +00:00
self.box_clone()
}
2019-04-29 05:55:44 +00:00
}
macro_rules! impl_display_object {
2019-05-07 10:34:17 +00:00
($field:ident) => {
2019-09-08 02:33:06 +00:00
fn depth(&self) -> crate::prelude::Depth {
self.$field.depth()
}
2019-05-09 01:10:43 +00:00
fn transform(&self) -> &crate::transform::Transform {
self.$field.transform()
}
fn matrix(&self) -> &crate::matrix::Matrix {
self.$field.matrix()
2019-05-09 01:10:43 +00:00
}
fn matrix_mut(&mut self) -> &mut crate::matrix::Matrix {
self.$field.matrix_mut()
}
2019-07-19 08:32:41 +00:00
fn set_matrix(&mut self, matrix: &crate::matrix::Matrix) {
2019-05-09 01:10:43 +00:00
self.$field.set_matrix(matrix)
}
fn color_transform(&self) -> &crate::color_transform::ColorTransform {
self.$field.color_transform()
2019-05-09 01:10:43 +00:00
}
2019-07-19 08:32:41 +00:00
fn set_color_transform(&mut self, color_transform: &crate::color_transform::ColorTransform) {
2019-05-09 01:10:43 +00:00
self.$field.set_color_transform(color_transform)
}
fn name(&self) -> &str {
self.$field.name()
}
fn set_name(&mut self, name: &str) {
self.$field.set_name(name)
}
2019-07-19 08:32:41 +00:00
fn clip_depth(&self) -> crate::prelude::Depth {
2019-05-12 17:48:00 +00:00
self.$field.clip_depth()
}
2019-07-19 08:32:41 +00:00
fn set_clip_depth(&mut self, depth: crate::prelude::Depth) {
2019-05-12 17:48:00 +00:00
self.$field.set_clip_depth(depth)
}
2019-08-13 02:00:12 +00:00
fn parent(&self) -> Option<crate::display_object::DisplayNode<'gc>> {
self.$field.parent()
}
fn set_parent(&mut self, parent: Option<crate::display_object::DisplayNode<'gc>>) {
self.$field.set_parent(parent)
}
fn box_clone(&self) -> Box<dyn crate::display_object::DisplayObject<'gc>> {
2019-05-09 01:10:43 +00:00
Box::new(self.clone())
}
2019-04-29 05:55:44 +00:00
};
}
2019-09-08 02:33:06 +00:00
/// Renders the children of a display object, taking masking into account.
// TODO(Herschel): Move this into an IDisplayObject/IDisplayObjectContainer trait when
// we figure out inheritance
pub fn render_children<'gc>(
context: &mut RenderContext<'_, 'gc>,
children: &std::collections::BTreeMap<Depth, DisplayNode<'gc>>,
) {
let mut clip_depth = 0;
let mut clip_depth_stack = vec![];
for (&depth, &child) in children {
// Check if we need to pop off a mask.
// This must be a while loop because multiple masks can be popped
// at the same dpeth.
while clip_depth > 0 && depth >= clip_depth {
context.renderer.pop_mask();
clip_depth = clip_depth_stack.pop().unwrap();
}
let child = child.read();
if child.clip_depth() > 0 {
// Push and render the mask.
clip_depth_stack.push(clip_depth);
clip_depth = child.clip_depth();
context.renderer.push_mask();
child.render(context);
context.renderer.activate_mask();
} else {
// Normal child.
child.render(context);
}
}
while !clip_depth_stack.is_empty() {
context.renderer.pop_mask();
clip_depth_stack.pop();
}
}
2019-05-24 17:25:03 +00:00
/// `DisplayNode` is the garbage-collected pointer between display objects.
/// TODO(Herschel): The extra Box here is necessary to hold the trait object inside a GC pointer,
/// but this is an extra allocation... Can we avoid this, maybe with a DST?
pub type DisplayNode<'gc> = GcCell<'gc, Box<dyn DisplayObject<'gc>>>;