From dbf02fb742c6b673bb2f48188fbd054517dc02ed Mon Sep 17 00:00:00 2001 From: Patrick Walton Date: Wed, 12 Jun 2019 10:46:00 -0700 Subject: [PATCH 01/26] Make `get_vertex_attr()` fallible --- gl/src/lib.rs | 10 +++-- gpu/src/lib.rs | 2 +- renderer/src/gpu/renderer.rs | 76 ++++++++++++++++++++---------------- ui/src/lib.rs | 9 +++-- 4 files changed, 57 insertions(+), 40 deletions(-) diff --git a/gl/src/lib.rs b/gl/src/lib.rs index 030f63f9..aa08233a 100644 --- a/gl/src/lib.rs +++ b/gl/src/lib.rs @@ -304,12 +304,16 @@ impl Device for GLDevice { } } - fn get_vertex_attr(&self, program: &Self::Program, name: &str) -> GLVertexAttr { + fn get_vertex_attr(&self, program: &Self::Program, name: &str) -> Option { let name = CString::new(format!("a{}", name)).unwrap(); let attr = unsafe { - gl::GetAttribLocation(program.gl_program, name.as_ptr() as *const GLchar) as GLuint + gl::GetAttribLocation(program.gl_program, name.as_ptr() as *const GLchar) }; ck(); - GLVertexAttr { attr } + if attr < 0 { + None + } else { + Some(GLVertexAttr { attr: attr as GLuint }) + } } fn get_uniform(&self, program: &GLProgram, name: &str) -> GLUniform { diff --git a/gpu/src/lib.rs b/gpu/src/lib.rs index cfe4b4ee..7d1fde49 100644 --- a/gpu/src/lib.rs +++ b/gpu/src/lib.rs @@ -44,7 +44,7 @@ pub trait Device { vertex_shader: Self::Shader, fragment_shader: Self::Shader, ) -> Self::Program; - fn get_vertex_attr(&self, program: &Self::Program, name: &str) -> Self::VertexAttr; + fn get_vertex_attr(&self, program: &Self::Program, name: &str) -> Option; fn get_uniform(&self, program: &Self::Program, name: &str) -> Self::Uniform; fn use_program(&self, program: &Self::Program); fn configure_vertex_attr(&self, attr: &Self::VertexAttr, descriptor: &VertexAttrDescriptor); diff --git a/renderer/src/gpu/renderer.rs b/renderer/src/gpu/renderer.rs index 0579d0f2..80bdc477 100644 --- a/renderer/src/gpu/renderer.rs +++ b/renderer/src/gpu/renderer.rs @@ -944,12 +944,12 @@ where BufferUploadMode::Dynamic, ); - let tess_coord_attr = device.get_vertex_attr(&fill_program.program, "TessCoord"); - let from_px_attr = device.get_vertex_attr(&fill_program.program, "FromPx"); - let to_px_attr = device.get_vertex_attr(&fill_program.program, "ToPx"); - let from_subpx_attr = device.get_vertex_attr(&fill_program.program, "FromSubpx"); - let to_subpx_attr = device.get_vertex_attr(&fill_program.program, "ToSubpx"); - let tile_index_attr = device.get_vertex_attr(&fill_program.program, "TileIndex"); + let tess_coord_attr = device.get_vertex_attr(&fill_program.program, "TessCoord").unwrap(); + let from_px_attr = device.get_vertex_attr(&fill_program.program, "FromPx").unwrap(); + let to_px_attr = device.get_vertex_attr(&fill_program.program, "ToPx").unwrap(); + let from_subpx_attr = device.get_vertex_attr(&fill_program.program, "FromSubpx").unwrap(); + let to_subpx_attr = device.get_vertex_attr(&fill_program.program, "ToSubpx").unwrap(); + let tile_index_attr = device.get_vertex_attr(&fill_program.program, "TileIndex").unwrap(); device.bind_vertex_array(&vertex_array); device.use_program(&fill_program.program); @@ -1029,10 +1029,14 @@ where ) -> AlphaTileVertexArray { let (vertex_array, vertex_buffer) = (device.create_vertex_array(), device.create_buffer()); - let tess_coord_attr = device.get_vertex_attr(&alpha_tile_program.program, "TessCoord"); - let tile_origin_attr = device.get_vertex_attr(&alpha_tile_program.program, "TileOrigin"); - let backdrop_attr = device.get_vertex_attr(&alpha_tile_program.program, "Backdrop"); - let tile_index_attr = device.get_vertex_attr(&alpha_tile_program.program, "TileIndex"); + let tess_coord_attr = device.get_vertex_attr(&alpha_tile_program.program, "TessCoord") + .unwrap(); + let tile_origin_attr = device.get_vertex_attr(&alpha_tile_program.program, "TileOrigin") + .unwrap(); + let backdrop_attr = device.get_vertex_attr(&alpha_tile_program.program, "Backdrop") + .unwrap(); + let tile_index_attr = device.get_vertex_attr(&alpha_tile_program.program, "TileIndex") + .unwrap(); let color_tex_coord_attr = device.get_vertex_attr(&alpha_tile_program.program, "ColorTexCoord"); @@ -1074,14 +1078,16 @@ where offset: 6, divisor: 1, }); - device.configure_vertex_attr(&color_tex_coord_attr, &VertexAttrDescriptor { - size: 2, - class: VertexAttrClass::FloatNorm, - attr_type: VertexAttrType::U16, - stride: MASK_TILE_INSTANCE_SIZE, - offset: 8, - divisor: 1, - }); + if let Some(color_tex_coord_attr) = color_tex_coord_attr { + device.configure_vertex_attr(&color_tex_coord_attr, &VertexAttrDescriptor { + size: 2, + class: VertexAttrClass::FloatNorm, + attr_type: VertexAttrType::U16, + stride: MASK_TILE_INSTANCE_SIZE, + offset: 8, + divisor: 1, + }); + } device.bind_buffer(quad_vertex_indices_buffer, BufferTarget::Index); AlphaTileVertexArray { vertex_array, vertex_buffer } @@ -1108,8 +1114,10 @@ where ) -> SolidTileVertexArray { let (vertex_array, vertex_buffer) = (device.create_vertex_array(), device.create_buffer()); - let tess_coord_attr = device.get_vertex_attr(&solid_tile_program.program, "TessCoord"); - let tile_origin_attr = device.get_vertex_attr(&solid_tile_program.program, "TileOrigin"); + let tess_coord_attr = device.get_vertex_attr(&solid_tile_program.program, "TessCoord") + .unwrap(); + let tile_origin_attr = device.get_vertex_attr(&solid_tile_program.program, "TileOrigin") + .unwrap(); let color_tex_coord_attr = device.get_vertex_attr(&solid_tile_program.program, "ColorTexCoord"); @@ -1135,14 +1143,16 @@ where offset: 0, divisor: 1, }); - device.configure_vertex_attr(&color_tex_coord_attr, &VertexAttrDescriptor { - size: 2, - class: VertexAttrClass::FloatNorm, - attr_type: VertexAttrType::U16, - stride: SOLID_TILE_INSTANCE_SIZE, - offset: 4, - divisor: 1, - }); + if let Some(color_tex_coord_attr) = color_tex_coord_attr { + device.configure_vertex_attr(&color_tex_coord_attr, &VertexAttrDescriptor { + size: 2, + class: VertexAttrClass::FloatNorm, + attr_type: VertexAttrType::U16, + stride: SOLID_TILE_INSTANCE_SIZE, + offset: 4, + divisor: 1, + }); + } device.bind_buffer(quad_vertex_indices_buffer, BufferTarget::Index); SolidTileVertexArray { vertex_array, vertex_buffer } @@ -1409,7 +1419,8 @@ where quad_vertex_indices_buffer: &D::Buffer, ) -> PostprocessVertexArray { let vertex_array = device.create_vertex_array(); - let position_attr = device.get_vertex_attr(&postprocess_program.program, "Position"); + let position_attr = device.get_vertex_attr(&postprocess_program.program, "Position") + .unwrap(); device.bind_vertex_array(&vertex_array); device.use_program(&postprocess_program.program); @@ -1462,8 +1473,7 @@ where let vertex_array = device.create_vertex_array(); let (vertex_buffer, index_buffer) = (device.create_buffer(), device.create_buffer()); - let position_attr = device.get_vertex_attr(&stencil_program.program, "Position"); - + let position_attr = device.get_vertex_attr(&stencil_program.program, "Position").unwrap(); device.bind_vertex_array(&vertex_array); device.use_program(&stencil_program.program); device.bind_buffer(&vertex_buffer, BufferTarget::Vertex); @@ -1529,8 +1539,8 @@ where ) -> ReprojectionVertexArray { let vertex_array = device.create_vertex_array(); - let position_attr = device.get_vertex_attr(&reprojection_program.program, "Position"); - + let position_attr = device.get_vertex_attr(&reprojection_program.program, "Position") + .unwrap(); device.bind_vertex_array(&vertex_array); device.use_program(&reprojection_program.program); device.bind_buffer(quad_vertex_positions_buffer, BufferTarget::Vertex); diff --git a/ui/src/lib.rs b/ui/src/lib.rs index 0955dbf7..794e5839 100644 --- a/ui/src/lib.rs +++ b/ui/src/lib.rs @@ -585,8 +585,10 @@ impl DebugTextureVertexArray where D: Device { let (vertex_buffer, index_buffer) = (device.create_buffer(), device.create_buffer()); let vertex_array = device.create_vertex_array(); - let position_attr = device.get_vertex_attr(&debug_texture_program.program, "Position"); - let tex_coord_attr = device.get_vertex_attr(&debug_texture_program.program, "TexCoord"); + let position_attr = device.get_vertex_attr(&debug_texture_program.program, "Position") + .unwrap(); + let tex_coord_attr = device.get_vertex_attr(&debug_texture_program.program, "TexCoord") + .unwrap(); device.bind_vertex_array(&vertex_array); device.use_program(&debug_texture_program.program); @@ -624,7 +626,8 @@ impl DebugSolidVertexArray where D: Device { let (vertex_buffer, index_buffer) = (device.create_buffer(), device.create_buffer()); let vertex_array = device.create_vertex_array(); - let position_attr = device.get_vertex_attr(&debug_solid_program.program, "Position"); + let position_attr = device.get_vertex_attr(&debug_solid_program.program, "Position") + .unwrap(); device.bind_vertex_array(&vertex_array); device.use_program(&debug_solid_program.program); device.bind_buffer(&vertex_buffer, BufferTarget::Vertex); From 5dfe14ebc48476506e068b51b05fcfe0c53a30ef Mon Sep 17 00:00:00 2001 From: Patrick Walton Date: Wed, 12 Jun 2019 10:41:54 -0700 Subject: [PATCH 02/26] Add a minimal `glutin` example --- Cargo.lock | 120 +++++++++++++++++++++ Cargo.toml | 1 + examples/canvas_glutin_minimal/Cargo.toml | 25 +++++ examples/canvas_glutin_minimal/src/main.rs | 97 +++++++++++++++++ 4 files changed, 243 insertions(+) create mode 100644 examples/canvas_glutin_minimal/Cargo.toml create mode 100644 examples/canvas_glutin_minimal/src/main.rs diff --git a/Cargo.lock b/Cargo.lock index ba24425d..18ff3a79 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -148,6 +148,19 @@ name = "byteorder" version = "1.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "canvas_glutin_minimal" +version = "0.1.0" +dependencies = [ + "gl 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", + "glutin 0.21.0 (registry+https://github.com/rust-lang/crates.io-index)", + "pathfinder_canvas 0.1.0", + "pathfinder_geometry 0.3.0", + "pathfinder_gl 0.1.0", + "pathfinder_gpu 0.1.0", + "pathfinder_renderer 0.1.0", +] + [[package]] name = "canvas_minimal" version = "0.1.0" @@ -419,6 +432,16 @@ dependencies = [ "sdl2-sys 0.32.6 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "derivative" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.15.34 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "dirs" version = "1.0.5" @@ -707,6 +730,72 @@ dependencies = [ "x11-dl 2.18.3 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "glutin" +version = "0.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "android_glue 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "cgl 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "cocoa 0.18.4 (registry+https://github.com/rust-lang/crates.io-index)", + "core-foundation 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)", + "core-graphics 0.17.3 (registry+https://github.com/rust-lang/crates.io-index)", + "derivative 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "glutin_egl_sys 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", + "glutin_emscripten_sys 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "glutin_gles2_sys 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", + "glutin_glx_sys 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "glutin_wgl_sys 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "libloading 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", + "objc 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", + "osmesa-sys 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "parking_lot 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", + "wayland-client 0.21.12 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", + "winit 0.19.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "glutin_egl_sys" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "gl_generator 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "glutin_emscripten_sys" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "glutin_gles2_sys" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "gl_generator 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", + "objc 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "glutin_glx_sys" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "gl_generator 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", + "x11-dl 2.18.3 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "glutin_wgl_sys" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "gl_generator 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "harfbuzz" version = "0.3.1" @@ -2115,6 +2204,29 @@ dependencies = [ "x11-dl 2.18.3 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "winit" +version = "0.19.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "android_glue 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "backtrace 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)", + "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", + "cocoa 0.18.4 (registry+https://github.com/rust-lang/crates.io-index)", + "core-foundation 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)", + "core-graphics 0.17.3 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.54 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", + "objc 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", + "parking_lot 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", + "percent-encoding 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", + "smithay-client-toolkit 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", + "wayland-client 0.21.12 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", + "x11-dl 2.18.3 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "x11-dl" version = "2.18.3" @@ -2191,6 +2303,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum crossbeam-utils 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "2760899e32a1d58d5abb31129f8fae5de75220bc2176e77ff7c627ae45c918d9" "checksum crossbeam-utils 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)" = "f8306fcef4a7b563b76b7dd949ca48f52bc1141aa067d2ea09565f3e2652aa5c" "checksum deflate 0.7.19 (registry+https://github.com/rust-lang/crates.io-index)" = "8a6abb26e16e8d419b5c78662aa9f82857c2386a073da266840e474d5055ec86" +"checksum derivative 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6073e9676dbebdddeabaeb63e3b7cefd23c86f5c41d381ee1237cc77b1079898" "checksum dirs 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "3fd78930633bd1c6e35c4b42b1df7b0cbc6bc191146e512bb3bedf243fcc3901" "checksum dlib 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "77e51249a9d823a4cb79e3eca6dcd756153e8ed0157b6c04775d04bf1b13b76a" "checksum downcast-rs 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "f2b92dfd5c2f75260cbf750572f95d387e7ca0ba5e3fbe9e1a33f23025be020f" @@ -2221,6 +2334,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum gl_generator 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "75d69f914b49d9ff32fdf394cbd798f8c716d74fd19f9cc29da3e99797b2a78d" "checksum gleam 0.6.17 (registry+https://github.com/rust-lang/crates.io-index)" = "7f46fd8874e043ffac0d638ed1567a2584f7814f6d72b4db37ab1689004a26c4" "checksum glutin 0.19.0 (registry+https://github.com/rust-lang/crates.io-index)" = "535c6eda58adbb227604b2db10a022ffd6339d7ea3e970f338e7d98aeb24fcc3" +"checksum glutin 0.21.0 (registry+https://github.com/rust-lang/crates.io-index)" = "cb26027a84c3b9e1949ef0df0b6a3db8d0c124243a5c161ea25c7def90cb1474" +"checksum glutin_egl_sys 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "23f48987ab6cb2b61ad903b59e54a2fd0c380a7baff68cffd6826b69a73dd326" +"checksum glutin_emscripten_sys 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "245b3fdb08df6ffed7585365851f8404af9c7e2dd4b59f15262e968b6a95a0c7" +"checksum glutin_gles2_sys 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "89996c30857ae1b4de4b5189abf1ea822a20a9fe9e1c93e5e7b862ff0bdd5cdf" +"checksum glutin_glx_sys 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "1290a5ca5e46fcfa7f66f949cc9d9194b2cb6f2ed61892c8c2b82343631dba57" +"checksum glutin_wgl_sys 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "f801bbc91efc22dd1c4818a47814fc72bf74d024510451b119381579bfa39021" "checksum harfbuzz 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "46f7426266a5ece3e49eae6f48e602c0f8c39917354a847eac9c06437dcde8da" "checksum harfbuzz-sys 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e1042ab0b3e7bc1ff64f7f5935778b644ff2194a1cae5ec52167127d3fd23961" "checksum hashbrown 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "3bae29b6653b3412c2e71e9d486db9f9df5d701941d86683005efb9f2d28e3da" @@ -2365,6 +2484,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" "checksum wincolor 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "561ed901ae465d6185fa7864d63fbd5720d0ef718366c9a4dc83cf6170d7e9ba" "checksum winit 0.18.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8c57c15bd4c0ef18dff33e263e452abe32d00e2e05771cacaa410a14cc1c0776" +"checksum winit 0.19.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d233301129ddd33260b47f76900b50e154b7254546e2edba0e5468a1a5fe4de3" "checksum x11-dl 2.18.3 (registry+https://github.com/rust-lang/crates.io-index)" = "940586acb859ea05c53971ac231685799a7ec1dee66ac0bccc0e6ad96e06b4e3" "checksum xdg 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d089681aa106a86fade1b0128fb5daf07d5867a509ab036d99988dec80429a57" "checksum xml-rs 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3c1cb601d29fe2c2ac60a2b2e5e293994d87a1f6fa9687a31a15270f909be9c2" diff --git a/Cargo.toml b/Cargo.toml index d477c5b9..34e73625 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,6 +6,7 @@ members = [ "demo/common", "demo/magicleap", "demo/native", + "examples/canvas_glutin_minimal", "examples/canvas_minimal", "examples/canvas_moire", "examples/canvas_text", diff --git a/examples/canvas_glutin_minimal/Cargo.toml b/examples/canvas_glutin_minimal/Cargo.toml new file mode 100644 index 00000000..37b25e22 --- /dev/null +++ b/examples/canvas_glutin_minimal/Cargo.toml @@ -0,0 +1,25 @@ +[package] +name = "canvas_glutin_minimal" +version = "0.1.0" +authors = ["Patrick Walton "] +edition = "2018" + +[dependencies] +gl = "0.6" +glutin = "0.21" + +[dependencies.pathfinder_canvas] +path = "../../canvas" + +[dependencies.pathfinder_geometry] +path = "../../geometry" + +[dependencies.pathfinder_gl] +path = "../../gl" + +[dependencies.pathfinder_gpu] +path = "../../gpu" + +[dependencies.pathfinder_renderer] +path = "../../renderer" + diff --git a/examples/canvas_glutin_minimal/src/main.rs b/examples/canvas_glutin_minimal/src/main.rs new file mode 100644 index 00000000..ce9360f4 --- /dev/null +++ b/examples/canvas_glutin_minimal/src/main.rs @@ -0,0 +1,97 @@ +// pathfinder/examples/canvas_glutin_minimal/src/main.rs +// +// Copyright © 2019 The Pathfinder Project Developers. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Demonstrates how to use the Pathfinder canvas API with `glutin`. + +use glutin::dpi::PhysicalSize; +use glutin::{ContextBuilder, ControlFlow, Event, EventsLoop, GlProfile, GlRequest, KeyboardInput}; +use glutin::{VirtualKeyCode, WindowBuilder, WindowEvent}; +use pathfinder_canvas::{CanvasFontContext, CanvasRenderingContext2D, Path2D}; +use pathfinder_geometry::basic::vector::{Vector2F, Vector2I}; +use pathfinder_geometry::basic::rect::RectF; +use pathfinder_geometry::color::ColorF; +use pathfinder_gl::{GLDevice, GLVersion}; +use pathfinder_gpu::resources::FilesystemResourceLoader; +use pathfinder_gpu::{ClearParams, Device}; +use pathfinder_renderer::concurrent::rayon::RayonExecutor; +use pathfinder_renderer::concurrent::scene_proxy::SceneProxy; +use pathfinder_renderer::gpu::renderer::{DestFramebuffer, Renderer}; +use pathfinder_renderer::options::RenderOptions; + +fn main() { + // Calculate the right logical size of the window. + let mut event_loop = EventsLoop::new(); + let hidpi_factor = event_loop.get_primary_monitor().get_hidpi_factor(); + let window_size = Vector2I::new(640, 480); + let physical_window_size = PhysicalSize::new(window_size.x() as f64, window_size.y() as f64); + let logical_window_size = physical_window_size.to_logical(hidpi_factor); + + // Open a window. + let window_builder = WindowBuilder::new().with_title("Minimal example") + .with_dimensions(logical_window_size); + + // Create an OpenGL 3.x context for Pathfinder to use. + let gl_context = ContextBuilder::new().with_gl(GlRequest::Latest) + .with_gl_profile(GlProfile::Core) + .build_windowed(window_builder, &event_loop) + .unwrap(); + + // Load OpenGL, and make the context current. + let gl_context = unsafe { gl_context.make_current().unwrap() }; + gl::load_with(|name| gl_context.get_proc_address(name) as *const _); + + // Create a Pathfinder renderer. + let mut renderer = Renderer::new(GLDevice::new(GLVersion::GL3, 0), + &FilesystemResourceLoader::locate(), + DestFramebuffer::full_window(window_size)); + + // Clear to white. + renderer.device.clear(&ClearParams { color: Some(ColorF::white()), ..ClearParams::default() }); + + // Make a canvas. We're going to draw a house. + let mut canvas = CanvasRenderingContext2D::new(CanvasFontContext::new(), window_size.to_f32()); + + // Set line width. + canvas.set_line_width(10.0); + + // Draw walls. + canvas.stroke_rect(RectF::new(Vector2F::new(75.0, 140.0), Vector2F::new(150.0, 110.0))); + + // Draw door. + canvas.fill_rect(RectF::new(Vector2F::new(130.0, 190.0), Vector2F::new(40.0, 60.0))); + + // Draw roof. + let mut path = Path2D::new(); + path.move_to(Vector2F::new(50.0, 140.0)); + path.line_to(Vector2F::new(150.0, 60.0)); + path.line_to(Vector2F::new(250.0, 140.0)); + path.close_path(); + canvas.stroke_path(path); + + // Render the canvas to screen. + let scene = SceneProxy::from_scene(canvas.into_scene(), RayonExecutor); + scene.build_and_render(&mut renderer, RenderOptions::default()); + gl_context.swap_buffers().unwrap(); + + // Wait for a keypress. + event_loop.run_forever(|event| { + match event { + Event::WindowEvent { event: WindowEvent::CloseRequested, .. } | + Event::WindowEvent { + event: WindowEvent::KeyboardInput { + input: KeyboardInput { virtual_keycode: Some(VirtualKeyCode::Escape), .. }, + .. + }, + .. + } => ControlFlow::Break, + _ => ControlFlow::Continue, + } + }) +} From 5d698998e9452b236e271cc94d384487837fba02 Mon Sep 17 00:00:00 2001 From: Jon Hardie Date: Sat, 15 Jun 2019 16:08:46 +1200 Subject: [PATCH 03/26] [WIP] Initial support for rendering graphic symbols from swf files. --- Cargo.toml | 2 + examples/swf_basic/Cargo.toml | 28 ++ examples/swf_basic/src/main.rs | 136 ++++++ examples/swf_basic/swf/tiger-flat.swf | Bin 0 -> 25311 bytes examples/swf_basic/swf/tiger.swf | Bin 0 -> 18971 bytes flash/Cargo.toml | 21 + flash/src/lib.rs | 207 +++++++++ flash/src/shapes.rs | 616 ++++++++++++++++++++++++++ flash/src/timeline.rs | 32 ++ 9 files changed, 1042 insertions(+) create mode 100644 examples/swf_basic/Cargo.toml create mode 100644 examples/swf_basic/src/main.rs create mode 100644 examples/swf_basic/swf/tiger-flat.swf create mode 100644 examples/swf_basic/swf/tiger.swf create mode 100644 flash/Cargo.toml create mode 100644 flash/src/lib.rs create mode 100644 flash/src/shapes.rs create mode 100644 flash/src/timeline.rs diff --git a/Cargo.toml b/Cargo.toml index d477c5b9..eaa64cae 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,9 +10,11 @@ members = [ "examples/canvas_moire", "examples/canvas_text", "examples/lottie_basic", + "examples/swf_basic", "geometry", "gl", "gpu", + "flash", "lottie", "renderer", "simd", diff --git a/examples/swf_basic/Cargo.toml b/examples/swf_basic/Cargo.toml new file mode 100644 index 00000000..eb64fe17 --- /dev/null +++ b/examples/swf_basic/Cargo.toml @@ -0,0 +1,28 @@ +[package] +name = "swf_basic" +version = "0.1.0" +authors = ["Jon Hardie "] +edition = "2018" + +[dependencies] +gl = "0.6" +sdl2 = "0.32" +sdl2-sys = "0.32" + +swf-parser = "0.7.0" +swf-tree = "0.7.0" + +[dependencies.pathfinder_flash] +path = "../../flash" + +[dependencies.pathfinder_geometry] +path = "../../geometry" + +[dependencies.pathfinder_gl] +path = "../../gl" + +[dependencies.pathfinder_gpu] +path = "../../gpu" + +[dependencies.pathfinder_renderer] +path = "../../renderer" diff --git a/examples/swf_basic/src/main.rs b/examples/swf_basic/src/main.rs new file mode 100644 index 00000000..ea7f8b73 --- /dev/null +++ b/examples/swf_basic/src/main.rs @@ -0,0 +1,136 @@ +// pathfinder/examples/swf_basic/src/main.rs +// +// Copyright © 2019 The Pathfinder Project Developers. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use pathfinder_geometry::basic::vector::{Vector2F, Vector2I}; +use pathfinder_geometry::basic::rect::RectF; +use pathfinder_gl::{GLDevice, GLVersion}; +use pathfinder_gpu::resources::FilesystemResourceLoader; +use pathfinder_gpu::{ClearParams, Device}; +use pathfinder_renderer::concurrent::rayon::RayonExecutor; +use pathfinder_renderer::concurrent::scene_proxy::SceneProxy; +use pathfinder_renderer::gpu::renderer::{DestFramebuffer, Renderer}; +use pathfinder_renderer::options::{RenderOptions, RenderTransform}; +use sdl2::event::Event; +use sdl2::keyboard::Keycode; +use sdl2::video::GLProfile; +use pathfinder_renderer::scene::Scene; +use pathfinder_flash::{draw_paths_into_scene, process_swf_tags}; +use std::env; +use std::fs::read; +use pathfinder_geometry::basic::transform2d::Transform2DF; + +fn main() { + let swf_bytes; + if let Some(path) = env::args().skip(1).next() { + match read(path) { + Ok(bytes) => { + swf_bytes = bytes; + }, + Err(e) => panic!(e) + } + } else { + // NOTE(jon): This is a version of the ghostscript tiger graphic flattened to a single + // layer with no overlapping shapes. This is how artwork is 'natively' created in the Flash + // authoring tool when an artist just draws directly onto the canvas (without 'object' mode + // turned on, which is the default). + // Subsequent shapes with different fills will knock out existing fills where they overlap. + // A downside of this in current pathfinder is that cracks are visible between shape fills - + // especially obvious if you set the context clear color to #ff00ff or similar. + + // Common speculation as to why the swf format stores vector graphics in this way says that + // it is to save on file-size bytes, however in the case of our tiger, it results in a + // larger file than the layered version, since the overlapping shapes and strokes create + // a lot more geometry. I think a more likely explanation for the choice is that it was + // done to reduce overdraw in the software rasterizer running on late 90's era hardware? + // Indeed, this mode gives pathfinders' occlusion culling pass nothing to do! + let default_tiger = include_bytes!("../swf/tiger-flat.swf"); + + // NOTE(jon): This is a version of the same graphic cut and pasted into the Flash authoring + // tool from the SVG version loaded in Illustrator. When layered graphics are pasted + // into Flash, by default they retain their layering, expressed as groups. + // They are still presented as being on a single timeline layer. + // They will be drawn back to front in much the same way as the SVG version. + + //let default_tiger = include_bytes!("../tiger.swf"); + swf_bytes = Vec::from(&default_tiger[..]); + } + + let (_, movie): (_, swf_tree::Movie) = swf_parser::parsers::movie::parse_movie(&swf_bytes[..]).unwrap(); + + // Set up SDL2. + let sdl_context = sdl2::init().unwrap(); + let video = sdl_context.video().unwrap(); + + // Make sure we have at least a GL 3.0 context. Pathfinder requires this. + let gl_attributes = video.gl_attr(); + gl_attributes.set_context_profile(GLProfile::Core); + gl_attributes.set_context_version(3, 3); + + // process swf scene + // TODO(jon): Since swf is a streaming format, this really wants to be a lazy iterator over + // swf frames eventually. + let (library, stage) = process_swf_tags(&movie); + + // Open a window. + let window_size = Vector2I::new(stage.width(), stage.height()); + let window = video.window("Minimal example", window_size.x() as u32, window_size.y() as u32) + .opengl() + .allow_highdpi() + .build() + .unwrap(); + + let pixel_size = Vector2I::new( + window.drawable_size().0 as i32, + window.drawable_size().1 as i32 + ); + let device_pixel_ratio = pixel_size.x() as f32 / window_size.x() as f32; + + // Create the GL context, and make it current. + let gl_context = window.gl_create_context().unwrap(); + gl::load_with(|name| video.gl_get_proc_address(name) as *const _); + window.gl_make_current(&gl_context).unwrap(); + + // Create a Pathfinder renderer. + let mut renderer = Renderer::new(GLDevice::new(GLVersion::GL3, 0), + &FilesystemResourceLoader::locate(), + DestFramebuffer::full_window(pixel_size)); + // Clear to swf stage background color. + let mut scene = Scene::new(); + scene.set_view_box(RectF::new( + Vector2F::default(), + Vector2F::new( + stage.width() as f32 * device_pixel_ratio, + stage.height() as f32 * device_pixel_ratio) + )); + draw_paths_into_scene(&library, &mut scene); + + // Render the canvas to screen. + renderer.device.clear(&ClearParams { + color: Some(stage.background_color()), + ..ClearParams::default() + }); + let scene = SceneProxy::from_scene(scene, RayonExecutor); + let mut render_options = RenderOptions::default(); + let scale_transform = Transform2DF::from_scale( + Vector2F::new(device_pixel_ratio, device_pixel_ratio) + ); + render_options.transform = RenderTransform::Transform2D(scale_transform); + scene.build_and_render(&mut renderer, render_options); + + window.gl_swap_window(); + // Wait for a keypress. + let mut event_pump = sdl_context.event_pump().unwrap(); + loop { + match event_pump.wait_event() { + Event::Quit {..} | Event::KeyDown { keycode: Some(Keycode::Escape), .. } => return, + _ => {} + } + } +} diff --git a/examples/swf_basic/swf/tiger-flat.swf b/examples/swf_basic/swf/tiger-flat.swf new file mode 100644 index 0000000000000000000000000000000000000000..70127188f531f9f5f5ad0fa219e95111bfbc1e83 GIT binary patch literal 25311 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

qxcY4QPw%XhNy?MpOoTlxVJSX_mL%5nt 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 Cs4jm1 literal 0 HcmV?d00001 diff --git a/examples/swf_basic/swf/tiger.swf b/examples/swf_basic/swf/tiger.swf new file mode 100644 index 0000000000000000000000000000000000000000..9bb17c65a7c9a2eebaa0a04b0f3cf8e68b302b22 GIT binary patch literal 18971 zcmV+aKLEf(S5pr}Q~&^YoTPjORFvEM?hK8TND7ilOLsR&42?>Qm)!0RVs} z)Og4D^}%)*xE_BVcVV>>%59!5q-M@I%nRt8HOBSvO!Zf-^<7Dg5p z`dbNlTW1S9T_<`A+o$9Lr1uD72DW-OU@JSYr3LBT@49a-?d|x<$$!E+nOpq@YhlZv zt8e+%fI-jFoY6_wijkRtiSZ8SR)|N`#z5E3(niJ7(o8`3PKs2*OxMg)YwS}S`SvwMH(>oFRb8JHVb*xBBim-*hj`g%NumNw?Pb^^LqR%T#5-8(== zCwg0BOFdIZT?Yet!#h*+G5!+#f1T1TGZ5&%ceuGZOMEwoKUvo9E0XrDzOW0VN-+RGI*T&Z1&Qkp3 zf12vfO!xNX0sqEKqW=@I|4{uCP5=Le(0{1@iDvo#W2XNSg7h!P{Ib*ULz?kt5fmT= zh{D|5+%)2#+!jb6Kv~bg!hn<+0Jy>4l)L+b6X{XtywS^ifD;*fsF%^p8~_jqxK+4; z1p?jx0dTikH$VU>++UyI|M>KX{p(IjYDEnZOArC=%2T&UV9Oq(IN{~)nKIRByBj;L zTTjDm!*pBnHTyTptZL)RH-rTQqc`6>=L@I~BNd}0U&5tCTL2r)H6S3?p^0W|p%A&w z@M6Ua=q&egQjO3I}`-YY})8k50{T!)cCie_sn)Jb`AOjYsWX(02_i@F=W z8Y&bitOdHhL8yW=7S-U%(7P~Sz#kNVzbIg`f8#4O9kM+e6MS46(jUgwK4GEF_Gvdc zC-^e7{$s*sE%)lgc^@_&W=;p^cA_tE)d-xUjIweHk0HcSCrPX z_%Fq3QPe%mP#&RCNrbbk);G%0GIyaRy?BaCf$D4kvU-W^Vs61Mn?E@%DfI@Oikm^2 zU1C0AuS#vl{yFZWAQ$~c_$6XD)G-XJul95DyYkOAR0P;2Z(?Q<%Tvn;>zV7PvIx<=GjQWdgsd22UP)&S(D326g7An*3$ldr$E zfk(dSkgFqv5?3i~I6 zThtE!riqK!@P@BYpo6n-)a2g20s8ZaYOt!e4Fzrr>^`5JrFmvcgGEEC;DMj^NVx9x zmstNghY0H)l97(l^@5^)e`hWY800SsNYnf$8igs3HQtlAIkZ&pJ2{pu z@Dteg+^rtinQmLe%ye9~KJ-iBg}uBu_her(M~#Ulz0Abu5S)3lA#?5zQj$@IgE~!s za37m^>6Pu6KMwpVv||k9B(kuK@?@%_M5^liFxjBS%FQjPGJ8>_ifzpS@e3Ge7G3|U zRmkJ~lA4d$+YNu?x%1gruU~7Z&pgbfjzhcGl^l*|$a|NI;)LlRXb4uKV*3>nuVXQN zUzdS958Jn>gIHqmWjIp?~G@>Hz~YaZbaMbYl9dW zNi53pc8tdaDIY+dNhXX(O^h7#L5Dn`@0e#NJ))p9WS)g026ZyeD@Wy!6V5TDjx$`l z!%jBnE2r~J-o0nzp5G32-B%q{T1$-S*`RRr(K&AujTHrO&W5X=dJe*kp3AnMW=;=3 zayR@MW>v&Wt4zAw>)T<1OVGa-EuiN~_1vwRo+!m6@?C5C6x&L0^HX7A639`$#1Ha3 zs|X}N_E}<4IZjzfh@B_r3*Ib+CqwY>X1>2xcL;5jBWm=h;vGdnjwT($i?7W zl48Ua^Hv`6zOQNBHk3EOUulC$58VY8?a#2Yl@C!w*K0zZ2-cdEUPpho{X>0=GGcxWu>Yk@J)?}aVkObaHm)&3O~YhRBhpuZH+C! z>`al;xRte*QoQ{x=dh32$}ZMNmtD;x8(_5{9x=9(<}TI~JX&#$>-@;AlH zrfn>kq~#EZ6NhVPW#&i3SQQ_DNc%X1PNrGabEcT&O?14FvAiAtRV*TiqI}rfa-K=R zZ=sanmB93WJ`d|eZB*D)P*Q=H!XGT#j}_v2zBvDB6;Y6)VW~z*k1u$1(E?8CsMrp41k%!Px6|_j@#py7+;1Qm>@rC*4J zrRVoip2i;8&t~V&@mNtdQl`XTMk&J*=NKcpIjQsCkzDuWxhMIx;}9J2iKFj^X3MjE zy~gE5%ukY(QwGyW=}R!=D64@Mr(0fel|Ws~wa=!!BsAGo?g~a{QRwotNN~Ke4C@m? z=ZVs3y$?+-(}H)QGdw)ZNwN7NRCHtygK05_rscF_E_?)#xGI zrI;v?Jod_JfIG^D42hN4t$%ZE-?mMg;VpI_G?|gf2UWjHI00?ggJxj;5e>T+6==GZg>a;Y=nUB*|h`%!M83P z@(kLVn?P!Hc>@7&B*)#dquAi(1v_SrI~1$wHG!xr(0{Wui@ z0=D9G?-{mBqu((cyMb;Co{{#tIAw!>8>DkYu~@f3%71ta(lJ_LyI#vfy?Nwa0TqS` z2OAs_a*HYj42YVw7jfOKRKeG1sI^Y?%@C7eC5d zenNc0?gM`&A!zH^T;6nr9bql)mS0fjwlK^ms6QH^u#_?qn>tyG!OnoT>r{;BzxkD) z7yn8^G^zjKcW}#3pb$U6laM}2^@aIV2S~Nn(YZ*Uzic;38}s4wSq1onuMgZ6_(D5( zPT1)hs|zh?M#fyyvfZFf@t5&Fruz!zC@v{hPplVLsqXeud!>Q*{CYa6?)c4nPD%wQQsK5{NB%oJOMyem_?NR>b=w4)|RoZ2z%iKh{r~v;& zc+&Nb-@Zc&T~{T25#cSr!-26lf^Sef7UVU@j|7xut=vfZj;TnKRB&iK z@^lBPqN3Wp#Y3N{2+ZIZ)mGcF>G3kZ_LWl=A;VT7$w?ZUlFvKTIpfu5H4d)8ZyHYC z5UL{JoRt}R9cJzgazoyf7tH!-xH%AX%Iwl3w)IKV-FNu%5VQdh5U~?~Yx7bKC=$ z(;)-sf3*tU^7H&J`IWbO{+^#5Nlx^C!*BbZA4o7O(r`;L*h$f*O{_CPlW2Ol{?(WB zwXQk0OU1OorpQ#GM|SWXAB6UK=?+H9i)Ra}9ot@MZMY;IWW$*5o7{2~dPBQ<4lE{? zX1^;i=PP6P{3af#-|^dnq1k;C^cmOn;grE|6L5|w9P5tXe4p0%k%uzK@*+k4m>m%!4y zCGcHia&ysb0w&I!2t!uodF!aDqdq9KrCZX1Qx@MpXU=h_rNdCRTBrUWmq5#(OW@?s zB~X=iU?Lr7k37>O2veq#51PxzSZ3c3X&C#Gu23Re<>STm16BEMjeq?#gXT>VnS(|0 zA8WiE+}QFUWrNHCJl|{%>r&^p-9L}~cLZmH?ZA<^B4<9(AEX@%w5~#%djCa$#@=t! z4*%Gu9q;DB-LM3;tO%=ALR+;6bze#Pv8kmJF)t3NJM-SC{$~X({#OOH{S1%|4`BzE|Aht_-rD}%I7*Jy43 zYlrrceP2g`dUd}!hFBf@Ee4=HT2v1N2`^YbhaCp24R(}3%M~zxzv^94$pfUHYiaqMr*spk$X__Nzb5nYe z0>zprewGl-Rg!*^hD294fC=X?LS(f0xA&^B?zvU&wcB%OcAf$c|C(_-T0JB+uIYP! zf|`p`c&@${n@avkb2iWMVRtjkGUuGcsCHBats0&r8-^N%JNDzkk?@0JOWAH5)LsNi z-=;4sV=dGvJr*SaNv&ap6l=U%VX2hmW6a-k*@5#LZUb(o9(QeLJytAI-07>#gl}n(!OA*{UYD1Mjm8 z2mP62&&skJdi{RQ+^?me3NV9_140qKaecRPzZ4HjI|gaTD6U;&_5_|}FhEm(1ZO~Z zS4Len$|(37{LG~X{Z(K8 z@;OdhX7#}2yD647y~YZPo82^p%!>D=Mj-KV7lfo0r4?fZ?$myY*&zwARQ-As-+IP8 z{=f@FOnyxAq29q8Qxa_BpwUhN#ZNddZ>j}&M&d{zuY?t>wQhbDsuW2V2`ct$PB-Y~{# zBx{wP5QLW$!6)NLO>xyWPP(`ScNit7BD#aUB5jT9UI%`gXzK+aSfc7E^Gr6o z2LIfB)xNRu{O6g!-LH|qTl*9#j0u_1rQn7I{|uAs3|E6`PXva43j=PuSol=F5b;dK zO{&PY@`n!Vpe_dmLP^h?l>wuc&t*^l#OEYYo44}|oFuMg?c>}u<3C`Z@j z4kb4n9L@aLBYP|dH3`VhAt+l_Hgk79ziz>M8?`$MU@rFBV6)Bua49!mIp}MR&7;$M zj)`y{z+5*zbOa<4IvpNT^~&ik1}!hD4Ivmif}4{LNxmP+&2}B}b3$neEKdrJ&e(v) zF<$`yAng6zG9Odk04X}Dc<=^YB0jRwqb|a};zwo=ZmB&y9$Po}x^wowsjx3|4r16W zgB~uAiSbXe+Gzm{Wq~aF^%ea5e>7_UEzUCtyij;ZQN$Pls?f374u>gk!s$kq_x+8T z*q2q6fEV)p6w@TML3Ms~)hkn^@L(^xSS1M3Z^eBhF!ytK3-~@^loHtKnC&jt>H~_I z;7uQBSNPBUUM1-ftg8aX(W)*dQ=#DVpYkyGThad%ZvA-Wsys}wDq|A&1!37SYqjpW zH{sm;OzVf&UpBlAVj#tGkK&S{NQK_lr1w5bVTSt82<9gl)tKDJL%Y9?8BaFV`6w}g zHb_)98RK54@jT=pyy#}%`LOdl1Jke24Y1m5yniotsqJZ?D`;TQ$-O&8YUdyIj@E`1 zkFdtw-03iGshrTzN|L0_9MY(=_~w@DKj*WOsL*R)_>p;(1uut@?t2K9`Zlj>qYlz- z@|Kp~CGWD~qhP1jo9E+Cc-@t^U2=pCkHbA2){R{^Mk(}uYmAoqdZIq*Os7-A6C6-2 zR-M*I&p;RN{-@+*Z~T}eUXH6wdA~Xv+H!hH_mDwUty`Pk>FIZIwRQBdIX>ga3}zS$ zA+!VmZgUC=DT#B)vkI1{M};RpTjKv3sTGxbYFiX94%?2)MX~L;WUTOIA|zs!G1MZ- zf+x2M3R8dY+dr39)arrJj_#uAQecJTi3zD#ehcR=^H`p-!-y5P20%hU_50XSw53wa z%G2m+cMD2ITR-B5PX(|sECGs^fG05xzjZ>Z22aPfoMvL808p(gSjjmWAVYO|$?EFv zNCvZXp}93>rNQ2uJ%HK}UT0poab=7v9Yp>9z^7JwbNKpVu517Ipt&_8+p3z0Is6wB z2C$2L6J}R&h88!1&m@0m2m01Co{{aB>WNuG7qbV)O4fb?=Ec)7^5$~C4Q={1v6_kP z*ZPU2QZU-(3BJAyl4YjuGbS=I_5t@By_J=F&$m?Z+RnY+?WuOG60HhuG!=qij|RUoQnr)u+8tfSe6Qx@w?0Q^t#y;jCVzkVtC?h*6oV)kc&z@elMPvfR)a~7I^&Cl~ zgv{AgAnH-ZCp99;Nz_34ZQv3$#zQ+85zpb2y|W=&+#R=P2Nh{#+|+C}X#MSo^w>*0 z7UQk#1*;)M=oogg63q!4ndEbdb-iZ&Z-RJs7sN(%VMv>njmY#mcXLF5>63XYA zRLjR=a^g?#2Py;(;iHGM!H8InCR?8kcH(-tJvq!oJbKLC;T>IK;{S}xa4l$vW9fss zEqyFmULv!5uQKP#){vj`B`w<}tz1_BotJj=-0nxx#oB~edIvgkH8sLNHiFtFA536! z>l=_5vyie!AwK8g5$H!ohNzpitx2uFbZ&ASj-p!5q@qOlq??CNIui+5lhFhn1$BQ4 z_b9b$faRB;i!YbMS+~kn-lM6hRlZB9!`7Vpk<_uVAhy22j$F+*Xph674#dh+;g8|` zNUT^$*rE_o*17IR(oxrKTYq7!$ld>LG>UOWY>gTrdLbUKWa545n$&bpbVv8gCXY(1 z1{7iCxx|WI?DajGvOSvfDcie|&K8I6M^eV-huHglaCG{5J5uqcQ_|2x|Jg7lhU7FV zV!;Zq<_9_k8w|Ppc(nC7W(^jD)6=6Bj5A&CPT|bghJO9*Z`LOU@ocqRY~kxjiW3?A z22`uo%!ho>`P4%$O+M8u{}JT($A@m&CG)v z5W2iLc>9q8Z{A9^LB(?39!L z9)C>|U{~_s*U`1T+sFU86Q@cdN(+5-Op<4k)Pd>3!t^abdTl(r#;4Ph`pKJfNCMh0 zpUK|+QuMPvbe}&VN&YID7M_z92%0;OPe|qya9VdH=tvIjoIyG$Kft&u(BG2?ocM^S z(41`sr(mPj^)Lld$qMn~R8Rj2^;c$3;B?JYEGDl}O#q-XQLNOW4@~F`YBTFt0<8HJmWz zFmOAXNB-!AA(`o5Pe&iTy${G=_;n)d0zq^m-med;oeL3<=JMrZprqXy{O9hn3x>ow z3cA~Aa19~ruz6C7pgwP{A44oSvT~!jLnHTA`G(9u329;NZ&{mfqIY91ggWeX_0-mu z+ZJxKH&`q9L)KU!TP;3jKWKA#om!v-mE>X=wUJJJAQT7ZHoN#XMFAj7g-F{gxEN$byEYVsu5Y0S#i-lU@alXGp^s z!tK>|pgEFFc)_9vq>J0O@8ddAHbue~Jc%VUU^RX| z?Ni=|ig{MmyMg+Lda<%%RwiQyL9U8j6>kh(hs5dM#&mKI_zy*l0o5X?8G%|TnK8Cz)pfHM

I()aSbUlelky*Dx`;UVF7x?#eE2bq=Xu{&sXCrW_3&-y` z&4?^VCji{L-igo@JT5DvXET@kAqj>AhKr1)&!((6>C+!wZDvoJ_vNe9SAio^&nJ9~ z@MGa=et`End;2X1KmADEDYwi*c=lan40E{wvW=NFyOKReC{@#Oft$H}4c@kG?-}kI z#>~20y(+6Gn{v@(gtb1~jIK0c(9ybjCdFm+-4DT12ri3wqr7WME0ysB4EZJ&gD#Oc zAyMv_a*F$cj+h_R|3G!RkFetb3wKr))gF#vf%`#4d8x8l1;bRdl6)tg@G;?{i}Mc2 z6D3>oZ*WzEMkD1jJbJ9x`P|$|#1wc?s$i^SJIs9}_>)IpX(GNWAy861(&bJZBzWOt z$c`%`kQ5PO=3;1eBsQM<2r4q|@n)*n6y%oLQ;bBRTrf@Jb%2d(pkN@v9fa-|Ss6&y zYXJi8YFy(~3m>&`XexQxMIoY9ux}M}Gz6-m576d*!)A;jmuFnsDrNk;AJ2ea4TA;a z0P#&MQD0qz0|G0iHtIR^V`13=Fd-a4=gQg=8dlI4lvuDa+3BN*u#}2;_sdSj$Q#Xs z{naBBv%UM6V_{*rM>_?!u7(IC0OH$Oq8eOuJ%dZ9HmW)E17RruFkb9IHMeL4R?tuH zUqRQ&oJ9PiQ$8mOpiU~<3C<+!Z(Jd0NG_4w<*uQj;XT|5u*>iRUlJg`n0AOrE2_r@;pyj zCnS`vJS;b-v7i>j;m-FLv45l=^w4|QFoGu)5I@dPQ0bCu8lH0tg$+Qq>U;*30^{nI z8LHB$7o@l^1_h`2#QUGxJr*Cj@v+>zWSuF`w)|VK5PBdyZWzU#4v3#;C@FR6(2K}i zI)17GKz`Bs3@omOr<-o5Li?&P#dS$ay2d9o^t4<`eE7!S@)DJ`!y+ll`hFRuyifR! zJ_@N60PIIGa^GAcWRY#N$MWG_v!zkmaq<-BeWFJa@9Z?li2b>{i1_n_28=G%bJTigvG~83t9Q!8I$YMG+l3sR6)uLjVwJhCziGJeba-#u zG~->pDac*2A5`Kvj9aL`D$DMr=*N9**VVge9;$D?!eH`HyB;68Dj#0CsP&mOT$i6_ z0_*Ad$xOyHH>b1mOljl~cKjR~H-vIka>`gn%gO{wmR8-~!7J9Xo%ZWKY|gyYXPc5t zjNTNf zFJn{fKX?$otC*CnNYY3iS5w8{2>Epg!+~zK92un@Kakj7FYjK{Z*V-x8lxBuOAD$b z=}$IHNcgsp9`K{P#WRSuyw9c1&>_l@SC}ovnyFtM)fbx(X!rzyS8vj+rP5Q`x#JxN z(J=)3+=52R^t-FPVR%5rc)ID9Or^Goh0FrYu8(q8nP;=RU~@eD(_RcM4+yp=N`Nny z;zB4a3?^6NprK*6@gUqgE~I?#1`rwyx)c{aANQ-h$DgFySj4&H~tl$)OhCX5<2OS_Ewd*GzGKd2(Xa_uV?L0No1gF6a$ZHTVE zEpIcMm?0M*du5}1Wg~@U*Fg!DD)V@Q2<;Y>ZLQ@@Qh15Fzz6J~5hSRD>+gp%mda~k zv1xN?t=(InwhXNzO;-zl^bRkO%3T3*rZFI>ttEGTe+L7$CjM*2L4#iJQ49Fgv5&*S z!wzbanNV8g6XAhI7ci0FAINZRRdJRUJ=a#%*HC896ZwOlU#5^qe3Us*?f3?qqHArj}ks3M|`P~t-g3<9<(-ttMqxbUVl2&||cE=T#tp43SD_xycW5l1p8 z*;`6C-Nny(VnF&Tn5l1zly_y>s6_JG(zvrv=v>=e9y7@dpPEm{d=!gm|CUCN)&3z5 z{!!anU)_bacvrJ{&w|1`)L}hlv4fVNFKM{vPUdnvX}|4vfjuKKavmy(WxOYbB{D+H2U(O&-Zx0cLH$Xm2Os z?7sA+k!YHDjF)8DCmX?~cTzAZCCyOY3PS4$vM$~j^jJ({i=VB1+*^RQ_2WVZv?lUU z?5VRt6);~X;nEW2tERh!cKqyt2}>w#I#zWO2MK+o$ci)z`RQO@qUZMo#wEEVUh?nS zN9H*X=H6agXE=1yp{^GI!dB55R(N*Xzh^H?MEIEX)M>)LYH_X5-|tp4Ku z>f(>V`s$IQ2jgs#9u>3>D@nb4go-B<2sWVpXm2|`xeGI9#!=ho(B{*XokU{OcamS^ zMrc;WH+HT0L}N>9+s1A)E<)Xf@^B2J^^1Gy#8NT;X9&UAbM$IY{clJ$W2_Amef4FY zShx<%ZnBL(w1#MUK|X^sf+gB#SXJFL(-g7c5d$IorZ}&mA0u+6F{>h_Rtp2 zFAGn4003_T0L@ETUPUv^Jv@^U&7z;!r03CLXdtxMY(&Ot!9=J7zlH=sci$w%Zb?JrRcCf}YyizNz6 z4XZj2;bNrJ$dAUZo)=l^cLnezV@d6a#_r_>_OeOQvj-ikyY)ZE`*yK|#DDaCdJN>A zdZA>OrPM{ZJe$)l_oeMoLmAT?(vMwL!!-@VHd3@g-yv?~@P2do-8k1CHc@rLK}hi! zZZv1q7t9{^GI8e94Lr*71p^UAa%4N4aCJAQq8gYv8MHoP{I(vfF+?_&3T$SzX3Qy* z3CaZH%7-xkbp*;3mO_JB-}&C8c@hA@fMrx;u9?HmXVCZM=h2*zG0wzSN=oiZ#sJb- zKnnlhn>8V;oOVw+Mg9rW$>EPrw@Fu%ixPqpPGT%V#3qMQHMu9R3?KIFjpI3&vz+S^ z>hgnDq_g^KgT#6$!%WnMV^=C{wu?M*=klu?w4KvQ=vcm!LoM`NmF!@WeHEb8NLh)HgipGTr&6`EoBUCh-E|w`o*KKB>mqVL!NbQ2iD2(ulAt zFmW1Cwp2CDJY;iZJg_~M6JN8MXJkIZH}~54Wr9udTFHQwMx5EkwCVTkN)wMAQy8zAUPpd7!IFD@zHgCme4_ScLkr@Vqso%Wz_#qq$yo|oF_Y3jMdtEC zihR?XZW5vt8S)50G-T=PqbCPKc{J~6ROW|^w^0Pw_l1v%TfD?@~b;19<8y3_AZe|YnG7k)iv`xQNh53ScV8aVZ=d+YcGbLl34Z>A(b?FJ!(p7x-!c~VuSzWPFBGIPs!m4`V@?=7Qwi|{yspepPtv`!NKpyn!u|4|qfet6D zD@V_l?L_tD?w8nDnbb)i!BL~zQkjD+^IA^8KJY<+?0%SG#doNCu597wW*vV*JTs#lYMZb zPgrIXz#f%z!Ir6TRNbDI&D*7VL%QzIjAWCd9${tjE=zwdij^l2BY&@g_q{r((23dp zXsDJ!tMd6~y^CvOR7hm(hi6v;VpubLhiMsr-Br&x@n zO7-e?6P3A__Aw*DMre}5!kCj5IhD124}6Zp zx9Z#9_?gB%C99hZvZ-3tIp{4nzHrEGE*`C+_1w;4FSc!cjl;8ve9<8PPSZU8|sc z`=bV-5!6NWh8=?{8*=T#(1^Go(-!~j65QFssesHcGtj@{o|C^Vf?Hog&QN1b;r0+ z);*M?SE`D5()7Z$zOZPmEIlYqnDxGMao?6hD@bxeP-v{5ADjI?t6}?u(D0n%$29qN zPSy}@Ot!_{)5U)@#cu^2S9OHE-;8|b{4`y3J(29}#)(vG0*vYu&zt^R+XtuMnS+23 z4e=RbQ_8dF!2WPMA#EYN75x1R1d!JfGI!krVe7&WLU~IoDWI*g&&YfEmpE{pylNMe z76)WxlV1s06fPqgE;O!%UPe`)k-aY#aUGK=doyQO-lM4d0Y`v?GCE~*!$(I-CN@PH zOI5qpC18RF(n+@4O-ax%!%FrzP=95<6p@n!-P%EJC}$!(9l41@7FL&@CB1T`*EGgU z7hFwPI8AbQEMB?q-r%&pWyVOJ|4?$C^#%D0Zt~)D*oT#g`Ldy3d_@a3xaA5COD*k@ zZK`d9V}f6gop~ih!6=o232GC#k7~3idfj@$(MDzoGQf`~UZh$H`1CV*R1rZHqT0!e z7NERDBd5!OAQR}4A}xt7nS2$vvBc-i^C%nmt@%T}TM zsxZPlJQljX^As&!LSuqqY~Z~K9pSyB?^`%%Eeol+@t+%(vx1+DpTRrVKD1Y+9Fm_W z__Q$9Yd9%%&Xy3Z=WAg;FpmHg!Wv!GGWSkO!8G=?DgzrB0L2T?>>piLK5%O)`;I@= zQ8Dp>>_y2cSqo))tpCag~P@(LSUh>OuM4|ho|3gHPhQZ z=unS{x64G&MV30H=De_>btl(}&Wd{4o3TdAag=GkAsf~cL$SZ8oLj8GjkLV%^)MU` zkyuH8z+rS()_c?;f+!+oO|C5KZ0d6BdbE}gdTr+^{aPZF=Hqg#gL5N@5?pY3fa{7V z+XMX&XHu|isF^pM@Bu+0OQ2t2yK^&1cy!4(rxs(5+Y2>hd0SyFS{@#!JpIx$Z#QYL zm$2nfhsA+%rY=sh>XAXF@Mg^eLGrIdUh%u{#+-<2eC>zvlF38AZrCmntYAdgY#BWd zbwiZxgMOSoMRyGVwS%ki3mM4^2}fzMQ!SkODkytZ%Vo4DF>R?`JP)9gQvA#6`sg!N zL>)*GT$=@(p*;|^^)in3Gv}kXoxG9ml{BnJaBM9*=XrBM9SU*;t52&m zM$Vl-*rVy?P@2GmMZ`%y>lS^nv8HPG!(aRJbQZUvN&hjmLI@ zdq2s2ykjWiX?e?_wjY0a%;J?n`ap0lirBuM)W<^O{WVm(R12#)>h2EQ1SKW1FQ3|p zpXf1$KH0pxo%)$K?KIePOA4W`TOj_e5Vvi<*Ha60?(>Y$QBw6@b`Nl-nqA^yvW~wE zO^g!oMJ93o=f|>-fanUCoyt*iWq1a3fkf3JDjAx1_+s8$UOR0N{i2~jl#&$<@) zEPhjTjxTu|aPC5K0C9`ZGgVjL=*x|5hBKx#vTkH1s_LqH8ItljYMQ?kg98l6Ka4=NM>w7I?*JH*g?vAc6_Nh}A>jLR_w6pD|L1PpY}2M;|vB0{xyQQKw5=t`h;CP~#T*O3^P9;a*RzVa9DAm_%9< zN#KZYw<-iKwlrJ2_yLDFCdFG6> zCLEB^ZKRy?uOQ8rbJ`5Q9`eQMQetvV-v?5`q6aNEYzmzn3vDp_IPZn!q0G^v>^1;a z3lAoDAf_|6=T+sdkyYI3?!AXQCiV>apz}=Qqj0SKRrqPK)9AG*v1i8Hm@%oeqB?); z>30B%!X`r`8DU0zOw>nB@EO#az0Zv%|H>32-`wAun z{zfw}U%Ipuxv9JkMF*J0$bOQWGmb~{u*Ks~#Nu1T_*=xb%u*wU{jnx+SiSp(2}g9e zHoUj>J_yv=O}Rh#gYg!y_76Zu4b{>zfxzECYW z3ld*>=&T*5jp=?jdPSIRw=x+srPXK}XJCj5dh%jaZ8`PfDH%=Fo1|`}PuTngr9>1o z^vPPTlI{*Xr;=kEzA@79EbaozT>&3xCI)1o$+gGJoz13E{Ph=0vsbcbQ3;0uEL3gN z;0<%ZwhZILr03};J_*z`%O_xU5Cf3P?_;CdpPVL#4l-dN zfBsMXKc1q?x3P}l2n)FxKA6iu(yC|NU0j7J`|>WlH(}wo;wjbv91ydc507s;Jl_!x zkxWboIsO=R1T>H}+_h`}Q=$D9KU)<;l>j5(6Hq%iA2cCs)Ishr0mE4Edxd4|Mvgg< z(etBFO}&MBbgU%9r{*|RZysgUFi#grE%mxS0ySYg0LT{#O|2_B^iRVjmrLbGQs+xS z+Od9z$llpVtkz)y>=A-LqI9W1Zq0cDcw#!(5WH1-+5GCaFDd9uAdcyL{?h zvBK^J>{nW_)@)_p=#RjC&i-427N@KBIdsu41^Zc!!X^GDU&C8AU^EZhAzg=>!E8R` z1HQiZ!(XzIwHnkPUk>xK+Ndjiz6~PPH(2T-N|^+ND)U7>voZYY;z+Ub*hvI!yhDa~ zzm2?(tFnszaeoviccnK7ug8ML@g-p&ZjZdhv(Pvh0HdEFHT#?vq>BD7H`zPtOVjt< zfwW5V_yT~zEQ1H1MG33FR2i4%3~icaH}Z%A z`npGSa;S*??&p=YnPT37T^m??t^r3==s6f2ir5lymd!XIeRi3ffuOSICCmKuiA?_~ zKI}?gvV}TF?^o!lNjqcWd+WSGqJ7MF6nj?H1d3EnoXLxsDSN`NA1~oXy<~4suVe%h z=#`+81zj)~>f3xUPY zUwp*Y0i*OHLXLA(9Lg!Bkp%vH6U+bfIu-h!bkb&{c%KEzjk1E*)~Sq#*NHyFg@-6a z6T4>pk;*GOLDD^0U44_5rC0JU7&c_vl~2$^ma$7EOiJt&m;X;8XBN!{;)U_3B5G-i zX*;xnB8hb@(OPN^LaB<{NoyAjwT0R$XslIRsa8aZ^^Y2Bb!d!W5Nm?k8cItgV=}hd zTAB9roSAuW&j0Ep;L zdY5j9 z{ND);I4QNGsSC63#B29miu2oO4@e(BXE39)mxGNSVnDJP9cm84uzZ*M8!Y2|v)8W^R@?P}}BV5^=kri)!VY?Jsf77*>f|$5e63lNk zox${I_CGsf4n%+7teVq9RX1_@d^sDz+}K*|qz$^St?R~#coX(NOFDry%i>B&J2qiq zgQ9KOBk>}Hlsr{jciMv0wP$d!I$W(70sOA#Pp{4#|1M~V+;l&)l}KGxOA*L+us?(>*WIxk;Ax0Ic}B|)w;;VE%Cu+<=$g~U6T#U$PtJ9Hw0 zb&|#}n;z>m{jDwXLq|7{QjH)1Rdw52GtGvfa3f96cw81ME5kwA|2a^}8C`2OeS*7d z^D*itdxP3iyRoHV*(WW;{SpxE3zaY0D9HK&HY8^lL4D0tSfaS?E7t4LYU6q5oXs*cEv%snE8K6xJ1ctgQRFe{f5@RQofR~9&ERYFNGg{#iHF`z{*(_Sq~*9 zJ(d(Kd5N{_dtVIs zEvC4E{-%6w4D5FHO;GJ03!!Cq0G+PmtK#ZhTb;x{dW4!bxqor+%-Iirk}dYY5IEWH_hZOv|b%`^+}TQdshW`^oep_imy;=I;( z_;!}%sFoZ#=gB)U9e>t0bcWCQWLSS;KwD_zpM#cx)5tCq@`0YkylDzl%fQI-oT|u@ zQNQn?msEQ=j-Fn9&tZ>QYbnLstDTh{tV|9%QCqLhNEz)nM89mJT~J*a@yKTjyDafI_fR5~tu^-M^J96a9r0XD#nR(*X@; zt_9^U3>}qf%B1lw#uS+BWtYq+MWgYnU14JxAy&d|0&xM`bc`l8kzc_ea<^wWhnT%$ zL0EQZbO2WlQz`mQSI(>)6w`lj9R76nN|e3OkQ3K?lUu-5GI233FPE4gcb}QWcko1h zBF6|VeJ)2nV{4tbxe+mC{zsA{T{QwHVX8bH;vUHIr~j@?*Y3Ywt?6?S#VO-@2y?xJ zCT*28#RPH8jc~U<1l#aUW}*@{A!#>u>Yl3vL4-BNG0^0>fzeO76+;%JgBN;`CTYitz((*#R-TwYI(kmmRfG#j*~Zp4T)q6c3V+vOxW?_EOnC#rVmd23)&e>( z3F)!>rV4unBh@CgM`b3l{{wF$wF{+NXZE?P!B%iCS`5r630`si zS<}LYy^U@DlkUOD)^2|wr{7=@xmYf?C1IH0eUo$RTurb1%#C`BwID`=Hib`a!dEa* zS=f8l9IxU5JXq(HvR}-#x$m(*Kl-74Ga@V;INEc11lrG|B+-%2Nc-aHG$fq@BwSV8 z!Nd)jMk(4}ZLEAfX0Gka$W2yf&+W0mcj}zV4h!N5oN;Sqy0LFU4J`;U_&P0cz$t|j zo7sLV72;z+d=W@%K!11t_Cyqd1;0Lomr9P-65SaH{Fe3q9zk-*EWfr5@H!tlQrNML z9>qp}{J|0#9Y7o%IOQe;=qOrh*M!4q#c_|cdYZU;FKF`gz83}HxVh85xrqMP4u1p3 GAu>ri%Vnql literal 0 HcmV?d00001 diff --git a/flash/Cargo.toml b/flash/Cargo.toml new file mode 100644 index 00000000..2dff909f --- /dev/null +++ b/flash/Cargo.toml @@ -0,0 +1,21 @@ +[package] +name = "pathfinder_flash" +version = "0.1.0" +authors = ["Jon Hardie "] +edition = "2018" + +[dependencies] +swf-parser = "0.7.0" +swf-tree = "0.7.0" + +[dependencies.pathfinder_geometry] +path = "../geometry" + +[dependencies.pathfinder_renderer] +path = "../renderer" + +[dependencies.pathfinder_gl] +path = "../gl" + +[dependencies.pathfinder_gpu] +path = "../gpu" diff --git a/flash/src/lib.rs b/flash/src/lib.rs new file mode 100644 index 00000000..fdc8b57e --- /dev/null +++ b/flash/src/lib.rs @@ -0,0 +1,207 @@ +// pathfinder/flash/src/lib.rs +// +// Copyright © 2019 The Pathfinder Project Developers. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use std::ops::Add; +use pathfinder_geometry::color::{ColorU, ColorF}; +use pathfinder_geometry::outline::{Outline, Contour}; +use pathfinder_geometry::basic::vector::Vector2F; +use pathfinder_geometry::stroke::{OutlineStrokeToFill, StrokeStyle}; +use pathfinder_renderer::scene::{PathObject, Scene}; + +use swf_tree; +use swf_tree::tags::SetBackgroundColor; +use swf_tree::{Tag, SRgb8, Movie}; + +use crate::shapes::{GraphicLayers, PaintOrLine}; + +mod shapes; + +type SymbolId = u16; + +// In swf, most values are specified in a fixed point format known as "twips" or twentieths of +// a pixel. We store twips in their integer form, as if we were to convert them to floating point +// at the beginning of the pipeline it's easy to start running into precision errors when we add +// coordinate deltas and then try and compare coords for equality. + +#[derive(Copy, Clone, Debug, PartialEq)] +struct Twips(i32); + +impl Twips { + // Divide twips by 20 to get the f32 value, just to be used once all processing + // of the swf coords is completed and we want to output. + fn as_f32(&self) -> f32 { + self.0 as f32 / 20.0 + } +} + +impl Add for Twips { + type Output = Twips; + fn add(self, rhs: Twips) -> Self { + Twips(self.0 + rhs.0) + } +} + +#[derive(Copy, Clone, Debug, PartialEq)] +struct Point2 { + x: T, + y: T +} + +impl Point2 { + fn as_f32(self: Point2) -> Point2 { + Point2 { + x: self.x.as_f32(), + y: self.y.as_f32(), + } + } +} + +impl Add for Point2 { + type Output = Self; + fn add(self, rhs: Self) -> Self { + Point2 { x: self.x + rhs.x, y: self.y + rhs.y } + } +} + +enum Symbol { + Graphic(GraphicLayers), + // Timeline, // TODO(jon) +} + +pub struct Stage { + // TODO(jon): Support some kind of lazy frames iterator. + // frames: Timeline, + background_color: SRgb8, + width: i32, + height: i32, +} + +impl Stage { + pub fn width(&self) -> i32 { + self.width + } + + pub fn height(&self) -> i32 { + self.height + } + + pub fn background_color(&self) -> ColorF { + ColorU { + r: self.background_color.r, + g: self.background_color.g, + b: self.background_color.b, + a: 255, + }.to_f32() + } +} + + +pub struct SymbolLibrary(Vec); + +impl SymbolLibrary { + fn add_symbol(&mut self, symbol: Symbol) { + self.0.push(symbol); + } + + fn symbols(&self) -> &Vec { + &self.0 + } +} + +pub fn process_swf_tags(movie: &Movie) -> (SymbolLibrary, Stage) { + let mut symbol_library = SymbolLibrary(Vec::new()); + let stage_width = Twips(movie.header.frame_size.x_max); + let stage_height = Twips(movie.header.frame_size.y_max); + // let num_frames = movie.header.frame_count; + + let mut stage = Stage { + // frames: Timeline(Vec::new()), // TODO(jon) + background_color: SRgb8 { + r: 255, + g: 255, + b: 255 + }, + width: stage_width.as_f32() as i32, + height: stage_height.as_f32() as i32, + }; + + for tag in &movie.tags { + match tag { + Tag::SetBackgroundColor(SetBackgroundColor { color }) => { + stage.background_color = *color; + }, + Tag::DefineShape(shape) => { + symbol_library.add_symbol(Symbol::Graphic(shapes::decode_shape(&shape))); + // We will assume that symbol ids just go up, and are 1 based. + let symbol_id: SymbolId = shape.id; + debug_assert!(symbol_id as usize == symbol_library.0.len()); + } + _ => () + } + } + (symbol_library, stage) +} + +#[allow(irrefutable_let_patterns)] +pub fn draw_paths_into_scene(library: &SymbolLibrary, scene: &mut Scene) { + for symbol in library.symbols() { + // NOTE: Right now symbols only contain graphics. + if let Symbol::Graphic(graphic) = symbol { + for style_layer in graphic.layers() { + debug_assert_ne!(style_layer.shapes().len(), 0); + let mut path = Outline::new(); + let paint_id = scene.push_paint(&style_layer.fill()); + + for shape in style_layer.shapes() { + let mut contour = Contour::new(); + let Point2 { x, y } = shape.outline.first().unwrap().from.as_f32(); + contour.push_endpoint(Vector2F::new(x, y)); + for segment in &shape.outline { + let Point2 { x, y } = segment.to.as_f32(); + match segment.ctrl { + Some(ctrl) => { + let Point2 { x: ctrl_x, y: ctrl_y } = ctrl.as_f32(); + contour.push_quadratic( + Vector2F::new(ctrl_x, ctrl_y), + Vector2F::new(x, y) + ); + } + None => { + contour.push_endpoint(Vector2F::new(x, y)); + }, + } + } + if shape.is_closed() { + // NOTE: I'm not sure if this really does anything in this context, + // since all our closed shapes already have coincident start and end points. + contour.close(); + } + path.push_contour(contour); + } + + if let PaintOrLine::Line(line) = style_layer.kind() { + let mut stroke_to_fill = OutlineStrokeToFill::new(&path, StrokeStyle { + line_width: line.width.as_f32(), + line_cap: line.cap, + line_join: line.join, + }); + stroke_to_fill.offset(); + path = stroke_to_fill.into_outline(); + } + + scene.push_path(PathObject::new( + path, + paint_id, + String::new() + )); + } + } + } +} diff --git a/flash/src/shapes.rs b/flash/src/shapes.rs new file mode 100644 index 00000000..cf724f50 --- /dev/null +++ b/flash/src/shapes.rs @@ -0,0 +1,616 @@ +use pathfinder_renderer::paint::Paint; +use pathfinder_geometry::stroke::{LineJoin, LineCap}; +use crate::{Twips, Point2}; +use std::mem; +use std::cmp::Ordering; +use swf_tree::{ + FillStyle, + StraightSRgba8, + LineStyle, + fill_styles, + JoinStyle, + CapStyle, + join_styles, + ShapeRecord, + shape_records, + Vector2D +}; +use pathfinder_geometry::color::ColorU; +use swf_tree::tags::DefineShape; + +#[derive(Clone, Copy, Debug)] +pub(crate) struct LineSegment { + pub(crate) from: Point2, + pub(crate) to: Point2, + pub(crate) ctrl: Option>, +} + +impl LineSegment { + fn reverse(&mut self) { + let tmp = self.from; + self.from = self.to; + self.to = tmp; + } +} + +#[derive(Copy, Clone, PartialEq, Debug)] +pub(crate) enum LineDirection { + Left, + Right, +} + +impl LineDirection { + fn reverse(&mut self) { + *self = match self { + LineDirection::Right => LineDirection::Left, + LineDirection::Left => LineDirection::Right + }; + } +} + +#[derive(Clone, Debug)] +pub(crate) struct Shape { + pub(crate) outline: Vec, // Could be Vec<(start, end)> + direction: LineDirection, + reversed: bool, +} + +impl Shape { + pub fn new_with_direction(direction: LineDirection) -> Shape { + Shape { + direction, + outline: Vec::new(), + reversed: false, + } + } + + fn prepend_shape(&mut self, shape: &mut Shape) { + shape.append_shape(&self); + mem::swap(&mut self.outline, &mut shape.outline); + } + + fn append_shape(&mut self, shape: &Shape) { + self.outline.extend_from_slice(&shape.outline); + } + + fn add_line_segment(&mut self, segment: LineSegment) { + self.outline.push(segment); + } + + #[inline] + fn len(&self) -> usize { + self.outline.len() + } + + #[inline] + fn first(&self) -> &LineSegment { + &self.outline.first().unwrap() + } + + #[inline] + fn last(&self) -> &LineSegment { + &self.outline.last().unwrap() + } + + #[inline] + fn comes_before(&self, other: &Shape) -> bool { + self.last().to == other.first().from + } + + #[inline] + fn comes_after(&self, other: &Shape) -> bool { + self.first().from == other.last().to + } + + #[inline] + pub(crate) fn is_closed(&self) -> bool { + self.len() > 1 && self.comes_after(self) + } + + fn reverse(&mut self) { + self.reversed = !self.reversed; + self.direction.reverse(); + for segment in &mut self.outline { + segment.reverse(); + } + self.outline.reverse(); + } +} + +pub(crate) struct SwfLineStyle { + color: Paint, + pub(crate) width: Twips, + pub(crate) join: LineJoin, + pub(crate) cap: LineCap, +} + +pub(crate) enum PaintOrLine { + Paint(Paint), + Line(SwfLineStyle), +} + +pub(crate) struct StyleLayer { + fill: PaintOrLine, + // TODO(jon): Maybe shapes are actually slices into a single buffer, then we don't + // need to realloc anything, we're just shuffling shapes around? + shapes: Vec, +} + +impl StyleLayer { + pub(crate) fn kind(&self) -> &PaintOrLine { + &self.fill + } + + fn is_fill(&self) -> bool { + match &self.fill { + PaintOrLine::Paint(_) => true, + PaintOrLine::Line(_) => false, + } + } + + pub(crate) fn fill(&self) -> Paint { + match &self.fill { + PaintOrLine::Paint(paint) => *paint, + PaintOrLine::Line(line) => line.color, + } + } + + fn push_new_shape(&mut self, direction: LineDirection) { + if let Some(prev_shape) = self.shapes.last_mut() { + // Check that the previous shape was actually used, otherwise reuse it. + if prev_shape.len() != 0 { + self.shapes.push(Shape::new_with_direction(direction)) + } else { + prev_shape.direction = direction; + } + } else { + self.shapes.push(Shape::new_with_direction(direction)) + } + } + + pub(crate) fn shapes(&self) -> &Vec { + &self.shapes + } + + fn shapes_mut(&mut self) -> &mut Vec { + &mut self.shapes + } + + fn current_shape_mut(&mut self) -> &mut Shape { + self.shapes.last_mut().unwrap() + } + + fn consolidate_edges(&mut self) { + // Reverse left fill shape fragments in place. + { + self.shapes + .iter_mut() + .filter(|frag| frag.direction == LineDirection::Left) + .for_each(|frag| frag.reverse()); + } + + // Sort shapes into [closed...open] + if self.is_fill() { + // I think sorting is only necessary when we want to have closed shapes, + // lines don't really need this? + self.shapes.sort_unstable_by(|a, b| { + match (a.is_closed(), b.is_closed()) { + (true, true) | (false, false) => Ordering::Equal, + (true, false) => Ordering::Less, + (false, true) => Ordering::Greater, + } + }); + } + + // A cursor at the index of the first unclosed shape, if any. + let first_open_index = self.shapes + .iter() + .position(|frag| !frag.is_closed()); + + if let Some(first_open_index) = first_open_index { + if self.shapes.len() - first_open_index >= 2 { + // TODO(jon): This might be sped up by doing it in a way that we don't have + // to allocate more vecs? + // Also, maybe avoid path reversal, and just flag the path as reversed and iterate it + // backwards. + let unmatched_pieces = find_matches(first_open_index, &mut self.shapes, false); + if let Some(mut unmatched_pieces) = unmatched_pieces { + if self.is_fill() { + // If they didn't match before, they're probably parts of inner shapes + // and should be reversed again so they have correct winding + let unclosed = find_matches(0, &mut unmatched_pieces, true); + // If it's a shape we should always be able to close it. + debug_assert!(unclosed.is_none()); + } + for dropped in &mut unmatched_pieces { + dropped.reverse(); + } + self.shapes.extend_from_slice(&unmatched_pieces); + } + // FIXME(jon): Sometimes we don't get the correct winding of internal closed shapes, + // need to figure out why this happens. + } + } + } +} + + +fn get_new_styles<'a>( + fills: &'a Vec, + lines: &'a Vec +) -> impl Iterator + 'a { + // This enforces the order that fills and line groupings are added in. + // Fills always come first. + fills.iter().filter_map(|fill_style| { + match fill_style { + FillStyle::Solid( + fill_styles::Solid { + color: StraightSRgba8 { + r, + g, + b, + a + } + } + ) => { + Some(PaintOrLine::Paint(Paint { + color: ColorU { + r: *r, + g: *g, + b: *b, + a: *a + } + })) + }, + _ => unimplemented!("Unimplemented fill style") + } + }).chain( + lines.iter().filter_map(|LineStyle { + width, + fill, + join, + start_cap, + end_cap: _, + /* + TODO(jon): Handle these cases? + pub no_h_scale: bool, + pub no_v_scale: bool, + pub no_close: bool, + pub pixel_hinting: bool, + */ + .. + }| { + if let FillStyle::Solid(fill_styles::Solid { + color: StraightSRgba8 { + r, + g, + b, + a + } + }) = fill { + // NOTE: PathFinder doesn't support different cap styles for start and end of + // strokes, so lets assume that they're always the same for the inputs we care about. + // Alternately, we split a line in two with a diff cap style for each. + // assert_eq!(start_cap, end_cap); + Some(PaintOrLine::Line(SwfLineStyle { + width: Twips(*width as i32), + color: Paint { color: ColorU { r: *r, g: *g, b: *b, a: *a } }, + join: match join { + JoinStyle::Bevel => LineJoin::Bevel, + JoinStyle::Round => LineJoin::Round, + JoinStyle::Miter(join_styles::Miter { limit }) => { + LineJoin::Miter(*limit as f32) + }, + }, + cap: match start_cap { + CapStyle::None => LineCap::Butt, + CapStyle::Square => LineCap::Square, + CapStyle::Round => LineCap::Round, + }, + })) + } else { + unimplemented!("unimplemented line fill style"); + } + }) + ) +} + +pub(crate) fn decode_shape(shape: &DefineShape) -> GraphicLayers { + let DefineShape { + shape, + // id, + // has_fill_winding, NOTE(jon): Could be important for some inputs? + // has_non_scaling_strokes, + // has_scaling_strokes, + .. + } = shape; + let mut graphic = GraphicLayers::new(); + let mut current_line_style = None; + let mut current_left_fill = None; + let mut current_right_fill = None; + let mut prev_pos = None; + + let mut some_fill_set = false; + let mut both_fills_set; + let mut both_fills_same = false; + let mut both_fills_set_and_same = false; + + // Create style groups for initially specified fills and lines. + for fills_or_line in get_new_styles(&shape.initial_styles.fill, &shape.initial_styles.line) { + match fills_or_line { + PaintOrLine::Paint(fill) => graphic.begin_fill_style(fill), + PaintOrLine::Line(line) => graphic.begin_line_style(line), + } + } + + for record in &shape.records { + match record { + ShapeRecord::StyleChange( + shape_records::StyleChange { + move_to, + new_styles, + line_style, + left_fill, + right_fill, + } + ) => { + // Start a whole new style grouping. + if let Some(new_style) = new_styles { + // Consolidate current style grouping and begin a new one. + graphic.end_style_group(); + graphic.begin_style_group(); + for fills_or_line in get_new_styles(&new_style.fill, &new_style.line) { + match fills_or_line { + PaintOrLine::Paint(fill) => graphic.begin_fill_style(fill), + PaintOrLine::Line(line) => graphic.begin_line_style(line), + } + } + } + + // If there's a change in right fill + if let Some(fill_id) = right_fill { + if *fill_id == 0 { + current_right_fill = None; + } else { + current_right_fill = Some(*fill_id); + graphic + .with_fill_style_mut(*fill_id) + .unwrap() + .push_new_shape(LineDirection::Right); + } + } + // If there's a change in left fill + if let Some(fill_id) = left_fill { + if *fill_id == 0 { + current_left_fill = None; + } else { + current_left_fill = Some(*fill_id); + graphic + .with_fill_style_mut(*fill_id) + .unwrap() + .push_new_shape(LineDirection::Left); + } + } + + some_fill_set = current_left_fill.is_some() || current_right_fill.is_some(); + both_fills_set = current_left_fill.is_some() && current_right_fill.is_some(); + both_fills_same = current_left_fill == current_right_fill; + both_fills_set_and_same = both_fills_set && both_fills_same; + + // If there's a change in line style + if let Some(style_id) = line_style { + if *style_id == 0 { + current_line_style = None; + } else { + current_line_style = Some(*style_id); + graphic + .with_line_style_mut(*style_id) + .unwrap() + .push_new_shape(LineDirection::Right); + } + } + + // Move to, start new shape fragments with the current styles. + if let Some(Vector2D { x, y }) = move_to { + let to: Point2 = Point2 { x: Twips(*x), y: Twips(*y) }; + prev_pos = Some(to); + + // If we didn't start a new shape for the current fill due to a fill + // style change earlier, we definitely want to start a new shape now, + // since each move_to command indicates a new shape fragment. + if let Some(current_right_fill) = current_right_fill { + graphic + .with_fill_style_mut(current_right_fill) + .unwrap() + .push_new_shape(LineDirection::Right); + } + if let Some(current_left_fill) = current_left_fill { + graphic + .with_fill_style_mut(current_left_fill) + .unwrap() + .push_new_shape(LineDirection::Left); + } + if let Some(current_line_style) = current_line_style { + // TODO(jon): Does the direction of this line depend on the current + // fill directions? + graphic + .with_line_style_mut(current_line_style) + .unwrap() + .push_new_shape(LineDirection::Right); + } + } + }, + ShapeRecord::Edge( + shape_records::Edge { + delta, + control_delta, + } + ) => { + let from = prev_pos.unwrap(); + let to = Point2 { + x: from.x + Twips(delta.x), + y: from.y + Twips(delta.y) + }; + prev_pos = Some(to); + let new_segment = LineSegment { + from, + to, + ctrl: control_delta.map(|Vector2D { x, y }| { + Point2 { + x: from.x + Twips(x), + y: from.y + Twips(y), + } + }), + }; + if some_fill_set && !both_fills_same { + for fill_id in [ + current_right_fill, + current_left_fill + ].iter() { + if let Some(fill_id) = fill_id { + graphic + .with_fill_style_mut(*fill_id) + .unwrap() + .current_shape_mut() + .add_line_segment(new_segment); + } + } + } else if both_fills_set_and_same { + for (fill_id, direction) in [ + (current_right_fill, LineDirection::Right), + (current_left_fill, LineDirection::Left) + ].iter() { + // NOTE: If both left and right fill are set the same, + // then we don't record the edge as part of the current shape; + // it's will just be an internal stroke inside an otherwise solid + // shape, and recording these edges as part of the shape means that + // we can't determine the closed shape outline later. + if let Some(fill_id) = fill_id { + graphic + .with_fill_style_mut(*fill_id) + .unwrap() + .push_new_shape(*direction); + } + } + } + if let Some(current_line_style) = current_line_style { + graphic + .with_line_style_mut(current_line_style) + .unwrap() + .current_shape_mut() + .add_line_segment(new_segment); + } + } + } + } + // NOTE: Consolidate current group of styles, joining edges of shapes/strokes where + // possible and forming closed shapes. In swf, all filled shapes should always be closed, + // so there will always be a solution for joining shape line segments together so that + // the start point and end point are coincident. + graphic.end_style_group(); + graphic +} + +fn find_matches( + mut first_open_index: usize, + shapes: &mut Vec, + reverse: bool +) -> Option> { + let mut dropped_pieces = None; + while first_open_index < shapes.len() { + // Take the last unclosed value, and try to join it onto + // one of the other unclosed values. + let mut last = shapes.pop().unwrap(); + if reverse { + last.reverse(); + } + let mut found_match = false; + for i in first_open_index..shapes.len() { + let fragment = &mut shapes[i]; + debug_assert!(!fragment.is_closed()); + if last.comes_after(fragment) { + // NOTE(jon): We do realloc quite a bit here, I wonder if it's worth trying + // to avoid that? Could do it with another level of indirection, where an outline + // is a list of fragments. + + // println!("app ({}, {})", last.reversed, fragment.reversed); + fragment.append_shape(&last); + found_match = true; + } else if last.comes_before(fragment) { + // println!("pre ({}, {})", last.reversed, fragment.reversed); + fragment.prepend_shape(&mut last); + found_match = true; + } + if found_match { + if fragment.is_closed() { + // Move the shape that was just closed to the left side of the current slice, + // and advance the cursor. + shapes.swap(first_open_index, i); + first_open_index += 1; + } + break; + } + } + if !found_match { + // Have we tried matching a reversed version of this segment? + // move last back onto the array, it will never be closed, presumably because + // it's a set of line segments rather than a shape that needs to be closed. + let dropped_pieces: &mut Vec = dropped_pieces.get_or_insert(Vec::new()); + dropped_pieces.push(last); + } + } + dropped_pieces +} + +pub(crate) struct GraphicLayers { + style_layers: Vec, + base_layer_offset: usize, + stroke_layer_offset: Option, +} + +impl GraphicLayers { + fn new() -> GraphicLayers { + GraphicLayers { style_layers: Vec::new(), stroke_layer_offset: None, base_layer_offset: 0 } + } + + fn begin_style_group(&mut self) { + self.stroke_layer_offset = None; + self.base_layer_offset = self.style_layers.len(); + } + + fn begin_fill_style(&mut self, fill: Paint) { + self.style_layers.push(StyleLayer { fill: PaintOrLine::Paint(fill), shapes: Vec::new() }) + } + + fn begin_line_style(&mut self, line: SwfLineStyle) { + if self.stroke_layer_offset.is_none() { + self.stroke_layer_offset = Some(self.style_layers.len()); + } + self.style_layers.push(StyleLayer { fill: PaintOrLine::Line(line), shapes: Vec::new() }) + } + + fn with_fill_style_mut(&mut self, fill_id: usize) -> Option<&mut StyleLayer> { + self.style_layers.get_mut(self.base_layer_offset + fill_id - 1) + } + + fn with_line_style_mut(&mut self, line_id: usize) -> Option<&mut StyleLayer> { + self.style_layers.get_mut((self.stroke_layer_offset.unwrap() + line_id) - 1) + } + + pub(crate) fn layers(&self) -> &Vec { + &self.style_layers + } + + fn end_style_group(&mut self) { + for style_layer in &mut self.style_layers[self.base_layer_offset..] { + // There can be an unused style group at the end of each layer, which we should remove. + if let Some(last) = style_layer.shapes().last() { + if last.len() == 0 { + style_layer.shapes_mut().pop(); + } + } + style_layer.consolidate_edges(); + } + } +} + diff --git a/flash/src/timeline.rs b/flash/src/timeline.rs new file mode 100644 index 00000000..662dba00 --- /dev/null +++ b/flash/src/timeline.rs @@ -0,0 +1,32 @@ +struct PlacementInfo { + symbol_id: u32, + translate_x: Twips, + translate_y: Twips, +} + +struct Timeline(Vec); + +impl Timeline { + fn first(&self) -> &Frame { + &self.0[0] + } + + fn last(&self) -> &Frame { + &self.0[self.0.len() - 1] + } + + fn first_mut(&mut self) -> &mut Frame { + &mut self.0[0] + } + + fn last_mut(&mut self) -> &mut Frame { + let last = self.0.len() - 1; + &mut self.0[last] + } +} + +struct Frame { + duration_frames_initial: u16, + duration_remaining_frames: u16, + placements: Vec +} From 5c5fe00b276e6d18e1752f2d7f56c6190daa9355 Mon Sep 17 00:00:00 2001 From: Patrick Walton Date: Mon, 17 Jun 2019 13:16:03 -0700 Subject: [PATCH 04/26] Fix build problem --- demo/common/src/device.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/demo/common/src/device.rs b/demo/common/src/device.rs index 29b27540..a34f7f83 100644 --- a/demo/common/src/device.rs +++ b/demo/common/src/device.rs @@ -63,7 +63,7 @@ where ) -> GroundVertexArray { let vertex_array = device.create_vertex_array(); - let position_attr = device.get_vertex_attr(&ground_program.program, "Position"); + let position_attr = device.get_vertex_attr(&ground_program.program, "Position").unwrap(); device.bind_vertex_array(&vertex_array); device.use_program(&ground_program.program); From b17d6c605ab13c3e2cac1e9fc961c478dd6013ce Mon Sep 17 00:00:00 2001 From: jonathanhardie Date: Wed, 19 Jun 2019 11:25:26 +1200 Subject: [PATCH 05/26] Remove incorrect debug assertion --- Cargo.lock | 162 ++++++++++++++++++++++++++++++++++++++------ flash/src/shapes.rs | 1 - 2 files changed, 140 insertions(+), 23 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 18ff3a79..36119c38 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -44,7 +44,7 @@ name = "approx" version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", + "num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -90,7 +90,7 @@ dependencies = [ [[package]] name = "autocfg" -version = "0.1.2" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -98,7 +98,7 @@ name = "backtrace" version = "0.3.15" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "autocfg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "autocfg 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", "backtrace-sys 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)", "cfg-if 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.54 (registry+https://github.com/rust-lang/crates.io-index)", @@ -143,6 +143,11 @@ name = "block" version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "build_const" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "byteorder" version = "1.3.1" @@ -233,7 +238,7 @@ version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "num-integer 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)", - "num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", + "num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", "time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -348,6 +353,14 @@ dependencies = [ "libc 0.2.54 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "crc" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "build_const 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "crc32fast" version = "1.2.0" @@ -518,7 +531,7 @@ version = "0.19.8" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "euclid_macros 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", + "num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -570,7 +583,7 @@ name = "float-cmp" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", + "num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -796,6 +809,11 @@ dependencies = [ "gl_generator 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "half" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "harfbuzz" version = "0.3.1" @@ -827,6 +845,11 @@ dependencies = [ "serde 1.0.91 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "hex" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "humantime" version = "1.2.0" @@ -847,7 +870,7 @@ dependencies = [ "num-derive 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", "num-iter 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)", "num-rational 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)", - "num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", + "num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", "png 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)", "scoped_threadpool 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -861,7 +884,7 @@ dependencies = [ "lzw 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)", "num-iter 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)", "num-rational 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", + "num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", "png 0.14.1 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -989,7 +1012,7 @@ name = "line_drawing" version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", + "num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1031,7 +1054,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "arrayvec 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)", "euclid 0.19.8 (registry+https://github.com/rust-lang/crates.io-index)", - "num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", + "num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1042,6 +1065,16 @@ dependencies = [ "lyon_geom 0.12.4 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "lzma-rs" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "crc 1.8.1 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "lzw" version = "0.10.0" @@ -1108,6 +1141,15 @@ name = "nodrop" version = "0.1.13" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "nom" +version = "4.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "memchr 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "version_check 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "num" version = "0.1.42" @@ -1115,7 +1157,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "num-integer 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)", "num-iter 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)", - "num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", + "num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1133,7 +1175,7 @@ name = "num-integer" version = "0.1.39" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", + "num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1142,7 +1184,7 @@ version = "0.1.37" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "num-integer 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)", - "num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", + "num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1151,7 +1193,7 @@ version = "0.1.42" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "num-integer 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)", - "num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", + "num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1160,13 +1202,16 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "num-integer 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)", - "num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", + "num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "num-traits" -version = "0.2.6" +version = "0.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "autocfg 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", +] [[package]] name = "num_cpus" @@ -1194,7 +1239,7 @@ name = "ordered-float" version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", + "num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1291,6 +1336,18 @@ dependencies = [ "usvg 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "pathfinder_flash" +version = "0.1.0" +dependencies = [ + "pathfinder_geometry 0.3.0", + "pathfinder_gl 0.1.0", + "pathfinder_gpu 0.1.0", + "pathfinder_renderer 0.1.0", + "swf-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "swf-tree 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "pathfinder_geometry" version = "0.3.0" @@ -1512,7 +1569,7 @@ name = "rand" version = "0.6.5" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "autocfg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "autocfg 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.54 (registry+https://github.com/rust-lang/crates.io-index)", "rand_chacha 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1530,7 +1587,7 @@ name = "rand_chacha" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "autocfg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "autocfg 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1591,7 +1648,7 @@ name = "rand_pcg" version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "autocfg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "autocfg 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", "rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1936,6 +1993,58 @@ dependencies = [ "phf 0.7.24 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "swf-fixed" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "serde 1.0.91 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "swf-parser" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "half 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "inflate 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "lzma-rs 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "memchr 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "nom 4.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", + "regex 1.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.39 (registry+https://github.com/rust-lang/crates.io-index)", + "swf-fixed 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", + "swf-tree 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "swf-tree" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "hex 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.91 (registry+https://github.com/rust-lang/crates.io-index)", + "swf-fixed 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "swf_basic" +version = "0.1.0" +dependencies = [ + "gl 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", + "pathfinder_flash 0.1.0", + "pathfinder_geometry 0.3.0", + "pathfinder_gl 0.1.0", + "pathfinder_gpu 0.1.0", + "pathfinder_renderer 0.1.0", + "sdl2 0.32.2 (registry+https://github.com/rust-lang/crates.io-index)", + "sdl2-sys 0.32.6 (registry+https://github.com/rust-lang/crates.io-index)", + "swf-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "swf-tree 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "syn" version = "0.15.34" @@ -2271,13 +2380,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum arrayvec 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)" = "92c7fb76bc8826a8b33b4ee5bb07a247a81e76764ab4d55e8f73e3a4d8808c71" "checksum ascii 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a5fc969a8ce2c9c0c4b0429bb8431544f6658283c8326ba5ff8c762b75369335" "checksum atty 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "9a7d5b8723950951411ee34d271d99dddcc2035a16ab25310ea2c8cfd4369652" -"checksum autocfg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a6d640bee2da49f60a4068a7fae53acde8982514ab7bae8b8cea9e88cbcfd799" +"checksum autocfg 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "0e49efa51329a5fd37e7c79db4621af617cd4e3e5bc224939808d076077077bf" "checksum backtrace 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)" = "f106c02a3604afcdc0df5d36cc47b44b55917dbaf3d808f71c163a0ddba64637" "checksum backtrace-sys 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)" = "797c830ac25ccc92a7f8a7b9862bde440715531514594a6154e3d4a54dd769b6" "checksum base64 0.9.3 (registry+https://github.com/rust-lang/crates.io-index)" = "489d6c0ed21b11d038c31b6ceccca973e65d73ba3bd8ecb9a2babf5546164643" "checksum bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "228047a76f468627ca71776ecdebd732a3423081fcf5125585bcd7c49886ce12" "checksum blake2-rfc 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)" = "5d6d530bdd2d52966a6d03b7a964add7ae1a288d25214066fd4b600f0f796400" "checksum block 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "0d8c1fef690941d3e7788d328517591fecc684c084084702d6ff1641e993699a" +"checksum build_const 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "39092a32794787acd8525ee150305ff051b0aa6cc2abaf193924f5ab05425f39" "checksum byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a019b10a2a7cdeb292db131fc8113e57ea2a908f6e7894b0c3c671893b65dbeb" "checksum cc 1.0.36 (registry+https://github.com/rust-lang/crates.io-index)" = "a0c56216487bb80eec9c4516337b2588a4f2a2290d72a1416d930e4dcdb0c90d" "checksum cesu8 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6d43a04d8753f35258c91f8ec639f792891f748a1edbd759cf1dcea3382ad83c" @@ -2296,6 +2406,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum core-foundation-sys 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e7ca8a5221364ef15ce201e8ed2f609fc312682a8f4e0e3d4aa5879764e0fa3b" "checksum core-graphics 0.17.3 (registry+https://github.com/rust-lang/crates.io-index)" = "56790968ab1c8a1202a102e6de05fc6e1ec87da99e4e93e9a7d13efbfc1e95a9" "checksum core-text 13.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d95a72b5e50e549969dd88eff3047495fe5b8c6f028635442c2b708be707e669" +"checksum crc 1.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d663548de7f5cca343f1e0a48d14dcfb0e9eb4e079ec58883b7251539fa10aeb" "checksum crc32fast 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ba125de2af0df55319f41944744ad91c71113bf74a4646efff39afe1f6842db1" "checksum crossbeam-channel 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "0f0ed1a4de2235cabda8558ff5840bffb97fcb64c97827f354a451307df5f72b" "checksum crossbeam-deque 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f739f8c5363aca78cfb059edf753d8f0d36908c348f3d8d1503f03d8b75d9cf3" @@ -2340,9 +2451,11 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum glutin_gles2_sys 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "89996c30857ae1b4de4b5189abf1ea822a20a9fe9e1c93e5e7b862ff0bdd5cdf" "checksum glutin_glx_sys 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "1290a5ca5e46fcfa7f66f949cc9d9194b2cb6f2ed61892c8c2b82343631dba57" "checksum glutin_wgl_sys 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "f801bbc91efc22dd1c4818a47814fc72bf74d024510451b119381579bfa39021" +"checksum half 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9353c2a89d550b58fa0061d8ed8d002a7d8cdf2494eb0e432859bd3a9e543836" "checksum harfbuzz 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "46f7426266a5ece3e49eae6f48e602c0f8c39917354a847eac9c06437dcde8da" "checksum harfbuzz-sys 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e1042ab0b3e7bc1ff64f7f5935778b644ff2194a1cae5ec52167127d3fd23961" "checksum hashbrown 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "3bae29b6653b3412c2e71e9d486db9f9df5d701941d86683005efb9f2d28e3da" +"checksum hex 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "805026a5d0141ffc30abb3be3173848ad46a1b1664fe632428479619a3644d77" "checksum humantime 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3ca7e5f2e110db35f93b837c81797f3714500b81d517bf20c431b16d3ca4f114" "checksum image 0.19.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ebdff791af04e30089bde8ad2a632b86af433b40c04db8d70ad4b21487db7a6a" "checksum image 0.21.1 (registry+https://github.com/rust-lang/crates.io-index)" = "293e54ce142a936a39da748ba8178ae6aa1914b82d846a4278f11590c89bf116" @@ -2368,6 +2481,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c84ec4b527950aa83a329754b01dbe3f58361d1c5efacd1f6d68c494d08a17c6" "checksum lyon_geom 0.12.4 (registry+https://github.com/rust-lang/crates.io-index)" = "0ea0ba5f8d2d91d6d895aca54d1ec0d84ddfa4826f33fbfe8abb39f08f9e4153" "checksum lyon_path 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e9dc8e0746b7cca11960b602f7fe037bb067746a01eab4aa502fed1494544843" +"checksum lzma-rs 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "9550ba35a4d6bb6be7f273bce93af3a3141c517bf7d7298763a7149e1bdb9af5" "checksum lzw 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7d947cbb889ed21c2a84be6ffbaebf5b4e0f4340638cba0444907e38b56be084" "checksum malloc_buf 0.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "62bb907fe88d54d8d9ce32a3cceab4218ed2f6b7d35617cafe9adf84e43919cb" "checksum memchr 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2efc7bc57c883d4a4d6e3246905283d8dae951bb3bd32f49d6ef297f546e1c39" @@ -2377,13 +2491,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum nfd 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "8e752e3c216bc8a491c5b59fa46da10f1379ae450b19ac688e07f4bb55042e98" "checksum nix 0.13.0 (registry+https://github.com/rust-lang/crates.io-index)" = "46f0f3210768d796e8fa79ec70ee6af172dacbe7147f5e69be5240a47778302b" "checksum nodrop 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)" = "2f9667ddcc6cc8a43afc9b7917599d7216aa09c463919ea32c59ed6cac8bc945" +"checksum nom 4.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2ad2a91a8e869eeb30b9cb3119ae87773a8f4ae617f41b1eb9c154b2905f7bd6" "checksum num 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)" = "4703ad64153382334aa8db57c637364c322d3372e097840c72000dabdcf6156e" "checksum num-derive 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "eafd0b45c5537c3ba526f79d3e75120036502bebacbb3f3220914067ce39dbf2" "checksum num-integer 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)" = "e83d528d2677f0518c570baf2b7abdcf0cd2d248860b68507bdcb3e91d4c0cea" "checksum num-iter 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)" = "af3fdbbc3291a5464dc57b03860ec37ca6bf915ed6ee385e7c6c052c422b2124" "checksum num-rational 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)" = "ee314c74bd753fc86b4780aa9475da469155f3848473a261d2d18e35245a784e" "checksum num-rational 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4e96f040177bb3da242b5b1ecf3f54b5d5af3efbbfb18608977a5d2767b22f10" -"checksum num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "0b3a5d7cc97d6d30d8b9bc8fa19bf45349ffe46241e8816f50f62f6d6aaabee1" +"checksum num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "6ba9a427cfca2be13aa6f6403b0b7e7368fe982bfa16fccc450ce74c46cd9b32" "checksum num_cpus 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1a23f0ed30a54abaa0c7e83b1d2d87ada7c3c23078d1d87815af3e3b6385fbba" "checksum numtoa 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b8f8bdf33df195859076e54ab11ee78a1b208382d3a26ec40d142ffc1ecc49ef" "checksum objc 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "31d20fd2b37e07cf5125be68357b588672e8cefe9a96f8c17a9d46053b3e590d" @@ -2453,6 +2568,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum strsim 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a" "checksum svgdom 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7a9b53b3ed152fc6b871f7232a8772c640567fd25d056941450637ecba32924d" "checksum svgtypes 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c43c25e6de7264024b5e351eb0c342039eb5acf51f2e9d0099bbd324b661453b" +"checksum swf-fixed 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "bf3c575807f18641c5e079568b53630a46baf441da57caccd9ced9a9ee70f941" +"checksum swf-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5b6349830c1ed5d26b97d801e3fb8664556e12a01560e3479e3961e8f5675a05" +"checksum swf-tree 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c075cea0328cc5f6ee694bcd1c43534d1186a730d79258b10735f8f08e2f1baa" "checksum syn 0.15.34 (registry+https://github.com/rust-lang/crates.io-index)" = "a1393e4a97a19c01e900df2aec855a29f71cf02c402e2f443b8d2747c25c5dbe" "checksum synstructure 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "73687139bf99285483c96ac0add482c3776528beac1d97d444f6e91f203a2015" "checksum term 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "edd106a334b7657c10b7c540a0106114feadeb4dc314513e97df481d5d966f42" diff --git a/flash/src/shapes.rs b/flash/src/shapes.rs index cf724f50..73d55603 100644 --- a/flash/src/shapes.rs +++ b/flash/src/shapes.rs @@ -527,7 +527,6 @@ fn find_matches( let mut found_match = false; for i in first_open_index..shapes.len() { let fragment = &mut shapes[i]; - debug_assert!(!fragment.is_closed()); if last.comes_after(fragment) { // NOTE(jon): We do realloc quite a bit here, I wonder if it's worth trying // to avoid that? Could do it with another level of indirection, where an outline From 487577a11b85145f85fc9bcfcac0ec8b4f34486a Mon Sep 17 00:00:00 2001 From: Patrick Walton Date: Wed, 5 Jun 2019 14:35:46 -0700 Subject: [PATCH 06/26] Add Metal support. This commit substantially reworks the `pathfinder_gpu` API to better support modern APIs like Metal. It should open the door to `gfx-rs`, `wgpu`, Vulkan, and D3D12 backends relatively straightforwardly. A new example, `canvas_metal_minimal`, has been added. Note that the new Metal shaders require a patched version of `spirv-cross` to build properly. An upstream patch is forthcoming. --- .gitignore | 1 + Cargo.lock | 89 + Cargo.toml | 2 + c/include/pathfinder/pathfinder.h | 32 +- c/src/lib.rs | 81 +- demo/common/Cargo.toml | 9 + demo/common/src/device.rs | 15 +- demo/common/src/lib.rs | 48 +- demo/common/src/renderer.rs | 140 +- demo/common/src/ui.rs | 16 +- demo/common/src/window.rs | 32 +- demo/magicleap/src/lib.rs | 1 + demo/native/Cargo.toml | 8 + demo/native/src/main.rs | 107 +- examples/c_canvas_minimal/c_canvas_minimal.c | 10 +- examples/canvas_glutin_minimal/src/main.rs | 16 +- examples/canvas_metal_minimal/Cargo.toml | 31 + examples/canvas_metal_minimal/src/main.rs | 87 + examples/canvas_minimal/src/main.rs | 14 +- examples/canvas_moire/src/main.rs | 16 +- examples/canvas_text/src/main.rs | 14 +- geometry/src/color.rs | 22 +- gl/src/lib.rs | 456 +++-- gpu/src/lib.rs | 124 +- metal/Cargo.toml | 24 + metal/src/lib.rs | 1484 +++++++++++++++++ renderer/Cargo.toml | 1 + renderer/src/builder.rs | 8 +- renderer/src/concurrent/scene_proxy.rs | 16 +- renderer/src/gpu/mod.rs | 1 + renderer/src/gpu/options.rs | 60 + renderer/src/gpu/renderer.rs | 803 +++++---- renderer/src/gpu_data.rs | 1 + renderer/src/lib.rs | 2 + renderer/src/options.rs | 15 +- renderer/src/scene.rs | 10 +- renderer/src/z_buffer.rs | 1 + resources/shaders/gl3/debug_solid.fs.glsl | 2 + resources/shaders/gl3/debug_solid.vs.glsl | 6 +- resources/shaders/gl3/debug_texture.fs.glsl | 2 + resources/shaders/gl3/debug_texture.vs.glsl | 10 +- resources/shaders/gl3/demo_ground.fs.glsl | 2 + resources/shaders/gl3/demo_ground.vs.glsl | 8 +- resources/shaders/gl3/fill.fs.glsl | 2 + resources/shaders/gl3/fill.vs.glsl | 16 +- resources/shaders/gl3/post.fs.glsl | 2 + resources/shaders/gl3/post.vs.glsl | 8 +- resources/shaders/gl3/reproject.fs.glsl | 2 + resources/shaders/gl3/reproject.vs.glsl | 13 +- resources/shaders/gl3/stencil.fs.glsl | 2 + resources/shaders/gl3/stencil.vs.glsl | 2 + resources/shaders/gl3/tile_alpha.fs.glsl | 2 + .../shaders/gl3/tile_alpha_monochrome.vs.glsl | 10 +- .../shaders/gl3/tile_alpha_multicolor.vs.glsl | 10 +- resources/shaders/gl3/tile_solid.fs.glsl | 2 + .../shaders/gl3/tile_solid_monochrome.vs.glsl | 9 +- .../shaders/gl3/tile_solid_multicolor.vs.glsl | 9 +- resources/shaders/metal/debug_solid.fs.metal | 10 +- resources/shaders/metal/debug_solid.vs.metal | 12 +- .../shaders/metal/debug_texture.fs.metal | 14 +- .../shaders/metal/debug_texture.vs.metal | 17 +- resources/shaders/metal/demo_ground.fs.metal | 11 +- resources/shaders/metal/demo_ground.vs.metal | 15 +- resources/shaders/metal/fill.fs.metal | 11 +- resources/shaders/metal/fill.vs.metal | 29 +- resources/shaders/metal/post.fs.metal | 38 +- resources/shaders/metal/post.vs.metal | 9 +- resources/shaders/metal/reproject.fs.metal | 14 +- resources/shaders/metal/reproject.vs.metal | 16 +- resources/shaders/metal/stencil.fs.metal | 1 + resources/shaders/metal/stencil.vs.metal | 3 +- resources/shaders/metal/tile_alpha.fs.metal | 11 +- .../metal/tile_alpha_monochrome.vs.metal | 26 +- .../metal/tile_alpha_multicolor.vs.metal | 27 +- resources/shaders/metal/tile_solid.fs.metal | 1 + .../metal/tile_solid_monochrome.vs.metal | 21 +- .../metal/tile_solid_multicolor.vs.metal | 22 +- resources/shaders/spirv/debug_solid.fs.spv | Bin 644 -> 0 bytes resources/shaders/spirv/debug_solid.vs.spv | Bin 1252 -> 0 bytes resources/shaders/spirv/debug_texture.fs.spv | Bin 1064 -> 0 bytes resources/shaders/spirv/debug_texture.vs.spv | Bin 1516 -> 0 bytes resources/shaders/spirv/demo_ground.fs.spv | Bin 908 -> 0 bytes resources/shaders/spirv/demo_ground.vs.spv | Bin 1328 -> 0 bytes resources/shaders/spirv/fill.fs.spv | Bin 2688 -> 0 bytes resources/shaders/spirv/fill.vs.spv | Bin 3908 -> 0 bytes resources/shaders/spirv/post.fs.spv | Bin 6864 -> 0 bytes resources/shaders/spirv/post.vs.spv | Bin 1080 -> 0 bytes resources/shaders/spirv/reproject.fs.spv | Bin 1212 -> 0 bytes resources/shaders/spirv/reproject.vs.spv | Bin 1144 -> 0 bytes resources/shaders/spirv/stencil.fs.spv | Bin 352 -> 0 bytes resources/shaders/spirv/stencil.vs.spv | Bin 908 -> 0 bytes resources/shaders/spirv/tile_alpha.fs.spv | Bin 1140 -> 0 bytes .../spirv/tile_alpha_monochrome.vs.spv | Bin 3876 -> 0 bytes .../spirv/tile_alpha_multicolor.vs.spv | Bin 4128 -> 0 bytes resources/shaders/spirv/tile_solid.fs.spv | Bin 376 -> 0 bytes .../spirv/tile_solid_monochrome.vs.spv | Bin 2016 -> 0 bytes .../spirv/tile_solid_multicolor.vs.spv | Bin 2268 -> 0 bytes shaders/Makefile | 26 +- shaders/debug_solid.vs.glsl | 4 +- shaders/debug_texture.vs.glsl | 8 +- shaders/demo_ground.vs.glsl | 6 +- shaders/fill.vs.glsl | 16 +- shaders/post.vs.glsl | 6 +- shaders/reproject.vs.glsl | 12 +- shaders/tile_alpha_vertex.inc.glsl | 8 +- shaders/tile_solid_vertex.inc.glsl | 7 +- ui/src/lib.rs | 117 +- 107 files changed, 3344 insertions(+), 1090 deletions(-) create mode 100644 examples/canvas_metal_minimal/Cargo.toml create mode 100644 examples/canvas_metal_minimal/src/main.rs create mode 100644 metal/Cargo.toml create mode 100644 metal/src/lib.rs create mode 100644 renderer/src/gpu/options.rs delete mode 100644 resources/shaders/spirv/debug_solid.fs.spv delete mode 100644 resources/shaders/spirv/debug_solid.vs.spv delete mode 100644 resources/shaders/spirv/debug_texture.fs.spv delete mode 100644 resources/shaders/spirv/debug_texture.vs.spv delete mode 100644 resources/shaders/spirv/demo_ground.fs.spv delete mode 100644 resources/shaders/spirv/demo_ground.vs.spv delete mode 100644 resources/shaders/spirv/fill.fs.spv delete mode 100644 resources/shaders/spirv/fill.vs.spv delete mode 100644 resources/shaders/spirv/post.fs.spv delete mode 100644 resources/shaders/spirv/post.vs.spv delete mode 100644 resources/shaders/spirv/reproject.fs.spv delete mode 100644 resources/shaders/spirv/reproject.vs.spv delete mode 100644 resources/shaders/spirv/stencil.fs.spv delete mode 100644 resources/shaders/spirv/stencil.vs.spv delete mode 100644 resources/shaders/spirv/tile_alpha.fs.spv delete mode 100644 resources/shaders/spirv/tile_alpha_monochrome.vs.spv delete mode 100644 resources/shaders/spirv/tile_alpha_multicolor.vs.spv delete mode 100644 resources/shaders/spirv/tile_solid.fs.spv delete mode 100644 resources/shaders/spirv/tile_solid_monochrome.vs.spv delete mode 100644 resources/shaders/spirv/tile_solid_multicolor.vs.spv diff --git a/.gitignore b/.gitignore index 82600a0a..4150bad5 100644 --- a/.gitignore +++ b/.gitignore @@ -6,6 +6,7 @@ target /site/dist node_modules /examples/c_canvas_minimal/build +/shaders/build # Editors *.swp diff --git a/Cargo.lock b/Cargo.lock index 18ff3a79..c35ee108 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -161,6 +161,24 @@ dependencies = [ "pathfinder_renderer 0.1.0", ] +[[package]] +name = "canvas_metal_minimal" +version = "0.1.0" +dependencies = [ + "foreign-types 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", + "gl 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", + "metal 0.14.0 (registry+https://github.com/rust-lang/crates.io-index)", + "objc 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", + "pathfinder_canvas 0.1.0", + "pathfinder_geometry 0.3.0", + "pathfinder_gl 0.1.0", + "pathfinder_gpu 0.1.0", + "pathfinder_metal 0.1.0", + "pathfinder_renderer 0.1.0", + "sdl2 0.32.2 (registry+https://github.com/rust-lang/crates.io-index)", + "sdl2-sys 0.32.6 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "canvas_minimal" version = "0.1.0" @@ -419,13 +437,16 @@ name = "demo" version = "0.1.0" dependencies = [ "color-backtrace 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", + "foreign-types 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "gl 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", "jemallocator 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", + "metal 0.14.0 (registry+https://github.com/rust-lang/crates.io-index)", "nfd 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)", "pathfinder_demo 0.1.0", "pathfinder_geometry 0.3.0", "pathfinder_gl 0.1.0", "pathfinder_gpu 0.1.0", + "pathfinder_metal 0.1.0", "pathfinder_simd 0.3.0", "pretty_env_logger 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "sdl2 0.32.2 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1083,6 +1104,23 @@ name = "memoffset" version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "metal" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", + "block 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "cocoa 0.18.4 (registry+https://github.com/rust-lang/crates.io-index)", + "core-graphics 0.17.3 (registry+https://github.com/rust-lang/crates.io-index)", + "foreign-types 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.54 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", + "objc 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", + "objc-foundation 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "objc_id 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "nfd" version = "0.0.4" @@ -1187,6 +1225,33 @@ version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "malloc_buf 0.0.6 (registry+https://github.com/rust-lang/crates.io-index)", + "objc_exception 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "objc-foundation" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "block 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "objc 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", + "objc_id 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "objc_exception" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "gcc 0.3.55 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "objc_id" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "objc 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1280,9 +1345,11 @@ dependencies = [ "gl 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", "image 0.21.1 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", + "metal 0.14.0 (registry+https://github.com/rust-lang/crates.io-index)", "pathfinder_geometry 0.3.0", "pathfinder_gl 0.1.0", "pathfinder_gpu 0.1.0", + "pathfinder_metal 0.1.0", "pathfinder_renderer 0.1.0", "pathfinder_simd 0.3.0", "pathfinder_svg 0.1.0", @@ -1356,10 +1423,28 @@ dependencies = [ "usvg 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "pathfinder_metal" +version = "0.1.0" +dependencies = [ + "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", + "block 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "cocoa 0.18.4 (registry+https://github.com/rust-lang/crates.io-index)", + "core-foundation 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)", + "foreign-types 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", + "metal 0.14.0 (registry+https://github.com/rust-lang/crates.io-index)", + "objc 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", + "pathfinder_geometry 0.3.0", + "pathfinder_gpu 0.1.0", + "pathfinder_simd 0.3.0", +] + [[package]] name = "pathfinder_renderer" version = "0.1.0" dependencies = [ + "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", "byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "fixedbitset 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", "hashbrown 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2374,6 +2459,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum memmap 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e2ffa2c986de11a9df78620c01eeaaf27d94d3ff02bf81bfcca953102dd0c6ff" "checksum memmap 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6585fd95e7bb50d6cc31e20d4cf9afb4e2ba16c5846fc76793f11218da9c475b" "checksum memoffset 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0f9dc261e2b62d7a622bf416ea3c5245cdd5d9a7fcc428c0d06804dfce1775b3" +"checksum metal 0.14.0 (registry+https://github.com/rust-lang/crates.io-index)" = "cd3f21d259068945192293b7a98b1c6844af9eb7602e393c405198b229efc157" "checksum nfd 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "8e752e3c216bc8a491c5b59fa46da10f1379ae450b19ac688e07f4bb55042e98" "checksum nix 0.13.0 (registry+https://github.com/rust-lang/crates.io-index)" = "46f0f3210768d796e8fa79ec70ee6af172dacbe7147f5e69be5240a47778302b" "checksum nodrop 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)" = "2f9667ddcc6cc8a43afc9b7917599d7216aa09c463919ea32c59ed6cac8bc945" @@ -2387,6 +2473,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum num_cpus 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1a23f0ed30a54abaa0c7e83b1d2d87ada7c3c23078d1d87815af3e3b6385fbba" "checksum numtoa 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b8f8bdf33df195859076e54ab11ee78a1b208382d3a26ec40d142ffc1ecc49ef" "checksum objc 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "31d20fd2b37e07cf5125be68357b588672e8cefe9a96f8c17a9d46053b3e590d" +"checksum objc-foundation 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "1add1b659e36c9607c7aab864a76c7a4c2760cd0cd2e120f3fb8b952c7e22bf9" +"checksum objc_exception 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "098cd29a2fa3c230d3463ae069cecccc3fdfd64c0d2496ab5b96f82dab6a00dc" +"checksum objc_id 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c92d4ddb4bd7b50d730c215ff871754d0da6b2178849f8a2a2ab69712d0c073b" "checksum ordered-float 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "18869315e81473c951eb56ad5558bbc56978562d3ecfb87abb7a1e944cea4518" "checksum osmesa-sys 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "88cfece6e95d2e717e0872a7f53a8684712ad13822a7979bc760b9c77ec0013b" "checksum owning_ref 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "49a4b8ea2179e6a2e27411d3bca09ca6dd630821cf6894c6c7c8467a8ee7ef13" diff --git a/Cargo.toml b/Cargo.toml index 34e73625..83f67f54 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -7,6 +7,7 @@ members = [ "demo/magicleap", "demo/native", "examples/canvas_glutin_minimal", + "examples/canvas_metal_minimal", "examples/canvas_minimal", "examples/canvas_moire", "examples/canvas_text", @@ -15,6 +16,7 @@ members = [ "gl", "gpu", "lottie", + "metal", "renderer", "simd", "svg", diff --git a/c/include/pathfinder/pathfinder.h b/c/include/pathfinder/pathfinder.h index 8962e782..d924ce7b 100644 --- a/c/include/pathfinder/pathfinder.h +++ b/c/include/pathfinder/pathfinder.h @@ -30,12 +30,9 @@ extern "C" { #define PF_GL_VERSION_GL3 0 #define PF_GL_VERSION_GLES3 1 -// `gpu` +// `renderer` -#define PF_CLEAR_FLAGS_HAS_COLOR 0x1 -#define PF_CLEAR_FLAGS_HAS_DEPTH 0x2 -#define PF_CLEAR_FLAGS_HAS_STENCIL 0x4 -#define PF_CLEAR_FLAGS_HAS_RECT 0x8 +#define PF_RENDERER_OPTIONS_FLAGS_HAS_BACKGROUND_COLOR 0x1 // Types @@ -85,24 +82,21 @@ typedef uint32_t PFGLVersion; // `gpu` -typedef uint8_t PFClearFlags; -struct PFClearParams { - PFColorF color; - float depth; - uint8_t stencil; - PFRectI rect; - PFClearFlags flags; -}; -typedef struct PFClearParams PFClearParams; struct PFResourceLoader; typedef struct PFResourceLoader *PFResourceLoaderRef; // `renderer` -struct PFRenderOptions { +typedef uint8_t PFRendererOptionsFlags; +struct PFRendererOptions { + PFColorF background_color; + PFRendererOptionsFlags flags; +}; +struct PFBuildOptions { uint32_t placeholder; }; -typedef struct PFRenderOptions PFRenderOptions; +typedef struct PFRendererOptions PFRendererOptions; +typedef struct PFBuildOptions PFBuildOptions; struct PFScene; typedef struct PFScene *PFSceneRef; struct PFSceneProxy; @@ -142,17 +136,17 @@ PFGLDestFramebufferRef PFGLDestFramebufferCreateFullWindow(const PFVector2I *win void PFGLDestFramebufferDestroy(PFGLDestFramebufferRef dest_framebuffer); PFGLDeviceRef PFGLDeviceCreate(PFGLVersion version, uint32_t default_framebuffer); void PFGLDeviceDestroy(PFGLDeviceRef device); -void PFGLDeviceClear(PFGLDeviceRef device, const PFClearParams *params); void PFGLLoadWith(PFGLFunctionLoader loader, void *userdata); PFGLRendererRef PFGLRendererCreate(PFGLDeviceRef device, PFResourceLoaderRef resources, - PFGLDestFramebufferRef dest_framebuffer); + PFGLDestFramebufferRef dest_framebuffer, + const PFRendererOptions *options); void PFGLRendererDestroy(PFGLRendererRef renderer); /// Returns a borrowed reference to the device. PFGLDeviceRef PFGLRendererGetDevice(PFGLRendererRef renderer); void PFSceneProxyBuildAndRenderGL(PFSceneProxyRef scene_proxy, PFGLRendererRef renderer, - const PFRenderOptions *options); + const PFBuildOptions *build_options); // `gpu` diff --git a/c/src/lib.rs b/c/src/lib.rs index f3ec9c71..7454e90c 100644 --- a/c/src/lib.rs +++ b/c/src/lib.rs @@ -18,11 +18,11 @@ use pathfinder_geometry::color::ColorF; use pathfinder_geometry::stroke::LineCap; use pathfinder_gl::{GLDevice, GLVersion}; use pathfinder_gpu::resources::{FilesystemResourceLoader, ResourceLoader}; -use pathfinder_gpu::{ClearParams, Device}; use pathfinder_renderer::concurrent::rayon::RayonExecutor; use pathfinder_renderer::concurrent::scene_proxy::SceneProxy; -use pathfinder_renderer::gpu::renderer::{DestFramebuffer, Renderer}; -use pathfinder_renderer::options::RenderOptions; +use pathfinder_renderer::gpu::options::{DestFramebuffer, RendererOptions}; +use pathfinder_renderer::gpu::renderer::Renderer; +use pathfinder_renderer::options::BuildOptions; use pathfinder_renderer::scene::Scene; use pathfinder_simd::default::F32x4; use std::ffi::CString; @@ -30,14 +30,13 @@ use std::os::raw::{c_char, c_void}; // Constants +// `canvas` pub const PF_LINE_CAP_BUTT: u8 = 0; pub const PF_LINE_CAP_SQUARE: u8 = 1; pub const PF_LINE_CAP_ROUND: u8 = 2; -pub const PF_CLEAR_FLAGS_HAS_COLOR: u8 = 0x1; -pub const PF_CLEAR_FLAGS_HAS_DEPTH: u8 = 0x2; -pub const PF_CLEAR_FLAGS_HAS_STENCIL: u8 = 0x4; -pub const PF_CLEAR_FLAGS_HAS_RECT: u8 = 0x8; +// `renderer` +pub const PF_RENDERER_OPTIONS_FLAGS_HAS_BACKGROUND_COLOR: u8 = 0x1; // Types @@ -87,22 +86,19 @@ pub type PFGLRendererRef = *mut Renderer; // FIXME(pcwalton): Double-boxing is unfortunate. Remove this when `std::raw::TraitObject` is // stable? pub type PFResourceLoaderRef = *mut Box; -#[repr(C)] -pub struct PFClearParams { - pub color: PFColorF, - pub depth: f32, - pub stencil: u8, - pub rect: PFRectI, - pub flags: PFClearFlags, -} -pub type PFClearFlags = u8; // `renderer` pub type PFSceneRef = *mut Scene; pub type PFSceneProxyRef = *mut SceneProxy; +#[repr(C)] +pub struct PFRendererOptions { + pub background_color: PFColorF, + pub flags: PFRendererOptionsFlags, +} +pub type PFRendererOptionsFlags = u8; // TODO(pcwalton) #[repr(C)] -pub struct PFRenderOptions { +pub struct PFBuildOptions { pub placeholder: u32, } @@ -252,11 +248,6 @@ pub unsafe extern "C" fn PFGLDeviceDestroy(device: PFGLDeviceRef) { drop(Box::from_raw(device)) } -#[no_mangle] -pub unsafe extern "C" fn PFGLDeviceClear(device: PFGLDeviceRef, params: *const PFClearParams) { - (*device).clear(&(*params).to_rust()) -} - #[no_mangle] pub unsafe extern "C" fn PFResourceLoaderDestroy(loader: PFResourceLoaderRef) { drop(Box::from_raw(loader)) @@ -279,11 +270,13 @@ pub unsafe extern "C" fn PFGLDestFramebufferDestroy(dest_framebuffer: PFGLDestFr #[no_mangle] pub unsafe extern "C" fn PFGLRendererCreate(device: PFGLDeviceRef, resources: PFResourceLoaderRef, - dest_framebuffer: PFGLDestFramebufferRef) + dest_framebuffer: PFGLDestFramebufferRef, + options: *const PFRendererOptions) -> PFGLRendererRef { Box::into_raw(Box::new(Renderer::new(*Box::from_raw(device), &**resources, - *Box::from_raw(dest_framebuffer)))) + *Box::from_raw(dest_framebuffer), + (*options).to_rust()))) } #[no_mangle] @@ -299,8 +292,8 @@ pub unsafe extern "C" fn PFGLRendererGetDevice(renderer: PFGLRendererRef) -> PFG #[no_mangle] pub unsafe extern "C" fn PFSceneProxyBuildAndRenderGL(scene_proxy: PFSceneProxyRef, renderer: PFGLRendererRef, - options: *const PFRenderOptions) { - (*scene_proxy).build_and_render(&mut *renderer, (*options).to_rust()) + build_options: *const PFBuildOptions) { + (*scene_proxy).build_and_render(&mut *renderer, (*build_options).to_rust()) } // `renderer` @@ -358,28 +351,14 @@ impl PFVector2I { } } -// Helpers for `gpu` +// Helpers for `renderer` -impl PFClearParams { - pub fn to_rust(&self) -> ClearParams { - ClearParams { - color: if (self.flags & PF_CLEAR_FLAGS_HAS_COLOR) != 0 { - Some(self.color.to_rust()) - } else { - None - }, - rect: if (self.flags & PF_CLEAR_FLAGS_HAS_RECT) != 0 { - Some(self.rect.to_rust()) - } else { - None - }, - depth: if (self.flags & PF_CLEAR_FLAGS_HAS_DEPTH) != 0 { - Some(self.depth) - } else { - None - }, - stencil: if (self.flags & PF_CLEAR_FLAGS_HAS_STENCIL) != 0 { - Some(self.stencil) +impl PFRendererOptions { + pub fn to_rust(&self) -> RendererOptions { + let has_background_color = self.flags & PF_RENDERER_OPTIONS_FLAGS_HAS_BACKGROUND_COLOR; + RendererOptions { + background_color: if has_background_color != 0 { + Some(self.background_color.to_rust()) } else { None }, @@ -387,10 +366,8 @@ impl PFClearParams { } } -// Helpers for `renderer` - -impl PFRenderOptions { - pub fn to_rust(&self) -> RenderOptions { - RenderOptions::default() +impl PFBuildOptions { + pub fn to_rust(&self) -> BuildOptions { + BuildOptions::default() } } diff --git a/demo/common/Cargo.toml b/demo/common/Cargo.toml index 95cb3976..3d2a88cb 100644 --- a/demo/common/Cargo.toml +++ b/demo/common/Cargo.toml @@ -4,6 +4,9 @@ version = "0.1.0" edition = "2018" authors = ["Patrick Walton "] +[features] +pf-gl = [] + [dependencies] clap = "2.32" gl = "0.6" @@ -28,6 +31,9 @@ path = "../../gl" [dependencies.pathfinder_gpu] path = "../../gpu" +[dependencies.pathfinder_metal] +path = "../../metal" + [dependencies.pathfinder_renderer] path = "../../renderer" @@ -39,3 +45,6 @@ path = "../../svg" [dependencies.pathfinder_ui] path = "../../ui" + +[target.'cfg(target_os = "macos")'.dependencies] +metal = "0.14" diff --git a/demo/common/src/device.rs b/demo/common/src/device.rs index a34f7f83..1417bb0b 100644 --- a/demo/common/src/device.rs +++ b/demo/common/src/device.rs @@ -65,18 +65,17 @@ where let position_attr = device.get_vertex_attr(&ground_program.program, "Position").unwrap(); - device.bind_vertex_array(&vertex_array); - device.use_program(&ground_program.program); - device.bind_buffer(quad_vertex_positions_buffer, BufferTarget::Vertex); - device.configure_vertex_attr(&position_attr, &VertexAttrDescriptor { + device.bind_buffer(&vertex_array, quad_vertex_positions_buffer, BufferTarget::Vertex); + device.configure_vertex_attr(&vertex_array, &position_attr, &VertexAttrDescriptor { size: 2, - class: VertexAttrClass::Float, - attr_type: VertexAttrType::U8, - stride: 0, + class: VertexAttrClass::Int, + attr_type: VertexAttrType::I16, + stride: 4, offset: 0, divisor: 0, + buffer_index: 0, }); - device.bind_buffer(quad_vertex_indices_buffer, BufferTarget::Index); + device.bind_buffer(&vertex_array, quad_vertex_indices_buffer, BufferTarget::Index); GroundVertexArray { vertex_array } } diff --git a/demo/common/src/lib.rs b/demo/common/src/lib.rs index 2121a93d..76c5a964 100644 --- a/demo/common/src/lib.rs +++ b/demo/common/src/lib.rs @@ -27,12 +27,12 @@ use pathfinder_geometry::basic::rect::RectF; use pathfinder_geometry::basic::transform2d::Transform2DF; use pathfinder_geometry::basic::transform3d::Transform3DF; use pathfinder_geometry::color::ColorU; -use pathfinder_gl::GLDevice; -use pathfinder_gpu::Device; use pathfinder_gpu::resources::ResourceLoader; +use pathfinder_gpu::Device; use pathfinder_renderer::concurrent::scene_proxy::{RenderCommandStream, SceneProxy}; -use pathfinder_renderer::gpu::renderer::{DestFramebuffer, RenderStats, RenderTime, Renderer}; -use pathfinder_renderer::options::{RenderOptions, RenderTransform}; +use pathfinder_renderer::gpu::options::{DestFramebuffer, RendererOptions}; +use pathfinder_renderer::gpu::renderer::{RenderStats, RenderTime, Renderer}; +use pathfinder_renderer::options::{BuildOptions, RenderTransform}; use pathfinder_renderer::post::STEM_DARKENING_FACTORS; use pathfinder_renderer::scene::Scene; use pathfinder_svg::BuiltSVG; @@ -44,6 +44,11 @@ use std::thread; use std::time::Duration; use usvg::{Options as UsvgOptions, Tree}; +#[cfg(any(not(target_os = "macos"), feature = "pf-gl"))] +use pathfinder_gl::GLDevice as DeviceImpl; +#[cfg(all(target_os = "macos", not(feature = "pf-gl")))] +use pathfinder_metal::MetalDevice as DeviceImpl; + static DEFAULT_SVG_VIRTUAL_PATH: &'static str = "svg/Ghostscript_Tiger.svg"; const MOUSELOOK_ROTATION_SPEED: f32 = 0.007; @@ -112,22 +117,31 @@ pub struct DemoApp where W: Window { build_time: Option, ui_model: DemoUIModel, - ui_presenter: DemoUIPresenter, + ui_presenter: DemoUIPresenter, scene_proxy: SceneProxy, - renderer: Renderer, + renderer: Renderer, - scene_framebuffer: Option<::Framebuffer>, + scene_framebuffer: Option<::Framebuffer>, - ground_program: GroundProgram, - ground_vertex_array: GroundVertexArray, + ground_program: GroundProgram, + ground_vertex_array: GroundVertexArray, } impl DemoApp where W: Window { pub fn new(window: W, window_size: WindowSize, mut options: Options) -> DemoApp { let expire_message_event_id = window.create_user_event_id(); - let device = GLDevice::new(window.gl_version(), window.gl_default_framebuffer()); + let device; + #[cfg(all(target_os = "macos", not(feature = "pf-gl")))] + { + device = DeviceImpl::new(window.metal_layer()); + } + #[cfg(any(not(target_os = "macos"), feature = "pf-gl"))] + { + device = DeviceImpl::new(window.gl_version(), window.gl_default_framebuffer()); + } + let resources = window.resource_loader(); // Read command line options. @@ -144,8 +158,12 @@ impl DemoApp where W: Window { viewport, window_size: window_size.device_size(), }; + // FIXME(pcwalton) + let render_options = RendererOptions { + background_color: None, + }; - let renderer = Renderer::new(device, resources, dest_framebuffer); + let renderer = Renderer::new(device, resources, dest_framebuffer, render_options); let scene_metadata = SceneMetadata::new_clipping_view_box(&mut built_svg.scene, viewport.size()); let camera = Camera::new(options.mode, scene_metadata.view_box, viewport.size()); @@ -246,7 +264,7 @@ impl DemoApp where W: Window { Camera::TwoD(transform) => Some(RenderTransform::Transform2D(transform)), }; - let render_options = RenderOptions { + let build_options = BuildOptions { transform: self.render_transform.clone().unwrap(), dilation: if self.ui_model.stem_darkening_effect_enabled { let font_size = APPROX_FONT_SIZE * self.window_size.backing_scale_factor; @@ -258,7 +276,7 @@ impl DemoApp where W: Window { subpixel_aa_enabled: self.ui_model.subpixel_aa_effect_enabled, }; - self.render_command_stream = Some(self.scene_proxy.build_with_stream(render_options)); + self.render_command_stream = Some(self.scene_proxy.build_with_stream(build_options)); } fn handle_events(&mut self, events: Vec) -> Vec { @@ -488,7 +506,9 @@ impl DemoApp where W: Window { self.handle_ui_events(frame, &mut ui_action); - self.window.present(); + self.renderer.device.end_commands(); + + self.window.present(&mut self.renderer.device); self.frame_counter += 1; } diff --git a/demo/common/src/renderer.rs b/demo/common/src/renderer.rs index 742186c1..fb42869d 100644 --- a/demo/common/src/renderer.rs +++ b/demo/common/src/renderer.rs @@ -15,10 +15,13 @@ use crate::window::{View, Window}; use crate::{BackgroundColor, DemoApp, UIVisibility}; use image::ColorType; use pathfinder_geometry::color::{ColorF, ColorU}; -use pathfinder_gpu::{ClearParams, DepthFunc, DepthState, Device, Primitive, RenderState}; -use pathfinder_gpu::{TextureFormat, UniformData}; +use pathfinder_gpu::{ClearOps, DepthFunc, DepthState, Device, Primitive, RenderOptions}; +use pathfinder_gpu::{RenderState, RenderTarget, TextureData, TextureFormat, UniformData}; +use pathfinder_geometry::basic::rect::RectI; use pathfinder_geometry::basic::transform3d::Transform3DF; -use pathfinder_renderer::gpu::renderer::{DestFramebuffer, RenderMode}; +use pathfinder_geometry::basic::vector::Vector2I; +use pathfinder_renderer::gpu::options::{DestFramebuffer, RendererOptions}; +use pathfinder_renderer::gpu::renderer::RenderMode; use pathfinder_renderer::gpu_data::RenderCommand; use pathfinder_renderer::options::RenderTransform; use pathfinder_renderer::post::DEFRINGING_KERNEL_CORE_GRAPHICS; @@ -42,13 +45,14 @@ const GRIDLINE_COUNT: i32 = 10; impl DemoApp where W: Window { pub fn prepare_frame_rendering(&mut self) -> u32 { - // Make the GL context current. + // Make the context current. let view = self.ui_model.mode.view(0); self.window.make_current(view); // Set up framebuffers. let window_size = self.window_size.device_size(); - let scene_count = match self.camera.mode() { + let mode = self.camera.mode(); + let scene_count = match mode { Mode::VR => { let viewport = self.window.viewport(View::Stereo(0)); if self.scene_framebuffer.is_none() @@ -82,49 +86,47 @@ impl DemoApp where W: Window { } }; - // Begin drawing the scene. - self.renderer.bind_dest_framebuffer(); - // Clear to the appropriate color. - let clear_color = if scene_count == 2 { - ColorF::transparent_black() - } else { - self.background_color().to_f32() + let clear_color = match mode { + Mode::TwoD => Some(self.background_color().to_f32()), + Mode::ThreeD => None, + Mode::VR => Some(ColorF::transparent_black()), }; - self.renderer.device.clear(&ClearParams { - color: Some(clear_color), - depth: Some(1.0), - stencil: Some(0), - ..ClearParams::default() - }); + self.renderer.set_options(RendererOptions { background_color: clear_color }); scene_count } pub fn draw_scene(&mut self) { + self.renderer.device.begin_commands(); + let view = self.ui_model.mode.view(0); self.window.make_current(view); if self.camera.mode() != Mode::VR { - self.draw_environment(); + self.draw_environment(0); } + self.renderer.device.end_commands(); + self.render_vector_scene(); // Reattach default framebuffer. - if self.camera.mode() != Mode::VR { - return; + if self.camera.mode() == Mode::VR { + if let DestFramebuffer::Other(scene_framebuffer) = + self.renderer + .replace_dest_framebuffer(DestFramebuffer::Default { + viewport: self.window.viewport(View::Mono), + window_size: self.window_size.device_size(), + }) + { + self.scene_framebuffer = Some(scene_framebuffer); + } } + } - if let DestFramebuffer::Other(scene_framebuffer) = - self.renderer - .replace_dest_framebuffer(DestFramebuffer::Default { - viewport: self.window.viewport(View::Mono), - window_size: self.window_size.device_size(), - }) - { - self.scene_framebuffer = Some(scene_framebuffer); - } + pub fn begin_compositing(&mut self) { + self.renderer.device.begin_commands(); } pub fn composite_scene(&mut self, render_scene_index: u32) { @@ -151,21 +153,12 @@ impl DemoApp where W: Window { let viewport = self.window.viewport(View::Stereo(render_scene_index)); self.window.make_current(View::Stereo(render_scene_index)); - self.renderer - .replace_dest_framebuffer(DestFramebuffer::Default { - viewport, - window_size: self.window_size.device_size(), - }); - - self.renderer.bind_draw_framebuffer(); - self.renderer.device.clear(&ClearParams { - color: Some(self.background_color().to_f32()), - depth: Some(1.0), - stencil: Some(0), - rect: Some(viewport), + self.renderer.replace_dest_framebuffer(DestFramebuffer::Default { + viewport, + window_size: self.window_size.device_size(), }); - self.draw_environment(); + self.draw_environment(render_scene_index); let scene_framebuffer = self.scene_framebuffer.as_ref().unwrap(); let scene_texture = self.renderer.device.framebuffer_texture(scene_framebuffer); @@ -207,7 +200,7 @@ impl DemoApp where W: Window { } // Draws the ground, if applicable. - fn draw_environment(&self) { + fn draw_environment(&self, render_scene_index: u32) { let frame = &self.current_frame.as_ref().unwrap(); let perspective = match frame.transform { @@ -233,31 +226,35 @@ impl DemoApp where W: Window { transform = transform.post_mul(&Transform3DF::from_scale(ground_scale, 1.0, ground_scale)); - let device = &self.renderer.device; - device.bind_vertex_array(&self.ground_vertex_array.vertex_array); - device.use_program(&self.ground_program.program); - device.set_uniform( - &self.ground_program.transform_uniform, - UniformData::from_transform_3d(&transform), - ); - device.set_uniform( - &self.ground_program.ground_color_uniform, - UniformData::Vec4(GROUND_SOLID_COLOR.to_f32().0), - ); - device.set_uniform( - &self.ground_program.gridline_color_uniform, - UniformData::Vec4(GROUND_LINE_COLOR.to_f32().0), - ); - device.set_uniform(&self.ground_program.gridline_count_uniform, - UniformData::Int(GRIDLINE_COUNT)); - device.draw_elements( - Primitive::Triangles, - 6, - &RenderState { + // Don't clear the first scene after drawing it. + let clear_color = if render_scene_index == 0 { + Some(self.background_color().to_f32()) + } else { + None + }; + + self.renderer.device.draw_elements(6, &RenderState { + target: &self.renderer.draw_render_target(), + program: &self.ground_program.program, + vertex_array: &self.ground_vertex_array.vertex_array, + primitive: Primitive::Triangles, + textures: &[], + uniforms: &[ + (&self.ground_program.transform_uniform, + UniformData::from_transform_3d(&transform)), + (&self.ground_program.ground_color_uniform, + UniformData::Vec4(GROUND_SOLID_COLOR.to_f32().0)), + (&self.ground_program.gridline_color_uniform, + UniformData::Vec4(GROUND_LINE_COLOR.to_f32().0)), + (&self.ground_program.gridline_count_uniform, UniformData::Int(GRIDLINE_COUNT)), + ], + viewport: self.renderer.draw_viewport(), + options: RenderOptions { depth: Some(DepthState { func: DepthFunc::Less, write: true }), - ..RenderState::default() + clear_ops: ClearOps { color: clear_color, depth: Some(1.0), stencil: Some(0) }, + ..RenderOptions::default() }, - ); + }); } fn render_vector_scene(&mut self) { @@ -305,10 +302,11 @@ impl DemoApp where W: Window { pub fn take_raster_screenshot(&mut self, path: PathBuf) { let drawable_size = self.window_size.device_size(); - let pixels = self - .renderer - .device - .read_pixels_from_default_framebuffer(drawable_size); + let viewport = RectI::new(Vector2I::default(), drawable_size); + let pixels = match self.renderer.device.read_pixels(&RenderTarget::Default, viewport) { + TextureData::U8(pixels) => pixels, + TextureData::U16(_) => panic!("Unexpected pixel format for default framebuffer!"), + }; image::save_buffer( path, &pixels, diff --git a/demo/common/src/ui.rs b/demo/common/src/ui.rs index 0a13c3bc..270893c5 100644 --- a/demo/common/src/ui.rs +++ b/demo/common/src/ui.rs @@ -500,9 +500,7 @@ where Vector2I::new(widget_x, slider_track_y), Vector2I::new(SLIDER_WIDTH, SLIDER_TRACK_HEIGHT), ); - debug_ui_presenter - .ui_presenter - .draw_rect_outline(device, slider_track_rect, TEXT_COLOR); + debug_ui_presenter.ui_presenter.draw_rect_outline(device, slider_track_rect, TEXT_COLOR); let slider_knob_x = widget_x + model.rotation - SLIDER_KNOB_WIDTH / 2; let slider_knob_rect = RectI::new( @@ -528,7 +526,11 @@ where let widget_origin = panel_position + Vector2I::new(0, widget_size.y() * index); let widget_rect = RectI::new(widget_origin, widget_size); - if self.draw_menu_item(device, debug_ui_presenter, &text, widget_rect, false) { + if self.draw_menu_item(device, + debug_ui_presenter, + &text, + widget_rect, + false) { // FIXME(pcwalton): This is not sufficient for Android, where we will need to take in // the contents of the file. if let Ok(path) = window.run_save_dialog(screenshot_type.extension()) { @@ -554,7 +556,11 @@ where let widget_rect = RectI::new(widget_origin, widget_size); let selected = color == model.background_color; - if self.draw_menu_item(device, debug_ui_presenter, text, widget_rect, selected) { + if self.draw_menu_item(device, + debug_ui_presenter, + text, + widget_rect, + selected) { model.background_color = color; *action = UIAction::ModelChanged; } diff --git a/demo/common/src/window.rs b/demo/common/src/window.rs index 6ca9852c..d8fc0019 100644 --- a/demo/common/src/window.rs +++ b/demo/common/src/window.rs @@ -10,24 +10,38 @@ //! A minimal cross-platform windowing layer. -use gl::types::GLuint; use pathfinder_geometry::basic::vector::Vector2I; use pathfinder_geometry::basic::rect::RectI; use pathfinder_geometry::basic::transform3d::{Perspective, Transform3DF}; -use pathfinder_gl::GLVersion; use pathfinder_gpu::resources::ResourceLoader; use rayon::ThreadPoolBuilder; use std::path::PathBuf; -pub trait Window { - fn gl_version(&self) -> GLVersion; - fn gl_default_framebuffer(&self) -> GLuint { - 0 - } +#[cfg(all(target_os = "macos", not(feature = "pf-gl")))] +use metal::CoreAnimationLayerRef; +#[cfg(all(target_os = "macos", not(feature = "pf-gl")))] +use pathfinder_metal::MetalDevice; + +#[cfg(any(not(target_os = "macos"), feature = "pf-gl"))] +use gl::types::GLuint; +#[cfg(any(not(target_os = "macos"), feature = "pf-gl"))] +use pathfinder_gl::{GLDevice, GLVersion}; + +pub trait Window { + #[cfg(any(not(target_os = "macos"), feature = "pf-gl"))] + fn gl_version(&self) -> GLVersion; + #[cfg(any(not(target_os = "macos"), feature = "pf-gl"))] + fn gl_default_framebuffer(&self) -> GLuint { 0 } + #[cfg(any(not(target_os = "macos"), feature = "pf-gl"))] + fn present(&mut self, device: &mut GLDevice); + + #[cfg(all(target_os = "macos", not(feature = "pf-gl")))] + fn metal_layer(&self) -> &CoreAnimationLayerRef; + #[cfg(all(target_os = "macos", not(feature = "pf-gl")))] + fn present(&mut self, device: &mut MetalDevice); - fn viewport(&self, view: View) -> RectI; fn make_current(&mut self, view: View); - fn present(&mut self); + fn viewport(&self, view: View) -> RectI; fn resource_loader(&self) -> &dyn ResourceLoader; fn create_user_event_id(&self) -> u32; fn push_user_event(message_type: u32, message_data: u32); diff --git a/demo/magicleap/src/lib.rs b/demo/magicleap/src/lib.rs index 8238b068..632023c0 100644 --- a/demo/magicleap/src/lib.rs +++ b/demo/magicleap/src/lib.rs @@ -113,6 +113,7 @@ pub unsafe extern "C" fn magicleap_pathfinder_demo_run(app: *mut c_void) { } let scene_count = app.demo.prepare_frame(events); app.demo.draw_scene(); + app.demo.begin_compositing(); for scene_index in 0..scene_count { app.demo.composite_scene(scene_index); } diff --git a/demo/native/Cargo.toml b/demo/native/Cargo.toml index 5e4468de..12515c04 100644 --- a/demo/native/Cargo.toml +++ b/demo/native/Cargo.toml @@ -5,6 +5,7 @@ edition = "2018" authors = ["Patrick Walton "] [features] +pf-gl = ["pathfinder_demo/pf-gl"] pf-no-simd = ["pathfinder_simd/pf-no-simd"] [dependencies] @@ -27,8 +28,15 @@ path = "../../gl" [dependencies.pathfinder_gpu] path = "../../gpu" +[dependencies.pathfinder_metal] +path = "../../metal" + [dependencies.pathfinder_simd] path = "../../simd" +[target.'cfg(target_os = "macos")'.dependencies] +foreign-types = "0.3" +metal = "0.14" + [target.'cfg(not(windows))'.dependencies] jemallocator = "0.1" diff --git a/demo/native/src/main.rs b/demo/native/src/main.rs index ad166dae..78636e4c 100644 --- a/demo/native/src/main.rs +++ b/demo/native/src/main.rs @@ -15,16 +15,33 @@ use pathfinder_demo::window::{Event, Keycode, SVGPath, View, Window, WindowSize} use pathfinder_demo::{DemoApp, Options}; use pathfinder_geometry::basic::vector::Vector2I; use pathfinder_geometry::basic::rect::RectI; -use pathfinder_gl::GLVersion; use pathfinder_gpu::resources::{FilesystemResourceLoader, ResourceLoader}; use sdl2::event::{Event as SDLEvent, WindowEvent}; use sdl2::keyboard::Keycode as SDLKeycode; -use sdl2::video::{GLContext, GLProfile, Window as SDLWindow}; +use sdl2::video::Window as SDLWindow; use sdl2::{EventPump, EventSubsystem, Sdl, VideoSubsystem}; use sdl2_sys::{SDL_Event, SDL_UserEvent}; use std::path::PathBuf; use std::ptr; +#[cfg(all(target_os = "macos", not(feature = "pf-gl")))] +use foreign_types::ForeignTypeRef; +#[cfg(all(target_os = "macos", not(feature = "pf-gl")))] +use metal::{CAMetalLayer, CoreAnimationLayerRef}; +#[cfg(all(target_os = "macos", not(feature = "pf-gl")))] +use pathfinder_metal::MetalDevice; +#[cfg(all(target_os = "macos", not(feature = "pf-gl")))] +use sdl2::hint; +#[cfg(all(target_os = "macos", not(feature = "pf-gl")))] +use sdl2::render::Canvas; +#[cfg(all(target_os = "macos", not(feature = "pf-gl")))] +use sdl2_sys::SDL_RenderGetMetalLayer; + +#[cfg(any(not(target_os = "macos"), feature = "pf-gl"))] +use pathfinder_gl::{GLDevice, GLVersion}; +#[cfg(any(not(target_os = "macos"), feature = "pf-gl"))] +use sdl2::video::{GLContext, GLProfile}; + #[cfg(not(windows))] use jemallocator; @@ -55,6 +72,7 @@ fn main() { let scene_count = app.prepare_frame(events); app.draw_scene(); + app.begin_compositing(); for scene_index in 0..scene_count { app.composite_scene(scene_index); } @@ -69,22 +87,36 @@ thread_local! { } struct WindowImpl { + #[cfg(any(not(target_os = "macos"), feature = "pf-gl"))] window: SDLWindow, + #[cfg(any(not(target_os = "macos"), feature = "pf-gl"))] + gl_context: GLContext, + + #[cfg(all(target_os = "macos", not(feature = "pf-gl")))] + canvas: Canvas, + #[cfg(all(target_os = "macos", not(feature = "pf-gl")))] + metal_layer: *mut CAMetalLayer, + event_pump: EventPump, #[allow(dead_code)] - gl_context: GLContext, resource_loader: FilesystemResourceLoader, selected_file: Option, open_svg_message_type: u32, } impl Window for WindowImpl { + #[cfg(any(not(target_os = "macos"), feature = "pf-gl"))] fn gl_version(&self) -> GLVersion { GLVersion::GL3 } + #[cfg(all(target_os = "macos", not(feature = "pf-gl")))] + fn metal_layer(&self) -> &CoreAnimationLayerRef { + unsafe { CoreAnimationLayerRef::from_ptr(self.metal_layer) } + } + fn viewport(&self, view: View) -> RectI { - let (width, height) = self.window.drawable_size(); + let (width, height) = self.window().drawable_size(); let mut width = width as i32; let height = height as i32; let mut x_offset = 0; @@ -95,12 +127,22 @@ impl Window for WindowImpl { RectI::new(Vector2I::new(x_offset, 0), Vector2I::new(width, height)) } + #[cfg(any(not(target_os = "macos"), feature = "pf-gl"))] fn make_current(&mut self, _view: View) { - self.window.gl_make_current(&self.gl_context).unwrap(); + self.window().gl_make_current(&self.gl_context).unwrap(); } - fn present(&mut self) { - self.window.gl_swap_window(); + #[cfg(all(target_os = "macos", not(feature = "pf-gl")))] + fn make_current(&mut self, _: View) {} + + #[cfg(any(not(target_os = "macos"), feature = "pf-gl"))] + fn present(&mut self, _: &mut GLDevice) { + self.window().gl_swap_window(); + } + + #[cfg(all(target_os = "macos", not(feature = "pf-gl")))] + fn present(&mut self, device: &mut MetalDevice) { + device.present_drawable(); } fn resource_loader(&self) -> &dyn ResourceLoader { @@ -141,6 +183,7 @@ impl Window for WindowImpl { } impl WindowImpl { + #[cfg(any(not(target_os = "macos"), feature = "pf-gl"))] fn new() -> WindowImpl { SDL_VIDEO.with(|sdl_video| { SDL_EVENT.with(|sdl_event| { @@ -185,9 +228,55 @@ impl WindowImpl { }) } + #[cfg(all(target_os = "macos", not(feature = "pf-gl")))] + fn new() -> WindowImpl { + assert!(hint::set("SDL_RENDER_DRIVER", "metal")); + + SDL_VIDEO.with(|sdl_video| { + SDL_EVENT.with(|sdl_event| { + let window = sdl_video + .window( + "Pathfinder Demo", + DEFAULT_WINDOW_WIDTH, + DEFAULT_WINDOW_HEIGHT, + ) + .opengl() + .resizable() + .allow_highdpi() + .build() + .unwrap(); + + let canvas = window.into_canvas().present_vsync().build().unwrap(); + let metal_layer = unsafe { + SDL_RenderGetMetalLayer(canvas.raw()) as *mut CAMetalLayer + }; + + let event_pump = SDL_CONTEXT.with(|sdl_context| sdl_context.event_pump().unwrap()); + + let resource_loader = FilesystemResourceLoader::locate(); + + let open_svg_message_type = unsafe { sdl_event.register_event().unwrap() }; + + WindowImpl { + event_pump, + canvas, + metal_layer, + resource_loader, + open_svg_message_type, + selected_file: None, + } + }) + }) + } + + #[cfg(any(not(target_os = "macos"), feature = "pf-gl"))] + fn window(&self) -> &SDLWindow { &self.window } + #[cfg(all(target_os = "macos", not(feature = "pf-gl")))] + fn window(&self) -> &SDLWindow { self.canvas.window() } + fn size(&self) -> WindowSize { - let (logical_width, logical_height) = self.window.size(); - let (drawable_width, _) = self.window.drawable_size(); + let (logical_width, logical_height) = self.window().size(); + let (drawable_width, _) = self.window().drawable_size(); WindowSize { logical_size: Vector2I::new(logical_width as i32, logical_height as i32), backing_scale_factor: drawable_width as f32 / logical_width as f32, diff --git a/examples/c_canvas_minimal/c_canvas_minimal.c b/examples/c_canvas_minimal/c_canvas_minimal.c index 9e773b02..9721ee3f 100644 --- a/examples/c_canvas_minimal/c_canvas_minimal.c +++ b/examples/c_canvas_minimal/c_canvas_minimal.c @@ -58,11 +58,9 @@ int main(int argc, const char **argv) { PFGLDestFramebufferCreateFullWindow(&(PFVector2I){640, 480}); PFGLRendererRef renderer = PFGLRendererCreate(PFGLDeviceCreate(PF_GL_VERSION_GL3, 0), PFFilesystemResourceLoaderLocate(), - dest_framebuffer); - - // Clear to white. - PFGLDeviceClear(PFGLRendererGetDevice(renderer), &(PFClearParams){ - (PFColorF){1.0, 1.0, 1.0, 1.0}, 0.0, 0, {0}, PF_CLEAR_FLAGS_HAS_COLOR + dest_framebuffer, + &(PFRendererOptions){ + (PFColorF){1.0, 1.0, 1.0, 1.0}, PF_RENDERER_OPTIONS_FLAGS_HAS_BACKGROUND_COLOR }); // Make a canvas. We're going to draw a house. @@ -89,7 +87,7 @@ int main(int argc, const char **argv) { // Render the canvas to screen. PFSceneRef scene = PFCanvasCreateScene(canvas); PFSceneProxyRef scene_proxy = PFSceneProxyCreateFromSceneAndRayonExecutor(scene); - PFSceneProxyBuildAndRenderGL(scene_proxy, renderer, &(PFRenderOptions){0}); + PFSceneProxyBuildAndRenderGL(scene_proxy, renderer, &(PFBuildOptions){0}); SDL_GL_SwapWindow(window); // Wait for a keypress. diff --git a/examples/canvas_glutin_minimal/src/main.rs b/examples/canvas_glutin_minimal/src/main.rs index ce9360f4..b73a0fdb 100644 --- a/examples/canvas_glutin_minimal/src/main.rs +++ b/examples/canvas_glutin_minimal/src/main.rs @@ -12,18 +12,18 @@ use glutin::dpi::PhysicalSize; use glutin::{ContextBuilder, ControlFlow, Event, EventsLoop, GlProfile, GlRequest, KeyboardInput}; -use glutin::{VirtualKeyCode, WindowBuilder, WindowEvent}; +use glutin::{VirtualKeyCode, WindowBuilder, WindowEvent}; use pathfinder_canvas::{CanvasFontContext, CanvasRenderingContext2D, Path2D}; use pathfinder_geometry::basic::vector::{Vector2F, Vector2I}; use pathfinder_geometry::basic::rect::RectF; use pathfinder_geometry::color::ColorF; use pathfinder_gl::{GLDevice, GLVersion}; use pathfinder_gpu::resources::FilesystemResourceLoader; -use pathfinder_gpu::{ClearParams, Device}; use pathfinder_renderer::concurrent::rayon::RayonExecutor; use pathfinder_renderer::concurrent::scene_proxy::SceneProxy; -use pathfinder_renderer::gpu::renderer::{DestFramebuffer, Renderer}; -use pathfinder_renderer::options::RenderOptions; +use pathfinder_renderer::gpu::renderer::Renderer; +use pathfinder_renderer::gpu::options::{DestFramebuffer, RendererOptions}; +use pathfinder_renderer::options::BuildOptions; fn main() { // Calculate the right logical size of the window. @@ -50,10 +50,8 @@ fn main() { // Create a Pathfinder renderer. let mut renderer = Renderer::new(GLDevice::new(GLVersion::GL3, 0), &FilesystemResourceLoader::locate(), - DestFramebuffer::full_window(window_size)); - - // Clear to white. - renderer.device.clear(&ClearParams { color: Some(ColorF::white()), ..ClearParams::default() }); + DestFramebuffer::full_window(window_size), + RendererOptions { background_color: Some(ColorF::white()) }); // Make a canvas. We're going to draw a house. let mut canvas = CanvasRenderingContext2D::new(CanvasFontContext::new(), window_size.to_f32()); @@ -77,7 +75,7 @@ fn main() { // Render the canvas to screen. let scene = SceneProxy::from_scene(canvas.into_scene(), RayonExecutor); - scene.build_and_render(&mut renderer, RenderOptions::default()); + scene.build_and_render(&mut renderer, BuildOptions::default()); gl_context.swap_buffers().unwrap(); // Wait for a keypress. diff --git a/examples/canvas_metal_minimal/Cargo.toml b/examples/canvas_metal_minimal/Cargo.toml new file mode 100644 index 00000000..41673409 --- /dev/null +++ b/examples/canvas_metal_minimal/Cargo.toml @@ -0,0 +1,31 @@ +[package] +name = "canvas_metal_minimal" +version = "0.1.0" +authors = ["Patrick Walton "] +edition = "2018" + +[dependencies] +foreign-types = "0.3" +gl = "0.6" +metal = "0.14" +objc = "0.2" +sdl2 = "0.32" +sdl2-sys = "0.32" + +[dependencies.pathfinder_canvas] +path = "../../canvas" + +[dependencies.pathfinder_geometry] +path = "../../geometry" + +[dependencies.pathfinder_gl] +path = "../../gl" + +[dependencies.pathfinder_gpu] +path = "../../gpu" + +[dependencies.pathfinder_metal] +path = "../../metal" + +[dependencies.pathfinder_renderer] +path = "../../renderer" diff --git a/examples/canvas_metal_minimal/src/main.rs b/examples/canvas_metal_minimal/src/main.rs new file mode 100644 index 00000000..043b9d5d --- /dev/null +++ b/examples/canvas_metal_minimal/src/main.rs @@ -0,0 +1,87 @@ +// pathfinder/examples/canvas_metal_minimal/src/main.rs +// +// Copyright © 2019 The Pathfinder Project Developers. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use foreign_types::ForeignTypeRef; +use metal::{CAMetalLayer, CoreAnimationLayerRef}; +use pathfinder_canvas::{CanvasFontContext, CanvasRenderingContext2D, Path2D}; +use pathfinder_geometry::basic::vector::{Vector2F, Vector2I}; +use pathfinder_geometry::basic::rect::RectF; +use pathfinder_geometry::color::ColorF; +use pathfinder_gpu::resources::FilesystemResourceLoader; +use pathfinder_metal::MetalDevice; +use pathfinder_renderer::concurrent::rayon::RayonExecutor; +use pathfinder_renderer::concurrent::scene_proxy::SceneProxy; +use pathfinder_renderer::gpu::options::{DestFramebuffer, RendererOptions}; +use pathfinder_renderer::gpu::renderer::Renderer; +use pathfinder_renderer::options::BuildOptions; +use sdl2::event::Event; +use sdl2::hint; +use sdl2::keyboard::Keycode; +use sdl2_sys::SDL_RenderGetMetalLayer; + +fn main() { + // Set up SDL2. + assert!(hint::set("SDL_RENDER_DRIVER", "metal")); + let sdl_context = sdl2::init().unwrap(); + let video = sdl_context.video().unwrap(); + + // Open a window. + let window_size = Vector2I::new(640, 480); + let window = video.window("Minimal example", window_size.x() as u32, window_size.y() as u32) + .opengl() + .build() + .unwrap(); + + // Create a Metal context. + let canvas = window.into_canvas().present_vsync().build().unwrap(); + let metal_layer = unsafe { + CoreAnimationLayerRef::from_ptr(SDL_RenderGetMetalLayer(canvas.raw()) as *mut CAMetalLayer) + }; + + // Create a Pathfinder renderer. + let mut renderer = Renderer::new(MetalDevice::new(metal_layer), + &FilesystemResourceLoader::locate(), + DestFramebuffer::full_window(window_size), + RendererOptions { background_color: Some(ColorF::white()) }); + + // Make a canvas. We're going to draw a house. + let mut canvas = CanvasRenderingContext2D::new(CanvasFontContext::new(), window_size.to_f32()); + + // Set line width. + canvas.set_line_width(10.0); + + // Draw walls. + canvas.stroke_rect(RectF::new(Vector2F::new(75.0, 140.0), Vector2F::new(150.0, 110.0))); + + // Draw door. + canvas.fill_rect(RectF::new(Vector2F::new(130.0, 190.0), Vector2F::new(40.0, 60.0))); + + // Draw roof. + let mut path = Path2D::new(); + path.move_to(Vector2F::new(50.0, 140.0)); + path.line_to(Vector2F::new(150.0, 60.0)); + path.line_to(Vector2F::new(250.0, 140.0)); + path.close_path(); + canvas.stroke_path(path); + + // Render the canvas to screen. + let scene = SceneProxy::from_scene(canvas.into_scene(), RayonExecutor); + scene.build_and_render(&mut renderer, BuildOptions::default()); + renderer.device.present_drawable(); + + // Wait for a keypress. + let mut event_pump = sdl_context.event_pump().unwrap(); + loop { + match event_pump.wait_event() { + Event::Quit {..} | Event::KeyDown { keycode: Some(Keycode::Escape), .. } => return, + _ => {} + } + } +} diff --git a/examples/canvas_minimal/src/main.rs b/examples/canvas_minimal/src/main.rs index 07588dcc..06fc1a7e 100644 --- a/examples/canvas_minimal/src/main.rs +++ b/examples/canvas_minimal/src/main.rs @@ -14,11 +14,11 @@ use pathfinder_geometry::basic::rect::RectF; use pathfinder_geometry::color::ColorF; use pathfinder_gl::{GLDevice, GLVersion}; use pathfinder_gpu::resources::FilesystemResourceLoader; -use pathfinder_gpu::{ClearParams, Device}; use pathfinder_renderer::concurrent::rayon::RayonExecutor; use pathfinder_renderer::concurrent::scene_proxy::SceneProxy; -use pathfinder_renderer::gpu::renderer::{DestFramebuffer, Renderer}; -use pathfinder_renderer::options::RenderOptions; +use pathfinder_renderer::gpu::options::{DestFramebuffer, RendererOptions}; +use pathfinder_renderer::gpu::renderer::Renderer; +use pathfinder_renderer::options::BuildOptions; use sdl2::event::Event; use sdl2::keyboard::Keycode; use sdl2::video::GLProfile; @@ -48,10 +48,8 @@ fn main() { // Create a Pathfinder renderer. let mut renderer = Renderer::new(GLDevice::new(GLVersion::GL3, 0), &FilesystemResourceLoader::locate(), - DestFramebuffer::full_window(window_size)); - - // Clear to white. - renderer.device.clear(&ClearParams { color: Some(ColorF::white()), ..ClearParams::default() }); + DestFramebuffer::full_window(window_size), + RendererOptions { background_color: Some(ColorF::white()) }); // Make a canvas. We're going to draw a house. let mut canvas = CanvasRenderingContext2D::new(CanvasFontContext::new(), window_size.to_f32()); @@ -75,7 +73,7 @@ fn main() { // Render the canvas to screen. let scene = SceneProxy::from_scene(canvas.into_scene(), RayonExecutor); - scene.build_and_render(&mut renderer, RenderOptions::default()); + scene.build_and_render(&mut renderer, BuildOptions::default()); window.gl_swap_window(); // Wait for a keypress. diff --git a/examples/canvas_moire/src/main.rs b/examples/canvas_moire/src/main.rs index 7a55404e..0ac8fffd 100644 --- a/examples/canvas_moire/src/main.rs +++ b/examples/canvas_moire/src/main.rs @@ -13,11 +13,11 @@ use pathfinder_geometry::basic::vector::{Vector2F, Vector2I}; use pathfinder_geometry::color::{ColorF, ColorU}; use pathfinder_gl::{GLDevice, GLVersion}; use pathfinder_gpu::resources::FilesystemResourceLoader; -use pathfinder_gpu::{ClearParams, Device}; use pathfinder_renderer::concurrent::rayon::RayonExecutor; use pathfinder_renderer::concurrent::scene_proxy::SceneProxy; -use pathfinder_renderer::gpu::renderer::{DestFramebuffer, Renderer}; -use pathfinder_renderer::options::RenderOptions; +use pathfinder_renderer::gpu::options::{DestFramebuffer, RendererOptions}; +use pathfinder_renderer::gpu::renderer::Renderer; +use pathfinder_renderer::options::BuildOptions; use sdl2::event::Event; use sdl2::keyboard::Keycode; use sdl2::video::GLProfile; @@ -67,7 +67,8 @@ fn main() { // Create our renderers. let renderer = Renderer::new(GLDevice::new(GLVersion::GL3, 0), &FilesystemResourceLoader::locate(), - DestFramebuffer::full_window(drawable_size)); + DestFramebuffer::full_window(drawable_size), + RendererOptions { background_color: Some(ColorF::white()) }); let mut moire_renderer = MoireRenderer::new(renderer, window_size, drawable_size); // Enter main render loop. @@ -124,10 +125,7 @@ impl MoireRenderer { Vector2F::new(1.0, sin_time).scale(cos_time * INNER_RADIUS); // Clear to background color. - self.renderer.device.clear(&ClearParams { - color: Some(background_color), - ..ClearParams::default() - }); + self.renderer.set_options(RendererOptions { background_color: Some(background_color) }); // Make a canvas. let mut canvas = CanvasRenderingContext2D::new(self.font_context.clone(), @@ -142,7 +140,7 @@ impl MoireRenderer { // Build and render scene. self.scene.replace_scene(canvas.into_scene()); - self.scene.build_and_render(&mut self.renderer, RenderOptions::default()); + self.scene.build_and_render(&mut self.renderer, BuildOptions::default()); self.frame += 1; } diff --git a/examples/canvas_text/src/main.rs b/examples/canvas_text/src/main.rs index 0829723e..de69fbe4 100644 --- a/examples/canvas_text/src/main.rs +++ b/examples/canvas_text/src/main.rs @@ -13,11 +13,11 @@ use pathfinder_geometry::basic::vector::{Vector2F, Vector2I}; use pathfinder_geometry::color::ColorF; use pathfinder_gl::{GLDevice, GLVersion}; use pathfinder_gpu::resources::FilesystemResourceLoader; -use pathfinder_gpu::{ClearParams, Device}; use pathfinder_renderer::concurrent::rayon::RayonExecutor; use pathfinder_renderer::concurrent::scene_proxy::SceneProxy; -use pathfinder_renderer::gpu::renderer::{DestFramebuffer, Renderer}; -use pathfinder_renderer::options::RenderOptions; +use pathfinder_renderer::gpu::options::{DestFramebuffer, RendererOptions}; +use pathfinder_renderer::gpu::renderer::Renderer; +use pathfinder_renderer::options::BuildOptions; use sdl2::event::Event; use sdl2::keyboard::Keycode; use sdl2::video::GLProfile; @@ -47,10 +47,8 @@ fn main() { // Create a Pathfinder renderer. let mut renderer = Renderer::new(GLDevice::new(GLVersion::GL3, 0), &FilesystemResourceLoader::locate(), - DestFramebuffer::full_window(window_size)); - - // Clear to white. - renderer.device.clear(&ClearParams { color: Some(ColorF::white()), ..ClearParams::default() }); + DestFramebuffer::full_window(window_size), + RendererOptions { background_color: Some(ColorF::white()) }); // Make a canvas. We're going to draw some text. let mut canvas = CanvasRenderingContext2D::new(CanvasFontContext::new(), window_size.to_f32()); @@ -63,7 +61,7 @@ fn main() { // Render the canvas to screen. let scene = SceneProxy::from_scene(canvas.into_scene(), RayonExecutor); - scene.build_and_render(&mut renderer, RenderOptions::default()); + scene.build_and_render(&mut renderer, BuildOptions::default()); window.gl_swap_window(); // Wait for a keypress. diff --git a/geometry/src/color.rs b/geometry/src/color.rs index cde14be6..5f3676be 100644 --- a/geometry/src/color.rs +++ b/geometry/src/color.rs @@ -75,13 +75,18 @@ impl Debug for ColorU { } } -#[derive(Clone, Copy)] +#[derive(Clone, Copy, Default)] pub struct ColorF(pub F32x4); impl ColorF { + #[inline] + pub fn new(r: f32, g: f32, b: f32, a: f32) -> ColorF { + ColorF(F32x4::new(r, g, b, a)) + } + #[inline] pub fn transparent_black() -> ColorF { - ColorF(F32x4::default()) + ColorF::default() } #[inline] @@ -120,3 +125,16 @@ impl ColorF { self.0[3] } } + +impl Debug for ColorF { + fn fmt(&self, formatter: &mut Formatter) -> fmt::Result { + write!( + formatter, + "rgba({}, {}, {}, {})", + self.r() * 255.0, + self.g() * 255.0, + self.b() * 255.0, + self.a() + ) + } +} diff --git a/gl/src/lib.rs b/gl/src/lib.rs index aa08233a..f53faeaf 100644 --- a/gl/src/lib.rs +++ b/gl/src/lib.rs @@ -14,13 +14,13 @@ extern crate log; use gl::types::{GLboolean, GLchar, GLenum, GLfloat, GLint, GLsizei, GLsizeiptr, GLuint, GLvoid}; -use pathfinder_geometry::basic::vector::Vector2I; use pathfinder_geometry::basic::rect::RectI; +use pathfinder_geometry::basic::vector::Vector2I; use pathfinder_gpu::resources::ResourceLoader; -use pathfinder_gpu::{BlendState, BufferData, BufferTarget, BufferUploadMode, ClearParams}; -use pathfinder_gpu::{DepthFunc, Device, Primitive, RenderState, ShaderKind, StencilFunc}; -use pathfinder_gpu::{TextureFormat, UniformData, VertexAttrClass}; -use pathfinder_gpu::{VertexAttrDescriptor, VertexAttrType}; +use pathfinder_gpu::{RenderTarget, BlendState, BufferData, BufferTarget, BufferUploadMode}; +use pathfinder_gpu::{ClearOps, DepthFunc, Device, Primitive, RenderOptions, RenderState}; +use pathfinder_gpu::{ShaderKind, StencilFunc, TextureData, TextureFormat, UniformData}; +use pathfinder_gpu::{VertexAttrClass, VertexAttrDescriptor, VertexAttrType}; use pathfinder_simd::default::F32x4; use std::ffi::CString; use std::mem; @@ -60,10 +60,32 @@ impl GLDevice { } } - fn set_render_state(&self, render_state: &RenderState) { + fn set_render_state(&self, render_state: &RenderState) { + self.bind_render_target(render_state.target); + + unsafe { + let (origin, size) = (render_state.viewport.origin(), render_state.viewport.size()); + gl::Viewport(origin.x(), origin.y(), size.x(), size.y()); + } + + if render_state.options.clear_ops.has_ops() { + self.clear(&render_state.options.clear_ops); + } + + self.use_program(render_state.program); + self.bind_vertex_array(render_state.vertex_array); + for (texture_unit, texture) in render_state.textures.iter().enumerate() { + self.bind_texture(texture, texture_unit as u32); + } + + render_state.uniforms.iter().for_each(|(uniform, data)| self.set_uniform(uniform, data)); + self.set_render_options(&render_state.options); + } + + fn set_render_options(&self, render_options: &RenderOptions) { unsafe { // Set blend. - match render_state.blend { + match render_options.blend { BlendState::Off => { gl::Disable(gl::BLEND); ck(); } @@ -91,7 +113,7 @@ impl GLDevice { } // Set depth. - match render_state.depth { + match render_options.depth { None => { gl::Disable(gl::DEPTH_TEST); ck(); } @@ -103,7 +125,7 @@ impl GLDevice { } // Set stencil. - match render_state.stencil { + match render_options.stencil { None => { gl::Disable(gl::STENCIL_TEST); ck(); } @@ -123,14 +145,50 @@ impl GLDevice { } // Set color mask. - let color_mask = render_state.color_mask as GLboolean; + let color_mask = render_options.color_mask as GLboolean; gl::ColorMask(color_mask, color_mask, color_mask, color_mask); ck(); } } - fn reset_render_state(&self, render_state: &RenderState) { + fn set_uniform(&self, uniform: &GLUniform, data: &UniformData) { unsafe { - match render_state.blend { + match *data { + UniformData::Int(value) => { + gl::Uniform1i(uniform.location, value); ck(); + } + UniformData::Mat4(data) => { + assert_eq!(mem::size_of::<[F32x4; 4]>(), 4 * 4 * 4); + let data_ptr: *const F32x4 = data.as_ptr(); + gl::UniformMatrix4fv(uniform.location, + 1, + gl::FALSE, + data_ptr as *const GLfloat); + } + UniformData::Vec2(data) => { + gl::Uniform2f(uniform.location, data.x(), data.y()); ck(); + } + UniformData::Vec4(data) => { + gl::Uniform4f(uniform.location, data.x(), data.y(), data.z(), data.w()); ck(); + } + UniformData::TextureUnit(unit) => { + gl::Uniform1i(uniform.location, unit as GLint); ck(); + } + } + } + } + + fn reset_render_state(&self, render_state: &RenderState) { + self.reset_render_options(&render_state.options); + for texture_unit in 0..(render_state.textures.len() as u32) { + self.unbind_texture(texture_unit); + } + self.unuse_program(); + self.unbind_vertex_array(); + } + + fn reset_render_options(&self, render_options: &RenderOptions) { + unsafe { + match render_options.blend { BlendState::Off => {} BlendState::RGBOneAlphaOneMinusSrcAlpha | BlendState::RGBOneAlphaOne | @@ -139,11 +197,11 @@ impl GLDevice { } } - if render_state.depth.is_some() { + if render_options.depth.is_some() { gl::Disable(gl::DEPTH_TEST); ck(); } - if render_state.stencil.is_some() { + if render_options.stencil.is_some() { gl::StencilMask(!0); ck(); gl::Disable(gl::STENCIL_TEST); ck(); } @@ -165,37 +223,18 @@ impl Device for GLDevice { type VertexAttr = GLVertexAttr; fn create_texture(&self, format: TextureFormat, size: Vector2I) -> GLTexture { - let (gl_internal_format, gl_format, gl_type); - match format { - TextureFormat::R8 => { - gl_internal_format = gl::R8 as GLint; - gl_format = gl::RED; - gl_type = gl::UNSIGNED_BYTE; - } - TextureFormat::R16F => { - gl_internal_format = gl::R16F as GLint; - gl_format = gl::RED; - gl_type = gl::HALF_FLOAT; - } - TextureFormat::RGBA8 => { - gl_internal_format = gl::RGBA as GLint; - gl_format = gl::RGBA; - gl_type = gl::UNSIGNED_BYTE; - } - } - - let mut texture = GLTexture { gl_texture: 0, size }; + let mut texture = GLTexture { gl_texture: 0, size, format }; unsafe { gl::GenTextures(1, &mut texture.gl_texture); ck(); self.bind_texture(&texture, 0); gl::TexImage2D(gl::TEXTURE_2D, 0, - gl_internal_format, + format.gl_internal_format(), size.x() as GLsizei, size.y() as GLsizei, 0, - gl_format, - gl_type, + format.gl_format(), + format.gl_type(), ptr::null()); ck(); } @@ -206,7 +245,7 @@ impl Device for GLDevice { fn create_texture_from_data(&self, size: Vector2I, data: &[u8]) -> GLTexture { assert!(data.len() >= size.x() as usize * size.y() as usize); - let mut texture = GLTexture { gl_texture: 0, size }; + let mut texture = GLTexture { gl_texture: 0, size, format: TextureFormat::R8 }; unsafe { gl::GenTextures(1, &mut texture.gl_texture); ck(); self.bind_texture(&texture, 0); @@ -324,13 +363,14 @@ impl Device for GLDevice { GLUniform { location } } - fn use_program(&self, program: &Self::Program) { - unsafe { - gl::UseProgram(program.gl_program); ck(); - } - } + fn configure_vertex_attr(&self, + vertex_array: &GLVertexArray, + attr: &GLVertexAttr, + descriptor: &VertexAttrDescriptor) { + debug_assert_ne!(descriptor.stride, 0); + + self.bind_vertex_array(vertex_array); - fn configure_vertex_attr(&self, attr: &GLVertexAttr, descriptor: &VertexAttrDescriptor) { unsafe { let attr_type = descriptor.attr_type.to_gl_type(); match descriptor.class { @@ -359,41 +399,8 @@ impl Device for GLDevice { gl::VertexAttribDivisor(attr.attr, descriptor.divisor); ck(); gl::EnableVertexAttribArray(attr.attr); ck(); } - } - fn set_uniform(&self, uniform: &Self::Uniform, data: UniformData) { - unsafe { - match data { - UniformData::Int(value) => { - gl::Uniform1i(uniform.location, value); ck(); - } - UniformData::Mat2(data) => { - assert_eq!(mem::size_of::(), 4 * 4); - let data_ptr: *const F32x4 = &data; - gl::UniformMatrix2fv(uniform.location, - 1, - gl::FALSE, - data_ptr as *const GLfloat); - } - UniformData::Mat4(data) => { - assert_eq!(mem::size_of::<[F32x4; 4]>(), 4 * 4 * 4); - let data_ptr: *const F32x4 = data.as_ptr(); - gl::UniformMatrix4fv(uniform.location, - 1, - gl::FALSE, - data_ptr as *const GLfloat); - } - UniformData::Vec2(data) => { - gl::Uniform2f(uniform.location, data.x(), data.y()); ck(); - } - UniformData::Vec4(data) => { - gl::Uniform4f(uniform.location, data.x(), data.y(), data.z(), data.w()); ck(); - } - UniformData::TextureUnit(unit) => { - gl::Uniform1i(uniform.location, unit as GLint); ck(); - } - } - } + self.unbind_vertex_array(); } fn create_framebuffer(&self, texture: GLTexture) -> GLFramebuffer { @@ -470,77 +477,67 @@ impl Device for GLDevice { self.set_texture_parameters(texture); } - fn read_pixels_from_default_framebuffer(&self, size: Vector2I) -> Vec { - let mut pixels = vec![0; size.x() as usize * size.y() as usize * 4]; - unsafe { - gl::BindFramebuffer(gl::FRAMEBUFFER, self.default_framebuffer); ck(); - gl::ReadPixels(0, - 0, - size.x() as GLsizei, - size.y() as GLsizei, - gl::RGBA, - gl::UNSIGNED_BYTE, - pixels.as_mut_ptr() as *mut GLvoid); ck(); - } + fn read_pixels(&self, render_target: &RenderTarget, viewport: RectI) -> TextureData { + let (origin, size) = (viewport.origin(), viewport.size()); + let format = self.render_target_format(render_target); + self.bind_render_target(render_target); - // Flip right-side-up. - let stride = size.x() as usize * 4; - for y in 0..(size.y() as usize / 2) { - let (index_a, index_b) = (y * stride, (size.y() as usize - y - 1) * stride); - for offset in 0..stride { - pixels.swap(index_a + offset, index_b + offset); + match format { + TextureFormat::R8 | TextureFormat::RGBA8 => { + let channels = format.channels(); + let mut pixels = vec![0; size.x() as usize * size.y() as usize * channels]; + unsafe { + gl::ReadPixels(origin.x(), + origin.y(), + size.x() as GLsizei, + size.y() as GLsizei, + format.gl_format(), + format.gl_type(), + pixels.as_mut_ptr() as *mut GLvoid); ck(); + } + flip_y(&mut pixels, size, channels); + TextureData::U8(pixels) } - } - - pixels - } - - fn clear(&self, params: &ClearParams) { - unsafe { - if let Some(rect) = params.rect { - let (origin, size) = (rect.origin(), rect.size()); - gl::Scissor(origin.x(), origin.y(), size.x(), size.y()); ck(); - gl::Enable(gl::SCISSOR_TEST); ck(); - } - - let mut flags = 0; - if let Some(color) = params.color { - gl::ColorMask(gl::TRUE, gl::TRUE, gl::TRUE, gl::TRUE); ck(); - gl::ClearColor(color.r(), color.g(), color.b(), color.a()); ck(); - flags |= gl::COLOR_BUFFER_BIT; - } - if let Some(depth) = params.depth { - gl::DepthMask(gl::TRUE); ck(); - gl::ClearDepthf(depth as _); ck(); // FIXME(pcwalton): GLES - flags |= gl::DEPTH_BUFFER_BIT; - } - if let Some(stencil) = params.stencil { - gl::StencilMask(!0); ck(); - gl::ClearStencil(stencil as GLint); ck(); - flags |= gl::STENCIL_BUFFER_BIT; - } - if flags != 0 { - gl::Clear(flags); ck(); - } - - if params.rect.is_some() { - gl::Disable(gl::SCISSOR_TEST); ck(); + TextureFormat::R16F => { + let mut pixels = vec![0; size.x() as usize * size.y() as usize]; + unsafe { + gl::ReadPixels(origin.x(), + origin.y(), + size.x() as GLsizei, + size.y() as GLsizei, + format.gl_format(), + format.gl_type(), + pixels.as_mut_ptr() as *mut GLvoid); ck(); + } + flip_y(&mut pixels, size, 1); + TextureData::U16(pixels) } } } - fn draw_arrays(&self, primitive: Primitive, index_count: u32, render_state: &RenderState) { + fn begin_commands(&self) { + // TODO(pcwalton): Add some checks in debug mode to make sure render commands are bracketed + // by these? + } + + fn end_commands(&self) { + unsafe { gl::Flush(); } + } + + fn draw_arrays(&self, index_count: u32, render_state: &RenderState) { self.set_render_state(render_state); unsafe { - gl::DrawArrays(primitive.to_gl_primitive(), 0, index_count as GLsizei); ck(); + gl::DrawArrays(render_state.primitive.to_gl_primitive(), + 0, + index_count as GLsizei); ck(); } self.reset_render_state(render_state); } - fn draw_elements(&self, primitive: Primitive, index_count: u32, render_state: &RenderState) { + fn draw_elements(&self, index_count: u32, render_state: &RenderState) { self.set_render_state(render_state); unsafe { - gl::DrawElements(primitive.to_gl_primitive(), + gl::DrawElements(render_state.primitive.to_gl_primitive(), index_count as GLsizei, gl::UNSIGNED_INT, ptr::null()); ck(); @@ -549,13 +546,12 @@ impl Device for GLDevice { } fn draw_elements_instanced(&self, - primitive: Primitive, index_count: u32, instance_count: u32, - render_state: &RenderState) { + render_state: &RenderState) { self.set_render_state(render_state); unsafe { - gl::DrawElementsInstanced(primitive.to_gl_primitive(), + gl::DrawElementsInstanced(render_state.primitive.to_gl_primitive(), index_count as GLsizei, gl::UNSIGNED_INT, ptr::null(), @@ -588,66 +584,102 @@ impl Device for GLDevice { } #[inline] - fn timer_query_is_available(&self, query: &Self::TimerQuery) -> bool { + fn get_timer_query(&self, query: &Self::TimerQuery) -> Option { unsafe { let mut result = 0; gl::GetQueryObjectiv(query.gl_query, gl::QUERY_RESULT_AVAILABLE, &mut result); ck(); - result != gl::FALSE as GLint - } - } - - #[inline] - fn get_timer_query(&self, query: &Self::TimerQuery) -> Duration { - unsafe { + if result == gl::FALSE as GLint { + return None; + } let mut result = 0; gl::GetQueryObjectui64v(query.gl_query, gl::QUERY_RESULT, &mut result); ck(); - Duration::from_nanos(result) + Some(Duration::from_nanos(result)) } } #[inline] + fn bind_buffer(&self, vertex_array: &GLVertexArray, buffer: &GLBuffer, target: BufferTarget) { + self.bind_vertex_array(vertex_array); + unsafe { + gl::BindBuffer(target.to_gl_target(), buffer.gl_buffer); ck(); + } + self.unbind_vertex_array(); + } + + #[inline] + fn create_shader( + &self, + resources: &dyn ResourceLoader, + name: &str, + kind: ShaderKind, + ) -> Self::Shader { + let suffix = match kind { + ShaderKind::Vertex => 'v', + ShaderKind::Fragment => 'f', + }; + let path = format!("shaders/gl3/{}.{}s.glsl", name, suffix); + self.create_shader_from_source(name, &resources.slurp(&path).unwrap(), kind) + } +} + +impl GLDevice { + fn bind_render_target(&self, attachment: &RenderTarget) { + match *attachment { + RenderTarget::Default => self.bind_default_framebuffer(), + RenderTarget::Framebuffer(framebuffer) => self.bind_framebuffer(framebuffer), + } + } + fn bind_vertex_array(&self, vertex_array: &GLVertexArray) { unsafe { gl::BindVertexArray(vertex_array.gl_vertex_array); ck(); } } - #[inline] - fn bind_buffer(&self, buffer: &GLBuffer, target: BufferTarget) { + fn unbind_vertex_array(&self) { unsafe { - gl::BindBuffer(target.to_gl_target(), buffer.gl_buffer); ck(); + gl::BindVertexArray(0); ck(); } } - #[inline] - fn bind_default_framebuffer(&self, viewport: RectI) { - unsafe { - gl::BindFramebuffer(gl::FRAMEBUFFER, self.default_framebuffer); ck(); - gl::Viewport(viewport.origin().x(), - viewport.origin().y(), - viewport.size().x(), - viewport.size().y()); ck(); - } - } - - #[inline] - fn bind_framebuffer(&self, framebuffer: &GLFramebuffer) { - unsafe { - gl::BindFramebuffer(gl::FRAMEBUFFER, framebuffer.gl_framebuffer); ck(); - gl::Viewport(0, 0, framebuffer.texture.size.x(), framebuffer.texture.size.y()); ck(); - } - } - - #[inline] fn bind_texture(&self, texture: &GLTexture, unit: u32) { unsafe { gl::ActiveTexture(gl::TEXTURE0 + unit); ck(); gl::BindTexture(gl::TEXTURE_2D, texture.gl_texture); ck(); } } -} -impl GLDevice { + fn unbind_texture(&self, unit: u32) { + unsafe { + gl::ActiveTexture(gl::TEXTURE0 + unit); ck(); + gl::BindTexture(gl::TEXTURE_2D, 0); ck(); + } + } + + fn use_program(&self, program: &GLProgram) { + unsafe { + gl::UseProgram(program.gl_program); ck(); + } + } + + fn unuse_program(&self) { + unsafe { + gl::UseProgram(0); ck(); + } + } + + fn bind_default_framebuffer(&self) { + unsafe { + gl::BindFramebuffer(gl::FRAMEBUFFER, self.default_framebuffer); ck(); + } + } + + fn bind_framebuffer(&self, framebuffer: &GLFramebuffer) { + unsafe { + gl::BindFramebuffer(gl::FRAMEBUFFER, framebuffer.gl_framebuffer); ck(); + } + } + fn preprocess(&self, output: &mut Vec, source: &[u8], version: &str) { let mut index = 0; while index < source.len() { @@ -669,6 +701,39 @@ impl GLDevice { } } } + + fn clear(&self, ops: &ClearOps) { + unsafe { + let mut flags = 0; + if let Some(color) = ops.color { + gl::ColorMask(gl::TRUE, gl::TRUE, gl::TRUE, gl::TRUE); ck(); + gl::ClearColor(color.r(), color.g(), color.b(), color.a()); ck(); + flags |= gl::COLOR_BUFFER_BIT; + } + if let Some(depth) = ops.depth { + gl::DepthMask(gl::TRUE); ck(); + gl::ClearDepthf(depth as _); ck(); // FIXME(pcwalton): GLES + flags |= gl::DEPTH_BUFFER_BIT; + } + if let Some(stencil) = ops.stencil { + gl::StencilMask(!0); ck(); + gl::ClearStencil(stencil as GLint); ck(); + flags |= gl::STENCIL_BUFFER_BIT; + } + if flags != 0 { + gl::Clear(flags); ck(); + } + } + } + + fn render_target_format(&self, render_target: &RenderTarget) -> TextureFormat { + match *render_target { + RenderTarget::Default => TextureFormat::RGBA8, + RenderTarget::Framebuffer(ref framebuffer) => { + self.framebuffer_texture(framebuffer).format + } + } + } } pub struct GLVertexArray { @@ -753,7 +818,7 @@ impl Drop for GLBuffer { #[derive(Debug)] pub struct GLUniform { - pub location: GLint, + location: GLint, } pub struct GLProgram { @@ -787,6 +852,7 @@ impl Drop for GLShader { pub struct GLTexture { gl_texture: GLuint, pub size: Vector2I, + pub format: TextureFormat, } pub struct GLTimerQuery { @@ -863,7 +929,36 @@ impl StencilFuncExt for StencilFunc { match self { StencilFunc::Always => gl::ALWAYS, StencilFunc::Equal => gl::EQUAL, - StencilFunc::NotEqual => gl::NOTEQUAL, + } + } +} + +trait TextureFormatExt { + fn gl_internal_format(self) -> GLint; + fn gl_format(self) -> GLuint; + fn gl_type(self) -> GLuint; +} + +impl TextureFormatExt for TextureFormat { + fn gl_internal_format(self) -> GLint { + match self { + TextureFormat::R8 => gl::R8 as GLint, + TextureFormat::R16F => gl::R16F as GLint, + TextureFormat::RGBA8 => gl::RGBA as GLint, + } + } + + fn gl_format(self) -> GLuint { + match self { + TextureFormat::R8 | TextureFormat::R16F => gl::RED, + TextureFormat::RGBA8 => gl::RGBA, + } + } + + fn gl_type(self) -> GLuint { + match self { + TextureFormat::R8 | TextureFormat::RGBA8 => gl::UNSIGNED_BYTE, + TextureFormat::R16F => gl::HALF_FLOAT, } } } @@ -929,4 +1024,15 @@ fn ck() { #[cfg(not(debug_assertions))] fn ck() {} -// Shader preprocessing +// Utilities + +// Flips a buffer of image data upside-down. +fn flip_y(pixels: &mut [T], size: Vector2I, channels: usize) { + let stride = size.x() as usize * channels; + for y in 0..(size.y() as usize / 2) { + let (index_a, index_b) = (y * stride, (size.y() as usize - y - 1) * stride); + for offset in 0..stride { + pixels.swap(index_a + offset, index_b + offset); + } + } +} diff --git a/gpu/src/lib.rs b/gpu/src/lib.rs index 7d1fde49..227b0993 100644 --- a/gpu/src/lib.rs +++ b/gpu/src/lib.rs @@ -21,7 +21,7 @@ use std::time::Duration; pub mod resources; -pub trait Device { +pub trait Device: Sized { type Buffer; type Framebuffer; type Program; @@ -34,6 +34,8 @@ pub trait Device { fn create_texture(&self, format: TextureFormat, size: Vector2I) -> Self::Texture; fn create_texture_from_data(&self, size: Vector2I, data: &[u8]) -> Self::Texture; + fn create_shader(&self, resources: &dyn ResourceLoader, name: &str, kind: ShaderKind) + -> Self::Shader; fn create_shader_from_source(&self, name: &str, source: &[u8], kind: ShaderKind) -> Self::Shader; fn create_vertex_array(&self) -> Self::VertexArray; @@ -46,9 +48,14 @@ pub trait Device { ) -> Self::Program; fn get_vertex_attr(&self, program: &Self::Program, name: &str) -> Option; fn get_uniform(&self, program: &Self::Program, name: &str) -> Self::Uniform; - fn use_program(&self, program: &Self::Program); - fn configure_vertex_attr(&self, attr: &Self::VertexAttr, descriptor: &VertexAttrDescriptor); - fn set_uniform(&self, uniform: &Self::Uniform, data: UniformData); + fn bind_buffer(&self, + vertex_array: &Self::VertexArray, + buffer: &Self::Buffer, + target: BufferTarget); + fn configure_vertex_attr(&self, + vertex_array: &Self::VertexArray, + attr: &Self::VertexAttr, + descriptor: &VertexAttrDescriptor); fn create_framebuffer(&self, texture: Self::Texture) -> Self::Framebuffer; fn create_buffer(&self) -> Self::Buffer; fn allocate_buffer( @@ -61,27 +68,19 @@ pub trait Device { fn framebuffer_texture<'f>(&self, framebuffer: &'f Self::Framebuffer) -> &'f Self::Texture; fn texture_size(&self, texture: &Self::Texture) -> Vector2I; fn upload_to_texture(&self, texture: &Self::Texture, size: Vector2I, data: &[u8]); - fn read_pixels_from_default_framebuffer(&self, size: Vector2I) -> Vec; - fn clear(&self, params: &ClearParams); - fn draw_arrays(&self, primitive: Primitive, index_count: u32, render_state: &RenderState); - fn draw_elements(&self, primitive: Primitive, index_count: u32, render_state: &RenderState); + fn read_pixels(&self, target: &RenderTarget, viewport: RectI) -> TextureData; + fn begin_commands(&self); + fn end_commands(&self); + fn draw_arrays(&self, index_count: u32, render_state: &RenderState); + fn draw_elements(&self, index_count: u32, render_state: &RenderState); fn draw_elements_instanced(&self, - primitive: Primitive, index_count: u32, instance_count: u32, - render_state: &RenderState); + render_state: &RenderState); fn create_timer_query(&self) -> Self::TimerQuery; fn begin_timer_query(&self, query: &Self::TimerQuery); fn end_timer_query(&self, query: &Self::TimerQuery); - fn timer_query_is_available(&self, query: &Self::TimerQuery) -> bool; - fn get_timer_query(&self, query: &Self::TimerQuery) -> Duration; - - // TODO(pcwalton): Go bindless... - fn bind_vertex_array(&self, vertex_array: &Self::VertexArray); - fn bind_buffer(&self, buffer: &Self::Buffer, target: BufferTarget); - fn bind_default_framebuffer(&self, viewport: RectI); - fn bind_framebuffer(&self, framebuffer: &Self::Framebuffer); - fn bind_texture(&self, texture: &Self::Texture, unit: u32); + fn get_timer_query(&self, query: &Self::TimerQuery) -> Option; fn create_texture_from_png(&self, resources: &dyn ResourceLoader, name: &str) -> Self::Texture { let data = resources.slurp(&format!("textures/{}.png", name)).unwrap(); @@ -92,20 +91,6 @@ pub trait Device { self.create_texture_from_data(size, &image) } - fn create_shader( - &self, - resources: &dyn ResourceLoader, - name: &str, - kind: ShaderKind, - ) -> Self::Shader { - let suffix = match kind { - ShaderKind::Vertex => 'v', - ShaderKind::Fragment => 'f', - }; - let source = resources.slurp(&format!("shaders/gl3/{}.{}s.glsl", name, suffix)).unwrap(); - self.create_shader_from_source(name, &source, kind) - } - fn create_program_from_shader_names( &self, resources: &dyn ResourceLoader, @@ -124,7 +109,7 @@ pub trait Device { } } -#[derive(Clone, Copy, Debug)] +#[derive(Clone, Copy, Debug, PartialEq)] pub enum TextureFormat { R8, R16F, @@ -167,7 +152,6 @@ pub enum ShaderKind { #[derive(Clone, Copy)] pub enum UniformData { Int(i32), - Mat2(F32x4), Mat4([F32x4; 4]), Vec2(F32x4), Vec4(F32x4), @@ -180,23 +164,41 @@ pub enum Primitive { Lines, } -#[derive(Clone, Copy, Default)] -pub struct ClearParams { +#[derive(Clone)] +pub struct RenderState<'a, D> where D: Device { + pub target: &'a RenderTarget<'a, D>, + pub program: &'a D::Program, + pub vertex_array: &'a D::VertexArray, + pub primitive: Primitive, + pub uniforms: &'a [(&'a D::Uniform, UniformData)], + pub textures: &'a [&'a D::Texture], + pub viewport: RectI, + pub options: RenderOptions, +} + +#[derive(Clone, Debug)] +pub struct RenderOptions { + pub blend: BlendState, + pub depth: Option, + pub stencil: Option, + pub clear_ops: ClearOps, + pub color_mask: bool, +} + +#[derive(Clone, Copy, Debug, Default)] +pub struct ClearOps { pub color: Option, - pub rect: Option, pub depth: Option, pub stencil: Option, } -#[derive(Clone, Debug)] -pub struct RenderState { - pub blend: BlendState, - pub depth: Option, - pub stencil: Option, - pub color_mask: bool, +#[derive(Clone, Copy, Debug)] +pub enum RenderTarget<'a, D> where D: Device { + Default, + Framebuffer(&'a D::Framebuffer), } -#[derive(Clone, Copy, Debug)] +#[derive(Clone, Copy, Debug, PartialEq)] pub enum BlendState { Off, RGBOneAlphaOne, @@ -228,16 +230,16 @@ pub struct StencilState { pub enum StencilFunc { Always, Equal, - NotEqual, } -impl Default for RenderState { +impl Default for RenderOptions { #[inline] - fn default() -> RenderState { - RenderState { + fn default() -> RenderOptions { + RenderOptions { blend: BlendState::default(), depth: None, stencil: None, + clear_ops: ClearOps::default(), color_mask: true, } } @@ -276,6 +278,12 @@ impl Default for StencilFunc { } } +#[derive(Clone, Debug)] +pub enum TextureData { + U8(Vec), + U16(Vec), +} + impl UniformData { #[inline] pub fn from_transform_3d(transform: &Transform3DF) -> UniformData { @@ -291,6 +299,7 @@ pub struct VertexAttrDescriptor { pub stride: usize, pub offset: usize, pub divisor: u32, + pub buffer_index: u32, } #[derive(Clone, Copy, Debug, PartialEq)] @@ -299,3 +308,20 @@ pub enum VertexAttrClass { FloatNorm, Int, } + +impl TextureFormat { + #[inline] + pub fn channels(self) -> usize { + match self { + TextureFormat::R8 | TextureFormat::R16F => 1, + TextureFormat::RGBA8 => 4, + } + } +} + +impl ClearOps { + #[inline] + pub fn has_ops(&self) -> bool { + self.color.is_some() || self.depth.is_some() || self.stencil.is_some() + } +} diff --git a/metal/Cargo.toml b/metal/Cargo.toml new file mode 100644 index 00000000..8ddef24b --- /dev/null +++ b/metal/Cargo.toml @@ -0,0 +1,24 @@ +[package] +name = "pathfinder_metal" +version = "0.1.0" +authors = ["Patrick Walton "] +edition = "2018" + +[dependencies] +bitflags = "1.0" +byteorder = "1.3" +block = "0.1" +cocoa = "0.18" +core-foundation = "0.6" +foreign-types = "0.3" +metal = "0.14" +objc = "0.2" + +[dependencies.pathfinder_geometry] +path = "../geometry" + +[dependencies.pathfinder_gpu] +path = "../gpu" + +[dependencies.pathfinder_simd] +path = "../simd" diff --git a/metal/src/lib.rs b/metal/src/lib.rs new file mode 100644 index 00000000..63856a09 --- /dev/null +++ b/metal/src/lib.rs @@ -0,0 +1,1484 @@ +// pathfinder/metal/src/lib.rs +// +// Copyright © 2019 The Pathfinder Project Developers. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! A Metal implementation of the device abstraction, for macOS and iOS. + +#![allow(non_upper_case_globals)] + +#[macro_use] +extern crate bitflags; +#[macro_use] +extern crate objc; + +use block::{Block, ConcreteBlock, RcBlock}; +use byteorder::{NativeEndian, WriteBytesExt}; +use cocoa::foundation::{NSRange, NSUInteger}; +use core_foundation::base::TCFType; +use core_foundation::string::{CFString, CFStringRef}; +use foreign_types::{ForeignType, ForeignTypeRef}; +use metal::{self, Argument, ArgumentEncoder, Buffer, CommandBuffer, CommandBufferRef}; +use metal::{CommandQueue, CompileOptions, CoreAnimationDrawable, CoreAnimationDrawableRef}; +use metal::{CoreAnimationLayer, CoreAnimationLayerRef, DepthStencilDescriptor, Function, Library}; +use metal::{MTLArgument, MTLArgumentEncoder, MTLBlendFactor, MTLClearColor, MTLColorWriteMask}; +use metal::{MTLCompareFunction, MTLDataType, MTLDevice, MTLFunctionType, MTLIndexType}; +use metal::{MTLLoadAction, MTLOrigin, MTLPixelFormat, MTLPrimitiveType, MTLRegion}; +use metal::{MTLRenderPipelineReflection, MTLRenderPipelineState, MTLResourceOptions}; +use metal::{MTLResourceUsage, MTLSamplerAddressMode, MTLSamplerMinMagFilter, MTLSize}; +use metal::{MTLStencilOperation, MTLStorageMode, MTLStoreAction, MTLTextureType, MTLTextureUsage}; +use metal::{MTLVertexFormat, MTLVertexStepFunction, MTLViewport, RenderCommandEncoder}; +use metal::{RenderCommandEncoderRef, RenderPassDescriptor, RenderPassDescriptorRef}; +use metal::{RenderPipelineColorAttachmentDescriptorRef, RenderPipelineDescriptor}; +use metal::{RenderPipelineReflection, RenderPipelineReflectionRef, RenderPipelineState}; +use metal::{SamplerDescriptor, SamplerState, StencilDescriptor, StructMemberRef, StructType}; +use metal::{StructTypeRef, TextureDescriptor, Texture, TextureRef, VertexAttribute}; +use metal::{VertexAttributeRef, VertexDescriptor, VertexDescriptorRef}; +use objc::runtime::{Class, Object}; +use pathfinder_geometry::basic::rect::RectI; +use pathfinder_geometry::basic::vector::Vector2I; +use pathfinder_gpu::resources::ResourceLoader; +use pathfinder_gpu::{BlendState, BufferData, BufferTarget, BufferUploadMode, DepthFunc, Device}; +use pathfinder_gpu::{Primitive, RenderState, RenderTarget, ShaderKind, StencilFunc, TextureData}; +use pathfinder_gpu::{TextureFormat, UniformData, VertexAttrClass}; +use pathfinder_gpu::{VertexAttrDescriptor, VertexAttrType}; +use pathfinder_simd::default::F32x4; +use std::cell::{Cell, RefCell}; +use std::mem; +use std::ptr; +use std::rc::Rc; +use std::slice; +use std::sync::Arc; +use std::time::{Duration, Instant}; + +const FIRST_VERTEX_BUFFER_INDEX: u64 = 1; + +pub struct MetalDevice { + device: metal::Device, + layer: CoreAnimationLayer, + drawable: CoreAnimationDrawable, + main_depth_stencil_texture: Texture, + command_queue: CommandQueue, + command_buffers: RefCell>, + sampler: SamplerState, + shared_event: SharedEvent, + shared_event_listener: SharedEventListener, + next_timer_query_event_value: Cell, +} + +pub struct MetalProgram { + vertex: MetalShader, + fragment: MetalShader, +} + +#[derive(Clone)] +pub struct MetalBuffer { + buffer: Rc>>, +} + +impl MetalDevice { + #[inline] + pub fn new(layer: &CoreAnimationLayerRef) -> MetalDevice { + let layer = layer.retain(); + let device = layer.device(); + let drawable = layer.next_drawable().unwrap().retain(); + let command_queue = device.new_command_queue(); + + let sampler_descriptor = SamplerDescriptor::new(); + sampler_descriptor.set_support_argument_buffers(true); + sampler_descriptor.set_normalized_coordinates(true); + sampler_descriptor.set_min_filter(MTLSamplerMinMagFilter::Linear); + sampler_descriptor.set_mag_filter(MTLSamplerMinMagFilter::Linear); + sampler_descriptor.set_address_mode_s(MTLSamplerAddressMode::ClampToEdge); + sampler_descriptor.set_address_mode_t(MTLSamplerAddressMode::ClampToEdge); + let sampler = device.new_sampler(&sampler_descriptor); + + let main_color_texture = drawable.texture(); + let framebuffer_size = Vector2I::new(main_color_texture.width() as i32, + main_color_texture.height() as i32); + let main_depth_stencil_texture = device.create_depth_stencil_texture(framebuffer_size); + + let shared_event = device.new_shared_event(); + + MetalDevice { + device, + layer, + drawable, + main_depth_stencil_texture, + command_queue, + command_buffers: RefCell::new(vec![]), + sampler, + shared_event, + shared_event_listener: SharedEventListener::new(), + next_timer_query_event_value: Cell::new(1), + } + } + + pub fn present_drawable(&mut self) { + self.begin_commands(); + self.command_buffers.borrow_mut().last().unwrap().present_drawable(&self.drawable); + self.end_commands(); + self.drawable = self.layer.next_drawable().unwrap().retain(); + } +} + +pub struct MetalFramebuffer(MetalTexture); + +pub struct MetalShader { + #[allow(dead_code)] + library: Library, + function: Function, + uniforms: RefCell, +} + +enum ShaderUniforms { + Unknown, + NoUniforms, + Uniforms { encoder: ArgumentEncoder, struct_type: StructType } +} + +pub struct MetalTexture { + texture: Texture, + dirty: Cell, +} + +pub struct MetalTimerQuery { + event_value: u64, + start_time: Cell>, + end_time: Cell>, +} + +#[derive(Clone)] +pub struct MetalUniform { + indices: RefCell>, + name: String, +} + +#[derive(Clone, Copy)] +pub struct MetalUniformIndices { + vertex: Option, + fragment: Option, +} + +#[derive(Clone, Copy)] +pub struct MetalUniformIndex { + main: u64, + sampler: Option, +} + +pub struct MetalVertexArray { + descriptor: VertexDescriptor, + vertex_buffers: RefCell>, + index_buffer: RefCell>, +} + +impl Device for MetalDevice { + type Buffer = MetalBuffer; + type Framebuffer = MetalFramebuffer; + type Program = MetalProgram; + type Shader = MetalShader; + type Texture = MetalTexture; + type TimerQuery = Arc; + type Uniform = MetalUniform; + type VertexArray = MetalVertexArray; + type VertexAttr = VertexAttribute; + + // TODO: Add texture usage hint. + fn create_texture(&self, format: TextureFormat, size: Vector2I) -> MetalTexture { + let descriptor = TextureDescriptor::new(); + descriptor.set_texture_type(MTLTextureType::D2); + match format { + TextureFormat::R8 => descriptor.set_pixel_format(MTLPixelFormat::R8Unorm), + TextureFormat::R16F => descriptor.set_pixel_format(MTLPixelFormat::R16Float), + TextureFormat::RGBA8 => descriptor.set_pixel_format(MTLPixelFormat::RGBA8Unorm), + } + descriptor.set_width(size.x() as u64); + descriptor.set_height(size.y() as u64); + descriptor.set_storage_mode(MTLStorageMode::Managed); + descriptor.set_usage(MTLTextureUsage::Unknown); + MetalTexture { texture: self.device.new_texture(&descriptor), dirty: Cell::new(false) } + } + + fn create_texture_from_data(&self, size: Vector2I, data: &[u8]) -> MetalTexture { + assert!(data.len() >= size.x() as usize * size.y() as usize); + let texture = self.create_texture(TextureFormat::R8, size); + self.upload_to_texture(&texture, size, data); + texture + } + + fn create_shader_from_source(&self, _: &str, source: &[u8], _: ShaderKind) -> MetalShader { + let source = String::from_utf8(source.to_vec()).expect("Source wasn't valid UTF-8!"); + + let compile_options = CompileOptions::new(); + let library = self.device.new_library_with_source(&source, &compile_options).unwrap(); + let function = library.get_function("main0", None).unwrap(); + + MetalShader { library, function, uniforms: RefCell::new(ShaderUniforms::Unknown) } + } + + fn create_vertex_array(&self) -> MetalVertexArray { + MetalVertexArray { + descriptor: VertexDescriptor::new().retain(), + vertex_buffers: RefCell::new(vec![]), + index_buffer: RefCell::new(None), + } + } + + fn bind_buffer(&self, + vertex_array: &MetalVertexArray, + buffer: &MetalBuffer, + target: BufferTarget) { + match target { + BufferTarget::Vertex => { + vertex_array.vertex_buffers.borrow_mut().push((*buffer).clone()) + } + BufferTarget::Index => { + *vertex_array.index_buffer.borrow_mut() = Some((*buffer).clone()) + } + } + } + + fn create_program_from_shaders(&self, + _: &dyn ResourceLoader, + _: &str, + vertex_shader: MetalShader, + fragment_shader: MetalShader) + -> MetalProgram { + MetalProgram { vertex: vertex_shader, fragment: fragment_shader } + } + + fn get_vertex_attr(&self, program: &MetalProgram, name: &str) -> Option { + // TODO(pcwalton): Cache the function? + let attributes = program.vertex.function.real_vertex_attributes(); + for attribute_index in 0..attributes.len() { + let attribute = attributes.object_at(attribute_index); + let this_name = attribute.name().as_bytes(); + if this_name[0] == b'a' && this_name[1..] == *name.as_bytes() { + return Some(attribute.retain()) + } + } + None + } + + fn get_uniform(&self, _: &Self::Program, name: &str) -> MetalUniform { + MetalUniform { indices: RefCell::new(None), name: name.to_owned() } + } + + fn configure_vertex_attr(&self, + vertex_array: &MetalVertexArray, + attr: &VertexAttribute, + descriptor: &VertexAttrDescriptor) { + debug_assert_ne!(descriptor.stride, 0); + + let attribute_index = attr.attribute_index(); + + let attr_info = vertex_array.descriptor + .attributes() + .object_at(attribute_index as usize) + .unwrap(); + let format = match (descriptor.class, descriptor.attr_type, descriptor.size) { + (VertexAttrClass::Int, VertexAttrType::I8, 2) => MTLVertexFormat::Char2, + (VertexAttrClass::Int, VertexAttrType::I8, 3) => MTLVertexFormat::Char3, + (VertexAttrClass::Int, VertexAttrType::I8, 4) => MTLVertexFormat::Char4, + (VertexAttrClass::Int, VertexAttrType::U8, 2) => MTLVertexFormat::UChar2, + (VertexAttrClass::Int, VertexAttrType::U8, 3) => MTLVertexFormat::UChar3, + (VertexAttrClass::Int, VertexAttrType::U8, 4) => MTLVertexFormat::UChar4, + (VertexAttrClass::FloatNorm, VertexAttrType::U8, 2) => { + MTLVertexFormat::UChar2Normalized + } + (VertexAttrClass::FloatNorm, VertexAttrType::U8, 3) => { + MTLVertexFormat::UChar3Normalized + } + (VertexAttrClass::FloatNorm, VertexAttrType::U8, 4) => { + MTLVertexFormat::UChar4Normalized + } + (VertexAttrClass::FloatNorm, VertexAttrType::I8, 2) => { + MTLVertexFormat::Char2Normalized + } + (VertexAttrClass::FloatNorm, VertexAttrType::I8, 3) => { + MTLVertexFormat::Char3Normalized + } + (VertexAttrClass::FloatNorm, VertexAttrType::I8, 4) => { + MTLVertexFormat::Char4Normalized + } + (VertexAttrClass::Int, VertexAttrType::I16, 2) => MTLVertexFormat::Short2, + (VertexAttrClass::Int, VertexAttrType::I16, 3) => MTLVertexFormat::Short3, + (VertexAttrClass::Int, VertexAttrType::I16, 4) => MTLVertexFormat::Short4, + (VertexAttrClass::Int, VertexAttrType::U16, 2) => MTLVertexFormat::UShort2, + (VertexAttrClass::Int, VertexAttrType::U16, 3) => MTLVertexFormat::UShort3, + (VertexAttrClass::Int, VertexAttrType::U16, 4) => MTLVertexFormat::UShort4, + (VertexAttrClass::FloatNorm, VertexAttrType::U16, 2) => { + MTLVertexFormat::UShort2Normalized + } + (VertexAttrClass::FloatNorm, VertexAttrType::U16, 3) => { + MTLVertexFormat::UShort3Normalized + } + (VertexAttrClass::FloatNorm, VertexAttrType::U16, 4) => { + MTLVertexFormat::UShort4Normalized + } + (VertexAttrClass::FloatNorm, VertexAttrType::I16, 2) => { + MTLVertexFormat::Short2Normalized + } + (VertexAttrClass::FloatNorm, VertexAttrType::I16, 3) => { + MTLVertexFormat::Short3Normalized + } + (VertexAttrClass::FloatNorm, VertexAttrType::I16, 4) => { + MTLVertexFormat::Short4Normalized + } + (VertexAttrClass::Float, VertexAttrType::F32, 1) => MTLVertexFormat::Float, + (VertexAttrClass::Float, VertexAttrType::F32, 2) => MTLVertexFormat::Float2, + (VertexAttrClass::Float, VertexAttrType::F32, 3) => MTLVertexFormat::Float3, + (VertexAttrClass::Float, VertexAttrType::F32, 4) => MTLVertexFormat::Float4, + (VertexAttrClass::Int, VertexAttrType::I8, 1) => MTLVertexFormat::Char, + (VertexAttrClass::Int, VertexAttrType::U8, 1) => MTLVertexFormat::UChar, + (VertexAttrClass::FloatNorm, VertexAttrType::I8, 1) => MTLVertexFormat::CharNormalized, + (VertexAttrClass::Int, VertexAttrType::I16, 1) => MTLVertexFormat::Short, + (VertexAttrClass::Int, VertexAttrType::U16, 1) => MTLVertexFormat::UShort, + (VertexAttrClass::FloatNorm, VertexAttrType::U16, 1) => { + MTLVertexFormat::UShortNormalized + } + (VertexAttrClass::FloatNorm, VertexAttrType::I16, 1) => { + MTLVertexFormat::ShortNormalized + } + (attr_class, attr_type, attr_size) => { + panic!("Unsupported vertex class/type/size combination: {:?}/{:?}/{}!", + attr_class, + attr_type, + attr_size) + } + }; + attr_info.set_format(format); + attr_info.set_offset(descriptor.offset as u64); + let buffer_index = descriptor.buffer_index as u64 + FIRST_VERTEX_BUFFER_INDEX; + attr_info.set_buffer_index(buffer_index); + + // FIXME(pcwalton): Metal separates out per-buffer info from per-vertex info, while our + // GL-like API does not. So we end up setting this state over and over again. Not great. + let layout = vertex_array.descriptor.layouts().object_at(buffer_index as usize).unwrap(); + if descriptor.divisor == 0 { + layout.set_step_function(MTLVertexStepFunction::PerVertex); + layout.set_step_rate(1); + } else { + layout.set_step_function(MTLVertexStepFunction::PerInstance); + layout.set_step_rate(descriptor.divisor as u64); + } + layout.set_stride(descriptor.stride as u64); + } + + fn create_framebuffer(&self, texture: MetalTexture) -> MetalFramebuffer { + MetalFramebuffer(texture) + } + + fn create_buffer(&self) -> MetalBuffer { + MetalBuffer { buffer: Rc::new(RefCell::new(None)) } + } + + fn allocate_buffer(&self, + buffer: &MetalBuffer, + data: BufferData, + _: BufferTarget, + mode: BufferUploadMode) { + let mut options = match mode { + BufferUploadMode::Static => MTLResourceOptions::CPUCacheModeWriteCombined, + BufferUploadMode::Dynamic => MTLResourceOptions::CPUCacheModeDefaultCache, + }; + options |= MTLResourceOptions::StorageModeManaged; + + match data { + BufferData::Uninitialized(size) => { + let size = (size * mem::size_of::()) as u64; + let new_buffer = self.device.new_buffer(size, options); + *buffer.buffer.borrow_mut() = Some(new_buffer); + } + BufferData::Memory(slice) => { + let size = (slice.len() * mem::size_of::()) as u64; + let new_buffer = self.device.new_buffer_with_data(slice.as_ptr() as *const _, + size, + options); + *buffer.buffer.borrow_mut() = Some(new_buffer); + } + } + } + + fn framebuffer_texture<'f>(&self, framebuffer: &'f MetalFramebuffer) -> &'f MetalTexture { + &framebuffer.0 + } + + fn texture_size(&self, texture: &MetalTexture) -> Vector2I { + Vector2I::new(texture.texture.width() as i32, texture.texture.height() as i32) + } + + fn upload_to_texture(&self, texture: &MetalTexture, size: Vector2I, data: &[u8]) { + assert!(data.len() >= size.x() as usize * size.y() as usize); + let format = self.texture_format(&texture.texture).expect("Unexpected texture format!"); + assert!(format == TextureFormat::R8 || format == TextureFormat::RGBA8); + + let origin = MTLOrigin { x: 0, y: 0, z: 0 }; + let size = MTLSize { width: size.x() as u64, height: size.y() as u64, depth: 1 }; + let region = MTLRegion { origin, size }; + let stride = size.width * format.channels() as u64; + texture.texture.replace_region(region, 0, stride, data.as_ptr() as *const _); + + texture.dirty.set(true); + } + + fn read_pixels(&self, target: &RenderTarget, viewport: RectI) -> TextureData { + let texture = self.render_target_color_texture(target); + self.synchronize_texture(&texture); + + let (origin, size) = (viewport.origin(), viewport.size()); + let metal_origin = MTLOrigin { x: origin.x() as u64, y: origin.y() as u64, z: 0 }; + let metal_size = MTLSize { width: size.x() as u64, height: size.y() as u64, depth: 1 }; + let metal_region = MTLRegion { origin: metal_origin, size: metal_size }; + + let format = self.texture_format(&texture) + .expect("Unexpected framebuffer texture format!"); + match format { + TextureFormat::R8 | TextureFormat::RGBA8 => { + let channels = format.channels(); + let stride = size.x() as usize * channels; + let mut pixels = vec![0; stride * size.y() as usize]; + texture.get_bytes(pixels.as_mut_ptr() as *mut _, metal_region, 0, stride as u64); + TextureData::U8(pixels) + } + TextureFormat::R16F => { + let stride = size.x() as usize; + let mut pixels = vec![0; stride * size.y() as usize]; + texture.get_bytes(pixels.as_mut_ptr() as *mut _, + metal_region, + 0, + stride as u64 * 2); + TextureData::U16(pixels) + } + } + } + + fn begin_commands(&self) { + self.command_buffers.borrow_mut().push(self.command_queue.new_command_buffer().retain()); + } + + fn end_commands(&self) { + let command_buffer = self.command_buffers.borrow_mut().pop().unwrap(); + command_buffer.commit(); + } + + fn draw_arrays(&self, index_count: u32, render_state: &RenderState) { + let encoder = self.prepare_to_draw(render_state); + let primitive = render_state.primitive.to_metal_primitive(); + encoder.draw_primitives(primitive, 0, index_count as u64); + encoder.end_encoding(); + } + + fn draw_elements(&self, index_count: u32, render_state: &RenderState) { + let encoder = self.prepare_to_draw(render_state); + let primitive = render_state.primitive.to_metal_primitive(); + let index_type = MTLIndexType::UInt32; + let index_count = index_count as u64; + let index_buffer = render_state.vertex_array + .index_buffer + .borrow(); + let index_buffer = index_buffer.as_ref().expect("No index buffer bound to VAO!"); + let index_buffer = index_buffer.buffer.borrow(); + let index_buffer = index_buffer.as_ref().expect("Index buffer not allocated!"); + encoder.draw_indexed_primitives(primitive, index_count, index_type, index_buffer, 0); + encoder.end_encoding(); + } + + fn draw_elements_instanced(&self, + index_count: u32, + instance_count: u32, + render_state: &RenderState) { + let encoder = self.prepare_to_draw(render_state); + let primitive = render_state.primitive.to_metal_primitive(); + let index_type = MTLIndexType::UInt32; + let index_buffer = render_state.vertex_array + .index_buffer + .borrow(); + let index_buffer = index_buffer.as_ref().expect("No index buffer bound to VAO!"); + let index_buffer = index_buffer.buffer.borrow(); + let index_buffer = index_buffer.as_ref().expect("Index buffer not allocated!"); + encoder.draw_indexed_primitives_instanced(primitive, + index_count as u64, + index_type, + index_buffer, + 0, + instance_count as u64); + encoder.end_encoding(); + } + + fn create_timer_query(&self) -> Arc { + let event_value = self.next_timer_query_event_value.get(); + self.next_timer_query_event_value.set(event_value + 2); + + let query = Arc::new(MetalTimerQuery { + event_value, + start_time: Cell::new(None), + end_time: Cell::new(None), + }); + + let captured_query = query.clone(); + let start_block = ConcreteBlock::new(move |_: *mut Object, _: u64| { + captured_query.start_time.set(Some(Instant::now())) + }); + let captured_query = query.clone(); + let end_block = ConcreteBlock::new(move |_: *mut Object, _: u64| { + captured_query.end_time.set(Some(Instant::now())) + }); + self.shared_event.notify_listener_at_value(&self.shared_event_listener, + event_value, + start_block.copy()); + self.shared_event.notify_listener_at_value(&self.shared_event_listener, + event_value + 1, + end_block.copy()); + + query + } + + fn begin_timer_query(&self, query: &Arc) { + self.command_buffers + .borrow_mut() + .last() + .unwrap() + .encode_signal_event(&self.shared_event, query.event_value); + } + + fn end_timer_query(&self, query: &Arc) { + self.command_buffers + .borrow_mut() + .last() + .unwrap() + .encode_signal_event(&self.shared_event, query.event_value + 1); + } + + fn get_timer_query(&self, query: &Arc) -> Option { + match (query.start_time.get(), query.end_time.get()) { + (Some(start_time), Some(end_time)) => Some(end_time - start_time), + _ => None, + } + } + + #[inline] + fn create_shader( + &self, + resources: &dyn ResourceLoader, + name: &str, + kind: ShaderKind, + ) -> Self::Shader { + let suffix = match kind { + ShaderKind::Vertex => 'v', + ShaderKind::Fragment => 'f', + }; + let path = format!("shaders/metal/{}.{}s.metal", name, suffix); + self.create_shader_from_source(name, &resources.slurp(&path).unwrap(), kind) + } +} + +impl MetalDevice { + fn get_uniform_index(&self, shader: &MetalShader, name: &str) -> Option { + let uniforms = shader.uniforms.borrow(); + let struct_type = match *uniforms { + ShaderUniforms::Unknown => panic!("get_uniform_index() called before reflection!"), + ShaderUniforms::NoUniforms => return None, + ShaderUniforms::Uniforms { ref struct_type, .. } => struct_type, + }; + let main_member = match struct_type.member_from_name(&format!("u{}", name)) { + None => return None, + Some(main_member) => main_member, + }; + let main_index = main_member.argument_index(); + let sampler_index = match struct_type.member_from_name(&format!("u{}Smplr", name)) { + None => None, + Some(sampler_member) => Some(sampler_member.argument_index()), + }; + Some(MetalUniformIndex { main: main_index, sampler: sampler_index }) + } + + fn populate_uniform_indices_if_necessary(&self, + uniform: &MetalUniform, + program: &MetalProgram) { + + let mut indices = uniform.indices.borrow_mut(); + if indices.is_some() { + return; + } + + *indices = Some(MetalUniformIndices { + vertex: self.get_uniform_index(&program.vertex, &uniform.name), + fragment: self.get_uniform_index(&program.fragment, &uniform.name), + }); + } + + fn render_target_color_texture(&self, render_target: &RenderTarget) + -> Texture { + match *render_target { + RenderTarget::Default {..} => self.drawable.texture().retain(), + RenderTarget::Framebuffer(framebuffer) => framebuffer.0.texture.retain(), + } + } + + fn render_target_depth_texture(&self, render_target: &RenderTarget) + -> Option { + match *render_target { + RenderTarget::Default {..} => Some(self.main_depth_stencil_texture.retain()), + RenderTarget::Framebuffer(_) => None, + } + } + + fn render_target_has_depth(&self, render_target: &RenderTarget) -> bool { + match *render_target { + RenderTarget::Default {..} => true, + RenderTarget::Framebuffer(_) => false, + } + } + + fn prepare_to_draw(&self, render_state: &RenderState) -> RenderCommandEncoder { + let command_buffers = self.command_buffers.borrow(); + let command_buffer = command_buffers.last().unwrap(); + + // FIXME(pcwalton): Is this necessary? + let mut blit_command_encoder = None; + for texture in render_state.textures { + if !texture.dirty.get() { + continue; + } + if blit_command_encoder.is_none() { + blit_command_encoder = Some(command_buffer.new_blit_command_encoder()); + } + let blit_command_encoder = blit_command_encoder.as_ref().unwrap(); + blit_command_encoder.synchronize_resource(&texture.texture); + texture.dirty.set(false); + } + if let Some(blit_command_encoder) = blit_command_encoder { + blit_command_encoder.end_encoding(); + } + + let render_pass_descriptor = self.create_render_pass_descriptor(render_state); + + let encoder = command_buffer.new_render_command_encoder(&render_pass_descriptor).retain(); + self.set_viewport(&encoder, &render_state.viewport); + + let render_pipeline_descriptor = RenderPipelineDescriptor::new(); + render_pipeline_descriptor.set_vertex_function(Some(&render_state.program + .vertex + .function)); + render_pipeline_descriptor.set_fragment_function(Some(&render_state.program + .fragment + .function)); + render_pipeline_descriptor.set_vertex_descriptor(Some(&render_state.vertex_array + .descriptor)); + + // Create render pipeline state. + let pipeline_color_attachment = render_pipeline_descriptor.color_attachments() + .object_at(0) + .unwrap(); + self.prepare_pipeline_color_attachment_for_render(pipeline_color_attachment, + render_state); + + if self.render_target_has_depth(render_state.target) { + let depth_stencil_format = MTLPixelFormat::Depth32Float_Stencil8; + render_pipeline_descriptor.set_depth_attachment_pixel_format(depth_stencil_format); + render_pipeline_descriptor.set_stencil_attachment_pixel_format(depth_stencil_format); + } + + let reflection_options = MTLPipelineOption::ArgumentInfo | + MTLPipelineOption::BufferTypeInfo; + let (render_pipeline_state, reflection) = + self.device.real_new_render_pipeline_state_with_reflection(&render_pipeline_descriptor, + reflection_options); + + self.populate_shader_uniforms_if_necessary(&render_state.program.vertex, &reflection); + self.populate_shader_uniforms_if_necessary(&render_state.program.fragment, &reflection); + + for (vertex_buffer_index, vertex_buffer) in render_state.vertex_array + .vertex_buffers + .borrow() + .iter() + .enumerate() { + let real_index = vertex_buffer_index as u64 + FIRST_VERTEX_BUFFER_INDEX; + let buffer = vertex_buffer.buffer.borrow(); + let buffer = buffer.as_ref().map(|buffer| buffer.as_ref()).unwrap(); + encoder.set_vertex_buffer(real_index, Some(buffer), 0); + encoder.use_resource(buffer, MTLResourceUsage::Read); + } + + self.set_uniforms(&encoder, render_state); + encoder.set_render_pipeline_state(&render_pipeline_state); + self.set_depth_stencil_state(&encoder, render_state); + encoder + } + + fn populate_shader_uniforms_if_necessary(&self, + shader: &MetalShader, + reflection: &RenderPipelineReflectionRef) { + let mut uniforms = shader.uniforms.borrow_mut(); + match *uniforms { + ShaderUniforms::Unknown => {} + ShaderUniforms::NoUniforms | ShaderUniforms::Uniforms { .. } => return, + } + + let arguments = match shader.function.function_type() { + MTLFunctionType::Vertex => reflection.real_vertex_arguments(), + MTLFunctionType::Fragment => reflection.real_fragment_arguments(), + _ => panic!("Unexpected shader function type!"), + }; + + let mut has_descriptor_set = false; + for argument_index in 0..arguments.len() { + let argument = arguments.object_at(argument_index); + if argument.name() == "spvDescriptorSet0" { + has_descriptor_set = true; + break; + } + } + if !has_descriptor_set { + *uniforms = ShaderUniforms::NoUniforms; + return; + } + + let (encoder, argument) = shader.function.new_argument_encoder_with_reflection(0); + match argument.buffer_data_type() { + MTLDataType::Struct => {} + data_type => { + panic!("Unexpected data type for argument buffer: {}!", data_type as u32) + } + } + let struct_type = argument.buffer_struct_type().retain(); + *uniforms = ShaderUniforms::Uniforms { encoder, struct_type }; + } + + fn create_argument_buffer(&self, shader: &MetalShader) -> Option { + let uniforms = shader.uniforms.borrow(); + let encoder = match *uniforms { + ShaderUniforms::Unknown => unreachable!(), + ShaderUniforms::NoUniforms => return None, + ShaderUniforms::Uniforms { ref encoder, .. } => encoder, + }; + + let buffer_options = MTLResourceOptions::CPUCacheModeDefaultCache | + MTLResourceOptions::StorageModeManaged; + let buffer = self.device.new_buffer(encoder.encoded_length(), buffer_options); + encoder.set_argument_buffer(&buffer, 0); + Some(buffer) + } + + fn set_uniforms(&self, + render_command_encoder: &RenderCommandEncoderRef, + render_state: &RenderState) { + let vertex_argument_buffer = self.create_argument_buffer(&render_state.program.vertex); + let fragment_argument_buffer = self.create_argument_buffer(&render_state.program.fragment); + + let vertex_uniforms = render_state.program.vertex.uniforms.borrow(); + let fragment_uniforms = render_state.program.fragment.uniforms.borrow(); + + let (mut have_vertex_uniforms, mut have_fragment_uniforms) = (false, false); + if let ShaderUniforms::Uniforms { .. } = *vertex_uniforms { + have_vertex_uniforms = true; + let vertex_argument_buffer = vertex_argument_buffer.as_ref().unwrap(); + render_command_encoder.use_resource(vertex_argument_buffer, MTLResourceUsage::Read); + render_command_encoder.set_vertex_buffer(0, Some(vertex_argument_buffer), 0); + } + if let ShaderUniforms::Uniforms { .. } = *fragment_uniforms { + have_fragment_uniforms = true; + let fragment_argument_buffer = fragment_argument_buffer.as_ref().unwrap(); + render_command_encoder.use_resource(fragment_argument_buffer, MTLResourceUsage::Read); + render_command_encoder.set_fragment_buffer(0, Some(fragment_argument_buffer), 0); + } + + if !have_vertex_uniforms && !have_fragment_uniforms { + return; + } + + let (mut uniform_buffer_data, mut uniform_buffer_ranges) = (vec![], vec![]); + for &(_, uniform_data) in render_state.uniforms.iter() { + let start_index = uniform_buffer_data.len(); + match uniform_data { + UniformData::Int(value) => { + uniform_buffer_data.write_i32::(value).unwrap() + } + UniformData::Mat4(matrix) => { + for column in &matrix { + uniform_buffer_data.write_f32::(column.x()).unwrap(); + uniform_buffer_data.write_f32::(column.y()).unwrap(); + uniform_buffer_data.write_f32::(column.z()).unwrap(); + uniform_buffer_data.write_f32::(column.w()).unwrap(); + } + } + UniformData::Vec2(vector) => { + uniform_buffer_data.write_f32::(vector.x()).unwrap(); + uniform_buffer_data.write_f32::(vector.y()).unwrap(); + } + UniformData::Vec4(vector) => { + uniform_buffer_data.write_f32::(vector.x()).unwrap(); + uniform_buffer_data.write_f32::(vector.y()).unwrap(); + uniform_buffer_data.write_f32::(vector.z()).unwrap(); + uniform_buffer_data.write_f32::(vector.w()).unwrap(); + } + UniformData::TextureUnit(_) => {} + } + let end_index = uniform_buffer_data.len(); + uniform_buffer_ranges.push(start_index..end_index); + } + + let buffer_options = MTLResourceOptions::CPUCacheModeWriteCombined | + MTLResourceOptions::StorageModeManaged; + let data_buffer = self.device + .new_buffer_with_data(uniform_buffer_data.as_ptr() as *const _, + uniform_buffer_data.len() as u64, + buffer_options); + + for (&(uniform, ref uniform_data), buffer_range) in + render_state.uniforms.iter().zip(uniform_buffer_ranges.iter()) { + self.populate_uniform_indices_if_necessary(uniform, &render_state.program); + let indices = uniform.indices.borrow_mut(); + let indices = indices.as_ref().unwrap(); + if let Some(vertex_index) = indices.vertex { + if let ShaderUniforms::Uniforms { + encoder: ref argument_encoder, + .. + } = *vertex_uniforms { + self.set_uniform(vertex_index, + argument_encoder, + uniform_data, + &data_buffer, + buffer_range.start as u64, + render_command_encoder, + render_state); + } + } + if let Some(fragment_index) = indices.fragment { + if let ShaderUniforms::Uniforms { + encoder: ref argument_encoder, + .. + } = *fragment_uniforms { + self.set_uniform(fragment_index, + argument_encoder, + uniform_data, + &data_buffer, + buffer_range.start as u64, + render_command_encoder, + render_state); + } + } + } + + render_command_encoder.use_resource(&data_buffer, MTLResourceUsage::Read); + + if let Some(vertex_argument_buffer) = vertex_argument_buffer { + let range = NSRange::new(0, vertex_argument_buffer.length()); + vertex_argument_buffer.did_modify_range(range); + } + if let Some(fragment_argument_buffer) = fragment_argument_buffer { + let range = NSRange::new(0, fragment_argument_buffer.length()); + fragment_argument_buffer.did_modify_range(range); + } + } + + fn set_uniform(&self, + argument_index: MetalUniformIndex, + argument_encoder: &ArgumentEncoder, + uniform_data: &UniformData, + buffer: &Buffer, + buffer_offset: u64, + render_command_encoder: &RenderCommandEncoderRef, + render_state: &RenderState) { + match *uniform_data { + UniformData::TextureUnit(unit) => { + let texture = render_state.textures[unit as usize]; + argument_encoder.set_texture(&texture.texture, argument_index.main); + let mut resource_usage = MTLResourceUsage::Read; + if let Some(sampler_index) = argument_index.sampler { + argument_encoder.set_sampler_state(&self.sampler, sampler_index); + resource_usage |= MTLResourceUsage::Sample; + } + render_command_encoder.use_resource(&texture.texture, resource_usage); + } + _ => argument_encoder.set_buffer(buffer, buffer_offset, argument_index.main), + } + } + + fn prepare_pipeline_color_attachment_for_render( + &self, + pipeline_color_attachment: &RenderPipelineColorAttachmentDescriptorRef, + render_state: &RenderState) { + let pixel_format = self.render_target_color_texture(&render_state.target).pixel_format(); + pipeline_color_attachment.set_pixel_format(pixel_format); + + let blending_enabled = render_state.options.blend != BlendState::Off; + pipeline_color_attachment.set_blending_enabled(blending_enabled); + match render_state.options.blend { + BlendState::Off => {} + BlendState::RGBOneAlphaOne => { + pipeline_color_attachment.set_source_rgb_blend_factor(MTLBlendFactor::One); + pipeline_color_attachment.set_destination_rgb_blend_factor(MTLBlendFactor::One); + pipeline_color_attachment.set_source_alpha_blend_factor(MTLBlendFactor::One); + pipeline_color_attachment.set_destination_alpha_blend_factor(MTLBlendFactor::One); + } + BlendState::RGBOneAlphaOneMinusSrcAlpha => { + pipeline_color_attachment.set_source_rgb_blend_factor(MTLBlendFactor::One); + pipeline_color_attachment.set_destination_rgb_blend_factor( + MTLBlendFactor::OneMinusSourceAlpha); + pipeline_color_attachment.set_source_alpha_blend_factor(MTLBlendFactor::One); + pipeline_color_attachment.set_destination_alpha_blend_factor(MTLBlendFactor::One); + } + BlendState::RGBSrcAlphaAlphaOneMinusSrcAlpha => { + pipeline_color_attachment.set_source_rgb_blend_factor(MTLBlendFactor::SourceAlpha); + pipeline_color_attachment.set_destination_rgb_blend_factor( + MTLBlendFactor::OneMinusSourceAlpha); + pipeline_color_attachment.set_source_alpha_blend_factor(MTLBlendFactor::One); + pipeline_color_attachment.set_destination_alpha_blend_factor(MTLBlendFactor::One); + } + } + + if render_state.options.color_mask { + pipeline_color_attachment.set_write_mask(MTLColorWriteMask::all()); + } else { + pipeline_color_attachment.set_write_mask(MTLColorWriteMask::empty()); + } + } + + fn create_render_pass_descriptor(&self, render_state: &RenderState) + -> RenderPassDescriptor { + let render_pass_descriptor = RenderPassDescriptor::new().retain(); + let color_attachment = render_pass_descriptor.color_attachments().object_at(0).unwrap(); + color_attachment.set_texture(Some(&self.render_target_color_texture(render_state.target))); + + match render_state.options.clear_ops.color { + Some(color) => { + let color = MTLClearColor::new(color.r() as f64, + color.g() as f64, + color.b() as f64, + color.a() as f64); + color_attachment.set_clear_color(color); + color_attachment.set_load_action(MTLLoadAction::Clear); + } + None => color_attachment.set_load_action(MTLLoadAction::Load), + } + color_attachment.set_store_action(MTLStoreAction::Store); + + let depth_stencil_texture = self.render_target_depth_texture(render_state.target); + if let Some(depth_stencil_texture) = depth_stencil_texture { + let depth_attachment = render_pass_descriptor.depth_attachment().unwrap(); + let stencil_attachment = render_pass_descriptor.stencil_attachment().unwrap(); + depth_attachment.set_texture(Some(&depth_stencil_texture)); + stencil_attachment.set_texture(Some(&depth_stencil_texture)); + + match render_state.options.clear_ops.depth { + Some(depth) => { + depth_attachment.set_clear_depth(depth as f64); + depth_attachment.set_load_action(MTLLoadAction::Clear); + } + None => depth_attachment.set_load_action(MTLLoadAction::Load), + } + depth_attachment.set_store_action(MTLStoreAction::Store); + + match render_state.options.clear_ops.stencil { + Some(value) => { + stencil_attachment.set_clear_stencil(value as u32); + stencil_attachment.set_load_action(MTLLoadAction::Clear); + } + None => stencil_attachment.set_load_action(MTLLoadAction::Load), + } + stencil_attachment.set_store_action(MTLStoreAction::Store); + } + + render_pass_descriptor + } + + fn set_depth_stencil_state(&self, + encoder: &RenderCommandEncoderRef, + render_state: &RenderState) { + let depth_stencil_descriptor = DepthStencilDescriptor::new(); + + match render_state.options.depth { + Some(depth_state) => { + let compare_function = depth_state.func.to_metal_compare_function(); + depth_stencil_descriptor.set_depth_compare_function(compare_function); + depth_stencil_descriptor.set_depth_write_enabled(depth_state.write); + } + None => { + depth_stencil_descriptor.set_depth_compare_function(MTLCompareFunction::Always); + depth_stencil_descriptor.set_depth_write_enabled(false); + } + } + + match render_state.options.stencil { + Some(stencil_state) => { + let stencil_descriptor = StencilDescriptor::new(); + let compare_function = stencil_state.func.to_metal_compare_function(); + let (pass_operation, write_mask) = if stencil_state.write { + (MTLStencilOperation::Replace, stencil_state.mask) + } else { + (MTLStencilOperation::Keep, 0) + }; + stencil_descriptor.set_stencil_compare_function(compare_function); + stencil_descriptor.set_stencil_failure_operation(MTLStencilOperation::Keep); + stencil_descriptor.set_depth_failure_operation(MTLStencilOperation::Keep); + stencil_descriptor.set_depth_stencil_pass_operation(pass_operation); + stencil_descriptor.set_write_mask(write_mask); + depth_stencil_descriptor.set_front_face_stencil(Some(&stencil_descriptor)); + depth_stencil_descriptor.set_back_face_stencil(Some(&stencil_descriptor)); + encoder.set_stencil_reference_value(stencil_state.reference); + } + None => { + depth_stencil_descriptor.set_front_face_stencil(None); + depth_stencil_descriptor.set_back_face_stencil(None); + } + } + + let depth_stencil_state = self.device.new_depth_stencil_state(&depth_stencil_descriptor); + encoder.set_depth_stencil_state(&depth_stencil_state); + } + + fn texture_format(&self, texture: &Texture) -> Option { + match texture.pixel_format() { + MTLPixelFormat::R8Unorm => Some(TextureFormat::R8), + MTLPixelFormat::R16Float => Some(TextureFormat::R16F), + MTLPixelFormat::RGBA8Unorm => Some(TextureFormat::RGBA8), + _ => None, + } + } + + fn set_viewport(&self, encoder: &RenderCommandEncoderRef, viewport: &RectI) { + encoder.set_viewport(MTLViewport { + originX: viewport.origin().x() as f64, + originY: viewport.origin().y() as f64, + width: viewport.size().x() as f64, + height: viewport.size().y() as f64, + znear: 0.0, + zfar: 1.0, + }) + } + + fn synchronize_texture(&self, texture: &Texture) { + { + let command_buffers = self.command_buffers.borrow(); + let encoder = command_buffers.last().unwrap().new_blit_command_encoder(); + encoder.synchronize_resource(&texture); + encoder.end_encoding(); + } + + self.end_commands(); + self.begin_commands(); + } +} + +trait DeviceExtra { + fn create_depth_stencil_texture(&self, size: Vector2I) -> Texture; +} + +impl DeviceExtra for metal::Device { + fn create_depth_stencil_texture(&self, size: Vector2I) -> Texture { + let descriptor = TextureDescriptor::new(); + descriptor.set_texture_type(MTLTextureType::D2); + descriptor.set_pixel_format(MTLPixelFormat::Depth32Float_Stencil8); + descriptor.set_width(size.x() as u64); + descriptor.set_height(size.y() as u64); + descriptor.set_storage_mode(MTLStorageMode::Private); + descriptor.set_usage(MTLTextureUsage::Unknown); + self.new_texture(&descriptor) + } +} + +// Conversion helpers + +trait DepthFuncExt { + fn to_metal_compare_function(self) -> MTLCompareFunction; +} + +impl DepthFuncExt for DepthFunc { + fn to_metal_compare_function(self) -> MTLCompareFunction { + match self { + DepthFunc::Less => MTLCompareFunction::Less, + DepthFunc::Always => MTLCompareFunction::Always, + } + } +} + +trait PrimitiveExt { + fn to_metal_primitive(self) -> MTLPrimitiveType; +} + +impl PrimitiveExt for Primitive { + fn to_metal_primitive(self) -> MTLPrimitiveType { + match self { + Primitive::Triangles => MTLPrimitiveType::Triangle, + Primitive::Lines => MTLPrimitiveType::Line, + } + } +} + +trait StencilFuncExt { + fn to_metal_compare_function(self) -> MTLCompareFunction; +} + +impl StencilFuncExt for StencilFunc { + fn to_metal_compare_function(self) -> MTLCompareFunction { + match self { + StencilFunc::Always => MTLCompareFunction::Always, + StencilFunc::Equal => MTLCompareFunction::Equal, + } + } +} + +trait UniformDataExt { + fn as_bytes(&self) -> Option<&[u8]>; +} + +impl UniformDataExt for UniformData { + fn as_bytes(&self) -> Option<&[u8]> { + unsafe { + match *self { + UniformData::TextureUnit(_) => None, + UniformData::Int(ref data) => { + Some(slice::from_raw_parts(data as *const i32 as *const u8, 4 * 1)) + } + UniformData::Mat4(ref data) => { + Some(slice::from_raw_parts(&data[0] as *const F32x4 as *const u8, 4 * 16)) + } + UniformData::Vec2(ref data) => { + Some(slice::from_raw_parts(data as *const F32x4 as *const u8, 4 * 2)) + } + UniformData::Vec4(ref data) => { + Some(slice::from_raw_parts(data as *const F32x4 as *const u8, 4 * 4)) + } + } + } + } +} + +// Extra structs missing from `metal-rs` + +bitflags! { + struct MTLPipelineOption: NSUInteger { + const ArgumentInfo = 1 << 0; + const BufferTypeInfo = 1 << 1; + } +} + +// Extra objects missing from `metal-rs` + +struct ArgumentArray(*mut Object); + +impl Drop for ArgumentArray { + fn drop(&mut self) { + unsafe { msg_send![self.0, release] } + } +} + +impl ArgumentArray { + unsafe fn from_ptr(object: *mut Object) -> ArgumentArray { + ArgumentArray(msg_send![object, retain]) + } + + fn len(&self) -> u64 { + unsafe { msg_send![self.0, count] } + } + + fn object_at(&self, index: u64) -> Argument { + unsafe { + let argument: *mut MTLArgument = msg_send![self.0, objectAtIndex:index]; + Argument::from_ptr(msg_send![argument, retain]) + } + } +} + +struct SharedEvent(*mut Object); + +impl Drop for SharedEvent { + fn drop(&mut self) { + unsafe { msg_send![self.0, release] } + } +} + +impl SharedEvent { + fn notify_listener_at_value(&self, + listener: &SharedEventListener, + value: u64, + block: RcBlock<(*mut Object, u64), ()>) { + unsafe { + // If the block doesn't have a signature, this segfaults. + let block = &*block as + *const Block<(*mut Object, u64), ()> as + *mut Block<(*mut Object, u64), ()> as + *mut BlockBase<(*mut Object, u64), ()>; + (*block).flags |= BLOCK_HAS_SIGNATURE | BLOCK_HAS_COPY_DISPOSE; + (*block).extra = &BLOCK_EXTRA; + msg_send![self.0, notifyListener:listener.0 atValue:value block:block]; + mem::forget(block); + } + + extern "C" fn dtor(_: *mut BlockBase<(*mut Object, u64), ()>) {} + + static mut SIGNATURE: &[u8] = b"v16@?0Q8\0"; + static mut SIGNATURE_PTR: *const i8 = unsafe { &SIGNATURE[0] as *const u8 as *const i8 }; + static mut BLOCK_EXTRA: BlockExtra<(*mut Object, u64), ()> = BlockExtra { + unknown0: 0 as *mut i32, + unknown1: 0 as *mut i32, + unknown2: 0 as *mut i32, + dtor: dtor, + signature: unsafe { &SIGNATURE_PTR }, + }; + } +} + +struct SharedEventListener(*mut Object); + +impl Drop for SharedEventListener { + fn drop(&mut self) { + unsafe { msg_send![self.0, release] } + } +} + +impl SharedEventListener { + fn new() -> SharedEventListener { + unsafe { + let listener: *mut Object = msg_send![class!(MTLSharedEventListener), alloc]; + SharedEventListener(msg_send![listener, init]) + } + } +} + +struct VertexAttributeArray(*mut Object); + +impl Drop for VertexAttributeArray { + fn drop(&mut self) { + unsafe { msg_send![self.0, release] } + } +} + +impl VertexAttributeArray { + unsafe fn from_ptr(object: *mut Object) -> VertexAttributeArray { + VertexAttributeArray(msg_send![object, retain]) + } + + fn len(&self) -> u64 { + unsafe { msg_send![self.0, count] } + } + + fn object_at(&self, index: u64) -> &VertexAttributeRef { + unsafe { VertexAttributeRef::from_ptr(msg_send![self.0, objectAtIndex:index]) } + } +} + +// Extra methods missing from `metal-rs` + +trait CoreAnimationLayerExt { + fn device(&self) -> metal::Device; +} + +impl CoreAnimationLayerExt for CoreAnimationLayer { + fn device(&self) -> metal::Device { + unsafe { + let device: *mut MTLDevice = msg_send![self.as_ptr(), device]; + metal::Device::from_ptr(msg_send![device, retain]) + } + } +} + +trait CommandBufferExt { + fn encode_signal_event(&self, event: &SharedEvent, value: u64); +} + +impl CommandBufferExt for CommandBuffer { + fn encode_signal_event(&self, event: &SharedEvent, value: u64) { + unsafe { + msg_send![self.as_ptr(), encodeSignalEvent:event.0 value:value] + } + } +} + +trait DeviceExt { + // `new_render_pipeline_state_with_reflection()` in `metal-rs` doesn't correctly initialize the + // `reflection` argument. This is a better definition. + fn real_new_render_pipeline_state_with_reflection(&self, + descriptor: &RenderPipelineDescriptor, + options: MTLPipelineOption) + -> (RenderPipelineState, + RenderPipelineReflection); + fn new_shared_event(&self) -> SharedEvent; +} + +impl DeviceExt for metal::Device { + fn real_new_render_pipeline_state_with_reflection(&self, + descriptor: &RenderPipelineDescriptor, + options: MTLPipelineOption) + -> (RenderPipelineState, + RenderPipelineReflection) { + unsafe { + let mut reflection_ptr: *mut MTLRenderPipelineReflection = ptr::null_mut(); + let mut error_ptr: *mut Object = ptr::null_mut(); + let render_pipeline_state_ptr: *mut MTLRenderPipelineState = + msg_send![self.as_ptr(), + newRenderPipelineStateWithDescriptor:descriptor.as_ptr() + options:options + reflection:&mut reflection_ptr + error:&mut error_ptr]; + if !error_ptr.is_null() { + let description: CFStringRef = msg_send![error_ptr, description]; + panic!("Render pipeline state construction failed: {}", + CFString::wrap_under_get_rule(description).to_string()); + } + assert!(!render_pipeline_state_ptr.is_null()); + assert!(!reflection_ptr.is_null()); + (RenderPipelineState::from_ptr(render_pipeline_state_ptr), + RenderPipelineReflection::from_ptr(msg_send![reflection_ptr, retain])) + } + } + + fn new_shared_event(&self) -> SharedEvent { + unsafe { SharedEvent(msg_send![self.as_ptr(), newSharedEvent]) } + } +} + +trait FunctionExt { + // `vertex_attributes()` in `metal-rs` segfaults! This is a better definition. + fn real_vertex_attributes(&self) -> VertexAttributeArray; + fn new_argument_encoder_with_reflection(&self, buffer_index: u64) + -> (ArgumentEncoder, Argument); +} + +impl FunctionExt for Function { + fn real_vertex_attributes(&self) -> VertexAttributeArray { + unsafe { + VertexAttributeArray::from_ptr(msg_send![(*self).as_ptr(), vertexAttributes]) + } + } + + fn new_argument_encoder_with_reflection(&self, buffer_index: u64) + -> (ArgumentEncoder, Argument) { + unsafe { + let mut reflection = ptr::null_mut(); + let encoder: *mut MTLArgumentEncoder = + msg_send![self.as_ptr(), newArgumentEncoderWithBufferIndex:buffer_index + reflection:&mut reflection]; + (ArgumentEncoder::from_ptr(encoder), Argument::from_ptr(reflection)) + } + } +} + +trait RenderPipelineReflectionExt { + // `vertex_arguments()` in `metal-rs` segfaults! This is a better definition. + fn real_vertex_arguments(&self) -> ArgumentArray; + // `fragment_arguments()` in `metal-rs` segfaults! This is a better definition. + fn real_fragment_arguments(&self) -> ArgumentArray; +} + +impl RenderPipelineReflectionExt for RenderPipelineReflectionRef { + fn real_vertex_arguments(&self) -> ArgumentArray { + unsafe { ArgumentArray::from_ptr(msg_send![self.as_ptr(), vertexArguments]) } + } + + fn real_fragment_arguments(&self) -> ArgumentArray { + unsafe { ArgumentArray::from_ptr(msg_send![self.as_ptr(), fragmentArguments]) } + } +} + +trait StructMemberExt { + fn argument_index(&self) -> u64; +} + +impl StructMemberExt for StructMemberRef { + fn argument_index(&self) -> u64 { + unsafe { msg_send![self.as_ptr(), argumentIndex] } + } +} + +// Memory management helpers + +trait Retain { + type Owned; + fn retain(&self) -> Self::Owned; +} + +impl Retain for CommandBufferRef { + type Owned = CommandBuffer; + fn retain(&self) -> CommandBuffer { + unsafe { CommandBuffer::from_ptr(msg_send![self.as_ptr(), retain]) } + } +} + +impl Retain for CoreAnimationDrawableRef { + type Owned = CoreAnimationDrawable; + fn retain(&self) -> CoreAnimationDrawable { + unsafe { CoreAnimationDrawable::from_ptr(msg_send![self.as_ptr(), retain]) } + } +} + +impl Retain for CoreAnimationLayerRef { + type Owned = CoreAnimationLayer; + fn retain(&self) -> CoreAnimationLayer { + unsafe { CoreAnimationLayer::from_ptr(msg_send![self.as_ptr(), retain]) } + } +} + +impl Retain for RenderCommandEncoderRef { + type Owned = RenderCommandEncoder; + fn retain(&self) -> RenderCommandEncoder { + unsafe { RenderCommandEncoder::from_ptr(msg_send![self.as_ptr(), retain]) } + } +} + +impl Retain for RenderPassDescriptorRef { + type Owned = RenderPassDescriptor; + fn retain(&self) -> RenderPassDescriptor { + unsafe { RenderPassDescriptor::from_ptr(msg_send![self.as_ptr(), retain]) } + } +} + +impl Retain for StructTypeRef { + type Owned = StructType; + fn retain(&self) -> StructType { + unsafe { StructType::from_ptr(msg_send![self.as_ptr(), retain]) } + } +} + +impl Retain for TextureRef { + type Owned = Texture; + fn retain(&self) -> Texture { + unsafe { Texture::from_ptr(msg_send![self.as_ptr(), retain]) } + } +} + +impl Retain for VertexAttributeRef { + type Owned = VertexAttribute; + fn retain(&self) -> VertexAttribute { + unsafe { VertexAttribute::from_ptr(msg_send![self.as_ptr(), retain]) } + } +} + +impl Retain for VertexDescriptorRef { + type Owned = VertexDescriptor; + fn retain(&self) -> VertexDescriptor { + unsafe { VertexDescriptor::from_ptr(msg_send![self.as_ptr(), retain]) } + } +} + +// Extra block stuff not supported by `block` + +const BLOCK_HAS_COPY_DISPOSE: i32 = 0x02000000; +const BLOCK_HAS_SIGNATURE: i32 = 0x40000000; + +#[repr(C)] +struct BlockBase { + isa: *const Class, // 0x00 + flags: i32, // 0x08 + _reserved: i32, // 0x0c + invoke: unsafe extern fn(*mut Block, ...) -> R, // 0x10 + extra: *const BlockExtra, // 0x18 +} + +type BlockExtraDtor = extern "C" fn(*mut BlockBase); + +#[repr(C)] +struct BlockExtra { + unknown0: *mut i32, // 0x00 + unknown1: *mut i32, // 0x08 + unknown2: *mut i32, // 0x10 + dtor: BlockExtraDtor, // 0x18 + signature: *const *const i8, // 0x20 +} diff --git a/renderer/Cargo.toml b/renderer/Cargo.toml index 0a575b30..106c0bab 100644 --- a/renderer/Cargo.toml +++ b/renderer/Cargo.toml @@ -5,6 +5,7 @@ edition = "2018" authors = ["Patrick Walton "] [dependencies] +bitflags = "1.0" byteorder = "1.2" fixedbitset = "0.1" hashbrown = "0.1" diff --git a/renderer/src/builder.rs b/renderer/src/builder.rs index 73562f8d..ff054432 100644 --- a/renderer/src/builder.rs +++ b/renderer/src/builder.rs @@ -12,7 +12,7 @@ use crate::concurrent::executor::Executor; use crate::gpu_data::{AlphaTileBatchPrimitive, BuiltObject, FillBatchPrimitive, RenderCommand}; -use crate::options::{PreparedRenderOptions, RenderCommandListener}; +use crate::options::{PreparedBuildOptions, RenderCommandListener}; use crate::scene::Scene; use crate::tile_map::DenseTileMap; use crate::tiles::{self, TILE_HEIGHT, TILE_WIDTH, Tiler}; @@ -28,7 +28,7 @@ use std::u16; pub(crate) struct SceneBuilder<'a> { scene: &'a Scene, - built_options: &'a PreparedRenderOptions, + built_options: &'a PreparedBuildOptions, pub(crate) next_alpha_tile_index: AtomicUsize, pub(crate) z_buffer: ZBuffer, @@ -38,7 +38,7 @@ pub(crate) struct SceneBuilder<'a> { impl<'a> SceneBuilder<'a> { pub(crate) fn new( scene: &'a Scene, - built_options: &'a PreparedRenderOptions, + built_options: &'a PreparedBuildOptions, listener: Box, ) -> SceneBuilder<'a> { let effective_view_box = scene.effective_view_box(built_options); @@ -76,7 +76,7 @@ impl<'a> SceneBuilder<'a> { &self, path_index: usize, view_box: RectF, - built_options: &PreparedRenderOptions, + built_options: &PreparedBuildOptions, scene: &Scene, ) -> Vec { let path_object = &scene.paths[path_index]; diff --git a/renderer/src/concurrent/scene_proxy.rs b/renderer/src/concurrent/scene_proxy.rs index 09c0e38d..a85d3e89 100644 --- a/renderer/src/concurrent/scene_proxy.rs +++ b/renderer/src/concurrent/scene_proxy.rs @@ -22,7 +22,7 @@ use crate::concurrent::executor::Executor; use crate::gpu::renderer::Renderer; use crate::gpu_data::RenderCommand; -use crate::options::{RenderCommandListener, RenderOptions}; +use crate::options::{BuildOptions, RenderCommandListener}; use crate::scene::Scene; use pathfinder_geometry::basic::rect::RectF; use pathfinder_gpu::Device; @@ -59,15 +59,15 @@ impl SceneProxy { #[inline] pub fn build_with_listener(&self, - options: RenderOptions, + options: BuildOptions, listener: Box) { self.sender.send(MainToWorkerMsg::Build(options, listener)).unwrap(); } #[inline] - pub fn build_with_stream(&self, options: RenderOptions) -> RenderCommandStream { + pub fn build_with_stream(&self, options: BuildOptions) -> RenderCommandStream { let (sender, receiver) = mpsc::sync_channel(MAX_MESSAGES_IN_FLIGHT); - let listener = Box::new(move |command| sender.send(command).unwrap()); + let listener = Box::new(move |command| drop(sender.send(command))); self.build_with_listener(options, listener); RenderCommandStream::new(receiver) } @@ -81,11 +81,11 @@ impl SceneProxy { /// renderer.render_command(&command) /// } #[inline] - pub fn build_and_render(&self, renderer: &mut Renderer, options: RenderOptions) + pub fn build_and_render(&self, renderer: &mut Renderer, build_options: BuildOptions) where D: Device { renderer.begin_scene(); - for command in self.build_with_stream(options) { - renderer.render_command(&command) + for command in self.build_with_stream(build_options) { + renderer.render_command(&command); } renderer.end_scene(); } @@ -118,7 +118,7 @@ fn scene_thread(mut scene: Scene, enum MainToWorkerMsg { ReplaceScene(Scene), SetViewBox(RectF), - Build(RenderOptions, Box), + Build(BuildOptions, Box), GetSVG(Sender>), } diff --git a/renderer/src/gpu/mod.rs b/renderer/src/gpu/mod.rs index cc28fc80..a5e818e0 100644 --- a/renderer/src/gpu/mod.rs +++ b/renderer/src/gpu/mod.rs @@ -11,4 +11,5 @@ //! The GPU renderer for Pathfinder 3. pub mod debug; +pub mod options; pub mod renderer; diff --git a/renderer/src/gpu/options.rs b/renderer/src/gpu/options.rs new file mode 100644 index 00000000..04c9af59 --- /dev/null +++ b/renderer/src/gpu/options.rs @@ -0,0 +1,60 @@ +// pathfinder/renderer/src/gpu/options.rs +// +// Copyright © 2019 The Pathfinder Project Developers. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use pathfinder_geometry::basic::rect::RectI; +use pathfinder_geometry::basic::vector::Vector2I; +use pathfinder_geometry::color::ColorF; +use pathfinder_gpu::Device; + +/// Options that influence rendering. +#[derive(Default)] +pub struct RendererOptions { + pub background_color: Option, +} + +#[derive(Clone)] +pub enum DestFramebuffer +where + D: Device, +{ + Default { + viewport: RectI, + window_size: Vector2I, + }, + Other(D::Framebuffer), +} + +impl Default for DestFramebuffer where D: Device { + #[inline] + fn default() -> DestFramebuffer { + DestFramebuffer::Default { viewport: RectI::default(), window_size: Vector2I::default() } + } +} + +impl DestFramebuffer +where + D: Device, +{ + #[inline] + pub fn full_window(window_size: Vector2I) -> DestFramebuffer { + let viewport = RectI::new(Vector2I::default(), window_size); + DestFramebuffer::Default { viewport, window_size } + } + + #[inline] + pub fn window_size(&self, device: &D) -> Vector2I { + match *self { + DestFramebuffer::Default { window_size, .. } => window_size, + DestFramebuffer::Other(ref framebuffer) => { + device.texture_size(device.framebuffer_texture(framebuffer)) + } + } + } +} diff --git a/renderer/src/gpu/renderer.rs b/renderer/src/gpu/renderer.rs index 80bdc477..e616615e 100644 --- a/renderer/src/gpu/renderer.rs +++ b/renderer/src/gpu/renderer.rs @@ -9,6 +9,7 @@ // except according to those terms. use crate::gpu::debug::DebugUIPresenter; +use crate::gpu::options::{DestFramebuffer, RendererOptions}; use crate::gpu_data::{AlphaTileBatchPrimitive, FillBatchPrimitive, PaintData}; use crate::gpu_data::{RenderCommand, SolidTileBatchPrimitive}; use crate::post::DefringingKernel; @@ -18,10 +19,10 @@ use pathfinder_geometry::basic::rect::RectI; use pathfinder_geometry::basic::transform3d::Transform3DF; use pathfinder_geometry::color::ColorF; use pathfinder_gpu::resources::ResourceLoader; -use pathfinder_gpu::{BlendState, BufferData, BufferTarget, BufferUploadMode, ClearParams}; -use pathfinder_gpu::{DepthFunc, DepthState, Device, Primitive, RenderState, StencilFunc}; -use pathfinder_gpu::{StencilState, TextureFormat, UniformData, VertexAttrClass}; -use pathfinder_gpu::{VertexAttrDescriptor, VertexAttrType}; +use pathfinder_gpu::{BlendState, BufferData, BufferTarget, BufferUploadMode, ClearOps}; +use pathfinder_gpu::{DepthFunc, DepthState, Device, Primitive, RenderOptions, RenderState}; +use pathfinder_gpu::{RenderTarget, StencilFunc, StencilState, TextureFormat, UniformData}; +use pathfinder_gpu::{VertexAttrClass, VertexAttrDescriptor, VertexAttrType}; use pathfinder_simd::default::{F32x4, I32x4}; use std::cmp; use std::collections::VecDeque; @@ -30,7 +31,7 @@ use std::ops::{Add, Div}; use std::time::Duration; use std::u32; -static QUAD_VERTEX_POSITIONS: [u8; 8] = [0, 0, 1, 0, 1, 1, 0, 1]; +static QUAD_VERTEX_POSITIONS: [u16; 8] = [0, 0, 1, 0, 1, 1, 0, 1]; static QUAD_VERTEX_INDICES: [u32; 6] = [0, 1, 3, 1, 2, 3]; // FIXME(pcwalton): Shrink this again! @@ -39,7 +40,7 @@ const MASK_FRAMEBUFFER_HEIGHT: i32 = TILE_HEIGHT as i32 * 256; // TODO(pcwalton): Replace with `mem::size_of` calls? const FILL_INSTANCE_SIZE: usize = 8; -const SOLID_TILE_INSTANCE_SIZE: usize = 10; +const SOLID_TILE_INSTANCE_SIZE: usize = 12; const MASK_TILE_INSTANCE_SIZE: usize = 12; const MAX_FILLS_PER_BATCH: usize = 0x4000; @@ -53,6 +54,7 @@ where // Core data dest_framebuffer: DestFramebuffer, + options: RendererOptions, fill_program: FillProgram, solid_multicolor_tile_program: SolidTileMulticolorProgram, alpha_multicolor_tile_program: AlphaTileMulticolorProgram, @@ -84,7 +86,7 @@ where reprojection_vertex_array: ReprojectionVertexArray, // Rendering state - mask_framebuffer_cleared: bool, + framebuffer_flags: FramebufferFlags, buffered_fills: Vec, // Debug @@ -103,11 +105,11 @@ impl Renderer where D: Device, { - pub fn new( - device: D, - resources: &dyn ResourceLoader, - dest_framebuffer: DestFramebuffer, - ) -> Renderer { + pub fn new(device: D, + resources: &dyn ResourceLoader, + dest_framebuffer: DestFramebuffer, + options: RendererOptions) + -> Renderer { let fill_program = FillProgram::new(&device, resources); let solid_multicolor_tile_program = SolidTileMulticolorProgram::new(&device, resources); @@ -190,10 +192,11 @@ where let window_size = dest_framebuffer.window_size(&device); let debug_ui_presenter = DebugUIPresenter::new(&device, resources, window_size); - let renderer = Renderer { + Renderer { device, dest_framebuffer, + options, fill_program, solid_monochrome_tile_program, alpha_monochrome_tile_program, @@ -227,23 +230,18 @@ where free_timer_queries: vec![], debug_ui_presenter, - mask_framebuffer_cleared: false, + framebuffer_flags: FramebufferFlags::empty(), buffered_fills: vec![], render_mode: RenderMode::default(), use_depth: false, - }; - - // As a convenience, bind the destination framebuffer. - renderer.bind_dest_framebuffer(); - - renderer + } } pub fn begin_scene(&mut self) { + self.framebuffer_flags = FramebufferFlags::empty(); + self.device.begin_commands(); self.init_postprocessing_framebuffer(); - - self.mask_framebuffer_cleared = false; self.stats = RenderStats::default(); } @@ -258,8 +256,8 @@ where RenderCommand::AddPaintData(ref paint_data) => self.upload_paint_data(paint_data), RenderCommand::AddFills(ref fills) => self.add_fills(fills), RenderCommand::FlushFills => { - self.begin_composite_timer_query(); self.draw_buffered_fills(); + self.begin_composite_timer_query(); } RenderCommand::SolidTile(ref solid_tiles) => { let count = solid_tiles.len(); @@ -284,10 +282,11 @@ where self.end_composite_timer_query(); self.pending_timers.push_back(mem::replace(&mut self.current_timers, RenderTimers::new())); + + self.device.end_commands(); } pub fn draw_debug_ui(&self) { - self.bind_dest_framebuffer(); self.debug_ui_presenter.draw(&self.device); } @@ -297,19 +296,19 @@ where // Accumulate stage-0 time. let mut total_stage_0_time = Duration::new(0, 0); for timer_query in &timers.stage_0 { - if !self.device.timer_query_is_available(timer_query) { - return None; + match self.device.get_timer_query(timer_query) { + None => return None, + Some(stage_0_time) => total_stage_0_time += stage_0_time, } - total_stage_0_time += self.device.get_timer_query(timer_query); } // Get stage-1 time. let stage_1_time = { let stage_1_timer_query = timers.stage_1.as_ref().unwrap(); - if !self.device.timer_query_is_available(&stage_1_timer_query) { - return None; + match self.device.get_timer_query(stage_1_timer_query) { + None => return None, + Some(query) => query, } - self.device.get_timer_query(stage_1_timer_query) }; // Recycle all timer queries. @@ -333,6 +332,11 @@ where mem::replace(&mut self.dest_framebuffer, new_dest_framebuffer) } + #[inline] + pub fn set_options(&mut self, new_options: RendererOptions) { + self.options = new_options + } + #[inline] pub fn set_main_framebuffer_size(&mut self, new_framebuffer_size: Vector2I) { self.debug_ui_presenter.ui_presenter.set_framebuffer_size(new_framebuffer_size); @@ -396,24 +400,11 @@ where ); } - fn clear_mask_framebuffer(&mut self) { - self.device.bind_framebuffer(&self.mask_framebuffer); - - // TODO(pcwalton): Only clear the appropriate portion? - self.device.clear(&ClearParams { - color: Some(ColorF::transparent_black()), - ..ClearParams::default() - }); - } - fn add_fills(&mut self, mut fills: &[FillBatchPrimitive]) { if fills.is_empty() { return; } - let timer_query = self.allocate_timer_query(); - self.device.begin_timer_query(&timer_query); - self.stats.fill_count += fills.len(); while !fills.is_empty() { @@ -424,9 +415,6 @@ where self.draw_buffered_fills(); } } - - self.device.end_timer_query(&timer_query); - self.current_timers.stage_0.push(timer_query); } fn draw_buffered_fills(&mut self) { @@ -441,178 +429,184 @@ where BufferUploadMode::Dynamic, ); - if !self.mask_framebuffer_cleared { - self.clear_mask_framebuffer(); - self.mask_framebuffer_cleared = true; - } - - self.device.bind_framebuffer(&self.mask_framebuffer); - - self.device - .bind_vertex_array(&self.fill_vertex_array.vertex_array); - self.device.use_program(&self.fill_program.program); - self.device.set_uniform( - &self.fill_program.framebuffer_size_uniform, - UniformData::Vec2( - I32x4::new(MASK_FRAMEBUFFER_WIDTH, MASK_FRAMEBUFFER_HEIGHT, 0, 0).to_f32x4(), - ), - ); - self.device.set_uniform( - &self.fill_program.tile_size_uniform, - UniformData::Vec2(I32x4::new(TILE_WIDTH as i32, TILE_HEIGHT as i32, 0, 0).to_f32x4()), - ); - self.device.bind_texture(&self.area_lut_texture, 0); - self.device.set_uniform( - &self.fill_program.area_lut_uniform, - UniformData::TextureUnit(0), - ); - let render_state = RenderState { - blend: BlendState::RGBOneAlphaOne, - ..RenderState::default() + let mut clear_color = None; + if !self.framebuffer_flags.contains( + FramebufferFlags::MUST_PRESERVE_MASK_FRAMEBUFFER_CONTENTS) { + clear_color = Some(ColorF::default()); }; - debug_assert!(self.buffered_fills.len() <= u32::MAX as usize); - self.device.draw_elements_instanced( - Primitive::Triangles, - 6, - self.buffered_fills.len() as u32, - &render_state, - ); - self.buffered_fills.clear() + let timer_query = self.allocate_timer_query(); + self.device.begin_timer_query(&timer_query); + + debug_assert!(self.buffered_fills.len() <= u32::MAX as usize); + self.device.draw_elements_instanced(6, self.buffered_fills.len() as u32, &RenderState { + target: &RenderTarget::Framebuffer(&self.mask_framebuffer), + program: &self.fill_program.program, + vertex_array: &self.fill_vertex_array.vertex_array, + primitive: Primitive::Triangles, + textures: &[&self.area_lut_texture], + uniforms: &[ + (&self.fill_program.framebuffer_size_uniform, + UniformData::Vec2(I32x4::new(MASK_FRAMEBUFFER_WIDTH, + MASK_FRAMEBUFFER_HEIGHT, + 0, + 0).to_f32x4())), + (&self.fill_program.tile_size_uniform, + UniformData::Vec2(I32x4::new(TILE_WIDTH as i32, + TILE_HEIGHT as i32, + 0, + 0).to_f32x4())), + (&self.fill_program.area_lut_uniform, UniformData::TextureUnit(0)), + ], + viewport: self.mask_viewport(), + options: RenderOptions { + blend: BlendState::RGBOneAlphaOne, + clear_ops: ClearOps { color: clear_color, ..ClearOps::default() }, + ..RenderOptions::default() + }, + }); + + self.device.end_timer_query(&timer_query); + self.current_timers.stage_0.push(timer_query); + + self.framebuffer_flags.insert(FramebufferFlags::MUST_PRESERVE_MASK_FRAMEBUFFER_CONTENTS); + self.buffered_fills.clear(); } fn draw_alpha_tiles(&mut self, count: u32) { - self.bind_draw_framebuffer(); + let clear_color = self.clear_color_for_draw_operation(); let alpha_tile_vertex_array = self.alpha_tile_vertex_array(); let alpha_tile_program = self.alpha_tile_program(); - self.device - .bind_vertex_array(&alpha_tile_vertex_array.vertex_array); - self.device.use_program(&alpha_tile_program.program); - self.device.set_uniform( - &alpha_tile_program.framebuffer_size_uniform, - UniformData::Vec2(self.draw_viewport().size().to_f32().0), - ); - self.device.set_uniform( - &alpha_tile_program.tile_size_uniform, - UniformData::Vec2(I32x4::new(TILE_WIDTH as i32, TILE_HEIGHT as i32, 0, 0).to_f32x4()), - ); - self.device - .bind_texture(self.device.framebuffer_texture(&self.mask_framebuffer), 0); - self.device.set_uniform( - &alpha_tile_program.stencil_texture_uniform, - UniformData::TextureUnit(0), - ); - self.device.set_uniform( - &alpha_tile_program.stencil_texture_size_uniform, - UniformData::Vec2( - I32x4::new(MASK_FRAMEBUFFER_WIDTH, MASK_FRAMEBUFFER_HEIGHT, 0, 0).to_f32x4(), - ), - ); + let draw_viewport = self.draw_viewport(); + let mut textures = vec![self.device.framebuffer_texture(&self.mask_framebuffer)]; + let mut uniforms = vec![ + (&alpha_tile_program.framebuffer_size_uniform, + UniformData::Vec2(draw_viewport.size().to_f32().0)), + (&alpha_tile_program.tile_size_uniform, + UniformData::Vec2(I32x4::new(TILE_WIDTH as i32, + TILE_HEIGHT as i32, + 0, + 0).to_f32x4())), + (&alpha_tile_program.stencil_texture_uniform, UniformData::TextureUnit(0)), + (&alpha_tile_program.stencil_texture_size_uniform, + UniformData::Vec2(I32x4::new(MASK_FRAMEBUFFER_WIDTH, + MASK_FRAMEBUFFER_HEIGHT, + 0, + 0).to_f32x4())), + // FIXME(pcwalton): Fill this in properly! + (&alpha_tile_program.view_box_origin_uniform, UniformData::Vec2(F32x4::default())), + ]; match self.render_mode { RenderMode::Multicolor => { let paint_texture = self.paint_texture.as_ref().unwrap(); - self.device.bind_texture(paint_texture, 1); - self.device.set_uniform( - &self.alpha_multicolor_tile_program.paint_texture_uniform, - UniformData::TextureUnit(1), - ); - self.device.set_uniform( - &self.alpha_multicolor_tile_program.paint_texture_size_uniform, - UniformData::Vec2(self.device.texture_size(paint_texture).0.to_f32x4()) - ); + textures.push(paint_texture); + uniforms.push((&self.alpha_multicolor_tile_program.paint_texture_uniform, + UniformData::TextureUnit(1))); + uniforms.push((&self.alpha_multicolor_tile_program.paint_texture_size_uniform, + UniformData::Vec2(self.device + .texture_size(paint_texture) + .0 + .to_f32x4()))); } RenderMode::Monochrome { .. } if self.postprocessing_needed() => { - self.device.set_uniform( - &self.alpha_monochrome_tile_program.color_uniform, - UniformData::Vec4(F32x4::splat(1.0)), - ); + uniforms.push((&self.alpha_monochrome_tile_program.color_uniform, + UniformData::Vec4(F32x4::splat(1.0)))); } RenderMode::Monochrome { fg_color, .. } => { - self.device.set_uniform( - &self.alpha_monochrome_tile_program.color_uniform, - UniformData::Vec4(fg_color.0), - ); + uniforms.push((&self.alpha_monochrome_tile_program.color_uniform, + UniformData::Vec4(fg_color.0))); } } - // FIXME(pcwalton): Fill this in properly! - self.device.set_uniform( - &alpha_tile_program.view_box_origin_uniform, - UniformData::Vec2(F32x4::default()), - ); - let render_state = RenderState { - blend: BlendState::RGBSrcAlphaAlphaOneMinusSrcAlpha, - stencil: self.stencil_state(), - ..RenderState::default() - }; - self.device.draw_elements_instanced(Primitive::Triangles, 6, count, &render_state); + self.device.draw_elements_instanced(6, count, &RenderState { + target: &self.draw_render_target(), + program: &alpha_tile_program.program, + vertex_array: &alpha_tile_vertex_array.vertex_array, + primitive: Primitive::Triangles, + textures: &textures, + uniforms: &uniforms, + viewport: draw_viewport, + options: RenderOptions { + blend: BlendState::RGBSrcAlphaAlphaOneMinusSrcAlpha, + stencil: self.stencil_state(), + clear_ops: ClearOps { color: clear_color, ..ClearOps::default() }, + ..RenderOptions::default() + }, + }); + + self.preserve_draw_framebuffer(); } fn draw_solid_tiles(&mut self, count: u32) { - self.bind_draw_framebuffer(); + let clear_color = self.clear_color_for_draw_operation(); let solid_tile_vertex_array = self.solid_tile_vertex_array(); let solid_tile_program = self.solid_tile_program(); - self.device - .bind_vertex_array(&solid_tile_vertex_array.vertex_array); - self.device.use_program(&solid_tile_program.program); - self.device.set_uniform( - &solid_tile_program.framebuffer_size_uniform, - UniformData::Vec2(self.draw_viewport().size().0.to_f32x4()), - ); - self.device.set_uniform( - &solid_tile_program.tile_size_uniform, - UniformData::Vec2(I32x4::new(TILE_WIDTH as i32, TILE_HEIGHT as i32, 0, 0).to_f32x4()), - ); + let draw_viewport = self.draw_viewport(); + let mut textures = vec![]; + let mut uniforms = vec![ + (&solid_tile_program.framebuffer_size_uniform, + UniformData::Vec2(draw_viewport.size().0.to_f32x4())), + (&solid_tile_program.tile_size_uniform, + UniformData::Vec2(I32x4::new(TILE_WIDTH as i32, + TILE_HEIGHT as i32, + 0, + 0).to_f32x4())), + // FIXME(pcwalton): Fill this in properly! + (&solid_tile_program.view_box_origin_uniform, UniformData::Vec2(F32x4::default())), + ]; match self.render_mode { RenderMode::Multicolor => { let paint_texture = self.paint_texture.as_ref().unwrap(); - self.device.bind_texture(paint_texture, 0); - self.device.set_uniform( - &self - .solid_multicolor_tile_program - .paint_texture_uniform, - UniformData::TextureUnit(0), - ); - self.device.set_uniform( - &self - .solid_multicolor_tile_program - .paint_texture_size_uniform, - UniformData::Vec2(self.device.texture_size(paint_texture).0.to_f32x4()) - ); + textures.push(paint_texture); + uniforms.push((&self.solid_multicolor_tile_program.paint_texture_uniform, + UniformData::TextureUnit(0))); + uniforms.push((&self.solid_multicolor_tile_program.paint_texture_size_uniform, + UniformData::Vec2(self.device + .texture_size(paint_texture) + .0 + .to_f32x4()))); } RenderMode::Monochrome { .. } if self.postprocessing_needed() => { - self.device.set_uniform( - &self.solid_monochrome_tile_program.color_uniform, - UniformData::Vec4(F32x4::splat(1.0)), - ); + uniforms.push((&self.solid_monochrome_tile_program.color_uniform, + UniformData::Vec4(F32x4::splat(1.0)))); } RenderMode::Monochrome { fg_color, .. } => { - self.device.set_uniform( - &self.solid_monochrome_tile_program.color_uniform, - UniformData::Vec4(fg_color.0), - ); + uniforms.push((&self.solid_monochrome_tile_program.color_uniform, + UniformData::Vec4(fg_color.0))); } } - // FIXME(pcwalton): Fill this in properly! - self.device.set_uniform( - &solid_tile_program.view_box_origin_uniform, - UniformData::Vec2(F32x4::default()), - ); - let render_state = RenderState { - stencil: self.stencil_state(), - ..RenderState::default() - }; - self.device.draw_elements_instanced(Primitive::Triangles, 6, count, &render_state); + self.device.draw_elements_instanced(6, count, &RenderState { + target: &self.draw_render_target(), + program: &solid_tile_program.program, + vertex_array: &solid_tile_vertex_array.vertex_array, + primitive: Primitive::Triangles, + textures: &textures, + uniforms: &uniforms, + viewport: draw_viewport, + options: RenderOptions { + stencil: self.stencil_state(), + clear_ops: ClearOps { color: clear_color, ..ClearOps::default() }, + ..RenderOptions::default() + }, + }); + + self.preserve_draw_framebuffer(); } fn postprocess(&mut self) { + let mut clear_color = None; + if !self.framebuffer_flags + .contains(FramebufferFlags::MUST_PRESERVE_DEST_FRAMEBUFFER_CONTENTS) { + clear_color = self.options.background_color; + } + let (fg_color, bg_color, defringing_kernel, gamma_correction_enabled); match self.render_mode { RenderMode::Multicolor => return, @@ -629,62 +623,52 @@ where } } - self.bind_dest_framebuffer(); - - self.device - .bind_vertex_array(&self.postprocess_vertex_array.vertex_array); - self.device.use_program(&self.postprocess_program.program); - self.device.set_uniform( - &self.postprocess_program.framebuffer_size_uniform, - UniformData::Vec2(self.main_viewport().size().to_f32().0), - ); - match defringing_kernel { - Some(ref kernel) => { - self.device.set_uniform( - &self.postprocess_program.kernel_uniform, - UniformData::Vec4(F32x4::from_slice(&kernel.0)), - ); - } - None => { - self.device.set_uniform( - &self.postprocess_program.kernel_uniform, - UniformData::Vec4(F32x4::default()), - ); - } - } - let postprocess_source_framebuffer = self.postprocess_source_framebuffer.as_ref().unwrap(); let source_texture = self .device .framebuffer_texture(postprocess_source_framebuffer); let source_texture_size = self.device.texture_size(source_texture); - self.device.bind_texture(&source_texture, 0); - self.device.set_uniform( - &self.postprocess_program.source_uniform, - UniformData::TextureUnit(0), - ); - self.device.set_uniform( - &self.postprocess_program.source_size_uniform, - UniformData::Vec2(source_texture_size.0.to_f32x4()), - ); - self.device.bind_texture(&self.gamma_lut_texture, 1); - self.device.set_uniform( - &self.postprocess_program.gamma_lut_uniform, - UniformData::TextureUnit(1), - ); - self.device.set_uniform( - &self.postprocess_program.fg_color_uniform, - UniformData::Vec4(fg_color.0), - ); - self.device.set_uniform( - &self.postprocess_program.bg_color_uniform, - UniformData::Vec4(bg_color.0), - ); - self.device.set_uniform( - &self.postprocess_program.gamma_correction_enabled_uniform, - UniformData::Int(gamma_correction_enabled as i32), - ); - self.device.draw_arrays(Primitive::Triangles, 4, &RenderState::default()); + let main_viewport = self.main_viewport(); + + let mut uniforms = vec![ + (&self.postprocess_program.framebuffer_size_uniform, + UniformData::Vec2(main_viewport.size().to_f32().0)), + (&self.postprocess_program.source_uniform, UniformData::TextureUnit(0)), + (&self.postprocess_program.source_size_uniform, + UniformData::Vec2(source_texture_size.0.to_f32x4())), + (&self.postprocess_program.gamma_lut_uniform, UniformData::TextureUnit(1)), + (&self.postprocess_program.fg_color_uniform, UniformData::Vec4(fg_color.0)), + (&self.postprocess_program.bg_color_uniform, UniformData::Vec4(bg_color.0)), + (&self.postprocess_program.gamma_correction_enabled_uniform, + UniformData::Int(gamma_correction_enabled as i32)), + ]; + + match defringing_kernel { + Some(ref kernel) => { + uniforms.push((&self.postprocess_program.kernel_uniform, + UniformData::Vec4(F32x4::from_slice(&kernel.0)))); + } + None => { + uniforms.push((&self.postprocess_program.kernel_uniform, + UniformData::Vec4(F32x4::default()))); + } + } + + self.device.draw_arrays(4, &RenderState { + target: &self.dest_render_target(), + program: &self.postprocess_program.program, + vertex_array: &self.postprocess_vertex_array.vertex_array, + primitive: Primitive::Triangles, + textures: &[&source_texture, &self.gamma_lut_texture], + uniforms: &uniforms, + viewport: main_viewport, + options: RenderOptions { + clear_ops: ClearOps { color: clear_color, ..ClearOps::default() }, + ..RenderOptions::default() + }, + }); + + self.framebuffer_flags.insert(FramebufferFlags::MUST_PRESERVE_DEST_FRAMEBUFFER_CONTENTS); } fn solid_tile_program(&self) -> &SolidTileProgram { @@ -715,7 +699,7 @@ where } } - fn draw_stencil(&self, quad_positions: &[Vector4F]) { + fn draw_stencil(&mut self, quad_positions: &[Vector4F]) { self.device.allocate_buffer( &self.stencil_vertex_array.vertex_buffer, BufferData::Memory(quad_positions), @@ -736,19 +720,17 @@ where BufferUploadMode::Dynamic, ); - self.bind_draw_framebuffer(); - - self.device.bind_vertex_array(&self.stencil_vertex_array.vertex_array); - self.device.use_program(&self.stencil_program.program); - self.device.draw_elements( - Primitive::Triangles, - indices.len() as u32, - &RenderState { + self.device.draw_elements(indices.len() as u32, &RenderState { + target: &self.draw_render_target(), + program: &self.stencil_program.program, + vertex_array: &self.stencil_vertex_array.vertex_array, + primitive: Primitive::Triangles, + textures: &[], + uniforms: &[], + viewport: self.draw_viewport(), + options: RenderOptions { // FIXME(pcwalton): Should we really write to the depth buffer? - depth: Some(DepthState { - func: DepthFunc::Less, - write: true, - }), + depth: Some(DepthState { func: DepthFunc::Less, write: true }), stencil: Some(StencilState { func: StencilFunc::Always, reference: 1, @@ -756,63 +738,57 @@ where write: true, }), color_mask: false, - ..RenderState::default() + clear_ops: ClearOps { stencil: Some(0), ..ClearOps::default() }, + ..RenderOptions::default() }, - ) + }); } pub fn reproject_texture( - &self, + &mut self, texture: &D::Texture, old_transform: &Transform3DF, new_transform: &Transform3DF, ) { - self.bind_draw_framebuffer(); + let clear_color = self.clear_color_for_draw_operation(); - self.device.bind_vertex_array(&self.reprojection_vertex_array.vertex_array); - self.device.use_program(&self.reprojection_program.program); - self.device.set_uniform( - &self.reprojection_program.old_transform_uniform, - UniformData::from_transform_3d(old_transform), - ); - self.device.set_uniform( - &self.reprojection_program.new_transform_uniform, - UniformData::from_transform_3d(new_transform), - ); - self.device.bind_texture(texture, 0); - self.device.set_uniform( - &self.reprojection_program.texture_uniform, - UniformData::TextureUnit(0), - ); - self.device.draw_elements( - Primitive::Triangles, - 6, - &RenderState { + self.device.draw_elements(6, &RenderState { + target: &self.draw_render_target(), + program: &self.reprojection_program.program, + vertex_array: &self.reprojection_vertex_array.vertex_array, + primitive: Primitive::Triangles, + textures: &[texture], + uniforms: &[ + (&self.reprojection_program.old_transform_uniform, + UniformData::from_transform_3d(old_transform)), + (&self.reprojection_program.new_transform_uniform, + UniformData::from_transform_3d(new_transform)), + (&self.reprojection_program.texture_uniform, UniformData::TextureUnit(0)), + ], + viewport: self.draw_viewport(), + options: RenderOptions { blend: BlendState::RGBSrcAlphaAlphaOneMinusSrcAlpha, - depth: Some(DepthState { - func: DepthFunc::Less, - write: false, - }), - ..RenderState::default() + depth: Some(DepthState { func: DepthFunc::Less, write: false, }), + clear_ops: ClearOps { color: clear_color, ..ClearOps::default() }, + ..RenderOptions::default() }, - ); + }); + + self.preserve_draw_framebuffer(); } - pub fn bind_draw_framebuffer(&self) { + pub fn draw_render_target(&self) -> RenderTarget { if self.postprocessing_needed() { - self.device - .bind_framebuffer(self.postprocess_source_framebuffer.as_ref().unwrap()); + RenderTarget::Framebuffer(self.postprocess_source_framebuffer.as_ref().unwrap()) } else { - self.bind_dest_framebuffer(); + self.dest_render_target() } } - pub fn bind_dest_framebuffer(&self) { + pub fn dest_render_target(&self) -> RenderTarget { match self.dest_framebuffer { - DestFramebuffer::Default { viewport, .. } => { - self.device.bind_default_framebuffer(viewport) - } - DestFramebuffer::Other(ref framebuffer) => self.device.bind_framebuffer(framebuffer), + DestFramebuffer::Default { .. } => RenderTarget::Default, + DestFramebuffer::Other(ref framebuffer) => RenderTarget::Framebuffer(framebuffer), } } @@ -833,16 +809,21 @@ where let texture = self .device .create_texture(TextureFormat::R8, source_framebuffer_size); - self.postprocess_source_framebuffer = Some(self.device.create_framebuffer(texture)) + self.postprocess_source_framebuffer = + Some(self.device.create_framebuffer(texture)); } }; - self.device - .bind_framebuffer(self.postprocess_source_framebuffer.as_ref().unwrap()); - self.device.clear(&ClearParams { - color: Some(ColorF::transparent_black()), - ..ClearParams::default() - }); + /* + self.device.clear(&RenderTarget::Framebuffer(self.postprocess_source_framebuffer + .as_ref() + .unwrap()), + RectI::new(Vector2I::default(), source_framebuffer_size), + &ClearParams { + color: Some(ColorF::transparent_black()), + ..ClearParams::default() + }); + */ } fn postprocessing_needed(&self) -> bool { @@ -869,7 +850,33 @@ where }) } - fn draw_viewport(&self) -> RectI { + fn clear_color_for_draw_operation(&mut self) -> Option { + let postprocessing_needed = self.postprocessing_needed(); + let flag = if postprocessing_needed { + FramebufferFlags::MUST_PRESERVE_POSTPROCESS_FRAMEBUFFER_CONTENTS + } else { + FramebufferFlags::MUST_PRESERVE_DEST_FRAMEBUFFER_CONTENTS + }; + + if self.framebuffer_flags.contains(flag) { + None + } else if !postprocessing_needed { + self.options.background_color + } else { + Some(ColorF::default()) + } + } + + fn preserve_draw_framebuffer(&mut self) { + let flag = if self.postprocessing_needed() { + FramebufferFlags::MUST_PRESERVE_POSTPROCESS_FRAMEBUFFER_CONTENTS + } else { + FramebufferFlags::MUST_PRESERVE_DEST_FRAMEBUFFER_CONTENTS + }; + self.framebuffer_flags.insert(flag); + } + + pub fn draw_viewport(&self) -> RectI { let main_viewport = self.main_viewport(); match self.render_mode { RenderMode::Monochrome { @@ -895,6 +902,11 @@ where } } + fn mask_viewport(&self) -> RectI { + let texture = self.device.framebuffer_texture(&self.mask_framebuffer); + RectI::new(Vector2I::default(), self.device.texture_size(texture)) + } + fn allocate_timer_query(&mut self) -> D::TimerQuery { match self.free_timer_queries.pop() { Some(query) => query, @@ -909,8 +921,9 @@ where } fn end_composite_timer_query(&mut self) { - let query = self.current_timers.stage_1.as_ref().expect("No stage 1 timer query yet?!"); - self.device.end_timer_query(&query); + if let Some(ref query) = self.current_timers.stage_1 { + self.device.end_timer_query(query); + } } } @@ -951,59 +964,63 @@ where let to_subpx_attr = device.get_vertex_attr(&fill_program.program, "ToSubpx").unwrap(); let tile_index_attr = device.get_vertex_attr(&fill_program.program, "TileIndex").unwrap(); - device.bind_vertex_array(&vertex_array); - device.use_program(&fill_program.program); - device.bind_buffer(quad_vertex_positions_buffer, BufferTarget::Vertex); - device.configure_vertex_attr(&tess_coord_attr, &VertexAttrDescriptor { + device.bind_buffer(&vertex_array, quad_vertex_positions_buffer, BufferTarget::Vertex); + device.configure_vertex_attr(&vertex_array, &tess_coord_attr, &VertexAttrDescriptor { size: 2, - class: VertexAttrClass::Float, - attr_type: VertexAttrType::U8, - stride: 0, + class: VertexAttrClass::Int, + attr_type: VertexAttrType::U16, + stride: 4, offset: 0, divisor: 0, + buffer_index: 0, }); - device.bind_buffer(&vertex_buffer, BufferTarget::Vertex); - device.configure_vertex_attr(&from_px_attr, &VertexAttrDescriptor { + device.bind_buffer(&vertex_array, &vertex_buffer, BufferTarget::Vertex); + device.configure_vertex_attr(&vertex_array, &from_px_attr, &VertexAttrDescriptor { size: 1, class: VertexAttrClass::Int, attr_type: VertexAttrType::U8, stride: FILL_INSTANCE_SIZE, offset: 0, divisor: 1, + buffer_index: 1, }); - device.configure_vertex_attr(&to_px_attr, &VertexAttrDescriptor { + device.configure_vertex_attr(&vertex_array, &to_px_attr, &VertexAttrDescriptor { size: 1, class: VertexAttrClass::Int, attr_type: VertexAttrType::U8, stride: FILL_INSTANCE_SIZE, offset: 1, divisor: 1, + buffer_index: 1, }); - device.configure_vertex_attr(&from_subpx_attr, &VertexAttrDescriptor { + device.configure_vertex_attr(&vertex_array, &from_subpx_attr, &VertexAttrDescriptor { size: 2, class: VertexAttrClass::FloatNorm, attr_type: VertexAttrType::U8, stride: FILL_INSTANCE_SIZE, offset: 2, divisor: 1, + buffer_index: 1, }); - device.configure_vertex_attr(&to_subpx_attr, &VertexAttrDescriptor { + device.configure_vertex_attr(&vertex_array, &to_subpx_attr, &VertexAttrDescriptor { size: 2, class: VertexAttrClass::FloatNorm, attr_type: VertexAttrType::U8, stride: FILL_INSTANCE_SIZE, offset: 4, divisor: 1, + buffer_index: 1, }); - device.configure_vertex_attr(&tile_index_attr, &VertexAttrDescriptor { + device.configure_vertex_attr(&vertex_array, &tile_index_attr, &VertexAttrDescriptor { size: 1, class: VertexAttrClass::Int, attr_type: VertexAttrType::U16, stride: FILL_INSTANCE_SIZE, offset: 6, divisor: 1, + buffer_index: 1, }); - device.bind_buffer(quad_vertex_indices_buffer, BufferTarget::Index); + device.bind_buffer(&vertex_array, quad_vertex_indices_buffer, BufferTarget::Index); FillVertexArray { vertex_array, vertex_buffer } } @@ -1042,53 +1059,58 @@ where // NB: The object must be of type `I16`, not `U16`, to work around a macOS Radeon // driver bug. - device.bind_vertex_array(&vertex_array); - device.use_program(&alpha_tile_program.program); - device.bind_buffer(quad_vertex_positions_buffer, BufferTarget::Vertex); - device.configure_vertex_attr(&tess_coord_attr, &VertexAttrDescriptor { + device.bind_buffer(&vertex_array, quad_vertex_positions_buffer, BufferTarget::Vertex); + device.configure_vertex_attr(&vertex_array, &tess_coord_attr, &VertexAttrDescriptor { size: 2, - class: VertexAttrClass::Float, - attr_type: VertexAttrType::U8, - stride: 0, + class: VertexAttrClass::Int, + attr_type: VertexAttrType::U16, + stride: 4, offset: 0, divisor: 0, + buffer_index: 0, }); - device.bind_buffer(&vertex_buffer, BufferTarget::Vertex); - device.configure_vertex_attr(&tile_origin_attr, &VertexAttrDescriptor { + device.bind_buffer(&vertex_array, &vertex_buffer, BufferTarget::Vertex); + device.configure_vertex_attr(&vertex_array, &tile_origin_attr, &VertexAttrDescriptor { size: 3, class: VertexAttrClass::Int, attr_type: VertexAttrType::U8, stride: MASK_TILE_INSTANCE_SIZE, offset: 0, divisor: 1, + buffer_index: 1, }); - device.configure_vertex_attr(&backdrop_attr, &VertexAttrDescriptor { + device.configure_vertex_attr(&vertex_array, &backdrop_attr, &VertexAttrDescriptor { size: 1, class: VertexAttrClass::Int, attr_type: VertexAttrType::I8, stride: MASK_TILE_INSTANCE_SIZE, offset: 3, divisor: 1, + buffer_index: 1, }); - device.configure_vertex_attr(&tile_index_attr, &VertexAttrDescriptor { + device.configure_vertex_attr(&vertex_array, &tile_index_attr, &VertexAttrDescriptor { size: 1, class: VertexAttrClass::Int, attr_type: VertexAttrType::I16, stride: MASK_TILE_INSTANCE_SIZE, offset: 6, divisor: 1, + buffer_index: 1, }); if let Some(color_tex_coord_attr) = color_tex_coord_attr { - device.configure_vertex_attr(&color_tex_coord_attr, &VertexAttrDescriptor { - size: 2, - class: VertexAttrClass::FloatNorm, - attr_type: VertexAttrType::U16, - stride: MASK_TILE_INSTANCE_SIZE, - offset: 8, - divisor: 1, - }); + device.configure_vertex_attr(&vertex_array, + &color_tex_coord_attr, + &VertexAttrDescriptor { + size: 2, + class: VertexAttrClass::FloatNorm, + attr_type: VertexAttrType::U16, + stride: MASK_TILE_INSTANCE_SIZE, + offset: 8, + divisor: 1, + buffer_index: 1, + }); } - device.bind_buffer(quad_vertex_indices_buffer, BufferTarget::Index); + device.bind_buffer(&vertex_array, quad_vertex_indices_buffer, BufferTarget::Index); AlphaTileVertexArray { vertex_array, vertex_buffer } } @@ -1123,37 +1145,40 @@ where // NB: The object must be of type short, not unsigned short, to work around a macOS // Radeon driver bug. - device.bind_vertex_array(&vertex_array); - device.use_program(&solid_tile_program.program); - device.bind_buffer(quad_vertex_positions_buffer, BufferTarget::Vertex); - device.configure_vertex_attr(&tess_coord_attr, &VertexAttrDescriptor { + device.bind_buffer(&vertex_array, quad_vertex_positions_buffer, BufferTarget::Vertex); + device.configure_vertex_attr(&vertex_array, &tess_coord_attr, &VertexAttrDescriptor { size: 2, - class: VertexAttrClass::Float, - attr_type: VertexAttrType::U8, - stride: 0, + class: VertexAttrClass::Int, + attr_type: VertexAttrType::U16, + stride: 4, offset: 0, divisor: 0, + buffer_index: 0, }); - device.bind_buffer(&vertex_buffer, BufferTarget::Vertex); - device.configure_vertex_attr(&tile_origin_attr, &VertexAttrDescriptor { + device.bind_buffer(&vertex_array, &vertex_buffer, BufferTarget::Vertex); + device.configure_vertex_attr(&vertex_array, &tile_origin_attr, &VertexAttrDescriptor { size: 2, - class: VertexAttrClass::Float, + class: VertexAttrClass::Int, attr_type: VertexAttrType::I16, stride: SOLID_TILE_INSTANCE_SIZE, offset: 0, divisor: 1, + buffer_index: 1, }); if let Some(color_tex_coord_attr) = color_tex_coord_attr { - device.configure_vertex_attr(&color_tex_coord_attr, &VertexAttrDescriptor { - size: 2, - class: VertexAttrClass::FloatNorm, - attr_type: VertexAttrType::U16, - stride: SOLID_TILE_INSTANCE_SIZE, - offset: 4, - divisor: 1, - }); + device.configure_vertex_attr(&vertex_array, + &color_tex_coord_attr, + &VertexAttrDescriptor { + size: 2, + class: VertexAttrClass::FloatNorm, + attr_type: VertexAttrType::U16, + stride: SOLID_TILE_INSTANCE_SIZE, + offset: 4, + divisor: 1, + buffer_index: 1, + }); } - device.bind_buffer(quad_vertex_indices_buffer, BufferTarget::Index); + device.bind_buffer(&vertex_array, quad_vertex_indices_buffer, BufferTarget::Index); SolidTileVertexArray { vertex_array, vertex_buffer } } @@ -1235,10 +1260,10 @@ where { fn new(device: &D, resources: &dyn ResourceLoader) -> SolidTileMulticolorProgram { let solid_tile_program = SolidTileProgram::new(device, "tile_solid_multicolor", resources); - let paint_texture_uniform = - device.get_uniform(&solid_tile_program.program, "PaintTexture"); - let paint_texture_size_uniform = - device.get_uniform(&solid_tile_program.program, "PaintTextureSize"); + let paint_texture_uniform = device.get_uniform(&solid_tile_program.program, + "PaintTexture"); + let paint_texture_size_uniform = device.get_uniform(&solid_tile_program.program, + "PaintTextureSize"); SolidTileMulticolorProgram { solid_tile_program, paint_texture_uniform, @@ -1383,8 +1408,8 @@ where let framebuffer_size_uniform = device.get_uniform(&program, "FramebufferSize"); let kernel_uniform = device.get_uniform(&program, "Kernel"); let gamma_lut_uniform = device.get_uniform(&program, "GammaLUT"); - let gamma_correction_enabled_uniform = - device.get_uniform(&program, "GammaCorrectionEnabled"); + let gamma_correction_enabled_uniform = device.get_uniform(&program, + "GammaCorrectionEnabled"); let fg_color_uniform = device.get_uniform(&program, "FGColor"); let bg_color_uniform = device.get_uniform(&program, "BGColor"); PostprocessProgram { @@ -1422,18 +1447,17 @@ where let position_attr = device.get_vertex_attr(&postprocess_program.program, "Position") .unwrap(); - device.bind_vertex_array(&vertex_array); - device.use_program(&postprocess_program.program); - device.bind_buffer(quad_vertex_positions_buffer, BufferTarget::Vertex); - device.configure_vertex_attr(&position_attr, &VertexAttrDescriptor { + device.bind_buffer(&vertex_array, quad_vertex_positions_buffer, BufferTarget::Vertex); + device.configure_vertex_attr(&vertex_array, &position_attr, &VertexAttrDescriptor { size: 2, - class: VertexAttrClass::Float, - attr_type: VertexAttrType::U8, - stride: 0, + class: VertexAttrClass::Int, + attr_type: VertexAttrType::U16, + stride: 4, offset: 0, divisor: 0, + buffer_index: 0, }); - device.bind_buffer(quad_vertex_indices_buffer, BufferTarget::Index); + device.bind_buffer(&vertex_array, quad_vertex_indices_buffer, BufferTarget::Index); PostprocessVertexArray { vertex_array } } @@ -1474,18 +1498,18 @@ where let (vertex_buffer, index_buffer) = (device.create_buffer(), device.create_buffer()); let position_attr = device.get_vertex_attr(&stencil_program.program, "Position").unwrap(); - device.bind_vertex_array(&vertex_array); - device.use_program(&stencil_program.program); - device.bind_buffer(&vertex_buffer, BufferTarget::Vertex); - device.configure_vertex_attr(&position_attr, &VertexAttrDescriptor { + + device.bind_buffer(&vertex_array, &vertex_buffer, BufferTarget::Vertex); + device.configure_vertex_attr(&vertex_array, &position_attr, &VertexAttrDescriptor { size: 3, class: VertexAttrClass::Float, attr_type: VertexAttrType::F32, stride: 4 * 4, offset: 0, divisor: 0, + buffer_index: 0, }); - device.bind_buffer(&index_buffer, BufferTarget::Index); + device.bind_buffer(&vertex_array, &index_buffer, BufferTarget::Index); StencilVertexArray { vertex_array, vertex_buffer, index_buffer } } @@ -1538,58 +1562,25 @@ where quad_vertex_indices_buffer: &D::Buffer, ) -> ReprojectionVertexArray { let vertex_array = device.create_vertex_array(); - let position_attr = device.get_vertex_attr(&reprojection_program.program, "Position") .unwrap(); - device.bind_vertex_array(&vertex_array); - device.use_program(&reprojection_program.program); - device.bind_buffer(quad_vertex_positions_buffer, BufferTarget::Vertex); - device.configure_vertex_attr(&position_attr, &VertexAttrDescriptor { + + device.bind_buffer(&vertex_array, quad_vertex_positions_buffer, BufferTarget::Vertex); + device.configure_vertex_attr(&vertex_array, &position_attr, &VertexAttrDescriptor { size: 2, - class: VertexAttrClass::Float, - attr_type: VertexAttrType::U8, - stride: 0, + class: VertexAttrClass::Int, + attr_type: VertexAttrType::I16, + stride: 4, offset: 0, divisor: 0, + buffer_index: 0, }); - device.bind_buffer(quad_vertex_indices_buffer, BufferTarget::Index); + device.bind_buffer(&vertex_array, quad_vertex_indices_buffer, BufferTarget::Index); ReprojectionVertexArray { vertex_array } } } -#[derive(Clone)] -pub enum DestFramebuffer -where - D: Device, -{ - Default { - viewport: RectI, - window_size: Vector2I, - }, - Other(D::Framebuffer), -} - -impl DestFramebuffer -where - D: Device, -{ - #[inline] - pub fn full_window(window_size: Vector2I) -> DestFramebuffer { - let viewport = RectI::new(Vector2I::default(), window_size); - DestFramebuffer::Default { viewport, window_size } - } - - fn window_size(&self, device: &D) -> Vector2I { - match *self { - DestFramebuffer::Default { window_size, .. } => window_size, - DestFramebuffer::Other(ref framebuffer) => { - device.texture_size(device.framebuffer_texture(framebuffer)) - } - } - } -} - #[derive(Clone, Copy)] pub enum RenderMode { Multicolor, @@ -1675,3 +1666,11 @@ impl Add for RenderTime { } } } + +bitflags! { + struct FramebufferFlags: u8 { + const MUST_PRESERVE_MASK_FRAMEBUFFER_CONTENTS = 0x01; + const MUST_PRESERVE_POSTPROCESS_FRAMEBUFFER_CONTENTS = 0x02; + const MUST_PRESERVE_DEST_FRAMEBUFFER_CONTENTS = 0x04; + } +} diff --git a/renderer/src/gpu_data.rs b/renderer/src/gpu_data.rs index 76734d59..6c5045f7 100644 --- a/renderer/src/gpu_data.rs +++ b/renderer/src/gpu_data.rs @@ -75,6 +75,7 @@ pub struct SolidTileBatchPrimitive { pub origin_u: u16, pub origin_v: u16, pub object_index: u16, + pub pad: u16, } #[derive(Clone, Copy, Debug, Default)] diff --git a/renderer/src/lib.rs b/renderer/src/lib.rs index 0f80405e..ea7f7072 100644 --- a/renderer/src/lib.rs +++ b/renderer/src/lib.rs @@ -10,6 +10,8 @@ //! The CPU portion of Pathfinder's renderer. +#[macro_use] +extern crate bitflags; #[macro_use] extern crate log; diff --git a/renderer/src/options.rs b/renderer/src/options.rs index 2cb34fe6..32357c08 100644 --- a/renderer/src/options.rs +++ b/renderer/src/options.rs @@ -11,10 +11,10 @@ //! Options that control how rendering is to be performed. use crate::gpu_data::RenderCommand; -use pathfinder_geometry::basic::vector::{Vector2F, Vector4F}; use pathfinder_geometry::basic::rect::RectF; use pathfinder_geometry::basic::transform2d::Transform2DF; use pathfinder_geometry::basic::transform3d::Perspective; +use pathfinder_geometry::basic::vector::{Vector2F, Vector4F}; use pathfinder_geometry::clip::PolygonClipper3D; pub trait RenderCommandListener: Send + Sync { @@ -31,16 +31,17 @@ where } } +/// Options that influence scene building. #[derive(Clone, Default)] -pub struct RenderOptions { +pub struct BuildOptions { pub transform: RenderTransform, pub dilation: Vector2F, pub subpixel_aa_enabled: bool, } -impl RenderOptions { - pub(crate) fn prepare(self, bounds: RectF) -> PreparedRenderOptions { - PreparedRenderOptions { +impl BuildOptions { + pub(crate) fn prepare(self, bounds: RectF) -> PreparedBuildOptions { + PreparedBuildOptions { transform: self.transform.prepare(bounds), dilation: self.dilation, subpixel_aa_enabled: self.subpixel_aa_enabled, @@ -119,13 +120,13 @@ impl RenderTransform { } } -pub(crate) struct PreparedRenderOptions { +pub(crate) struct PreparedBuildOptions { pub(crate) transform: PreparedRenderTransform, pub(crate) dilation: Vector2F, pub(crate) subpixel_aa_enabled: bool, } -impl PreparedRenderOptions { +impl PreparedBuildOptions { #[inline] pub(crate) fn bounding_quad(&self) -> BoundingQuad { match self.transform { diff --git a/renderer/src/scene.rs b/renderer/src/scene.rs index 45cc1c44..db5319c6 100644 --- a/renderer/src/scene.rs +++ b/renderer/src/scene.rs @@ -12,8 +12,8 @@ use crate::builder::SceneBuilder; use crate::concurrent::executor::Executor; -use crate::options::{PreparedRenderOptions, PreparedRenderTransform}; -use crate::options::{RenderCommandListener, RenderOptions}; +use crate::options::{BuildOptions, PreparedBuildOptions}; +use crate::options::{PreparedRenderTransform, RenderCommandListener}; use crate::paint::{Paint, PaintId}; use hashbrown::HashMap; use pathfinder_geometry::basic::vector::Vector2F; @@ -89,7 +89,7 @@ impl Scene { pub(crate) fn apply_render_options( &self, original_outline: &Outline, - options: &PreparedRenderOptions, + options: &PreparedBuildOptions, ) -> Outline { let effective_view_box = self.effective_view_box(options); @@ -156,7 +156,7 @@ impl Scene { } #[inline] - pub(crate) fn effective_view_box(&self, render_options: &PreparedRenderOptions) -> RectF { + pub(crate) fn effective_view_box(&self, render_options: &PreparedBuildOptions) -> RectF { if render_options.subpixel_aa_enabled { self.view_box.scale_xy(Vector2F::new(3.0, 1.0)) } else { @@ -166,7 +166,7 @@ impl Scene { #[inline] pub fn build(&self, - options: RenderOptions, + options: BuildOptions, listener: Box, executor: &E) where E: Executor { diff --git a/renderer/src/z_buffer.rs b/renderer/src/z_buffer.rs index 889cc666..858a9e90 100644 --- a/renderer/src/z_buffer.rs +++ b/renderer/src/z_buffer.rs @@ -91,6 +91,7 @@ impl SolidTileBatchPrimitive { object_index: object_index, origin_u: origin_uv.x() as u16, origin_v: origin_uv.y() as u16, + pad: 0, } } } diff --git a/resources/shaders/gl3/debug_solid.fs.glsl b/resources/shaders/gl3/debug_solid.fs.glsl index eeaaf489..06550da6 100644 --- a/resources/shaders/gl3/debug_solid.fs.glsl +++ b/resources/shaders/gl3/debug_solid.fs.glsl @@ -1,4 +1,6 @@ #version {{version}} +// Automatically generated from files in pathfinder/shaders/. Do not edit! + diff --git a/resources/shaders/gl3/debug_solid.vs.glsl b/resources/shaders/gl3/debug_solid.vs.glsl index 3c38f3f7..a5ac2df8 100644 --- a/resources/shaders/gl3/debug_solid.vs.glsl +++ b/resources/shaders/gl3/debug_solid.vs.glsl @@ -1,4 +1,6 @@ #version {{version}} +// Automatically generated from files in pathfinder/shaders/. Do not edit! + @@ -14,10 +16,10 @@ precision highp float; uniform vec2 uFramebufferSize; -in vec2 aPosition; +in ivec2 aPosition; void main(){ - vec2 position = aPosition / uFramebufferSize * 2.0 - 1.0; + vec2 position = vec2(aPosition)/ uFramebufferSize * 2.0 - 1.0; gl_Position = vec4(position . x, - position . y, 0.0, 1.0); } diff --git a/resources/shaders/gl3/debug_texture.fs.glsl b/resources/shaders/gl3/debug_texture.fs.glsl index 9601adf2..5670374b 100644 --- a/resources/shaders/gl3/debug_texture.fs.glsl +++ b/resources/shaders/gl3/debug_texture.fs.glsl @@ -1,4 +1,6 @@ #version {{version}} +// Automatically generated from files in pathfinder/shaders/. Do not edit! + diff --git a/resources/shaders/gl3/debug_texture.vs.glsl b/resources/shaders/gl3/debug_texture.vs.glsl index b3b546d8..d037b869 100644 --- a/resources/shaders/gl3/debug_texture.vs.glsl +++ b/resources/shaders/gl3/debug_texture.vs.glsl @@ -1,4 +1,6 @@ #version {{version}} +// Automatically generated from files in pathfinder/shaders/. Do not edit! + @@ -15,14 +17,14 @@ precision highp float; uniform vec2 uFramebufferSize; uniform vec2 uTextureSize; -in vec2 aPosition; -in vec2 aTexCoord; +in ivec2 aPosition; +in ivec2 aTexCoord; out vec2 vTexCoord; void main(){ - vTexCoord = aTexCoord / uTextureSize; - vec2 position = aPosition / uFramebufferSize * 2.0 - 1.0; + vTexCoord = vec2(aTexCoord)/ uTextureSize; + vec2 position = vec2(aPosition)/ uFramebufferSize * 2.0 - 1.0; gl_Position = vec4(position . x, - position . y, 0.0, 1.0); } diff --git a/resources/shaders/gl3/demo_ground.fs.glsl b/resources/shaders/gl3/demo_ground.fs.glsl index 3bf84270..49dd50dc 100644 --- a/resources/shaders/gl3/demo_ground.fs.glsl +++ b/resources/shaders/gl3/demo_ground.fs.glsl @@ -1,4 +1,6 @@ #version {{version}} +// Automatically generated from files in pathfinder/shaders/. Do not edit! + diff --git a/resources/shaders/gl3/demo_ground.vs.glsl b/resources/shaders/gl3/demo_ground.vs.glsl index 418eb50a..4f216416 100644 --- a/resources/shaders/gl3/demo_ground.vs.glsl +++ b/resources/shaders/gl3/demo_ground.vs.glsl @@ -1,4 +1,6 @@ #version {{version}} +// Automatically generated from files in pathfinder/shaders/. Do not edit! + @@ -15,12 +17,12 @@ precision highp float; uniform mat4 uTransform; uniform int uGridlineCount; -in vec2 aPosition; +in ivec2 aPosition; out vec2 vTexCoord; void main(){ - vTexCoord = aPosition * float(uGridlineCount); - gl_Position = uTransform * vec4(aPosition . x, 0.0, aPosition . y, 1.0); + vTexCoord = vec2(aPosition * uGridlineCount); + gl_Position = uTransform * vec4(ivec4(aPosition . x, 0, aPosition . y, 1)); } diff --git a/resources/shaders/gl3/fill.fs.glsl b/resources/shaders/gl3/fill.fs.glsl index aeebe141..d70a93bd 100644 --- a/resources/shaders/gl3/fill.fs.glsl +++ b/resources/shaders/gl3/fill.fs.glsl @@ -1,4 +1,6 @@ #version {{version}} +// Automatically generated from files in pathfinder/shaders/. Do not edit! + diff --git a/resources/shaders/gl3/fill.vs.glsl b/resources/shaders/gl3/fill.vs.glsl index fac4560a..83314eb1 100644 --- a/resources/shaders/gl3/fill.vs.glsl +++ b/resources/shaders/gl3/fill.vs.glsl @@ -1,4 +1,6 @@ #version {{version}} +// Automatically generated from files in pathfinder/shaders/. Do not edit! + @@ -15,7 +17,7 @@ precision highp float; uniform vec2 uFramebufferSize; uniform vec2 uTileSize; -in vec2 aTessCoord; +in uvec2 aTessCoord; in uint aFromPx; in uint aToPx; in vec2 aFromSubpx; @@ -27,7 +29,7 @@ out vec2 vTo; vec2 computeTileOffset(uint tileIndex, float stencilTextureWidth){ uint tilesPerRow = uint(stencilTextureWidth / uTileSize . x); - uvec2 tileOffset = uvec2(aTileIndex % tilesPerRow, aTileIndex / tilesPerRow); + uvec2 tileOffset = uvec2(tileIndex % tilesPerRow, tileIndex / tilesPerRow); return vec2(tileOffset)* uTileSize; } @@ -38,11 +40,11 @@ void main(){ vec2 to = vec2(aToPx & 15u, aToPx >> 4u)+ aToSubpx; vec2 position; - if(aTessCoord . x < 0.5) + if(aTessCoord . x == 0u) position . x = floor(min(from . x, to . x)); else position . x = ceil(max(from . x, to . x)); - if(aTessCoord . y < 0.5) + if(aTessCoord . y == 0u) position . y = floor(min(from . y, to . y)); else position . y = uTileSize . y; @@ -50,6 +52,10 @@ void main(){ vFrom = from - position; vTo = to - position; - gl_Position = vec4((tileOrigin + position)/ uFramebufferSize * 2.0 - 1.0, 0.0, 1.0); + vec2 globalPosition =(tileOrigin + position)/ uFramebufferSize * 2.0 - 1.0; + + + + gl_Position = vec4(globalPosition, 0.0, 1.0); } diff --git a/resources/shaders/gl3/post.fs.glsl b/resources/shaders/gl3/post.fs.glsl index 0a74556b..b9de3d7b 100644 --- a/resources/shaders/gl3/post.fs.glsl +++ b/resources/shaders/gl3/post.fs.glsl @@ -1,4 +1,6 @@ #version {{version}} +// Automatically generated from files in pathfinder/shaders/. Do not edit! + diff --git a/resources/shaders/gl3/post.vs.glsl b/resources/shaders/gl3/post.vs.glsl index 29e75ade..b30dcf8d 100644 --- a/resources/shaders/gl3/post.vs.glsl +++ b/resources/shaders/gl3/post.vs.glsl @@ -1,4 +1,6 @@ #version {{version}} +// Automatically generated from files in pathfinder/shaders/. Do not edit! + @@ -12,12 +14,12 @@ precision highp float; -in vec2 aPosition; +in ivec2 aPosition; out vec2 vTexCoord; void main(){ - vTexCoord = aPosition; - gl_Position = vec4(aPosition * 2.0 - 1.0, 0.0, 1.0); + vTexCoord = vec2(aPosition); + gl_Position = vec4(vec2(aPosition)* 2.0 - 1.0, 0.0, 1.0); } diff --git a/resources/shaders/gl3/reproject.fs.glsl b/resources/shaders/gl3/reproject.fs.glsl index 427b632c..f1344a2e 100644 --- a/resources/shaders/gl3/reproject.fs.glsl +++ b/resources/shaders/gl3/reproject.fs.glsl @@ -1,4 +1,6 @@ #version {{version}} +// Automatically generated from files in pathfinder/shaders/. Do not edit! + diff --git a/resources/shaders/gl3/reproject.vs.glsl b/resources/shaders/gl3/reproject.vs.glsl index d1c70544..35a3db40 100644 --- a/resources/shaders/gl3/reproject.vs.glsl +++ b/resources/shaders/gl3/reproject.vs.glsl @@ -1,4 +1,6 @@ #version {{version}} +// Automatically generated from files in pathfinder/shaders/. Do not edit! + @@ -14,12 +16,17 @@ precision highp float; uniform mat4 uNewTransform; -in vec2 aPosition; +in ivec2 aPosition; out vec2 vTexCoord; void main(){ - vTexCoord = aPosition; - gl_Position = uNewTransform * vec4(aPosition, 0.0, 1.0); + vec2 position = vec2(aPosition); + vTexCoord = position; + + + + + gl_Position = uNewTransform * vec4(position, 0.0, 1.0); } diff --git a/resources/shaders/gl3/stencil.fs.glsl b/resources/shaders/gl3/stencil.fs.glsl index e2e093ab..b37ee045 100644 --- a/resources/shaders/gl3/stencil.fs.glsl +++ b/resources/shaders/gl3/stencil.fs.glsl @@ -1,4 +1,6 @@ #version {{version}} +// Automatically generated from files in pathfinder/shaders/. Do not edit! + diff --git a/resources/shaders/gl3/stencil.vs.glsl b/resources/shaders/gl3/stencil.vs.glsl index 2fee81a2..0f44276e 100644 --- a/resources/shaders/gl3/stencil.vs.glsl +++ b/resources/shaders/gl3/stencil.vs.glsl @@ -1,4 +1,6 @@ #version {{version}} +// Automatically generated from files in pathfinder/shaders/. Do not edit! + diff --git a/resources/shaders/gl3/tile_alpha.fs.glsl b/resources/shaders/gl3/tile_alpha.fs.glsl index 3af9cf4d..0e7247d7 100644 --- a/resources/shaders/gl3/tile_alpha.fs.glsl +++ b/resources/shaders/gl3/tile_alpha.fs.glsl @@ -1,4 +1,6 @@ #version {{version}} +// Automatically generated from files in pathfinder/shaders/. Do not edit! + diff --git a/resources/shaders/gl3/tile_alpha_monochrome.vs.glsl b/resources/shaders/gl3/tile_alpha_monochrome.vs.glsl index d99d7dd7..df40901e 100644 --- a/resources/shaders/gl3/tile_alpha_monochrome.vs.glsl +++ b/resources/shaders/gl3/tile_alpha_monochrome.vs.glsl @@ -1,4 +1,6 @@ #version {{version}} +// Automatically generated from files in pathfinder/shaders/. Do not edit! + @@ -30,10 +32,10 @@ uniform vec2 uTileSize; uniform vec2 uStencilTextureSize; uniform vec2 uViewBoxOrigin; -in vec2 aTessCoord; +in uvec2 aTessCoord; in uvec3 aTileOrigin; in int aBackdrop; -in uint aTileIndex; +in int aTileIndex; out vec2 vTexCoord; out float vBackdrop; @@ -49,9 +51,9 @@ vec2 computeTileOffset(uint tileIndex, float stencilTextureWidth){ void computeVaryings(){ vec2 origin = vec2(aTileOrigin . xy)+ vec2(aTileOrigin . z & 15u, aTileOrigin . z >> 4u)* 256.0; - vec2 pixelPosition =(origin + aTessCoord)* uTileSize + uViewBoxOrigin; + vec2 pixelPosition =(origin + vec2(aTessCoord))* uTileSize + uViewBoxOrigin; vec2 position =(pixelPosition / uFramebufferSize * 2.0 - 1.0)* vec2(1.0, - 1.0); - vec2 maskTexCoordOrigin = computeTileOffset(aTileIndex, uStencilTextureSize . x); + vec2 maskTexCoordOrigin = computeTileOffset(uint(aTileIndex), uStencilTextureSize . x); vec2 maskTexCoord = maskTexCoordOrigin + aTessCoord * uTileSize; vTexCoord = maskTexCoord / uStencilTextureSize; diff --git a/resources/shaders/gl3/tile_alpha_multicolor.vs.glsl b/resources/shaders/gl3/tile_alpha_multicolor.vs.glsl index be655748..2adf4dc3 100644 --- a/resources/shaders/gl3/tile_alpha_multicolor.vs.glsl +++ b/resources/shaders/gl3/tile_alpha_multicolor.vs.glsl @@ -1,4 +1,6 @@ #version {{version}} +// Automatically generated from files in pathfinder/shaders/. Do not edit! + @@ -30,10 +32,10 @@ uniform vec2 uTileSize; uniform vec2 uStencilTextureSize; uniform vec2 uViewBoxOrigin; -in vec2 aTessCoord; +in uvec2 aTessCoord; in uvec3 aTileOrigin; in int aBackdrop; -in uint aTileIndex; +in int aTileIndex; out vec2 vTexCoord; out float vBackdrop; @@ -49,9 +51,9 @@ vec2 computeTileOffset(uint tileIndex, float stencilTextureWidth){ void computeVaryings(){ vec2 origin = vec2(aTileOrigin . xy)+ vec2(aTileOrigin . z & 15u, aTileOrigin . z >> 4u)* 256.0; - vec2 pixelPosition =(origin + aTessCoord)* uTileSize + uViewBoxOrigin; + vec2 pixelPosition =(origin + vec2(aTessCoord))* uTileSize + uViewBoxOrigin; vec2 position =(pixelPosition / uFramebufferSize * 2.0 - 1.0)* vec2(1.0, - 1.0); - vec2 maskTexCoordOrigin = computeTileOffset(aTileIndex, uStencilTextureSize . x); + vec2 maskTexCoordOrigin = computeTileOffset(uint(aTileIndex), uStencilTextureSize . x); vec2 maskTexCoord = maskTexCoordOrigin + aTessCoord * uTileSize; vTexCoord = maskTexCoord / uStencilTextureSize; diff --git a/resources/shaders/gl3/tile_solid.fs.glsl b/resources/shaders/gl3/tile_solid.fs.glsl index 2079d945..f8f8f7a7 100644 --- a/resources/shaders/gl3/tile_solid.fs.glsl +++ b/resources/shaders/gl3/tile_solid.fs.glsl @@ -1,4 +1,6 @@ #version {{version}} +// Automatically generated from files in pathfinder/shaders/. Do not edit! + diff --git a/resources/shaders/gl3/tile_solid_monochrome.vs.glsl b/resources/shaders/gl3/tile_solid_monochrome.vs.glsl index d7544c26..c0808cbd 100644 --- a/resources/shaders/gl3/tile_solid_monochrome.vs.glsl +++ b/resources/shaders/gl3/tile_solid_monochrome.vs.glsl @@ -1,4 +1,6 @@ #version {{version}} +// Automatically generated from files in pathfinder/shaders/. Do not edit! + @@ -29,19 +31,18 @@ uniform vec2 uFramebufferSize; uniform vec2 uTileSize; uniform vec2 uViewBoxOrigin; -in vec2 aTessCoord; -in vec2 aTileOrigin; +in uvec2 aTessCoord; +in ivec2 aTileOrigin; out vec4 vColor; vec4 getColor(); void computeVaryings(){ - vec2 pixelPosition =(aTileOrigin + aTessCoord)* uTileSize + uViewBoxOrigin; + vec2 pixelPosition = vec2(aTileOrigin + ivec2(aTessCoord))* uTileSize + uViewBoxOrigin; vec2 position =(pixelPosition / uFramebufferSize * 2.0 - 1.0)* vec2(1.0, - 1.0); vColor = getColor(); - gl_Position = vec4(position, 0.0, 1.0); } diff --git a/resources/shaders/gl3/tile_solid_multicolor.vs.glsl b/resources/shaders/gl3/tile_solid_multicolor.vs.glsl index 0e23e0a4..4ff5208c 100644 --- a/resources/shaders/gl3/tile_solid_multicolor.vs.glsl +++ b/resources/shaders/gl3/tile_solid_multicolor.vs.glsl @@ -1,4 +1,6 @@ #version {{version}} +// Automatically generated from files in pathfinder/shaders/. Do not edit! + @@ -29,19 +31,18 @@ uniform vec2 uFramebufferSize; uniform vec2 uTileSize; uniform vec2 uViewBoxOrigin; -in vec2 aTessCoord; -in vec2 aTileOrigin; +in uvec2 aTessCoord; +in ivec2 aTileOrigin; out vec4 vColor; vec4 getColor(); void computeVaryings(){ - vec2 pixelPosition =(aTileOrigin + aTessCoord)* uTileSize + uViewBoxOrigin; + vec2 pixelPosition = vec2(aTileOrigin + ivec2(aTessCoord))* uTileSize + uViewBoxOrigin; vec2 position =(pixelPosition / uFramebufferSize * 2.0 - 1.0)* vec2(1.0, - 1.0); vColor = getColor(); - gl_Position = vec4(position, 0.0, 1.0); } diff --git a/resources/shaders/metal/debug_solid.fs.metal b/resources/shaders/metal/debug_solid.fs.metal index 6fc13e2f..49f35a94 100644 --- a/resources/shaders/metal/debug_solid.fs.metal +++ b/resources/shaders/metal/debug_solid.fs.metal @@ -1,17 +1,23 @@ +// Automatically generated from files in pathfinder/shaders/. Do not edit! #include #include using namespace metal; +struct spvDescriptorSetBuffer0 +{ + constant float4* uColor [[id(0)]]; +}; + struct main0_out { float4 oFragColor [[color(0)]]; }; -fragment main0_out main0(float4 uColor [[buffer(0)]]) +fragment main0_out main0(constant spvDescriptorSetBuffer0& spvDescriptorSet0 [[buffer(0)]]) { main0_out out = {}; - out.oFragColor = float4(uColor.xyz, 1.0) * uColor.w; + out.oFragColor = float4((*spvDescriptorSet0.uColor).xyz, 1.0) * (*spvDescriptorSet0.uColor).w; return out; } diff --git a/resources/shaders/metal/debug_solid.vs.metal b/resources/shaders/metal/debug_solid.vs.metal index bcad2a03..ec9d440f 100644 --- a/resources/shaders/metal/debug_solid.vs.metal +++ b/resources/shaders/metal/debug_solid.vs.metal @@ -1,8 +1,14 @@ +// Automatically generated from files in pathfinder/shaders/. Do not edit! #include #include using namespace metal; +struct spvDescriptorSetBuffer0 +{ + constant float2* uFramebufferSize [[id(0)]]; +}; + struct main0_out { float4 gl_Position [[position]]; @@ -10,13 +16,13 @@ struct main0_out struct main0_in { - float2 aPosition [[attribute(0)]]; + int2 aPosition [[attribute(0)]]; }; -vertex main0_out main0(main0_in in [[stage_in]], float2 uFramebufferSize [[buffer(0)]], uint gl_VertexID [[vertex_id]], uint gl_InstanceID [[instance_id]]) +vertex main0_out main0(main0_in in [[stage_in]], constant spvDescriptorSetBuffer0& spvDescriptorSet0 [[buffer(0)]]) { main0_out out = {}; - float2 position = ((in.aPosition / uFramebufferSize) * 2.0) - float2(1.0); + float2 position = ((float2(in.aPosition) / (*spvDescriptorSet0.uFramebufferSize)) * 2.0) - float2(1.0); out.gl_Position = float4(position.x, -position.y, 0.0, 1.0); return out; } diff --git a/resources/shaders/metal/debug_texture.fs.metal b/resources/shaders/metal/debug_texture.fs.metal index 67bc2370..9949a558 100644 --- a/resources/shaders/metal/debug_texture.fs.metal +++ b/resources/shaders/metal/debug_texture.fs.metal @@ -1,8 +1,16 @@ +// Automatically generated from files in pathfinder/shaders/. Do not edit! #include #include using namespace metal; +struct spvDescriptorSetBuffer0 +{ + constant float4* uColor [[id(0)]]; + texture2d uTexture [[id(1)]]; + sampler uTextureSmplr [[id(2)]]; +}; + struct main0_out { float4 oFragColor [[color(0)]]; @@ -13,11 +21,11 @@ struct main0_in float2 vTexCoord [[user(locn0)]]; }; -fragment main0_out main0(main0_in in [[stage_in]], float4 uColor [[buffer(0)]], texture2d uTexture [[texture(0)]], sampler uTextureSmplr [[sampler(0)]]) +fragment main0_out main0(main0_in in [[stage_in]], constant spvDescriptorSetBuffer0& spvDescriptorSet0 [[buffer(0)]]) { main0_out out = {}; - float alpha = uTexture.sample(uTextureSmplr, in.vTexCoord).x * uColor.w; - out.oFragColor = float4(uColor.xyz, 1.0) * alpha; + float alpha = spvDescriptorSet0.uTexture.sample(spvDescriptorSet0.uTextureSmplr, in.vTexCoord).x * (*spvDescriptorSet0.uColor).w; + out.oFragColor = float4((*spvDescriptorSet0.uColor).xyz, 1.0) * alpha; return out; } diff --git a/resources/shaders/metal/debug_texture.vs.metal b/resources/shaders/metal/debug_texture.vs.metal index 25eb20b8..87a31507 100644 --- a/resources/shaders/metal/debug_texture.vs.metal +++ b/resources/shaders/metal/debug_texture.vs.metal @@ -1,8 +1,15 @@ +// Automatically generated from files in pathfinder/shaders/. Do not edit! #include #include using namespace metal; +struct spvDescriptorSetBuffer0 +{ + constant float2* uTextureSize [[id(0)]]; + constant float2* uFramebufferSize [[id(1)]]; +}; + struct main0_out { float2 vTexCoord [[user(locn0)]]; @@ -11,15 +18,15 @@ struct main0_out struct main0_in { - float2 aPosition [[attribute(0)]]; - float2 aTexCoord [[attribute(1)]]; + int2 aPosition [[attribute(0)]]; + int2 aTexCoord [[attribute(1)]]; }; -vertex main0_out main0(main0_in in [[stage_in]], float2 uTextureSize [[buffer(0)]], float2 uFramebufferSize [[buffer(1)]], uint gl_VertexID [[vertex_id]], uint gl_InstanceID [[instance_id]]) +vertex main0_out main0(main0_in in [[stage_in]], constant spvDescriptorSetBuffer0& spvDescriptorSet0 [[buffer(0)]]) { main0_out out = {}; - out.vTexCoord = in.aTexCoord / uTextureSize; - float2 position = ((in.aPosition / uFramebufferSize) * 2.0) - float2(1.0); + out.vTexCoord = float2(in.aTexCoord) / (*spvDescriptorSet0.uTextureSize); + float2 position = ((float2(in.aPosition) / (*spvDescriptorSet0.uFramebufferSize)) * 2.0) - float2(1.0); out.gl_Position = float4(position.x, -position.y, 0.0, 1.0); return out; } diff --git a/resources/shaders/metal/demo_ground.fs.metal b/resources/shaders/metal/demo_ground.fs.metal index 919b2f37..1b64111f 100644 --- a/resources/shaders/metal/demo_ground.fs.metal +++ b/resources/shaders/metal/demo_ground.fs.metal @@ -1,8 +1,15 @@ +// Automatically generated from files in pathfinder/shaders/. Do not edit! #include #include using namespace metal; +struct spvDescriptorSetBuffer0 +{ + constant float4* uGridlineColor [[id(0)]]; + constant float4* uGroundColor [[id(1)]]; +}; + struct main0_out { float4 oFragColor [[color(0)]]; @@ -13,12 +20,12 @@ struct main0_in float2 vTexCoord [[user(locn0)]]; }; -fragment main0_out main0(main0_in in [[stage_in]], float4 uGridlineColor [[buffer(0)]], float4 uGroundColor [[buffer(1)]]) +fragment main0_out main0(main0_in in [[stage_in]], constant spvDescriptorSetBuffer0& spvDescriptorSet0 [[buffer(0)]]) { main0_out out = {}; float2 texCoordPx = fract(in.vTexCoord) / fwidth(in.vTexCoord); bool4 _33 = bool4(any(texCoordPx <= float2(1.0))); - out.oFragColor = float4(_33.x ? uGridlineColor.x : uGroundColor.x, _33.y ? uGridlineColor.y : uGroundColor.y, _33.z ? uGridlineColor.z : uGroundColor.z, _33.w ? uGridlineColor.w : uGroundColor.w); + out.oFragColor = float4(_33.x ? (*spvDescriptorSet0.uGridlineColor).x : (*spvDescriptorSet0.uGroundColor).x, _33.y ? (*spvDescriptorSet0.uGridlineColor).y : (*spvDescriptorSet0.uGroundColor).y, _33.z ? (*spvDescriptorSet0.uGridlineColor).z : (*spvDescriptorSet0.uGroundColor).z, _33.w ? (*spvDescriptorSet0.uGridlineColor).w : (*spvDescriptorSet0.uGroundColor).w); return out; } diff --git a/resources/shaders/metal/demo_ground.vs.metal b/resources/shaders/metal/demo_ground.vs.metal index 049083ea..997185f5 100644 --- a/resources/shaders/metal/demo_ground.vs.metal +++ b/resources/shaders/metal/demo_ground.vs.metal @@ -1,8 +1,15 @@ +// Automatically generated from files in pathfinder/shaders/. Do not edit! #include #include using namespace metal; +struct spvDescriptorSetBuffer0 +{ + constant int* uGridlineCount [[id(0)]]; + constant float4x4* uTransform [[id(1)]]; +}; + struct main0_out { float2 vTexCoord [[user(locn0)]]; @@ -11,14 +18,14 @@ struct main0_out struct main0_in { - float2 aPosition [[attribute(0)]]; + int2 aPosition [[attribute(0)]]; }; -vertex main0_out main0(main0_in in [[stage_in]], int uGridlineCount [[buffer(0)]], float4x4 uTransform [[buffer(1)]], uint gl_VertexID [[vertex_id]], uint gl_InstanceID [[instance_id]]) +vertex main0_out main0(main0_in in [[stage_in]], constant spvDescriptorSetBuffer0& spvDescriptorSet0 [[buffer(0)]]) { main0_out out = {}; - out.vTexCoord = in.aPosition * float(uGridlineCount); - out.gl_Position = uTransform * float4(in.aPosition.x, 0.0, in.aPosition.y, 1.0); + out.vTexCoord = float2(in.aPosition * int2((*spvDescriptorSet0.uGridlineCount))); + out.gl_Position = (*spvDescriptorSet0.uTransform) * float4(int4(in.aPosition.x, 0, in.aPosition.y, 1)); return out; } diff --git a/resources/shaders/metal/fill.fs.metal b/resources/shaders/metal/fill.fs.metal index d002bba6..bfa765e5 100644 --- a/resources/shaders/metal/fill.fs.metal +++ b/resources/shaders/metal/fill.fs.metal @@ -1,8 +1,15 @@ +// Automatically generated from files in pathfinder/shaders/. Do not edit! #include #include using namespace metal; +struct spvDescriptorSetBuffer0 +{ + texture2d uAreaLUT [[id(0)]]; + sampler uAreaLUTSmplr [[id(1)]]; +}; + struct main0_out { float4 oFragColor [[color(0)]]; @@ -14,7 +21,7 @@ struct main0_in float2 vTo [[user(locn1)]]; }; -fragment main0_out main0(main0_in in [[stage_in]], texture2d uAreaLUT [[texture(0)]], sampler uAreaLUTSmplr [[sampler(0)]]) +fragment main0_out main0(main0_in in [[stage_in]], constant spvDescriptorSetBuffer0& spvDescriptorSet0 [[buffer(0)]]) { main0_out out = {}; float2 from = in.vFrom; @@ -29,7 +36,7 @@ fragment main0_out main0(main0_in in [[stage_in]], texture2d uAreaLUT [[t float y = mix(left.y, right.y, t); float d = (right.y - left.y) / (right.x - left.x); float dX = window.x - window.y; - out.oFragColor = float4(uAreaLUT.sample(uAreaLUTSmplr, (float2(y + 8.0, abs(d * dX)) / float2(16.0))).x * dX); + out.oFragColor = float4(spvDescriptorSet0.uAreaLUT.sample(spvDescriptorSet0.uAreaLUTSmplr, (float2(y + 8.0, abs(d * dX)) / float2(16.0))).x * dX); return out; } diff --git a/resources/shaders/metal/fill.vs.metal b/resources/shaders/metal/fill.vs.metal index 1c545156..87f77d2a 100644 --- a/resources/shaders/metal/fill.vs.metal +++ b/resources/shaders/metal/fill.vs.metal @@ -1,3 +1,4 @@ +// Automatically generated from files in pathfinder/shaders/. Do not edit! #pragma clang diagnostic ignored "-Wmissing-prototypes" #include @@ -5,6 +6,12 @@ using namespace metal; +struct spvDescriptorSetBuffer0 +{ + constant float2* uTileSize [[id(0)]]; + constant float2* uFramebufferSize [[id(1)]]; +}; + struct main0_out { float2 vFrom [[user(locn0)]]; @@ -14,7 +21,7 @@ struct main0_out struct main0_in { - float2 aTessCoord [[attribute(0)]]; + uint2 aTessCoord [[attribute(0)]]; uint aFromPx [[attribute(1)]]; uint aToPx [[attribute(2)]]; float2 aFromSubpx [[attribute(3)]]; @@ -22,23 +29,23 @@ struct main0_in uint aTileIndex [[attribute(5)]]; }; -float2 computeTileOffset(thread const uint& tileIndex, thread const float& stencilTextureWidth, thread float2 uTileSize, thread uint& aTileIndex) +float2 computeTileOffset(thread const uint& tileIndex, thread const float& stencilTextureWidth, thread float2 uTileSize) { uint tilesPerRow = uint(stencilTextureWidth / uTileSize.x); - uint2 tileOffset = uint2(aTileIndex % tilesPerRow, aTileIndex / tilesPerRow); + uint2 tileOffset = uint2(tileIndex % tilesPerRow, tileIndex / tilesPerRow); return float2(tileOffset) * uTileSize; } -vertex main0_out main0(main0_in in [[stage_in]], float2 uTileSize [[buffer(0)]], float2 uFramebufferSize [[buffer(1)]], uint gl_VertexID [[vertex_id]], uint gl_InstanceID [[instance_id]]) +vertex main0_out main0(main0_in in [[stage_in]], constant spvDescriptorSetBuffer0& spvDescriptorSet0 [[buffer(0)]]) { main0_out out = {}; uint param = in.aTileIndex; - float param_1 = uFramebufferSize.x; - float2 tileOrigin = computeTileOffset(param, param_1, uTileSize, in.aTileIndex); + float param_1 = (*spvDescriptorSet0.uFramebufferSize).x; + float2 tileOrigin = computeTileOffset(param, param_1, (*spvDescriptorSet0.uTileSize)); float2 from = float2(float(in.aFromPx & 15u), float(in.aFromPx >> 4u)) + in.aFromSubpx; float2 to = float2(float(in.aToPx & 15u), float(in.aToPx >> 4u)) + in.aToSubpx; float2 position; - if (in.aTessCoord.x < 0.5) + if (in.aTessCoord.x == 0u) { position.x = floor(fast::min(from.x, to.x)); } @@ -46,17 +53,19 @@ vertex main0_out main0(main0_in in [[stage_in]], float2 uTileSize [[buffer(0)]], { position.x = ceil(fast::max(from.x, to.x)); } - if (in.aTessCoord.y < 0.5) + if (in.aTessCoord.y == 0u) { position.y = floor(fast::min(from.y, to.y)); } else { - position.y = uTileSize.y; + position.y = (*spvDescriptorSet0.uTileSize).y; } out.vFrom = from - position; out.vTo = to - position; - out.gl_Position = float4((((tileOrigin + position) / uFramebufferSize) * 2.0) - float2(1.0), 0.0, 1.0); + float2 globalPosition = (((tileOrigin + position) / (*spvDescriptorSet0.uFramebufferSize)) * 2.0) - float2(1.0); + globalPosition.y = -globalPosition.y; + out.gl_Position = float4(globalPosition, 0.0, 1.0); return out; } diff --git a/resources/shaders/metal/post.fs.metal b/resources/shaders/metal/post.fs.metal index 66ca87f8..989fd5d7 100644 --- a/resources/shaders/metal/post.fs.metal +++ b/resources/shaders/metal/post.fs.metal @@ -1,3 +1,4 @@ +// Automatically generated from files in pathfinder/shaders/. Do not edit! #pragma clang diagnostic ignored "-Wmissing-prototypes" #include @@ -5,6 +6,19 @@ using namespace metal; +struct spvDescriptorSetBuffer0 +{ + constant float4* uKernel [[id(0)]]; + texture2d uGammaLUT [[id(1)]]; + texture2d uSource [[id(2)]]; + constant float2* uSourceSize [[id(3)]]; + sampler uSourceSmplr [[id(4)]]; + sampler uGammaLUTSmplr [[id(5)]]; + constant int* uGammaCorrectionEnabled [[id(6)]]; + constant float4* uBGColor [[id(7)]]; + constant float4* uFGColor [[id(8)]]; +}; + struct main0_out { float4 oFragColor [[color(0)]]; @@ -78,42 +92,42 @@ float3 gammaCorrect(thread const float3& bgColor, thread const float3& fgColor, return float3(gammaCorrectChannel(param, param_1, uGammaLUT, uGammaLUTSmplr), gammaCorrectChannel(param_2, param_3, uGammaLUT, uGammaLUTSmplr), gammaCorrectChannel(param_4, param_5, uGammaLUT, uGammaLUTSmplr)); } -fragment main0_out main0(main0_in in [[stage_in]], int uGammaCorrectionEnabled [[buffer(2)]], float4 uKernel [[buffer(0)]], float2 uSourceSize [[buffer(1)]], float4 uBGColor [[buffer(3)]], float4 uFGColor [[buffer(4)]], texture2d uGammaLUT [[texture(0)]], texture2d uSource [[texture(0)]], sampler uGammaLUTSmplr [[sampler(0)]], sampler uSourceSmplr [[sampler(0)]]) +fragment main0_out main0(main0_in in [[stage_in]], constant spvDescriptorSetBuffer0& spvDescriptorSet0 [[buffer(0)]]) { main0_out out = {}; float3 alpha; - if (uKernel.w == 0.0) + if ((*spvDescriptorSet0.uKernel).w == 0.0) { - alpha = uSource.sample(uSourceSmplr, in.vTexCoord).xxx; + alpha = spvDescriptorSet0.uSource.sample(spvDescriptorSet0.uSourceSmplr, in.vTexCoord).xxx; } else { - float param_3 = 1.0 / uSourceSize.x; + float param_3 = 1.0 / (*spvDescriptorSet0.uSourceSize).x; float4 param; float param_1; float4 param_2; - sample9Tap(param, param_1, param_2, param_3, uKernel, uSource, uSourceSmplr, in.vTexCoord); + sample9Tap(param, param_1, param_2, param_3, (*spvDescriptorSet0.uKernel), spvDescriptorSet0.uSource, spvDescriptorSet0.uSourceSmplr, in.vTexCoord); float4 alphaLeft = param; float alphaCenter = param_1; float4 alphaRight = param_2; float4 param_4 = alphaLeft; float3 param_5 = float3(alphaCenter, alphaRight.xy); - float r = convolve7Tap(param_4, param_5, uKernel); + float r = convolve7Tap(param_4, param_5, (*spvDescriptorSet0.uKernel)); float4 param_6 = float4(alphaLeft.yzw, alphaCenter); float3 param_7 = alphaRight.xyz; - float g = convolve7Tap(param_6, param_7, uKernel); + float g = convolve7Tap(param_6, param_7, (*spvDescriptorSet0.uKernel)); float4 param_8 = float4(alphaLeft.zw, alphaCenter, alphaRight.x); float3 param_9 = alphaRight.yzw; - float b = convolve7Tap(param_8, param_9, uKernel); + float b = convolve7Tap(param_8, param_9, (*spvDescriptorSet0.uKernel)); alpha = float3(r, g, b); } - if (uGammaCorrectionEnabled != 0) + if ((*spvDescriptorSet0.uGammaCorrectionEnabled) != 0) { - float3 param_10 = uBGColor.xyz; + float3 param_10 = (*spvDescriptorSet0.uBGColor).xyz; float3 param_11 = alpha; - alpha = gammaCorrect(param_10, param_11, uGammaLUT, uGammaLUTSmplr); + alpha = gammaCorrect(param_10, param_11, spvDescriptorSet0.uGammaLUT, spvDescriptorSet0.uGammaLUTSmplr); } - out.oFragColor = float4(mix(uBGColor.xyz, uFGColor.xyz, alpha), 1.0); + out.oFragColor = float4(mix((*spvDescriptorSet0.uBGColor).xyz, (*spvDescriptorSet0.uFGColor).xyz, alpha), 1.0); return out; } diff --git a/resources/shaders/metal/post.vs.metal b/resources/shaders/metal/post.vs.metal index a960ca1b..0fcc0bf6 100644 --- a/resources/shaders/metal/post.vs.metal +++ b/resources/shaders/metal/post.vs.metal @@ -1,3 +1,4 @@ +// Automatically generated from files in pathfinder/shaders/. Do not edit! #include #include @@ -11,14 +12,14 @@ struct main0_out struct main0_in { - float2 aPosition [[attribute(0)]]; + int2 aPosition [[attribute(0)]]; }; -vertex main0_out main0(main0_in in [[stage_in]], uint gl_VertexID [[vertex_id]], uint gl_InstanceID [[instance_id]]) +vertex main0_out main0(main0_in in [[stage_in]]) { main0_out out = {}; - out.vTexCoord = in.aPosition; - out.gl_Position = float4((in.aPosition * 2.0) - float2(1.0), 0.0, 1.0); + out.vTexCoord = float2(in.aPosition); + out.gl_Position = float4((float2(in.aPosition) * 2.0) - float2(1.0), 0.0, 1.0); return out; } diff --git a/resources/shaders/metal/reproject.fs.metal b/resources/shaders/metal/reproject.fs.metal index 3e2a2039..be9ff4dd 100644 --- a/resources/shaders/metal/reproject.fs.metal +++ b/resources/shaders/metal/reproject.fs.metal @@ -1,8 +1,16 @@ +// Automatically generated from files in pathfinder/shaders/. Do not edit! #include #include using namespace metal; +struct spvDescriptorSetBuffer0 +{ + constant float4x4* uOldTransform [[id(0)]]; + texture2d uTexture [[id(1)]]; + sampler uTextureSmplr [[id(2)]]; +}; + struct main0_out { float4 oFragColor [[color(0)]]; @@ -13,12 +21,12 @@ struct main0_in float2 vTexCoord [[user(locn0)]]; }; -fragment main0_out main0(main0_in in [[stage_in]], float4x4 uOldTransform [[buffer(0)]], texture2d uTexture [[texture(0)]], sampler uTextureSmplr [[sampler(0)]]) +fragment main0_out main0(main0_in in [[stage_in]], constant spvDescriptorSetBuffer0& spvDescriptorSet0 [[buffer(0)]]) { main0_out out = {}; - float4 normTexCoord = uOldTransform * float4(in.vTexCoord, 0.0, 1.0); + float4 normTexCoord = (*spvDescriptorSet0.uOldTransform) * float4(in.vTexCoord, 0.0, 1.0); float2 texCoord = ((normTexCoord.xy / float2(normTexCoord.w)) + float2(1.0)) * 0.5; - out.oFragColor = uTexture.sample(uTextureSmplr, texCoord); + out.oFragColor = spvDescriptorSet0.uTexture.sample(spvDescriptorSet0.uTextureSmplr, texCoord); return out; } diff --git a/resources/shaders/metal/reproject.vs.metal b/resources/shaders/metal/reproject.vs.metal index d125c376..3bdc9034 100644 --- a/resources/shaders/metal/reproject.vs.metal +++ b/resources/shaders/metal/reproject.vs.metal @@ -1,8 +1,14 @@ +// Automatically generated from files in pathfinder/shaders/. Do not edit! #include #include using namespace metal; +struct spvDescriptorSetBuffer0 +{ + constant float4x4* uNewTransform [[id(0)]]; +}; + struct main0_out { float2 vTexCoord [[user(locn0)]]; @@ -11,14 +17,16 @@ struct main0_out struct main0_in { - float2 aPosition [[attribute(0)]]; + int2 aPosition [[attribute(0)]]; }; -vertex main0_out main0(main0_in in [[stage_in]], float4x4 uNewTransform [[buffer(0)]], uint gl_VertexID [[vertex_id]], uint gl_InstanceID [[instance_id]]) +vertex main0_out main0(main0_in in [[stage_in]], constant spvDescriptorSetBuffer0& spvDescriptorSet0 [[buffer(0)]]) { main0_out out = {}; - out.vTexCoord = in.aPosition; - out.gl_Position = uNewTransform * float4(in.aPosition, 0.0, 1.0); + float2 position = float2(in.aPosition); + out.vTexCoord = position; + position.y = 1.0 - position.y; + out.gl_Position = (*spvDescriptorSet0.uNewTransform) * float4(position, 0.0, 1.0); return out; } diff --git a/resources/shaders/metal/stencil.fs.metal b/resources/shaders/metal/stencil.fs.metal index 426311ef..999cc7e1 100644 --- a/resources/shaders/metal/stencil.fs.metal +++ b/resources/shaders/metal/stencil.fs.metal @@ -1,3 +1,4 @@ +// Automatically generated from files in pathfinder/shaders/. Do not edit! #include #include diff --git a/resources/shaders/metal/stencil.vs.metal b/resources/shaders/metal/stencil.vs.metal index 2dc23a5d..6b6182d4 100644 --- a/resources/shaders/metal/stencil.vs.metal +++ b/resources/shaders/metal/stencil.vs.metal @@ -1,3 +1,4 @@ +// Automatically generated from files in pathfinder/shaders/. Do not edit! #include #include @@ -13,7 +14,7 @@ struct main0_in float3 aPosition [[attribute(0)]]; }; -vertex main0_out main0(main0_in in [[stage_in]], uint gl_VertexID [[vertex_id]], uint gl_InstanceID [[instance_id]]) +vertex main0_out main0(main0_in in [[stage_in]]) { main0_out out = {}; out.gl_Position = float4(in.aPosition, 1.0); diff --git a/resources/shaders/metal/tile_alpha.fs.metal b/resources/shaders/metal/tile_alpha.fs.metal index 30afe4cd..2e72b19e 100644 --- a/resources/shaders/metal/tile_alpha.fs.metal +++ b/resources/shaders/metal/tile_alpha.fs.metal @@ -1,8 +1,15 @@ +// Automatically generated from files in pathfinder/shaders/. Do not edit! #include #include using namespace metal; +struct spvDescriptorSetBuffer0 +{ + texture2d uStencilTexture [[id(0)]]; + sampler uStencilTextureSmplr [[id(1)]]; +}; + struct main0_out { float4 oFragColor [[color(0)]]; @@ -15,10 +22,10 @@ struct main0_in float4 vColor [[user(locn2)]]; }; -fragment main0_out main0(main0_in in [[stage_in]], texture2d uStencilTexture [[texture(0)]], sampler uStencilTextureSmplr [[sampler(0)]]) +fragment main0_out main0(main0_in in [[stage_in]], constant spvDescriptorSetBuffer0& spvDescriptorSet0 [[buffer(0)]]) { main0_out out = {}; - float coverage = abs(uStencilTexture.sample(uStencilTextureSmplr, in.vTexCoord).x + in.vBackdrop); + float coverage = abs(spvDescriptorSet0.uStencilTexture.sample(spvDescriptorSet0.uStencilTextureSmplr, in.vTexCoord).x + in.vBackdrop); out.oFragColor = float4(in.vColor.xyz, in.vColor.w * coverage); return out; } diff --git a/resources/shaders/metal/tile_alpha_monochrome.vs.metal b/resources/shaders/metal/tile_alpha_monochrome.vs.metal index e92a3af0..9c9e1b56 100644 --- a/resources/shaders/metal/tile_alpha_monochrome.vs.metal +++ b/resources/shaders/metal/tile_alpha_monochrome.vs.metal @@ -1,3 +1,4 @@ +// Automatically generated from files in pathfinder/shaders/. Do not edit! #pragma clang diagnostic ignored "-Wmissing-prototypes" #include @@ -5,6 +6,15 @@ using namespace metal; +struct spvDescriptorSetBuffer0 +{ + constant float2* uTileSize [[id(0)]]; + constant float2* uViewBoxOrigin [[id(1)]]; + constant float2* uFramebufferSize [[id(2)]]; + constant float2* uStencilTextureSize [[id(3)]]; + constant float4* uColor [[id(4)]]; +}; + struct main0_out { float2 vTexCoord [[user(locn0)]]; @@ -15,10 +25,10 @@ struct main0_out struct main0_in { - float2 aTessCoord [[attribute(0)]]; + uint2 aTessCoord [[attribute(0)]]; uint3 aTileOrigin [[attribute(1)]]; int aBackdrop [[attribute(2)]]; - uint aTileIndex [[attribute(3)]]; + int aTileIndex [[attribute(3)]]; }; float2 computeTileOffset(thread const uint& tileIndex, thread const float& stencilTextureWidth, thread float2 uTileSize) @@ -33,25 +43,25 @@ float4 getColor(thread float4 uColor) return uColor; } -void computeVaryings(thread float2 uTileSize, thread uint3& aTileOrigin, thread float2& aTessCoord, thread float2 uViewBoxOrigin, thread float2 uFramebufferSize, thread uint& aTileIndex, thread float2 uStencilTextureSize, thread float2& vTexCoord, thread float& vBackdrop, thread int& aBackdrop, thread float4& vColor, thread float4& gl_Position, thread float4 uColor) +void computeVaryings(thread float2 uTileSize, thread uint3& aTileOrigin, thread uint2& aTessCoord, thread float2 uViewBoxOrigin, thread float2 uFramebufferSize, thread int& aTileIndex, thread float2 uStencilTextureSize, thread float2& vTexCoord, thread float& vBackdrop, thread int& aBackdrop, thread float4& vColor, thread float4& gl_Position, thread float4 uColor) { float2 origin = float2(aTileOrigin.xy) + (float2(float(aTileOrigin.z & 15u), float(aTileOrigin.z >> 4u)) * 256.0); - float2 pixelPosition = ((origin + aTessCoord) * uTileSize) + uViewBoxOrigin; + float2 pixelPosition = ((origin + float2(aTessCoord)) * uTileSize) + uViewBoxOrigin; float2 position = (((pixelPosition / uFramebufferSize) * 2.0) - float2(1.0)) * float2(1.0, -1.0); - uint param = aTileIndex; + uint param = uint(aTileIndex); float param_1 = uStencilTextureSize.x; float2 maskTexCoordOrigin = computeTileOffset(param, param_1, uTileSize); - float2 maskTexCoord = maskTexCoordOrigin + (aTessCoord * uTileSize); + float2 maskTexCoord = maskTexCoordOrigin + (float2(aTessCoord) * uTileSize); vTexCoord = maskTexCoord / uStencilTextureSize; vBackdrop = float(aBackdrop); vColor = getColor(uColor); gl_Position = float4(position, 0.0, 1.0); } -vertex main0_out main0(main0_in in [[stage_in]], float2 uTileSize [[buffer(0)]], float2 uViewBoxOrigin [[buffer(1)]], float2 uFramebufferSize [[buffer(2)]], float2 uStencilTextureSize [[buffer(3)]], float4 uColor [[buffer(4)]], uint gl_VertexID [[vertex_id]], uint gl_InstanceID [[instance_id]]) +vertex main0_out main0(main0_in in [[stage_in]], constant spvDescriptorSetBuffer0& spvDescriptorSet0 [[buffer(0)]]) { main0_out out = {}; - computeVaryings(uTileSize, in.aTileOrigin, in.aTessCoord, uViewBoxOrigin, uFramebufferSize, in.aTileIndex, uStencilTextureSize, out.vTexCoord, out.vBackdrop, in.aBackdrop, out.vColor, out.gl_Position, uColor); + computeVaryings((*spvDescriptorSet0.uTileSize), in.aTileOrigin, in.aTessCoord, (*spvDescriptorSet0.uViewBoxOrigin), (*spvDescriptorSet0.uFramebufferSize), in.aTileIndex, (*spvDescriptorSet0.uStencilTextureSize), out.vTexCoord, out.vBackdrop, in.aBackdrop, out.vColor, out.gl_Position, (*spvDescriptorSet0.uColor)); return out; } diff --git a/resources/shaders/metal/tile_alpha_multicolor.vs.metal b/resources/shaders/metal/tile_alpha_multicolor.vs.metal index 525d7fe3..bc25f729 100644 --- a/resources/shaders/metal/tile_alpha_multicolor.vs.metal +++ b/resources/shaders/metal/tile_alpha_multicolor.vs.metal @@ -1,3 +1,4 @@ +// Automatically generated from files in pathfinder/shaders/. Do not edit! #pragma clang diagnostic ignored "-Wmissing-prototypes" #include @@ -5,6 +6,16 @@ using namespace metal; +struct spvDescriptorSetBuffer0 +{ + constant float2* uTileSize [[id(0)]]; + texture2d uPaintTexture [[id(1)]]; + constant float2* uViewBoxOrigin [[id(2)]]; + sampler uPaintTextureSmplr [[id(3)]]; + constant float2* uFramebufferSize [[id(4)]]; + constant float2* uStencilTextureSize [[id(5)]]; +}; + struct main0_out { float2 vTexCoord [[user(locn0)]]; @@ -15,10 +26,10 @@ struct main0_out struct main0_in { - float2 aTessCoord [[attribute(0)]]; + uint2 aTessCoord [[attribute(0)]]; uint3 aTileOrigin [[attribute(1)]]; int aBackdrop [[attribute(2)]]; - uint aTileIndex [[attribute(3)]]; + int aTileIndex [[attribute(3)]]; float2 aColorTexCoord [[attribute(4)]]; }; @@ -34,25 +45,25 @@ float4 getColor(thread texture2d uPaintTexture, thread const sampler uPai return uPaintTexture.sample(uPaintTextureSmplr, aColorTexCoord, level(0.0)); } -void computeVaryings(thread float2 uTileSize, thread uint3& aTileOrigin, thread float2& aTessCoord, thread float2 uViewBoxOrigin, thread float2 uFramebufferSize, thread uint& aTileIndex, thread float2 uStencilTextureSize, thread float2& vTexCoord, thread float& vBackdrop, thread int& aBackdrop, thread float4& vColor, thread float4& gl_Position, thread texture2d uPaintTexture, thread const sampler uPaintTextureSmplr, thread float2& aColorTexCoord) +void computeVaryings(thread float2 uTileSize, thread uint3& aTileOrigin, thread uint2& aTessCoord, thread float2 uViewBoxOrigin, thread float2 uFramebufferSize, thread int& aTileIndex, thread float2 uStencilTextureSize, thread float2& vTexCoord, thread float& vBackdrop, thread int& aBackdrop, thread float4& vColor, thread float4& gl_Position, thread texture2d uPaintTexture, thread const sampler uPaintTextureSmplr, thread float2& aColorTexCoord) { float2 origin = float2(aTileOrigin.xy) + (float2(float(aTileOrigin.z & 15u), float(aTileOrigin.z >> 4u)) * 256.0); - float2 pixelPosition = ((origin + aTessCoord) * uTileSize) + uViewBoxOrigin; + float2 pixelPosition = ((origin + float2(aTessCoord)) * uTileSize) + uViewBoxOrigin; float2 position = (((pixelPosition / uFramebufferSize) * 2.0) - float2(1.0)) * float2(1.0, -1.0); - uint param = aTileIndex; + uint param = uint(aTileIndex); float param_1 = uStencilTextureSize.x; float2 maskTexCoordOrigin = computeTileOffset(param, param_1, uTileSize); - float2 maskTexCoord = maskTexCoordOrigin + (aTessCoord * uTileSize); + float2 maskTexCoord = maskTexCoordOrigin + (float2(aTessCoord) * uTileSize); vTexCoord = maskTexCoord / uStencilTextureSize; vBackdrop = float(aBackdrop); vColor = getColor(uPaintTexture, uPaintTextureSmplr, aColorTexCoord); gl_Position = float4(position, 0.0, 1.0); } -vertex main0_out main0(main0_in in [[stage_in]], float2 uTileSize [[buffer(0)]], float2 uViewBoxOrigin [[buffer(1)]], float2 uFramebufferSize [[buffer(2)]], float2 uStencilTextureSize [[buffer(3)]], texture2d uPaintTexture [[texture(0)]], sampler uPaintTextureSmplr [[sampler(0)]], uint gl_VertexID [[vertex_id]], uint gl_InstanceID [[instance_id]]) +vertex main0_out main0(main0_in in [[stage_in]], constant spvDescriptorSetBuffer0& spvDescriptorSet0 [[buffer(0)]]) { main0_out out = {}; - computeVaryings(uTileSize, in.aTileOrigin, in.aTessCoord, uViewBoxOrigin, uFramebufferSize, in.aTileIndex, uStencilTextureSize, out.vTexCoord, out.vBackdrop, in.aBackdrop, out.vColor, out.gl_Position, uPaintTexture, uPaintTextureSmplr, in.aColorTexCoord); + computeVaryings((*spvDescriptorSet0.uTileSize), in.aTileOrigin, in.aTessCoord, (*spvDescriptorSet0.uViewBoxOrigin), (*spvDescriptorSet0.uFramebufferSize), in.aTileIndex, (*spvDescriptorSet0.uStencilTextureSize), out.vTexCoord, out.vBackdrop, in.aBackdrop, out.vColor, out.gl_Position, spvDescriptorSet0.uPaintTexture, spvDescriptorSet0.uPaintTextureSmplr, in.aColorTexCoord); return out; } diff --git a/resources/shaders/metal/tile_solid.fs.metal b/resources/shaders/metal/tile_solid.fs.metal index fed4023d..ac500c97 100644 --- a/resources/shaders/metal/tile_solid.fs.metal +++ b/resources/shaders/metal/tile_solid.fs.metal @@ -1,3 +1,4 @@ +// Automatically generated from files in pathfinder/shaders/. Do not edit! #include #include diff --git a/resources/shaders/metal/tile_solid_monochrome.vs.metal b/resources/shaders/metal/tile_solid_monochrome.vs.metal index 83410055..46328863 100644 --- a/resources/shaders/metal/tile_solid_monochrome.vs.metal +++ b/resources/shaders/metal/tile_solid_monochrome.vs.metal @@ -1,3 +1,4 @@ +// Automatically generated from files in pathfinder/shaders/. Do not edit! #pragma clang diagnostic ignored "-Wmissing-prototypes" #include @@ -5,6 +6,14 @@ using namespace metal; +struct spvDescriptorSetBuffer0 +{ + constant float2* uTileSize [[id(0)]]; + constant float2* uViewBoxOrigin [[id(1)]]; + constant float2* uFramebufferSize [[id(2)]]; + constant float4* uColor [[id(3)]]; +}; + struct main0_out { float4 vColor [[user(locn0)]]; @@ -13,8 +22,8 @@ struct main0_out struct main0_in { - float2 aTessCoord [[attribute(0)]]; - float2 aTileOrigin [[attribute(1)]]; + uint2 aTessCoord [[attribute(0)]]; + int2 aTileOrigin [[attribute(1)]]; }; float4 getColor(thread float4 uColor) @@ -22,18 +31,18 @@ float4 getColor(thread float4 uColor) return uColor; } -void computeVaryings(thread float2& aTileOrigin, thread float2& aTessCoord, thread float2 uTileSize, thread float2 uViewBoxOrigin, thread float2 uFramebufferSize, thread float4& vColor, thread float4& gl_Position, thread float4 uColor) +void computeVaryings(thread int2& aTileOrigin, thread uint2& aTessCoord, thread float2 uTileSize, thread float2 uViewBoxOrigin, thread float2 uFramebufferSize, thread float4& vColor, thread float4& gl_Position, thread float4 uColor) { - float2 pixelPosition = ((aTileOrigin + aTessCoord) * uTileSize) + uViewBoxOrigin; + float2 pixelPosition = (float2(aTileOrigin + int2(aTessCoord)) * uTileSize) + uViewBoxOrigin; float2 position = (((pixelPosition / uFramebufferSize) * 2.0) - float2(1.0)) * float2(1.0, -1.0); vColor = getColor(uColor); gl_Position = float4(position, 0.0, 1.0); } -vertex main0_out main0(main0_in in [[stage_in]], float2 uTileSize [[buffer(0)]], float2 uViewBoxOrigin [[buffer(1)]], float2 uFramebufferSize [[buffer(2)]], float4 uColor [[buffer(3)]], uint gl_VertexID [[vertex_id]], uint gl_InstanceID [[instance_id]]) +vertex main0_out main0(main0_in in [[stage_in]], constant spvDescriptorSetBuffer0& spvDescriptorSet0 [[buffer(0)]]) { main0_out out = {}; - computeVaryings(in.aTileOrigin, in.aTessCoord, uTileSize, uViewBoxOrigin, uFramebufferSize, out.vColor, out.gl_Position, uColor); + computeVaryings(in.aTileOrigin, in.aTessCoord, (*spvDescriptorSet0.uTileSize), (*spvDescriptorSet0.uViewBoxOrigin), (*spvDescriptorSet0.uFramebufferSize), out.vColor, out.gl_Position, (*spvDescriptorSet0.uColor)); return out; } diff --git a/resources/shaders/metal/tile_solid_multicolor.vs.metal b/resources/shaders/metal/tile_solid_multicolor.vs.metal index 3f5d0c45..edfe17d0 100644 --- a/resources/shaders/metal/tile_solid_multicolor.vs.metal +++ b/resources/shaders/metal/tile_solid_multicolor.vs.metal @@ -1,3 +1,4 @@ +// Automatically generated from files in pathfinder/shaders/. Do not edit! #pragma clang diagnostic ignored "-Wmissing-prototypes" #include @@ -5,6 +6,15 @@ using namespace metal; +struct spvDescriptorSetBuffer0 +{ + constant float2* uTileSize [[id(0)]]; + texture2d uPaintTexture [[id(1)]]; + constant float2* uViewBoxOrigin [[id(2)]]; + sampler uPaintTextureSmplr [[id(3)]]; + constant float2* uFramebufferSize [[id(4)]]; +}; + struct main0_out { float4 vColor [[user(locn0)]]; @@ -13,8 +23,8 @@ struct main0_out struct main0_in { - float2 aTessCoord [[attribute(0)]]; - float2 aTileOrigin [[attribute(1)]]; + uint2 aTessCoord [[attribute(0)]]; + int2 aTileOrigin [[attribute(1)]]; float2 aColorTexCoord [[attribute(2)]]; }; @@ -23,18 +33,18 @@ float4 getColor(thread texture2d uPaintTexture, thread const sampler uPai return uPaintTexture.sample(uPaintTextureSmplr, aColorTexCoord, level(0.0)); } -void computeVaryings(thread float2& aTileOrigin, thread float2& aTessCoord, thread float2 uTileSize, thread float2 uViewBoxOrigin, thread float2 uFramebufferSize, thread float4& vColor, thread float4& gl_Position, thread texture2d uPaintTexture, thread const sampler uPaintTextureSmplr, thread float2& aColorTexCoord) +void computeVaryings(thread int2& aTileOrigin, thread uint2& aTessCoord, thread float2 uTileSize, thread float2 uViewBoxOrigin, thread float2 uFramebufferSize, thread float4& vColor, thread float4& gl_Position, thread texture2d uPaintTexture, thread const sampler uPaintTextureSmplr, thread float2& aColorTexCoord) { - float2 pixelPosition = ((aTileOrigin + aTessCoord) * uTileSize) + uViewBoxOrigin; + float2 pixelPosition = (float2(aTileOrigin + int2(aTessCoord)) * uTileSize) + uViewBoxOrigin; float2 position = (((pixelPosition / uFramebufferSize) * 2.0) - float2(1.0)) * float2(1.0, -1.0); vColor = getColor(uPaintTexture, uPaintTextureSmplr, aColorTexCoord); gl_Position = float4(position, 0.0, 1.0); } -vertex main0_out main0(main0_in in [[stage_in]], float2 uTileSize [[buffer(0)]], float2 uViewBoxOrigin [[buffer(1)]], float2 uFramebufferSize [[buffer(2)]], texture2d uPaintTexture [[texture(0)]], sampler uPaintTextureSmplr [[sampler(0)]], uint gl_VertexID [[vertex_id]], uint gl_InstanceID [[instance_id]]) +vertex main0_out main0(main0_in in [[stage_in]], constant spvDescriptorSetBuffer0& spvDescriptorSet0 [[buffer(0)]]) { main0_out out = {}; - computeVaryings(in.aTileOrigin, in.aTessCoord, uTileSize, uViewBoxOrigin, uFramebufferSize, out.vColor, out.gl_Position, uPaintTexture, uPaintTextureSmplr, in.aColorTexCoord); + computeVaryings(in.aTileOrigin, in.aTessCoord, (*spvDescriptorSet0.uTileSize), (*spvDescriptorSet0.uViewBoxOrigin), (*spvDescriptorSet0.uFramebufferSize), out.vColor, out.gl_Position, spvDescriptorSet0.uPaintTexture, spvDescriptorSet0.uPaintTextureSmplr, in.aColorTexCoord); return out; } diff --git a/resources/shaders/spirv/debug_solid.fs.spv b/resources/shaders/spirv/debug_solid.fs.spv deleted file mode 100644 index ae1e7b85c0fe2cea57566e63c24cfbb86f9bed24..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 644 zcmZ9J%}N775QM+|ne1vbKgJ~LL82ao;6X(Y6%hh=k+2;)lNWd zSa!Oqrn|Z)OLq!LC@9&WiZ&?;P^aeqXnZ#wzP{ZL_Yd}@XpmVbO_Lfq_O)7pd*491o%H=_!dP}jM^tf+_DFHZ%-j`$lYfATSfHC0;y^VH$OR$%g->r%{){dC8b8IDI wx_d+6c{_ejtQW7j&I$J1k3KYuylKa4-U)mXe19EWL-;9~_bTk0gd-Au07NDmivR!s diff --git a/resources/shaders/spirv/debug_solid.vs.spv b/resources/shaders/spirv/debug_solid.vs.spv deleted file mode 100644 index 0c94d0dfa07e41bf550045bc9e8cbd4649547308..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1252 zcmZ9LOKTKS5QV>fN27@`Ch-wtVthw~3l%|p;ovwSi-CaKVbsph(3ymp4u~5CH?I7> zZUi~ib%}a6Gw0N~Ri~$hi!R>OsGpye}tB`B{AKypCcaTTWqm`8U2AHz8Mu$?vEhys4|B zPBm?Yi(qk7OAw|9CSpi64~tl7;LtC#=rb&tOzGk-do zgHGVuy=Y@6oV-e>t#nE3t~k||N5wM7@+X`Fi^Qheunl4Vmq{$P4y=$;xK{brNtprT z#0#HxFT&3pE5H0He%AemxUhQH*&?-C3oU#V@S@>wFI9ip>+5|jk+NcW+ata3MX$F? z$|cu}Tk|=F9E!=)6`z&fj64hLy=s1{an)<62h|V`y9zb0xd-Lbtiqf^54Zk`-|^h? zA^kn~tGuc&tUak-z}l1W6Ed5<`qz=iU&OXgX|)f1fvW%9_jSg19Pqr){D*x-a1Kl( z{-<;2o!2h<&RwuKqIUw{om&FaD)xfJYKwbKW^>qZKbnu~>z(Ociw~Mj*JwvUa|4Y3 l>UVB}aeWG#+ilMyUbB@a<ADVp!(nCcM6(J;qP@&NC1uq&{6E_VXd+D{mx0fJ( zd(OnI4a1zZ&f5Fzz0Rr1jRp!D2HdBMc}fakhN<{(@9geuem&mbeDwICidm`zA=iVm8;)Z}oGz zcX{<AdMz3FqJMZ+D^Iqpc3a@-YeZJo5 zp`87A7iz`UbA2;ve1G|bI_9!hL(MNr>fDRo`j-4ZCxu7nAp8;Q!F-a>X>0Q&*^N|vac%;{EwV>6(U#u1y%GS*Xw-)_9u3J-;v(EWe{_3WUhZ- z-jVm%_jLbhN38l3OFEwIHPq!V`7{Fp<-Axfw*m|Jerr3mb|uxxY5LoEB{_M zCgykF{bcwy^xS*y@SXELqUusjs;H(ht*AUxs;VMsT&ewSY;JAV2g9BE%JauCCKMSF z&ZNfecPweIo%aBztX8@pX-U#kNzWujid2>Ku_7gkkJThftnTY}cCgy-7dwKJSoij^ zSgHw0qwVZqI4ZKO{9DFMxaTG9_Xqhf@7o^4*rDA#3?`~+n)>yky_bC+?e1p9VUJXc zk~-a1Gb=u2#V|Xdcj|EtxzH_D&G_hG@w_(-y+V%rcDk+AZoa>k4~FgDmrRKw(}ly1 z=+o)8%7GheN|c&joo;KRSJrH-NopuIjpnVg#HbHu2l8lh65lw&M~|cRXmJt;{s$#? zKTheg{>RGqQO*rK?h23B(NJWy#Mp~Fl1m)(9>A%+ldAC+?S;sG&nU9of}~l+syUZ_ z3yL-7bBMok%)4VY`P05z$b*^3-sI1^CLs?-I}Z6N$#Nl2J=#&vJosqGSypVjUMk_c zfUg+-@s|Cs`Tl$-(~3=V?#6+S2iLv-oMOwN4Y7ImA@rb*9r20#@@Cly%=bo&88?kr z?#vAEtrIhEJEq?qzcX{g9UdOZKl0w}0so2jrZ4ls_#89><1_e$67!DxbJ+2Zs`ehJ zMQ^@e^nUGrpK;Fuo^+3X*;g!`lZ-?BjUw}(Sm0lD&jOxt&qDpIWE|qZz2{|nZ!#~N z9=j@;m-zY9V{?*m$uXPViM>~1I^OmBpfB^$^qyq#z`5@nJPw>?$>QI==7D)3HB~d+ d>)wYr-mnw>@P>cR_>afz1cv`t6}?nN{{UeyW4izV diff --git a/resources/shaders/spirv/demo_ground.fs.spv b/resources/shaders/spirv/demo_ground.fs.spv deleted file mode 100644 index 8dc291cf6243e259735c00dfc7669a8d0318a52b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 908 zcmY+CNlF7z6h%+s-9J1!P{t&YB`T**Mhvze zI{kqH-S(?;66^DF>m&uIzWL>_bJxu8 z^P#wuRp7Zb?04_`gIZiS4zAJym{Ka_X3rmx3X_wf} znz#AiF7`;Q?*bSnevXia_g=JbF}HfJxNe=P-oo-jtHh-jnyt`SyoX~F)2KPMG|vwq ziP!2~=-#FC%zdf(`>Bx{KjFINiDG5mr00EmUESU#yt}?Buv+owM0Sq2vVP9b{vt8W zOXdUS%LlRfu?)tmM*7!WdxdO5|YPEVFimQj}G?VT~{4W6~1pEQm Ce>2qp diff --git a/resources/shaders/spirv/demo_ground.vs.spv b/resources/shaders/spirv/demo_ground.vs.spv deleted file mode 100644 index 0a0926a6f5d4eb63a7dd54289b2eec8f02bc7e27..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1328 zcmY+CU279z5QR^&`);b$)>`|a*4kRXtHBEuK~yAxSm{Ne#oG|f8Wy&@l5C}TW=Htw~QG2f=wbapqx~gqOZM7sVDzWe2@aV8RuO{8+FP_0zQe;Fp z%erX)v80o6Rsb$ou5?|}6G=}cMT*px^syxc#sBexg5`WWPS1K}IhzPh(4wUAu$*UA zR#G@9(Xyn|!7Q8PS&{b2)1s>V8U`Gr#$>qB_dH zr*%#pW7cUt>gCzjem1Yh#phH(k!ix1?-sKh&&I|4OF28KedwL$qk4#gzRisOX+AnA z>N*E~Ndv{EdE2Vh7`^8)TEWZ-AAHC89~Ay+BM)nQ_3i4s#)lqwTyCJqa`90Y9q0Rk zn?A(RL~d|CdccXKRkf|ou3cF6zplt)JCZgOtK(ey?I_lQ&w>B7W8Mt25$8prp^1a( zhi^@>E*r1L@RwXae(HhQ6-NJ6@6Q`0|C;Ax`;OPV-j-smJ0IV+@42Z#jGmi5FYk_? zVBR|#sL3ohtb??vST}7~vKh$V@)&;d!R#GtX1eVdKD$IeJ15R}&*KfgZ}`VM_>X)R z<_7P3ezPMmccmu%!Q2)6Qo(M;zA!ZXR@?6X#_xH_Zvv*~72kR3v#q%Ar-I$_s$@C% z-zu_u<0GFP@cz*MUct2PdVO{P2fe&W{0-->bGTE(xhI)_sE%oW;Cbwd7(4o57tyi diff --git a/resources/shaders/spirv/fill.fs.spv b/resources/shaders/spirv/fill.fs.spv deleted file mode 100644 index 4cb3b288627ff14dc30c22142e38799cca4cf7e0..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2688 zcmZveX>(Ln5Qd-3%_Ko0i)tNTL`u2ng;*vk(o8P68>vX<1hJSNsQl z^KbdZD(mU#u3V_ORZ}zX+sk=RpYA!g=^Pt}5yqKdlfko_4kN&J#^QT+?#kTM`o`ka ziIXquv4bWY_1Vb;qY$543#+#^Y!4q;0Cv%YZ31X$=m3{Spv&kzG2(5&a=&-W9Afj_ zof!~a8Xg2TdfFOxXuH}Azg@uE((*>dJpuGrS8hs}=Q&_=_4Zs_YM8Kv9I1te_`c9Z>`rKa7)0Q>HgBf+_kIfm`(kU3lghY zY~8e5pSIl`_v53jc}&EkEGvO9D898dgE>M`G*%&msKba*&*JPPq!9mZ*YX%P2M;b<&4UwL28b=}7| zxexoyb-s;WB6xL*t)*RgkZpXI{_1W&g%8p2J%pe6JYyd@^NFpsPwBfkfYXJ0fq$Jo zMK|`PHXk+oONVaevhVHds4uKIxi@=2f6sMaoc)&1{@icd=Kuu%H{IxqgBd4Z>pqgX z3m?in^K_%19*eW~yx}j#Vn5D~ys`SL+1kpNW@p3mXzOvNsvKwHe!2IY-io<{-|0q~(N<)^V;? zNAu}F@EP29+DpSnL-KzN!I#hc5S^E!f41uW2}GQH#a$UvTQ5ub^0_vowx2@qRom+j zaq?B$8xU)1v$p={$yMIZhxFtZ5PbQ3Iix4Qg5YcIuOZ^(UB~}YIcx9zv7C2Doy7{o z|M73x1FI06_euHu0HL?=j}UqP$e1+@;>w4(O$Fb3z%zYFYYJbck*Ms z{4e+!!dKgMx^b8GQ@^&$x%Rs6QhB$PKHrtxcj>zW;U_=Oc;ve4`_O$K>*YPI?LS61 H%?SSkKmwEa diff --git a/resources/shaders/spirv/fill.vs.spv b/resources/shaders/spirv/fill.vs.spv deleted file mode 100644 index 1ae09e95694f83f3ec9e21e5ea9bf0c9d9adc656..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3908 zcmZvf>2nli5XPVE?(Bjfh+H0sARbt16y;Ln5+nps0$IU3F3D_I-DKh(5b**L1P{D# z{XhKd7yl%WDlO~R(=9`ase;VY{k+{h-Tl7(Zn?CsCJm^jdHO~9vqU8gNLrw({T(_u zdT_AYn;6`<=^+@4R5l`<#k#@XE0U%ft!cn&Nt-3@mh_~grzMR@dP~xKl0KC5lcb*| zl~qm_x2>GXK3T~B9w{Z4wUHPJg^d?JS59Z5S!vQs8oDyff$(bnnI?XGfO?lkws zw>99oGyFdgyiRM93?!;)5PSPNjj8l_zu8PXZq~l>K}j=>PGidaRJ36Z-Xy8n$xs`g zTsHP~vZ;|-^G99{kM@tx%)%*aFEL~}pPV=9*+`y?#PZ*$XU>L`SUno`wA6^*+SnhCmuf;(hO}58|r}H(#B78o7>64z5RFb{fgkxw0p_NW7x-2k7wgZU0HeGg`DfY}4!uupD_n7sie z-u+4}Upx!!|0^=|$cj9CBFkeb+uDeOoS}>FBwygFq@^kuZ>{abJoe?Pm~M^xU89O> zlKo@N3Y9faGCjKau0ys`6`?sNak9K&Dk@8RPX zj~^fCZ*}{~!MAySh!^|d$SwN&onQ1%y?KI9y~%OJv(?VKEBJA*E%tUfH|&Aw57vi0 z`XexU`lE>H4>0x)`#ax@fBx3<@OCa!NzWGIXcg9-_8y2h!1Nh?K^$QE3{0)gd9CQt zRjTL%$Jku$Js2Ex#CE~gv;VOPW{+Z%-nnSJ{9A|}d?}Cp|8My$$GhU&zA$`dXW*}$ zkH7ETHgSM|blcd)KbRhmT!QIw@Ma~}BYYnZG5)EN?FH7-2b|yZCYZmR&w=Sz&ga1J zIiHJ|^QMS7N5R{@j~SZu-VT+`Hh8xZ>*pOZKK6QRXGC6#FgCAAZYP!+pZyqB$ zIK+=U{B801`@5Zvtd+^=-x>Gun9E}g!<2si&DU(Ve8_q{*6c7J%<{xy*(sTwT%Pay zC%o^^I%kh$Jmkbm?vRDweSSxXScfE&6=U6R=jW9*!@eeBJs_Ek{TQ)6#hs!M>p?p| zWpaG8Kc4YD7_lCbjE9_9sVg#S#eO{E_n2a>MqU1^65EqUC6lpN|4>=adEfo5is_Cq zo4p5l$2L9og7;O?_KPkL&P$TTROGxYnS7z$;G|c)@9&aqJ^F>JT3?O1jvj*-c3+jO zXR*t7gW>+AlEu${A?Dy8zecR%lF5TJagA8HS0RsBn;y@4?s$^vBi2dRksEkn_r#o7 z!ElSQl5_af>@}|$=NWb9+h2Ei)U55YsF_`UB&!)Z?mj2IX1qr%ndhNsdqy&OaNh7d z6geHq<;{~ zuaEuwiDVq)!THqB+lwCKWyyHRFT3n>dza0qIP1QYY(_Ds;`_dmjEnBD66>vRB$M-m z>|2*Hk499pIrg1oTy)Gj>{172-48xbnVEby82&#R&{hrDOym6Gw-FC_xh*Q&%;C2X z@9Z0X1JMVI3$u;iJ~6AfGw~ZIW)*v5iLZ;kS>b(CJabms9Z;4-*4*UlkWcx{yV>Q$ zk54c);68S{&%?mnGvQqF*|XL;$b-W@oEaK;ov*pzYwq;BI&x~pJ&-dHTj+>`Z$*X; h^mqIBGc(BNJuX8J=3L@VdfxluUgseHS0%&L<3E+GK#TwY diff --git a/resources/shaders/spirv/post.fs.spv b/resources/shaders/spirv/post.fs.spv deleted file mode 100644 index b6d2fec3f1e906d766194ec03a93915a9384efaf..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6864 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 diff --git a/resources/shaders/spirv/post.vs.spv b/resources/shaders/spirv/post.vs.spv deleted file mode 100644 index 6d35fb90ef6c4475e3c3396c437bdf31e41ca863..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1080 zcmY+C&1(};6vcnZ%p}!nYt^=X)Y@8I3B`qqAb!z6taK5nxDCM$VIU@w1Szfr_x`0gL*eJ=iYPgJ@34iwGX<`qRR>osAGdREnt;SeETP-Cx?sW+2P|Sk7TTo1yRmA z7vnz%K98!Y;6n7mHQ)fa4`gJtfp;w^$p7OP6w&kbLwSBQo6XOVQ?Lq*2D3%AtY!`_ z=&%8dC&NKG|5(nK<+=MhDQ{S7Iy!WNug=I<)8%RPt*m?MnwrLw;nAe}(yJEB(ezVE zK^EE#b$EvHWLPge?u8D|G@cBPr*+S959pJ}Id-G7#-5?UZz)2LVcuwRwcp;v-<;ay z>2{widd;~K~-st)$;G{7AXm5L|2T<7L7fh`iC{e1me;I-nb8 cyqmbz^uf7rD8h&ROA(@~Ep_)m0 zln~!w=j(wR7lC{6TLeD}6cluU_Z_Gx&*&>g7y}OKX0W|?vR2p4u65+k1IL^DyW7pq z!Qtn+83bQNk8eZbii!o`=*;;leAMrnoiA(ke%)BJ;-NLS_fC$En?3uiQ%0ZbajXCM z<`DKy!~5QE7+X_pCe{-VpBFD@y=l6U#d4%V{GX*@1Xu#*DCt39vt6Q$4CVahDLI$_ z+x_vZE&q}-u-Un+H<9&x1M5wuS9$ef@2LM(%IJM5&$oCw@b@>KpU?iDpP}SxdUvT8 zUyFA??PoUao!WZ0PwPj$yQx*9AF&xbX$y>TKmF@(c(r(uf(H;f{jH`*&U#|s!1bIe zaxgoWJ^s+8O0DziJhooEtFtA3mDyi_$X9FzQ<>j~m|D1;oU7$#lGF1Ry{I>vTKCM` zjDJ(b-W)_9HLoeclbk*EawUCk(hCoZ$;rFy^Oh>IzmZzs#PjW}$!}4`dFRvl^ZS{c zGi+V=THQ+e)a#Gb-O71)?^kknAb8(d|7Iv>f8XU%zDb*5KXd++_kWxkdCxl!a)0UY Hf)4)xUq?Rb diff --git a/resources/shaders/spirv/reproject.vs.spv b/resources/shaders/spirv/reproject.vs.spv deleted file mode 100644 index 9b39096ee1e45cf70d82df2665effa6796fd5f90..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1144 zcmZ9KU279z5QU#)cav(hwQ4`qT3f5$2*nE(K~$uLS}9U#@iqjzhJ`edBx>=>zu>?1 zMv!OrT}0<*_spD`IWzNS?d>kK=rYFxYFnaB3z(-9-~Gem!=35ubm#GtM=}=3f+%N^ zi}9ZWXZ>msSquFuwy{vQUn3@K|-tMsayjM+U{n5vg zf-JOa_FMzLyeq$*O!}kgr}5-0>2tQhuvZH?*bA<+4u-vhQC;g`57;M<`8J|rjh(H* zZzw{ireAA(^&Py>U!R)gd4+wl$kk^bwKjDdd^gn;tJ&Nl@zpEt#J$>4XDhBn{I8Hj zY!g@|r<=I;+azZ$>Cpc?VehXtQIpuWs3v<{Pd(IN5Aky9xkkedN5Rhq_`oKT_~QGp{+k!u;s6VxwDv6yExhKt+JxS31Tvrlyc5Ymy=CbTOJAf<%ieNX u@;*^)Rr}AgdtWR42IQK11~H~v8UI0&zxmj)eHT0l_#()|=KgVf;{EttH~45PYywC@Nwgru3mw=xYdd2@C61l6@#X`Dgng zlrwj>;=JU}nKLuzo}10m*CiyB3^*djE-4AHL1Dks^UL$`y8AwUcl=h2EixmDv&{oL z=fICe-70wmJO&Pdmq12F3Y;Yn$p7O83O0acGry=-SJkSkZZ)HDT%p>{y6)OG#4GXSe8-gvGTlfFZ89y(vxk>9JIq1uR?P1i0Rr=IJLbsz26@*SF~ z9m=r zC;6d}hCig{?+0?zF!cT3?8S8_c^#w2_8im99@}?JZ+Ss!`kr~e_^Rt3p9yw{=l*TT Pn~!9ci~pB|6B6zKMX@=L diff --git a/resources/shaders/spirv/tile_alpha.fs.spv b/resources/shaders/spirv/tile_alpha.fs.spv deleted file mode 100644 index 006cb101c9179314bb137408f2377daa8ff4a5dd..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1140 zcmZ9K-Afc<6vltMGqby9X=Z9>ADVp|(nUoO1tlbeP@&NEvO9=mPHgMqZ5RE|-30MF z^Nwu2Fw8vXJaf)-p7&(!%`UX)(&GvBS)fe|n57f%-M#(2?H}Xe_Os_tWz3NUQO-Ow zU)Z*qk2E;AMRAg)u`^Pu1UhX-r!uFo#JFi$ztY^>Zy#2(^zDPUX8{tMBTPC9etjCkng?NmuGQ$kSxAmt_ zgV)Ho0Kr=)XEu?Hy-HXgJuBqQrF!a-KcBQ4moIik>&w5A_}=vrIaiZb&sM@qf$DlI z>0k9*Ppn7Qv)_%_1){Ebv7WhE<{K~VYhJ8}jUIinw*035X2LHhVlK6Mhk!tC! zyXgBhd3baQ!XL37ETs9rP=tm>2#)d3v6ZkKcUd3*tM96w^Jn5*PrTKr-wDoInnQi& z-;jkKVtRpmLj~poA`RrXt@UwZ}9yz_phYw0R+c*Gt)yj m-}@%^D8=mA#2%-Z8a~kt&07%v%QtU*XY*do{h`H6TKom8$2h$J diff --git a/resources/shaders/spirv/tile_alpha_monochrome.vs.spv b/resources/shaders/spirv/tile_alpha_monochrome.vs.spv deleted file mode 100644 index 782bc4f9579eed7822025c38862b31919b4defd8..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3876 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 diff --git a/resources/shaders/spirv/tile_solid.fs.spv b/resources/shaders/spirv/tile_solid.fs.spv deleted file mode 100644 index cce9973509dfa21e87490918d21e784113db7874..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 376 zcmY+ATMI!!6otRJIqsJfZzAvVfRuPql)U)`N=e}q^4q;A?R`cvHO;KO*4}H)INMLa zkdUWBwi;LrP$H-2db`^W?vKM@G#-kgic_IzY9x5jec7L`LKL(Y>Nu_E0f)l^8v_CV zrw;_}NmsZ1ahaaeTc#-i&xqG})pW9miiQ8;CRXS7)Cs+}aO8k4(8iO1V#(XZ$6RQA s7O`ZP*9l)le&)vu7Eh^72e#xTY30Ue7e@dJ6wOVzPzZn zm#sQ>P4JR z7MIbLD>t>1P_N9&Sw%2cUxy{l<6bB?XNy?J8Ha$&IYv)o88)goiBpSluF=!5Sgg!u z)po->DQOqpllWWkJwGJ26~nI&XM6s+eg84FUY9YwpTK=ojdsE>yU(75%D1tz(ZlDa z7TgyDn3Tn4sJ22?hds{K_c)7O+P<%W@tKpwbS&^@G*8R{OEW?~TsHqb5AuK2*=XO*-fa`!>0zNA0?Jo^Ny4 zO@F|6^O(A}&sn<>&Dl<dD|iPai;;WBb7(oEOot>5B#VRJ^>e_x z?HDg}#)O#z82$ow>L zy2011;_GwXaLj(U{eRL7#uqH|4_qJnP!EhR(j36}0(?Wc&69bv(DaYG=AT>2EO+1i z^RGI(sm}g4c&hykUZ5Vn;B9MT-XHKC_t8;*uM>XH-|jzrPRAwV5Ko-<-5)QV^MTDs z7Ehdy+%svPQ1HV3_} zt={IN!Du!c%&S*L7!>&=40iJ}jH>))fVa}%<&#md*liLrrT>YasjH5p(R6RNsKU;$ ze3ehe^N-0bQ>G)5#-Uo97Sj@ArjCwDn&rz-^r!Q@%BK_pms*C~c@ehCe4J0rMs36G zFrTkYr{!+VJ1uDe?|J@H@HgMVwv&e+A5NEk-R{3jtb;I??|X0`m&3jA!{Wt@Q2H}g z8-09f*@8P_2;*YV59LlMtFWZ5j@vo-;`1GKjnAyio=>XycJwiiaWPmc^4WSmuZELR zP^QFY$06oj^6L-tNwpo8)uN0wGTWi$wjGxH{pjlP|M~lU$xI95Vo)c)v2O39jd3y9 znAGt%)+P0nTK~@rh1QtfgE{!=d(#hozu{*F_^A;-xap_w&G*1fKfRCsC(5js95lp< zwt8RcJfn@6@Yt4~61yAopr5>3`%=TrxcD!64DzPW%{u5Wn7zXfZr*3#h@H8g{({+y z6KY!?7i}Bs-kegR6-gH)omQ$tl40J5cUUqTzSrGHEfLi+Jda?{pLMEd}3kUB2mmegO>&Kxy+X6Udkl6P z4)#CXcFA|1J?^{hvg;JB{_3_5CFA0YIe#LV9bJ c+1-OYANc $@ + mkdir -p $(TARGET_DIR)/gl3 && echo $(GLSL_VERSION_HEADER) > $@ && echo $(HEADER) >> $@ && ( glslangValidator $(GLSLANGFLAGS) -S frag -E $< | sed $(GLSL_SED_ARGS) >> $@ ) || ( rm $@ && exit 1 ) -$(TARGET_DIR)/spirv/%.vs.spv: %.vs.glsl $(INCLUDES) - mkdir -p $(TARGET_DIR)/spirv && glslangValidator $(GLSLANGFLAGS) -G$(GLSL_VERSION) -S vert -o $@ $< +build/metal/%.vs.spv: %.vs.glsl $(INCLUDES) + mkdir -p build/metal && glslangValidator $(GLSLANGFLAGS_METAL) -G$(GLSL_VERSION) -S vert -o $@ $< $(TARGET_DIR)/gl3/%.vs.glsl: %.vs.glsl $(INCLUDES) - mkdir -p $(TARGET_DIR)/gl3 && glslangValidator $(GLSLANGFLAGS) -S vert -E $< | sed $(SED_ARGS) > $@ + mkdir -p $(TARGET_DIR)/gl3 && echo $(GLSL_VERSION_HEADER) > $@ && echo $(HEADER) >> $@ && ( glslangValidator $(GLSLANGFLAGS) -S vert -E $< | sed $(GLSL_SED_ARGS) >> $@ ) || ( rm $@ && exit 1 ) -$(TARGET_DIR)/metal/%.metal: $(TARGET_DIR)/spirv/%.spv - mkdir -p $(TARGET_DIR)/metal && spirv-cross $(SPIRVCROSSFLAGS) --output $@ $< +$(TARGET_DIR)/metal/%.metal: build/metal/%.spv + mkdir -p $(TARGET_DIR)/metal && echo $(HEADER) > $@ && ( $(SPIRVCROSS) $(SPIRVCROSSFLAGS) $< | sed $(METAL_SED_ARGS) >> $@ ) || ( rm $@ && exit 1 ) diff --git a/shaders/debug_solid.vs.glsl b/shaders/debug_solid.vs.glsl index 10b92ad8..8dd2f383 100644 --- a/shaders/debug_solid.vs.glsl +++ b/shaders/debug_solid.vs.glsl @@ -14,9 +14,9 @@ precision highp float; uniform vec2 uFramebufferSize; -in vec2 aPosition; +in ivec2 aPosition; void main() { - vec2 position = aPosition / uFramebufferSize * 2.0 - 1.0; + vec2 position = vec2(aPosition) / uFramebufferSize * 2.0 - 1.0; gl_Position = vec4(position.x, -position.y, 0.0, 1.0); } diff --git a/shaders/debug_texture.vs.glsl b/shaders/debug_texture.vs.glsl index 734916f1..7df2a288 100644 --- a/shaders/debug_texture.vs.glsl +++ b/shaders/debug_texture.vs.glsl @@ -15,13 +15,13 @@ precision highp float; uniform vec2 uFramebufferSize; uniform vec2 uTextureSize; -in vec2 aPosition; -in vec2 aTexCoord; +in ivec2 aPosition; +in ivec2 aTexCoord; out vec2 vTexCoord; void main() { - vTexCoord = aTexCoord / uTextureSize; - vec2 position = aPosition / uFramebufferSize * 2.0 - 1.0; + vTexCoord = vec2(aTexCoord) / uTextureSize; + vec2 position = vec2(aPosition) / uFramebufferSize * 2.0 - 1.0; gl_Position = vec4(position.x, -position.y, 0.0, 1.0); } diff --git a/shaders/demo_ground.vs.glsl b/shaders/demo_ground.vs.glsl index b145ce04..e2a618b6 100644 --- a/shaders/demo_ground.vs.glsl +++ b/shaders/demo_ground.vs.glsl @@ -15,11 +15,11 @@ precision highp float; uniform mat4 uTransform; uniform int uGridlineCount; -in vec2 aPosition; +in ivec2 aPosition; out vec2 vTexCoord; void main() { - vTexCoord = aPosition * float(uGridlineCount); - gl_Position = uTransform * vec4(aPosition.x, 0.0, aPosition.y, 1.0); + vTexCoord = vec2(aPosition * uGridlineCount); + gl_Position = uTransform * vec4(ivec4(aPosition.x, 0, aPosition.y, 1)); } diff --git a/shaders/fill.vs.glsl b/shaders/fill.vs.glsl index f5abbf7e..7b75578b 100644 --- a/shaders/fill.vs.glsl +++ b/shaders/fill.vs.glsl @@ -1,6 +1,6 @@ #version 330 -// pathfinder/resources/fill.vs.glsl +// pathfinder/shaders/fill.vs.glsl // // Copyright © 2019 The Pathfinder Project Developers. // @@ -15,7 +15,7 @@ precision highp float; uniform vec2 uFramebufferSize; uniform vec2 uTileSize; -in vec2 aTessCoord; +in uvec2 aTessCoord; in uint aFromPx; in uint aToPx; in vec2 aFromSubpx; @@ -27,7 +27,7 @@ out vec2 vTo; vec2 computeTileOffset(uint tileIndex, float stencilTextureWidth) { uint tilesPerRow = uint(stencilTextureWidth / uTileSize.x); - uvec2 tileOffset = uvec2(aTileIndex % tilesPerRow, aTileIndex / tilesPerRow); + uvec2 tileOffset = uvec2(tileIndex % tilesPerRow, tileIndex / tilesPerRow); return vec2(tileOffset) * uTileSize; } @@ -38,11 +38,11 @@ void main() { vec2 to = vec2(aToPx & 15u, aToPx >> 4u) + aToSubpx; vec2 position; - if (aTessCoord.x < 0.5) + if (aTessCoord.x == 0u) position.x = floor(min(from.x, to.x)); else position.x = ceil(max(from.x, to.x)); - if (aTessCoord.y < 0.5) + if (aTessCoord.y == 0u) position.y = floor(min(from.y, to.y)); else position.y = uTileSize.y; @@ -50,5 +50,9 @@ void main() { vFrom = from - position; vTo = to - position; - gl_Position = vec4((tileOrigin + position) / uFramebufferSize * 2.0 - 1.0, 0.0, 1.0); + vec2 globalPosition = (tileOrigin + position) / uFramebufferSize * 2.0 - 1.0; +#ifdef PF_ORIGIN_UPPER_LEFT + globalPosition.y = -globalPosition.y; +#endif + gl_Position = vec4(globalPosition, 0.0, 1.0); } diff --git a/shaders/post.vs.glsl b/shaders/post.vs.glsl index 2ee824a7..137cf388 100644 --- a/shaders/post.vs.glsl +++ b/shaders/post.vs.glsl @@ -12,11 +12,11 @@ precision highp float; -in vec2 aPosition; +in ivec2 aPosition; out vec2 vTexCoord; void main() { - vTexCoord = aPosition; - gl_Position = vec4(aPosition * 2.0 - 1.0, 0.0, 1.0); + vTexCoord = vec2(aPosition); + gl_Position = vec4(vec2(aPosition) * 2.0 - 1.0, 0.0, 1.0); } diff --git a/shaders/reproject.vs.glsl b/shaders/reproject.vs.glsl index 91d9f9a9..f10433b1 100644 --- a/shaders/reproject.vs.glsl +++ b/shaders/reproject.vs.glsl @@ -14,11 +14,17 @@ precision highp float; uniform mat4 uNewTransform; -in vec2 aPosition; +in ivec2 aPosition; out vec2 vTexCoord; void main() { - vTexCoord = aPosition; - gl_Position = uNewTransform * vec4(aPosition, 0.0, 1.0); + vec2 position = vec2(aPosition); + vTexCoord = position; + +#ifdef PF_ORIGIN_UPPER_LEFT + // FIXME(pcwalton): This is wrong. + position.y = 1.0 - position.y; +#endif + gl_Position = uNewTransform * vec4(position, 0.0, 1.0); } diff --git a/shaders/tile_alpha_vertex.inc.glsl b/shaders/tile_alpha_vertex.inc.glsl index 6993a13d..e5211809 100644 --- a/shaders/tile_alpha_vertex.inc.glsl +++ b/shaders/tile_alpha_vertex.inc.glsl @@ -13,10 +13,10 @@ uniform vec2 uTileSize; uniform vec2 uStencilTextureSize; uniform vec2 uViewBoxOrigin; -in vec2 aTessCoord; +in uvec2 aTessCoord; in uvec3 aTileOrigin; in int aBackdrop; -in uint aTileIndex; +in int aTileIndex; out vec2 vTexCoord; out float vBackdrop; @@ -32,9 +32,9 @@ vec2 computeTileOffset(uint tileIndex, float stencilTextureWidth) { void computeVaryings() { vec2 origin = vec2(aTileOrigin.xy) + vec2(aTileOrigin.z & 15u, aTileOrigin.z >> 4u) * 256.0; - vec2 pixelPosition = (origin + aTessCoord) * uTileSize + uViewBoxOrigin; + vec2 pixelPosition = (origin + vec2(aTessCoord)) * uTileSize + uViewBoxOrigin; vec2 position = (pixelPosition / uFramebufferSize * 2.0 - 1.0) * vec2(1.0, -1.0); - vec2 maskTexCoordOrigin = computeTileOffset(aTileIndex, uStencilTextureSize.x); + vec2 maskTexCoordOrigin = computeTileOffset(uint(aTileIndex), uStencilTextureSize.x); vec2 maskTexCoord = maskTexCoordOrigin + aTessCoord * uTileSize; vTexCoord = maskTexCoord / uStencilTextureSize; diff --git a/shaders/tile_solid_vertex.inc.glsl b/shaders/tile_solid_vertex.inc.glsl index 73f30cd0..fc7c8bc5 100644 --- a/shaders/tile_solid_vertex.inc.glsl +++ b/shaders/tile_solid_vertex.inc.glsl @@ -12,18 +12,17 @@ uniform vec2 uFramebufferSize; uniform vec2 uTileSize; uniform vec2 uViewBoxOrigin; -in vec2 aTessCoord; -in vec2 aTileOrigin; +in uvec2 aTessCoord; +in ivec2 aTileOrigin; out vec4 vColor; vec4 getColor(); void computeVaryings() { - vec2 pixelPosition = (aTileOrigin + aTessCoord) * uTileSize + uViewBoxOrigin; + vec2 pixelPosition = vec2(aTileOrigin + ivec2(aTessCoord)) * uTileSize + uViewBoxOrigin; vec2 position = (pixelPosition / uFramebufferSize * 2.0 - 1.0) * vec2(1.0, -1.0); vColor = getColor(); - //vColor = vec4(1.0, 0.0, 0.0, 1.0); gl_Position = vec4(position, 0.0, 1.0); } diff --git a/ui/src/lib.rs b/ui/src/lib.rs index 794e5839..18817224 100644 --- a/ui/src/lib.rs +++ b/ui/src/lib.rs @@ -22,7 +22,7 @@ use pathfinder_geometry::basic::rect::RectI; use pathfinder_geometry::color::ColorU; use pathfinder_gpu::resources::ResourceLoader; use pathfinder_gpu::{BlendState, BufferData, BufferTarget, BufferUploadMode, Device, Primitive}; -use pathfinder_gpu::{RenderState, UniformData, VertexAttrClass}; +use pathfinder_gpu::{RenderOptions, RenderState, RenderTarget, UniformData, VertexAttrClass}; use pathfinder_gpu::{VertexAttrDescriptor, VertexAttrType}; use pathfinder_simd::default::F32x4; use serde_json; @@ -131,7 +131,11 @@ impl UIPresenter where D: Device { self.draw_rect(device, rect, color, false); } - fn draw_rect(&self, device: &D, rect: RectI, color: ColorU, filled: bool) { + fn draw_rect(&self, + device: &D, + rect: RectI, + color: ColorU, + filled: bool) { let vertex_data = [ DebugSolidVertex::new(rect.origin()), DebugSolidVertex::new(rect.upper_right()), @@ -160,8 +164,6 @@ impl UIPresenter where D: Device { index_data: &[u32], color: ColorU, filled: bool) { - device.bind_vertex_array(&self.solid_vertex_array.vertex_array); - device.allocate_buffer(&self.solid_vertex_array.vertex_buffer, BufferData::Memory(vertex_data), BufferTarget::Vertex, @@ -171,15 +173,23 @@ impl UIPresenter where D: Device { BufferTarget::Index, BufferUploadMode::Dynamic); - device.use_program(&self.solid_program.program); - device.set_uniform(&self.solid_program.framebuffer_size_uniform, - UniformData::Vec2(self.framebuffer_size.0.to_f32x4())); - set_color_uniform(device, &self.solid_program.color_uniform, color); - let primitive = if filled { Primitive::Triangles } else { Primitive::Lines }; - device.draw_elements(primitive, index_data.len() as u32, &RenderState { - blend: BlendState::RGBOneAlphaOneMinusSrcAlpha, - ..RenderState::default() + device.draw_elements(index_data.len() as u32, &RenderState { + target: &RenderTarget::Default, + program: &self.solid_program.program, + vertex_array: &self.solid_vertex_array.vertex_array, + primitive, + uniforms: &[ + (&self.solid_program.framebuffer_size_uniform, + UniformData::Vec2(self.framebuffer_size.0.to_f32x4())), + (&self.solid_program.color_uniform, get_color_uniform(color)), + ], + textures: &[], + viewport: RectI::new(Vector2I::default(), self.framebuffer_size), + options: RenderOptions { + blend: BlendState::RGBOneAlphaOneMinusSrcAlpha, + ..RenderOptions::default() + }, }); } @@ -396,19 +406,25 @@ impl UIPresenter where D: Device { BufferTarget::Index, BufferUploadMode::Dynamic); - device.bind_vertex_array(&self.texture_vertex_array.vertex_array); - device.use_program(&self.texture_program.program); - device.set_uniform(&self.texture_program.framebuffer_size_uniform, - UniformData::Vec2(self.framebuffer_size.0.to_f32x4())); - device.set_uniform(&self.texture_program.texture_size_uniform, - UniformData::Vec2(device.texture_size(&texture).0.to_f32x4())); - set_color_uniform(device, &self.texture_program.color_uniform, color); - device.bind_texture(texture, 0); - device.set_uniform(&self.texture_program.texture_uniform, UniformData::TextureUnit(0)); - - device.draw_elements(Primitive::Triangles, index_data.len() as u32, &RenderState { - blend: BlendState::RGBOneAlphaOneMinusSrcAlpha, - ..RenderState::default() + device.draw_elements(index_data.len() as u32, &RenderState { + target: &RenderTarget::Default, + program: &self.texture_program.program, + vertex_array: &self.texture_vertex_array.vertex_array, + primitive: Primitive::Triangles, + textures: &[&texture], + uniforms: &[ + (&self.texture_program.framebuffer_size_uniform, + UniformData::Vec2(self.framebuffer_size.0.to_f32x4())), + (&self.texture_program.color_uniform, get_color_uniform(color)), + (&self.texture_program.texture_uniform, UniformData::TextureUnit(0)), + (&self.texture_program.texture_size_uniform, + UniformData::Vec2(device.texture_size(&texture).0.to_f32x4())) + ], + viewport: RectI::new(Vector2I::default(), self.framebuffer_size), + options: RenderOptions { + blend: BlendState::RGBOneAlphaOneMinusSrcAlpha, + ..RenderOptions::default() + }, }); } @@ -508,9 +524,9 @@ impl UIPresenter where D: Device { let highlight_size = Vector2I::new(SEGMENT_SIZE, BUTTON_HEIGHT); let x_offset = value as i32 * SEGMENT_SIZE + (value as i32 - 1); self.draw_solid_rounded_rect(device, - RectI::new(origin + Vector2I::new(x_offset, 0), + RectI::new(origin + Vector2I::new(x_offset, 0), highlight_size), - TEXT_COLOR); + TEXT_COLOR); } let mut segment_origin = origin + Vector2I::new(SEGMENT_SIZE + 1, 0); @@ -520,9 +536,9 @@ impl UIPresenter where D: Device { Some(value) if value == prev_segment_index || value == next_segment_index => {} _ => { self.draw_line(device, - segment_origin, - segment_origin + Vector2I::new(0, BUTTON_HEIGHT), - TEXT_COLOR); + segment_origin, + segment_origin + Vector2I::new(0, BUTTON_HEIGHT), + TEXT_COLOR); } } segment_origin = segment_origin + Vector2I::new(SEGMENT_SIZE + 1, 0); @@ -590,25 +606,25 @@ impl DebugTextureVertexArray where D: Device { let tex_coord_attr = device.get_vertex_attr(&debug_texture_program.program, "TexCoord") .unwrap(); - device.bind_vertex_array(&vertex_array); - device.use_program(&debug_texture_program.program); - device.bind_buffer(&vertex_buffer, BufferTarget::Vertex); - device.bind_buffer(&index_buffer, BufferTarget::Index); - device.configure_vertex_attr(&position_attr, &VertexAttrDescriptor { + device.bind_buffer(&vertex_array, &vertex_buffer, BufferTarget::Vertex); + device.bind_buffer(&vertex_array, &index_buffer, BufferTarget::Index); + device.configure_vertex_attr(&vertex_array, &position_attr, &VertexAttrDescriptor { size: 2, - class: VertexAttrClass::Float, - attr_type: VertexAttrType::U16, + class: VertexAttrClass::Int, + attr_type: VertexAttrType::I16, stride: DEBUG_TEXTURE_VERTEX_SIZE, offset: 0, divisor: 0, + buffer_index: 0, }); - device.configure_vertex_attr(&tex_coord_attr, &VertexAttrDescriptor { + device.configure_vertex_attr(&vertex_array, &tex_coord_attr, &VertexAttrDescriptor { size: 2, - class: VertexAttrClass::Float, - attr_type: VertexAttrType::U16, + class: VertexAttrClass::Int, + attr_type: VertexAttrType::I16, stride: DEBUG_TEXTURE_VERTEX_SIZE, offset: 4, divisor: 0, + buffer_index: 0, }); DebugTextureVertexArray { vertex_array, vertex_buffer, index_buffer } @@ -626,19 +642,18 @@ impl DebugSolidVertexArray where D: Device { let (vertex_buffer, index_buffer) = (device.create_buffer(), device.create_buffer()); let vertex_array = device.create_vertex_array(); - let position_attr = device.get_vertex_attr(&debug_solid_program.program, "Position") - .unwrap(); - device.bind_vertex_array(&vertex_array); - device.use_program(&debug_solid_program.program); - device.bind_buffer(&vertex_buffer, BufferTarget::Vertex); - device.bind_buffer(&index_buffer, BufferTarget::Index); - device.configure_vertex_attr(&position_attr, &VertexAttrDescriptor { + let position_attr = + device.get_vertex_attr(&debug_solid_program.program, "Position").unwrap(); + device.bind_buffer(&vertex_array, &vertex_buffer, BufferTarget::Vertex); + device.bind_buffer(&vertex_array, &index_buffer, BufferTarget::Index); + device.configure_vertex_attr(&vertex_array, &position_attr, &VertexAttrDescriptor { size: 2, - class: VertexAttrClass::Float, - attr_type: VertexAttrType::U16, + class: VertexAttrClass::Int, + attr_type: VertexAttrType::I16, stride: DEBUG_SOLID_VERTEX_SIZE, offset: 0, divisor: 0, + buffer_index: 0, }); DebugSolidVertexArray { vertex_array, vertex_buffer, index_buffer } @@ -714,9 +729,9 @@ impl CornerRects { } } -fn set_color_uniform(device: &D, uniform: &D::Uniform, color: ColorU) where D: Device { +fn get_color_uniform(color: ColorU) -> UniformData { let color = F32x4::new(color.r as f32, color.g as f32, color.b as f32, color.a as f32); - device.set_uniform(uniform, UniformData::Vec4(color * F32x4::splat(1.0 / 255.0))); + UniformData::Vec4(color * F32x4::splat(1.0 / 255.0)) } #[derive(Clone, Copy)] From 71623eaab312ee0c33ba8ffa70954e166b564dfb Mon Sep 17 00:00:00 2001 From: Patrick Walton Date: Thu, 20 Jun 2019 12:34:55 -0700 Subject: [PATCH 07/26] Make Metal dependencies in the demo Mac-only --- demo/common/Cargo.toml | 6 +++--- demo/native/Cargo.toml | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/demo/common/Cargo.toml b/demo/common/Cargo.toml index 3d2a88cb..c73270df 100644 --- a/demo/common/Cargo.toml +++ b/demo/common/Cargo.toml @@ -31,9 +31,6 @@ path = "../../gl" [dependencies.pathfinder_gpu] path = "../../gpu" -[dependencies.pathfinder_metal] -path = "../../metal" - [dependencies.pathfinder_renderer] path = "../../renderer" @@ -48,3 +45,6 @@ path = "../../ui" [target.'cfg(target_os = "macos")'.dependencies] metal = "0.14" + +[target.'cfg(target_os = "macos")'.dependencies.pathfinder_metal] +path = "../../metal" diff --git a/demo/native/Cargo.toml b/demo/native/Cargo.toml index 12515c04..05c33dd3 100644 --- a/demo/native/Cargo.toml +++ b/demo/native/Cargo.toml @@ -28,9 +28,6 @@ path = "../../gl" [dependencies.pathfinder_gpu] path = "../../gpu" -[dependencies.pathfinder_metal] -path = "../../metal" - [dependencies.pathfinder_simd] path = "../../simd" @@ -38,5 +35,8 @@ path = "../../simd" foreign-types = "0.3" metal = "0.14" +[target.'cfg(target_os = "macos")'.dependencies.pathfinder_metal] +path = "../../metal" + [target.'cfg(not(windows))'.dependencies] jemallocator = "0.1" From d2fbb23031f0eb2608d598bdec2cdd34cf1cb0c0 Mon Sep 17 00:00:00 2001 From: Patrick Walton Date: Thu, 20 Jun 2019 13:01:54 -0700 Subject: [PATCH 08/26] Expose more stroke features in the C API --- c/include/pathfinder/pathfinder.h | 11 ++++++++++ c/src/lib.rs | 35 ++++++++++++++++++++++++++++++- 2 files changed, 45 insertions(+), 1 deletion(-) diff --git a/c/include/pathfinder/pathfinder.h b/c/include/pathfinder/pathfinder.h index d924ce7b..b89404d4 100644 --- a/c/include/pathfinder/pathfinder.h +++ b/c/include/pathfinder/pathfinder.h @@ -25,6 +25,10 @@ extern "C" { #define PF_LINE_CAP_SQUARE 1 #define PF_LINE_CAP_ROUND 2 +#define PF_LINE_JOIN_MITER 0 +#define PF_LINE_JOIN_BEVEL 1 +#define PF_LINE_JOIN_ROUND 2 + // `gl` #define PF_GL_VERSION_GL3 0 @@ -45,6 +49,7 @@ typedef struct PFPath *PFPathRef; struct PFCanvasFontContext; typedef struct PFCanvasFontContext *PFCanvasFontContextRef; typedef uint8_t PFLineCap; +typedef uint8_t PFLineJoin; // `geometry` @@ -116,6 +121,12 @@ void PFCanvasFillRect(PFCanvasRef canvas, const PFRectF *rect); void PFCanvasStrokeRect(PFCanvasRef canvas, const PFRectF *rect); void PFCanvasSetLineWidth(PFCanvasRef canvas, float new_line_width); void PFCanvasSetLineCap(PFCanvasRef canvas, PFLineCap new_line_cap); +void PFCanvasSetLineJoin(PFCanvasRef canvas, PFLineJoin new_line_join); +void PFCanvasSetMiterLimit(PFCanvasRef canvas, float new_miter_limit); +void PFCanvasSetLineDash(PFCanvasRef canvas, + const float *new_line_dashes, + size_t new_line_dash_count); +void PFCanvasSetLineDashOffset(PFCanvasRef canvas, float offset); void PFCanvasFillPath(PFCanvasRef canvas, PFPathRef path); void PFCanvasStrokePath(PFCanvasRef canvas, PFPathRef path); PFPathRef PFPathCreate(); diff --git a/c/src/lib.rs b/c/src/lib.rs index 7454e90c..e9cb913d 100644 --- a/c/src/lib.rs +++ b/c/src/lib.rs @@ -11,7 +11,7 @@ //! C bindings to Pathfinder. use gl; -use pathfinder_canvas::{CanvasFontContext, CanvasRenderingContext2D, Path2D}; +use pathfinder_canvas::{CanvasFontContext, CanvasRenderingContext2D, LineJoin, Path2D}; use pathfinder_geometry::basic::vector::{Vector2F, Vector2I}; use pathfinder_geometry::basic::rect::{RectF, RectI}; use pathfinder_geometry::color::ColorF; @@ -27,14 +27,20 @@ use pathfinder_renderer::scene::Scene; use pathfinder_simd::default::F32x4; use std::ffi::CString; use std::os::raw::{c_char, c_void}; +use std::slice; // Constants // `canvas` + pub const PF_LINE_CAP_BUTT: u8 = 0; pub const PF_LINE_CAP_SQUARE: u8 = 1; pub const PF_LINE_CAP_ROUND: u8 = 2; +pub const PF_LINE_JOIN_MITER: u8 = 0; +pub const PF_LINE_JOIN_BEVEL: u8 = 1; +pub const PF_LINE_JOIN_ROUND: u8 = 2; + // `renderer` pub const PF_RENDERER_OPTIONS_FLAGS_HAS_BACKGROUND_COLOR: u8 = 0x1; @@ -45,6 +51,7 @@ pub type PFCanvasRef = *mut CanvasRenderingContext2D; pub type PFPathRef = *mut Path2D; pub type PFCanvasFontContextRef = *mut CanvasFontContext; pub type PFLineCap = u8; +pub type PFLineJoin = u8; // `geometry` #[repr(C)] @@ -164,6 +171,32 @@ pub unsafe extern "C" fn PFCanvasSetLineCap(canvas: PFCanvasRef, new_line_cap: P }); } +#[no_mangle] +pub unsafe extern "C" fn PFCanvasSetLineJoin(canvas: PFCanvasRef, new_line_join: PFLineJoin) { + (*canvas).set_line_join(match new_line_join { + PF_LINE_JOIN_BEVEL => LineJoin::Bevel, + PF_LINE_JOIN_ROUND => LineJoin::Round, + _ => LineJoin::Miter, + }); +} + +#[no_mangle] +pub unsafe extern "C" fn PFCanvasSetMiterLimit(canvas: PFCanvasRef, new_miter_limit: f32) { + (*canvas).set_miter_limit(new_miter_limit); +} + +#[no_mangle] +pub unsafe extern "C" fn PFCanvasSetLineDash(canvas: PFCanvasRef, + new_line_dashes: *const f32, + new_line_dash_count: usize) { + (*canvas).set_line_dash(slice::from_raw_parts(new_line_dashes, new_line_dash_count).to_vec()) +} + +#[no_mangle] +pub unsafe extern "C" fn PFCanvasSetLineDashOffset(canvas: PFCanvasRef, new_offset: f32) { + (*canvas).set_line_dash_offset(new_offset) +} + /// Consumes the path. #[no_mangle] pub unsafe extern "C" fn PFCanvasFillPath(canvas: PFCanvasRef, path: PFPathRef) { From 2129e4f2e128afd95b04aabfca48490ca7c51967 Mon Sep 17 00:00:00 2001 From: Patrick Walton Date: Thu, 20 Jun 2019 15:51:25 -0700 Subject: [PATCH 09/26] Add missing path methods to the C API --- c/include/pathfinder/pathfinder.h | 20 ++++++++++++++ c/src/lib.rs | 44 ++++++++++++++++++++++++++++++- 2 files changed, 63 insertions(+), 1 deletion(-) diff --git a/c/include/pathfinder/pathfinder.h b/c/include/pathfinder/pathfinder.h index b89404d4..6073bb51 100644 --- a/c/include/pathfinder/pathfinder.h +++ b/c/include/pathfinder/pathfinder.h @@ -29,6 +29,11 @@ extern "C" { #define PF_LINE_JOIN_BEVEL 1 #define PF_LINE_JOIN_ROUND 2 +// `geometry` + +#define PF_ARC_DIRECTION_CW 0 +#define PF_ARC_DIRECTION_CCW 1 + // `gl` #define PF_GL_VERSION_GL3 0 @@ -50,6 +55,7 @@ struct PFCanvasFontContext; typedef struct PFCanvasFontContext *PFCanvasFontContextRef; typedef uint8_t PFLineCap; typedef uint8_t PFLineJoin; +typedef uint8_t PFArcDirection; // `geometry` @@ -139,6 +145,20 @@ void PFPathBezierCurveTo(PFPathRef path, const PFVector2F *ctrl0, const PFVector2F *ctrl1, const PFVector2F *to); +void PFPathArc(PFPathRef path, + const PFVector2F *center, + float radius, + float start_angle, + float end_angle, + PFArcDirection direction); +void PFPathArcTo(PFPathRef path, const PFVector2F *ctrl, const PFVector2F *to, float radius); +void PFPathRect(PFPathRef path, const PFRectF *rect); +void PFPathEllipse(PFPathRef path, + const PFVector2F *center, + const PFVector2F *axes, + float rotation, + float start_angle, + float end_angle); void PFPathClosePath(PFPathRef path); // `gl` diff --git a/c/src/lib.rs b/c/src/lib.rs index e9cb913d..4fc204f2 100644 --- a/c/src/lib.rs +++ b/c/src/lib.rs @@ -12,9 +12,10 @@ use gl; use pathfinder_canvas::{CanvasFontContext, CanvasRenderingContext2D, LineJoin, Path2D}; -use pathfinder_geometry::basic::vector::{Vector2F, Vector2I}; use pathfinder_geometry::basic::rect::{RectF, RectI}; +use pathfinder_geometry::basic::vector::{Vector2F, Vector2I}; use pathfinder_geometry::color::ColorF; +use pathfinder_geometry::outline::ArcDirection; use pathfinder_geometry::stroke::LineCap; use pathfinder_gl::{GLDevice, GLVersion}; use pathfinder_gpu::resources::{FilesystemResourceLoader, ResourceLoader}; @@ -41,7 +42,13 @@ pub const PF_LINE_JOIN_MITER: u8 = 0; pub const PF_LINE_JOIN_BEVEL: u8 = 1; pub const PF_LINE_JOIN_ROUND: u8 = 2; +// `geometry` + +pub const PF_ARC_DIRECTION_CW: u8 = 0; +pub const PF_ARC_DIRECTION_CCW: u8 = 1; + // `renderer` + pub const PF_RENDERER_OPTIONS_FLAGS_HAS_BACKGROUND_COLOR: u8 = 0x1; // Types @@ -52,6 +59,7 @@ pub type PFPathRef = *mut Path2D; pub type PFCanvasFontContextRef = *mut CanvasFontContext; pub type PFLineCap = u8; pub type PFLineJoin = u8; +pub type PFArcDirection = u8; // `geometry` #[repr(C)] @@ -249,6 +257,40 @@ pub unsafe extern "C" fn PFPathBezierCurveTo(path: PFPathRef, (*path).bezier_curve_to((*ctrl0).to_rust(), (*ctrl1).to_rust(), (*to).to_rust()) } +#[no_mangle] +pub unsafe extern "C" fn PFPathArc(path: PFPathRef, + center: *const PFVector2F, + radius: f32, + start_angle: f32, + end_angle: f32, + direction: PFArcDirection) { + let direction = if direction == 0 { ArcDirection::CW } else { ArcDirection::CCW }; + (*path).arc((*center).to_rust(), radius, start_angle, end_angle, direction) +} + +#[no_mangle] +pub unsafe extern "C" fn PFPathArcTo(path: PFPathRef, + ctrl: *const PFVector2F, + to: *const PFVector2F, + radius: f32) { + (*path).arc_to((*ctrl).to_rust(), (*to).to_rust(), radius) +} + +#[no_mangle] +pub unsafe extern "C" fn PFPathRect(path: PFPathRef, rect: *const PFRectF) { + (*path).rect((*rect).to_rust()) +} + +#[no_mangle] +pub unsafe extern "C" fn PFPathEllipse(path: PFPathRef, + center: *const PFVector2F, + axes: *const PFVector2F, + rotation: f32, + start_angle: f32, + end_angle: f32) { + (*path).ellipse((*center).to_rust(), (*axes).to_rust(), rotation, start_angle, end_angle) +} + #[no_mangle] pub unsafe extern "C" fn PFPathClosePath(path: PFPathRef) { (*path).close_path() From 36db39883cbfa6ea989bcd283cac2e4c5f40aed0 Mon Sep 17 00:00:00 2001 From: Patrick Walton Date: Thu, 20 Jun 2019 16:07:38 -0700 Subject: [PATCH 10/26] Add C bindings to the canvas text APIs --- Cargo.lock | 1 + c/Cargo.toml | 1 + c/include/pathfinder/pathfinder.h | 16 +++++++++ c/src/lib.rs | 56 ++++++++++++++++++++++++++++++- 4 files changed, 73 insertions(+), 1 deletion(-) diff --git a/Cargo.lock b/Cargo.lock index c35ee108..55ca57e5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1318,6 +1318,7 @@ name = "pathfinder_c" version = "0.1.0" dependencies = [ "gl 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.54 (registry+https://github.com/rust-lang/crates.io-index)", "pathfinder_canvas 0.1.0", "pathfinder_geometry 0.3.0", "pathfinder_gl 0.1.0", diff --git a/c/Cargo.toml b/c/Cargo.toml index 7c17d4b2..ea2c8146 100644 --- a/c/Cargo.toml +++ b/c/Cargo.toml @@ -9,6 +9,7 @@ crate-type = ["staticlib"] [dependencies] gl = "0.6" +libc = "0.2" [dependencies.pathfinder_canvas] path = "../canvas" diff --git a/c/include/pathfinder/pathfinder.h b/c/include/pathfinder/pathfinder.h index 6073bb51..2833da22 100644 --- a/c/include/pathfinder/pathfinder.h +++ b/c/include/pathfinder/pathfinder.h @@ -56,6 +56,10 @@ typedef struct PFCanvasFontContext *PFCanvasFontContextRef; typedef uint8_t PFLineCap; typedef uint8_t PFLineJoin; typedef uint8_t PFArcDirection; +struct PFTextMetrics { + float width; +}; +typedef struct PFTextMetrics PFTextMetrics; // `geometry` @@ -125,6 +129,18 @@ PFCanvasFontContextRef PFCanvasFontContextClone(PFCanvasFontContextRef font_cont PFSceneRef PFCanvasCreateScene(PFCanvasRef canvas); void PFCanvasFillRect(PFCanvasRef canvas, const PFRectF *rect); void PFCanvasStrokeRect(PFCanvasRef canvas, const PFRectF *rect); +void PFCanvasFillText(PFCanvasRef canvas, + const char *string, + size_t string_len, + const PFVector2F *position); +void PFCanvasStrokeText(PFCanvasRef canvas, + const char *string, + size_t string_len, + const PFVector2F *position); +void PFCanvasMeasureText(PFCanvasRef canvas, + const char *string, + size_t string_len, + PFTextMetrics *out_text_metrics); void PFCanvasSetLineWidth(PFCanvasRef canvas, float new_line_width); void PFCanvasSetLineCap(PFCanvasRef canvas, PFLineCap new_line_cap); void PFCanvasSetLineJoin(PFCanvasRef canvas, PFLineJoin new_line_join); diff --git a/c/src/lib.rs b/c/src/lib.rs index 4fc204f2..f071bdba 100644 --- a/c/src/lib.rs +++ b/c/src/lib.rs @@ -11,7 +11,8 @@ //! C bindings to Pathfinder. use gl; -use pathfinder_canvas::{CanvasFontContext, CanvasRenderingContext2D, LineJoin, Path2D}; +use pathfinder_canvas::{CanvasFontContext, CanvasRenderingContext2D, LineJoin}; +use pathfinder_canvas::{Path2D, TextMetrics}; use pathfinder_geometry::basic::rect::{RectF, RectI}; use pathfinder_geometry::basic::vector::{Vector2F, Vector2I}; use pathfinder_geometry::color::ColorF; @@ -29,6 +30,7 @@ use pathfinder_simd::default::F32x4; use std::ffi::CString; use std::os::raw::{c_char, c_void}; use std::slice; +use std::str; // Constants @@ -60,6 +62,10 @@ pub type PFCanvasFontContextRef = *mut CanvasFontContext; pub type PFLineCap = u8; pub type PFLineJoin = u8; pub type PFArcDirection = u8; +#[repr(C)] +pub struct PFTextMetrics { + pub width: f32, +} // `geometry` #[repr(C)] @@ -155,6 +161,8 @@ pub unsafe extern "C" fn PFCanvasCreateScene(canvas: PFCanvasRef) -> PFSceneRef Box::into_raw(Box::new(Box::from_raw(canvas).into_scene())) } +// Drawing rectangles + #[no_mangle] pub unsafe extern "C" fn PFCanvasFillRect(canvas: PFCanvasRef, rect: *const PFRectF) { (*canvas).fill_rect((*rect).to_rust()) @@ -165,6 +173,33 @@ pub unsafe extern "C" fn PFCanvasStrokeRect(canvas: PFCanvasRef, rect: *const PF (*canvas).stroke_rect((*rect).to_rust()) } +// Drawing text + +#[no_mangle] +pub unsafe extern "C" fn PFCanvasFillText(canvas: PFCanvasRef, + string: *const c_char, + string_len: usize, + position: *const PFVector2F) { + (*canvas).fill_text(to_rust_string(&string, string_len), (*position).to_rust()) +} + +#[no_mangle] +pub unsafe extern "C" fn PFCanvasStrokeText(canvas: PFCanvasRef, + string: *const c_char, + string_len: usize, + position: *const PFVector2F) { + (*canvas).stroke_text(to_rust_string(&string, string_len), (*position).to_rust()) +} + +#[no_mangle] +pub unsafe extern "C" fn PFCanvasMeasureText(canvas: PFCanvasRef, + string: *const c_char, + string_len: usize, + out_text_metrics: *mut PFTextMetrics) { + debug_assert!(!out_text_metrics.is_null()); + *out_text_metrics = (*canvas).measure_text(to_rust_string(&string, string_len)).to_c() +} + #[no_mangle] pub unsafe extern "C" fn PFCanvasSetLineWidth(canvas: PFCanvasRef, new_line_width: f32) { (*canvas).set_line_width(new_line_width) @@ -389,6 +424,25 @@ pub unsafe extern "C" fn PFSceneProxyDestroy(scene_proxy: PFSceneProxyRef) { drop(Box::from_raw(scene_proxy)) } +// Helpers for `canvas` + +unsafe fn to_rust_string(ptr: &*const c_char, mut len: usize) -> &str { + if len == 0 { + len = libc::strlen(*ptr); + } + str::from_utf8(slice::from_raw_parts(*ptr as *const u8, len)).unwrap() +} + +trait TextMetricsExt { + fn to_c(&self) -> PFTextMetrics; +} + +impl TextMetricsExt for TextMetrics { + fn to_c(&self) -> PFTextMetrics { + PFTextMetrics { width: self.width } + } +} + // Helpers for `geometry` impl PFColorF { From 4d53ab60fc895926634b4a41b7367cd8049c64eb Mon Sep 17 00:00:00 2001 From: Jon Hardie Date: Fri, 21 Jun 2019 11:10:26 +1200 Subject: [PATCH 11/26] [WIP] Updating to master --- examples/swf_basic/src/main.rs | 29 ++++++++++++++--------------- 1 file changed, 14 insertions(+), 15 deletions(-) diff --git a/examples/swf_basic/src/main.rs b/examples/swf_basic/src/main.rs index ea7f8b73..ed5e9f9d 100644 --- a/examples/swf_basic/src/main.rs +++ b/examples/swf_basic/src/main.rs @@ -12,11 +12,11 @@ use pathfinder_geometry::basic::vector::{Vector2F, Vector2I}; use pathfinder_geometry::basic::rect::RectF; use pathfinder_gl::{GLDevice, GLVersion}; use pathfinder_gpu::resources::FilesystemResourceLoader; -use pathfinder_gpu::{ClearParams, Device}; use pathfinder_renderer::concurrent::rayon::RayonExecutor; use pathfinder_renderer::concurrent::scene_proxy::SceneProxy; -use pathfinder_renderer::gpu::renderer::{DestFramebuffer, Renderer}; -use pathfinder_renderer::options::{RenderOptions, RenderTransform}; +use pathfinder_renderer::gpu::renderer::Renderer; +use pathfinder_renderer::gpu::options::{DestFramebuffer, RendererOptions}; +use pathfinder_renderer::options::{RenderTransform, BuildOptions}; use sdl2::event::Event; use sdl2::keyboard::Keycode; use sdl2::video::GLProfile; @@ -50,7 +50,7 @@ fn main() { // a lot more geometry. I think a more likely explanation for the choice is that it was // done to reduce overdraw in the software rasterizer running on late 90's era hardware? // Indeed, this mode gives pathfinders' occlusion culling pass nothing to do! - let default_tiger = include_bytes!("../swf/tiger-flat.swf"); + //let default_tiger = include_bytes!("../swf/tiger-flat.swf"); // NOTE(jon): This is a version of the same graphic cut and pasted into the Flash authoring // tool from the SVG version loaded in Illustrator. When layered graphics are pasted @@ -58,7 +58,7 @@ fn main() { // They are still presented as being on a single timeline layer. // They will be drawn back to front in much the same way as the SVG version. - //let default_tiger = include_bytes!("../tiger.swf"); + let default_tiger = include_bytes!("../swf/tiger.swf"); swf_bytes = Vec::from(&default_tiger[..]); } @@ -98,9 +98,12 @@ fn main() { window.gl_make_current(&gl_context).unwrap(); // Create a Pathfinder renderer. - let mut renderer = Renderer::new(GLDevice::new(GLVersion::GL3, 0), - &FilesystemResourceLoader::locate(), - DestFramebuffer::full_window(pixel_size)); + let mut renderer = Renderer::new( + GLDevice::new(GLVersion::GL3, 0), + &FilesystemResourceLoader::locate(), + DestFramebuffer::full_window(pixel_size), + RendererOptions { background_color: Some(stage.background_color()) } + ); // Clear to swf stage background color. let mut scene = Scene::new(); scene.set_view_box(RectF::new( @@ -112,17 +115,13 @@ fn main() { draw_paths_into_scene(&library, &mut scene); // Render the canvas to screen. - renderer.device.clear(&ClearParams { - color: Some(stage.background_color()), - ..ClearParams::default() - }); let scene = SceneProxy::from_scene(scene, RayonExecutor); - let mut render_options = RenderOptions::default(); + let mut build_options = BuildOptions::default(); let scale_transform = Transform2DF::from_scale( Vector2F::new(device_pixel_ratio, device_pixel_ratio) ); - render_options.transform = RenderTransform::Transform2D(scale_transform); - scene.build_and_render(&mut renderer, render_options); + build_options.transform = RenderTransform::Transform2D(scale_transform); + scene.build_and_render(&mut renderer, build_options); window.gl_swap_window(); // Wait for a keypress. From f730e5d2db2b54c3bc654b0a6f7783280953432b Mon Sep 17 00:00:00 2001 From: Jon Hardie Date: Fri, 21 Jun 2019 11:12:10 +1200 Subject: [PATCH 12/26] [WIP] Remove incorrect debug assertion --- flash/src/lib.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/flash/src/lib.rs b/flash/src/lib.rs index fdc8b57e..34bf5518 100644 --- a/flash/src/lib.rs +++ b/flash/src/lib.rs @@ -155,7 +155,6 @@ pub fn draw_paths_into_scene(library: &SymbolLibrary, scene: &mut Scene) { // NOTE: Right now symbols only contain graphics. if let Symbol::Graphic(graphic) = symbol { for style_layer in graphic.layers() { - debug_assert_ne!(style_layer.shapes().len(), 0); let mut path = Outline::new(); let paint_id = scene.push_paint(&style_layer.fill()); From 3f601be08cecefde489c103a81d6e2036818fd7f Mon Sep 17 00:00:00 2001 From: Patrick Walton Date: Thu, 20 Jun 2019 16:57:20 -0700 Subject: [PATCH 13/26] Add C bindings to fill and stroke styles --- c/include/pathfinder/pathfinder.h | 10 ++++++++ c/src/lib.rs | 40 +++++++++++++++++++++++++++++-- 2 files changed, 48 insertions(+), 2 deletions(-) diff --git a/c/include/pathfinder/pathfinder.h b/c/include/pathfinder/pathfinder.h index 2833da22..3ab80705 100644 --- a/c/include/pathfinder/pathfinder.h +++ b/c/include/pathfinder/pathfinder.h @@ -53,6 +53,8 @@ struct PFPath; typedef struct PFPath *PFPathRef; struct PFCanvasFontContext; typedef struct PFCanvasFontContext *PFCanvasFontContextRef; +struct PFFillStyle; +typedef struct PFFillStyle *PFFillStyleRef; typedef uint8_t PFLineCap; typedef uint8_t PFLineJoin; typedef uint8_t PFArcDirection; @@ -67,6 +69,10 @@ struct PFColorF { float r, g, b, a; }; typedef struct PFColorF PFColorF; +struct PFColorU { + uint8_t r, g, b, a; +}; +typedef struct PFColorU PFColorU; struct PFVector2F { float x, y; }; @@ -149,6 +155,8 @@ void PFCanvasSetLineDash(PFCanvasRef canvas, const float *new_line_dashes, size_t new_line_dash_count); void PFCanvasSetLineDashOffset(PFCanvasRef canvas, float offset); +void PFCanvasSetFillStyle(PFCanvasRef canvas, PFFillStyleRef fill_style); +void PFCanvasSetStrokeStyle(PFCanvasRef canvas, PFFillStyleRef stroke_style); void PFCanvasFillPath(PFCanvasRef canvas, PFPathRef path); void PFCanvasStrokePath(PFCanvasRef canvas, PFPathRef path); PFPathRef PFPathCreate(); @@ -176,6 +184,8 @@ void PFPathEllipse(PFPathRef path, float start_angle, float end_angle); void PFPathClosePath(PFPathRef path); +PFFillStyleRef PFFillStyleCreateColor(PFColorU color); +void PFFillStyleDestroy(PFFillStyleRef fill_style); // `gl` diff --git a/c/src/lib.rs b/c/src/lib.rs index f071bdba..b70f62c9 100644 --- a/c/src/lib.rs +++ b/c/src/lib.rs @@ -11,11 +11,11 @@ //! C bindings to Pathfinder. use gl; -use pathfinder_canvas::{CanvasFontContext, CanvasRenderingContext2D, LineJoin}; +use pathfinder_canvas::{CanvasFontContext, CanvasRenderingContext2D, FillStyle, LineJoin}; use pathfinder_canvas::{Path2D, TextMetrics}; use pathfinder_geometry::basic::rect::{RectF, RectI}; use pathfinder_geometry::basic::vector::{Vector2F, Vector2I}; -use pathfinder_geometry::color::ColorF; +use pathfinder_geometry::color::{ColorF, ColorU}; use pathfinder_geometry::outline::ArcDirection; use pathfinder_geometry::stroke::LineCap; use pathfinder_gl::{GLDevice, GLVersion}; @@ -59,6 +59,7 @@ pub const PF_RENDERER_OPTIONS_FLAGS_HAS_BACKGROUND_COLOR: u8 = 0x1; pub type PFCanvasRef = *mut CanvasRenderingContext2D; pub type PFPathRef = *mut Path2D; pub type PFCanvasFontContextRef = *mut CanvasFontContext; +pub type PFFillStyleRef = *mut FillStyle; pub type PFLineCap = u8; pub type PFLineJoin = u8; pub type PFArcDirection = u8; @@ -95,6 +96,13 @@ pub struct PFColorF { pub b: f32, pub a: f32, } +#[repr(C)] +pub struct PFColorU { + pub r: u8, + pub g: u8, + pub b: u8, + pub a: u8, +} // `gl` pub type PFGLDeviceRef = *mut GLDevice; @@ -240,6 +248,17 @@ pub unsafe extern "C" fn PFCanvasSetLineDashOffset(canvas: PFCanvasRef, new_offs (*canvas).set_line_dash_offset(new_offset) } +#[no_mangle] +pub unsafe extern "C" fn PFCanvasSetFillStyle(canvas: PFCanvasRef, fill_style: PFFillStyleRef) { + (*canvas).set_fill_style(*fill_style) +} + +#[no_mangle] +pub unsafe extern "C" fn PFCanvasSetStrokeStyle(canvas: PFCanvasRef, + stroke_style: PFFillStyleRef) { + (*canvas).set_stroke_style(*stroke_style) +} + /// Consumes the path. #[no_mangle] pub unsafe extern "C" fn PFCanvasFillPath(canvas: PFCanvasRef, path: PFPathRef) { @@ -331,6 +350,16 @@ pub unsafe extern "C" fn PFPathClosePath(path: PFPathRef) { (*path).close_path() } +#[no_mangle] +pub unsafe extern "C" fn PFFillStyleCreateColor(color: *const PFColorU) -> PFFillStyleRef { + Box::into_raw(Box::new(FillStyle::Color((*color).to_rust()))) +} + +#[no_mangle] +pub unsafe extern "C" fn PFFillStyleDestroy(fill_style: PFFillStyleRef) { + drop(Box::from_raw(fill_style)) +} + // `gl` #[no_mangle] @@ -452,6 +481,13 @@ impl PFColorF { } } +impl PFColorU { + #[inline] + pub fn to_rust(&self) -> ColorU { + ColorU { r: self.r, g: self.g, b: self.b, a: self.a } + } +} + impl PFRectF { #[inline] pub fn to_rust(&self) -> RectF { From 010bc6607393ca09bb4ad46ece1d2861716423cc Mon Sep 17 00:00:00 2001 From: Patrick Walton Date: Thu, 20 Jun 2019 17:13:15 -0700 Subject: [PATCH 14/26] Upgrade `resvg` to 0.7 --- Cargo.lock | 135 ++++++++++++++++++++++++----------- demo/common/Cargo.toml | 2 +- demo/magicleap/Cargo.toml | 2 +- svg/Cargo.toml | 2 +- svg/src/lib.rs | 14 +--- utils/svg-to-skia/Cargo.toml | 2 +- 6 files changed, 100 insertions(+), 57 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 55ca57e5..fb9935bd 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -117,11 +117,10 @@ dependencies = [ [[package]] name = "base64" -version = "0.9.3" +version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "safemem 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -423,6 +422,14 @@ dependencies = [ "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "data-url" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "matches 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "deflate" version = "0.7.19" @@ -588,11 +595,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "float-cmp" -version = "0.4.0" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", -] [[package]] name = "float-ord" @@ -838,6 +842,15 @@ dependencies = [ "pkg-config 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "harfbuzz_rs" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", + "harfbuzz-sys 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "hashbrown" version = "0.1.8" @@ -971,6 +984,14 @@ name = "khronos_api" version = "3.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "kurbo" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "arrayvec 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "lazy_static" version = "1.3.0" @@ -1076,6 +1097,11 @@ dependencies = [ "libc 0.2.54 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "matches" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "memchr" version = "2.2.0" @@ -1356,7 +1382,7 @@ dependencies = [ "pathfinder_svg 0.1.0", "pathfinder_ui 0.1.0", "rayon 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", - "usvg 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "usvg 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1421,7 +1447,7 @@ dependencies = [ "pathfinder_ui 0.1.0", "rayon 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", "smallvec 0.6.9 (registry+https://github.com/rust-lang/crates.io-index)", - "usvg 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "usvg 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1475,7 +1501,7 @@ dependencies = [ "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", "pathfinder_geometry 0.3.0", "pathfinder_renderer 0.1.0", - "usvg 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "usvg 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1712,7 +1738,7 @@ dependencies = [ [[package]] name = "rctree" -version = "0.2.2" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -1769,10 +1795,10 @@ dependencies = [ [[package]] name = "roxmltree" -version = "0.4.1" +version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "xmlparser 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", + "xmlparser 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1804,11 +1830,6 @@ name = "ryu" version = "0.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "safemem" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "same-file" version = "1.0.4" @@ -1998,27 +2019,27 @@ source = "registry+https://github.com/rust-lang/crates.io-index" name = "svg-to-skia" version = "0.1.0" dependencies = [ - "usvg 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "usvg 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "svgdom" -version = "0.15.0" +version = "0.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "roxmltree 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", + "roxmltree 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", "simplecss 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", - "svgtypes 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "svgtypes 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "svgtypes" -version = "0.3.0" +version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "float-cmp 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "float-cmp 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", "phf 0.7.24 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -2098,11 +2119,24 @@ dependencies = [ "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "ttf-parser" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "ucd-util" version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "unicode-bidi" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "matches 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "unicode-normalization" version = "0.1.8" @@ -2112,8 +2146,13 @@ dependencies = [ ] [[package]] -name = "unicode-segmentation" -version = "1.2.1" +name = "unicode-script" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "unicode-vo" +version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -2136,16 +2175,22 @@ dependencies = [ [[package]] name = "usvg" -version = "0.4.0" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "base64 0.9.3 (registry+https://github.com/rust-lang/crates.io-index)", + "base64 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)", + "data-url 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "harfbuzz_rs 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "kurbo 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", "libflate 0.1.22 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "lyon_geom 0.12.4 (registry+https://github.com/rust-lang/crates.io-index)", - "rctree 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "svgdom 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)", - "unicode-segmentation 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "memmap 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rctree 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", + "svgdom 0.17.0 (registry+https://github.com/rust-lang/crates.io-index)", + "ttf-parser 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-bidi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-script 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-vo 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -2343,7 +2388,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "xmlparser" -version = "0.8.1" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" [metadata] @@ -2360,7 +2405,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum autocfg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a6d640bee2da49f60a4068a7fae53acde8982514ab7bae8b8cea9e88cbcfd799" "checksum backtrace 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)" = "f106c02a3604afcdc0df5d36cc47b44b55917dbaf3d808f71c163a0ddba64637" "checksum backtrace-sys 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)" = "797c830ac25ccc92a7f8a7b9862bde440715531514594a6154e3d4a54dd769b6" -"checksum base64 0.9.3 (registry+https://github.com/rust-lang/crates.io-index)" = "489d6c0ed21b11d038c31b6ceccca973e65d73ba3bd8ecb9a2babf5546164643" +"checksum base64 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0b25d992356d2eb0ed82172f5248873db5560c4721f564b13cb5193bda5e668e" "checksum bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "228047a76f468627ca71776ecdebd732a3423081fcf5125585bcd7c49886ce12" "checksum blake2-rfc 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)" = "5d6d530bdd2d52966a6d03b7a964add7ae1a288d25214066fd4b600f0f796400" "checksum block 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "0d8c1fef690941d3e7788d328517591fecc684c084084702d6ff1641e993699a" @@ -2388,6 +2433,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum crossbeam-epoch 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "927121f5407de9956180ff5e936fe3cf4324279280001cd56b669d28ee7e9150" "checksum crossbeam-utils 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "2760899e32a1d58d5abb31129f8fae5de75220bc2176e77ff7c627ae45c918d9" "checksum crossbeam-utils 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)" = "f8306fcef4a7b563b76b7dd949ca48f52bc1141aa067d2ea09565f3e2652aa5c" +"checksum data-url 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d33fe99ccedd6e84bc035f1931bb2e6be79739d6242bd895e7311c886c50dc9c" "checksum deflate 0.7.19 (registry+https://github.com/rust-lang/crates.io-index)" = "8a6abb26e16e8d419b5c78662aa9f82857c2386a073da266840e474d5055ec86" "checksum derivative 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6073e9676dbebdddeabaeb63e3b7cefd23c86f5c41d381ee1237cc77b1079898" "checksum dirs 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "3fd78930633bd1c6e35c4b42b1df7b0cbc6bc191146e512bb3bedf243fcc3901" @@ -2404,7 +2450,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "795bd83d3abeb9220f257e597aa0080a508b27533824adf336529648f6abf7e2" "checksum failure_derive 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "ea1063915fd7ef4309e222a5a07cf9c319fb9c7836b1f89b85458672dbb127e1" "checksum fixedbitset 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "86d4de0081402f5e88cdac65c8dcdcc73118c1a7a465e2a05f0da05843a8ea33" -"checksum float-cmp 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "134a8fa843d80a51a5b77d36d42bc2def9edcb0262c914861d08129fd1926600" +"checksum float-cmp 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "17ae3a6394183450225f33d9419cbd627b3cfc831e14f3f1146d5bcaf984e00c" "checksum float-ord 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7bad48618fdb549078c333a7a8528acb57af271d0433bdecd523eb620628364e" "checksum font-kit 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5be0133b580e2920076afd5bd4b81dc172d10e5653bd1c516476718d52347859" "checksum foreign-types 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" @@ -2428,6 +2474,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum glutin_wgl_sys 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "f801bbc91efc22dd1c4818a47814fc72bf74d024510451b119381579bfa39021" "checksum harfbuzz 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "46f7426266a5ece3e49eae6f48e602c0f8c39917354a847eac9c06437dcde8da" "checksum harfbuzz-sys 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e1042ab0b3e7bc1ff64f7f5935778b644ff2194a1cae5ec52167127d3fd23961" +"checksum harfbuzz_rs 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "534c8e9b15d8db6e69654b07dad955f4132757194e7d2bba620d38cf08996088" "checksum hashbrown 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "3bae29b6653b3412c2e71e9d486db9f9df5d701941d86683005efb9f2d28e3da" "checksum humantime 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3ca7e5f2e110db35f93b837c81797f3714500b81d517bf20c431b16d3ca4f114" "checksum image 0.19.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ebdff791af04e30089bde8ad2a632b86af433b40c04db8d70ad4b21487db7a6a" @@ -2443,6 +2490,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum khronos 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c0711aaa80e6ba6eb1fa8978f1f46bfcb38ceb2f3f33f3736efbff39dac89f50" "checksum khronos_api 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "037ab472c33f67b5fbd3e9163a2645319e5356fcd355efa6d4eb7fff4bbcb554" "checksum khronos_api 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e2db585e1d738fc771bf08a151420d3ed193d9d895a36df7f6f8a9456b911ddc" +"checksum kurbo 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2e6076333105a72e8d2c227ba6a6da0dc3c8e5f53f02053f598a6087a1ea8991" "checksum lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bc5729f27f159ddd61f4df6228e827e86643d4d3e7c32183cb30a1c08f604a14" "checksum libc 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)" = "e32a70cf75e5846d53a673923498228bbec6a8624708a9ea5645f075d6276122" "checksum libc 0.2.54 (registry+https://github.com/rust-lang/crates.io-index)" = "c6785aa7dd976f5fbf3b71cfd9cd49d7f783c1ff565a858d71031c6c313aa5c6" @@ -2456,6 +2504,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum lyon_path 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e9dc8e0746b7cca11960b602f7fe037bb067746a01eab4aa502fed1494544843" "checksum lzw 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7d947cbb889ed21c2a84be6ffbaebf5b4e0f4340638cba0444907e38b56be084" "checksum malloc_buf 0.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "62bb907fe88d54d8d9ce32a3cceab4218ed2f6b7d35617cafe9adf84e43919cb" +"checksum matches 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "7ffc5c5338469d4d3ea17d269fa8ea3512ad247247c30bd2df69e68309ed0a08" "checksum memchr 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2efc7bc57c883d4a4d6e3246905283d8dae951bb3bd32f49d6ef297f546e1c39" "checksum memmap 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e2ffa2c986de11a9df78620c01eeaaf27d94d3ff02bf81bfcca953102dd0c6ff" "checksum memmap 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6585fd95e7bb50d6cc31e20d4cf9afb4e2ba16c5846fc76793f11218da9c475b" @@ -2505,19 +2554,18 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum rand_xorshift 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cbf7e9e623549b0e21f6e97cf8ecf247c1a8fd2e8a992ae265314300b2455d5c" "checksum rayon 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "373814f27745b2686b350dd261bfd24576a6fb0e2c5919b3a2b6005f820b0473" "checksum rayon-core 1.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b055d1e92aba6877574d8fe604a63c8b5df60f60e5982bf7ccbb1338ea527356" -"checksum rctree 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "da0b3901505c2faa2390e27188078852eb3ed0dd9176e2153f403cdcdd18e0e7" +"checksum rctree 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "193d11923532b462b7231e2d7fb785a9c0d580b03c0eccac460a1e9ee0e87fda" "checksum rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2" "checksum redox_syscall 0.1.54 (registry+https://github.com/rust-lang/crates.io-index)" = "12229c14a0f65c4f1cb046a3b52047cdd9da1f4b30f8a39c5063c8bae515e252" "checksum redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7e891cfe48e9100a70a3b6eb652fef28920c117d366339687bd5576160db0f76" "checksum redox_users 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3fe5204c3a17e97dde73f285d49be585df59ed84b50a872baf416e73b62c3828" "checksum regex 1.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "8f0a0bcab2fd7d1d7c54fa9eae6f43eddeb9ce2e7352f8518a814a4f65d60c58" "checksum regex-syntax 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)" = "dcfd8681eebe297b81d98498869d4aae052137651ad7b96822f09ceb690d0a96" -"checksum roxmltree 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "02660467d0c2da1b6276042501aee6e15ec5b8ff59423243f185b294cd53acf3" +"checksum roxmltree 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "330d8f80a274bc3cb608908ee345970e7e24b96907f1ad69615a498bec57871c" "checksum rustc-demangle 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)" = "ccc78bfd5acd7bf3e89cffcf899e5cb1a52d6fafa8dec2739ad70c9577a57288" "checksum rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" "checksum rusttype 0.7.6 (registry+https://github.com/rust-lang/crates.io-index)" = "25951e85bb2647960969f72c559392245a5bd07446a589390bf427dda31cdc4a" "checksum ryu 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "b96a9549dc8d48f2c283938303c4b5a77aa29bfbc5b54b084fb1630408899a8f" -"checksum safemem 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8dca453248a96cb0749e36ccdfe2b0b4e54a61bfef89fb97ec621eb8e0a93dd9" "checksum same-file 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "8f20c4be53a8a1ff4c1f1b2bd14570d2f634628709752f0702ecdd2b3f9a5267" "checksum scoped_threadpool 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "1d51f5df5af43ab3f1360b429fa5e0152ac5ce8c0bd6485cae490332e96846a8" "checksum scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "94258f53601af11e6a49f722422f6e3425c52b06245a5cf9bc09908b174f5e27" @@ -2541,8 +2589,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum stable_deref_trait 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "dba1a27d3efae4351c8051072d619e3ade2820635c3958d826bfea39d59b54c8" "checksum stb_truetype 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "69b7df505db8e81d54ff8be4693421e5b543e08214bd8d99eb761fcb4d5668ba" "checksum strsim 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a" -"checksum svgdom 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7a9b53b3ed152fc6b871f7232a8772c640567fd25d056941450637ecba32924d" -"checksum svgtypes 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c43c25e6de7264024b5e351eb0c342039eb5acf51f2e9d0099bbd324b661453b" +"checksum svgdom 0.17.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9ddce601e49ed213b0126ff4172cd9f5f8dba5f1df2277ecbe0e298f9865baba" +"checksum svgtypes 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "444c882c28925ae0585df228a90f9951569588646ceca4753560de93cdd02258" "checksum syn 0.15.34 (registry+https://github.com/rust-lang/crates.io-index)" = "a1393e4a97a19c01e900df2aec855a29f71cf02c402e2f443b8d2747c25c5dbe" "checksum synstructure 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "73687139bf99285483c96ac0add482c3776528beac1d97d444f6e91f203a2015" "checksum term 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "edd106a334b7657c10b7c540a0106114feadeb4dc314513e97df481d5d966f42" @@ -2551,13 +2599,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum textwrap 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060" "checksum thread_local 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c6b53e329000edc2b34dbe8545fd20e55a333362d0a321909685a19bd28c3f1b" "checksum time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)" = "db8dcfca086c1143c9270ac42a2bbd8a7ee477b78ac8e45b19abfb0cbede4b6f" +"checksum ttf-parser 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "29637063e570f7e5260924119666113215386c1b94e1d1ceb4525e269dfbe2d0" "checksum ucd-util 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "535c204ee4d8434478593480b8f86ab45ec9aae0e83c568ca81abf0fd0e88f86" +"checksum unicode-bidi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "49f2bd0c6468a8230e1db229cff8029217cf623c767ea5d60bfbd42729ea54d5" "checksum unicode-normalization 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "141339a08b982d942be2ca06ff8b076563cbe223d1befd5450716790d44e2426" -"checksum unicode-segmentation 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "aa6024fc12ddfd1c6dbc14a80fa2324d4568849869b779f6bd37e5e4c03344d1" +"checksum unicode-script 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "09f03ad95feb4fde244d79985bfd79eb34ff2702fedb441d2ba3f4ff813efd19" +"checksum unicode-vo 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b1d386ff53b415b7fe27b50bb44679e2cc4660272694b7b6f3326d8480823a94" "checksum unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "882386231c45df4700b275c7ff55b6f3698780a650026380e72dabe76fa46526" "checksum unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc" "checksum unreachable 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "382810877fe448991dfc7f0dd6e3ae5d58088fd0ea5e35189655f84e6814fa56" -"checksum usvg 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f9ebf4d5244ba2e8305caf9de7949377794ecdea5a9e3c84fc5610d78d21f5ee" +"checksum usvg 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e3dbc9befcea2c86048398f47e0e4c98a748e6d9404eb3de564eb7048a7ec635" "checksum utf8-ranges 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "796f7e48bef87609f7ade7e06495a87d5cd06c7866e6a5cbfceffc558a243737" "checksum vec_map 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "05c78687fb1a80548ae3250346c3db86a80a7cdd77bda190189f2d0a0987c81a" "checksum version_check 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "914b1a6776c4c929a602fafd8bc742e06365d4bcbe48c30f9cca5824f70dc9dd" @@ -2579,4 +2630,4 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum xdg 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d089681aa106a86fade1b0128fb5daf07d5867a509ab036d99988dec80429a57" "checksum xml-rs 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3c1cb601d29fe2c2ac60a2b2e5e293994d87a1f6fa9687a31a15270f909be9c2" "checksum xml-rs 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "541b12c998c5b56aa2b4e6f18f03664eef9a4fd0a246a55594efae6cc2d964b5" -"checksum xmlparser 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d78a7f29bb57edf63321d545d84f99360df71df36929a090bc067e1bcb65e34d" +"checksum xmlparser 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ecec95f00fb0ff019153e64ea520f87d1409769db3e8f4db3ea588638a3e1cee" diff --git a/demo/common/Cargo.toml b/demo/common/Cargo.toml index c73270df..45ea0798 100644 --- a/demo/common/Cargo.toml +++ b/demo/common/Cargo.toml @@ -11,7 +11,7 @@ pf-gl = [] clap = "2.32" gl = "0.6" rayon = "1.0" -usvg = "0.4" +usvg = "0.7" [dependencies.image] version = "0.21" diff --git a/demo/magicleap/Cargo.toml b/demo/magicleap/Cargo.toml index 22a81069..efba31a8 100644 --- a/demo/magicleap/Cargo.toml +++ b/demo/magicleap/Cargo.toml @@ -7,7 +7,7 @@ authors = ["Alan Jeffrey "] [dependencies] gl = "0.6" rayon = "1.0" -usvg = "0.4" +usvg = "0.7" egl = "0.2" log = "0.4" smallvec = "0.6" diff --git a/svg/Cargo.toml b/svg/Cargo.toml index 61d0280a..d735fdaf 100644 --- a/svg/Cargo.toml +++ b/svg/Cargo.toml @@ -6,7 +6,7 @@ authors = ["Patrick Walton "] [dependencies] bitflags = "1.0" -usvg = "0.4" +usvg = "0.7" [dependencies.pathfinder_geometry] path = "../geometry" diff --git a/svg/src/lib.rs b/svg/src/lib.rs index ab664535..e9f14486 100644 --- a/svg/src/lib.rs +++ b/svg/src/lib.rs @@ -104,10 +104,6 @@ impl BuiltSVG { self.result_flags .insert(BuildResultFlags::UNSUPPORTED_MASK_ATTR); } - if group.opacity.is_some() { - self.result_flags - .insert(BuildResultFlags::UNSUPPORTED_OPACITY_ATTR); - } for kid in node.children() { self.process_node(&kid, &transform) @@ -140,7 +136,7 @@ impl BuiltSVG { line_width: f32::max(stroke.width.value() as f32, HAIRLINE_STROKE_WIDTH), line_cap: LineCap::from_usvg_line_cap(stroke.linecap), line_join: LineJoin::from_usvg_line_join(stroke.linejoin, - stroke.miterlimit as f32), + stroke.miterlimit.value() as f32), }; let path = UsvgPathToSegments::new(path.segments.iter().cloned()); @@ -194,10 +190,6 @@ impl BuiltSVG { self.result_flags .insert(BuildResultFlags::UNSUPPORTED_NESTED_SVG_NODE); } - NodeKind::Text(..) => { - self.result_flags - .insert(BuildResultFlags::UNSUPPORTED_TEXT_NODE); - } } } } @@ -268,8 +260,8 @@ impl PaintExt for Paint { fn usvg_rect_to_euclid_rect(rect: &UsvgRect) -> RectF { RectF::new( - Vector2F::new(rect.x as f32, rect.y as f32), - Vector2F::new(rect.width as f32, rect.height as f32), + Vector2F::new(rect.x() as f32, rect.y() as f32), + Vector2F::new(rect.width() as f32, rect.height() as f32), ) } diff --git a/utils/svg-to-skia/Cargo.toml b/utils/svg-to-skia/Cargo.toml index a3a57cb4..1024e7c1 100644 --- a/utils/svg-to-skia/Cargo.toml +++ b/utils/svg-to-skia/Cargo.toml @@ -5,4 +5,4 @@ authors = ["Patrick Walton "] edition = "2018" [dependencies] -usvg = "0.4" +usvg = "0.7" From 8ec4f04deb8894d21e712b564a18c5a33cf3dfcd Mon Sep 17 00:00:00 2001 From: Patrick Walton Date: Thu, 20 Jun 2019 21:34:46 -0700 Subject: [PATCH 15/26] Make `canvas-text` use a custom font --- resources/fonts/SIL Open Font License.txt | 49 ++++++++++++++++++++++ resources/fonts/overpass-regular.otf | Bin 0 -> 69728 bytes 2 files changed, 49 insertions(+) create mode 100755 resources/fonts/SIL Open Font License.txt create mode 100755 resources/fonts/overpass-regular.otf diff --git a/resources/fonts/SIL Open Font License.txt b/resources/fonts/SIL Open Font License.txt new file mode 100755 index 00000000..ec2cdcae --- /dev/null +++ b/resources/fonts/SIL Open Font License.txt @@ -0,0 +1,49 @@ +Copyright 2011 Red Hat, Inc., +with Reserved Font Name OVERPASS. + +This Font Software is licensed under the SIL Open Font License, Version 1.1. +This license is copied below, and is also available with a FAQ at: +http://scripts.sil.org/OFL + + +This Font Software is licensed under the SIL Open Font License, Version 1.1. +This license is copied below, and is also available with a FAQ at: http://scripts.sil.org/OFL + +----------------------------------------------------------- +SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007 +----------------------------------------------------------- + +PREAMBLE +The goals of the Open Font License (OFL) are to stimulate worldwide development of collaborative font projects, to support the font creation efforts of academic and linguistic communities, and to provide a free and open framework in which fonts may be shared and improved in partnership with others. + +The OFL allows the licensed fonts to be used, studied, modified and redistributed freely as long as they are not sold by themselves. The fonts, including any derivative works, can be bundled, embedded, redistributed and/or sold with any software provided that any reserved names are not used by derivative works. The fonts and derivatives, however, cannot be released under any other type of license. The requirement for fonts to remain under this license does not apply to any document created using the fonts or their derivatives. + +DEFINITIONS +"Font Software" refers to the set of files released by the Copyright Holder(s) under this license and clearly marked as such. This may include source files, build scripts and documentation. + +"Reserved Font Name" refers to any names specified as such after the copyright statement(s). + +"Original Version" refers to the collection of Font Software components as distributed by the Copyright Holder(s). + +"Modified Version" refers to any derivative made by adding to, deleting, or substituting -- in part or in whole -- any of the components of the Original Version, by changing formats or by porting the Font Software to a new environment. + +"Author" refers to any designer, engineer, programmer, technical writer or other person who contributed to the Font Software. + +PERMISSION & CONDITIONS +Permission is hereby granted, free of charge, to any person obtaining a copy of the Font Software, to use, study, copy, merge, embed, modify, redistribute, and sell modified and unmodified copies of the Font Software, subject to the following conditions: + +1) Neither the Font Software nor any of its individual components, in Original or Modified Versions, may be sold by itself. + +2) Original or Modified Versions of the Font Software may be bundled, redistributed and/or sold with any software, provided that each copy contains the above copyright notice and this license. These can be included either as stand-alone text files, human-readable headers or in the appropriate machine-readable metadata fields within text or binary files as long as those fields can be easily viewed by the user. + +3) No Modified Version of the Font Software may use the Reserved Font Name(s) unless explicit written permission is granted by the corresponding Copyright Holder. This restriction only applies to the primary font name as presented to the users. + +4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font Software shall not be used to promote, endorse or advertise any Modified Version, except to acknowledge the contribution(s) of the Copyright Holder(s) and the Author(s) or with their explicit written permission. + +5) The Font Software, modified or unmodified, in part or in whole, must be distributed entirely under this license, and must not be distributed under any other license. The requirement for fonts to remain under this license does not apply to any document created using the Font Software. + +TERMINATION +This license becomes null and void if any of the above conditions are not met. + +DISCLAIMER +THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM OTHER DEALINGS IN THE FONT SOFTWARE. \ No newline at end of file diff --git a/resources/fonts/overpass-regular.otf b/resources/fonts/overpass-regular.otf new file mode 100755 index 0000000000000000000000000000000000000000..c9531c0e49f9487c545b5707b9bebfa33805930c GIT binary patch literal 69728 zcmdqJd0bRw`v?5J&ulQGSd3!|4s*a=0Rcr6S7Z?q0a;vH)PXs`=rDsb188MhmRgp3 zdzPh^xsj8W)uBfo2_{0};fc-~+ zQCZ_k%Esm#82BETsVfkkTUatMW!i|k3qaT%0A^IwIBSdl%=io#>jFAGS}i$UmRnBf z02~1@q`F#ihOIZ)fUp?=dREs2=lpW&hS>n?0GLW^oO5c~(INmi1iXD5gFlPy}`q00W={ns*L(a(br`|AJ0;o;nM2{sI&F*u6>Y&lB!^Bd;qkAxF3lgM}J&6Kaqtlp#YfqlZv|9H9)u zs6Tw2JEcn9Ue7swLowdW&zT)Hq0slxNPQMd<5x?H3P(=d?phj=mv9>ST;L6UGM$^;#B ztQMjWfm9&{CG2;0U{&!EZnFC1W{vida9Cy+YqT$~?$-YR( z|L(aP_2Fgjz>$jqu+hH`)g-_5ySBqHT19Z?8;~L$yh!TEAN3t7kPpdH+xD-M0 zhb=@r_92qZL@e{5E4u{|tO^cRjR9;hI$)I?o@_r7gleSe zx}YzA-jBX)KazAQDAlDPMOTedVSfws)pg@=Bkx-P7mcI2+CJG1^w)Jk0<9GS;Vq=- zouLIvOKLE0qN>*v~nb_iX5+%ttgGW9y&06H~>%Nb6T0Y>77$?_pp|tPVjZTH z^$@K-t!%&$>vFAZY*TMSk@a1zJ`7zt+q7~x#&izNX~s>RXKD2o^zZz&R_=flTPLmD zF*ekP(=dESadF~j2# zd5?hTmjaT%UUDTC)=U0cXCP24Rn>W%{y~XJNlC*=1%`)O611jCl0V?~dBrPqxx8!W zU33RTrx^4*T~dwHKTGsgw#O(-^3+RWj?WtmsKv?dV71@vtqS_Q@nUJUuf`b=uk}^T za(i2;>s!%}=u1xc?}@Aq25Zv?4s2*>Nc2mtYG*L9!dKI#(nWYw5*pOdqlcL9u8_O| z$!u<2mao>1pYdjMX|+4R@fS;cmB9w5Um}t{>S&i(=XFVbF<32$C3*Q`VXfpE&FFL(0&Q4FjCpzn$ZjZCvBZ&>}V72HJb2281 z&S1J(qbX3~ch?33i2=7K(dVxkSeTP_o+3N`pr&#HiBtF7NQmXVjYorFBf0pR>iVfB7ifX=IK&)}j70V?t zQ0??fE>$KqG>PP*p0!SY&@1@^)$UqVGQME7l8YnknJYR2qQ~d0qGzyLn#-B( z^##R%&*LHw5UiGJ0;Jx7M3Io-i^Yp>Z-uAM<)(q&xuQ$*yX#e^6VZWqvBK#kbjs_z zE)O9h)s#yv7nRy$;qs zw85FPptU^^FIM{+qey$rdS3u%cQt9?cnOca_`g^n~2z<@_P{AysgH;H$jMEm!zzYJFbG8w?P=Z4K$~`A2I`2w9-!A=|FW zMc-;VHBOgAvpHSdu!6pL(It7Lpxav&PZ|)YD-Q(S!8)q=So0QC&s~hqBYn)(RrRH9 z&<%Ol%ZQJsr7EhO-YQbHN}s>RN&e4I)#M~Y3fNAgxWbBFsX>&y^=`k1K0sKe0e^ zQy}>(??kW9&*}A5itb=QbbDRydbg|2>1m@u5lCz>(6&>l3)9qD*r?cEwFY$Uc<@Nf4?g}-4 z2iy2-?&kwiD4c12%_VC5BTkH4L`rVY!)Ho}u-Cn7+dyN!yx|~6$Sm~BLt^f~>Zm+rknW)=Ksg>%;+eL6+ zfZQz~qlI9}8E|{%iuG=(L5-2LcwIp9Cz{QJ`iTX;zlihiWl|TA`0&5FX*F7Sq(DHF z=G1!J749In>7e8#TWVu~n&pMuW`)o1mjbnY_1R*V^_$A6)G|%j%tfjWrDk=BusvRs=2S?v+?<^iv%J0rkL0RS z8Q$Up-9B#{Jg$T@1!xj+8>IbeY89-e4C3F2C(&$9Re95nz&2^5&)>#5alb$*D^-Vr zP`p@E7vQ;6+ZZW%gKj^io1q;|Yf7X#K|V-J!rBhJJP-T-JpXFPiBPC1rBG9lK{;3Z zU01nO;iJ6NTj%j`N!0t?F40{X^0D0THP;hz(Je`AjYOf8@3OM;N;2~^@+M>#n@e-E z)xB0pVNU7fjN)uDuS6^=E}WE?m7OJil2Ib&m3$g6PR=XMEi5Y)CubBFXB3o96$^93 zjDo4+_`HIwcrklQQE_%jiC9=H=1nNd&&$q=7xM}-^UJdG3dV_J%Sy$9LfXwu$Scjx z5=#sDP;IKb>=K%6LUwUxZbm_A#@M|4ywa)hVoqLZ0nM3HSS)6UMH$7Vd6{MT8O35z zS#eQeNw%0#kR=ur7UUJ=6z3I;%bt*3P)ZYJ78Xq{&Ks9o8ZQ=Qlx7!{#*3xJ8ClsA zGK$B?6NZJQx!J`c?~*9y6^I3eV)i5&T#}oSpDz+aTILXQ3-hzGi^Z|oVt!u6*nHwu zF~^?sFJ8>bn2<4!CIT+2tE9x*>e|unpj0#6?HXB_lRv#dDi=jM9tda$AywWwel|eq zwnwTA4kYI<`4g*yHJ+C98|~;PuTsnttDW_<1)<$>ouAT?c+nlCl&pNN8bv7p_`D+7 zNTAwRN1G6yA5^)Wbh09TEanBA&I++WY6$wg$b=8Imb%75kdIj zgbNaCINq}$!iUO#%cCqv@Nnuy7jK$6B~G`zz<1^Pz#y z>g0HZdOG1j06vItq8?7Txn-5Z!|`plpa*9=VL+L@(*S$hDI^QysS>!jD>2D<}HBT)#+91MPHE#Zbk)9&U{vq=S_lC*n?M4bpV7 zd9}^S`P9IvA}>omPecQ^tUPKG|QjvQ|(h;%{k_-7E)g!gePm&5@qQ*0IPKrpx z2d@?_$XC?zwN$T6+);VzM*xW}9)(s?ZGqMx36f*QDkzX9Ccg|)wQUVw2nAKQJ3UMJgaJXS20!F zskaC(r z5HARKRkw(Hw07Hkhxn*!FmXNPHA1`%Njt>b|HP3i^I2V;@VU}>m5-D?G(ggFFOrPP z*$^fwe+hfyE$N7A8Es=8@s4P0wF2V6TyCu)&(U7f+u}=e&*pxEO0B++^o1g7tKQJ8 zWD#mVieRJxZ80Ift8u*jdc*-Amq4rjI=N3&bzhw~L@wZ``_m!qFv)irRJSNTngbu5^Iem z0rD_tzK+>8}o~&|K^+EyEaUUMi z6IG_vlSZ`l9jZ6?p$>kY5t1B26p}WRXP|eog7$e!TkB{qZ`JFNALQ~8yYu|9z4f-{ zi3O@1|E(NCTGiIx1Kc($;BM!!NhTr62|MyK#Anr?5T$Ci*M2`no}DmmwH;M1A>0eO zFRkKSqbPJ)w)wYshx8|ueW-awXs4uRCaqlfYqqS$e#$y1ZieEpDqo6SSBgmg7yS#- zIpHrcuw7RDw{(W&b0rH^wUb&xo|yJ_gnh{NeO$|^2Wd4$D{3LlQ+)u*vz*gPxdO#r z-b3unpOm$!xkacywW?VRMOR7e+=8FV@wQT-Y^6PS+xPholGp5mEQ<0a;)ALs6#Z52 zOBSc*PbxL4d_tLID;LyU`QK?n$itHVmCyi@>jY(dl(l+Wd~HaY8Jt%Xo&5im$VM8t)r9O%rM_)^qfC^tJ;FUC zFV#Lt(=X4oRO&;r`+Gid>f6Kv+9?%d0`gG8_fNE6649IcW-4d3j}s{3Sk-XrYCY9Z zy(h_tJiaPJl?#L``CZ~zYrd^&k*X84qmy`hNP=ptZ%@Au<=hLAMufD2a`=$H3S|NR znFEB0x{{g$(R(Q0oy*@sb5aXs3#}No=6q^fC?{6O5$#vc|0zFr0q%`$D^OITm1#Y7hekVYvJt}Lavwz8q~5giQBMu&P3^B*(SPvMT3#B8 z^=kfk`CdcCi)2-)*-Q$j{Qth@e=jpNCXmNXX&U7qs;2#4_8G+4f49@1>|EXV zhAgDjAE~)ANiw8Y>RAGvIkZ}-DlhevSIz&`Q??M+>gX%w*P%R3-Q&=VL}!RYqyeG5 zo|@&g*UwPSM|lkCSpwG=HL}r~66Wv>wtZ$-%`Q=+BK?{&`LolimEo@=UUWC z74eyHz0w}s$9>b~>$K;yx<8|Am$Z{?l_IUm@%EXO>RbJq?F`bq2JNl>lXd=I>_lCy zRrlyL_CI9P?e-SxeuX$gnoz6l?Z^kT#%ba)X`C9Dt{ef|$GlKR7t#i@8b8-0%FaU` zR?YLSbPv*YClu0u)i%ifL)k5z#kJb{618QKB2o*9HR zg?g&I3`KI{GRZMSRY=mIbE&~x)^y%YRubBigm!Z6^T+>0b?d0MQKn7i)}{yDfP`@R zcX3EPnNwqM`!fiY67_V2C{!(%A~DIHyd!AOhg!&M5NH3B zwyU$w;X6w@?GAC5JnbxwUjx@p7tfMfDO4kL+dNR!fmV*S<;Q=^XVp8lu5x8glPp61 zC)8IxgZRH$kD8OFw$q!xmmqQMui23*i7RDJ)L-?I|6wPj%}iQAa!_OMmGU{#5Ou#v zRFh98N&h!z6ogBN$8=_`uGC%&|8B*$^M|yn?S7&Cc~r<>kS-FA|9?3D`g@(Yd{MyQ8!I91$-2ZBhC?~8JtJNGdcy$L>cEawG^QY#VA6d zc2h{y6IO&RothRP2gUq34%u8X>J1~^!_bLlA&M}S_ZWv9_Vg0Q{$jIr>fn=)zD~_heUk=m)}H`X?!9&>At)@6-3u$&hJ*Pt9&L5 zNl$1+^_*P2Yg1)RYZA^Od`kJsbklsf6v@iy&Y4yseWN#8fh>VEsSp!*TgVDkJqpRO zOw&SjRvOn{$LaQqtR>VhH16Md2z9Q|+Jtc{?WB{$Cly1IvdWGBJa6Lv@(#a(-{cLv z?96;1kJ5A^l!#hXqZXri9!@7O)4Bg0soi)^=R1#bhp zp?xdm`*ij_uqE@S>`kSh1|H;bpPt8Orr%{Ce@%Ivx&x@>cL8dysh;ntI|Vg2SNA~_ z+11EFxd)whs^@s243)A_x>KP29IdVHASsg2nIes(bCE=dVrMRc0GvE0B>Sg57vwK>0HG%UJzxxKf6W+Ae-+54jEmvzw!({|NXx%xCUL(4N-_jci0gF z2Smgo4n5Elz0ezd&=>vC9|I7N1SDc0|K+U|48mZfVhGYO6vL2?;TVCD7=_Uo!__#G zt6L6tae25FaFF_z#i+>NEU2lrwb zmSY80Vii_n4erDJcmNOLAv}yn@F>>eF+7fScmhviJvLw?p2E}EglDiBTd)<|@GPFg zc07+4@FHHq%XkGluoJIh7hc0|ypA{6I_$xl*o(LDHr~Ozcn|xqAMfJ;4&o3F;{$w% zkMJ=*!KXNaqd11o@Hvj-3w((aIEhm@jWallMw|oi6~4wd_!j5!9sYsu@dJLuPxu+X z;Gg&vdOdyU<5rA;0i$p$E-?d3Wn)wFr!lg_6uZGt#Fe4knGFd5evAJv&JItDe zu0opdp76f#d7JeY#QZ8+#jc{r*H00LU2*-A*z03g#J(8&MeG@E{j1|_aot+hcWLXh zOP4PF0bKf5TXnzGM}5241YCRrxOmIOsz1a3JkgM&Q<-0~FF)Zu z=-Vl`0Bk6`pFPVyU_S_*0U<_+7g7LWhzf202`R!5VQkx)EBzCC3qyq*fq%>e5K2{O z`%lOfasjpuuW&v74bQ-ehwua*!*=Y(4*ZU__#XG;DMaFGtixtJf}{8uo$x$fM+7?J zD!hz6_!7tQCby^cXuwI#!527zvzj(C%*9t+BlqGa*suZLa=pA6CWPZr%)>3X6$>yQ zx8X(HjytfB+ujl^=C&tbDelERScVl?jstiJtFV$=U>M9egi8#JF@foro*9^tnOGPL zXJ%$$9au*e!8)<4*wrkOSy^XhV_n!atSjrrqF6NR&g?9PIhe>|Ssd%Zda_=uH|xXt zvVJ(v5?CTjV##bUOJze?8XL-nv2-?^jbJ0$DCnSPquCgi!N#&omc_DJ4jadESsuHV zjc5660@*MtW+kkYm9a@|GMmDtvg_FO>;`rt3^1}8%*k9#VwJ3lRWmo6$!0MRt6^T| zW3_BH^Rob}XANutyA6lg?Q9{tgWU-WIr|VsEo| z*t_gKwvX*)``P>K06WMIu}|2?>@fR)eaJpyd)S-Uiq32;cCyF0Kk7ib72a3Vu(!0Y z2HXnpc(M*4VDx-KgI54N31B^d2LNo);5PspHFyTVQyN$SJgvb)05)kr^HD#7#{g{B zU^{><8qk*swra2gz%~tj2k@*0YXLl`!S?_kPjlQ4;CT%QmlrgM1n{B;R|9xS1ETR| z4G0&ali(46uTAUISCe*X@H2o{HRuFjmj<-vYZ|-`a2kk?2!Ov+T}J?KXmAw(`o0nY zt^cM5^uAYvF99walFxAfZ)-q(-vRJ0kBq>38jx)EY0v;*zXm4(ysyC=00%Vq0>D8H zPH5keqHjr^1#lR^hX76i_(%itejjTv7XbN0g0BF4s(rVrQR5f!jOaL~!A$@@)4&Gc za}7w3h&F<60ge;V{WZXGBD`(}I1NOHNyCZoqHjE$*5FY9XEd0n(Li+E0&tuNFVb&{ zwFC<^yb1UD+IqC+Z2*0diUa8j;Y4sd0QycA0e!#gI}H{B_y@ps@J;|fXs`spj~Xln z@Dspw=Pm%hXh2`q`lkj<0sN}Ly#Ti>vMq{Vr1u2N)UR;Smr$?*z#kec2Ow)evZWl6 zfOPzV2CD%4j|M9NC;*zFehuVLfI}F7iyD{#P^>37q<%Dv(T7IpD=bEUC8=#J861c& z^feMT2w({S8w{{iwI3S-urXR)2EZsD>HwAru!#U04X|Q>m8km8N&z-qtD6BZr}~i- zRt~TVfY-SI76AA&2(UVU)oaiIumu2{qXOwNn+q_C+_wX49>7Q!EC8FY!6JaIQi1H7 z(U=cZKCur0_7T7a0PJIceFCrofPD(EBLH8&8DJV8*+u%k3c!j0p{oi+kI+p8HVqJ> z03jNjCLs+R*g!ydPX*F1VV?@57sC50u*HDzIUtbj{s0JHsz7=qoKS)EQ8=jr>6$K5 z1-1;(^;Uu13+SFvfqbNHw+d_tpnFpV^0hGwfS5Z~KF0hC#Qdi6PP77IXVnjhHgI5f z0b*A`?56r1F$x^W2Z+%su)6`VJ0RLspC!hC1NjC~Q~~z^Vyp`EEj%$!1w0Ihy;UGT zDkiBwzC=s`MAE&bfH({g(^a1(W`P4f0L1w!u;qZbK?Sw~5Vxv8{w~&_0$T~hT2&yu zi0z^RTMfjNUjVTu0rox+drAe;@7U8SkiN&B0bygI=J7_Uh2zS%p5aLzVq6Sa6{OyUZ(uZpgY|` zuY@U2b=SZ2KP86lww|53cYWjP1Knp9MdCMse{HD~x*!JqF$lvk7UMAqH$vhEAak(* zi?Ix=@E{(;Mr_54*oD2=j}LGJU!oD;;dfkQdKSUDF$e3#2C!t7#zwJhHlCHS>zTx6 zv3hn3Tf|nd2iRk51KZ4AW_#JY>?3x9eapUQ|70?|C>Vqe!qvhxf?en-3=mR9nyWSJEi+t_nq!% z-5LHeQk(fWLSiGGHDmfo+QtG`2kw|<5GA^ns3P5Ni` zFX?yb-_;+`f299Re@cH||C9cLL1(ziaE&3x(9@7$7-UE{WEgS{g@!4H>4r)}jUi~b z*>JnzF2f4L1BS;9PaC!yb{gI?95fs;oHTr6_{H!)M!{${b~eTs`xujq>Bh0f@y1f) z^~Q3e+ZZt3WL#*x+qlyBpz(3zCgbzQoyI-J_l$>)M~q(@8;#!?e=*9&izb7qgDKL~ z%_N%om=aBcO~XxfraSAr?xdu#!_-HL`WWQ(1*O?_PEQqm1V^HenK(WCkNBwI_Ex&R z?%-UtZ)%{friOo|gZ|#v?ew_Zm6f%ApR2AS==KJsD!!!YgGKTTLY@fqtsq?y1 zQj&)Foi6&ygU5H1-;`vxnHW6GSr_n&I-TJ>r@|n!Hg`Yugd3@W@V@kr{t`t z3rZFIXD0ti{gN}Y)kjuFw%SzT_E*%^RC=U2nJ!<@Sy3T*gP9dhzt3CI@?O!}se(7T z_|Gh@?Dsi?S^TG@Vw9~tII>d9G!lQ$ZhhzD$F)vg#XD5BbQsrC%2uh8)JL{DQ0?71 zd>nmn$f=T0UGDT(w>DL^Y07P_&MkNP^MY=VOLFs{c`D*=?V+ybPAn}R@8*l;@t-OO zbMn;YycQ&{ZJn69qzp>SyVgCE_s&Y1+1hw5=lo3mb9@`bX0<7Mc07jZUv0JItFH4_ zIsJ7t9%o%J+gnx0375Q8g(_=&+JjdYw(YEvo9yQ}_}i>l+_ubH3j-c!pqdxeQ7OLG znqrPppv|CwHYMq12``saNG`X>;|#R&wxqQf&{|8{%n{_H`D#N3m6kjGr7aaH$z!QL zB{@TFP6?Jf{biiMGL_mot|MjYPx@$DovIF6E3Y9N%NkVHmLp}Vp47FiYiLEYPHW~P z2TyKom|W#|)=P8w&&e*gjfoJhgQK`b<^eI^M=9%jE8C(AdoD zT2%HX-a5B+%uOv#v+I21y)VRHMLCIO^b|(!THaIyT(dScm zTgnjLGcAW6$;pHGBPms)Pmwu;>O9G*gL$>uH#wOPNlxW`Q}`M=Lo&5D!Z;;0Gm|Dy z%18<}_!3=SUyaWz@#jsFU#$qZ=kSVvR4;jXsnT8FrjNI-#_x4&qbhxMe%>co?U&R} z5`D&x*U{9}n`Y!sJ|mUXK2+ip@B%GD1$8D~YVh$VUyUl9em{MfqLM5lC3%=i?J!PQ z^01-2m48u1ZBFAAE?%Y|gHzIylK6)TTR*XJL*I%U_?H9!mtRH<{SiFwrgUozreg(m;%$7#Oe~e%${uDX z1dA|C$QOdbGr~6EZQ-0w(Dl`&>z>rTt2?cSUa!AOKUKd$zeoR${saA|`tSAsH1swM zG>kB07$zBJ7-kvj47VFL8g?1pF#Kj{Hg+@GjfKW?;|k+i;}gcs#utpQ7+*7fVLWFF zHzk@Tnr<*TP1UA3rg^5@O^ZzHO)r_=FdZ;`8-}p3u+Cv!!@7rwVST~|gk^+{51SZP z9X2oQ&ak_~R)*adwk2#&*xO-;!afc=7WQ3Ob9l$_uHp9Z#PBiU#o^b5PYbUJZwS9F z{Lb(-;ZKHd34bB{mGIr+d&55r|04W+_z&S1%to`-9AoZnPB5pKhnUBjv&}{3NguuY z^z+Z(XLm)9D%t?JzF*_`_lk&I59(L;+z3htd=)~Xlzy8#gZ81vMwYF^6^Y0vb zYt!MEcil2)vty9S?Y(hkadgDSTMc`j+qi3Q)Jxv=vub?7s##CY-X62CIxzdz1z{1( zRxewTc4gCGhvcp%8MUYAB(p1nKCOk|Ay^9#K`*xE3cW9p@+xI9rnKT=#FhM z7Fm?>ojlfYTJa8-tv*xyguHmAcYz!&_mn%oA;-%}pTAgf*qdz`IoMPjq=3iMTUq*`AvDCQSPa{Y538o^q1c=$l>c>J$EYVr%696BVv?I z#zy5+n|!-mV*2&zag!&`EbQm782Z>PtL(3DUH8P}j%iyBx7~irfGYwC;%kRG-T2<{4kB@(Lnxk}t;S1yXZHBsSFVEiH+*_jrs_qHHqE+jPhF9Z~Y8du-eSy#Cb>*T=}E^3#TgYF1TFkBYGUD0kW| zmpPhd4sNb7DV=k@d6~1G+FKiwS!qar_VBb{q9b;%dgIX-UJKi_ZO!htqM9BU+`Pk7 z;H~a;b4zWv##52x%NkvF-bI2iLm(6Hsf_3O7qzwlVC$8)o<++jUG zd;AvT&L?Khbk+Ku(yaBb-Ru|_G~_(_=Jd~^BRA7CG$0t*<`&#DWEn#5{P?@aUY{ zHQwm!ZuFPcI4n)yCfF_42JH8nd18n;Ks-$k&;q4V!M= z5&iP6hj+c~h_Gpn%_0xWJ*b40PHUJxE5=fPp{T*4l^jS;6)RS*Sh9M_YKLXW{4eBzN9F#XTjcE@DASD(ZQJ-%ygi~hPKlKt zQDWqnNZD}2y6zn%(zfXqgLTGa`wMr)Sl9XN5yapb#Nb;TIYC3t`aRP>kG3>cn=Os9 zQSKG>&Gn!3Pc51_V$|M=$DiJ~`q8y9ff2=(g|~%$DG#$beNVmm%I2qE*s-a0`gEUn znj>O7aqHo8I*UnR+b5ajM5WHKa^Z@_t5&UCzM?}2EAL&lJZklwD;LH@*oGK~&+j`| zirF~FaOmLrV_!vCY;uQZf5I#V_&;Y#={rDOk|TNRTW=J-%waLX5;9DeA``|m$I zJnPzdL-HLFZ(nDB+EwN8&5$f%hV$a~_)s6B&ljVp`HZ@JMJ-7L(9nX6 zd*j(x);{8WxNC`f`uI^%h1+Xih_UFJ)^z#Bs4Q!mCYQ;J4E>DCM&)~h{QclRiyGyH zCfOqQHduJ5iIL~Z2W-Etd~fH`=r=!_shI9@H2al#Jn%Ry2j%dCk@C&QijG+tWuo>~EiyC!Wz+*3~~_w=|p?VYW1_Zm=x8ZSlQ#+_TWJTUl+G zcklAs)vEWK-CQ+s$9;EQkDN%O9C`%lsScmJYp?y4&oQ##LsE z?Hl=lRgd4db;a6l%je!db5+CF$^%^^WIKCBcIafi<$R-jveBY+o^#(f2Knki%GIXT zNlN5nhG}U#jTR*+uQ|<5$+zlG$!l!#t*4b+jS-~hZ(nD(C|{-9Ez0VqBO}a~!^`Xz z+luAOR;+f&b#j7X^@`;ym#$j6YO!UeyzCfT)^t+0OkQSdI(e-5q%k7d{DNiA*|~G&dzT*v(bL4(Yn(@ zdBuyb&TH5fbC2)dz;b_>WuouZ1N)xZ{ocDzPa8k6c1n@MqHH%fAsYaK>-eS(--68<#djzJCc*7r+wv=1I#zx#vOl%n`ZAQQdjVy85PZpUIt$Gg;qg zk%y-Ls&pA&>947ASf0NtX2}#cX+^~R6W7-_6@F>iV3xoAT4%X%Lj$wONs$(1xxD(Q zy#LtJhDggSdxSh(UcU3?ov-Xy`rn)4*TxNHPn;XcVPEWhH{ zt&j1`jrDYmK(`R<_+9cQe%(|Jgs0I}-dH;wDnAE2&*=2`b$%zhpP%x+&*+}#5byz` zOUaKIT}d7Tjxc=2=t}W8qszoo{Ce{=LoL7Cb~03ge#I!juN^k>3+abISBMMwWyRgV zz5KT1QLuaX^@58oQrHT*Mqn%HLV)fEmIBN9CBO=PrFJtggYL=M1Aqi}AHz&w4x<~D z?flMn8L$TMf$js{pxfFE(EZ!v{FdMxztgP%dkC1N!)%5+MmMNi`5pEa;3WfIV{`|y zm(fk|O5j#K?$D!(4!PN*j6DMOFkRrY$H6v&Z2)@;>Pscu> zJ2UnX*g?89V29}1j2#0z!q}&DrNBPZvy+US06PnI2JAH0dB(m4I|tSX_6^uqjQxYL zAHjYW*iT@;GWG-5?_mD}b^%NQYXbWhm<;v@STooq#x6q8K@cD?2zt7J6ATbKKrlhD zKrllHhhT&d2B9N_t07zkp%aA85F#L0Aw)v3LAZu)=7g?vA18Ey(47fU5Mm(oU_u-O zkqNyZI3VGql^}=D{M_stCi*CHGKsQIX zTpy-it$)if&EPdWZurR9**L^F)R=C}GG1rgXgp-P#x&2gH4I@>!xo1ld~*1#@Q1@+ z3;#6ycXNjMg2iB|wD>LeSnjjDWO>K(x#cU%KP?wJ7&}bw;O#J{!%H0_JH~cQ?wHxJ zu;a}gmvnrs*IT;&*e$)=qHdpdJKgP^It{+ZWnb+vS+lm`r-ik%rdC-(l><8hI31LAVxa^pUU`$rGfBc;cL9*_6f(qmhX6FsAQru59}d412h zJ@4-MNY8CO5BEIN^VeRwUf1;M)oW0%vAyzpP3<+iSD@D&y&mYbrPtwJU-XiD>wDMr zZs@(N_r~74dw<)<(dXtqtNJ|IXK$aM`=W2hzA=3V^v&u!qwnm#xAuLa@8P~5_Dk-U z)$fLWbNfBe@40^a`wRVN_g~n5W&fx9zu*7-fXD#@2b2w{AMntCR|b3>Z;zi8ABbNO zzaf5S{D<-96FMZMCrnP5nlLNjri2F*-by%>a4zB3#PGyx68k5PPIM>MCEk;`F>z<& zyNO>WHVw26>_70@ft3UA9{9w-w+8-}l#?_kX=&1iq_>jJCjFMolC8#5n&@TN8CN)^O5sM z{xtHJk9=B)Q@44~0*X7=s`@)176TWJWh)6eIJO6~d?@PJhWA^4b+UCex=G)}{pUEaU zT}~^LtqI2*yZ21nF|pwK4Mh)6Sk^7uv}4H&w{5$*Y+~0PGY)>Z|N8Bj4-V`0Qr-32 zGozJG{o)l-iTbv$9OXEnA3fnv<2U;be*Wcqxhbgy*N$>TPzEukL3TB4FzbHo!c$H8 z4x?=O*6_Vau_PJfErXSRn#PtH2AGcQHAE=Q>+0FLM%}qCjq+#41Fsp5oAR$W$VW|s z%MHqpru^#+BTWZ(8zKT3_AkDcH-4>?zq+t8&b<52wY|*|l3jkH=}4UUwdON@?GbCo znB~olI@y0=WnXjZ#RS`6^UY?tf76k^W~J}NltlZQb@g)Zlk%FAa#X_xvwWmc_hXkv zxwo8Wl!v}A8^8ap}~v zH{_-|BG%ZOx)Kq}qCZ#K#@g>S^HeQTC+{I*l!WFZwz1~lmVPj?zNzCudHn76rs+qm zuvR@V-*(b?quIKpDZR{Oeer&~b<5;8O!ATDCR@J!ouzV`l2|XZ!%bzk+nXXjw!%6t zG-4?qvHE_yb?M|cOih!Tn`|E&tpk2|(_~$Gc#{0!1e0}u;=9*wT{_d;Jp95#d)P;x z=ss#HvMsmE6I&*hg@baJa=U!)6YJUqa+bVtp4qp({1J!su?0iT*0l>}kKbzC@#M?` zyY^wjTWsV4rS@LCb?t(gX63P_aR+5vx!rnR&T1NG zJG<}o6T8%De;I0~GXk1)R)IZ2d7!E2u)MtC!-Gs-a#XjqsmLa8Kdf$qpN_XjD8DHk zE}UTJ8+GTKuCX=BX9pYqJfY{$h$rN|r`2ZSqiM z*uH(rFnO4qE)UH=pbS-pDZ}KUg@y7kWvG&_3_Fl-h-kJ)D8Jq++ndfbM1Cm8DEf2O zkK|5rnQfEt8Tn0v>>H%`Ox826G%s6Zj!GFl~8F{Kf7L7H^RDjSI#aWTSDmGRB~U8|P;jWV7+>qc%P`)>x~IF+^1N zlSdZSKT&@nQXZ7vu&yEUi*LR-_uV&Ez`A&Wd~ZM7Iis~?!B?g~9y8CcGvc4p*o^LyS z{Mmi)IIQ&_4K>IHqhga2pWFZN`}gkYHq>}m?ZS$=F6A0IxvO>Sv0ZPy@nzK4*#{F6 zGK%9%HdMSdF2?#&@|4Vpu~AC+$Y$pZ83jUR71(c9id~+5TMA&aKbv zj+xbbz-E1E%#>XpAK3Ns(O2pGqS#>FdcCu>rZhUDIpI;ebq1I5y0t6J5z5vL_Ty)D z@(oHC+i9a`XNufg4n)bbzmtb--x-r;%pIPm#3~h0O2vM~x_@{KA0UrAt9y?R*#G5z z*(z5=$rX8WZ0?saX~yl-zEg%Mv!j$iiqhLNEhZwl>E`F;!UiVSpU}y#HbvP!N<6eX z@0+6CNACS?+w9}LXO5r#*inOQNLLJ|M>Fzw^w~OlA=np~`uoij#Eu-{~Fj=QzNeyc6j9-(yGU|-l2)GbuH z*cy#Z_6w&Bsm6#$GVScx*Yf^vb@GwvvP({s#}v!ON|7@4dc~zADr4VKisT~4 zNxjl(mK-O?$X7olC&``Vh|Nk5B}Tb=wlYw$IwF*1>*|}{dap>1ik|S!bG!#z#(kxaaKaVZZMG=3Ti{ zl-wchq#`O|gY#2sV~$rF-hcd+m(E6?esgl}h@2ZUra2T-t`eT4_r#p=76L|F~;XM(Q}%u&lDJU(R%-&osn8cVwL0B|74+b@lSt z<4vUvtjXG_YqEA}l*j&byl+$KFr#v**=v|A|BvaoURh$4m&nHr5qHi1QhxW8oOXgW zIls|yj0XKv7UXX7RfB&~?8Rksyj6~;nZWr(S#NaP--C3I`3! z%ITAO<1^b_j>)-(s%@W_%ZBKP+4E1zFPxB{ZeWMb$*(o)GCfoWq@*HsWR~{Wo}r+ z{P`#4XO75KCn7)oy6Bud?_AN>)?ej!=i6k*58ucUjn^H{-0ZOa@ZP4)Zyt#HCGCXL zQR$GD-aCKGq<6eA)?c%0rsfWgQX+mxl4D}5KQv|Ovv1t_?%~}pfAHaMXWqmcre!;< zzbe1#(+b`^bL_o?XV2~%KW4~;NokIV*=y?MO(*2%PP2Eul6QWslj%sgZi{S_OXQoP z@a_lwep z6i!TaL^Q|UD%<5igI)gFmTFg;^{I3Wdy8zB>tuW6D{@TMXI5Cx$a?wbMP}T zQZ?EB+}$xtCePw0BTvZ2rfJK}O>fCYTcb(&Q;w7WlzSM?nwn=SC5BO^h$m$Csq+-G zn!4F;H7gJ5n`WMBo=K4`H1HkU=ceYFa)}|;BsVKPlxC%eA=MP2Fp5&kPeg7x^PcQb z^yj`kXZ6U_#{oH3rL*cBB^EQw;nP(-EZVT&c2 z#N=7tbEn_eEMW5fwAbhN{r>*o;dXZRnVDywotdZ3(}$-P&(PtHcv2kxPQ$%Fft|_6 z4>JNPURF-J3EQvDsPgv)n+mH-51!Y;tTJd@!R>t{^$y@qo`_36C}!Pf^lKJ|F4f|( zU4VhXFa}uY0283+p98S2ljE>O-um?X9dSAFd&EPqlo`!(Hy-JyGUvCgE?A(&=HoEk zqx-e-4Hr)ooGlc&y^mHT?{_cJzN~!@-N7DrgwOF}ycmzfeX%?CfIip?mWW)%BX0=d z7rGqzvEtm=Q{b?09D{#huy&$40Xm~tlA6Fcb-brGlfJ4@I3`}O|BPI*Fh=S zvep|EQkr!D@)PK{2E|+JEdr~yixX&xGALkcz!2fEGkRli6y#mFv3U!=SAa<=UI!)$ zR&NZ_1Ow;OG|#$e=1?VeG&+a+g=`J;>*#w1FPEH|VZ^dGmfaI|FfvP*ygA(^Ws3z@ z0yB&=V2(5`bx->K~h(V;&HYh3A3l7#o zYVF_K?1L@aY^HUaoy$TYen!Zd+Pue}*WxEErN>h;4~ajFxKT3iK2!7aK45{; zz!*E2h26269iD~9;4w9L7P#r^%yFN&&;7oLTTi37<+%%K1W$|ERT&Q=jN2q(pkb>a+&>TEMitAv@s$ruuI@jc* zfVtM)&{k)3MoLvkE3MzKc#WihIq;b2MGT6GxGN+wJy@8FpJ6BbfqBhBe>lXbvz(iy znPTgKs9B*)6LoHx^;iK%W9x@ab`NPFubslyJh(l?9h>Z+<3sGmep<05Yi!LwW{qUY z9>}Wyer&Qq0lCq;`BcP+n4tE@(RPW9g9!Z-Nk~2vB6BaK7i5bS?1z2L9vhX!T zGiprX@%40^l%$Bm<9R8m-k8Lyw+s6rTLEjN%6>>aLhwd)9L4!bZLC`??4{j=8F_+L zy#eB%a3!+5Wc}bJjDeAZf5qIqrJl~NA|w;ZiSsdyGAOx{Q%cu;hum&z18VujOAAhV zh!ChO$~<-Ss@7043Ae$@<>Lm3>K2OweesC`vI2S`(#XX|NHB0EdlBd3iMSFxthOsy z>(Xjn(Nuv5zdIWha3FxU5%9?zK>>@Ui9D$8VbxuBB2q7upHDP!uOS4l;@uEeEBOyp za<6+Jhg_n@rt4P;ihAp%f&*G700U-Lm8pn(1fNUq_-KSRrXP8(e5lZO7NYA7OOP6y zT4mc!NDZEA5Fx@k1FSc2rA>C$254lV-KZPgCeL?Wx>0w|bzc4)?c7B^D_umc_H2vw zi7Tx=asJMOylLZgxXb`QDQiz%y7geswDCH%13|b-;7X*<){_xevrOPhzD4ROp7Kyz z{v_)R!UVoBU=R55b8cK=8`q|>igGIGN zKx8X%Y9K3s|LI8n_r)TPQ5udiTuIZwfl98%QMuQ}sc^a$TaWCDhv89=dH^RT*Ybmx z+=4cLmDbjmp4zfxuZRPb8#gC)4XJ<7_ZF>Nhu7J(1RN6qhU6!yf*{p*#1)S?tLdVTD&o7K%elcwI#Wi2NBP@w z#d+&z?2j;-fnxS2JeqmJVxOiC%=bC@M^0*P%(*ai%G~)=9rvs`;HA5MhTpU$uXx|? zyuEvOZ{8?-Utreg;3e!?hECK~Bla=#oE_KN zX|at1bOI4RKL>rFXU&ndiw=nQk1=H~lglu##ZJTU4E!y&`x%de+1tc& zJMSb+LGFSA77`5<4*k%Fw?%2fACb+gB==gH+?4+ff-$CiUS2Nmff;@0=}kv;>zM+I z$>0Z>j`KFiUm!%WdSS?OM0v!=-~;R+ce&pOnvU~b(Rc(yh+2#D|Jmf$RTz(;h|Ip6 zKNL4#OYNn~PKfh=YqISsj3Dh~2~mz{WgU_D&r&c;deuqb{PY>dSFMgvrTT8d2%)0N zqnga%XW_5W0(WWv;?Ax`+_v4u=dJb5l4@sf{8g4EQ zZEMx@_T2>Bb{RVPP_n4Cy7&aXsg|jpk|g|m_Qa1TT#t_u3r;*pxqLdWy5sOdX0hMu zO$)Tc9LvE1l*cO!=ZamOc8YcTn1`-YjtBOH-$BS&$6!CaXZO@oZU+X!ofy#&u7 zliN7Ns@DjhlM%K1bnQnlIht(A?O8JKTKN^AV=|5xm^Z#6HyqZWibzD}=97}yXo35F z0OC%rMf;7<`N@c@UM6rSzeQ?$0fx7By0c&}z?Dy(CYRFZEuHQxOz~{#b+{vnAiaJK zbL19(C%u;MS41LNxy!wVCh7S%Xq52}zOyiWPZY31TEM@$SM}=6 z=!#yw?8f!zRWs(5SZBUu^^tQIjvP93_WQN-7p_~qSX5&w045Hrlg#Rd!9=U8PpTeq znPgFT#BxhsEAJyDRcE*<;v)yvbX+>3Pw>zEU>9rF8YaldiBx{t|Qo9!fW zFUF2};mt-kc=w;O(L&uHw`pkV^@zUv3^qSgKpt+x!{_&Z`tt|hla2?(6S>)kOEtfb z+CRKlH+cWI1?M%VkLH!#J+#RyM|b-obJTgpiLbPs2F~s2kiYcwCUJ$YtJ4C_fbxx1 z&bmtHU)?8a92WUZv|D^M&r3J;J7)2rnw7t5??NO0&4KAgfGdCh+K-i0GkzL1a+brGu~%n45Y@>NendlI<1YpU6yha( z<58w5^B2=rrQsOUv=<*$;?c7@b?I>fD`ASLo+0bXA42{^SpUGP(g0hZ%zMK9s}e8c z4JVi;P6=igPTkUR#>%5BCXZd>JW2E)kGfWh!k(g ze4yS9YYk5g^h;@-0*09U_GkEwwP_xT= zGtXExY>TdMyk9{CQ(78mP;9rJjeZ*^&^Mn+-#k@R1q?zG4{dAVhg$lip(&tI(c}Sb zdEkGmhp*x5ZVmVgY&m5@zonvK$;3*m)MCEd5d1a%`nRFLgYwSLhBIRSk~E+9tmmfd=ag5ywany>L;|6J^@2m&SsJOpUtT}$I>aq6mjoH0>Pn|PJRPT;% zfc>A8mLFS`mV*Z1LCs3bL5(af#>-^gesn_|l74_G{BtG#6A=6fhRZ)Pdv7ZUHgF~I5Gr_Z zk=ir8Sv(wHz=Pldk=!;I+cUV2J@lQ7`?8#mJ@i#_C0z|l&gXadTFI4Ei1~~W#3ccwgjZpqb0SN&-EUAX!FcG|lf;C>3CwdJBHWaAoDR^kdm~GM9qI@mR zZ&-F@fEKHdit)VF# zeq+_A10KTrXEcnchdzx8DLH^YUPQLrX${O)5BETK?Xr;lM@2XY?VcHr_j}b>iI+Ic zo3>h4HH!hZEDO5ARLyzlgUgiT_Ak7rQ{#Eqrn>37Y8plx6z~K|(QznC@6=n<%YZT z$y%6xUjf(Q5Pu&ESg;weYuwa%TRok1yC*SuMMrj?)85#-dAztynZ9Xd%6jdn!OMH~ zxv|(#aylnxkJz<{U+BEI~PHU>YxZD8<8L_)hyz&Ld2{-WSbp}Fj(ZI{n7ke4YH|m7D{+6Kv>U47-eX18P!M!# z{9gJ3zLd>WEJ1z|1nCR@=)V1j4sG1;w93_a?b;&eV%;ZWtJYdy0 zrPU>@qd{>B`|^Kg-Ms`IG}7{BAzQgOG5=V>?%=?DU4=5kV`Hk5cJ^$yZ^XePM?Wxn zD5twPb>BvWiEkS=*Pp51Qr99-tdr~|1raDhg-N5E1&I7(T5et0tr-nkE*;M{e{rZh zRG9dWd+G8$_2uY#$>c3-0?%7ZRqT9(d83Jk?$VHyyyU{9JslH0Q(cq1;49;h4(cp) zL|V+b!FSd#S?+M6(3{1*aWVt{!YTY~Hc{x=e67wxd8A&RTrEN9%>t?RgIp^?=-GU! zhM)a`qu;>iFbR0_r+~r!{Gq-34jkOHZ|xeljq5iQZagf)wNM1tLy>waA}+tO(vogU z?1$j}hdz84G!^|3iOx$^+$y(y;@p%Y>p>=pDI73k#{us=1->12*NnWnSo@4M_ zJPMDk!85__*wLi)ViB8N=ZR{KNJCZ^p)c5$918F%5{ldqk(kv!n_T zXkaSg%Sy#!w7S^+XrykF0Bfv^{FqCNgu>Npo!yqN-tWF!Fn0cgeK|1(kSC+PWshvf z#Yo5HHb2ZcZW7eH8$t0~!#gmiArq7esFJqw2lDfa_jwd-*x>2D(PfXv0TFM<(|Lac z+wnR6K>nWMVvqa{8$3N+T=sY#5Y_$xPbYXawS5xpZB-`uatk0U9l=ugfS1AtqP1Iw zKQLSoghK%j{cr*9hx2hi$d`2w%>wslMBx6G>>BV2(?MGyYk0HJ2@?wt_{-Af3(T8} z_<_h(2oI{QkX*&BP>&%1SwbxF2x*iY@)-i|Y&e}CYiwBLyZLqb6xQKNg z%T%yY+oS!X{iC-=Z{6Ca+e%Va$Knoq?skU$S~b2yv@j5@kU!H;A8B)W9z-k1XZh)) zRIioYR9}GEi2GJxZh%#(hXsISnk1HJ<3Nu6r8sdJYvO4io!*|B#u5rSMK8m-Iu7(ueO zjuHMj-^^-C?1W&k=@s7v$qEdqKPka$Os{xb^!LOBfkdwX1LcWn3Tgy1t2c(Njz|`x zJzH4jys3z{ZAJr^$VBEYt3mJ+d-T?zC?*)je(1BHwE$vCQ_D@S79hW728;!>07C$n zkwx)J3sP%S(ce!DlBY*Yg5<9;Lb{-U1cKG|!!X{ar9|35u$sW!26+fSK))CywQEZ1 zhhWHu;k*r+EI<@_Wci0-d{;DCkmixr2@X|FPuGk;pt&<3Ojhy{P~ktqSmf@5qBbW>f;8et*0M0!udu8lt1P#m+mY) zBHo#Jy=?qlChthvnM<0B`Vy~Wy4$y>+@3s{DO|m1=N#?qMcdp~i<53opISbF*|JK% zbe?A3jwQR-=q8N6Ir-LY#_h=2?U%F-<^vq=y!_>-pBtb4^lhKs4io!}>aD_51m;!p zS_WgA4opK5ZTgGvf<_1rtB7*xJeWyurxA5kwrN;bVJd2@q@h2d*z=~8uMjLTrO34} zS7r$-?!$_@QTGXtpV7l!LQ!rz_0D*&RmpUY>Ly&qftO(ULPSeLDiu<3f8o-FOAVRg ze1v06Gns$W9FA~ZwRq-AgnyEJy@a0RIlE86OIZT&l}GEi2B~d-LF6u+IC#adR|n6P zT?DS-A5nr!loMT-FPpv+VJ%$x@8Sjj{%oZ7#Mui%O^JLLqPn|FUJK_BosE@Ug?~t0 zH%B5OcS#)yYZ^~{=)=!OIp`wvYuRKrz;hz?;W(4u2*h1TL0rQMfx8eba1AYc%{^lT zVu##G5G?&LtS534pf7pG+2q#?HQ$w15?+rn0l6z#5^jz#4ey2aj3YWG`p#46N*J}N zsi-fCF&*!TTI?+3=EWyJlY6;@i6e~g31w$8z>}sdxxwpXct?$odbQX>Z$iI40=$tO z-iA)$P5)*TeU?Xj>6+~}z&zs4??s%yC*sbxm~NzRn%2z~jNMIbUD0qfLyjk~eR#FH z#nMwMZI(*->($eLWe2WgW?`*8XgetjTvzRO&|+>#Z)}Tu)pi5xYlm}-i$%_Fl|jjs zV#jiR$byH@|12$g{NvGe8?!~cO1a$K(PObzJq10l%0~+5MA+8R^cR``gojnFwj-AC zEetn}=WT>3=uV~88-qg#u{Zn$KM~gDB)r;`B0qGw(&}R4@(^KWvzBqc%(+c5#zy(k zMlj1qcL_1e2%+&hdDfJblk~;L1~9urELDWgMliP#JPD&tY1z`{qqmg`scV1XQdvcV zSX__)fFRgdhc|*V)YTaWnr6Z|cH*WLi)OAw>cKLLw*-#S7aNaOLeEA8ob4~%xLSOv zSlpLYv@0if-j5wfh{*pO#M`SDn?Z*V-CS2^$N4LfU(;y5C5jjCWSgUU)y?|v_wvgg zZA#>A(JTR~2uGYSKH_ZzFSI~tv2M3c(LDwALg7(?aIult-hP#Ige4c5OvC_JFB{-~ z?SZ_|;> zH5>Bu1W^l@cLy_|o+$tm`X`!>H=~jD?iU+hfY~_%_ZCi&H?YWbhV-RD#__fXx;Yme ztA|++;ba~8T)Knm*H&ZwQtZoj7ZwVCf~D2PMgyqM$XJ}vB2&q~;rL|Kf8^0@)n81$ zN*HE(#Rs%l8zF2YQ6VcNf!x9?Ot1K*Ld$cix?wP$xHHrnxLPUA+92gTWx3aN{gqtp zOJcI@jq5-CB!$DC8gmR#4fV=8b6gK9sAtv0sM+`7mFgC=rUCYoaJYR2*!l0_aBApL zjeGn`g5qXQvoBMs{fJ59t$}+19A>S9MO@EOGz`QC0Imw?^Thp-SdX1H|)BS6PYxfnJr6H7I_=fm@KFP)tImnaas-OO{SsiPUn9+0Ay_ zO;v@dh%*9bhq!;OGSzKCj|;_h$e6604eiGO^FN88UaQUK94e1k{-dDfVxE!1*^9P$w`h9m7O)X5^0cW$q?bIS*Y25 zoFTyIRK&d}J%K#yXvDq5w~X(`Ar>Z@*7HM!bwUOT#T)pcf?Yse6Iv?}R}U#wW{C+V z7$WQwz@L0ESo^{J-)q5HvJT)?ABK@yvRwmz`(Xk5F5?=JM6 ziz;UebiLsSsFol+35W9Cg>Pg_wnFMj+!n?`HS~sAB(iZm&SM}?wotcMz5^>py-O%1 zjoE(alZ%MiyD4HMYBVUanj*eN<34odHzDz6(lT9g% zBTHtj$&DCmYL^LI>9rr93<=Q4qN z`z^u)jA!`n!Xx`uSDCJ4U~t-$_#d0CBkTjcjg|jw7dos#7g|NhC#wYR5RoQNwMdhP zHVM)`<7)E2on-=dh;;OmPtI5z!IvbL>^k(l#j&FqSIRU^8wUO_0{T<7rTW2jqrQWK za;obR5(NIq(EzSvU;YdU7C&vV@B5U}%Nn?)oFKHi9$+I08z(v(58+`|41&e-S3dlM z8E=E8c($yg#4&;Sw2pQbJjhZhPwn~toZ5dUQ@i|_ypk>p5tcVwzKZ3Q^mnq7b{1L$ zfP$vP0fMI~i?>1c0?Z&g2jUbgJ)oOPkvb!;9L{}iyd`8gNk^Kv*&so){QLscHa%n zl~V_+%1c_j#w)zWUc?G5{&M8VKDg~)%ipXO>o!&sFY$S+hS<$KetnZ}*v6v4_0vER z(sBM|hP$v);4U}`*mfDZ;Uz7;Z*}=GpnGADWc%^PDD-PW*~Q12cO$~3dD4eZRet6B*vP){P=rNegCN0 z>12hxq?w_~_7t=oCF-Z3>~j^@GA0>rrxsx#<2Gu*}d%769F*)IFrV5 zp8A8ag~|EpsgF8vp42dbTT9K!T5)o#Zq`_a+p8ajxV03K5BKYxgjHl7{df1ZLGlEJ zW9On{#B+wUu>w?_^j~?;EXKY(_x`_OJE@iJnmy!hjzqGL++)IlkMP%Tp!S#dF2omb zqCBk)`(P$N3g%U^(@|;jtj77l0kVl{wVnHut?3JcZ-^jgi+ByM<(=#Ard)HYamS%|OQ-OHH}=paT$jwwbKO9M3AKZas&?^g!Ro#N zl$FN}T)iX`G5q}5Ll>SE>eeA#rsV2-2#b^xH!WLA_Gps@$(r!r@zy>zOV)lc;Gdm@ zjrOu5rnFn$GvW-0{? zk~dbNbMpSP_-wJx77jM>tAFbpZL6qk4MLQWT*LT;tlM&}F zj>Z-j9MPO|DO~Hc#?3*;Ioh3?dU?H0ZR{ZphMV+B=%6TTa^=I38n0+6dDK$UXdRB! zCdFJt<4{m3u$Mg3nH175U}=RTKt=3cc&ZapEbS#ah8c&{L5z}ft38}wdgj2U;X3vD=z8c>ajO#M)mzoWbZq;adoTNd z7~8X_P8OctalrxxRIr?cd$Cb_!gE4)TfmS?mV1xqvikg>f+E=;*ZsQh8<-Og zvs?W^HYU2Kc#52~bnHDg#Vct`%w`MQagW)+1)FCs-eRGadIwa)>U#;*u)5mn>O*M} zu|skcR}Xr~=NrzI+|Cil?P1pVdu?8*oxc9!vu6i>xOrx`t9!C|e=qZW!1~*m(qgj- z!>|r(%Lao|^u~wzN37)0w2m3fHk#J)U|CfQqR5>G-IzLTi7mzq!#ZL^5vzuSg-*72 zJ{P(3&re*uQ*m@&UmaK9*J<83of;1fsFiNqqoH%-lSTzZ2k@89?mbv2Zob59@p0e2 zS-WBLj@u%9sl0t2%<7=K=B>lIaUMuR@6MYr>OG@aikiH7wp-bJZ-|mPDikTi$hpz0c9XR3eX=f2ONjXXg3&g#lEw|Sk)TgB*?wNim;$G_I0L|a^I|S~fo`h&Rnao;KDZQfp7rB&P>i?%?N{}iy|NZTq zH(=8ZD~PC)CXp_@nS?-x&qkngrZug>oF9fF?#-uAPW8()1oSo1YX}NN+$$T>>E|{} z$xpe{f7t90xK}o$(@RWdE{J=1aR#}$92s=n%Zt;=?@0o9r=g4+#n+Ck6ktIh;?5=f zGl2Ab!cbE5sZ}|8^n_`R3*yc>&LFpBY$nI)h%+Tj5@1sr+IeH&wc9uD-A?hgf|yE} zRWa`lSd`DJ;0`9hm+6SxpRfoS=NqT+FK%9Yd~ZS7KsS#Ne{YdHn6Tp&1EX$ZUv@Lz za>aw$vnxOQi1ti@%d#cT>*lQ7ke%ZtuA0km`xCb8KI3*r%N4N8YzTwi`Y@Y>F6Mc4LTpK(3oTHrOu>sDpg9j}qXeLwBHw)2|)y5n_n=mtlP zrQo9UjQ33o$jVAf%gPQ&_w^0%_t9}wDAmuG-(I?lWuWt?ceHGO;5uALbKxv#H3L2hAVHn03V&?Vof@oxic**+b?aaZ$N;Lj%(M>-ng(oPmpA$r)Om~_u5w{O^D%r)BUru z($ljt{nLH7Zuj4+<7_PSM$V4+ZSHnf78yHf5+2K_v(nQD20{;C9cRx_ICUZKo4!4J z=gtg*Wvh?B|5hDLjv}bZVC33cErR$6*9W`ad+Qb?)ZG+y^efw?Bv zxq{lLR%3lgCJLD+7)R!ML0xkQwspLKGoo+9`IeYx>uCZ`Bj0j!yma750f$G!kjb~K zV9Q-D7q(d6WjRL@Yn|H?YV9b;b?0tCI5Y5OHVWi_xpDnFwCT21jdum!gf2Jelaw zJlJH;6tEtOG7%J!K}*tw`7f->f94#?0xf4g;&PjFA90Q(`w`B7L!T%y38`@!6nvrt z6cAEK?QTK3Hw|0vDqss7;_tq`D3gIDL?9%9!W-EL3i)4dT>B2W$wYv{8_?y(W^Y*S zZ6%X}D}@p<<)H!IUceNiPl(s2YE$AS^ zW0T@FsUgYw@Q}!;P#sQR!~{kLLX26atf5vuAn9 z*|Xy0>{$_e5cUcbFk|%G!Squ~p5el$_N8NY`5j5gsqv9XQOV*WNM=q6?Ne0V<>QlL zV-iJ3FJ)3=(_&LKDS`0;i8@SQgtt&X^(Jn>Z|4KW>W>1`Px!k%DfjLwqz_pyz*)FgO&@D| zplCAxAL!a29l>UdQO6zuGp09^bnI$u_HT*B@Q9{xZyLU5jW~-Tq?$Bt|4@)i6JgB;;!NV;o|oZpI1C1BY@l za9rLpa8jvBYfv<4Ni}@iI3YktOxP@72A30Vf%0$xV(~OD;2(aZU+JlbAE`h+yr0HQ42PHF1?ROui2vA1I{h zO-p#(8&jRIo#^zPAmh~$yhoMr#l4C@-`^XHt#!sp52Q&-u*3A9xR>q|k{2?LrmfO6 zUVg7~hmN+^YeB0sPP$JXw!T;S=bzQ%@E1BK5||^uxGhXVaN?&-jJ6~bqfQ;N%d6?L z3i(sG)MUX+`znn4SZTd!?kW@*yj}p$!WwCaH!Sm}-`@iX`8s?9ycw8aZbdxNl z$-KOZu}7I*RftM+SQWC zqLZ14yZp1`lEYIH_Jt*-?Tb&^bv`IH^H|cY3(4Gpc~*zPFO1L6{QjJlv!~ioIa#q; zyLRnt)0xYqsKa}L*PYX5?ubcF7K;nA(y~*tQaWa(>~@R{IIfFKj!KD2u?P!^ z4hmUtInhhw=MoYau5$}=+qT8mA~;wd8ld&^&CC{eCuHU1hh*hw(i1XM)8aRTX6qsn z6QdHeyLaZKr-->3aha)_gs6n51YJ~aSWZZ;1xHPxZMGlV`u(ONi`B<{E?v~@Ql9W> z=)7!^+mtmi3*%PnB4Q#UG{F%;fj&C_ZT>#neZ#}T!y-Zg{X%`hd;`71y#2i`!U7}p zK^ni<@K{}JOyUkLr|&^g1*LXQ`C^)PviDYv$L3(KkkFXeP~F_jNom^>EW%o|QoipplQcV%S8N5w}aioW^)-*8<}RB&`)ghgOf zNT^<)65y-h^fnab8xZ8D(IexTwHWQ!j9Cmgnl?2hDJeYe<*yJ4+331VJahe_ByYxDaCZ}UY=z~PgoYGUlaobaL z(cz&HI?g<(9Tga!pP0ELCw+IE%l5FC=masD<;71P$EG{Q;GT*|IM1Hh=|CDC<~6J%&3si=y)+cJ~myG9=s!f)H1i<7PeLIvm+@b zNK6mSi{7RQ5BHA@(}gO7V*?XIb-OmFdM3DA6l~ftcbO(A);}eEM`C)ME+#Q1IZ<=W z>x^fyj&r1`+(TP;O?1@+MEFGn>5@WIBNKuw;{3xB1GL+GgZv`J$f&4Dj|g{PU1ZY6 zZ5rS3@Q^vWkcim$q}ceF1Tk@EY(|DADKaTCGK7rU&EHY)x+G#(ur?wrB2tXn<+n}4 znOjm+NJJ4?qzW?S@FKWz0-4ekN6u?_g> zQehE~7mb7N2jXJlW8%f^OHA)epmr(Oz5w&mniFEi8YW&J7p&JT`Udm(Tb()}O-fFK z@o7hPu{e9z$pq!!1r|7a*Wpx4UG9*NZ7iePsA`cxRU6x;jUm3xXOQ%HlY%efs7R8~ z(TeOW!5#O`Es z*aG$-dzyXBzGC0AAC%_G&y`x`DCIKc2BoWVv(iTysZ3F(EAy2i<< zR8L4u!oN8wy4CP_3;Q2aC0nRl>^%RCm8aFl^D_%t$s@TaAtyekW4w2wcd{#JjUFA! zS?Jv~llg}2ZCo7c8txV0(=j4DEGM`Kx0jZ5n84z8#-+h7AzQ+|I!5G%=YC-KU(00E?!7g`HFk4X4zZhg zLN@I({fnPX1~obPfV*7vL>$G=aa=cjhU52_bfegBE{_2#ot*u@CDFcWg>tv|s{IqR zxc$Jd@kl)3RexZvAK!hfNSv;mw0Z&lCP-HYPW-U%?t&$>IeYur(R1!A@_1c%3kX+y%oLc`*M(RSPnXV$^&id+;3Na`KW-xfa}HHh;0@&78Yp`8%dRyI~Qt&v8!n zL@jogbFA3z?r~|n_`^fq^}PPp4GnM?!4_=K9`*Am)?sAK;ukvY+_O=HBhqlDXhGWK zsTyoG7u(`KIyHP2T_>HcwWVRStONSPfrl0G)&O&>6av;`Z1Q3y$^!dg;{v zkd)=T-@5;(xlrxT$|YwJ%r6}^X#qKl;8ycl1mA0qw`qP!7 zWm9KuS};qLW*R5+vj4xRlHT!)g?+`I`7RqhJzO^K@!Th>FiE~2o)j7v656a7Aj$b7 z!Xm@NH6e*1N%0A>u?ad=u2<8{wSsB_dQ>0~6M3mhLicet3ptXKxsJgOqLet>$TDi) zK~VjA{=n_BGi!S4R3il0bGeQ?uX1QPGC@@sUvMIScSu0NCsW~^Pw`(94NBDkIK=<+ zYy*`6&ae{%m1lH|>#OQ=?n0#Ep}q>&v#Nh6!oSaJ(Yvb(cV+KCsJXM?jJ^H*B@@@? zY%JWSQ?3}aPSq}AJmLZ`JZZp&2)Da;zrkt{$1 zBGZM$sea2yU&wh$M;Tz7vid%JgRe8HMacM#aSUIB(O$qFR;~8lw053mWr@+{AC89_WiqT4HLm_#POm!|A0=OeoP8sH9)` zeS7yDD&AbMMoj*GPhonhdq#)(Yuy*m)2uA=*soJ12|t&f`0>QXX)FCnhDuN5+RIh^kxWSjB=0`ZMa`0J3Uir5d`PX=)sN!LMz0rLr%r}}0tcpMX=^U9rKmBI;9GSC6FQ{$?v^WNJ{LXP}!AxD1TWa(`coelMhY~mcJw)I0K zM~q5JUMr|bR@AyPDrrN5aRaN`BH&V752f5H6~`V04X&B)@VONb)O{_2K47#5HR-ZCt-$@5V!-swF`5fKzkysq-;W z<&AGLKeN~1CZpo(*hNTH=N)qmp*GJNKRqk_x;{@T&q`-(&rIl=(k@YmH=Dstp2 zIrY4aeD>>k%8U{ynrcJQ6i4wCO=+kvDVpj;b)snM8)_g$Q-i6Q6iv;c=1?>>pK_yU z%7gNtXlgT+LDAGMlHi}pqmENFb&5Jm(bNU%GDTBm)Gdmp?of9qa(F=nWkyv}l@v|Y zP%kK&`h)s|qNzXW{uE6Qq{Aqhj-VqbnvNzX640@99HpS+=~RlQGfDb?I)~1o6!Zyl zmMukcY<8t=D04E#k00g#D$1JbL=C4b$1ECe zLroetW{wRtZ`^ltY$&IxV;0#^9@8DB*--i!)4sK#;=Xg3ZbN0xA$5x9d^gpGoZTzq zA(Z-p>fCZ=Mtw$gpt`hNDJV77k?PuVWlpuFG*q{iD~4)EX{qilS1i?@`jYypI8W%#8GJInBE8QRKl zpbUr0&|ZcUoL76e($i!(M}|ve=p;iI8E%%LpA17}7$d_J8D?%=;o(f@%dl96hh=zD zhNUvRB*SYmye-2@89tEVqm9lRo#|&Xd@aM@Whlw;1A%7dGDI?LCqru)eksGwE$_aW z1O9Izkub@b$^U=|bhWec9Ne!e%wtOc;<&j!Y!|8n0Nq!oC zrDJ)=ciMH$0+9rfzD2755-6>4I+m7l<*;6wpN6MA*p`xgp z)X!86RZrW{J?Vk;6nY88P{AK-sF;s6^sJ9H^umud^x}`dQ3|><)sgN>b)>sf9Vv6l z@1u!|`S=HQmugGT`uGQ>pd6_#bYH3qJ%H*$nNg7xqWe>bGN-0|JViTxJVmekc#3xV zc#3LAb)ec(0@arC`)Hu_A74{39}QH($Jf+fA74|_$Jcacsu$gr>P2^_deM_VzNV*s zd`-{#XrLEU^_!mV}GpLUL2LIo2{@vrhe=$^-j}>Gj)Rm7F)YXp_ts|m7r~glJ zUjk)Sb*24%=f3yq4K=(f3XmC@1Z5CVKn6ubL{P*D2T%r45t+mpjk6|g=#HUX>F)gg zwhB(=5LEQfvPse!o9ODKext#^LcnPKgc7Z0K}<>l>glz=d+&R%sIozg-TSVy@4e@q zd(OG%?DOq?_C5E#d8p+A)N&ze_3Q&V3}yl%&IQvQZ}_*<<6{#({70O*-4-8-1hSeIS-FvN7 z{r)KDC|;CR%Jt!ie@rD?Sq*?+6UlEp?zRbUUi&ZFCK=|_hLV1B6xSub7D}^!8}K{* z9@`&`TGdt zuix$e$=?F_2Yic4-|P4Jk8rfE?y*+zEo!ZB?0pZ}Fi(q951M9Zg?e!*r4-$5vJmxv z?%omNZrd>%lWN`E`g&>0_!hqh153AKUC~nA=&$Y zf8RIw2LCevwZ&)ClfEIzYxF<$FZ()Vk@YY82LG_%AbB+Tuh;elMyocP0N>yn{c9Q} z4Zhw#<{QI)ETy(jb7@JP!%4B{j2fQI;UO!AN<>)ghZA}JZ{2%uJLdBmS}w0c&%4I*ZYlrgY_-o z{}13F^=kotXVe~B{F{Cgj?&fF#T)&LzQs40{QCc8GGwtph?`$P6~&fT+Csa3O>&)& zH;b^>#fQI)&Nx=j)Z#axr>vSi{%zlA&+$!=wWEJC&RO{R*Ltc0$k)ZsU?r$r(>Er4 zhM{|-qxVhb54iQKk>u>Zi%MI~H^vfc6h4>qY&{0(%&upBlW+M#E!T!(JHW;xr0YsY zUs#I8#3Q3E6-V|#Xb6CwLXTPi;{o|VKJ!g}ui=SrLfY?)YwnwIxaH?R_B+uvdhRTe zNF$9JWHI8uD9vzJW3q%=_gd?-uS~w)H=C6ECfO*4@+S8?{0?Eq4(YhU93&>;m0^=v zKxW14EnL~{8-$~VrNZ2{6id5ND|u+gvM6GFNC(5yi zyFH00mRzi--{e~iH8oR;sI(-LX~1tS9RpvDN^>=`bHCN^l%<-oUP3+|Pp#$O{)@Cg zg=63B>*HD}FVpy;<@GY)pNa2Ky5@GQ!Zuh~(kdl$<&xMi_hyUn`;irvOZGxrM|OqD zUx<6kU&qbyoGhfUO{05CODfc;P?EKMiEgTu9-&*|kf~{j%(niO%F8#|; zYsoQtFTUGq*|wx_f`q4Sp6Qz)jh%wsc_5ib?7%pqVm}@-xylV@m314_Z3YtNv+>*f zQ|iYizs>LRdyD!&*tkb?xW5haZx4%0NIJ7!8Uj~2)ynPuK#wC)ElphI8~ko$51eZq z5>@#Pek-zmt#9!g%#IA_nTJNj0^z|3`pjzEq^bx-0S4a0Y`mM#8!okVc`;Yx&etBt1 z^R|?phorgc2>)7qtuXs(^i9%wCiU{Q_-*pn9B6Zxm39Cf@@V`z_nL+H6-c&k!GH7R zNH{tEz&60i)9t>Eu~Pu8uGSRlbBT31AJz!N%KJv@px+;zg(;db%x^=0BmK)5>>Duz zeL-XHU7v_+qsSc z)cf^(-hajoe!tG@3ug&kd&Ykr#q2Aj{u4L&k97SO{>Z<>=lmyp9vzjha#M+S!j&!3 zSovj-EeOn0YZ}q!P$n(XQ!Kl%Y=Kq*bh3A*dVH;o^1 zyXB+M;08q7G;IsCt>LF`RUBNsOY_54q0-f|!QECGTvxZc5PsuUyWVcK8{pQo30vG6 z_nsT<-g7%#vm4_cbboYvwYTHRZngV7NZ3Bex@oSiRj6~b-1;CNbh5o#zk%-t-Ge^C zz+kAG<6d$L+{SjpGM6q5>b1D%cC!War`p?gKh-z~>&^Q|IzCanO#EcUf2QMe#KZKL z>G)i6(_Z9a@r#Y)J{?z!PZu92zD9h3_)>Ax1mq0ye&QF1PZ3`yKFl~i(D7k9eq6`q z(IsxxvCa92J9YeocxT1jD#S2-NZPwbQtN1F>mbOd#FuynI(yGR+^(3@Er#Xd6O7|- z9WNB`E^gj_a;C1{{`oEt|DpJy;sX@F#dsng{IocdP-*^o5c$?U;HT@3yR?oXi85r6 z!)T1baTtqn7>@}!9w%TTPQ)afgvmG=Q*a8V;#5q-bex9MF#~5{Ca%SGxE?p)My$e3 zSc`Rd9zVms;uXA#U*Wgdg5O~)w&7j;9`E6OG~)kbJN|$jXu_ZI3I2lp_za$8z$D9< zVU887Vl_LkBRjJTyRip*@o@HKe;&a>Jc>hjG>_qE9>;NooXdG!z=gbwi@2CexQr{flGpG$-oRD7nYZvZ-a%`JJjP=N=HPNH#%iY7 zhy6H!<2j#~@KRpIt3ljTXs^FUYyEFLs22N|k{0{F-(Z`K_|mO*ur|934k@IOMLEvH z`M3ZVVm9XBB3z8Qn2!ax1PgH~F2m(mge$NZS7Hg4Vi}fW1#ZT-a0_n5ZMYqG;7;6y zyKxV`jql)Za4)`#)%aWd9lnSA@O`Yo-{XEffQL|rXYm3y;OAN)^EN&}3-)3kKE>w* z9TQA3&2m;U&l=XUCwoVIIgm$kFo*M4j^Y@O<#Pf(hbWDhLVsKH zh9fWx#925CS=6H*IX=QCQO>8hL8Cm4KIm7-HO$dg_5Cv(y302V=E-=NQ+Wo~^Gwdhk9jfY;^$nzOYv`9 z#H;WIui@QV)41GP0y$X==F?815@jeu2jq}LEyiFBh~sb^9L8cSau|nk2rwSwk-!8@ zKvMXX!bD6&8YkjJWH1SnkQJJxa57Ft4pT4%HQ&EX&n1(7$$8_Xz z8cst8oQ~5`jTxAM8k~VM&;c_s6ScS=*Tdlk+<*W#;zp#f3agOAO}Ghpjqse>F~B;k zLk_Rt73A06yQtZpVNU=ZrBgG?l1X3KtK}hi^9)%Q#a0t>onnxqe5gdUukKr-Ma5P6F z%j0+)vK+^8$Z`TFAj=bY0#ZDYCnCj@coI^a!YN2`DyJgHX`F@}PvdFGaRz4~$C;do z9M9resNgv~2Nj&fS*YOoJRg<3kQbtob2tZ;oXfeW zG4fo(CCGCbmm$v;T!B1SawYP-hSwm^>v$cic>`}iHCJ&Js(CYSMm2BYE$G18cpEzK z4&H%U-o?8#${g2VxMn5^9EA+VX%*lg9MfjDVsCyQGvmzjONP&0Q5t@sLTK<3@O=qVR*C+jW$EMc4zMs*6%OXI&c4p%T5hm7`?E*tsfL)^4Bv{2lv zCiYCW#bvjpei#yk9@>vZ4+I$ADp2+81!8zf2+!N54T%_963h~`U~z`e4nyIP)0yFY zd_CSD4J!Uu9bDwwoeFlmn^ zzWw$yIbCS0%8^qmSL)5A`EqP4M>#s-e4LLgF2DtFxDXd2z--J$5_2#IDO`k$kjGri zMS%I3k2Drw0Rq_*SzM0Gk;ft|LOHI$6{x^sEJhWs#FfZn36`J(mSQPtunfzP#&Rr2 z2duyfbi~cL9mE~D0}glM9whN?+>0`N7vBZ38uuZG@8f<{;{iN?3Os~|K-8fQc|40} zQH2-q0+P~=S^OM7M-sopFHx&C`2jw_2gsuZwjy>f_Ja5npMv-tpCf5P2uDX-ai3rU zjwz<#m}VLYma`m5R76Hd|JQAG9i6AF)GRRYTDsr68>B#YPo{k*P;2FsAOrD7x z&*s@E=eax=z27@sa z861Tn=nR|F84biB;l1IiQMfO@U$^rx&cZQTknJoAR>9Md*gU}s$2Oqr+e`Y15gZ-i*m=5)0Q7Dr*bnvf)-20rT5+%zwqVj8OMF*21d=e~X*`Vp z&)^y1?{x8u?C3ytbV_z~8Af9??AH+{!pZUtWcem!^QL6&CS~oWWbKyW0?bBQxSYm3 z%tJXY#id9Ki_=2htS~nxzd(qvX(4PzsG7m|@qJ{4n`!(@^j*`xg2K?WEaDV?i{FCy z9e!uuGU3l4KEWp-{(`@N*pL07Ff=0!%?Lv?!qAK`G|eotusL8kGD6afkTfGCO$$jg z?8HvU@Gu^R47;)`GVIRo$Z!~kpb3Z3*VnPGO(b~ZA+4a?4;Gipn= z96Cl@jJ`bzF&#DX+tOjkD7Wza9iyB>idS{m{2(No@0OCjUntbce0Cw3wum)Gas9U0 zwneggoe(#We<2}!O$uL= zLe`{^H7QIjldpmDFNDaN6tbp-tSR{#C@%wruSxk}Lu5_Ln?QLGLhMY*k3b=4O5Owt zM^o}CP-tp?v^0`J)1=TeB{WS5O;aUyX-b|23R6?^FHp#ul9z$P*OYt>6v~D(|Iq$S zY5q?kYf4@K3SU$51yCrPl1G5T+LW-?32U9O)(LB!ur?6Z2Ey7vbNhs_woEhpgb=q( z^ZbNxw@kDBgwVGP!~kTGf&KiCVJ_8^p-p$WdN!|~E!Wtx`F0tSLY7pdOU-{&u0D0r zqDl2^AYGb}E=@|8n(ysA&3$I0NSb!vDJ}0nD3pM z%j7hdsggY8HH)c~ROF>^t2KYgY5r27nMp=#oP-L^XexOMPeFxrbzTycmn`KaMS00jUh|qt&1)(&uc?$o zg|nNCeAoQ$NaTr-`tWUO2=<|JcIGUlYut0ieciKGQ3k`|OmS`bQ_^n6l!J}Et) zlAcd#c2fa|E|M+t)0%~5{>V_C5|KQa4>A!+K&c&NKE*_<{`(>e%6w+6pTs<2fyPOo z5fW%@1gdL7bxnZSBp!a%>yV5r5wrB|+9o*J4z6G+09j5>-q-3I@&Tb;?Y+=D{D%Bk zOvLoUm*g|_CHX>qNxn*7lHaE<$sf~~koJGm4GBH$NKVFa>8u zvGI53!!aJG;H)S%{{DOfCSWSgj$-5Q&`08UoQiXz*!X+&V{ihd;atp`KYz(JE+t+m z-buWt_yF;t;-kcm7oQ?NLwwf4Wy_bki^Ug;FBV@Rex3Nu;&+IDNBr-^?-&2!Wh>`j z;vN#O6W<{IQ}Nfu-xA*{zC(Ps_&(!7V#yVk&kriaYsI^Y_ZA-@K3IH&_!#ly#V3nT zTeAF;CBaPbS>kiV7lT_&V`A@%7>_iEk8t zb@|GL%YxU%>&1T~zD4{!@g3sL;(rw1EB?9hMB?geS6rRQis!{UiFX(8BR)`ksQ5AB zW5p+m+Z$@VMg9i%lwJ6BxQ(SMSyKNUM>cZ~=g(iAhi~w04jtOyrs?h2?7HxG3*z4g zF#A#~z=SPdm)qQeUyGYnZSTgu8t;Um7=`086=&f>EWl!{#46l@d$9&T#3QJ~^Vo<@ zsK+~aH}pMoQ`k=YquR*f3A`K~y^41t|MYv&-d1H<&1~hA?LUn6_Uj~e9$()coi`rz zy7i00dx%TlM|*#1t08P%gY936&VL-8*V{V_egM+en_8LGTNS%isqFUx zEbcd~2lbmMwsyjC6B3-ui@AW8!12c=XIA#VgIq6OC%#VnLHs)$ACx|+K{dap-(0yH zEv;haS^8EnGeF)}h#}1yG;NncIo^W9T)j(O zU|JrXQIGW;f#;hv(vF;=_D|Yq^e(@-aTnC-@}mK}-drM)KfBeS1zf#yrIqJ>2e#3+hvrcX8FdF9xBTmMpN;wBaXY|Kt yOvK50r#{bCJ;delDL&0-_$+_K^?Z)c^99frggCZ literal 0 HcmV?d00001 From 0012f09eebfda65625ff0f755f61444a8b8e72a1 Mon Sep 17 00:00:00 2001 From: Patrick Walton Date: Thu, 20 Jun 2019 21:43:57 -0700 Subject: [PATCH 16/26] Fix examples --- Cargo.lock | 41 ++++------- c/include/pathfinder/pathfinder.h | 2 +- c/src/lib.rs | 4 +- canvas/Cargo.toml | 4 +- canvas/src/lib.rs | 72 ++++++++++++++++---- examples/c_canvas_minimal/c_canvas_minimal.c | 2 +- examples/canvas_glutin_minimal/src/main.rs | 3 +- examples/canvas_metal_minimal/src/main.rs | 3 +- examples/canvas_minimal/src/main.rs | 3 +- examples/canvas_moire/src/main.rs | 2 +- examples/canvas_text/Cargo.toml | 1 + examples/canvas_text/src/main.rs | 18 +++-- text/Cargo.toml | 4 +- 13 files changed, 102 insertions(+), 57 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index fb9935bd..3ce77aac 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -210,6 +210,7 @@ dependencies = [ name = "canvas_text" version = "0.1.0" dependencies = [ + "font-kit 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "gl 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", "pathfinder_canvas 0.1.0", "pathfinder_geometry 0.3.0", @@ -495,13 +496,11 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "dwrote" -version = "0.5.1" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.54 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.91 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.91 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -605,23 +604,18 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "font-kit" -version = "0.1.0" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "arrayvec 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)", - "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", "byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "cocoa 0.18.4 (registry+https://github.com/rust-lang/crates.io-index)", "core-foundation 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)", "core-graphics 0.17.3 (registry+https://github.com/rust-lang/crates.io-index)", "core-text 13.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "dirs 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", - "dwrote 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", + "dwrote 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", "euclid 0.19.8 (registry+https://github.com/rust-lang/crates.io-index)", - "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "float-ord 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "freetype 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", - "itertools 0.7.11 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.54 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", @@ -907,14 +901,6 @@ dependencies = [ "adler32 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "itertools" -version = "0.7.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "either 1.5.2 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "itoa" version = "0.4.4" @@ -1357,11 +1343,11 @@ dependencies = [ name = "pathfinder_canvas" version = "0.1.0" dependencies = [ - "font-kit 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "font-kit 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "pathfinder_geometry 0.3.0", "pathfinder_renderer 0.1.0", "pathfinder_text 0.1.0", - "skribo 0.0.1 (git+https://github.com/linebender/skribo.git?rev=a89e9ca99e0d6736ea1b7754517f4df14fd96a2b)", + "skribo 0.0.1 (git+https://github.com/linebender/skribo.git?rev=a2d683856ba1f2d0095b12dd7823d1602a87614e)", ] [[package]] @@ -1509,11 +1495,11 @@ name = "pathfinder_text" version = "0.1.0" dependencies = [ "euclid 0.19.8 (registry+https://github.com/rust-lang/crates.io-index)", - "font-kit 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "font-kit 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "lyon_path 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)", "pathfinder_geometry 0.3.0", "pathfinder_renderer 0.1.0", - "skribo 0.0.1 (git+https://github.com/linebender/skribo.git?rev=a89e9ca99e0d6736ea1b7754517f4df14fd96a2b)", + "skribo 0.0.1 (git+https://github.com/linebender/skribo.git?rev=a2d683856ba1f2d0095b12dd7823d1602a87614e)", ] [[package]] @@ -1961,10 +1947,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "skribo" version = "0.0.1" -source = "git+https://github.com/linebender/skribo.git?rev=a89e9ca99e0d6736ea1b7754517f4df14fd96a2b#a89e9ca99e0d6736ea1b7754517f4df14fd96a2b" +source = "git+https://github.com/linebender/skribo.git?rev=a2d683856ba1f2d0095b12dd7823d1602a87614e#a2d683856ba1f2d0095b12dd7823d1602a87614e" dependencies = [ "euclid 0.19.8 (registry+https://github.com/rust-lang/crates.io-index)", - "font-kit 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "font-kit 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "harfbuzz 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "harfbuzz-sys 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2439,7 +2425,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum dirs 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "3fd78930633bd1c6e35c4b42b1df7b0cbc6bc191146e512bb3bedf243fcc3901" "checksum dlib 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "77e51249a9d823a4cb79e3eca6dcd756153e8ed0157b6c04775d04bf1b13b76a" "checksum downcast-rs 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "f2b92dfd5c2f75260cbf750572f95d387e7ca0ba5e3fbe9e1a33f23025be020f" -"checksum dwrote 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "30a998e9ff70cd208ccdc4f864e998688bf61d7b897dccec8e17a884d17358bf" +"checksum dwrote 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0bd1369e02db5e9b842a9b67bce8a2fcc043beafb2ae8a799dd482d46ea1ff0d" "checksum egl 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)" = "a373bc9844200b1ff15bd1b245931d1c20d09d06e4ec09f361171f29a4b0752d" "checksum either 1.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "5527cfe0d098f36e3f8839852688e63c8fff1c90b2b405aef730615f9a7bcf7b" "checksum env_logger 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b61fa891024a945da30a9581546e8cfaf5602c7b3f4c137a2805cf388f92075a" @@ -2452,7 +2438,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum fixedbitset 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "86d4de0081402f5e88cdac65c8dcdcc73118c1a7a465e2a05f0da05843a8ea33" "checksum float-cmp 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "17ae3a6394183450225f33d9419cbd627b3cfc831e14f3f1146d5bcaf984e00c" "checksum float-ord 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7bad48618fdb549078c333a7a8528acb57af271d0433bdecd523eb620628364e" -"checksum font-kit 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5be0133b580e2920076afd5bd4b81dc172d10e5653bd1c516476718d52347859" +"checksum font-kit 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c5b784f7a48d718df8d9ee28f81f8afa0a7ffdd61038957cba1ec6837a836d46" "checksum foreign-types 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" "checksum foreign-types-shared 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" "checksum freetype 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "11926b2b410b469d0e9399eca4cbbe237a9ef02176c485803b29216307e8e028" @@ -2480,7 +2466,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum image 0.19.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ebdff791af04e30089bde8ad2a632b86af433b40c04db8d70ad4b21487db7a6a" "checksum image 0.21.1 (registry+https://github.com/rust-lang/crates.io-index)" = "293e54ce142a936a39da748ba8178ae6aa1914b82d846a4278f11590c89bf116" "checksum inflate 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)" = "1cdb29978cc5797bd8dcc8e5bf7de604891df2a8dc576973d71a281e916db2ff" -"checksum itertools 0.7.11 (registry+https://github.com/rust-lang/crates.io-index)" = "0d47946d458e94a1b7bcabbf6521ea7c037062c81f534615abcad76e84d4970d" "checksum itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "501266b7edd0174f8530248f87f99c88fbe60ca4ef3dd486835b8d8d53136f7f" "checksum jemalloc-sys 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "bfc62c8e50e381768ce8ee0428ee53741929f7ebd73e4d83f669bcf7693e00ae" "checksum jemallocator 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "9f0cd42ac65f758063fea55126b0148b1ce0a6354ff78e07a4d6806bc65c4ab3" @@ -2582,7 +2567,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum shared_library 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "5a9e7e0f2bfae24d8a5b5a66c5b257a83c7412304311512a0c054cd5e619da11" "checksum simplecss 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "135685097a85a64067df36e28a243e94a94f76d829087ce0be34eeb014260c0e" "checksum siphasher 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "0b8de496cf83d4ed58b6be86c3a275b8602f6ffe98d3024a869e124147a9a3ac" -"checksum skribo 0.0.1 (git+https://github.com/linebender/skribo.git?rev=a89e9ca99e0d6736ea1b7754517f4df14fd96a2b)" = "" +"checksum skribo 0.0.1 (git+https://github.com/linebender/skribo.git?rev=a2d683856ba1f2d0095b12dd7823d1602a87614e)" = "" "checksum slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c111b5bd5695e56cffe5129854aa230b39c93a305372fdbb2668ca2394eea9f8" "checksum smallvec 0.6.9 (registry+https://github.com/rust-lang/crates.io-index)" = "c4488ae950c49d403731982257768f48fada354a5203fe81f9bb6f43ca9002be" "checksum smithay-client-toolkit 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)" = "aa4899558362a65589b53313935099835acf999740915e134dff20cca7c6a28b" diff --git a/c/include/pathfinder/pathfinder.h b/c/include/pathfinder/pathfinder.h index 3ab80705..7ded8d08 100644 --- a/c/include/pathfinder/pathfinder.h +++ b/c/include/pathfinder/pathfinder.h @@ -129,7 +129,7 @@ typedef struct PFSceneProxy *PFSceneProxyRef; PFCanvasRef PFCanvasCreate(PFCanvasFontContextRef font_context, const PFVector2F *size); void PFCanvasDestroy(PFCanvasRef canvas); -PFCanvasFontContextRef PFCanvasFontContextCreate(); +PFCanvasFontContextRef PFCanvasFontContextCreateWithSystemSource(); void PFCanvasFontContextDestroy(PFCanvasFontContextRef font_context); PFCanvasFontContextRef PFCanvasFontContextClone(PFCanvasFontContextRef font_context); PFSceneRef PFCanvasCreateScene(PFCanvasRef canvas); diff --git a/c/src/lib.rs b/c/src/lib.rs index b70f62c9..219e43bd 100644 --- a/c/src/lib.rs +++ b/c/src/lib.rs @@ -148,8 +148,8 @@ pub unsafe extern "C" fn PFCanvasDestroy(canvas: PFCanvasRef) { } #[no_mangle] -pub unsafe extern "C" fn PFCanvasFontContextCreate() -> PFCanvasFontContextRef { - Box::into_raw(Box::new(CanvasFontContext::new())) +pub unsafe extern "C" fn PFCanvasFontContextCreateWithSystemSource() -> PFCanvasFontContextRef { + Box::into_raw(Box::new(CanvasFontContext::from_system_source())) } #[no_mangle] diff --git a/canvas/Cargo.toml b/canvas/Cargo.toml index d93ac0cf..1c620859 100644 --- a/canvas/Cargo.toml +++ b/canvas/Cargo.toml @@ -8,7 +8,7 @@ edition = "2018" crate-type = ["rlib", "staticlib"] [dependencies] -font-kit = "0.1" +font-kit = "0.2" [dependencies.pathfinder_geometry] path = "../geometry" @@ -21,4 +21,4 @@ path = "../text" [dependencies.skribo] git = "https://github.com/linebender/skribo.git" -rev = "a89e9ca99e0d6736ea1b7754517f4df14fd96a2b" +rev = "a2d683856ba1f2d0095b12dd7823d1602a87614e" diff --git a/canvas/src/lib.rs b/canvas/src/lib.rs index b31fa1c0..9f710dd0 100644 --- a/canvas/src/lib.rs +++ b/canvas/src/lib.rs @@ -11,9 +11,12 @@ //! A simple API for Pathfinder that mirrors a subset of HTML canvas. use font_kit::family_name::FamilyName; +use font_kit::handle::Handle; use font_kit::hinting::HintingOptions; +use font_kit::loaders::default::Font; use font_kit::properties::Properties; -use font_kit::source::SystemSource; +use font_kit::source::{Source, SystemSource}; +use font_kit::sources::mem::MemSource; use pathfinder_geometry::basic::line_segment::LineSegment2F; use pathfinder_geometry::basic::vector::Vector2F; use pathfinder_geometry::basic::rect::RectF; @@ -29,6 +32,7 @@ use pathfinder_text::{SceneExt, TextRenderMode}; use skribo::{FontCollection, FontFamily, Layout, TextStyle}; use std::default::Default; use std::f32::consts::PI; +use std::iter; use std::mem; use std::sync::Arc; @@ -170,6 +174,40 @@ impl CanvasRenderingContext2D { // Text styles + #[inline] + pub fn set_font_collection(&mut self, font_collection: Arc) { + self.current_state.font_collection = font_collection; + } + + #[inline] + pub fn set_font_families(&mut self, font_families: I) where I: Iterator { + let mut font_collection = FontCollection::new(); + for font_family in font_families { + font_collection.add_family(font_family); + } + self.current_state.font_collection = Arc::new(font_collection); + } + + /// A convenience method to set a single font family. + #[inline] + pub fn set_font_family(&mut self, font_family: FontFamily) { + self.set_font_families(iter::once(font_family)) + } + + /// A convenience method to set a single font family consisting of a single font. + #[inline] + pub fn set_font(&mut self, font: Font) { + self.set_font_family(FontFamily::new_from_font(font)) + } + + /// A convenience method to set a single font family consisting of a font + /// described by a PostScript name. + #[inline] + pub fn set_font_by_postscript_name(&mut self, postscript_name: &str) { + let font = self.font_context.font_source.select_by_postscript_name(postscript_name); + self.set_font(font.expect("Didn't find the font!").load().unwrap()); + } + #[inline] pub fn set_font_size(&mut self, new_font_size: f32) { self.current_state.font_size = new_font_size; @@ -509,29 +547,37 @@ pub struct TextMetrics { #[derive(Clone)] pub struct CanvasFontContext { #[allow(dead_code)] - font_source: Arc, + font_source: Arc, #[allow(dead_code)] default_font_collection: Arc, } impl CanvasFontContext { - pub fn new() -> CanvasFontContext { - let font_source = Arc::new(SystemSource::new()); - + pub fn new(font_source: Arc) -> CanvasFontContext { let mut default_font_collection = FontCollection::new(); - let default_font = - font_source.select_best_match(&[FamilyName::SansSerif], &Properties::new()) - .expect("Failed to select the default font!") - .load() - .expect("Failed to load the default font!"); - default_font_collection.add_family(FontFamily::new_from_font(default_font)); - let default_font_collection = Arc::new(default_font_collection); + if let Ok(default_font) = font_source.select_best_match(&[FamilyName::SansSerif], + &Properties::new()) { + if let Ok(default_font) = default_font.load() { + default_font_collection.add_family(FontFamily::new_from_font(default_font)); + } + } CanvasFontContext { font_source, - default_font_collection, + default_font_collection: Arc::new(default_font_collection), } } + + /// A convenience method to create a font context with the system source. + /// This allows usage of fonts installed on the system. + pub fn from_system_source() -> CanvasFontContext { + CanvasFontContext::new(Arc::new(SystemSource::new())) + } + + /// A convenience method to create a font context with a set of in-memory fonts. + pub fn from_fonts(fonts: I) -> CanvasFontContext where I: Iterator { + CanvasFontContext::new(Arc::new(MemSource::from_fonts(fonts).unwrap())) + } } // Text layout utilities diff --git a/examples/c_canvas_minimal/c_canvas_minimal.c b/examples/c_canvas_minimal/c_canvas_minimal.c index 9721ee3f..bcfa09b9 100644 --- a/examples/c_canvas_minimal/c_canvas_minimal.c +++ b/examples/c_canvas_minimal/c_canvas_minimal.c @@ -64,7 +64,7 @@ int main(int argc, const char **argv) { }); // Make a canvas. We're going to draw a house. - PFCanvasRef canvas = PFCanvasCreate(PFCanvasFontContextCreate(), + PFCanvasRef canvas = PFCanvasCreate(PFCanvasFontContextCreateWithSystemSource(), &(PFVector2F){640.0f, 480.0f}); // Set line width. diff --git a/examples/canvas_glutin_minimal/src/main.rs b/examples/canvas_glutin_minimal/src/main.rs index b73a0fdb..9b8662c0 100644 --- a/examples/canvas_glutin_minimal/src/main.rs +++ b/examples/canvas_glutin_minimal/src/main.rs @@ -54,7 +54,8 @@ fn main() { RendererOptions { background_color: Some(ColorF::white()) }); // Make a canvas. We're going to draw a house. - let mut canvas = CanvasRenderingContext2D::new(CanvasFontContext::new(), window_size.to_f32()); + let mut canvas = CanvasRenderingContext2D::new(CanvasFontContext::from_system_source(), + window_size.to_f32()); // Set line width. canvas.set_line_width(10.0); diff --git a/examples/canvas_metal_minimal/src/main.rs b/examples/canvas_metal_minimal/src/main.rs index 043b9d5d..8d8417ad 100644 --- a/examples/canvas_metal_minimal/src/main.rs +++ b/examples/canvas_metal_minimal/src/main.rs @@ -52,7 +52,8 @@ fn main() { RendererOptions { background_color: Some(ColorF::white()) }); // Make a canvas. We're going to draw a house. - let mut canvas = CanvasRenderingContext2D::new(CanvasFontContext::new(), window_size.to_f32()); + let mut canvas = CanvasRenderingContext2D::new(CanvasFontContext::from_system_source(), + window_size.to_f32()); // Set line width. canvas.set_line_width(10.0); diff --git a/examples/canvas_minimal/src/main.rs b/examples/canvas_minimal/src/main.rs index 06fc1a7e..230640c3 100644 --- a/examples/canvas_minimal/src/main.rs +++ b/examples/canvas_minimal/src/main.rs @@ -52,7 +52,8 @@ fn main() { RendererOptions { background_color: Some(ColorF::white()) }); // Make a canvas. We're going to draw a house. - let mut canvas = CanvasRenderingContext2D::new(CanvasFontContext::new(), window_size.to_f32()); + let mut canvas = CanvasRenderingContext2D::new(CanvasFontContext::from_system_source(), + window_size.to_f32()); // Set line width. canvas.set_line_width(10.0); diff --git a/examples/canvas_moire/src/main.rs b/examples/canvas_moire/src/main.rs index 0ac8fffd..1f579b1e 100644 --- a/examples/canvas_moire/src/main.rs +++ b/examples/canvas_moire/src/main.rs @@ -100,7 +100,7 @@ impl MoireRenderer { -> MoireRenderer { MoireRenderer { renderer, - font_context: CanvasFontContext::new(), + font_context: CanvasFontContext::from_system_source(), scene: SceneProxy::new(RayonExecutor), frame: 0, window_size, diff --git a/examples/canvas_text/Cargo.toml b/examples/canvas_text/Cargo.toml index 174d4c96..720a0863 100644 --- a/examples/canvas_text/Cargo.toml +++ b/examples/canvas_text/Cargo.toml @@ -5,6 +5,7 @@ authors = ["Patrick Walton "] edition = "2018" [dependencies] +font-kit = "0.2" gl = "0.6" sdl2 = "0.32" sdl2-sys = "0.32" diff --git a/examples/canvas_text/src/main.rs b/examples/canvas_text/src/main.rs index de69fbe4..7d4b8385 100644 --- a/examples/canvas_text/src/main.rs +++ b/examples/canvas_text/src/main.rs @@ -8,11 +8,12 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use font_kit::handle::Handle; use pathfinder_canvas::{CanvasFontContext, CanvasRenderingContext2D, TextAlign}; use pathfinder_geometry::basic::vector::{Vector2F, Vector2I}; use pathfinder_geometry::color::ColorF; use pathfinder_gl::{GLDevice, GLVersion}; -use pathfinder_gpu::resources::FilesystemResourceLoader; +use pathfinder_gpu::resources::{FilesystemResourceLoader, ResourceLoader}; use pathfinder_renderer::concurrent::rayon::RayonExecutor; use pathfinder_renderer::concurrent::scene_proxy::SceneProxy; use pathfinder_renderer::gpu::options::{DestFramebuffer, RendererOptions}; @@ -21,6 +22,8 @@ use pathfinder_renderer::options::BuildOptions; use sdl2::event::Event; use sdl2::keyboard::Keycode; use sdl2::video::GLProfile; +use std::iter; +use std::sync::Arc; fn main() { // Set up SDL2. @@ -45,15 +48,22 @@ fn main() { window.gl_make_current(&gl_context).unwrap(); // Create a Pathfinder renderer. + let resource_loader = FilesystemResourceLoader::locate(); let mut renderer = Renderer::new(GLDevice::new(GLVersion::GL3, 0), - &FilesystemResourceLoader::locate(), + &resource_loader, DestFramebuffer::full_window(window_size), RendererOptions { background_color: Some(ColorF::white()) }); - // Make a canvas. We're going to draw some text. - let mut canvas = CanvasRenderingContext2D::new(CanvasFontContext::new(), window_size.to_f32()); + // Load a font. + let font_data = Arc::new(resource_loader.slurp("fonts/overpass-regular.otf").unwrap()); + let font = Handle::from_memory(font_data, 0); + let font_context = CanvasFontContext::from_fonts(iter::once(font)); + + // Make a canvas. + let mut canvas = CanvasRenderingContext2D::new(font_context, window_size.to_f32()); // Draw the text. + canvas.set_font_by_postscript_name("Overpass-Regular"); canvas.set_font_size(32.0); canvas.fill_text("Hello Pathfinder!", Vector2F::new(32.0, 48.0)); canvas.set_text_align(TextAlign::Right); diff --git a/text/Cargo.toml b/text/Cargo.toml index 352e801f..76985371 100644 --- a/text/Cargo.toml +++ b/text/Cargo.toml @@ -6,7 +6,7 @@ edition = "2018" [dependencies] euclid = "0.19" -font-kit = "0.1" +font-kit = "0.2" lyon_path = "0.12" [dependencies.pathfinder_geometry] @@ -17,4 +17,4 @@ path = "../renderer" [dependencies.skribo] git = "https://github.com/linebender/skribo.git" -rev = "a89e9ca99e0d6736ea1b7754517f4df14fd96a2b" +rev = "a2d683856ba1f2d0095b12dd7823d1602a87614e" From de0662e08e85d9b23a85f073303b925b9be15b36 Mon Sep 17 00:00:00 2001 From: Patrick Walton Date: Fri, 21 Jun 2019 07:24:06 -0700 Subject: [PATCH 17/26] Update `spirv-cross` to upstream master. A fix has been merged for the issue that was breaking Pathfinder, so we can now use the master branch. --- resources/shaders/gl3/reproject.vs.glsl | 1 + resources/shaders/metal/debug_texture.fs.metal | 6 +++--- resources/shaders/metal/post.fs.metal | 10 +++++----- resources/shaders/metal/tile_alpha_multicolor.vs.metal | 10 +++++----- resources/shaders/metal/tile_solid_multicolor.vs.metal | 8 ++++---- 5 files changed, 18 insertions(+), 17 deletions(-) diff --git a/resources/shaders/gl3/reproject.vs.glsl b/resources/shaders/gl3/reproject.vs.glsl index 35a3db40..f32005f2 100644 --- a/resources/shaders/gl3/reproject.vs.glsl +++ b/resources/shaders/gl3/reproject.vs.glsl @@ -27,6 +27,7 @@ void main(){ + gl_Position = uNewTransform * vec4(position, 0.0, 1.0); } diff --git a/resources/shaders/metal/debug_texture.fs.metal b/resources/shaders/metal/debug_texture.fs.metal index 9949a558..80a811f3 100644 --- a/resources/shaders/metal/debug_texture.fs.metal +++ b/resources/shaders/metal/debug_texture.fs.metal @@ -6,9 +6,9 @@ using namespace metal; struct spvDescriptorSetBuffer0 { - constant float4* uColor [[id(0)]]; - texture2d uTexture [[id(1)]]; - sampler uTextureSmplr [[id(2)]]; + texture2d uTexture [[id(0)]]; + sampler uTextureSmplr [[id(1)]]; + constant float4* uColor [[id(2)]]; }; struct main0_out diff --git a/resources/shaders/metal/post.fs.metal b/resources/shaders/metal/post.fs.metal index 989fd5d7..3c9502b4 100644 --- a/resources/shaders/metal/post.fs.metal +++ b/resources/shaders/metal/post.fs.metal @@ -8,12 +8,12 @@ using namespace metal; struct spvDescriptorSetBuffer0 { - constant float4* uKernel [[id(0)]]; - texture2d uGammaLUT [[id(1)]]; - texture2d uSource [[id(2)]]; - constant float2* uSourceSize [[id(3)]]; + texture2d uGammaLUT [[id(0)]]; + sampler uGammaLUTSmplr [[id(1)]]; + constant float4* uKernel [[id(2)]]; + texture2d uSource [[id(3)]]; sampler uSourceSmplr [[id(4)]]; - sampler uGammaLUTSmplr [[id(5)]]; + constant float2* uSourceSize [[id(5)]]; constant int* uGammaCorrectionEnabled [[id(6)]]; constant float4* uBGColor [[id(7)]]; constant float4* uFGColor [[id(8)]]; diff --git a/resources/shaders/metal/tile_alpha_multicolor.vs.metal b/resources/shaders/metal/tile_alpha_multicolor.vs.metal index bc25f729..7e62af78 100644 --- a/resources/shaders/metal/tile_alpha_multicolor.vs.metal +++ b/resources/shaders/metal/tile_alpha_multicolor.vs.metal @@ -9,11 +9,11 @@ using namespace metal; struct spvDescriptorSetBuffer0 { constant float2* uTileSize [[id(0)]]; - texture2d uPaintTexture [[id(1)]]; - constant float2* uViewBoxOrigin [[id(2)]]; - sampler uPaintTextureSmplr [[id(3)]]; - constant float2* uFramebufferSize [[id(4)]]; - constant float2* uStencilTextureSize [[id(5)]]; + constant float2* uViewBoxOrigin [[id(1)]]; + constant float2* uFramebufferSize [[id(2)]]; + constant float2* uStencilTextureSize [[id(3)]]; + texture2d uPaintTexture [[id(4)]]; + sampler uPaintTextureSmplr [[id(5)]]; }; struct main0_out diff --git a/resources/shaders/metal/tile_solid_multicolor.vs.metal b/resources/shaders/metal/tile_solid_multicolor.vs.metal index edfe17d0..573f5173 100644 --- a/resources/shaders/metal/tile_solid_multicolor.vs.metal +++ b/resources/shaders/metal/tile_solid_multicolor.vs.metal @@ -9,10 +9,10 @@ using namespace metal; struct spvDescriptorSetBuffer0 { constant float2* uTileSize [[id(0)]]; - texture2d uPaintTexture [[id(1)]]; - constant float2* uViewBoxOrigin [[id(2)]]; - sampler uPaintTextureSmplr [[id(3)]]; - constant float2* uFramebufferSize [[id(4)]]; + constant float2* uViewBoxOrigin [[id(1)]]; + constant float2* uFramebufferSize [[id(2)]]; + texture2d uPaintTexture [[id(3)]]; + sampler uPaintTextureSmplr [[id(4)]]; }; struct main0_out From 336f2ca30261edc00a88bfdba03595d7cd4087f6 Mon Sep 17 00:00:00 2001 From: Patrick Walton Date: Fri, 21 Jun 2019 09:28:15 -0700 Subject: [PATCH 18/26] Rename `pathfinder_flash` to `pathfinder_swf` for consistency with other crates in the Rust Flash ecosystem --- Cargo.lock | 26 +++++++++++++------------- Cargo.toml | 2 +- examples/swf_basic/Cargo.toml | 6 +++--- examples/swf_basic/src/main.rs | 2 +- {flash => swf}/Cargo.toml | 2 +- {flash => swf}/src/lib.rs | 2 +- {flash => swf}/src/shapes.rs | 10 ++++++++++ {flash => swf}/src/timeline.rs | 10 ++++++++++ 8 files changed, 40 insertions(+), 20 deletions(-) rename {flash => swf}/Cargo.toml (93%) rename {flash => swf}/src/lib.rs (99%) rename {flash => swf}/src/shapes.rs (98%) rename {flash => swf}/src/timeline.rs (59%) diff --git a/Cargo.lock b/Cargo.lock index ebab8efd..186eb4ef 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1416,18 +1416,6 @@ dependencies = [ "usvg 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "pathfinder_flash" -version = "0.1.0" -dependencies = [ - "pathfinder_geometry 0.3.0", - "pathfinder_gl 0.1.0", - "pathfinder_gpu 0.1.0", - "pathfinder_renderer 0.1.0", - "swf-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "swf-tree 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "pathfinder_geometry" version = "0.3.0" @@ -1547,6 +1535,18 @@ dependencies = [ "usvg 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "pathfinder_swf" +version = "0.1.0" +dependencies = [ + "pathfinder_geometry 0.3.0", + "pathfinder_gl 0.1.0", + "pathfinder_gpu 0.1.0", + "pathfinder_renderer 0.1.0", + "swf-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "swf-tree 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "pathfinder_text" version = "0.1.0" @@ -2127,11 +2127,11 @@ name = "swf_basic" version = "0.1.0" dependencies = [ "gl 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", - "pathfinder_flash 0.1.0", "pathfinder_geometry 0.3.0", "pathfinder_gl 0.1.0", "pathfinder_gpu 0.1.0", "pathfinder_renderer 0.1.0", + "pathfinder_swf 0.1.0", "sdl2 0.32.2 (registry+https://github.com/rust-lang/crates.io-index)", "sdl2-sys 0.32.6 (registry+https://github.com/rust-lang/crates.io-index)", "swf-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", diff --git a/Cargo.toml b/Cargo.toml index 305b8133..d11db85e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -16,12 +16,12 @@ members = [ "geometry", "gl", "gpu", - "flash", "lottie", "metal", "renderer", "simd", "svg", + "swf", "text", "ui", "utils/area-lut", diff --git a/examples/swf_basic/Cargo.toml b/examples/swf_basic/Cargo.toml index eb64fe17..ced4ed19 100644 --- a/examples/swf_basic/Cargo.toml +++ b/examples/swf_basic/Cargo.toml @@ -12,9 +12,6 @@ sdl2-sys = "0.32" swf-parser = "0.7.0" swf-tree = "0.7.0" -[dependencies.pathfinder_flash] -path = "../../flash" - [dependencies.pathfinder_geometry] path = "../../geometry" @@ -26,3 +23,6 @@ path = "../../gpu" [dependencies.pathfinder_renderer] path = "../../renderer" + +[dependencies.pathfinder_swf] +path = "../../swf" diff --git a/examples/swf_basic/src/main.rs b/examples/swf_basic/src/main.rs index ed5e9f9d..39959d99 100644 --- a/examples/swf_basic/src/main.rs +++ b/examples/swf_basic/src/main.rs @@ -21,7 +21,7 @@ use sdl2::event::Event; use sdl2::keyboard::Keycode; use sdl2::video::GLProfile; use pathfinder_renderer::scene::Scene; -use pathfinder_flash::{draw_paths_into_scene, process_swf_tags}; +use pathfinder_swf::{draw_paths_into_scene, process_swf_tags}; use std::env; use std::fs::read; use pathfinder_geometry::basic::transform2d::Transform2DF; diff --git a/flash/Cargo.toml b/swf/Cargo.toml similarity index 93% rename from flash/Cargo.toml rename to swf/Cargo.toml index 2dff909f..b063d864 100644 --- a/flash/Cargo.toml +++ b/swf/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "pathfinder_flash" +name = "pathfinder_swf" version = "0.1.0" authors = ["Jon Hardie "] edition = "2018" diff --git a/flash/src/lib.rs b/swf/src/lib.rs similarity index 99% rename from flash/src/lib.rs rename to swf/src/lib.rs index 34bf5518..94bf0e35 100644 --- a/flash/src/lib.rs +++ b/swf/src/lib.rs @@ -1,4 +1,4 @@ -// pathfinder/flash/src/lib.rs +// pathfinder/swf/src/lib.rs // // Copyright © 2019 The Pathfinder Project Developers. // diff --git a/flash/src/shapes.rs b/swf/src/shapes.rs similarity index 98% rename from flash/src/shapes.rs rename to swf/src/shapes.rs index 73d55603..b2c94936 100644 --- a/flash/src/shapes.rs +++ b/swf/src/shapes.rs @@ -1,3 +1,13 @@ +// pathfinder/swf/src/shapes.rs +// +// Copyright © 2019 The Pathfinder Project Developers. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + use pathfinder_renderer::paint::Paint; use pathfinder_geometry::stroke::{LineJoin, LineCap}; use crate::{Twips, Point2}; diff --git a/flash/src/timeline.rs b/swf/src/timeline.rs similarity index 59% rename from flash/src/timeline.rs rename to swf/src/timeline.rs index 662dba00..e3f684b3 100644 --- a/flash/src/timeline.rs +++ b/swf/src/timeline.rs @@ -1,3 +1,13 @@ +// pathfinder/swf/src/timeline.rs +// +// Copyright © 2019 The Pathfinder Project Developers. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + struct PlacementInfo { symbol_id: u32, translate_x: Twips, From b16300bf0266acabe165d25d4b7bc9da8c99c582 Mon Sep 17 00:00:00 2001 From: Patrick Walton Date: Fri, 21 Jun 2019 09:32:48 -0700 Subject: [PATCH 19/26] Move the SWF assets into `resources/`. --- examples/swf_basic/src/main.rs | 9 +++++---- .../swf_basic => resources}/swf/tiger-flat.swf | Bin {examples/swf_basic => resources}/swf/tiger.swf | Bin 3 files changed, 5 insertions(+), 4 deletions(-) rename {examples/swf_basic => resources}/swf/tiger-flat.swf (100%) rename {examples/swf_basic => resources}/swf/tiger.swf (100%) diff --git a/examples/swf_basic/src/main.rs b/examples/swf_basic/src/main.rs index 39959d99..a06d7f79 100644 --- a/examples/swf_basic/src/main.rs +++ b/examples/swf_basic/src/main.rs @@ -11,7 +11,7 @@ use pathfinder_geometry::basic::vector::{Vector2F, Vector2I}; use pathfinder_geometry::basic::rect::RectF; use pathfinder_gl::{GLDevice, GLVersion}; -use pathfinder_gpu::resources::FilesystemResourceLoader; +use pathfinder_gpu::resources::{FilesystemResourceLoader, ResourceLoader}; use pathfinder_renderer::concurrent::rayon::RayonExecutor; use pathfinder_renderer::concurrent::scene_proxy::SceneProxy; use pathfinder_renderer::gpu::renderer::Renderer; @@ -27,6 +27,8 @@ use std::fs::read; use pathfinder_geometry::basic::transform2d::Transform2DF; fn main() { + let resource_loader = FilesystemResourceLoader::locate(); + let swf_bytes; if let Some(path) = env::args().skip(1).next() { match read(path) { @@ -50,7 +52,6 @@ fn main() { // a lot more geometry. I think a more likely explanation for the choice is that it was // done to reduce overdraw in the software rasterizer running on late 90's era hardware? // Indeed, this mode gives pathfinders' occlusion culling pass nothing to do! - //let default_tiger = include_bytes!("../swf/tiger-flat.swf"); // NOTE(jon): This is a version of the same graphic cut and pasted into the Flash authoring // tool from the SVG version loaded in Illustrator. When layered graphics are pasted @@ -58,7 +59,7 @@ fn main() { // They are still presented as being on a single timeline layer. // They will be drawn back to front in much the same way as the SVG version. - let default_tiger = include_bytes!("../swf/tiger.swf"); + let default_tiger = resource_loader.slurp("swf/tiger.swf").unwrap(); swf_bytes = Vec::from(&default_tiger[..]); } @@ -100,7 +101,7 @@ fn main() { // Create a Pathfinder renderer. let mut renderer = Renderer::new( GLDevice::new(GLVersion::GL3, 0), - &FilesystemResourceLoader::locate(), + &resource_loader, DestFramebuffer::full_window(pixel_size), RendererOptions { background_color: Some(stage.background_color()) } ); diff --git a/examples/swf_basic/swf/tiger-flat.swf b/resources/swf/tiger-flat.swf similarity index 100% rename from examples/swf_basic/swf/tiger-flat.swf rename to resources/swf/tiger-flat.swf diff --git a/examples/swf_basic/swf/tiger.swf b/resources/swf/tiger.swf similarity index 100% rename from examples/swf_basic/swf/tiger.swf rename to resources/swf/tiger.swf From 431dcf3d2e884e5a241e65f68d1685963deb2d6f Mon Sep 17 00:00:00 2001 From: Patrick Walton Date: Fri, 21 Jun 2019 10:06:19 -0700 Subject: [PATCH 20/26] Rename `pathfinder_geometry::basic` to simply `pathfinder_geometry`, and move the remaining code in that crate to a new crate, `pathfinder_content` The old hierarchy was confusing. --- Cargo.lock | 32 ++++- Cargo.toml | 1 + c/Cargo.toml | 3 + c/src/lib.rs | 46 ++++--- canvas/Cargo.toml | 3 + canvas/src/lib.rs | 20 +-- content/Cargo.toml | 17 +++ {geometry => content}/src/clip.rs | 10 +- {geometry => content}/src/color.rs | 0 {geometry => content}/src/dash.rs | 0 {geometry => content}/src/dilation.rs | 4 +- .../src/basic/mod.rs => content/src/lib.rs | 26 +++- {geometry => content}/src/orientation.rs | 0 {geometry => content}/src/outline.rs | 14 +- {geometry => content}/src/segment.rs | 10 +- {geometry => content}/src/stroke.rs | 10 +- content/src/transform.rs | 124 ++++++++++++++++++ demo/android/rust/src/lib.rs | 4 +- demo/common/Cargo.toml | 3 + demo/common/src/camera.rs | 8 +- demo/common/src/lib.rs | 10 +- demo/common/src/renderer.rs | 8 +- demo/common/src/ui.rs | 4 +- demo/common/src/window.rs | 6 +- demo/magicleap/Cargo.toml | 3 + demo/magicleap/src/display.rs | 8 +- demo/magicleap/src/glwindow.rs | 8 +- demo/magicleap/src/immersive.rs | 14 +- demo/magicleap/src/lib.rs | 10 +- demo/magicleap/src/magicleap.rs | 12 +- demo/native/src/main.rs | 4 +- examples/canvas_glutin_minimal/Cargo.toml | 3 + examples/canvas_glutin_minimal/src/main.rs | 6 +- examples/canvas_metal_minimal/Cargo.toml | 3 + examples/canvas_metal_minimal/src/main.rs | 6 +- examples/canvas_minimal/Cargo.toml | 3 + examples/canvas_minimal/src/main.rs | 6 +- examples/canvas_moire/Cargo.toml | 3 + examples/canvas_moire/src/main.rs | 4 +- examples/canvas_text/Cargo.toml | 3 + examples/canvas_text/src/main.rs | 4 +- examples/swf_basic/src/main.rs | 6 +- geometry/Cargo.toml | 5 - geometry/src/lib.rs | 26 +--- geometry/src/{basic => }/line_segment.rs | 4 +- geometry/src/{basic => }/rect.rs | 2 +- geometry/src/{basic => }/transform2d.rs | 63 +-------- geometry/src/{basic => }/transform3d.rs | 66 +--------- geometry/src/unit_vector.rs | 2 +- geometry/src/{basic => }/vector.rs | 0 gl/src/lib.rs | 4 +- gpu/Cargo.toml | 3 + gpu/src/lib.rs | 8 +- metal/src/lib.rs | 4 +- renderer/Cargo.toml | 3 + renderer/src/builder.rs | 6 +- renderer/src/concurrent/scene_proxy.rs | 2 +- renderer/src/gpu/debug.rs | 4 +- renderer/src/gpu/options.rs | 6 +- renderer/src/gpu/renderer.rs | 8 +- renderer/src/gpu_data.rs | 6 +- renderer/src/options.rs | 10 +- renderer/src/paint.rs | 4 +- renderer/src/scene.rs | 10 +- renderer/src/tile_map.rs | 4 +- renderer/src/tiles.rs | 10 +- renderer/src/z_buffer.rs | 4 +- svg/Cargo.toml | 3 + svg/src/lib.rs | 17 +-- swf/Cargo.toml | 3 + swf/src/lib.rs | 8 +- swf/src/shapes.rs | 4 +- text/Cargo.toml | 3 + text/src/lib.rs | 8 +- ui/Cargo.toml | 3 + ui/src/lib.rs | 6 +- 76 files changed, 443 insertions(+), 345 deletions(-) create mode 100644 content/Cargo.toml rename {geometry => content}/src/clip.rs (98%) rename {geometry => content}/src/color.rs (100%) rename {geometry => content}/src/dash.rs (100%) rename {geometry => content}/src/dilation.rs (98%) rename geometry/src/basic/mod.rs => content/src/lib.rs (50%) rename {geometry => content}/src/orientation.rs (100%) rename {geometry => content}/src/outline.rs (98%) rename {geometry => content}/src/segment.rs (98%) rename {geometry => content}/src/stroke.rs (98%) create mode 100644 content/src/transform.rs rename geometry/src/{basic => }/line_segment.rs (98%) rename geometry/src/{basic => }/rect.rs (99%) rename geometry/src/{basic => }/transform2d.rs (82%) rename geometry/src/{basic => }/transform3d.rs (89%) rename geometry/src/{basic => }/vector.rs (100%) diff --git a/Cargo.lock b/Cargo.lock index 186eb4ef..1a5dc613 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -159,6 +159,7 @@ dependencies = [ "gl 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", "glutin 0.21.0 (registry+https://github.com/rust-lang/crates.io-index)", "pathfinder_canvas 0.1.0", + "pathfinder_content 0.1.0", "pathfinder_geometry 0.3.0", "pathfinder_gl 0.1.0", "pathfinder_gpu 0.1.0", @@ -174,6 +175,7 @@ dependencies = [ "metal 0.14.0 (registry+https://github.com/rust-lang/crates.io-index)", "objc 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", "pathfinder_canvas 0.1.0", + "pathfinder_content 0.1.0", "pathfinder_geometry 0.3.0", "pathfinder_gl 0.1.0", "pathfinder_gpu 0.1.0", @@ -189,6 +191,7 @@ version = "0.1.0" dependencies = [ "gl 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", "pathfinder_canvas 0.1.0", + "pathfinder_content 0.1.0", "pathfinder_geometry 0.3.0", "pathfinder_gl 0.1.0", "pathfinder_gpu 0.1.0", @@ -203,6 +206,7 @@ version = "0.1.0" dependencies = [ "gl 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", "pathfinder_canvas 0.1.0", + "pathfinder_content 0.1.0", "pathfinder_geometry 0.3.0", "pathfinder_gl 0.1.0", "pathfinder_gpu 0.1.0", @@ -218,6 +222,7 @@ dependencies = [ "font-kit 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "gl 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", "pathfinder_canvas 0.1.0", + "pathfinder_content 0.1.0", "pathfinder_geometry 0.3.0", "pathfinder_gl 0.1.0", "pathfinder_gpu 0.1.0", @@ -1377,6 +1382,7 @@ dependencies = [ "gl 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.54 (registry+https://github.com/rust-lang/crates.io-index)", "pathfinder_canvas 0.1.0", + "pathfinder_content 0.1.0", "pathfinder_geometry 0.3.0", "pathfinder_gl 0.1.0", "pathfinder_gpu 0.1.0", @@ -1389,12 +1395,25 @@ name = "pathfinder_canvas" version = "0.1.0" dependencies = [ "font-kit 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "pathfinder_content 0.1.0", "pathfinder_geometry 0.3.0", "pathfinder_renderer 0.1.0", "pathfinder_text 0.1.0", "skribo 0.0.1 (git+https://github.com/linebender/skribo.git?rev=a2d683856ba1f2d0095b12dd7823d1602a87614e)", ] +[[package]] +name = "pathfinder_content" +version = "0.1.0" +dependencies = [ + "arrayvec 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)", + "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", + "pathfinder_geometry 0.3.0", + "pathfinder_simd 0.3.0", + "smallvec 0.6.9 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "pathfinder_demo" version = "0.1.0" @@ -1404,6 +1423,7 @@ dependencies = [ "image 0.21.1 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "metal 0.14.0 (registry+https://github.com/rust-lang/crates.io-index)", + "pathfinder_content 0.1.0", "pathfinder_geometry 0.3.0", "pathfinder_gl 0.1.0", "pathfinder_gpu 0.1.0", @@ -1420,13 +1440,8 @@ dependencies = [ name = "pathfinder_geometry" version = "0.3.0" dependencies = [ - "arrayvec 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)", - "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "pathfinder_simd 0.3.0", - "serde 1.0.91 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.91 (registry+https://github.com/rust-lang/crates.io-index)", - "smallvec 0.6.9 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1447,6 +1462,7 @@ name = "pathfinder_gpu" version = "0.1.0" dependencies = [ "image 0.21.1 (registry+https://github.com/rust-lang/crates.io-index)", + "pathfinder_content 0.1.0", "pathfinder_geometry 0.3.0", "pathfinder_simd 0.3.0", ] @@ -1468,6 +1484,7 @@ dependencies = [ "gl 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", "glutin 0.19.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", + "pathfinder_content 0.1.0", "pathfinder_demo 0.1.0", "pathfinder_geometry 0.3.0", "pathfinder_gl 0.1.0", @@ -1507,6 +1524,7 @@ dependencies = [ "fixedbitset 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", "hashbrown 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", + "pathfinder_content 0.1.0", "pathfinder_geometry 0.3.0", "pathfinder_gpu 0.1.0", "pathfinder_simd 0.3.0", @@ -1530,6 +1548,7 @@ name = "pathfinder_svg" version = "0.1.0" dependencies = [ "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", + "pathfinder_content 0.1.0", "pathfinder_geometry 0.3.0", "pathfinder_renderer 0.1.0", "usvg 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1539,6 +1558,7 @@ dependencies = [ name = "pathfinder_swf" version = "0.1.0" dependencies = [ + "pathfinder_content 0.1.0", "pathfinder_geometry 0.3.0", "pathfinder_gl 0.1.0", "pathfinder_gpu 0.1.0", @@ -1554,6 +1574,7 @@ dependencies = [ "euclid 0.19.8 (registry+https://github.com/rust-lang/crates.io-index)", "font-kit 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "lyon_path 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)", + "pathfinder_content 0.1.0", "pathfinder_geometry 0.3.0", "pathfinder_renderer 0.1.0", "skribo 0.0.1 (git+https://github.com/linebender/skribo.git?rev=a2d683856ba1f2d0095b12dd7823d1602a87614e)", @@ -1564,6 +1585,7 @@ name = "pathfinder_ui" version = "0.1.0" dependencies = [ "hashbrown 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", + "pathfinder_content 0.1.0", "pathfinder_geometry 0.3.0", "pathfinder_gpu 0.1.0", "pathfinder_simd 0.3.0", diff --git a/Cargo.toml b/Cargo.toml index d11db85e..5d8e378e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -2,6 +2,7 @@ members = [ "c", "canvas", + "content", "demo/android/rust", "demo/common", "demo/magicleap", diff --git a/c/Cargo.toml b/c/Cargo.toml index ea2c8146..caad0fec 100644 --- a/c/Cargo.toml +++ b/c/Cargo.toml @@ -14,6 +14,9 @@ libc = "0.2" [dependencies.pathfinder_canvas] path = "../canvas" +[dependencies.pathfinder_content] +path = "../content" + [dependencies.pathfinder_geometry] path = "../geometry" diff --git a/c/src/lib.rs b/c/src/lib.rs index 219e43bd..9823f7d1 100644 --- a/c/src/lib.rs +++ b/c/src/lib.rs @@ -13,11 +13,11 @@ use gl; use pathfinder_canvas::{CanvasFontContext, CanvasRenderingContext2D, FillStyle, LineJoin}; use pathfinder_canvas::{Path2D, TextMetrics}; -use pathfinder_geometry::basic::rect::{RectF, RectI}; -use pathfinder_geometry::basic::vector::{Vector2F, Vector2I}; -use pathfinder_geometry::color::{ColorF, ColorU}; -use pathfinder_geometry::outline::ArcDirection; -use pathfinder_geometry::stroke::LineCap; +use pathfinder_content::color::{ColorF, ColorU}; +use pathfinder_content::outline::ArcDirection; +use pathfinder_content::stroke::LineCap; +use pathfinder_geometry::rect::{RectF, RectI}; +use pathfinder_geometry::vector::{Vector2F, Vector2I}; use pathfinder_gl::{GLDevice, GLVersion}; use pathfinder_gpu::resources::{FilesystemResourceLoader, ResourceLoader}; use pathfinder_renderer::concurrent::rayon::RayonExecutor; @@ -44,7 +44,7 @@ pub const PF_LINE_JOIN_MITER: u8 = 0; pub const PF_LINE_JOIN_BEVEL: u8 = 1; pub const PF_LINE_JOIN_ROUND: u8 = 2; -// `geometry` +// `content` pub const PF_ARC_DIRECTION_CW: u8 = 0; pub const PF_ARC_DIRECTION_CCW: u8 = 1; @@ -68,6 +68,22 @@ pub struct PFTextMetrics { pub width: f32, } +// `content` +#[repr(C)] +pub struct PFColorF { + pub r: f32, + pub g: f32, + pub b: f32, + pub a: f32, +} +#[repr(C)] +pub struct PFColorU { + pub r: u8, + pub g: u8, + pub b: u8, + pub a: u8, +} + // `geometry` #[repr(C)] pub struct PFVector2F { @@ -89,20 +105,6 @@ pub struct PFRectI { pub origin: PFVector2I, pub lower_right: PFVector2I, } -#[repr(C)] -pub struct PFColorF { - pub r: f32, - pub g: f32, - pub b: f32, - pub a: f32, -} -#[repr(C)] -pub struct PFColorU { - pub r: u8, - pub g: u8, - pub b: u8, - pub a: u8, -} // `gl` pub type PFGLDeviceRef = *mut GLDevice; @@ -472,7 +474,7 @@ impl TextMetricsExt for TextMetrics { } } -// Helpers for `geometry` +// Helpers for `content` impl PFColorF { #[inline] @@ -488,6 +490,8 @@ impl PFColorU { } } +// Helpers for `geometry` + impl PFRectF { #[inline] pub fn to_rust(&self) -> RectF { diff --git a/canvas/Cargo.toml b/canvas/Cargo.toml index 1c620859..fb4f8037 100644 --- a/canvas/Cargo.toml +++ b/canvas/Cargo.toml @@ -10,6 +10,9 @@ crate-type = ["rlib", "staticlib"] [dependencies] font-kit = "0.2" +[dependencies.pathfinder_content] +path = "../content" + [dependencies.pathfinder_geometry] path = "../geometry" diff --git a/canvas/src/lib.rs b/canvas/src/lib.rs index 9f710dd0..581ca48a 100644 --- a/canvas/src/lib.rs +++ b/canvas/src/lib.rs @@ -17,15 +17,15 @@ use font_kit::loaders::default::Font; use font_kit::properties::Properties; use font_kit::source::{Source, SystemSource}; use font_kit::sources::mem::MemSource; -use pathfinder_geometry::basic::line_segment::LineSegment2F; -use pathfinder_geometry::basic::vector::Vector2F; -use pathfinder_geometry::basic::rect::RectF; -use pathfinder_geometry::basic::transform2d::Transform2DF; -use pathfinder_geometry::color::ColorU; -use pathfinder_geometry::dash::OutlineDash; -use pathfinder_geometry::outline::{ArcDirection, Contour, Outline}; -use pathfinder_geometry::stroke::{LineCap, LineJoin as StrokeLineJoin}; -use pathfinder_geometry::stroke::{OutlineStrokeToFill, StrokeStyle}; +use pathfinder_content::color::ColorU; +use pathfinder_content::dash::OutlineDash; +use pathfinder_content::outline::{ArcDirection, Contour, Outline}; +use pathfinder_content::stroke::{LineCap, LineJoin as StrokeLineJoin}; +use pathfinder_content::stroke::{OutlineStrokeToFill, StrokeStyle}; +use pathfinder_geometry::line_segment::LineSegment2F; +use pathfinder_geometry::vector::Vector2F; +use pathfinder_geometry::rect::RectF; +use pathfinder_geometry::transform2d::Transform2DF; use pathfinder_renderer::paint::{Paint, PaintId}; use pathfinder_renderer::scene::{PathObject, Scene}; use pathfinder_text::{SceneExt, TextRenderMode}; @@ -526,7 +526,7 @@ pub enum TextAlign { Center, } -// We duplicate `pathfinder_geometry::stroke::LineJoin` here because the HTML canvas API treats the +// We duplicate `pathfinder_content::stroke::LineJoin` here because the HTML canvas API treats the // miter limit as part of the canvas state, while the native Pathfinder API treats the miter limit // as part of the line join. Pathfinder's choice is more logical, because the miter limit is // specific to miter joins. In this API, however, for compatibility we go with the HTML canvas diff --git a/content/Cargo.toml b/content/Cargo.toml new file mode 100644 index 00000000..cdd7b473 --- /dev/null +++ b/content/Cargo.toml @@ -0,0 +1,17 @@ +[package] +name = "pathfinder_content" +version = "0.1.0" +authors = ["Patrick Walton "] +edition = "2018" + +[dependencies] +arrayvec = "0.4" +bitflags = "1.0" +log = "0.4" +smallvec = "0.6" + +[dependencies.pathfinder_geometry] +path = "../geometry" + +[dependencies.pathfinder_simd] +path = "../simd" diff --git a/geometry/src/clip.rs b/content/src/clip.rs similarity index 98% rename from geometry/src/clip.rs rename to content/src/clip.rs index 4569a68d..b4620ba5 100644 --- a/geometry/src/clip.rs +++ b/content/src/clip.rs @@ -1,4 +1,4 @@ -// pathfinder/geometry/src/clip.rs +// pathfinder/content/src/clip.rs // // Copyright © 2019 The Pathfinder Project Developers. // @@ -8,13 +8,13 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use crate::basic::line_segment::LineSegment2F; -use crate::basic::vector::{Vector2F, Vector4F}; -use crate::basic::rect::RectF; use crate::outline::{Contour, PointFlags, PushSegmentFlags}; use crate::segment::{CubicSegment, Segment}; -use crate::util::lerp; use arrayvec::ArrayVec; +use pathfinder_geometry::line_segment::LineSegment2F; +use pathfinder_geometry::rect::RectF; +use pathfinder_geometry::util::lerp; +use pathfinder_geometry::vector::{Vector2F, Vector4F}; use smallvec::SmallVec; use std::fmt::Debug; use std::mem; diff --git a/geometry/src/color.rs b/content/src/color.rs similarity index 100% rename from geometry/src/color.rs rename to content/src/color.rs diff --git a/geometry/src/dash.rs b/content/src/dash.rs similarity index 100% rename from geometry/src/dash.rs rename to content/src/dash.rs diff --git a/geometry/src/dilation.rs b/content/src/dilation.rs similarity index 98% rename from geometry/src/dilation.rs rename to content/src/dilation.rs index 4441c90b..40a1c729 100644 --- a/geometry/src/dilation.rs +++ b/content/src/dilation.rs @@ -1,4 +1,4 @@ -// pathfinder/geometry/src/dilation.rs +// pathfinder/content/src/dilation.rs // // Copyright © 2019 The Pathfinder Project Developers. // @@ -8,9 +8,9 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use crate::basic::vector::Vector2F; use crate::orientation::Orientation; use crate::outline::Contour; +use pathfinder_geometry::vector::Vector2F; pub struct ContourDilator<'a> { contour: &'a mut Contour, diff --git a/geometry/src/basic/mod.rs b/content/src/lib.rs similarity index 50% rename from geometry/src/basic/mod.rs rename to content/src/lib.rs index d77c1fc0..00abb4d1 100644 --- a/geometry/src/basic/mod.rs +++ b/content/src/lib.rs @@ -1,4 +1,4 @@ -// pathfinder/geometry/src/basic/mod.rs +// pathfinder/content/src/lib.rs // // Copyright © 2019 The Pathfinder Project Developers. // @@ -8,10 +8,22 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -//! Basic geometry and linear algebra primitives, optimized with SIMD. +//! Pathfinder's representation of a vector scene. +//! +//! This module also contains various path utilities. -pub mod line_segment; -pub mod rect; -pub mod transform2d; -pub mod transform3d; -pub mod vector; +#[macro_use] +extern crate bitflags; +#[macro_use] +extern crate log; + +pub mod clip; +pub mod color; +pub mod dash; +pub mod orientation; +pub mod outline; +pub mod segment; +pub mod stroke; +pub mod transform; + +mod dilation; diff --git a/geometry/src/orientation.rs b/content/src/orientation.rs similarity index 100% rename from geometry/src/orientation.rs rename to content/src/orientation.rs diff --git a/geometry/src/outline.rs b/content/src/outline.rs similarity index 98% rename from geometry/src/outline.rs rename to content/src/outline.rs index 5858941c..b09cc668 100644 --- a/geometry/src/outline.rs +++ b/content/src/outline.rs @@ -1,4 +1,4 @@ -// pathfinder/geometry/src/outline.rs +// pathfinder/content/src/outline.rs // // Copyright © 2019 The Pathfinder Project Developers. // @@ -10,16 +10,16 @@ //! A compressed in-memory representation of paths. -use crate::basic::line_segment::LineSegment2F; -use crate::basic::vector::Vector2F; -use crate::basic::rect::RectF; -use crate::basic::transform2d::Transform2DF; -use crate::basic::transform3d::Perspective; use crate::clip::{self, ContourPolygonClipper, ContourRectClipper}; use crate::dilation::ContourDilator; use crate::orientation::Orientation; use crate::segment::{Segment, SegmentFlags, SegmentKind}; -use crate::unit_vector::UnitVector; +use pathfinder_geometry::line_segment::LineSegment2F; +use pathfinder_geometry::rect::RectF; +use pathfinder_geometry::transform2d::Transform2DF; +use pathfinder_geometry::transform3d::Perspective; +use pathfinder_geometry::unit_vector::UnitVector; +use pathfinder_geometry::vector::Vector2F; use std::f32::consts::PI; use std::fmt::{self, Debug, Formatter}; use std::mem; diff --git a/geometry/src/segment.rs b/content/src/segment.rs similarity index 98% rename from geometry/src/segment.rs rename to content/src/segment.rs index 2cd8adf4..4a9d6a76 100644 --- a/geometry/src/segment.rs +++ b/content/src/segment.rs @@ -1,4 +1,4 @@ -// pathfinder/geometry/src/segment.rs +// pathfinder/content/src/segment.rs // // Copyright © 2019 The Pathfinder Project Developers. // @@ -10,10 +10,10 @@ //! Line or curve segments, optimized with SIMD. -use crate::basic::line_segment::LineSegment2F; -use crate::basic::vector::Vector2F; -use crate::basic::transform2d::Transform2DF; -use crate::util::{self, EPSILON}; +use pathfinder_geometry::line_segment::LineSegment2F; +use pathfinder_geometry::transform2d::Transform2DF; +use pathfinder_geometry::util::{self, EPSILON}; +use pathfinder_geometry::vector::Vector2F; use pathfinder_simd::default::F32x4; use std::f32::consts::SQRT_2; diff --git a/geometry/src/stroke.rs b/content/src/stroke.rs similarity index 98% rename from geometry/src/stroke.rs rename to content/src/stroke.rs index 4e9a195a..48f68276 100644 --- a/geometry/src/stroke.rs +++ b/content/src/stroke.rs @@ -1,4 +1,4 @@ -// pathfinder/geometry/src/stroke.rs +// pathfinder/content/src/stroke.rs // // Copyright © 2019 The Pathfinder Project Developers. // @@ -10,12 +10,12 @@ //! Utilities for converting path strokes to fills. -use crate::basic::line_segment::LineSegment2F; -use crate::basic::vector::Vector2F; -use crate::basic::rect::RectF; -use crate::basic::transform2d::Transform2DF; use crate::outline::{ArcDirection, Contour, Outline, PushSegmentFlags}; use crate::segment::Segment; +use pathfinder_geometry::line_segment::LineSegment2F; +use pathfinder_geometry::rect::RectF; +use pathfinder_geometry::transform2d::Transform2DF; +use pathfinder_geometry::vector::Vector2F; use std::f32; const TOLERANCE: f32 = 0.01; diff --git a/content/src/transform.rs b/content/src/transform.rs new file mode 100644 index 00000000..283b4386 --- /dev/null +++ b/content/src/transform.rs @@ -0,0 +1,124 @@ +// pathfinder/content/src/transform.rs +// +// Copyright © 2019 The Pathfinder Project Developers. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Utilities for transforming paths. + +use crate::segment::Segment; +use pathfinder_geometry::transform2d::Transform2DF; +use pathfinder_geometry::transform3d::Perspective; + +/// Transforms a path with a SIMD 2D transform. +pub struct Transform2DFPathIter +where + I: Iterator, +{ + iter: I, + transform: Transform2DF, +} + +impl Iterator for Transform2DFPathIter +where + I: Iterator, +{ + type Item = Segment; + + #[inline] + fn next(&mut self) -> Option { + // TODO(pcwalton): Can we go faster by transforming an entire line segment with SIMD? + let mut segment = self.iter.next()?; + if !segment.is_none() { + segment + .baseline + .set_from(&self.transform.transform_point(segment.baseline.from())); + segment + .baseline + .set_to(&self.transform.transform_point(segment.baseline.to())); + if !segment.is_line() { + segment + .ctrl + .set_from(&self.transform.transform_point(segment.ctrl.from())); + if !segment.is_quadratic() { + segment + .ctrl + .set_to(&self.transform.transform_point(segment.ctrl.to())); + } + } + } + Some(segment) + } +} + +impl Transform2DFPathIter +where + I: Iterator, +{ + #[inline] + pub fn new(iter: I, transform: &Transform2DF) -> Transform2DFPathIter { + Transform2DFPathIter { + iter, + transform: *transform, + } + } +} + +/// Transforms a path with a perspective projection. +pub struct PerspectivePathIter +where + I: Iterator, +{ + iter: I, + perspective: Perspective, +} + +impl Iterator for PerspectivePathIter +where + I: Iterator, +{ + type Item = Segment; + + #[inline] + fn next(&mut self) -> Option { + let mut segment = self.iter.next()?; + if !segment.is_none() { + segment.baseline.set_from( + &self + .perspective + .transform_point_2d(&segment.baseline.from()), + ); + segment + .baseline + .set_to(&self.perspective.transform_point_2d(&segment.baseline.to())); + if !segment.is_line() { + segment + .ctrl + .set_from(&self.perspective.transform_point_2d(&segment.ctrl.from())); + if !segment.is_quadratic() { + segment + .ctrl + .set_to(&self.perspective.transform_point_2d(&segment.ctrl.to())); + } + } + } + Some(segment) + } +} + +impl PerspectivePathIter +where + I: Iterator, +{ + #[inline] + pub fn new(iter: I, perspective: &Perspective) -> PerspectivePathIter { + PerspectivePathIter { + iter, + perspective: *perspective, + } + } +} diff --git a/demo/android/rust/src/lib.rs b/demo/android/rust/src/lib.rs index 6e322418..4fdf1fa7 100644 --- a/demo/android/rust/src/lib.rs +++ b/demo/android/rust/src/lib.rs @@ -16,8 +16,8 @@ use jni::{JNIEnv, JavaVM}; use pathfinder_demo::window::{Event, SVGPath, View, Window, WindowSize}; use pathfinder_demo::DemoApp; use pathfinder_demo::Options; -use pathfinder_geometry::basic::vector::Vector2I; -use pathfinder_geometry::basic::rect::RectI; +use pathfinder_geometry::vector::Vector2I; +use pathfinder_geometry::rect::RectI; use pathfinder_gl::GLVersion; use pathfinder_gpu::resources::ResourceLoader; use std::cell::RefCell; diff --git a/demo/common/Cargo.toml b/demo/common/Cargo.toml index 45ea0798..b6aa30e5 100644 --- a/demo/common/Cargo.toml +++ b/demo/common/Cargo.toml @@ -22,6 +22,9 @@ features = ["png_codec"] version = "0.4" features = ["release_max_level_warn"] +[dependencies.pathfinder_content] +path = "../../content" + [dependencies.pathfinder_geometry] path = "../../geometry" diff --git a/demo/common/src/camera.rs b/demo/common/src/camera.rs index f8dc6445..eea0649e 100644 --- a/demo/common/src/camera.rs +++ b/demo/common/src/camera.rs @@ -14,10 +14,10 @@ // proper. use crate::window::{OcularTransform, View}; -use pathfinder_geometry::basic::vector::{Vector2F, Vector2I, Vector4F}; -use pathfinder_geometry::basic::rect::RectF; -use pathfinder_geometry::basic::transform2d::Transform2DF; -use pathfinder_geometry::basic::transform3d::{Perspective, Transform3DF}; +use pathfinder_geometry::vector::{Vector2F, Vector2I, Vector4F}; +use pathfinder_geometry::rect::RectF; +use pathfinder_geometry::transform2d::Transform2DF; +use pathfinder_geometry::transform3d::{Perspective, Transform3DF}; use std::f32::consts::FRAC_PI_4; const NEAR_CLIP_PLANE: f32 = 0.01; diff --git a/demo/common/src/lib.rs b/demo/common/src/lib.rs index 76c5a964..e97231b2 100644 --- a/demo/common/src/lib.rs +++ b/demo/common/src/lib.rs @@ -22,11 +22,11 @@ use crate::device::{GroundProgram, GroundVertexArray}; use crate::ui::{DemoUIModel, DemoUIPresenter, ScreenshotInfo, ScreenshotType, UIAction}; use crate::window::{Event, Keycode, SVGPath, Window, WindowSize}; use clap::{App, Arg}; -use pathfinder_geometry::basic::vector::{Vector2F, Vector2I}; -use pathfinder_geometry::basic::rect::RectF; -use pathfinder_geometry::basic::transform2d::Transform2DF; -use pathfinder_geometry::basic::transform3d::Transform3DF; -use pathfinder_geometry::color::ColorU; +use pathfinder_geometry::vector::{Vector2F, Vector2I}; +use pathfinder_geometry::rect::RectF; +use pathfinder_geometry::transform2d::Transform2DF; +use pathfinder_geometry::transform3d::Transform3DF; +use pathfinder_content::color::ColorU; use pathfinder_gpu::resources::ResourceLoader; use pathfinder_gpu::Device; use pathfinder_renderer::concurrent::scene_proxy::{RenderCommandStream, SceneProxy}; diff --git a/demo/common/src/renderer.rs b/demo/common/src/renderer.rs index fb42869d..c4bc0cc3 100644 --- a/demo/common/src/renderer.rs +++ b/demo/common/src/renderer.rs @@ -14,12 +14,12 @@ use crate::camera::{Camera, Mode}; use crate::window::{View, Window}; use crate::{BackgroundColor, DemoApp, UIVisibility}; use image::ColorType; -use pathfinder_geometry::color::{ColorF, ColorU}; +use pathfinder_content::color::{ColorF, ColorU}; use pathfinder_gpu::{ClearOps, DepthFunc, DepthState, Device, Primitive, RenderOptions}; use pathfinder_gpu::{RenderState, RenderTarget, TextureData, TextureFormat, UniformData}; -use pathfinder_geometry::basic::rect::RectI; -use pathfinder_geometry::basic::transform3d::Transform3DF; -use pathfinder_geometry::basic::vector::Vector2I; +use pathfinder_geometry::rect::RectI; +use pathfinder_geometry::transform3d::Transform3DF; +use pathfinder_geometry::vector::Vector2I; use pathfinder_renderer::gpu::options::{DestFramebuffer, RendererOptions}; use pathfinder_renderer::gpu::renderer::RenderMode; use pathfinder_renderer::gpu_data::RenderCommand; diff --git a/demo/common/src/ui.rs b/demo/common/src/ui.rs index 270893c5..2c7c8c5e 100644 --- a/demo/common/src/ui.rs +++ b/demo/common/src/ui.rs @@ -11,8 +11,8 @@ use crate::camera::Mode; use crate::window::Window; use crate::{BackgroundColor, Options}; -use pathfinder_geometry::basic::vector::Vector2I; -use pathfinder_geometry::basic::rect::RectI; +use pathfinder_geometry::vector::Vector2I; +use pathfinder_geometry::rect::RectI; use pathfinder_gpu::resources::ResourceLoader; use pathfinder_gpu::Device; use pathfinder_renderer::gpu::debug::DebugUIPresenter; diff --git a/demo/common/src/window.rs b/demo/common/src/window.rs index d8fc0019..edacf767 100644 --- a/demo/common/src/window.rs +++ b/demo/common/src/window.rs @@ -10,9 +10,9 @@ //! A minimal cross-platform windowing layer. -use pathfinder_geometry::basic::vector::Vector2I; -use pathfinder_geometry::basic::rect::RectI; -use pathfinder_geometry::basic::transform3d::{Perspective, Transform3DF}; +use pathfinder_geometry::vector::Vector2I; +use pathfinder_geometry::rect::RectI; +use pathfinder_geometry::transform3d::{Perspective, Transform3DF}; use pathfinder_gpu::resources::ResourceLoader; use rayon::ThreadPoolBuilder; use std::path::PathBuf; diff --git a/demo/magicleap/Cargo.toml b/demo/magicleap/Cargo.toml index efba31a8..6e7e8ff0 100644 --- a/demo/magicleap/Cargo.toml +++ b/demo/magicleap/Cargo.toml @@ -20,6 +20,9 @@ crate-type = ["cdylib"] [features] mocked = ["glutin"] +[dependencies.pathfinder_content] +path = "../../content" + [dependencies.pathfinder_demo] path = "../common" diff --git a/demo/magicleap/src/display.rs b/demo/magicleap/src/display.rs index 6a0f94ba..2176e43d 100644 --- a/demo/magicleap/src/display.rs +++ b/demo/magicleap/src/display.rs @@ -10,10 +10,10 @@ use std::error::Error; use std::io; -use pathfinder_geometry::basic::point::Point2DI32; -use pathfinder_geometry::basic::rect::RectI32; -use pathfinder_geometry::basic::transform3d::Perspective; -use pathfinder_geometry::basic::transform3d::Transform3DF32; +use pathfinder_geometry::point::Point2DI32; +use pathfinder_geometry::rect::RectI32; +use pathfinder_geometry::transform3d::Perspective; +use pathfinder_geometry::transform3d::Transform3DF32; use pathfinder_gl::GLVersion; use pathfinder_gpu::resources::ResourceLoader; diff --git a/demo/magicleap/src/glwindow.rs b/demo/magicleap/src/glwindow.rs index bd90d08e..50005428 100644 --- a/demo/magicleap/src/glwindow.rs +++ b/demo/magicleap/src/glwindow.rs @@ -25,10 +25,10 @@ use crate::display::Display; use crate::display::DisplayCamera; use crate::display::DisplayError; -use pathfinder_geometry::basic::point::Point2DI32; -use pathfinder_geometry::basic::rect::RectI32; -use pathfinder_geometry::basic::transform3d::Transform3DF32; -use pathfinder_geometry::basic::transform3d::Perspective; +use pathfinder_geometry::point::Point2DI32; +use pathfinder_geometry::rect::RectI32; +use pathfinder_geometry::transform3d::Transform3DF32; +use pathfinder_geometry::transform3d::Perspective; use pathfinder_gl::GLVersion; use pathfinder_gpu::resources::FilesystemResourceLoader; use pathfinder_gpu::resources::ResourceLoader; diff --git a/demo/magicleap/src/immersive.rs b/demo/magicleap/src/immersive.rs index 775a0b37..b01741ce 100644 --- a/demo/magicleap/src/immersive.rs +++ b/demo/magicleap/src/immersive.rs @@ -15,13 +15,13 @@ use pathfinder_demo::Camera; use pathfinder_demo::CameraTransform3D; use pathfinder_gl::GLDevice; use pathfinder_renderer::gpu::renderer::Renderer; -use pathfinder_geometry::basic::point::Point2DI32; -use pathfinder_geometry::basic::point::Point2DF32; -use pathfinder_geometry::basic::point::Point3DF32; -use pathfinder_geometry::basic::rect::RectI32; -use pathfinder_geometry::basic::transform2d::Transform2DF32; -use pathfinder_geometry::basic::transform3d::Transform3DF32; -use pathfinder_geometry::basic::transform3d::Perspective; +use pathfinder_geometry::point::Point2DI32; +use pathfinder_geometry::point::Point2DF32; +use pathfinder_geometry::point::Point3DF32; +use pathfinder_geometry::rect::RectI32; +use pathfinder_geometry::transform2d::Transform2DF32; +use pathfinder_geometry::transform3d::Transform3DF32; +use pathfinder_geometry::transform3d::Perspective; use pathfinder_gpu::Device; use pathfinder_simd::default::F32x4; use pathfinder_svg::BuiltSVG; diff --git a/demo/magicleap/src/lib.rs b/demo/magicleap/src/lib.rs index 632023c0..5530e4ab 100644 --- a/demo/magicleap/src/lib.rs +++ b/demo/magicleap/src/lib.rs @@ -29,11 +29,11 @@ use pathfinder_demo::BackgroundColor; use pathfinder_demo::Mode; use pathfinder_demo::window::Event; use pathfinder_demo::window::SVGPath; -use pathfinder_geometry::basic::vector::Vector2F; -use pathfinder_geometry::basic::vector::Vector2I; -use pathfinder_geometry::basic::rect::RectI; -use pathfinder_geometry::basic::transform2d::Transform2DF; -use pathfinder_geometry::color::ColorF; +use pathfinder_geometry::vector::Vector2F; +use pathfinder_geometry::vector::Vector2I; +use pathfinder_geometry::rect::RectI; +use pathfinder_geometry::transform2d::Transform2DF; +use pathfinder_content::color::ColorF; use pathfinder_gl::GLDevice; use pathfinder_gl::GLVersion; use pathfinder_gpu::ClearParams; diff --git a/demo/magicleap/src/magicleap.rs b/demo/magicleap/src/magicleap.rs index 1790c4a3..29c74df9 100644 --- a/demo/magicleap/src/magicleap.rs +++ b/demo/magicleap/src/magicleap.rs @@ -48,12 +48,12 @@ use pathfinder_demo::window::OcularTransform; use pathfinder_demo::window::View; use pathfinder_demo::window::Window; use pathfinder_demo::window::WindowSize; -use pathfinder_geometry::basic::vector::Vector2I; -use pathfinder_geometry::basic::vector::Vector2F; -use pathfinder_geometry::basic::rect::RectF; -use pathfinder_geometry::basic::rect::RectI; -use pathfinder_geometry::basic::transform3d::Perspective; -use pathfinder_geometry::basic::transform3d::Transform3DF; +use pathfinder_geometry::vector::Vector2I; +use pathfinder_geometry::vector::Vector2F; +use pathfinder_geometry::rect::RectF; +use pathfinder_geometry::rect::RectI; +use pathfinder_geometry::transform3d::Perspective; +use pathfinder_geometry::transform3d::Transform3DF; use pathfinder_geometry::util; use pathfinder_gl::GLVersion; use pathfinder_gpu::resources::FilesystemResourceLoader; diff --git a/demo/native/src/main.rs b/demo/native/src/main.rs index 78636e4c..29069ae1 100644 --- a/demo/native/src/main.rs +++ b/demo/native/src/main.rs @@ -13,8 +13,8 @@ use nfd::Response; use pathfinder_demo::window::{Event, Keycode, SVGPath, View, Window, WindowSize}; use pathfinder_demo::{DemoApp, Options}; -use pathfinder_geometry::basic::vector::Vector2I; -use pathfinder_geometry::basic::rect::RectI; +use pathfinder_geometry::vector::Vector2I; +use pathfinder_geometry::rect::RectI; use pathfinder_gpu::resources::{FilesystemResourceLoader, ResourceLoader}; use sdl2::event::{Event as SDLEvent, WindowEvent}; use sdl2::keyboard::Keycode as SDLKeycode; diff --git a/examples/canvas_glutin_minimal/Cargo.toml b/examples/canvas_glutin_minimal/Cargo.toml index 37b25e22..2b1a6bb3 100644 --- a/examples/canvas_glutin_minimal/Cargo.toml +++ b/examples/canvas_glutin_minimal/Cargo.toml @@ -11,6 +11,9 @@ glutin = "0.21" [dependencies.pathfinder_canvas] path = "../../canvas" +[dependencies.pathfinder_content] +path = "../../content" + [dependencies.pathfinder_geometry] path = "../../geometry" diff --git a/examples/canvas_glutin_minimal/src/main.rs b/examples/canvas_glutin_minimal/src/main.rs index 9b8662c0..597f7e27 100644 --- a/examples/canvas_glutin_minimal/src/main.rs +++ b/examples/canvas_glutin_minimal/src/main.rs @@ -14,9 +14,9 @@ use glutin::dpi::PhysicalSize; use glutin::{ContextBuilder, ControlFlow, Event, EventsLoop, GlProfile, GlRequest, KeyboardInput}; use glutin::{VirtualKeyCode, WindowBuilder, WindowEvent}; use pathfinder_canvas::{CanvasFontContext, CanvasRenderingContext2D, Path2D}; -use pathfinder_geometry::basic::vector::{Vector2F, Vector2I}; -use pathfinder_geometry::basic::rect::RectF; -use pathfinder_geometry::color::ColorF; +use pathfinder_content::color::ColorF; +use pathfinder_geometry::vector::{Vector2F, Vector2I}; +use pathfinder_geometry::rect::RectF; use pathfinder_gl::{GLDevice, GLVersion}; use pathfinder_gpu::resources::FilesystemResourceLoader; use pathfinder_renderer::concurrent::rayon::RayonExecutor; diff --git a/examples/canvas_metal_minimal/Cargo.toml b/examples/canvas_metal_minimal/Cargo.toml index 41673409..74cfde80 100644 --- a/examples/canvas_metal_minimal/Cargo.toml +++ b/examples/canvas_metal_minimal/Cargo.toml @@ -15,6 +15,9 @@ sdl2-sys = "0.32" [dependencies.pathfinder_canvas] path = "../../canvas" +[dependencies.pathfinder_content] +path = "../../content" + [dependencies.pathfinder_geometry] path = "../../geometry" diff --git a/examples/canvas_metal_minimal/src/main.rs b/examples/canvas_metal_minimal/src/main.rs index 8d8417ad..2b0b6b06 100644 --- a/examples/canvas_metal_minimal/src/main.rs +++ b/examples/canvas_metal_minimal/src/main.rs @@ -11,9 +11,9 @@ use foreign_types::ForeignTypeRef; use metal::{CAMetalLayer, CoreAnimationLayerRef}; use pathfinder_canvas::{CanvasFontContext, CanvasRenderingContext2D, Path2D}; -use pathfinder_geometry::basic::vector::{Vector2F, Vector2I}; -use pathfinder_geometry::basic::rect::RectF; -use pathfinder_geometry::color::ColorF; +use pathfinder_content::color::ColorF; +use pathfinder_geometry::vector::{Vector2F, Vector2I}; +use pathfinder_geometry::rect::RectF; use pathfinder_gpu::resources::FilesystemResourceLoader; use pathfinder_metal::MetalDevice; use pathfinder_renderer::concurrent::rayon::RayonExecutor; diff --git a/examples/canvas_minimal/Cargo.toml b/examples/canvas_minimal/Cargo.toml index ccd2fe25..0becc032 100644 --- a/examples/canvas_minimal/Cargo.toml +++ b/examples/canvas_minimal/Cargo.toml @@ -12,6 +12,9 @@ sdl2-sys = "0.32" [dependencies.pathfinder_canvas] path = "../../canvas" +[dependencies.pathfinder_content] +path = "../../content" + [dependencies.pathfinder_geometry] path = "../../geometry" diff --git a/examples/canvas_minimal/src/main.rs b/examples/canvas_minimal/src/main.rs index 230640c3..dce34e5d 100644 --- a/examples/canvas_minimal/src/main.rs +++ b/examples/canvas_minimal/src/main.rs @@ -9,9 +9,9 @@ // except according to those terms. use pathfinder_canvas::{CanvasFontContext, CanvasRenderingContext2D, Path2D}; -use pathfinder_geometry::basic::vector::{Vector2F, Vector2I}; -use pathfinder_geometry::basic::rect::RectF; -use pathfinder_geometry::color::ColorF; +use pathfinder_geometry::vector::{Vector2F, Vector2I}; +use pathfinder_geometry::rect::RectF; +use pathfinder_content::color::ColorF; use pathfinder_gl::{GLDevice, GLVersion}; use pathfinder_gpu::resources::FilesystemResourceLoader; use pathfinder_renderer::concurrent::rayon::RayonExecutor; diff --git a/examples/canvas_moire/Cargo.toml b/examples/canvas_moire/Cargo.toml index 0bab187d..cb8f98ea 100644 --- a/examples/canvas_moire/Cargo.toml +++ b/examples/canvas_moire/Cargo.toml @@ -12,6 +12,9 @@ sdl2-sys = "0.32" [dependencies.pathfinder_canvas] path = "../../canvas" +[dependencies.pathfinder_content] +path = "../../content" + [dependencies.pathfinder_geometry] path = "../../geometry" diff --git a/examples/canvas_moire/src/main.rs b/examples/canvas_moire/src/main.rs index 1f579b1e..36312a09 100644 --- a/examples/canvas_moire/src/main.rs +++ b/examples/canvas_moire/src/main.rs @@ -9,8 +9,8 @@ // except according to those terms. use pathfinder_canvas::{CanvasFontContext, CanvasRenderingContext2D, FillStyle, Path2D}; -use pathfinder_geometry::basic::vector::{Vector2F, Vector2I}; -use pathfinder_geometry::color::{ColorF, ColorU}; +use pathfinder_geometry::vector::{Vector2F, Vector2I}; +use pathfinder_content::color::{ColorF, ColorU}; use pathfinder_gl::{GLDevice, GLVersion}; use pathfinder_gpu::resources::FilesystemResourceLoader; use pathfinder_renderer::concurrent::rayon::RayonExecutor; diff --git a/examples/canvas_text/Cargo.toml b/examples/canvas_text/Cargo.toml index 720a0863..6250e71a 100644 --- a/examples/canvas_text/Cargo.toml +++ b/examples/canvas_text/Cargo.toml @@ -13,6 +13,9 @@ sdl2-sys = "0.32" [dependencies.pathfinder_canvas] path = "../../canvas" +[dependencies.pathfinder_content] +path = "../../content" + [dependencies.pathfinder_geometry] path = "../../geometry" diff --git a/examples/canvas_text/src/main.rs b/examples/canvas_text/src/main.rs index 7d4b8385..2942e3ae 100644 --- a/examples/canvas_text/src/main.rs +++ b/examples/canvas_text/src/main.rs @@ -10,8 +10,8 @@ use font_kit::handle::Handle; use pathfinder_canvas::{CanvasFontContext, CanvasRenderingContext2D, TextAlign}; -use pathfinder_geometry::basic::vector::{Vector2F, Vector2I}; -use pathfinder_geometry::color::ColorF; +use pathfinder_geometry::vector::{Vector2F, Vector2I}; +use pathfinder_content::color::ColorF; use pathfinder_gl::{GLDevice, GLVersion}; use pathfinder_gpu::resources::{FilesystemResourceLoader, ResourceLoader}; use pathfinder_renderer::concurrent::rayon::RayonExecutor; diff --git a/examples/swf_basic/src/main.rs b/examples/swf_basic/src/main.rs index a06d7f79..cd790074 100644 --- a/examples/swf_basic/src/main.rs +++ b/examples/swf_basic/src/main.rs @@ -8,8 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use pathfinder_geometry::basic::vector::{Vector2F, Vector2I}; -use pathfinder_geometry::basic::rect::RectF; +use pathfinder_geometry::vector::{Vector2F, Vector2I}; +use pathfinder_geometry::rect::RectF; use pathfinder_gl::{GLDevice, GLVersion}; use pathfinder_gpu::resources::{FilesystemResourceLoader, ResourceLoader}; use pathfinder_renderer::concurrent::rayon::RayonExecutor; @@ -24,7 +24,7 @@ use pathfinder_renderer::scene::Scene; use pathfinder_swf::{draw_paths_into_scene, process_swf_tags}; use std::env; use std::fs::read; -use pathfinder_geometry::basic::transform2d::Transform2DF; +use pathfinder_geometry::transform2d::Transform2DF; fn main() { let resource_loader = FilesystemResourceLoader::locate(); diff --git a/geometry/Cargo.toml b/geometry/Cargo.toml index 580a84da..8136c255 100644 --- a/geometry/Cargo.toml +++ b/geometry/Cargo.toml @@ -5,11 +5,6 @@ edition = "2018" authors = ["Patrick Walton "] [dependencies] -arrayvec = "0.4" -bitflags = "1.0" -serde = "1.0" -serde_derive = "1.0" -smallvec = "0.6" [dependencies.log] version = "0.4" diff --git a/geometry/src/lib.rs b/geometry/src/lib.rs index 8445b7ae..3ff52601 100644 --- a/geometry/src/lib.rs +++ b/geometry/src/lib.rs @@ -8,24 +8,12 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -//! Utilities for Bézier curves. -//! -//! These may be merged into upstream Lyon eventually. +//! Basic geometry and linear algebra primitives, optimized with SIMD. -#[macro_use] -extern crate bitflags; -#[macro_use] -extern crate log; - -pub mod basic; -pub mod clip; -pub mod color; -pub mod dash; -pub mod orientation; -pub mod outline; -pub mod segment; -pub mod stroke; +pub mod line_segment; +pub mod rect; +pub mod transform2d; +pub mod transform3d; +pub mod unit_vector; pub mod util; - -mod dilation; -mod unit_vector; +pub mod vector; diff --git a/geometry/src/basic/line_segment.rs b/geometry/src/line_segment.rs similarity index 98% rename from geometry/src/basic/line_segment.rs rename to geometry/src/line_segment.rs index 3d68f655..7842c893 100644 --- a/geometry/src/basic/line_segment.rs +++ b/geometry/src/line_segment.rs @@ -10,8 +10,8 @@ //! Line segment types, optimized with SIMD. -use crate::basic::vector::Vector2F; -use crate::basic::transform2d::Matrix2x2F; +use crate::vector::Vector2F; +use crate::transform2d::Matrix2x2F; use crate::util; use pathfinder_simd::default::F32x4; use std::ops::{Add, Sub}; diff --git a/geometry/src/basic/rect.rs b/geometry/src/rect.rs similarity index 99% rename from geometry/src/basic/rect.rs rename to geometry/src/rect.rs index 95e60ee3..ec7e103a 100644 --- a/geometry/src/basic/rect.rs +++ b/geometry/src/rect.rs @@ -10,7 +10,7 @@ //! 2D axis-aligned rectangles, optimized with SIMD. -use crate::basic::vector::{Vector2F, Vector2I}; +use crate::vector::{Vector2F, Vector2I}; use pathfinder_simd::default::{F32x4, I32x4}; #[derive(Clone, Copy, Debug, PartialEq, Default)] diff --git a/geometry/src/basic/transform2d.rs b/geometry/src/transform2d.rs similarity index 82% rename from geometry/src/basic/transform2d.rs rename to geometry/src/transform2d.rs index db0df148..b48c8882 100644 --- a/geometry/src/basic/transform2d.rs +++ b/geometry/src/transform2d.rs @@ -10,11 +10,10 @@ //! 2D affine transforms. -use crate::basic::line_segment::LineSegment2F; -use crate::basic::vector::Vector2F; -use crate::basic::rect::RectF; -use crate::basic::transform3d::Transform3DF; -use crate::segment::Segment; +use crate::line_segment::LineSegment2F; +use crate::vector::Vector2F; +use crate::rect::RectF; +use crate::transform3d::Transform3DF; use crate::unit_vector::UnitVector; use pathfinder_simd::default::F32x4; use std::ops::Sub; @@ -295,57 +294,3 @@ impl Transform2DF { Vector2F(self.matrix.0.zwxy()).length() } } - -/// Transforms a path with a SIMD 2D transform. -pub struct Transform2DFPathIter -where - I: Iterator, -{ - iter: I, - transform: Transform2DF, -} - -impl Iterator for Transform2DFPathIter -where - I: Iterator, -{ - type Item = Segment; - - #[inline] - fn next(&mut self) -> Option { - // TODO(pcwalton): Can we go faster by transforming an entire line segment with SIMD? - let mut segment = self.iter.next()?; - if !segment.is_none() { - segment - .baseline - .set_from(&self.transform.transform_point(segment.baseline.from())); - segment - .baseline - .set_to(&self.transform.transform_point(segment.baseline.to())); - if !segment.is_line() { - segment - .ctrl - .set_from(&self.transform.transform_point(segment.ctrl.from())); - if !segment.is_quadratic() { - segment - .ctrl - .set_to(&self.transform.transform_point(segment.ctrl.to())); - } - } - } - Some(segment) - } -} - -impl Transform2DFPathIter -where - I: Iterator, -{ - #[inline] - pub fn new(iter: I, transform: &Transform2DF) -> Transform2DFPathIter { - Transform2DFPathIter { - iter, - transform: *transform, - } - } -} diff --git a/geometry/src/basic/transform3d.rs b/geometry/src/transform3d.rs similarity index 89% rename from geometry/src/basic/transform3d.rs rename to geometry/src/transform3d.rs index bdd71c0c..7425b34c 100644 --- a/geometry/src/basic/transform3d.rs +++ b/geometry/src/transform3d.rs @@ -10,10 +10,9 @@ //! 3D transforms that can be applied to paths. -use crate::basic::vector::{Vector2F, Vector2I, Vector4F}; -use crate::basic::rect::RectF; -use crate::basic::transform2d::Matrix2x2F; -use crate::segment::Segment; +use crate::vector::{Vector2F, Vector2I, Vector4F}; +use crate::rect::RectF; +use crate::transform2d::Matrix2x2F; use pathfinder_simd::default::F32x4; use std::ops::{Add, Neg}; @@ -372,65 +371,10 @@ impl Perspective { } } -/// Transforms a path with a perspective projection. -pub struct PerspectivePathIter -where - I: Iterator, -{ - iter: I, - perspective: Perspective, -} - -impl Iterator for PerspectivePathIter -where - I: Iterator, -{ - type Item = Segment; - - #[inline] - fn next(&mut self) -> Option { - let mut segment = self.iter.next()?; - if !segment.is_none() { - segment.baseline.set_from( - &self - .perspective - .transform_point_2d(&segment.baseline.from()), - ); - segment - .baseline - .set_to(&self.perspective.transform_point_2d(&segment.baseline.to())); - if !segment.is_line() { - segment - .ctrl - .set_from(&self.perspective.transform_point_2d(&segment.ctrl.from())); - if !segment.is_quadratic() { - segment - .ctrl - .set_to(&self.perspective.transform_point_2d(&segment.ctrl.to())); - } - } - } - Some(segment) - } -} - -impl PerspectivePathIter -where - I: Iterator, -{ - #[inline] - pub fn new(iter: I, perspective: &Perspective) -> PerspectivePathIter { - PerspectivePathIter { - iter, - perspective: *perspective, - } - } -} - #[cfg(test)] mod test { - use crate::basic::vector::Vector4F; - use crate::basic::transform3d::Transform3DF; + use crate::vector::Vector4F; + use crate::transform3d::Transform3DF; #[test] fn test_post_mul() { diff --git a/geometry/src/unit_vector.rs b/geometry/src/unit_vector.rs index 35533e7a..b46431b0 100644 --- a/geometry/src/unit_vector.rs +++ b/geometry/src/unit_vector.rs @@ -10,7 +10,7 @@ //! A utility module that allows unit vectors to be treated like angles. -use crate::basic::vector::Vector2F; +use crate::vector::Vector2F; use pathfinder_simd::default::F32x4; #[derive(Clone, Copy, Debug)] diff --git a/geometry/src/basic/vector.rs b/geometry/src/vector.rs similarity index 100% rename from geometry/src/basic/vector.rs rename to geometry/src/vector.rs diff --git a/gl/src/lib.rs b/gl/src/lib.rs index f53faeaf..1c832544 100644 --- a/gl/src/lib.rs +++ b/gl/src/lib.rs @@ -14,8 +14,8 @@ extern crate log; use gl::types::{GLboolean, GLchar, GLenum, GLfloat, GLint, GLsizei, GLsizeiptr, GLuint, GLvoid}; -use pathfinder_geometry::basic::rect::RectI; -use pathfinder_geometry::basic::vector::Vector2I; +use pathfinder_geometry::rect::RectI; +use pathfinder_geometry::vector::Vector2I; use pathfinder_gpu::resources::ResourceLoader; use pathfinder_gpu::{RenderTarget, BlendState, BufferData, BufferTarget, BufferUploadMode}; use pathfinder_gpu::{ClearOps, DepthFunc, Device, Primitive, RenderOptions, RenderState}; diff --git a/gpu/Cargo.toml b/gpu/Cargo.toml index c493efa2..cc9ca12f 100644 --- a/gpu/Cargo.toml +++ b/gpu/Cargo.toml @@ -11,6 +11,9 @@ version = "0.21" default-features = false features = ["png_codec"] +[dependencies.pathfinder_content] +path = "../content" + [dependencies.pathfinder_geometry] path = "../geometry" diff --git a/gpu/src/lib.rs b/gpu/src/lib.rs index 227b0993..70dcd132 100644 --- a/gpu/src/lib.rs +++ b/gpu/src/lib.rs @@ -12,10 +12,10 @@ use crate::resources::ResourceLoader; use image::ImageFormat; -use pathfinder_geometry::basic::vector::Vector2I; -use pathfinder_geometry::basic::rect::RectI; -use pathfinder_geometry::basic::transform3d::Transform3DF; -use pathfinder_geometry::color::ColorF; +use pathfinder_content::color::ColorF; +use pathfinder_geometry::rect::RectI; +use pathfinder_geometry::transform3d::Transform3DF; +use pathfinder_geometry::vector::Vector2I; use pathfinder_simd::default::F32x4; use std::time::Duration; diff --git a/metal/src/lib.rs b/metal/src/lib.rs index 63856a09..3c1c4f89 100644 --- a/metal/src/lib.rs +++ b/metal/src/lib.rs @@ -40,8 +40,8 @@ use metal::{SamplerDescriptor, SamplerState, StencilDescriptor, StructMemberRef, use metal::{StructTypeRef, TextureDescriptor, Texture, TextureRef, VertexAttribute}; use metal::{VertexAttributeRef, VertexDescriptor, VertexDescriptorRef}; use objc::runtime::{Class, Object}; -use pathfinder_geometry::basic::rect::RectI; -use pathfinder_geometry::basic::vector::Vector2I; +use pathfinder_geometry::rect::RectI; +use pathfinder_geometry::vector::Vector2I; use pathfinder_gpu::resources::ResourceLoader; use pathfinder_gpu::{BlendState, BufferData, BufferTarget, BufferUploadMode, DepthFunc, Device}; use pathfinder_gpu::{Primitive, RenderState, RenderTarget, ShaderKind, StencilFunc, TextureData}; diff --git a/renderer/Cargo.toml b/renderer/Cargo.toml index 106c0bab..e8e789a0 100644 --- a/renderer/Cargo.toml +++ b/renderer/Cargo.toml @@ -18,6 +18,9 @@ smallvec = "0.6" version = "0.4" features = ["release_max_level_warn"] +[dependencies.pathfinder_content] +path = "../content" + [dependencies.pathfinder_geometry] path = "../geometry" diff --git a/renderer/src/builder.rs b/renderer/src/builder.rs index ff054432..b3d4ca1c 100644 --- a/renderer/src/builder.rs +++ b/renderer/src/builder.rs @@ -17,9 +17,9 @@ use crate::scene::Scene; use crate::tile_map::DenseTileMap; use crate::tiles::{self, TILE_HEIGHT, TILE_WIDTH, Tiler}; use crate::z_buffer::ZBuffer; -use pathfinder_geometry::basic::line_segment::{LineSegment2F, LineSegmentU4, LineSegmentU8}; -use pathfinder_geometry::basic::vector::{Vector2F, Vector2I}; -use pathfinder_geometry::basic::rect::{RectF, RectI}; +use pathfinder_geometry::line_segment::{LineSegment2F, LineSegmentU4, LineSegmentU8}; +use pathfinder_geometry::vector::{Vector2F, Vector2I}; +use pathfinder_geometry::rect::{RectF, RectI}; use pathfinder_geometry::util; use pathfinder_simd::default::{F32x4, I32x4}; use std::sync::atomic::{AtomicUsize, Ordering}; diff --git a/renderer/src/concurrent/scene_proxy.rs b/renderer/src/concurrent/scene_proxy.rs index a85d3e89..22e29155 100644 --- a/renderer/src/concurrent/scene_proxy.rs +++ b/renderer/src/concurrent/scene_proxy.rs @@ -24,7 +24,7 @@ use crate::gpu::renderer::Renderer; use crate::gpu_data::RenderCommand; use crate::options::{BuildOptions, RenderCommandListener}; use crate::scene::Scene; -use pathfinder_geometry::basic::rect::RectF; +use pathfinder_geometry::rect::RectF; use pathfinder_gpu::Device; use std::sync::mpsc::{self, Receiver, Sender}; use std::thread; diff --git a/renderer/src/gpu/debug.rs b/renderer/src/gpu/debug.rs index 5e982d79..7d28b952 100644 --- a/renderer/src/gpu/debug.rs +++ b/renderer/src/gpu/debug.rs @@ -16,8 +16,8 @@ //! The debug font atlas was generated using: https://evanw.github.io/font-texture-generator/ use crate::gpu::renderer::{RenderStats, RenderTime}; -use pathfinder_geometry::basic::vector::Vector2I; -use pathfinder_geometry::basic::rect::RectI; +use pathfinder_geometry::vector::Vector2I; +use pathfinder_geometry::rect::RectI; use pathfinder_gpu::resources::ResourceLoader; use pathfinder_gpu::Device; use pathfinder_ui::{FONT_ASCENT, LINE_HEIGHT, PADDING, UIPresenter, WINDOW_COLOR}; diff --git a/renderer/src/gpu/options.rs b/renderer/src/gpu/options.rs index 04c9af59..8ffe9d88 100644 --- a/renderer/src/gpu/options.rs +++ b/renderer/src/gpu/options.rs @@ -8,9 +8,9 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use pathfinder_geometry::basic::rect::RectI; -use pathfinder_geometry::basic::vector::Vector2I; -use pathfinder_geometry::color::ColorF; +use pathfinder_geometry::rect::RectI; +use pathfinder_geometry::vector::Vector2I; +use pathfinder_content::color::ColorF; use pathfinder_gpu::Device; /// Options that influence rendering. diff --git a/renderer/src/gpu/renderer.rs b/renderer/src/gpu/renderer.rs index e616615e..87565d36 100644 --- a/renderer/src/gpu/renderer.rs +++ b/renderer/src/gpu/renderer.rs @@ -14,10 +14,10 @@ use crate::gpu_data::{AlphaTileBatchPrimitive, FillBatchPrimitive, PaintData}; use crate::gpu_data::{RenderCommand, SolidTileBatchPrimitive}; use crate::post::DefringingKernel; use crate::tiles::{TILE_HEIGHT, TILE_WIDTH}; -use pathfinder_geometry::basic::vector::{Vector2I, Vector4F}; -use pathfinder_geometry::basic::rect::RectI; -use pathfinder_geometry::basic::transform3d::Transform3DF; -use pathfinder_geometry::color::ColorF; +use pathfinder_geometry::vector::{Vector2I, Vector4F}; +use pathfinder_geometry::rect::RectI; +use pathfinder_geometry::transform3d::Transform3DF; +use pathfinder_content::color::ColorF; use pathfinder_gpu::resources::ResourceLoader; use pathfinder_gpu::{BlendState, BufferData, BufferTarget, BufferUploadMode, ClearOps}; use pathfinder_gpu::{DepthFunc, DepthState, Device, Primitive, RenderOptions, RenderState}; diff --git a/renderer/src/gpu_data.rs b/renderer/src/gpu_data.rs index 6c5045f7..6e65cb46 100644 --- a/renderer/src/gpu_data.rs +++ b/renderer/src/gpu_data.rs @@ -12,9 +12,9 @@ use crate::options::BoundingQuad; use crate::tile_map::DenseTileMap; -use pathfinder_geometry::basic::line_segment::{LineSegmentU4, LineSegmentU8}; -use pathfinder_geometry::basic::vector::Vector2I; -use pathfinder_geometry::basic::rect::RectF; +use pathfinder_geometry::line_segment::{LineSegmentU4, LineSegmentU8}; +use pathfinder_geometry::vector::Vector2I; +use pathfinder_geometry::rect::RectF; use std::fmt::{Debug, Formatter, Result as DebugResult}; use std::time::Duration; diff --git a/renderer/src/options.rs b/renderer/src/options.rs index 32357c08..0266ec78 100644 --- a/renderer/src/options.rs +++ b/renderer/src/options.rs @@ -11,11 +11,11 @@ //! Options that control how rendering is to be performed. use crate::gpu_data::RenderCommand; -use pathfinder_geometry::basic::rect::RectF; -use pathfinder_geometry::basic::transform2d::Transform2DF; -use pathfinder_geometry::basic::transform3d::Perspective; -use pathfinder_geometry::basic::vector::{Vector2F, Vector4F}; -use pathfinder_geometry::clip::PolygonClipper3D; +use pathfinder_geometry::rect::RectF; +use pathfinder_geometry::transform2d::Transform2DF; +use pathfinder_geometry::transform3d::Perspective; +use pathfinder_geometry::vector::{Vector2F, Vector4F}; +use pathfinder_content::clip::PolygonClipper3D; pub trait RenderCommandListener: Send + Sync { fn send(&self, command: RenderCommand); diff --git a/renderer/src/paint.rs b/renderer/src/paint.rs index d0140004..2426092c 100644 --- a/renderer/src/paint.rs +++ b/renderer/src/paint.rs @@ -10,8 +10,8 @@ use crate::gpu_data::PaintData; use crate::scene::Scene; -use pathfinder_geometry::basic::vector::Vector2I; -use pathfinder_geometry::color::ColorU; +use pathfinder_geometry::vector::Vector2I; +use pathfinder_content::color::ColorU; const PAINT_TEXTURE_WIDTH: i32 = 256; const PAINT_TEXTURE_HEIGHT: i32 = 256; diff --git a/renderer/src/scene.rs b/renderer/src/scene.rs index db5319c6..328c3f82 100644 --- a/renderer/src/scene.rs +++ b/renderer/src/scene.rs @@ -16,11 +16,11 @@ use crate::options::{BuildOptions, PreparedBuildOptions}; use crate::options::{PreparedRenderTransform, RenderCommandListener}; use crate::paint::{Paint, PaintId}; use hashbrown::HashMap; -use pathfinder_geometry::basic::vector::Vector2F; -use pathfinder_geometry::basic::rect::RectF; -use pathfinder_geometry::basic::transform2d::Transform2DF; -use pathfinder_geometry::color::ColorU; -use pathfinder_geometry::outline::Outline; +use pathfinder_geometry::vector::Vector2F; +use pathfinder_geometry::rect::RectF; +use pathfinder_geometry::transform2d::Transform2DF; +use pathfinder_content::color::ColorU; +use pathfinder_content::outline::Outline; use std::io::{self, Write}; #[derive(Clone)] diff --git a/renderer/src/tile_map.rs b/renderer/src/tile_map.rs index a280df3b..f0d5ac40 100644 --- a/renderer/src/tile_map.rs +++ b/renderer/src/tile_map.rs @@ -8,8 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use pathfinder_geometry::basic::vector::Vector2I; -use pathfinder_geometry::basic::rect::RectI; +use pathfinder_geometry::vector::Vector2I; +use pathfinder_geometry::rect::RectI; #[derive(Debug)] pub struct DenseTileMap { diff --git a/renderer/src/tiles.rs b/renderer/src/tiles.rs index 3f5eb89a..0c98f0a5 100644 --- a/renderer/src/tiles.rs +++ b/renderer/src/tiles.rs @@ -12,11 +12,11 @@ use crate::builder::SceneBuilder; use crate::gpu_data::{AlphaTileBatchPrimitive, BuiltObject, TileObjectPrimitive}; use crate::paint::{self, PaintId}; use crate::sorted_vector::SortedVector; -use pathfinder_geometry::basic::line_segment::LineSegment2F; -use pathfinder_geometry::basic::vector::{Vector2F, Vector2I}; -use pathfinder_geometry::basic::rect::{RectF, RectI}; -use pathfinder_geometry::outline::{Contour, Outline, PointIndex}; -use pathfinder_geometry::segment::Segment; +use pathfinder_geometry::line_segment::LineSegment2F; +use pathfinder_geometry::vector::{Vector2F, Vector2I}; +use pathfinder_geometry::rect::{RectF, RectI}; +use pathfinder_content::outline::{Contour, Outline, PointIndex}; +use pathfinder_content::segment::Segment; use std::cmp::Ordering; use std::mem; diff --git a/renderer/src/z_buffer.rs b/renderer/src/z_buffer.rs index 858a9e90..ae4bdf9e 100644 --- a/renderer/src/z_buffer.rs +++ b/renderer/src/z_buffer.rs @@ -15,8 +15,8 @@ use crate::paint; use crate::scene::PathObject; use crate::tile_map::DenseTileMap; use crate::tiles; -use pathfinder_geometry::basic::vector::Vector2I; -use pathfinder_geometry::basic::rect::RectF; +use pathfinder_geometry::vector::Vector2I; +use pathfinder_geometry::rect::RectF; use std::ops::Range; use std::sync::atomic::{AtomicUsize, Ordering as AtomicOrdering}; diff --git a/svg/Cargo.toml b/svg/Cargo.toml index d735fdaf..13c630dc 100644 --- a/svg/Cargo.toml +++ b/svg/Cargo.toml @@ -8,6 +8,9 @@ authors = ["Patrick Walton "] bitflags = "1.0" usvg = "0.7" +[dependencies.pathfinder_content] +path = "../content" + [dependencies.pathfinder_geometry] path = "../geometry" diff --git a/svg/src/lib.rs b/svg/src/lib.rs index e9f14486..2d9b6454 100644 --- a/svg/src/lib.rs +++ b/svg/src/lib.rs @@ -13,14 +13,15 @@ #[macro_use] extern crate bitflags; -use pathfinder_geometry::basic::line_segment::LineSegment2F; -use pathfinder_geometry::basic::vector::Vector2F; -use pathfinder_geometry::basic::rect::RectF; -use pathfinder_geometry::basic::transform2d::{Transform2DF, Transform2DFPathIter}; -use pathfinder_geometry::color::ColorU; -use pathfinder_geometry::outline::Outline; -use pathfinder_geometry::segment::{Segment, SegmentFlags}; -use pathfinder_geometry::stroke::{LineCap, LineJoin, OutlineStrokeToFill, StrokeStyle}; +use pathfinder_content::color::ColorU; +use pathfinder_content::outline::Outline; +use pathfinder_content::segment::{Segment, SegmentFlags}; +use pathfinder_content::stroke::{LineCap, LineJoin, OutlineStrokeToFill, StrokeStyle}; +use pathfinder_content::transform::Transform2DFPathIter; +use pathfinder_geometry::line_segment::LineSegment2F; +use pathfinder_geometry::rect::RectF; +use pathfinder_geometry::transform2d::Transform2DF; +use pathfinder_geometry::vector::Vector2F; use pathfinder_renderer::paint::Paint; use pathfinder_renderer::scene::{PathObject, Scene}; use std::fmt::{Display, Formatter, Result as FormatResult}; diff --git a/swf/Cargo.toml b/swf/Cargo.toml index b063d864..389a0fd7 100644 --- a/swf/Cargo.toml +++ b/swf/Cargo.toml @@ -8,6 +8,9 @@ edition = "2018" swf-parser = "0.7.0" swf-tree = "0.7.0" +[dependencies.pathfinder_content] +path = "../content" + [dependencies.pathfinder_geometry] path = "../geometry" diff --git a/swf/src/lib.rs b/swf/src/lib.rs index 94bf0e35..c8a683e8 100644 --- a/swf/src/lib.rs +++ b/swf/src/lib.rs @@ -9,10 +9,10 @@ // except according to those terms. use std::ops::Add; -use pathfinder_geometry::color::{ColorU, ColorF}; -use pathfinder_geometry::outline::{Outline, Contour}; -use pathfinder_geometry::basic::vector::Vector2F; -use pathfinder_geometry::stroke::{OutlineStrokeToFill, StrokeStyle}; +use pathfinder_content::color::{ColorU, ColorF}; +use pathfinder_content::outline::{Outline, Contour}; +use pathfinder_geometry::vector::Vector2F; +use pathfinder_content::stroke::{OutlineStrokeToFill, StrokeStyle}; use pathfinder_renderer::scene::{PathObject, Scene}; use swf_tree; diff --git a/swf/src/shapes.rs b/swf/src/shapes.rs index b2c94936..ff0a7b02 100644 --- a/swf/src/shapes.rs +++ b/swf/src/shapes.rs @@ -9,7 +9,7 @@ // except according to those terms. use pathfinder_renderer::paint::Paint; -use pathfinder_geometry::stroke::{LineJoin, LineCap}; +use pathfinder_content::stroke::{LineJoin, LineCap}; use crate::{Twips, Point2}; use std::mem; use std::cmp::Ordering; @@ -25,7 +25,7 @@ use swf_tree::{ shape_records, Vector2D }; -use pathfinder_geometry::color::ColorU; +use pathfinder_content::color::ColorU; use swf_tree::tags::DefineShape; #[derive(Clone, Copy, Debug)] diff --git a/text/Cargo.toml b/text/Cargo.toml index 76985371..493f98e3 100644 --- a/text/Cargo.toml +++ b/text/Cargo.toml @@ -9,6 +9,9 @@ euclid = "0.19" font-kit = "0.2" lyon_path = "0.12" +[dependencies.pathfinder_content] +path = "../content" + [dependencies.pathfinder_geometry] path = "../geometry" diff --git a/text/src/lib.rs b/text/src/lib.rs index cbf56765..49dcd1ce 100644 --- a/text/src/lib.rs +++ b/text/src/lib.rs @@ -13,10 +13,10 @@ use font_kit::error::GlyphLoadingError; use font_kit::hinting::HintingOptions; use font_kit::loader::Loader; use lyon_path::builder::{FlatPathBuilder, PathBuilder}; -use pathfinder_geometry::basic::vector::Vector2F; -use pathfinder_geometry::basic::transform2d::Transform2DF; -use pathfinder_geometry::outline::{Contour, Outline}; -use pathfinder_geometry::stroke::{OutlineStrokeToFill, StrokeStyle}; +use pathfinder_content::outline::{Contour, Outline}; +use pathfinder_content::stroke::{OutlineStrokeToFill, StrokeStyle}; +use pathfinder_geometry::transform2d::Transform2DF; +use pathfinder_geometry::vector::Vector2F; use pathfinder_renderer::paint::PaintId; use pathfinder_renderer::scene::{PathObject, Scene}; use skribo::{FontCollection, Layout, TextStyle}; diff --git a/ui/Cargo.toml b/ui/Cargo.toml index 259f8c26..2cad25a6 100644 --- a/ui/Cargo.toml +++ b/ui/Cargo.toml @@ -13,6 +13,9 @@ serde_json = "1.0" version = "0.1" features = ["serde"] +[dependencies.pathfinder_content] +path = "../content" + [dependencies.pathfinder_geometry] path = "../geometry" diff --git a/ui/src/lib.rs b/ui/src/lib.rs index 18817224..7ae36ab3 100644 --- a/ui/src/lib.rs +++ b/ui/src/lib.rs @@ -17,9 +17,9 @@ extern crate serde_derive; use hashbrown::HashMap; -use pathfinder_geometry::basic::vector::{Vector2F, Vector2I}; -use pathfinder_geometry::basic::rect::RectI; -use pathfinder_geometry::color::ColorU; +use pathfinder_content::color::ColorU; +use pathfinder_geometry::rect::RectI; +use pathfinder_geometry::vector::{Vector2F, Vector2I}; use pathfinder_gpu::resources::ResourceLoader; use pathfinder_gpu::{BlendState, BufferData, BufferTarget, BufferUploadMode, Device, Primitive}; use pathfinder_gpu::{RenderOptions, RenderState, RenderTarget, UniformData, VertexAttrClass}; From 9107f21966f126b31114a2bab6740b62d3975d6c Mon Sep 17 00:00:00 2001 From: Patrick Walton Date: Thu, 20 Jun 2019 22:18:09 -0700 Subject: [PATCH 21/26] wip --- .gitignore | 1 + Cargo.lock | 51 +++++++++++++++++++++++++++++++++++++++++++++++++ c/Cargo.toml | 4 ++++ c/build.rs | 20 +++++++++++++++++++ c/cbindgen.toml | 13 +++++++++++++ 5 files changed, 89 insertions(+) create mode 100644 c/build.rs create mode 100644 c/cbindgen.toml diff --git a/.gitignore b/.gitignore index 4150bad5..ac289464 100644 --- a/.gitignore +++ b/.gitignore @@ -7,6 +7,7 @@ target node_modules /examples/c_canvas_minimal/build /shaders/build +/c/build # Editors *.swp diff --git a/Cargo.lock b/Cargo.lock index 1a5dc613..bc59b993 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -231,6 +231,23 @@ dependencies = [ "sdl2-sys 0.32.6 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "cbindgen" +version = "0.8.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.91 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.91 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.39 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.15.34 (registry+https://github.com/rust-lang/crates.io-index)", + "tempfile 3.0.8 (registry+https://github.com/rust-lang/crates.io-index)", + "toml 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "cc" version = "1.0.36" @@ -1379,6 +1396,7 @@ dependencies = [ name = "pathfinder_c" version = "0.1.0" dependencies = [ + "cbindgen 0.8.7 (registry+https://github.com/rust-lang/crates.io-index)", "gl 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.54 (registry+https://github.com/rust-lang/crates.io-index)", "pathfinder_canvas 0.1.0", @@ -1858,6 +1876,14 @@ dependencies = [ "ucd-util 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "remove_dir_all" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "roxmltree" version = "0.6.1" @@ -2181,6 +2207,19 @@ dependencies = [ "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "tempfile" +version = "3.0.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cfg-if 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.54 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.54 (registry+https://github.com/rust-lang/crates.io-index)", + "remove_dir_all 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "term" version = "0.5.2" @@ -2236,6 +2275,14 @@ dependencies = [ "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "toml" +version = "0.4.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "serde 1.0.91 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "ttf-parser" version = "0.1.0" @@ -2528,6 +2575,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum block 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "0d8c1fef690941d3e7788d328517591fecc684c084084702d6ff1641e993699a" "checksum build_const 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "39092a32794787acd8525ee150305ff051b0aa6cc2abaf193924f5ab05425f39" "checksum byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a019b10a2a7cdeb292db131fc8113e57ea2a908f6e7894b0c3c671893b65dbeb" +"checksum cbindgen 0.8.7 (registry+https://github.com/rust-lang/crates.io-index)" = "1f861ef68cabbb271d373a7795014052bff37edce22c620d95e395e8719d7dc5" "checksum cc 1.0.36 (registry+https://github.com/rust-lang/crates.io-index)" = "a0c56216487bb80eec9c4516337b2588a4f2a2290d72a1416d930e4dcdb0c90d" "checksum cesu8 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6d43a04d8753f35258c91f8ec639f792891f748a1edbd759cf1dcea3382ad83c" "checksum cfg-if 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "11d43355396e872eefb45ce6342e4374ed7bc2b3a502d1b28e36d6e23c05d1f4" @@ -2683,6 +2731,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum redox_users 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3fe5204c3a17e97dde73f285d49be585df59ed84b50a872baf416e73b62c3828" "checksum regex 1.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "8f0a0bcab2fd7d1d7c54fa9eae6f43eddeb9ce2e7352f8518a814a4f65d60c58" "checksum regex-syntax 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)" = "dcfd8681eebe297b81d98498869d4aae052137651ad7b96822f09ceb690d0a96" +"checksum remove_dir_all 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "4a83fa3702a688b9359eccba92d153ac33fd2e8462f9e0e3fdf155239ea7792e" "checksum roxmltree 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "330d8f80a274bc3cb608908ee345970e7e24b96907f1ad69615a498bec57871c" "checksum rustc-demangle 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)" = "ccc78bfd5acd7bf3e89cffcf899e5cb1a52d6fafa8dec2739ad70c9577a57288" "checksum rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" @@ -2718,12 +2767,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum swf-tree 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c075cea0328cc5f6ee694bcd1c43534d1186a730d79258b10735f8f08e2f1baa" "checksum syn 0.15.34 (registry+https://github.com/rust-lang/crates.io-index)" = "a1393e4a97a19c01e900df2aec855a29f71cf02c402e2f443b8d2747c25c5dbe" "checksum synstructure 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "73687139bf99285483c96ac0add482c3776528beac1d97d444f6e91f203a2015" +"checksum tempfile 3.0.8 (registry+https://github.com/rust-lang/crates.io-index)" = "7dc4738f2e68ed2855de5ac9cdbe05c9216773ecde4739b2f095002ab03a13ef" "checksum term 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "edd106a334b7657c10b7c540a0106114feadeb4dc314513e97df481d5d966f42" "checksum termcolor 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "4096add70612622289f2fdcdbd5086dc81c1e2675e6ae58d6c4f62a16c6d7f2f" "checksum termion 1.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "dde0593aeb8d47accea5392b39350015b5eccb12c0d98044d856983d89548dea" "checksum textwrap 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060" "checksum thread_local 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c6b53e329000edc2b34dbe8545fd20e55a333362d0a321909685a19bd28c3f1b" "checksum time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)" = "db8dcfca086c1143c9270ac42a2bbd8a7ee477b78ac8e45b19abfb0cbede4b6f" +"checksum toml 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)" = "758664fc71a3a69038656bee8b6be6477d2a6c315a6b81f7081f591bffa4111f" "checksum ttf-parser 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "29637063e570f7e5260924119666113215386c1b94e1d1ceb4525e269dfbe2d0" "checksum ucd-util 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "535c204ee4d8434478593480b8f86ab45ec9aae0e83c568ca81abf0fd0e88f86" "checksum unicode-bidi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "49f2bd0c6468a8230e1db229cff8029217cf623c767ea5d60bfbd42729ea54d5" diff --git a/c/Cargo.toml b/c/Cargo.toml index caad0fec..e894ec6c 100644 --- a/c/Cargo.toml +++ b/c/Cargo.toml @@ -3,6 +3,7 @@ name = "pathfinder_c" version = "0.1.0" authors = ["Patrick Walton "] edition = "2018" +build = "build.rs" [lib] crate-type = ["staticlib"] @@ -31,3 +32,6 @@ path = "../renderer" [dependencies.pathfinder_simd] path = "../simd" + +[build-dependencies] +cbindgen = "0.8" diff --git a/c/build.rs b/c/build.rs new file mode 100644 index 00000000..def89d30 --- /dev/null +++ b/c/build.rs @@ -0,0 +1,20 @@ +// pathfinder/c/build.rs +// +// Copyright © 2019 The Pathfinder Project Developers. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use cbindgen; +use std::env; +use std::fs; + +fn main() { + fs::create_dir_all("build/include/pathfinder").expect("Failed to create directories!"); + let crate_dir = env::var("CARGO_MANIFEST_DIR").unwrap(); + cbindgen::generate(crate_dir).expect("cbindgen failed!") + .write_to_file("build/include/pathfinder/pathfinder.h"); +} diff --git a/c/cbindgen.toml b/c/cbindgen.toml new file mode 100644 index 00000000..d5f73f3a --- /dev/null +++ b/c/cbindgen.toml @@ -0,0 +1,13 @@ +language = "C" +header = "/* Generated code. Do not edit; instead run `cargo build` in `pathfinder_c`. */" +include_guard = "PF_PATHFINDER_H" +include_version = true + +[parse] +parse_deps = true +include = [ + "pathfinder_canvas", + "pathfinder_geometry", + "pathfinder_gl", + "pathfinder_renderer", +] From 1caad35b46a9b8ef16bb55fa171fd6dafbbf70e8 Mon Sep 17 00:00:00 2001 From: Patrick Walton Date: Fri, 21 Jun 2019 11:35:18 -0700 Subject: [PATCH 22/26] Use `cbindgen` instead of hand-writing a header file --- c/cbindgen.toml | 8 +- c/include/pathfinder/pathfinder.h | 222 ----------------------------- examples/c_canvas_minimal/Makefile | 2 +- 3 files changed, 8 insertions(+), 224 deletions(-) delete mode 100644 c/include/pathfinder/pathfinder.h diff --git a/c/cbindgen.toml b/c/cbindgen.toml index d5f73f3a..4d096e5d 100644 --- a/c/cbindgen.toml +++ b/c/cbindgen.toml @@ -1,5 +1,10 @@ language = "C" -header = "/* Generated code. Do not edit; instead run `cargo build` in `pathfinder_c`. */" +header = """\ +/* Generated code. Do not edit; instead run `cargo build` in `pathfinder_c`. */ + +extern \"C\" { +""" +trailer = "}" include_guard = "PF_PATHFINDER_H" include_version = true @@ -7,6 +12,7 @@ include_version = true parse_deps = true include = [ "pathfinder_canvas", + "pathfinder_content", "pathfinder_geometry", "pathfinder_gl", "pathfinder_renderer", diff --git a/c/include/pathfinder/pathfinder.h b/c/include/pathfinder/pathfinder.h deleted file mode 100644 index 7ded8d08..00000000 --- a/c/include/pathfinder/pathfinder.h +++ /dev/null @@ -1,222 +0,0 @@ -// pathfinder/c/include/pathfinder/pathfinder.h -// -// Copyright © 2019 The Pathfinder Project Developers. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -#ifndef PF_PATHFINDER_H -#define PF_PATHFINDER_H - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -// Macros - -// `canvas` - -#define PF_LINE_CAP_BUTT 0 -#define PF_LINE_CAP_SQUARE 1 -#define PF_LINE_CAP_ROUND 2 - -#define PF_LINE_JOIN_MITER 0 -#define PF_LINE_JOIN_BEVEL 1 -#define PF_LINE_JOIN_ROUND 2 - -// `geometry` - -#define PF_ARC_DIRECTION_CW 0 -#define PF_ARC_DIRECTION_CCW 1 - -// `gl` - -#define PF_GL_VERSION_GL3 0 -#define PF_GL_VERSION_GLES3 1 - -// `renderer` - -#define PF_RENDERER_OPTIONS_FLAGS_HAS_BACKGROUND_COLOR 0x1 - -// Types - -// `canvas` - -struct PFCanvas; -typedef struct PFCanvas *PFCanvasRef; -struct PFPath; -typedef struct PFPath *PFPathRef; -struct PFCanvasFontContext; -typedef struct PFCanvasFontContext *PFCanvasFontContextRef; -struct PFFillStyle; -typedef struct PFFillStyle *PFFillStyleRef; -typedef uint8_t PFLineCap; -typedef uint8_t PFLineJoin; -typedef uint8_t PFArcDirection; -struct PFTextMetrics { - float width; -}; -typedef struct PFTextMetrics PFTextMetrics; - -// `geometry` - -struct PFColorF { - float r, g, b, a; -}; -typedef struct PFColorF PFColorF; -struct PFColorU { - uint8_t r, g, b, a; -}; -typedef struct PFColorU PFColorU; -struct PFVector2F { - float x, y; -}; -typedef struct PFVector2F PFVector2F; -struct PFVector2I { - int32_t x, y; -}; -typedef struct PFVector2I PFVector2I; -struct PFRectF { - PFVector2F origin, lower_right; -}; -typedef struct PFRectF PFRectF; -struct PFRectI { - PFVector2I origin, lower_right; -}; -typedef struct PFRectI PFRectI; - -// `gl` - -struct PFGLDevice; -typedef struct PFGLDevice *PFGLDeviceRef; -struct PFGLDestFramebuffer; -typedef struct PFGLDestFramebuffer *PFGLDestFramebufferRef; -typedef const void *(*PFGLFunctionLoader)(const char *data, void *userdata); -struct PFGLRenderer; -typedef struct PFGLRenderer *PFGLRendererRef; -typedef uint32_t PFGLVersion; - -// `gpu` - -struct PFResourceLoader; -typedef struct PFResourceLoader *PFResourceLoaderRef; - -// `renderer` - -typedef uint8_t PFRendererOptionsFlags; -struct PFRendererOptions { - PFColorF background_color; - PFRendererOptionsFlags flags; -}; -struct PFBuildOptions { - uint32_t placeholder; -}; -typedef struct PFRendererOptions PFRendererOptions; -typedef struct PFBuildOptions PFBuildOptions; -struct PFScene; -typedef struct PFScene *PFSceneRef; -struct PFSceneProxy; -typedef struct PFSceneProxy *PFSceneProxyRef; - -// Functions - -// `canvas` - -PFCanvasRef PFCanvasCreate(PFCanvasFontContextRef font_context, const PFVector2F *size); -void PFCanvasDestroy(PFCanvasRef canvas); -PFCanvasFontContextRef PFCanvasFontContextCreateWithSystemSource(); -void PFCanvasFontContextDestroy(PFCanvasFontContextRef font_context); -PFCanvasFontContextRef PFCanvasFontContextClone(PFCanvasFontContextRef font_context); -PFSceneRef PFCanvasCreateScene(PFCanvasRef canvas); -void PFCanvasFillRect(PFCanvasRef canvas, const PFRectF *rect); -void PFCanvasStrokeRect(PFCanvasRef canvas, const PFRectF *rect); -void PFCanvasFillText(PFCanvasRef canvas, - const char *string, - size_t string_len, - const PFVector2F *position); -void PFCanvasStrokeText(PFCanvasRef canvas, - const char *string, - size_t string_len, - const PFVector2F *position); -void PFCanvasMeasureText(PFCanvasRef canvas, - const char *string, - size_t string_len, - PFTextMetrics *out_text_metrics); -void PFCanvasSetLineWidth(PFCanvasRef canvas, float new_line_width); -void PFCanvasSetLineCap(PFCanvasRef canvas, PFLineCap new_line_cap); -void PFCanvasSetLineJoin(PFCanvasRef canvas, PFLineJoin new_line_join); -void PFCanvasSetMiterLimit(PFCanvasRef canvas, float new_miter_limit); -void PFCanvasSetLineDash(PFCanvasRef canvas, - const float *new_line_dashes, - size_t new_line_dash_count); -void PFCanvasSetLineDashOffset(PFCanvasRef canvas, float offset); -void PFCanvasSetFillStyle(PFCanvasRef canvas, PFFillStyleRef fill_style); -void PFCanvasSetStrokeStyle(PFCanvasRef canvas, PFFillStyleRef stroke_style); -void PFCanvasFillPath(PFCanvasRef canvas, PFPathRef path); -void PFCanvasStrokePath(PFCanvasRef canvas, PFPathRef path); -PFPathRef PFPathCreate(); -void PFPathDestroy(PFPathRef path); -PFPathRef PFPathClone(PFPathRef path); -void PFPathMoveTo(PFPathRef path, const PFVector2F *to); -void PFPathLineTo(PFPathRef path, const PFVector2F *to); -void PFPathQuadraticCurveTo(PFPathRef path, const PFVector2F *ctrl, const PFVector2F *to); -void PFPathBezierCurveTo(PFPathRef path, - const PFVector2F *ctrl0, - const PFVector2F *ctrl1, - const PFVector2F *to); -void PFPathArc(PFPathRef path, - const PFVector2F *center, - float radius, - float start_angle, - float end_angle, - PFArcDirection direction); -void PFPathArcTo(PFPathRef path, const PFVector2F *ctrl, const PFVector2F *to, float radius); -void PFPathRect(PFPathRef path, const PFRectF *rect); -void PFPathEllipse(PFPathRef path, - const PFVector2F *center, - const PFVector2F *axes, - float rotation, - float start_angle, - float end_angle); -void PFPathClosePath(PFPathRef path); -PFFillStyleRef PFFillStyleCreateColor(PFColorU color); -void PFFillStyleDestroy(PFFillStyleRef fill_style); - -// `gl` - -PFGLDestFramebufferRef PFGLDestFramebufferCreateFullWindow(const PFVector2I *window_size); -void PFGLDestFramebufferDestroy(PFGLDestFramebufferRef dest_framebuffer); -PFGLDeviceRef PFGLDeviceCreate(PFGLVersion version, uint32_t default_framebuffer); -void PFGLDeviceDestroy(PFGLDeviceRef device); -void PFGLLoadWith(PFGLFunctionLoader loader, void *userdata); -PFGLRendererRef PFGLRendererCreate(PFGLDeviceRef device, - PFResourceLoaderRef resources, - PFGLDestFramebufferRef dest_framebuffer, - const PFRendererOptions *options); -void PFGLRendererDestroy(PFGLRendererRef renderer); -/// Returns a borrowed reference to the device. -PFGLDeviceRef PFGLRendererGetDevice(PFGLRendererRef renderer); -void PFSceneProxyBuildAndRenderGL(PFSceneProxyRef scene_proxy, - PFGLRendererRef renderer, - const PFBuildOptions *build_options); - -// `gpu` - -PFResourceLoaderRef PFFilesystemResourceLoaderLocate(); -void PFResourceLoaderDestroy(PFResourceLoaderRef loader); - -// `renderer` - -PFSceneProxyRef PFSceneProxyCreateFromSceneAndRayonExecutor(PFSceneRef scene); -void PFSceneProxyDestroy(PFSceneProxyRef scene_proxy); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/examples/c_canvas_minimal/Makefile b/examples/c_canvas_minimal/Makefile index 35f4b9ef..14563401 100644 --- a/examples/c_canvas_minimal/Makefile +++ b/examples/c_canvas_minimal/Makefile @@ -5,7 +5,7 @@ RUST_TARGET_DIR?=../../target RUST_SRC_DIR?=../../c RUSTFLAGS?=-C target-cpu=native -CFLAGS?=-Wall -g -I../../c/include +CFLAGS?=-Wall -g -I../../c/build/include LIBS?=-lpathfinder_c MKDIR?=mkdir -p RM?=rm From 1c34b12948da385e71f273b6717359d463dcbfef Mon Sep 17 00:00:00 2001 From: Patrick Walton Date: Fri, 21 Jun 2019 13:17:11 -0700 Subject: [PATCH 23/26] Add some font functions to the C API --- Cargo.lock | 1 + c/Cargo.toml | 1 + c/src/lib.rs | 26 ++++++++++++++++++++++++++ 3 files changed, 28 insertions(+) diff --git a/Cargo.lock b/Cargo.lock index bc59b993..9333a6c7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1397,6 +1397,7 @@ name = "pathfinder_c" version = "0.1.0" dependencies = [ "cbindgen 0.8.7 (registry+https://github.com/rust-lang/crates.io-index)", + "font-kit 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "gl 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.54 (registry+https://github.com/rust-lang/crates.io-index)", "pathfinder_canvas 0.1.0", diff --git a/c/Cargo.toml b/c/Cargo.toml index e894ec6c..a4ea30e5 100644 --- a/c/Cargo.toml +++ b/c/Cargo.toml @@ -9,6 +9,7 @@ build = "build.rs" crate-type = ["staticlib"] [dependencies] +font-kit = "0.2" gl = "0.6" libc = "0.2" diff --git a/c/src/lib.rs b/c/src/lib.rs index 9823f7d1..b8403638 100644 --- a/c/src/lib.rs +++ b/c/src/lib.rs @@ -10,6 +10,7 @@ //! C bindings to Pathfinder. +use font_kit::handle::Handle; use gl; use pathfinder_canvas::{CanvasFontContext, CanvasRenderingContext2D, FillStyle, LineJoin}; use pathfinder_canvas::{Path2D, TextMetrics}; @@ -55,6 +56,9 @@ pub const PF_RENDERER_OPTIONS_FLAGS_HAS_BACKGROUND_COLOR: u8 = 0x1; // Types +// External: `font-kit` +pub type FKHandleRef = *mut Handle; + // `canvas` pub type PFCanvasRef = *mut CanvasRenderingContext2D; pub type PFPathRef = *mut Path2D; @@ -154,6 +158,16 @@ pub unsafe extern "C" fn PFCanvasFontContextCreateWithSystemSource() -> PFCanvas Box::into_raw(Box::new(CanvasFontContext::from_system_source())) } +#[no_mangle] +pub unsafe extern "C" fn PFCanvasFontContextCreateWithFonts(fonts: *const FKHandleRef, + font_count: usize) + -> PFCanvasFontContextRef { + let fonts = slice::from_raw_parts(fonts, font_count); + Box::into_raw(Box::new(CanvasFontContext::from_fonts(fonts.into_iter().map(|font| { + (**font).clone() + })))) +} + #[no_mangle] pub unsafe extern "C" fn PFCanvasFontContextDestroy(font_context: PFCanvasFontContextRef) { drop(Box::from_raw(font_context)) @@ -250,6 +264,18 @@ pub unsafe extern "C" fn PFCanvasSetLineDashOffset(canvas: PFCanvasRef, new_offs (*canvas).set_line_dash_offset(new_offset) } +#[no_mangle] +pub unsafe extern "C" fn PFCanvasSetFontByPostScriptName(canvas: PFCanvasRef, + postscript_name: *const c_char, + postscript_name_len: usize) { + (*canvas).set_font_by_postscript_name(to_rust_string(&postscript_name, postscript_name_len)) +} + +#[no_mangle] +pub unsafe extern "C" fn PFCanvasSetFontSize(canvas: PFCanvasRef, new_font_size: f32) { + (*canvas).set_font_size(new_font_size) +} + #[no_mangle] pub unsafe extern "C" fn PFCanvasSetFillStyle(canvas: PFCanvasRef, fill_style: PFFillStyleRef) { (*canvas).set_fill_style(*fill_style) From 2c49a3360e1a4f907d25b6c033f6244b2fec1243 Mon Sep 17 00:00:00 2001 From: Patrick Walton Date: Fri, 21 Jun 2019 13:37:17 -0700 Subject: [PATCH 24/26] Add Metal support to the C API --- Cargo.lock | 3 ++ c/Cargo.toml | 7 +++ c/src/lib.rs | 77 ++++++++++++++++++++++++++++++ examples/c_canvas_minimal/Makefile | 2 +- 4 files changed, 88 insertions(+), 1 deletion(-) diff --git a/Cargo.lock b/Cargo.lock index 9333a6c7..215c4503 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1398,13 +1398,16 @@ version = "0.1.0" dependencies = [ "cbindgen 0.8.7 (registry+https://github.com/rust-lang/crates.io-index)", "font-kit 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "foreign-types 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "gl 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.54 (registry+https://github.com/rust-lang/crates.io-index)", + "metal 0.14.0 (registry+https://github.com/rust-lang/crates.io-index)", "pathfinder_canvas 0.1.0", "pathfinder_content 0.1.0", "pathfinder_geometry 0.3.0", "pathfinder_gl 0.1.0", "pathfinder_gpu 0.1.0", + "pathfinder_metal 0.1.0", "pathfinder_renderer 0.1.0", "pathfinder_simd 0.3.0", ] diff --git a/c/Cargo.toml b/c/Cargo.toml index a4ea30e5..e1c0eb0b 100644 --- a/c/Cargo.toml +++ b/c/Cargo.toml @@ -10,6 +10,7 @@ crate-type = ["staticlib"] [dependencies] font-kit = "0.2" +foreign-types = "0.3" gl = "0.6" libc = "0.2" @@ -34,5 +35,11 @@ path = "../renderer" [dependencies.pathfinder_simd] path = "../simd" +[target.'cfg(target_os = "macos")'.dependencies] +metal = "0.14" + +[target.'cfg(target_os = "macos")'.dependencies.pathfinder_metal] +path = "../metal" + [build-dependencies] cbindgen = "0.8" diff --git a/c/src/lib.rs b/c/src/lib.rs index b8403638..6b6235c1 100644 --- a/c/src/lib.rs +++ b/c/src/lib.rs @@ -11,6 +11,7 @@ //! C bindings to Pathfinder. use font_kit::handle::Handle; +use foreign_types::ForeignTypeRef; use gl; use pathfinder_canvas::{CanvasFontContext, CanvasRenderingContext2D, FillStyle, LineJoin}; use pathfinder_canvas::{Path2D, TextMetrics}; @@ -33,6 +34,11 @@ use std::os::raw::{c_char, c_void}; use std::slice; use std::str; +#[cfg(all(target_os = "macos", not(feature = "pf-gl")))] +use metal::{CAMetalLayer, CoreAnimationLayerRef}; +#[cfg(all(target_os = "macos", not(feature = "pf-gl")))] +use pathfinder_metal::MetalDevice; + // Constants // `canvas` @@ -118,10 +124,18 @@ pub type PFGLFunctionLoader = extern "C" fn(name: *const c_char, userdata: *mut // `gpu` pub type PFGLDestFramebufferRef = *mut DestFramebuffer; pub type PFGLRendererRef = *mut Renderer; +#[cfg(all(target_os = "macos", not(feature = "pf-gl")))] +pub type PFMetalDestFramebufferRef = *mut DestFramebuffer; +#[cfg(all(target_os = "macos", not(feature = "pf-gl")))] +pub type PFMetalRendererRef = *mut Renderer; // FIXME(pcwalton): Double-boxing is unfortunate. Remove this when `std::raw::TraitObject` is // stable? pub type PFResourceLoaderRef = *mut Box; +// `metal` +#[cfg(all(target_os = "macos", not(feature = "pf-gl")))] +pub type PFMetalDeviceRef = *mut MetalDevice; + // `renderer` pub type PFSceneRef = *mut Scene; pub type PFSceneProxyRef = *mut SceneProxy; @@ -456,6 +470,46 @@ pub unsafe extern "C" fn PFGLRendererGetDevice(renderer: PFGLRendererRef) -> PFG &mut (*renderer).device } +#[cfg(all(target_os = "macos", not(feature = "pf-gl")))] +#[no_mangle] +pub unsafe extern "C" fn PFMetalDestFramebufferCreateFullWindow(window_size: *const PFVector2I) + -> PFMetalDestFramebufferRef { + Box::into_raw(Box::new(DestFramebuffer::full_window((*window_size).to_rust()))) +} + +#[cfg(all(target_os = "macos", not(feature = "pf-gl")))] +#[no_mangle] +pub unsafe extern "C" fn PFMetalDestFramebufferDestroy(dest_framebuffer: + PFMetalDestFramebufferRef) { + drop(Box::from_raw(dest_framebuffer)) +} + +/// Takes ownership of `device` and `dest_framebuffer`, but not `resources`. +#[cfg(all(target_os = "macos", not(feature = "pf-gl")))] +#[no_mangle] +pub unsafe extern "C" fn PFMetalRendererCreate(device: PFMetalDeviceRef, + resources: PFResourceLoaderRef, + dest_framebuffer: PFMetalDestFramebufferRef, + options: *const PFRendererOptions) + -> PFMetalRendererRef { + Box::into_raw(Box::new(Renderer::new(*Box::from_raw(device), + &**resources, + *Box::from_raw(dest_framebuffer), + (*options).to_rust()))) +} + +#[cfg(all(target_os = "macos", not(feature = "pf-gl")))] +#[no_mangle] +pub unsafe extern "C" fn PFMetalRendererDestroy(renderer: PFMetalRendererRef) { + drop(Box::from_raw(renderer)) +} + +#[cfg(all(target_os = "macos", not(feature = "pf-gl")))] +#[no_mangle] +pub unsafe extern "C" fn PFMetalRendererGetDevice(renderer: PFMetalRendererRef) -> PFMetalDeviceRef { + &mut (*renderer).device +} + #[no_mangle] pub unsafe extern "C" fn PFSceneProxyBuildAndRenderGL(scene_proxy: PFSceneProxyRef, renderer: PFGLRendererRef, @@ -463,6 +517,29 @@ pub unsafe extern "C" fn PFSceneProxyBuildAndRenderGL(scene_proxy: PFSceneProxyR (*scene_proxy).build_and_render(&mut *renderer, (*build_options).to_rust()) } +#[cfg(all(target_os = "macos", not(feature = "pf-gl")))] +#[no_mangle] +pub unsafe extern "C" fn PFSceneProxyBuildAndRenderMetal(scene_proxy: PFSceneProxyRef, + renderer: PFMetalRendererRef, + build_options: *const PFBuildOptions) { + (*scene_proxy).build_and_render(&mut *renderer, (*build_options).to_rust()) +} + +// `metal` + +#[cfg(all(target_os = "macos", not(feature = "pf-gl")))] +#[no_mangle] +pub unsafe extern "C" fn PFMetalDeviceCreate(layer: *mut CAMetalLayer) + -> PFMetalDeviceRef { + Box::into_raw(Box::new(MetalDevice::new(CoreAnimationLayerRef::from_ptr(layer)))) +} + +#[cfg(all(target_os = "macos", not(feature = "pf-gl")))] +#[no_mangle] +pub unsafe extern "C" fn PFMetalDeviceDestroy(device: PFMetalDeviceRef) { + drop(Box::from_raw(device)) +} + // `renderer` #[no_mangle] diff --git a/examples/c_canvas_minimal/Makefile b/examples/c_canvas_minimal/Makefile index 14563401..d2c8a5dc 100644 --- a/examples/c_canvas_minimal/Makefile +++ b/examples/c_canvas_minimal/Makefile @@ -15,7 +15,7 @@ UNAME=$(shell uname -s) ifeq ($(UNAME),Darwin) # FIXME(pcwalton): Don't link against HarfBuzz!! LIBS+=-framework OpenGL -framework CoreFoundation -framework CoreGraphics -framework CoreText - LIBS+=-lharfbuzz + LIBS+=-framework Metal -lharfbuzz else LIBS+=-lGL endif From d86ff9011a4b304121ee75ed5f6352b426f9852a Mon Sep 17 00:00:00 2001 From: Patrick Walton Date: Fri, 21 Jun 2019 18:04:18 -0700 Subject: [PATCH 25/26] Update the postprocessing shader and vertex array for the Metal changes. Closes #201. --- renderer/src/gpu/renderer.rs | 4 ++-- resources/shaders/gl3/post.vs.glsl | 10 ++++++++-- resources/shaders/metal/post.vs.metal | 6 ++++-- shaders/post.vs.glsl | 10 ++++++++-- 4 files changed, 22 insertions(+), 8 deletions(-) diff --git a/renderer/src/gpu/renderer.rs b/renderer/src/gpu/renderer.rs index 87565d36..f70f56d7 100644 --- a/renderer/src/gpu/renderer.rs +++ b/renderer/src/gpu/renderer.rs @@ -654,7 +654,7 @@ where } } - self.device.draw_arrays(4, &RenderState { + self.device.draw_elements(6, &RenderState { target: &self.dest_render_target(), program: &self.postprocess_program.program, vertex_array: &self.postprocess_vertex_array.vertex_array, @@ -1451,7 +1451,7 @@ where device.configure_vertex_attr(&vertex_array, &position_attr, &VertexAttrDescriptor { size: 2, class: VertexAttrClass::Int, - attr_type: VertexAttrType::U16, + attr_type: VertexAttrType::I16, stride: 4, offset: 0, divisor: 0, diff --git a/resources/shaders/gl3/post.vs.glsl b/resources/shaders/gl3/post.vs.glsl index b30dcf8d..a1d8effb 100644 --- a/resources/shaders/gl3/post.vs.glsl +++ b/resources/shaders/gl3/post.vs.glsl @@ -19,7 +19,13 @@ in ivec2 aPosition; out vec2 vTexCoord; void main(){ - vTexCoord = vec2(aPosition); - gl_Position = vec4(vec2(aPosition)* 2.0 - 1.0, 0.0, 1.0); + vec2 position = vec2(aPosition); + vTexCoord = position; + + + + + + gl_Position = vec4(vec2(position)* 2.0 - 1.0, 0.0, 1.0); } diff --git a/resources/shaders/metal/post.vs.metal b/resources/shaders/metal/post.vs.metal index 0fcc0bf6..f7385038 100644 --- a/resources/shaders/metal/post.vs.metal +++ b/resources/shaders/metal/post.vs.metal @@ -18,8 +18,10 @@ struct main0_in vertex main0_out main0(main0_in in [[stage_in]]) { main0_out out = {}; - out.vTexCoord = float2(in.aPosition); - out.gl_Position = float4((float2(in.aPosition) * 2.0) - float2(1.0), 0.0, 1.0); + float2 position = float2(in.aPosition); + out.vTexCoord = position; + position.y = 1.0 - position.y; + out.gl_Position = float4((float2(position) * 2.0) - float2(1.0), 0.0, 1.0); return out; } diff --git a/shaders/post.vs.glsl b/shaders/post.vs.glsl index 137cf388..52cf3eea 100644 --- a/shaders/post.vs.glsl +++ b/shaders/post.vs.glsl @@ -17,6 +17,12 @@ in ivec2 aPosition; out vec2 vTexCoord; void main() { - vTexCoord = vec2(aPosition); - gl_Position = vec4(vec2(aPosition) * 2.0 - 1.0, 0.0, 1.0); + vec2 position = vec2(aPosition); + vTexCoord = position; + +#ifdef PF_ORIGIN_UPPER_LEFT + // FIXME(pcwalton): This is wrong. + position.y = 1.0 - position.y; +#endif + gl_Position = vec4(vec2(position) * 2.0 - 1.0, 0.0, 1.0); } From dfdfebfdd239346f733c5443f6f067158d900a9b Mon Sep 17 00:00:00 2001 From: Patrick Walton Date: Sat, 22 Jun 2019 14:38:56 -0700 Subject: [PATCH 26/26] Fix use-after-free in Metal argument encoding --- metal/src/lib.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/metal/src/lib.rs b/metal/src/lib.rs index 3c1c4f89..13f157bc 100644 --- a/metal/src/lib.rs +++ b/metal/src/lib.rs @@ -1356,6 +1356,7 @@ impl FunctionExt for Function { let encoder: *mut MTLArgumentEncoder = msg_send![self.as_ptr(), newArgumentEncoderWithBufferIndex:buffer_index reflection:&mut reflection]; + msg_send![reflection, retain]; (ArgumentEncoder::from_ptr(encoder), Argument::from_ptr(reflection)) } }