Add lyon
This commit is contained in:
parent
ba6843cf55
commit
f69381cdda
|
@ -25,6 +25,7 @@ swf = { git = "https://github.com/Herschel/swf-rs", version = "*" }
|
|||
|
||||
# Desktop dependencies
|
||||
[target.'cfg(not(target_arch = "wasm32"))'.dependencies]
|
||||
lyon = "0.13.1"
|
||||
structopt = "0.2.15"
|
||||
glium = "0.24"
|
||||
glutin = "0.20"
|
||||
|
|
|
@ -1,7 +1,18 @@
|
|||
pub mod common;
|
||||
pub mod glium;
|
||||
pub mod shape_utils;
|
||||
|
||||
use swf::Shape;
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
pub mod web_canvas;
|
||||
|
||||
use self::common::ShapeHandle;
|
||||
use crate::{matrix::Matrix, Color};
|
||||
|
||||
pub trait RenderBackend {
|
||||
//fn register_shape(shape: &Shape) {}
|
||||
fn register_shape(&mut self, shape: &swf::Shape) -> common::ShapeHandle;
|
||||
|
||||
fn begin_frame(&mut self);
|
||||
fn clear(&mut self, color: crate::Color);
|
||||
fn render_shape(&mut self, shape: ShapeHandle, matrix: &Matrix);
|
||||
fn end_frame(&mut self);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,2 @@
|
|||
#[derive(Copy, Clone, Debug)]
|
||||
pub struct ShapeHandle(pub usize);
|
|
@ -1,17 +1,484 @@
|
|||
use super::RenderBackend;
|
||||
use super::{common::ShapeHandle, shape_utils, RenderBackend};
|
||||
use crate::backend::ui::glutin::GlutinBackend;
|
||||
use glium::Display;
|
||||
use glutin::Context;
|
||||
use crate::{matrix::Matrix, Color};
|
||||
use glium::{implement_vertex, uniform, Display, Frame, Surface};
|
||||
use lyon::tessellation::geometry_builder::{BuffersBuilder, VertexBuffers, VertexConstructor};
|
||||
use lyon::tessellation::FillVertex;
|
||||
use lyon::{path::PathEvent, tessellation, tessellation::FillTessellator};
|
||||
use std::collections::{HashMap, VecDeque};
|
||||
use swf::{FillStyle, LineStyle};
|
||||
|
||||
pub struct GliumRenderBackend {
|
||||
display: Display,
|
||||
target: Option<Frame>,
|
||||
shader_program: glium::Program,
|
||||
meshes: Vec<Mesh>,
|
||||
}
|
||||
|
||||
impl GliumRenderBackend {
|
||||
pub fn new(ui: &mut GlutinBackend) -> Result<GliumRenderBackend, Box<std::error::Error>> {
|
||||
let display = Display::from_gl_window(ui.take_context())?;
|
||||
Ok(GliumRenderBackend { display })
|
||||
|
||||
let shader_program =
|
||||
glium::Program::from_source(&display, VERTEX_SHADER, FRAGMENT_SHADER, None)?;
|
||||
|
||||
Ok(GliumRenderBackend {
|
||||
display,
|
||||
shader_program,
|
||||
target: None,
|
||||
meshes: vec![],
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl RenderBackend for GliumRenderBackend {}
|
||||
impl RenderBackend for GliumRenderBackend {
|
||||
fn register_shape(&mut self, shape: &swf::Shape) -> ShapeHandle {
|
||||
let handle = ShapeHandle(self.meshes.len());
|
||||
|
||||
use lyon::tessellation::FillOptions;
|
||||
|
||||
// let mut mesh: VertexBuffers<_, u16> = VertexBuffers::new();
|
||||
// let paths = swf_shape_to_lyon_paths(shape);
|
||||
// let fill_tess = FillTessellator::new();
|
||||
// for path in paths {
|
||||
// let mut buffers_builder = BuffersBuilder::new(&mut mesh, ());
|
||||
// fill_tess.tessellate_path(
|
||||
// path.into_iter(),
|
||||
// &FillOptions::even_odd(),
|
||||
// &mut buffers_builder,
|
||||
// );
|
||||
// }
|
||||
|
||||
let vertices = vec![
|
||||
Vertex {
|
||||
position: [0.0, 0.0],
|
||||
color: [1.0, 0.0, 0.0, 1.0],
|
||||
},
|
||||
Vertex {
|
||||
position: [100.0, 0.0],
|
||||
color: [1.0, 0.0, 0.0, 1.0],
|
||||
},
|
||||
Vertex {
|
||||
position: [100.0, 100.0],
|
||||
color: [1.0, 0.0, 0.0, 1.0],
|
||||
},
|
||||
Vertex {
|
||||
position: [0.0, 100.0],
|
||||
color: [1.0, 0.0, 0.0, 1.0],
|
||||
},
|
||||
];
|
||||
let indices = vec![0, 1, 2, 0, 2, 3];
|
||||
let vertex_buffer = glium::VertexBuffer::new(&self.display, &vertices).unwrap();
|
||||
let index_buffer = glium::IndexBuffer::new(
|
||||
&self.display,
|
||||
glium::index::PrimitiveType::TrianglesList,
|
||||
&indices,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let mesh = Mesh {
|
||||
vertex_buffer,
|
||||
index_buffer,
|
||||
};
|
||||
self.meshes.push(mesh);
|
||||
|
||||
handle
|
||||
}
|
||||
|
||||
fn begin_frame(&mut self) {
|
||||
assert!(self.target.is_none());
|
||||
self.target = Some(self.display.draw());
|
||||
}
|
||||
|
||||
fn end_frame(&mut self) {
|
||||
assert!(self.target.is_some());
|
||||
let target = self.target.take().unwrap();
|
||||
target.finish().unwrap();
|
||||
}
|
||||
|
||||
fn clear(&mut self, color: Color) {
|
||||
let target = self.target.as_mut().unwrap();
|
||||
target.clear_color(
|
||||
f32::from(color.r) / 255.0,
|
||||
f32::from(color.g) / 255.0,
|
||||
f32::from(color.b) / 255.0,
|
||||
f32::from(color.a) / 255.0,
|
||||
);
|
||||
}
|
||||
|
||||
fn render_shape(&mut self, shape: ShapeHandle, matrix: &Matrix) {
|
||||
let mesh = &self.meshes[shape.0];
|
||||
|
||||
let view_matrix = [
|
||||
[1.0 / 250.0f32, 0.0, 0.0, 0.0],
|
||||
[0.0, -1.0 / 250.0, 0.0, 0.0],
|
||||
[0.0, 0.0, 1.0, 0.0],
|
||||
[-1.0, 1.0, 0.0, 1.0],
|
||||
];
|
||||
|
||||
let world_matrix = [
|
||||
[matrix.a, matrix.b, 0.0, 0.0],
|
||||
[matrix.b, matrix.d, 0.0, 0.0],
|
||||
[0.0, 0.0, 1.0, 0.0],
|
||||
[matrix.tx, matrix.ty, 0.0, 1.0],
|
||||
];
|
||||
|
||||
let target = self.target.as_mut().unwrap();
|
||||
target
|
||||
.draw(
|
||||
&mesh.vertex_buffer,
|
||||
&mesh.index_buffer,
|
||||
&self.shader_program,
|
||||
&uniform! { view_matrix: view_matrix, world_matrix: world_matrix },
|
||||
&Default::default(),
|
||||
)
|
||||
.unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
struct Vertex {
|
||||
position: [f32; 2],
|
||||
color: [f32; 4],
|
||||
}
|
||||
|
||||
implement_vertex!(Vertex, position, color);
|
||||
|
||||
const VERTEX_SHADER: &str = r#"
|
||||
#version 140
|
||||
|
||||
uniform mat4 view_matrix;
|
||||
uniform mat4 world_matrix;
|
||||
|
||||
in vec2 position;
|
||||
in vec4 color;
|
||||
out vec4 frag_color;
|
||||
|
||||
void main() {
|
||||
frag_color = color;
|
||||
gl_Position = view_matrix * world_matrix * vec4(position, 0.0, 1.0);
|
||||
}
|
||||
"#;
|
||||
|
||||
const FRAGMENT_SHADER: &str = r#"
|
||||
#version 140
|
||||
in vec4 frag_color;
|
||||
out vec4 out_color;
|
||||
void main() {
|
||||
out_color = frag_color;
|
||||
}
|
||||
"#;
|
||||
|
||||
struct Mesh {
|
||||
vertex_buffer: glium::VertexBuffer<Vertex>,
|
||||
index_buffer: glium::IndexBuffer<u32>,
|
||||
}
|
||||
|
||||
fn point(x: f32, y: f32) -> lyon::math::Point {
|
||||
lyon::math::Point::new(x, y)
|
||||
}
|
||||
|
||||
fn swf_shape_to_lyon_paths(shape: &swf::Shape) -> Vec<Vec<lyon::path::PathEvent>> {
|
||||
let cmds = get_paths(shape);
|
||||
let mut out_paths = vec![];
|
||||
let mut prev;
|
||||
use lyon::geom::{LineSegment, QuadraticBezierSegment};
|
||||
for cmd in cmds {
|
||||
if let PathCommandType::Fill(fill_style) = cmd.command_type {
|
||||
let mut out_path = vec![PathEvent::MoveTo(point(cmd.path.start.0, cmd.path.start.1))];
|
||||
prev = point(cmd.path.start.0, cmd.path.start.1);
|
||||
for edge in cmd.path.edges {
|
||||
let out_cmd = match edge {
|
||||
PathEdge::Straight(x, y) => {
|
||||
let cmd = PathEvent::Line(LineSegment {
|
||||
from: prev,
|
||||
to: point(x, y),
|
||||
});
|
||||
prev = point(x, y);
|
||||
cmd
|
||||
}
|
||||
PathEdge::Bezier(x1, y1, x2, y2) => {
|
||||
let cmd = PathEvent::Quadratic(QuadraticBezierSegment {
|
||||
from: prev,
|
||||
ctrl: point(x1, y1),
|
||||
to: point(x2, y2),
|
||||
});
|
||||
prev = point(x2, y2);
|
||||
cmd
|
||||
}
|
||||
};
|
||||
out_path.push(out_cmd);
|
||||
}
|
||||
out_path.push(PathEvent::Close(LineSegment {
|
||||
from: prev,
|
||||
to: prev,
|
||||
}));
|
||||
out_paths.push(out_path);
|
||||
}
|
||||
}
|
||||
out_paths
|
||||
}
|
||||
|
||||
fn get_paths(shape: &swf::Shape) -> impl Iterator<Item = PathCommand> {
|
||||
let mut x = 0.0;
|
||||
let mut y = 0.0;
|
||||
|
||||
let mut fill_styles = &shape.styles.fill_styles;
|
||||
let mut line_styles = &shape.styles.line_styles;
|
||||
let mut fill_style_0 = 0;
|
||||
let mut fill_style_1 = 0;
|
||||
let mut line_style = 0;
|
||||
|
||||
let mut paths: HashMap<u32, PendingPaths> = HashMap::new();
|
||||
let mut strokes: HashMap<u32, PendingPaths> = HashMap::new();
|
||||
|
||||
let mut out = vec![];
|
||||
|
||||
for record in &shape.shape {
|
||||
use swf::ShapeRecord::*;
|
||||
match record {
|
||||
StyleChange(style_change) => {
|
||||
if let Some((move_x, move_y)) = style_change.move_to {
|
||||
x = move_x;
|
||||
y = move_y;
|
||||
}
|
||||
|
||||
if let Some(i) = style_change.fill_style_0 {
|
||||
fill_style_0 = i;
|
||||
}
|
||||
|
||||
if let Some(i) = style_change.fill_style_1 {
|
||||
fill_style_1 = i;
|
||||
}
|
||||
|
||||
if let Some(i) = style_change.line_style {
|
||||
line_style = i;
|
||||
}
|
||||
|
||||
if let Some(ref new_styles) = style_change.new_styles {
|
||||
for (id, paths) in paths {
|
||||
for path in paths.open_paths {
|
||||
out.push(PathCommand {
|
||||
command_type: paths.command_type.clone(),
|
||||
path,
|
||||
})
|
||||
}
|
||||
}
|
||||
for (id, paths) in strokes {
|
||||
for path in paths.open_paths {
|
||||
out.push(PathCommand {
|
||||
command_type: paths.command_type.clone(),
|
||||
path,
|
||||
})
|
||||
}
|
||||
}
|
||||
paths = HashMap::new();
|
||||
strokes = HashMap::new();
|
||||
fill_styles = &new_styles.fill_styles;
|
||||
line_styles = &new_styles.line_styles;
|
||||
}
|
||||
}
|
||||
|
||||
StraightEdge { delta_x, delta_y } => {
|
||||
if fill_style_0 != 0 {
|
||||
let path = paths.entry(fill_style_0).or_insert_with(|| {
|
||||
PendingPaths::new(PathCommandType::Fill(
|
||||
fill_styles[fill_style_0 as usize - 1].clone(),
|
||||
))
|
||||
});
|
||||
path.add_edge((x + delta_x, y + delta_y), PathEdge::Straight(x, y));
|
||||
}
|
||||
|
||||
if fill_style_1 != 0 {
|
||||
let path = paths.entry(fill_style_1).or_insert_with(|| {
|
||||
PendingPaths::new(PathCommandType::Fill(
|
||||
fill_styles[fill_style_1 as usize - 1].clone(),
|
||||
))
|
||||
});
|
||||
path.add_edge((x, y), PathEdge::Straight(x + delta_x, y + delta_y));
|
||||
}
|
||||
|
||||
if line_style != 0 {
|
||||
let path = strokes.entry(line_style).or_insert_with(|| {
|
||||
PendingPaths::new(PathCommandType::Stroke(
|
||||
line_styles[line_style as usize - 1].clone(),
|
||||
))
|
||||
});
|
||||
path.add_edge((x, y), PathEdge::Straight(x + delta_x, y + delta_y));
|
||||
}
|
||||
|
||||
x += delta_x;
|
||||
y += delta_y;
|
||||
}
|
||||
|
||||
CurvedEdge {
|
||||
control_delta_x,
|
||||
control_delta_y,
|
||||
anchor_delta_x,
|
||||
anchor_delta_y,
|
||||
} => {
|
||||
if fill_style_0 != 0 {
|
||||
let path = paths.entry(fill_style_0).or_insert_with(|| {
|
||||
PendingPaths::new(PathCommandType::Fill(
|
||||
fill_styles[fill_style_0 as usize - 1].clone(),
|
||||
))
|
||||
});
|
||||
path.add_edge(
|
||||
(
|
||||
x + control_delta_x + anchor_delta_x,
|
||||
y + control_delta_y + anchor_delta_y,
|
||||
),
|
||||
PathEdge::Bezier(x + control_delta_x, y + control_delta_y, x, y),
|
||||
);
|
||||
}
|
||||
|
||||
if fill_style_1 != 0 {
|
||||
let path = paths.entry(fill_style_1).or_insert_with(|| {
|
||||
PendingPaths::new(PathCommandType::Fill(
|
||||
fill_styles[fill_style_1 as usize - 1].clone(),
|
||||
))
|
||||
});
|
||||
path.add_edge(
|
||||
(x, y),
|
||||
PathEdge::Bezier(
|
||||
x + control_delta_x,
|
||||
y + control_delta_y,
|
||||
x + control_delta_x + anchor_delta_x,
|
||||
y + control_delta_y + anchor_delta_y,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
if line_style != 0 {
|
||||
let path = strokes.entry(line_style).or_insert_with(|| {
|
||||
PendingPaths::new(PathCommandType::Stroke(
|
||||
line_styles[line_style as usize - 1].clone(),
|
||||
))
|
||||
});
|
||||
path.add_edge(
|
||||
(x, y),
|
||||
PathEdge::Bezier(
|
||||
x + control_delta_x,
|
||||
y + control_delta_y,
|
||||
x + control_delta_x + anchor_delta_x,
|
||||
y + control_delta_y + anchor_delta_y,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
x += control_delta_x + anchor_delta_x;
|
||||
y += control_delta_y + anchor_delta_y;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (id, paths) in paths {
|
||||
for path in paths.open_paths {
|
||||
out.push(PathCommand {
|
||||
command_type: paths.command_type.clone(),
|
||||
path,
|
||||
})
|
||||
}
|
||||
}
|
||||
for (id, paths) in strokes {
|
||||
for path in paths.open_paths {
|
||||
out.push(PathCommand {
|
||||
command_type: paths.command_type.clone(),
|
||||
path,
|
||||
})
|
||||
}
|
||||
}
|
||||
out.into_iter()
|
||||
}
|
||||
|
||||
pub struct PathCommand {
|
||||
command_type: PathCommandType,
|
||||
path: Path,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
enum PathCommandType {
|
||||
Fill(FillStyle),
|
||||
Stroke(LineStyle),
|
||||
}
|
||||
|
||||
struct PendingPaths {
|
||||
command_type: PathCommandType,
|
||||
open_paths: Vec<Path>,
|
||||
}
|
||||
|
||||
impl PendingPaths {
|
||||
fn new(command_type: PathCommandType) -> PendingPaths {
|
||||
Self {
|
||||
command_type,
|
||||
open_paths: vec![],
|
||||
}
|
||||
}
|
||||
|
||||
fn add_edge(&mut self, start: (f32, f32), edge: PathEdge) {
|
||||
let new_path = Path {
|
||||
start,
|
||||
end: match edge {
|
||||
PathEdge::Straight(x, y) => (x, y),
|
||||
PathEdge::Bezier(_cx, _cy, ax, ay) => (ax, ay),
|
||||
},
|
||||
|
||||
edges: {
|
||||
let mut edges = VecDeque::new();
|
||||
edges.push_back(edge);
|
||||
edges
|
||||
},
|
||||
};
|
||||
|
||||
self.merge_subpath(new_path);
|
||||
}
|
||||
|
||||
fn merge_subpath(&mut self, mut path: Path) {
|
||||
fn approx_eq(a: (f32, f32), b: (f32, f32)) -> bool {
|
||||
let dx = a.0 - b.0;
|
||||
let dy = a.1 - b.1;
|
||||
const EPSILON: f32 = 0.0001;
|
||||
dx.abs() < EPSILON && dy.abs() < EPSILON
|
||||
}
|
||||
|
||||
let mut path_index = None;
|
||||
for (i, other) in self.open_paths.iter_mut().enumerate() {
|
||||
if approx_eq(path.end, other.start) {
|
||||
other.start = path.start;
|
||||
for edge in path.edges.iter().rev() {
|
||||
other.edges.push_front(*edge);
|
||||
}
|
||||
path_index = Some(i);
|
||||
break;
|
||||
}
|
||||
|
||||
if approx_eq(other.end, path.start) {
|
||||
other.end = path.end;
|
||||
other.edges.append(&mut path.edges);
|
||||
|
||||
path_index = Some(i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(i) = path_index {
|
||||
let path = self.open_paths.swap_remove(i);
|
||||
self.merge_subpath(path);
|
||||
} else {
|
||||
self.open_paths.push(path);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct Path {
|
||||
start: (f32, f32),
|
||||
end: (f32, f32),
|
||||
|
||||
edges: VecDeque<PathEdge>,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
enum PathEdge {
|
||||
Straight(f32, f32),
|
||||
Bezier(f32, f32, f32, f32),
|
||||
}
|
||||
|
|
|
@ -266,7 +266,7 @@ struct Stroke {
|
|||
}
|
||||
|
||||
// TODO(Herschel): Iterater-ize this.
|
||||
fn swf_shape_to_paths(shape: &Shape) -> (Vec<Path>, Vec<Path>) {
|
||||
pub fn swf_shape_to_paths(shape: &Shape) -> (Vec<Path>, Vec<Path>) {
|
||||
let mut layers = vec![];
|
||||
let mut paths = HashMap::<u32, Path>::new();
|
||||
let mut stroke_paths = HashMap::<u32, Path>::new();
|
|
@ -0,0 +1,62 @@
|
|||
use super::RenderBackend;
|
||||
use web_sys::{CanvasRenderingContext2d, HtmlImageElement>;
|
||||
|
||||
pub struct WebCanvasRenderBackend {
|
||||
context: CanvasRenderingContext2d,
|
||||
width: f64,
|
||||
height: f64,
|
||||
|
||||
shapes: Vec<ShapeData>,
|
||||
}
|
||||
|
||||
struct ShapeData {
|
||||
image: HtmlImageElement,
|
||||
x_min: f64,
|
||||
y_min: f64,
|
||||
}
|
||||
|
||||
impl WebCanvas {
|
||||
fn new(context: CanvasRenderingContext2d, width: f64, height: f64) -> WebCanvas {
|
||||
context: CanvasRenderingContext2d,
|
||||
width: f64,
|
||||
height: f64,
|
||||
}
|
||||
}
|
||||
|
||||
impl RenderBackend for WebCanvas {
|
||||
fn register_shape(&mut self, shape: &swf::Shape) -> ShapeHandle {
|
||||
let handle = ShapeHandle(self.meshes.len());
|
||||
|
||||
let image = HtmlImageElement::new().unwrap();
|
||||
|
||||
use url::percent_encoding::{percent_encode, DEFAULT_ENCODE_SET};
|
||||
let svg = super::shape_utils::swf_shape_to_paths(&shape);
|
||||
let svg_encoded = format!("data:image/xvg+xml;{}", percent_encode(svg, DEFAULT_ENCODE_SET));
|
||||
image.set_src(&svg_encoded);
|
||||
|
||||
self.shapes.push(ShapeData{
|
||||
image, x_min: shape.shape_bounds.x_min.into(), y_min: shape.shape_bounds.y_min.into()
|
||||
});
|
||||
|
||||
handle
|
||||
}
|
||||
|
||||
fn begin_frame(&mut self) {
|
||||
context.reset_transform();
|
||||
}
|
||||
|
||||
fn end_frame(&mut self) {
|
||||
// Noop
|
||||
}
|
||||
|
||||
fn clear(&mut self, color: Color) {
|
||||
let color = format!("rgb({}, {}, {}", color.r, color.g, color.b);
|
||||
context.fill_rect(0, 0, self.width, self.height, &color);
|
||||
}
|
||||
|
||||
fn render_shape(&mut self, shape: ShapeHandle, matrix: &Matrix) {
|
||||
let shape = &self.shapes[shape.0];
|
||||
context.set_transform(matrix.a, matrix.b, matrix.c, matrix.d, matrix.tx, matrix.ty).unwrap();
|
||||
context.draw_image_with_html_image_element(&shape.image, shape.x_min, shape.y_min).unwrap();
|
||||
}
|
||||
}
|
|
@ -1,8 +1,8 @@
|
|||
pub enum Character {
|
||||
Graphic {
|
||||
//image: HtmlImageElement,
|
||||
x_min: f32,
|
||||
y_min: f32,
|
||||
shape_handle: crate::backend::render::common::ShapeHandle,
|
||||
},
|
||||
MovieClip {
|
||||
num_frames: u16,
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
use crate::backend::render::common::ShapeHandle;
|
||||
use crate::color_transform::ColorTransform;
|
||||
use crate::display_object::DisplayObject;
|
||||
use crate::matrix::Matrix;
|
||||
|
@ -7,6 +8,7 @@ use bacon_rajan_cc::{Trace, Tracer};
|
|||
use web_sys::HtmlImageElement;
|
||||
|
||||
pub struct Graphic {
|
||||
shape_handle: ShapeHandle,
|
||||
matrix: Matrix,
|
||||
color_transform: ColorTransform,
|
||||
x_min: f32,
|
||||
|
@ -14,8 +16,9 @@ pub struct Graphic {
|
|||
}
|
||||
|
||||
impl Graphic {
|
||||
pub fn new(x_min: f32, y_min: f32) -> Graphic {
|
||||
pub fn new(shape_handle: ShapeHandle, x_min: f32, y_min: f32) -> Graphic {
|
||||
Graphic {
|
||||
shape_handle,
|
||||
color_transform: Default::default(),
|
||||
x_min,
|
||||
y_min,
|
||||
|
@ -63,7 +66,10 @@ impl DisplayObject for Graphic {
|
|||
// .draw_image_with_html_image_element(&self.image, self.x_min.into(), self.y_min.into())
|
||||
// .expect("Couldn't render image");
|
||||
|
||||
context.matrix_stack.pop();
|
||||
context
|
||||
.renderer
|
||||
.render_shape(self.shape_handle, &world_matrix);
|
||||
|
||||
context.color_transform_stack.push(&self.color_transform);
|
||||
}
|
||||
|
||||
|
|
|
@ -7,10 +7,10 @@ mod library;
|
|||
mod matrix;
|
||||
mod movie_clip;
|
||||
mod player;
|
||||
mod shape_utils;
|
||||
mod stage;
|
||||
|
||||
pub use player::Player;
|
||||
use swf::Color;
|
||||
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
#[allow(dead_code)]
|
||||
|
|
|
@ -31,12 +31,13 @@ impl Library {
|
|||
) -> Result<DisplayObjectNode, Box<std::error::Error>> {
|
||||
match self.characters.get(&id) {
|
||||
Some(Character::Graphic {
|
||||
//image,
|
||||
x_min,
|
||||
y_min,
|
||||
shape_handle,
|
||||
}) => Ok(DisplayObjectNode::Graphic(Graphic::new(
|
||||
//image.clone(),
|
||||
*x_min, *y_min,
|
||||
*shape_handle,
|
||||
*x_min,
|
||||
*y_min,
|
||||
))),
|
||||
Some(Character::MovieClip {
|
||||
tag_stream_start,
|
||||
|
|
|
@ -27,14 +27,12 @@ pub struct Player {
|
|||
render_context: RenderContext,
|
||||
|
||||
ui: Box<UiBackend>,
|
||||
renderer: Box<RenderBackend>,
|
||||
|
||||
library: Library,
|
||||
stage: Cc<RefCell<Stage>>,
|
||||
|
||||
frame_rate: f64,
|
||||
frame_accumulator: f64,
|
||||
//cur_timestamp: f64,
|
||||
}
|
||||
|
||||
#[cfg_attr(target_arch = "wasm32", wasm_bindgen)]
|
||||
|
@ -49,9 +47,9 @@ impl Player {
|
|||
tag_stream,
|
||||
|
||||
ui,
|
||||
renderer,
|
||||
|
||||
render_context: RenderContext {
|
||||
renderer,
|
||||
matrix_stack: MatrixStack::new(),
|
||||
color_transform_stack: ColorTransformStack::new(),
|
||||
},
|
||||
|
@ -61,7 +59,6 @@ impl Player {
|
|||
|
||||
frame_rate: swf.frame_rate.into(),
|
||||
frame_accumulator: 0.0,
|
||||
//cur_timestamp: std::time::Instant::now(),
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -81,21 +78,18 @@ impl Player {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn tick(&mut self, timestamp: f64) {
|
||||
// let dt = timestamp - self.cur_timestamp;
|
||||
// self.cur_timestamp = timestamp;
|
||||
pub fn tick(&mut self, dt: f64) {
|
||||
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();
|
||||
}
|
||||
|
||||
// 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();
|
||||
// }
|
||||
if needs_render {
|
||||
self.render();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -105,6 +99,7 @@ impl Player {
|
|||
tag_stream: &mut self.tag_stream,
|
||||
position_stack: vec![],
|
||||
library: &mut self.library,
|
||||
renderer: &mut *self.render_context.renderer,
|
||||
};
|
||||
|
||||
let mut stage = self.stage.borrow_mut();
|
||||
|
@ -113,10 +108,11 @@ impl Player {
|
|||
}
|
||||
|
||||
fn render(&mut self) {
|
||||
self.render_context.renderer.begin_frame();
|
||||
|
||||
let stage = self.stage.borrow_mut();
|
||||
|
||||
/*
|
||||
let background_color = stage.background_color();
|
||||
/*let background_color = stage.background_color();
|
||||
let css_color = format!(
|
||||
"rgb({}, {}, {})",
|
||||
background_color.r, background_color.g, background_color.b
|
||||
|
@ -132,9 +128,11 @@ impl Player {
|
|||
self.render_context
|
||||
.context_2d
|
||||
.fill_rect(0.0, 0.0, width, height);
|
||||
*/
|
||||
*/
|
||||
|
||||
stage.render(&mut self.render_context);
|
||||
|
||||
self.render_context.renderer.end_frame();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -142,10 +140,11 @@ pub struct UpdateContext<'a> {
|
|||
pub tag_stream: &'a mut swf::read::Reader<Cursor<Vec<u8>>>,
|
||||
pub position_stack: Vec<u64>,
|
||||
pub library: &'a mut Library,
|
||||
pub renderer: &'a mut RenderBackend,
|
||||
}
|
||||
|
||||
pub struct RenderContext {
|
||||
//pub context_2d: CanvasRenderingContext2d,
|
||||
pub renderer: Box<RenderBackend>,
|
||||
pub matrix_stack: MatrixStack,
|
||||
pub color_transform_stack: ColorTransformStack,
|
||||
}
|
||||
|
|
|
@ -79,12 +79,11 @@ impl DisplayObject for Stage {
|
|||
|
||||
Tag::DefineShape(shape) => {
|
||||
if !context.library.contains_character(shape.id) {
|
||||
//let mut image = HtmlImageElement::new().unwrap();
|
||||
//image.set_src(&url_encoded_svg);
|
||||
let shape_handle = context.renderer.register_shape(&shape);
|
||||
context.library.register_character(
|
||||
shape.id,
|
||||
Character::Graphic {
|
||||
//image,
|
||||
shape_handle,
|
||||
x_min: shape.shape_bounds.x_min,
|
||||
y_min: shape.shape_bounds.y_min,
|
||||
},
|
||||
|
@ -155,6 +154,8 @@ impl DisplayObject for Stage {
|
|||
}
|
||||
|
||||
fn render(&self, context: &mut RenderContext) {
|
||||
context.renderer.clear(self.background_color.clone());
|
||||
|
||||
context.matrix_stack.push(&self.matrix);
|
||||
context.color_transform_stack.push(&self.color_transform);
|
||||
|
||||
|
|
Loading…
Reference in New Issue