2019-04-25 17:52:22 +00:00
|
|
|
mod character;
|
2019-04-26 21:11:29 +00:00
|
|
|
mod color_transform;
|
2019-04-25 17:52:22 +00:00
|
|
|
mod display_object;
|
|
|
|
mod graphic;
|
|
|
|
mod library;
|
|
|
|
mod matrix;
|
|
|
|
mod movie_clip;
|
|
|
|
mod shape_utils;
|
2019-04-26 03:27:44 +00:00
|
|
|
mod stage;
|
2019-04-25 17:52:22 +00:00
|
|
|
|
2019-04-26 21:11:29 +00:00
|
|
|
use self::color_transform::{ColorTransform, ColorTransformStack};
|
2019-04-25 17:52:22 +00:00
|
|
|
use self::display_object::DisplayObject;
|
|
|
|
use self::library::Library;
|
|
|
|
use self::matrix::{Matrix, MatrixStack};
|
|
|
|
use self::movie_clip::MovieClip;
|
2019-04-26 03:27:44 +00:00
|
|
|
use self::stage::Stage;
|
2019-04-25 17:52:22 +00:00
|
|
|
use bacon_rajan_cc::Cc;
|
|
|
|
use js_sys::{ArrayBuffer, Uint8Array};
|
|
|
|
use log::{info, trace, warn};
|
|
|
|
use std::cell::RefCell;
|
|
|
|
use std::collections::HashMap;
|
|
|
|
use std::io::Cursor;
|
|
|
|
use std::rc::Rc;
|
|
|
|
use wasm_bindgen::prelude::*;
|
|
|
|
use wasm_bindgen::JsCast;
|
|
|
|
use web_sys::{CanvasRenderingContext2d, HtmlCanvasElement, HtmlImageElement};
|
|
|
|
|
|
|
|
type CharacterId = swf::CharacterId;
|
|
|
|
|
|
|
|
#[wasm_bindgen]
|
|
|
|
pub struct Player {
|
|
|
|
tag_stream: swf::read::Reader<Cursor<Vec<u8>>>,
|
2019-04-26 03:27:44 +00:00
|
|
|
|
2019-04-25 17:52:22 +00:00
|
|
|
canvas: HtmlCanvasElement,
|
|
|
|
render_context: RenderContext,
|
|
|
|
|
|
|
|
library: Library,
|
2019-04-26 03:27:44 +00:00
|
|
|
stage: Cc<RefCell<Stage>>,
|
2019-04-25 17:52:22 +00:00
|
|
|
|
|
|
|
frame_rate: f64,
|
|
|
|
frame_accumulator: f64,
|
|
|
|
cur_timestamp: f64,
|
|
|
|
}
|
|
|
|
|
|
|
|
#[wasm_bindgen]
|
|
|
|
impl Player {
|
|
|
|
pub fn new(data: ArrayBuffer, canvas: HtmlCanvasElement) -> Player {
|
|
|
|
console_error_panic_hook::set_once();
|
|
|
|
console_log::init_with_level(log::Level::Trace).expect("error initializing log");
|
|
|
|
|
|
|
|
let data = Uint8Array::new(data.as_ref());
|
|
|
|
let mut swf_data = vec![0; data.byte_length() as usize];
|
|
|
|
data.copy_to(&mut swf_data[..]);
|
|
|
|
|
|
|
|
let (swf, tag_stream) = swf::read::read_swf_header_decompressed(&swf_data[..]).unwrap();
|
|
|
|
info!("{}x{}", swf.stage_size.x_max, swf.stage_size.y_max);
|
|
|
|
|
|
|
|
canvas.set_width(swf.stage_size.x_max as u32);
|
|
|
|
canvas.set_height(swf.stage_size.y_max as u32);
|
|
|
|
|
|
|
|
let context: CanvasRenderingContext2d = canvas
|
|
|
|
.get_context("2d")
|
|
|
|
.expect("Expected canvas")
|
|
|
|
.expect("Expected canvas")
|
|
|
|
.dyn_into()
|
|
|
|
.expect("Expected CanvasRenderingContext2d");
|
|
|
|
|
|
|
|
Player {
|
|
|
|
tag_stream,
|
|
|
|
canvas,
|
2019-04-26 03:27:44 +00:00
|
|
|
|
2019-04-25 17:52:22 +00:00
|
|
|
render_context: RenderContext {
|
|
|
|
context_2d: context,
|
|
|
|
matrix_stack: MatrixStack::new(),
|
2019-04-26 21:11:29 +00:00
|
|
|
color_transform_stack: ColorTransformStack::new(),
|
2019-04-25 17:52:22 +00:00
|
|
|
},
|
|
|
|
|
|
|
|
library: Library::new(),
|
2019-04-26 03:27:44 +00:00
|
|
|
stage: Stage::new(swf.num_frames),
|
2019-04-25 17:52:22 +00:00
|
|
|
|
|
|
|
frame_rate: swf.frame_rate.into(),
|
|
|
|
frame_accumulator: 0.0,
|
|
|
|
cur_timestamp: web_sys::window()
|
|
|
|
.expect("Expected window")
|
|
|
|
.performance()
|
|
|
|
.expect("Expected performance")
|
|
|
|
.now(),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn tick(&mut self, timestamp: f64) {
|
|
|
|
let dt = timestamp - self.cur_timestamp;
|
|
|
|
self.cur_timestamp = timestamp;
|
|
|
|
|
|
|
|
self.frame_accumulator += dt;
|
|
|
|
let frame_time = 1000.0 / self.frame_rate;
|
|
|
|
let needs_render = self.frame_accumulator >= frame_time;
|
|
|
|
while self.frame_accumulator >= frame_time {
|
|
|
|
self.frame_accumulator -= frame_time;
|
|
|
|
self.run_frame();
|
|
|
|
}
|
|
|
|
|
|
|
|
if needs_render {
|
|
|
|
self.render();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Player {
|
|
|
|
fn run_frame(&mut self) {
|
2019-04-26 03:27:44 +00:00
|
|
|
let mut update_context = UpdateContext {
|
|
|
|
tag_stream: &mut self.tag_stream,
|
|
|
|
position_stack: vec![],
|
|
|
|
library: &mut self.library,
|
|
|
|
};
|
|
|
|
|
|
|
|
let mut stage = self.stage.borrow_mut();
|
|
|
|
stage.run_frame(&mut update_context);
|
|
|
|
stage.update_frame_number();
|
2019-04-25 17:52:22 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
fn render(&mut self) {
|
2019-04-26 03:27:44 +00:00
|
|
|
let stage = self.stage.borrow_mut();
|
|
|
|
let background_color = stage.background_color();
|
|
|
|
let css_color = format!(
|
2019-04-25 17:52:22 +00:00
|
|
|
"rgb({}, {}, {})",
|
2019-04-26 03:27:44 +00:00
|
|
|
background_color.r, background_color.g, background_color.b
|
2019-04-25 17:52:22 +00:00
|
|
|
);
|
2019-04-26 03:27:44 +00:00
|
|
|
self.render_context.context_2d.reset_transform().unwrap();
|
2019-04-25 17:52:22 +00:00
|
|
|
self.render_context
|
|
|
|
.context_2d
|
2019-04-26 03:27:44 +00:00
|
|
|
.set_fill_style(&format!("{}", css_color).into());
|
2019-04-25 17:52:22 +00:00
|
|
|
|
|
|
|
let width: f64 = self.canvas.width().into();
|
|
|
|
let height: f64 = self.canvas.height().into();
|
|
|
|
|
|
|
|
self.render_context
|
|
|
|
.context_2d
|
|
|
|
.fill_rect(0.0, 0.0, width, height);
|
|
|
|
|
2019-04-26 03:27:44 +00:00
|
|
|
stage.render(&mut self.render_context);
|
2019-04-25 17:52:22 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-04-26 03:27:44 +00:00
|
|
|
pub struct UpdateContext<'a> {
|
|
|
|
tag_stream: &'a mut swf::read::Reader<Cursor<Vec<u8>>>,
|
|
|
|
position_stack: Vec<u64>,
|
|
|
|
library: &'a mut Library,
|
|
|
|
}
|
|
|
|
|
2019-04-25 17:52:22 +00:00
|
|
|
pub struct RenderContext {
|
|
|
|
context_2d: CanvasRenderingContext2d,
|
|
|
|
matrix_stack: MatrixStack,
|
2019-04-26 21:11:29 +00:00
|
|
|
color_transform_stack: ColorTransformStack,
|
2019-04-25 17:52:22 +00:00
|
|
|
}
|