mirror of
https://github.com/italicsjenga/vello.git
synced 2025-01-09 20:31:29 +11:00
Add C api for glyph rendering
First cut at a public C api that supports glyph rendering on Metal targets.
This commit is contained in:
parent
b178741c19
commit
532b6ee808
132
Cargo.lock
generated
132
Cargo.lock
generated
|
@ -127,6 +127,25 @@ dependencies = [
|
||||||
"nix 0.18.0",
|
"nix 0.18.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "cbindgen"
|
||||||
|
version = "0.20.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "51e3973b165dc0f435831a9e426de67e894de532754ff7a3f307c03ee5dec7dc"
|
||||||
|
dependencies = [
|
||||||
|
"clap",
|
||||||
|
"heck",
|
||||||
|
"indexmap",
|
||||||
|
"log",
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"serde",
|
||||||
|
"serde_json",
|
||||||
|
"syn",
|
||||||
|
"tempfile",
|
||||||
|
"toml",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cc"
|
name = "cc"
|
||||||
version = "1.0.73"
|
version = "1.0.73"
|
||||||
|
@ -452,6 +471,15 @@ version = "1.2.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "9ea835d29036a4087793836fa931b08837ad5e957da9e23886b29586fb9b6650"
|
checksum = "9ea835d29036a4087793836fa931b08837ad5e957da9e23886b29586fb9b6650"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "fastrand"
|
||||||
|
version = "1.7.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "c3fcf0cee53519c866c09b5de1f6c56ff9d647101f81c1964fa632e148896cdf"
|
||||||
|
dependencies = [
|
||||||
|
"instant",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "fnv"
|
name = "fnv"
|
||||||
version = "1.0.7"
|
version = "1.0.7"
|
||||||
|
@ -501,6 +529,21 @@ version = "1.8.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "eabb4a44450da02c90444cf74558da904edde8fb4e9035a9a6a4e15445af0bd7"
|
checksum = "eabb4a44450da02c90444cf74558da904edde8fb4e9035a9a6a4e15445af0bd7"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "hashbrown"
|
||||||
|
version = "0.11.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "heck"
|
||||||
|
version = "0.3.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "6d621efb26863f0e9924c6ac577e8275e5e6b77455db64ffa6c65c904e9e132c"
|
||||||
|
dependencies = [
|
||||||
|
"unicode-segmentation",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "hermit-abi"
|
name = "hermit-abi"
|
||||||
version = "0.1.19"
|
version = "0.1.19"
|
||||||
|
@ -516,6 +559,16 @@ version = "1.0.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39"
|
checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "indexmap"
|
||||||
|
version = "1.8.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "0f647032dfaa1f8b6dc29bd3edb7bbef4861b8b8007ebb118d6db284fd59f6ee"
|
||||||
|
dependencies = [
|
||||||
|
"autocfg",
|
||||||
|
"hashbrown",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "instant"
|
name = "instant"
|
||||||
version = "0.1.12"
|
version = "0.1.12"
|
||||||
|
@ -525,6 +578,12 @@ dependencies = [
|
||||||
"cfg-if 1.0.0",
|
"cfg-if 1.0.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "itoa"
|
||||||
|
version = "1.0.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1aab8fc367588b89dcee83ab0fd66b72b50b72fa1904d7095045ace2b0c81c35"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "jni-sys"
|
name = "jni-sys"
|
||||||
version = "0.3.0"
|
version = "0.3.0"
|
||||||
|
@ -876,6 +935,19 @@ version = "2.1.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d4fd5641d01c8f18a23da7b6fe29298ff4b55afcccdf78973b24cf3175fee32e"
|
checksum = "d4fd5641d01c8f18a23da7b6fe29298ff4b55afcccdf78973b24cf3175fee32e"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "pgpu-render"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"cbindgen",
|
||||||
|
"cocoa",
|
||||||
|
"metal",
|
||||||
|
"objc",
|
||||||
|
"piet-gpu",
|
||||||
|
"piet-gpu-hal",
|
||||||
|
"piet-scene",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "piet"
|
name = "piet"
|
||||||
version = "0.2.0"
|
version = "0.2.0"
|
||||||
|
@ -1131,6 +1203,15 @@ dependencies = [
|
||||||
"thiserror",
|
"thiserror",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "remove_dir_all"
|
||||||
|
version = "0.5.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "3acd125665422973a33ac9d3dd2df85edad0f4ae9b00dafb1a05e43a9f5ef8e7"
|
||||||
|
dependencies = [
|
||||||
|
"winapi",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "roxmltree"
|
name = "roxmltree"
|
||||||
version = "0.13.1"
|
version = "0.13.1"
|
||||||
|
@ -1150,6 +1231,12 @@ dependencies = [
|
||||||
"owned_ttf_parser",
|
"owned_ttf_parser",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ryu"
|
||||||
|
version = "1.0.9"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "73b4b750c782965c211b42f022f59af1fbceabdd026623714f104152f1ec149f"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "same-file"
|
name = "same-file"
|
||||||
version = "1.0.6"
|
version = "1.0.6"
|
||||||
|
@ -1176,6 +1263,31 @@ name = "serde"
|
||||||
version = "1.0.137"
|
version = "1.0.137"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "61ea8d54c77f8315140a05f4c7237403bf38b72704d031543aa1d16abbf517d1"
|
checksum = "61ea8d54c77f8315140a05f4c7237403bf38b72704d031543aa1d16abbf517d1"
|
||||||
|
dependencies = [
|
||||||
|
"serde_derive",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "serde_derive"
|
||||||
|
version = "1.0.137"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1f26faba0c3959972377d3b2d306ee9f71faee9714294e41bb777f83f88578be"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "serde_json"
|
||||||
|
version = "1.0.81"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9b7ce2b32a1aed03c558dc61a5cd328f15aff2dbc17daad8fb8af04d2100e15c"
|
||||||
|
dependencies = [
|
||||||
|
"itoa",
|
||||||
|
"ryu",
|
||||||
|
"serde",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "smallvec"
|
name = "smallvec"
|
||||||
|
@ -1235,6 +1347,20 @@ dependencies = [
|
||||||
"unicode-xid",
|
"unicode-xid",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tempfile"
|
||||||
|
version = "3.3.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5cdb1ef4eaeeaddc8fbd371e5017057064af0911902ef36b39801f67cc6d79e4"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if 1.0.0",
|
||||||
|
"fastrand",
|
||||||
|
"libc",
|
||||||
|
"redox_syscall",
|
||||||
|
"remove_dir_all",
|
||||||
|
"winapi",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "textwrap"
|
name = "textwrap"
|
||||||
version = "0.11.0"
|
version = "0.11.0"
|
||||||
|
@ -1330,6 +1456,12 @@ dependencies = [
|
||||||
"unic-common",
|
"unic-common",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "unicode-segmentation"
|
||||||
|
version = "1.9.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7e8820f5d777f6224dc4be3632222971ac30164d4a258d595640799554ebfd99"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "unicode-width"
|
name = "unicode-width"
|
||||||
version = "0.1.9"
|
version = "0.1.9"
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
[workspace]
|
[workspace]
|
||||||
|
|
||||||
members = [
|
members = [
|
||||||
|
"pgpu-render",
|
||||||
"piet-gpu",
|
"piet-gpu",
|
||||||
"piet-gpu-derive",
|
"piet-gpu-derive",
|
||||||
"piet-gpu-hal",
|
"piet-gpu-hal",
|
||||||
|
|
21
pgpu-render/Cargo.toml
Normal file
21
pgpu-render/Cargo.toml
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
[package]
|
||||||
|
name = "pgpu-render"
|
||||||
|
version = "0.1.0"
|
||||||
|
description = "C interface for glyph rendering using piet-gpu."
|
||||||
|
license = "MIT/Apache-2.0"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
[lib]
|
||||||
|
crate-type = ["cdylib"]
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
piet-gpu = { path = "../piet-gpu" }
|
||||||
|
piet-gpu-hal = { path = "../piet-gpu-hal" }
|
||||||
|
piet-scene = { path = "../piet-scene" }
|
||||||
|
|
||||||
|
metal = "0.22"
|
||||||
|
cocoa = "0.24.0"
|
||||||
|
objc = "0.2.5"
|
||||||
|
|
||||||
|
[build-dependencies]
|
||||||
|
cbindgen = "0.20.0"
|
29
pgpu-render/build.rs
Normal file
29
pgpu-render/build.rs
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
// Copyright 2022 The piet-gpu authors.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// https://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
//
|
||||||
|
// Also licensed under MIT license, at your choice.
|
||||||
|
|
||||||
|
extern crate cbindgen;
|
||||||
|
|
||||||
|
use std::env;
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let crate_dir = env::var("CARGO_MANIFEST_DIR").unwrap();
|
||||||
|
|
||||||
|
cbindgen::Builder::new()
|
||||||
|
.with_crate(crate_dir)
|
||||||
|
.generate()
|
||||||
|
.expect("Unable to generate bindings")
|
||||||
|
.write_to_file("pgpu.h");
|
||||||
|
}
|
140
pgpu-render/pgpu.h
Normal file
140
pgpu-render/pgpu.h
Normal file
|
@ -0,0 +1,140 @@
|
||||||
|
#include <cstdarg>
|
||||||
|
#include <cstdint>
|
||||||
|
#include <cstdlib>
|
||||||
|
#include <ostream>
|
||||||
|
#include <new>
|
||||||
|
|
||||||
|
/// Encoded (possibly color) outline for a glyph.
|
||||||
|
struct PgpuGlyph;
|
||||||
|
|
||||||
|
/// Context for loading and scaling glyphs.
|
||||||
|
struct PgpuGlyphContext;
|
||||||
|
|
||||||
|
/// Context for loading a scaling glyphs from a specific font.
|
||||||
|
struct PgpuGlyphProvider;
|
||||||
|
|
||||||
|
/// State and resources for rendering a scene.
|
||||||
|
struct PgpuRenderer;
|
||||||
|
|
||||||
|
/// Encoded streams and resources describing a vector graphics scene.
|
||||||
|
struct PgpuScene;
|
||||||
|
|
||||||
|
/// Builder for constructing an encoded scene.
|
||||||
|
struct PgpuSceneBuilder;
|
||||||
|
|
||||||
|
/// Tag and value for a font variation axis.
|
||||||
|
struct PgpuFontVariation {
|
||||||
|
/// Tag that specifies the axis.
|
||||||
|
uint32_t tag;
|
||||||
|
/// Requested setting for the axis.
|
||||||
|
float value;
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Description of a font.
|
||||||
|
struct PgpuFontDesc {
|
||||||
|
/// Pointer to the context of the font file.
|
||||||
|
const uint8_t *data;
|
||||||
|
/// Size of the font file data in bytes.
|
||||||
|
uintptr_t data_len;
|
||||||
|
/// Index of the requested font in the font file.
|
||||||
|
uint32_t index;
|
||||||
|
/// Unique identifier for the font.
|
||||||
|
uint64_t unique_id;
|
||||||
|
/// Requested size in pixels per em unit. Set to 0.0 for
|
||||||
|
/// unscaled outlines.
|
||||||
|
float ppem;
|
||||||
|
/// Pointer to array of font variation settings.
|
||||||
|
const PgpuFontVariation *variations;
|
||||||
|
/// Number of font variation settings.
|
||||||
|
uintptr_t variations_len;
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Rectangle defined by minimum and maximum points.
|
||||||
|
struct PgpuRect {
|
||||||
|
float x0;
|
||||||
|
float y0;
|
||||||
|
float x1;
|
||||||
|
float y1;
|
||||||
|
};
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
|
||||||
|
/// Creates a new piet-gpu renderer for the specified Metal device and
|
||||||
|
/// command queue.
|
||||||
|
///
|
||||||
|
/// device: MTLDevice*
|
||||||
|
/// queue: MTLCommandQueue*
|
||||||
|
PgpuRenderer *pgpu_renderer_new(void *device, void *queue);
|
||||||
|
|
||||||
|
/// Renders a prepared scene into a texture target. Commands for rendering are
|
||||||
|
/// recorded into the specified command buffer. Returns an id representing
|
||||||
|
/// resources that may have been allocated during this process. After the
|
||||||
|
/// command buffer has been retired, call `pgpu_renderer_release` with this id
|
||||||
|
/// to drop any associated resources.
|
||||||
|
///
|
||||||
|
/// target: MTLTexture*
|
||||||
|
/// cmdbuf: MTLCommandBuffer*
|
||||||
|
uint32_t pgpu_renderer_render(PgpuRenderer *renderer,
|
||||||
|
const PgpuScene *scene,
|
||||||
|
void *target,
|
||||||
|
void *cmdbuf);
|
||||||
|
|
||||||
|
/// Releases the internal resources associated with the specified id from a
|
||||||
|
/// previous render operation.
|
||||||
|
void pgpu_renderer_release(PgpuRenderer *renderer, uint32_t id);
|
||||||
|
|
||||||
|
/// Destroys the piet-gpu renderer.
|
||||||
|
void pgpu_renderer_destroy(PgpuRenderer *renderer);
|
||||||
|
|
||||||
|
/// Creates a new, empty piet-gpu scene.
|
||||||
|
PgpuScene *pgpu_scene_new();
|
||||||
|
|
||||||
|
/// Destroys the piet-gpu scene.
|
||||||
|
void pgpu_scene_destroy(PgpuScene *scene);
|
||||||
|
|
||||||
|
/// Creates a new builder for filling a piet-gpu scene. The specified scene
|
||||||
|
/// should not be accessed while the builder is live.
|
||||||
|
PgpuSceneBuilder *pgpu_scene_builder_new(PgpuScene *scene);
|
||||||
|
|
||||||
|
/// Adds a glyph with the specified transform to the underlying scene.
|
||||||
|
void pgpu_scene_builder_add_glyph(PgpuSceneBuilder *builder,
|
||||||
|
const PgpuGlyph *glyph,
|
||||||
|
const float (*transform)[6]);
|
||||||
|
|
||||||
|
/// Finalizes the scene builder, making the underlying scene ready for
|
||||||
|
/// rendering. This takes ownership and consumes the builder.
|
||||||
|
void pgpu_scene_builder_finish(PgpuSceneBuilder *builder);
|
||||||
|
|
||||||
|
/// Creates a new context for loading glyph outlines.
|
||||||
|
PgpuGlyphContext *pgpu_glyph_context_new();
|
||||||
|
|
||||||
|
/// Destroys the glyph context.
|
||||||
|
void pgpu_glyph_context_destroy(PgpuGlyphContext *gcx);
|
||||||
|
|
||||||
|
/// Creates a new glyph provider for the specified glyph context and font
|
||||||
|
/// descriptor. May return nullptr if the font data is invalid. Only one glyph
|
||||||
|
/// provider may be live for a glyph context.
|
||||||
|
PgpuGlyphProvider *pgpu_glyph_provider_new(PgpuGlyphContext *gcx, const PgpuFontDesc *font);
|
||||||
|
|
||||||
|
/// Returns an encoded outline for the specified glyph provider and glyph id.
|
||||||
|
/// May return nullptr if the requested glyph is not available.
|
||||||
|
const PgpuGlyph *pgpu_glyph_provider_get(PgpuGlyphProvider *provider, uint16_t gid);
|
||||||
|
|
||||||
|
/// Returns an encoded color outline for the specified glyph provider, color
|
||||||
|
/// palette index and glyph id. May return nullptr if the requested glyph is
|
||||||
|
/// not available.
|
||||||
|
PgpuGlyph *pgpu_glyph_provider_get_color(PgpuGlyphProvider *provider,
|
||||||
|
uint16_t palette_index,
|
||||||
|
uint16_t gid);
|
||||||
|
|
||||||
|
/// Destroys the glyph provider.
|
||||||
|
void pgpu_glyph_provider_destroy(PgpuGlyphProvider *provider);
|
||||||
|
|
||||||
|
/// Computes the bounding box for the glyph after applying the specified
|
||||||
|
/// transform.
|
||||||
|
PgpuRect pgpu_glyph_bbox(const PgpuGlyph *glyph, const float (*transform)[6]);
|
||||||
|
|
||||||
|
/// Destroys the glyph.
|
||||||
|
void pgpu_glyph_destroy(PgpuGlyph *glyph);
|
||||||
|
|
||||||
|
} // extern "C"
|
233
pgpu-render/src/lib.rs
Normal file
233
pgpu-render/src/lib.rs
Normal file
|
@ -0,0 +1,233 @@
|
||||||
|
// Copyright 2022 The piet-gpu authors.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// https://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
//
|
||||||
|
// Also licensed under MIT license, at your choice.
|
||||||
|
|
||||||
|
mod render;
|
||||||
|
|
||||||
|
use render::*;
|
||||||
|
use std::ffi::c_void;
|
||||||
|
use std::mem::transmute;
|
||||||
|
|
||||||
|
/// Creates a new piet-gpu renderer for the specified Metal device and
|
||||||
|
/// command queue.
|
||||||
|
///
|
||||||
|
/// device: MTLDevice*
|
||||||
|
/// queue: MTLCommandQueue*
|
||||||
|
#[no_mangle]
|
||||||
|
pub unsafe extern "C" fn pgpu_renderer_new(
|
||||||
|
device: *mut c_void,
|
||||||
|
queue: *mut c_void,
|
||||||
|
) -> *mut PgpuRenderer {
|
||||||
|
let device: &metal::DeviceRef = transmute(device);
|
||||||
|
let queue: &metal::CommandQueueRef = transmute(queue);
|
||||||
|
Box::into_raw(Box::new(PgpuRenderer::new(device, queue)))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Renders a prepared scene into a texture target. Commands for rendering are
|
||||||
|
/// recorded into the specified command buffer. Returns an id representing
|
||||||
|
/// resources that may have been allocated during this process. After the
|
||||||
|
/// command buffer has been retired, call `pgpu_renderer_release` with this id
|
||||||
|
/// to drop any associated resources.
|
||||||
|
///
|
||||||
|
/// target: MTLTexture*
|
||||||
|
/// cmdbuf: MTLCommandBuffer*
|
||||||
|
#[no_mangle]
|
||||||
|
pub unsafe extern "C" fn pgpu_renderer_render(
|
||||||
|
renderer: *mut PgpuRenderer,
|
||||||
|
scene: *const PgpuScene,
|
||||||
|
target: *mut c_void,
|
||||||
|
cmdbuf: *mut c_void,
|
||||||
|
) -> u32 {
|
||||||
|
let cmdbuf: &metal::CommandBufferRef = transmute(cmdbuf);
|
||||||
|
let target: &metal::TextureRef = transmute(target);
|
||||||
|
(*renderer).render(&*scene, cmdbuf, target)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Releases the internal resources associated with the specified id from a
|
||||||
|
/// previous render operation.
|
||||||
|
#[no_mangle]
|
||||||
|
pub unsafe extern "C" fn pgpu_renderer_release(renderer: *mut PgpuRenderer, id: u32) {
|
||||||
|
(*renderer).release(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Destroys the piet-gpu renderer.
|
||||||
|
#[no_mangle]
|
||||||
|
pub unsafe extern "C" fn pgpu_renderer_destroy(renderer: *mut PgpuRenderer) {
|
||||||
|
Box::from_raw(renderer);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Creates a new, empty piet-gpu scene.
|
||||||
|
#[no_mangle]
|
||||||
|
pub unsafe extern "C" fn pgpu_scene_new() -> *mut PgpuScene {
|
||||||
|
Box::into_raw(Box::new(PgpuScene::new()))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Destroys the piet-gpu scene.
|
||||||
|
#[no_mangle]
|
||||||
|
pub unsafe extern "C" fn pgpu_scene_destroy(scene: *mut PgpuScene) {
|
||||||
|
Box::from_raw(scene);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Creates a new builder for filling a piet-gpu scene. The specified scene
|
||||||
|
/// should not be accessed while the builder is live.
|
||||||
|
#[no_mangle]
|
||||||
|
pub unsafe extern "C" fn pgpu_scene_builder_new(
|
||||||
|
scene: *mut PgpuScene,
|
||||||
|
) -> *mut PgpuSceneBuilder<'static> {
|
||||||
|
Box::into_raw(Box::new((*scene).build()))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Adds a glyph with the specified transform to the underlying scene.
|
||||||
|
#[no_mangle]
|
||||||
|
pub unsafe extern "C" fn pgpu_scene_builder_add_glyph(
|
||||||
|
builder: *mut PgpuSceneBuilder<'static>,
|
||||||
|
glyph: *const PgpuGlyph,
|
||||||
|
transform: &[f32; 6],
|
||||||
|
) {
|
||||||
|
let transform = piet_scene::geometry::Affine::new(transform);
|
||||||
|
(*builder).add_glyph(&*glyph, &transform);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Finalizes the scene builder, making the underlying scene ready for
|
||||||
|
/// rendering. This takes ownership and consumes the builder.
|
||||||
|
#[no_mangle]
|
||||||
|
pub unsafe extern "C" fn pgpu_scene_builder_finish(builder: *mut PgpuSceneBuilder<'static>) {
|
||||||
|
let builder = Box::from_raw(builder);
|
||||||
|
builder.finish();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Creates a new context for loading glyph outlines.
|
||||||
|
#[no_mangle]
|
||||||
|
pub unsafe extern "C" fn pgpu_glyph_context_new() -> *mut PgpuGlyphContext {
|
||||||
|
Box::into_raw(Box::new(PgpuGlyphContext::new()))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Destroys the glyph context.
|
||||||
|
#[no_mangle]
|
||||||
|
pub unsafe extern "C" fn pgpu_glyph_context_destroy(gcx: *mut PgpuGlyphContext) {
|
||||||
|
Box::from_raw(gcx);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Description of a font.
|
||||||
|
#[derive(Copy, Clone)]
|
||||||
|
#[repr(C)]
|
||||||
|
pub struct PgpuFontDesc {
|
||||||
|
/// Pointer to the context of the font file.
|
||||||
|
data: *const u8,
|
||||||
|
/// Size of the font file data in bytes.
|
||||||
|
data_len: usize,
|
||||||
|
/// Index of the requested font in the font file.
|
||||||
|
index: u32,
|
||||||
|
/// Unique identifier for the font.
|
||||||
|
unique_id: u64,
|
||||||
|
/// Requested size in pixels per em unit. Set to 0.0 for
|
||||||
|
/// unscaled outlines.
|
||||||
|
ppem: f32,
|
||||||
|
/// Pointer to array of font variation settings.
|
||||||
|
variations: *const PgpuFontVariation,
|
||||||
|
/// Number of font variation settings.
|
||||||
|
variations_len: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Creates a new glyph provider for the specified glyph context and font
|
||||||
|
/// descriptor. May return nullptr if the font data is invalid. Only one glyph
|
||||||
|
/// provider may be live for a glyph context.
|
||||||
|
#[no_mangle]
|
||||||
|
pub unsafe extern "C" fn pgpu_glyph_provider_new(
|
||||||
|
gcx: *mut PgpuGlyphContext,
|
||||||
|
font: *const PgpuFontDesc,
|
||||||
|
) -> *mut PgpuGlyphProvider<'static> {
|
||||||
|
let font = &*font;
|
||||||
|
let font_data = std::slice::from_raw_parts(font.data, font.data_len);
|
||||||
|
let variations = std::slice::from_raw_parts(font.variations, font.variations_len);
|
||||||
|
if let Some(provider) = (*gcx).new_provider(
|
||||||
|
font_data,
|
||||||
|
font.index,
|
||||||
|
font.unique_id,
|
||||||
|
font.ppem,
|
||||||
|
false,
|
||||||
|
variations,
|
||||||
|
) {
|
||||||
|
Box::into_raw(Box::new(provider))
|
||||||
|
} else {
|
||||||
|
std::ptr::null_mut()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns an encoded outline for the specified glyph provider and glyph id.
|
||||||
|
/// May return nullptr if the requested glyph is not available.
|
||||||
|
#[no_mangle]
|
||||||
|
pub unsafe extern "C" fn pgpu_glyph_provider_get(
|
||||||
|
provider: *mut PgpuGlyphProvider,
|
||||||
|
gid: u16,
|
||||||
|
) -> *const PgpuGlyph {
|
||||||
|
if let Some(glyph) = (*provider).get(gid) {
|
||||||
|
Box::into_raw(Box::new(glyph))
|
||||||
|
} else {
|
||||||
|
std::ptr::null()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns an encoded color outline for the specified glyph provider, color
|
||||||
|
/// palette index and glyph id. May return nullptr if the requested glyph is
|
||||||
|
/// not available.
|
||||||
|
#[no_mangle]
|
||||||
|
pub unsafe extern "C" fn pgpu_glyph_provider_get_color(
|
||||||
|
provider: *mut PgpuGlyphProvider,
|
||||||
|
palette_index: u16,
|
||||||
|
gid: u16,
|
||||||
|
) -> *mut PgpuGlyph {
|
||||||
|
if let Some(glyph) = (*provider).get_color(palette_index, gid) {
|
||||||
|
Box::into_raw(Box::new(glyph))
|
||||||
|
} else {
|
||||||
|
std::ptr::null_mut()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Destroys the glyph provider.
|
||||||
|
#[no_mangle]
|
||||||
|
pub unsafe extern "C" fn pgpu_glyph_provider_destroy(provider: *mut PgpuGlyphProvider) {
|
||||||
|
Box::from_raw(provider);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Rectangle defined by minimum and maximum points.
|
||||||
|
#[derive(Copy, Clone, Default)]
|
||||||
|
#[repr(C)]
|
||||||
|
pub struct PgpuRect {
|
||||||
|
pub x0: f32,
|
||||||
|
pub y0: f32,
|
||||||
|
pub x1: f32,
|
||||||
|
pub y1: f32,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Computes the bounding box for the glyph after applying the specified
|
||||||
|
/// transform.
|
||||||
|
#[no_mangle]
|
||||||
|
pub unsafe extern "C" fn pgpu_glyph_bbox(glyph: *const PgpuGlyph, transform: &[f32; 6]) -> PgpuRect {
|
||||||
|
let transform = piet_scene::geometry::Affine::new(transform);
|
||||||
|
let rect = (*glyph).bbox(Some(transform));
|
||||||
|
PgpuRect {
|
||||||
|
x0: rect.min.x,
|
||||||
|
y0: rect.min.y,
|
||||||
|
x1: rect.max.x,
|
||||||
|
y1: rect.max.y,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Destroys the glyph.
|
||||||
|
#[no_mangle]
|
||||||
|
pub unsafe extern "C" fn pgpu_glyph_destroy(glyph: *mut PgpuGlyph) {
|
||||||
|
Box::from_raw(glyph);
|
||||||
|
}
|
222
pgpu-render/src/render.rs
Normal file
222
pgpu-render/src/render.rs
Normal file
|
@ -0,0 +1,222 @@
|
||||||
|
// Copyright 2022 The piet-gpu authors.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// https://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
//
|
||||||
|
// Also licensed under MIT license, at your choice.
|
||||||
|
|
||||||
|
use piet_gpu::{EncodedSceneRef, PixelFormat, RenderConfig};
|
||||||
|
use piet_gpu_hal::{QueryPool, Session};
|
||||||
|
use piet_scene::glyph::pinot::{types::Tag, FontDataRef};
|
||||||
|
use piet_scene::geometry::{Affine, Rect};
|
||||||
|
use piet_scene::glyph::{GlyphContext, GlyphProvider};
|
||||||
|
use piet_scene::resource::ResourceContext;
|
||||||
|
use piet_scene::scene::{Fragment, Scene};
|
||||||
|
|
||||||
|
/// State and resources for rendering a scene.
|
||||||
|
pub struct PgpuRenderer {
|
||||||
|
session: Session,
|
||||||
|
pgpu_renderer: Option<piet_gpu::Renderer>,
|
||||||
|
query_pool: QueryPool,
|
||||||
|
width: u32,
|
||||||
|
height: u32,
|
||||||
|
is_color: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PgpuRenderer {
|
||||||
|
pub fn new(device: &metal::DeviceRef, queue: &metal::CommandQueueRef) -> Self {
|
||||||
|
let piet_device = piet_gpu_hal::Device::new_from_raw_mtl(device, &queue);
|
||||||
|
let session = Session::new(piet_device);
|
||||||
|
let query_pool = session.create_query_pool(12).unwrap();
|
||||||
|
Self {
|
||||||
|
session,
|
||||||
|
pgpu_renderer: None,
|
||||||
|
query_pool,
|
||||||
|
width: 0,
|
||||||
|
height: 0,
|
||||||
|
is_color: false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn render(
|
||||||
|
&mut self,
|
||||||
|
scene: &PgpuScene,
|
||||||
|
cmdbuf: &metal::CommandBufferRef,
|
||||||
|
target: &metal::TextureRef,
|
||||||
|
) -> u32 {
|
||||||
|
let is_color = target.pixel_format() != metal::MTLPixelFormat::A8Unorm;
|
||||||
|
let width = target.width() as u32;
|
||||||
|
let height = target.height() as u32;
|
||||||
|
if self.pgpu_renderer.is_none()
|
||||||
|
|| self.width != width
|
||||||
|
|| self.height != height
|
||||||
|
|| self.is_color != is_color
|
||||||
|
{
|
||||||
|
self.width = width;
|
||||||
|
self.height = height;
|
||||||
|
self.is_color = is_color;
|
||||||
|
let format = if is_color {
|
||||||
|
PixelFormat::Rgba8
|
||||||
|
} else {
|
||||||
|
PixelFormat::A8
|
||||||
|
};
|
||||||
|
let config = RenderConfig::new(width as usize, height as usize).pixel_format(format);
|
||||||
|
unsafe {
|
||||||
|
self.pgpu_renderer =
|
||||||
|
piet_gpu::Renderer::new_from_config(&self.session, config, 1).ok();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
unsafe {
|
||||||
|
let mut cmd_buf = self.session.cmd_buf_from_raw_mtl(cmdbuf);
|
||||||
|
let dst_image = self
|
||||||
|
.session
|
||||||
|
.image_from_raw_mtl(target, self.width, self.height);
|
||||||
|
if let Some(renderer) = &mut self.pgpu_renderer {
|
||||||
|
renderer.upload_scene(&scene.encoded_scene(), 0).unwrap();
|
||||||
|
renderer.record(&mut cmd_buf, &self.query_pool, 0);
|
||||||
|
// TODO later: we can bind the destination image and avoid the copy.
|
||||||
|
cmd_buf.blit_image(&renderer.image_dev, &dst_image);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
0
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn release(&mut self, _id: u32) {
|
||||||
|
// TODO: worry about freeing resources / managing overlapping submits
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Encoded streams and resources describing a vector graphics scene.
|
||||||
|
pub struct PgpuScene {
|
||||||
|
scene: Scene,
|
||||||
|
rcx: ResourceContext,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PgpuScene {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Self {
|
||||||
|
scene: Scene::default(),
|
||||||
|
rcx: ResourceContext::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn build(&mut self) -> PgpuSceneBuilder {
|
||||||
|
self.rcx.advance();
|
||||||
|
PgpuSceneBuilder(piet_scene::scene::build_scene(
|
||||||
|
&mut self.scene,
|
||||||
|
&mut self.rcx,
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn encoded_scene<'a>(&'a self) -> EncodedSceneRef<'a, piet_scene::geometry::Affine> {
|
||||||
|
let d = self.scene.data();
|
||||||
|
EncodedSceneRef {
|
||||||
|
transform_stream: &d.transform_stream,
|
||||||
|
tag_stream: &d.tag_stream,
|
||||||
|
pathseg_stream: &d.pathseg_stream,
|
||||||
|
linewidth_stream: &d.linewidth_stream,
|
||||||
|
drawtag_stream: &d.drawtag_stream,
|
||||||
|
drawdata_stream: &d.drawdata_stream,
|
||||||
|
n_path: d.n_path,
|
||||||
|
n_pathseg: d.n_pathseg,
|
||||||
|
n_clip: d.n_clip,
|
||||||
|
ramp_data: self.rcx.ramp_data(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Builder for constructing an encoded scene.
|
||||||
|
pub struct PgpuSceneBuilder<'a>(piet_scene::scene::Builder<'a>);
|
||||||
|
|
||||||
|
impl<'a> PgpuSceneBuilder<'a> {
|
||||||
|
pub fn add_glyph(&mut self, glyph: &PgpuGlyph, transform: &piet_scene::geometry::Affine) {
|
||||||
|
self.0.push_transform(*transform);
|
||||||
|
self.0.append(&glyph.fragment);
|
||||||
|
self.0.pop_transform();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn finish(self) {
|
||||||
|
self.0.finish();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Tag and value for a font variation axis.
|
||||||
|
#[derive(Copy, Clone)]
|
||||||
|
#[repr(C)]
|
||||||
|
pub struct PgpuFontVariation {
|
||||||
|
/// Tag that specifies the axis.
|
||||||
|
pub tag: u32,
|
||||||
|
/// Requested setting for the axis.
|
||||||
|
pub value: f32,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Context for loading and scaling glyphs.
|
||||||
|
pub struct PgpuGlyphContext(GlyphContext);
|
||||||
|
|
||||||
|
impl PgpuGlyphContext {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Self(GlyphContext::new())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn new_provider<'a>(
|
||||||
|
&'a mut self,
|
||||||
|
font_data: &'a [u8],
|
||||||
|
font_index: u32,
|
||||||
|
font_id: u64,
|
||||||
|
ppem: f32,
|
||||||
|
hint: bool,
|
||||||
|
variations: &[PgpuFontVariation],
|
||||||
|
) -> Option<PgpuGlyphProvider> {
|
||||||
|
let font = FontDataRef::new(font_data).and_then(|f| f.get(font_index))?;
|
||||||
|
Some(PgpuGlyphProvider(
|
||||||
|
self.0.new_provider(
|
||||||
|
&font,
|
||||||
|
Some(font_id),
|
||||||
|
ppem,
|
||||||
|
hint,
|
||||||
|
variations
|
||||||
|
.iter()
|
||||||
|
.map(|variation| (Tag(variation.tag), variation.value)),
|
||||||
|
),
|
||||||
|
))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Context for loading a scaling glyphs from a specific font.
|
||||||
|
pub struct PgpuGlyphProvider<'a>(GlyphProvider<'a>);
|
||||||
|
|
||||||
|
impl<'a> PgpuGlyphProvider<'a> {
|
||||||
|
pub fn get(&mut self, gid: u16) -> Option<PgpuGlyph> {
|
||||||
|
let fragment = self.0.get(gid)?;
|
||||||
|
Some(PgpuGlyph { fragment })
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_color(&mut self, palette_index: u16, gid: u16) -> Option<PgpuGlyph> {
|
||||||
|
let fragment = self.0.get_color(palette_index, gid)?;
|
||||||
|
Some(PgpuGlyph { fragment })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Encoded (possibly color) outline for a glyph.
|
||||||
|
pub struct PgpuGlyph {
|
||||||
|
fragment: Fragment,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PgpuGlyph {
|
||||||
|
pub fn bbox(&self, transform: Option<Affine>) -> Rect {
|
||||||
|
if let Some(transform) = &transform {
|
||||||
|
Rect::from_points(self.fragment.points().iter().map(|p| p.transform(transform)))
|
||||||
|
} else {
|
||||||
|
Rect::from_points(self.fragment.points())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -19,7 +19,7 @@ use core::borrow::Borrow;
|
||||||
use core::hash::{Hash, Hasher};
|
use core::hash::{Hash, Hasher};
|
||||||
|
|
||||||
/// Two dimensional point.
|
/// Two dimensional point.
|
||||||
#[derive(Copy, Clone, PartialEq, PartialOrd, Default, Debug)]
|
#[derive(Copy, Clone, PartialEq, PartialOrd, Default, Debug, Pod, Zeroable)]
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
pub struct Point {
|
pub struct Point {
|
||||||
pub x: f32,
|
pub x: f32,
|
||||||
|
@ -168,7 +168,7 @@ impl std::ops::Mul for Affine {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Axis-aligned rectangle represented as minimum and maximum points.
|
/// Axis-aligned rectangle represented as minimum and maximum points.
|
||||||
#[derive(Copy, Clone, Default, Debug)]
|
#[derive(Copy, Clone, Default, Debug, Pod, Zeroable)]
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
pub struct Rect {
|
pub struct Rect {
|
||||||
pub min: Point,
|
pub min: Point,
|
||||||
|
|
|
@ -17,11 +17,15 @@
|
||||||
pub use pinot;
|
pub use pinot;
|
||||||
|
|
||||||
use crate::brush::{Brush, Color};
|
use crate::brush::{Brush, Color};
|
||||||
|
use crate::geometry::Affine;
|
||||||
use crate::path::Element;
|
use crate::path::Element;
|
||||||
use crate::scene::{build_fragment, Fill, Fragment};
|
use crate::scene::{build_fragment, Fill, Fragment};
|
||||||
|
|
||||||
use moscato::{Context, Scaler};
|
use moscato::{Context, Scaler};
|
||||||
use pinot::{types::Tag, FontRef};
|
use pinot::{types::Tag, FontRef};
|
||||||
|
|
||||||
|
use smallvec::SmallVec;
|
||||||
|
|
||||||
/// General context for creating scene fragments for glyph outlines.
|
/// General context for creating scene fragments for glyph outlines.
|
||||||
pub struct GlyphContext {
|
pub struct GlyphContext {
|
||||||
ctx: Context,
|
ctx: Context,
|
||||||
|
@ -99,40 +103,70 @@ impl<'a> GlyphProvider<'a> {
|
||||||
let glyph = self.scaler.color_glyph(palette_index, gid)?;
|
let glyph = self.scaler.color_glyph(palette_index, gid)?;
|
||||||
let mut fragment = Fragment::default();
|
let mut fragment = Fragment::default();
|
||||||
let mut builder = build_fragment(&mut fragment);
|
let mut builder = build_fragment(&mut fragment);
|
||||||
|
let mut xform_stack: SmallVec<[Affine; 8]> = SmallVec::new();
|
||||||
for command in glyph.commands() {
|
for command in glyph.commands() {
|
||||||
match command {
|
match command {
|
||||||
Command::PushTransform(xform) => {
|
Command::PushTransform(xform) => {
|
||||||
builder.push_transform(convert_transform(xform));
|
xform_stack.push(convert_transform(xform));
|
||||||
}
|
}
|
||||||
Command::PopTransform => builder.pop_transform(),
|
Command::PopTransform => { xform_stack.pop(); },
|
||||||
Command::PushClip(path_index) => {
|
Command::PushClip(path_index) => {
|
||||||
let path = glyph.path(*path_index)?;
|
let path = glyph.path(*path_index)?;
|
||||||
builder.push_layer(Default::default(), convert_path(path.elements()));
|
if let Some(xform) = xform_stack.last() {
|
||||||
|
builder.push_layer(
|
||||||
|
Default::default(),
|
||||||
|
convert_transformed_path(path.elements(), xform),
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
builder.push_layer(Default::default(), convert_path(path.elements()));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Command::PopClip => builder.pop_layer(),
|
Command::PopClip => builder.pop_layer(),
|
||||||
Command::PushLayer(bounds) => {
|
Command::PushLayer(bounds) => {
|
||||||
let rect = Rect {
|
let mut rect = Rect {
|
||||||
min: Point::new(bounds.min.x, bounds.min.y),
|
min: Point::new(bounds.min.x, bounds.min.y),
|
||||||
max: Point::new(bounds.max.x, bounds.max.y),
|
max: Point::new(bounds.max.x, bounds.max.y),
|
||||||
};
|
};
|
||||||
|
if let Some(xform) = xform_stack.last() {
|
||||||
|
rect.min = rect.min.transform(xform);
|
||||||
|
rect.max = rect.max.transform(xform);
|
||||||
|
}
|
||||||
builder.push_layer(Default::default(), rect.elements());
|
builder.push_layer(Default::default(), rect.elements());
|
||||||
}
|
}
|
||||||
Command::PopLayer => builder.pop_layer(),
|
Command::PopLayer => builder.pop_layer(),
|
||||||
Command::BeginBlend(bounds, mode) => {
|
Command::BeginBlend(bounds, mode) => {
|
||||||
let rect = Rect {
|
let mut rect = Rect {
|
||||||
min: Point::new(bounds.min.x, bounds.min.y),
|
min: Point::new(bounds.min.x, bounds.min.y),
|
||||||
max: Point::new(bounds.max.x, bounds.max.y),
|
max: Point::new(bounds.max.x, bounds.max.y),
|
||||||
};
|
};
|
||||||
|
if let Some(xform) = xform_stack.last() {
|
||||||
|
rect.min = rect.min.transform(xform);
|
||||||
|
rect.max = rect.max.transform(xform);
|
||||||
|
}
|
||||||
builder.push_layer(convert_blend(*mode), rect.elements())
|
builder.push_layer(convert_blend(*mode), rect.elements())
|
||||||
}
|
}
|
||||||
Command::EndBlend => builder.pop_layer(),
|
Command::EndBlend => builder.pop_layer(),
|
||||||
Command::SimpleFill(path_index, brush, xform) => {
|
Command::SimpleFill(path_index, brush, brush_xform) => {
|
||||||
let path = glyph.path(*path_index)?;
|
let path = glyph.path(*path_index)?;
|
||||||
let brush = convert_brush(brush);
|
let brush = convert_brush(brush);
|
||||||
let xform = xform.map(|xform| convert_transform(&xform));
|
let brush_xform = brush_xform.map(|xform| convert_transform(&xform));
|
||||||
builder.fill(Fill::NonZero, &brush, xform, convert_path(path.elements()));
|
if let Some(xform) = xform_stack.last() {
|
||||||
|
builder.fill(
|
||||||
|
Fill::NonZero,
|
||||||
|
&brush,
|
||||||
|
brush_xform,
|
||||||
|
convert_transformed_path(path.elements(), xform),
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
builder.fill(
|
||||||
|
Fill::NonZero,
|
||||||
|
&brush,
|
||||||
|
brush_xform,
|
||||||
|
convert_path(path.elements()),
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Command::Fill(brush, xform) => {
|
Command::Fill(brush, brush_xform) => {
|
||||||
// TODO: this needs to compute a bounding box for
|
// TODO: this needs to compute a bounding box for
|
||||||
// the parent clips
|
// the parent clips
|
||||||
}
|
}
|
||||||
|
@ -161,6 +195,28 @@ fn convert_path(
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn convert_transformed_path(
|
||||||
|
path: impl Iterator<Item = moscato::Element> + Clone,
|
||||||
|
xform: &Affine,
|
||||||
|
) -> impl Iterator<Item = Element> + Clone {
|
||||||
|
use crate::geometry::Point;
|
||||||
|
let xform = *xform;
|
||||||
|
path.map(move |el| match el {
|
||||||
|
moscato::Element::MoveTo(p0) => Element::MoveTo(Point::new(p0.x, p0.y).transform(&xform)),
|
||||||
|
moscato::Element::LineTo(p0) => Element::LineTo(Point::new(p0.x, p0.y).transform(&xform)),
|
||||||
|
moscato::Element::QuadTo(p0, p1) => Element::QuadTo(
|
||||||
|
Point::new(p0.x, p0.y).transform(&xform),
|
||||||
|
Point::new(p1.x, p1.y).transform(&xform),
|
||||||
|
),
|
||||||
|
moscato::Element::CurveTo(p0, p1, p2) => Element::CurveTo(
|
||||||
|
Point::new(p0.x, p0.y).transform(&xform),
|
||||||
|
Point::new(p1.x, p1.y).transform(&xform),
|
||||||
|
Point::new(p2.x, p2.y).transform(&xform),
|
||||||
|
),
|
||||||
|
moscato::Element::Close => Element::Close,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
fn convert_blend(mode: moscato::CompositeMode) -> crate::scene::Blend {
|
fn convert_blend(mode: moscato::CompositeMode) -> crate::scene::Blend {
|
||||||
use crate::scene::{Blend, Compose, Mix};
|
use crate::scene::{Blend, Compose, Mix};
|
||||||
use moscato::CompositeMode;
|
use moscato::CompositeMode;
|
||||||
|
|
|
@ -23,8 +23,9 @@ pub use builder::{build_fragment, build_scene, Builder};
|
||||||
pub use style::*;
|
pub use style::*;
|
||||||
|
|
||||||
use super::brush::*;
|
use super::brush::*;
|
||||||
use super::geometry::{Affine, Rect};
|
use super::geometry::{Affine, Point, Rect};
|
||||||
use super::path::Element;
|
use super::path::Element;
|
||||||
|
|
||||||
use core::ops::Range;
|
use core::ops::Range;
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
|
@ -94,6 +95,12 @@ pub struct Fragment {
|
||||||
resources: FragmentResources,
|
resources: FragmentResources,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Fragment {
|
||||||
|
pub fn points(&self) -> &[Point] {
|
||||||
|
bytemuck::cast_slice(&self.data.pathseg_stream)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
struct FragmentResources {
|
struct FragmentResources {
|
||||||
patches: Vec<ResourcePatch>,
|
patches: Vec<ResourcePatch>,
|
||||||
|
|
Loading…
Reference in a new issue