Compare commits
10 Commits
a29dd979c1
...
5fa9e8f883
Author | SHA1 | Date |
---|---|---|
|
5fa9e8f883 | |
|
4ac0bbae7e | |
|
1b070fc0db | |
|
e5912d7d70 | |
![]() |
4968e819c0 | |
![]() |
30419d0766 | |
![]() |
dc6034f666 | |
![]() |
91d821a1f2 | |
![]() |
f1bce9fd62 | |
![]() |
cb4eb597c3 |
File diff suppressed because it is too large
Load Diff
10
c/Cargo.toml
10
c/Cargo.toml
|
@ -4,11 +4,8 @@ version = "0.1.0"
|
|||
authors = ["Patrick Walton <pcwalton@mimiga.net>"]
|
||||
edition = "2018"
|
||||
|
||||
[features]
|
||||
capi = []
|
||||
|
||||
[lib]
|
||||
crate-type = ["staticlib"]
|
||||
crate-type = ["staticlib", "cdylib"]
|
||||
name = "pathfinder"
|
||||
|
||||
[dependencies]
|
||||
|
@ -16,8 +13,13 @@ font-kit = "0.6"
|
|||
foreign-types = "0.3"
|
||||
gl = "0.14"
|
||||
libc = "0.2"
|
||||
simple_logger = "4.3"
|
||||
usvg = "0.9"
|
||||
|
||||
[dependencies.log]
|
||||
version = "0.4"
|
||||
features = ["max_level_info"]
|
||||
|
||||
[dependencies.pathfinder_canvas]
|
||||
features = ["pf-text"]
|
||||
path = "../canvas"
|
||||
|
|
101
c/src/lib.rs
101
c/src/lib.rs
|
@ -10,6 +10,7 @@
|
|||
|
||||
//! C bindings to Pathfinder.
|
||||
|
||||
use font_kit::font::Font;
|
||||
use font_kit::handle::Handle;
|
||||
use gl;
|
||||
use pathfinder_canvas::{Canvas, CanvasFontContext, CanvasRenderingContext2D, FillStyle, LineJoin};
|
||||
|
@ -27,6 +28,7 @@ use pathfinder_gpu::Device;
|
|||
use pathfinder_resources::ResourceLoader;
|
||||
use pathfinder_resources::fs::FilesystemResourceLoader;
|
||||
use pathfinder_resources::embedded::EmbeddedResourceLoader;
|
||||
use pathfinder_renderer::concurrent::executor::SequentialExecutor;
|
||||
use pathfinder_renderer::concurrent::rayon::RayonExecutor;
|
||||
use pathfinder_renderer::concurrent::scene_proxy::SceneProxy;
|
||||
use pathfinder_renderer::gpu::options::{DestFramebuffer, RendererLevel};
|
||||
|
@ -39,7 +41,7 @@ use pathfinder_svg::SVGScene;
|
|||
use std::ffi::CString;
|
||||
use std::os::raw::{c_char, c_void};
|
||||
use std::path::PathBuf;
|
||||
use std::ptr;
|
||||
use std::ptr::{self, NonNull};
|
||||
use std::slice;
|
||||
use std::str;
|
||||
use usvg::{Options, Tree};
|
||||
|
@ -51,6 +53,11 @@ use metal::{self, CoreAnimationDrawableRef, DeviceRef as NativeMetalDeviceRef};
|
|||
#[cfg(all(target_os = "macos", not(feature = "pf-gl")))]
|
||||
use pathfinder_metal::MetalDevice;
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "system" fn init_logging() {
|
||||
simple_logger::init_with_env().unwrap();
|
||||
}
|
||||
|
||||
// Constants
|
||||
|
||||
// `canvas`
|
||||
|
@ -102,6 +109,7 @@ pub type FKHandleRef = *mut Handle;
|
|||
pub type PFCanvasRef = *mut CanvasRenderingContext2D;
|
||||
pub type PFPathRef = *mut Path2D;
|
||||
pub type PFCanvasFontContextRef = *mut CanvasFontContext;
|
||||
pub type FKFontRef = NonNull<Font>;
|
||||
pub type PFFillStyleRef = *mut FillStyle;
|
||||
pub type PFLineCap = u8;
|
||||
pub type PFLineJoin = u8;
|
||||
|
@ -272,6 +280,13 @@ pub unsafe extern "C" fn PFCanvasCreateScene(canvas: PFCanvasRef) -> PFSceneRef
|
|||
Box::into_raw(Box::new(Box::from_raw(canvas).into_canvas().into_scene()))
|
||||
}
|
||||
|
||||
// Extensions
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn PFCanvasClear(canvas: PFCanvasRef) {
|
||||
(*canvas).clear()
|
||||
}
|
||||
|
||||
// Drawing rectangles
|
||||
|
||||
#[no_mangle]
|
||||
|
@ -284,6 +299,11 @@ pub unsafe extern "C" fn PFCanvasStrokeRect(canvas: PFCanvasRef, rect: *const PF
|
|||
(*canvas).stroke_rect((*rect).to_rust())
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn PFCanvasClearRect(canvas: PFCanvasRef, rect: *const PFRectF) {
|
||||
(*canvas).clear_rect((*rect).to_rust())
|
||||
}
|
||||
|
||||
// Drawing text
|
||||
|
||||
#[no_mangle]
|
||||
|
@ -306,9 +326,8 @@ pub unsafe extern "C" fn PFCanvasStrokeText(canvas: PFCanvasRef,
|
|||
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()
|
||||
out_text_metrics: NonNull<PFTextMetrics>) {
|
||||
out_text_metrics.write((*canvas).measure_text(to_rust_string(&string, string_len)).to_c())
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
|
@ -375,10 +394,33 @@ pub unsafe extern "C" fn PFCanvasSetLineDashOffset(canvas: PFCanvasRef, new_offs
|
|||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn PFCanvasSetFontByPostScriptName(canvas: PFCanvasRef,
|
||||
pub unsafe extern "C" fn PFCanvasFontContextGetFontByPostScriptName(context: PFCanvasFontContextRef,
|
||||
postscript_name: *const c_char,
|
||||
postscript_name_len: usize) {
|
||||
(*canvas).set_font(to_rust_string(&postscript_name, postscript_name_len))
|
||||
postscript_name_len: usize) -> Option<FKFontRef> {
|
||||
let name = to_rust_string(&postscript_name, postscript_name_len);
|
||||
match (*context).get_font_by_postscript_name(name) {
|
||||
Ok(font) => NonNull::new(Box::into_raw(Box::new(font))),
|
||||
Err(e) => {
|
||||
log::error!("Failed to get font {:?}: {:?}", name, e);
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn FKFontDestroy(font: FKFontRef) {
|
||||
drop(Box::from_raw(font.as_ptr()))
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn PFCanvasSetFont(canvas: PFCanvasRef, font: FKFontRef) -> i32 {
|
||||
match (*canvas).set_font(font.as_ref().clone()) {
|
||||
Ok(_) => 0,
|
||||
Err(e) => {
|
||||
log::error!("Failed to set font: {:?}", e);
|
||||
1
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
|
@ -621,6 +663,33 @@ pub unsafe extern "C" fn PFGLRendererGetDevice(renderer: PFGLRendererRef) -> PFG
|
|||
(*renderer).device_mut()
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn PFGLRendererSetViewport(renderer: PFGLRendererRef, new_viewport: PFRectI) -> i32 {
|
||||
match (*renderer).options_mut().dest {
|
||||
DestFramebuffer::Default { ref mut viewport, .. } => {
|
||||
*viewport = new_viewport.to_rust();
|
||||
0
|
||||
}
|
||||
DestFramebuffer::Other(_) => 1,
|
||||
}
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn PFGLRendererSetWindowSize(renderer: PFGLRendererRef, new_window_size: PFVector2I) -> i32 {
|
||||
match (*renderer).options_mut().dest {
|
||||
DestFramebuffer::Default { ref mut window_size, .. } => {
|
||||
*window_size = new_window_size.to_rust();
|
||||
0
|
||||
}
|
||||
DestFramebuffer::Other(_) => 1,
|
||||
}
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn PFGLRendererDestFramebufferSizeChanged(renderer: PFGLRendererRef) {
|
||||
(*renderer).dest_framebuffer_size_changed()
|
||||
}
|
||||
|
||||
#[cfg(all(target_os = "macos", not(feature = "pf-gl")))]
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn PFMetalDestFramebufferCreateFullWindow(window_size: *const PFVector2I)
|
||||
|
@ -785,12 +854,18 @@ pub unsafe extern "C" fn PFSceneDestroy(scene: PFSceneRef) {
|
|||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn PFSceneProxyCreateFromSceneAndRayonExecutor(scene: PFSceneRef,
|
||||
level: PFRendererLevel)
|
||||
-> PFSceneProxyRef {
|
||||
Box::into_raw(Box::new(SceneProxy::from_scene(*Box::from_raw(scene),
|
||||
to_rust_renderer_level(level),
|
||||
RayonExecutor)))
|
||||
pub unsafe extern "C" fn PFSceneProxyCreateWithSequentialExecutor(level: PFRendererLevel) -> PFSceneProxyRef {
|
||||
Box::into_raw(Box::new(SceneProxy::new(to_rust_renderer_level(level), SequentialExecutor)))
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn PFSceneProxyCreateWithRayonExecutor(level: PFRendererLevel) -> PFSceneProxyRef {
|
||||
Box::into_raw(Box::new(SceneProxy::new(to_rust_renderer_level(level), RayonExecutor)))
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn PFSceneProxyReplaceScene(scene_proxy: PFSceneProxyRef, scene: PFSceneRef) {
|
||||
(*scene_proxy).replace_scene(*Box::from_raw(scene))
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
|
||||
use crate::{CanvasRenderingContext2D, State, TextAlign, TextBaseline};
|
||||
use font_kit::canvas::RasterizationOptions;
|
||||
use font_kit::error::{FontLoadingError, SelectionError};
|
||||
use font_kit::family_name::FamilyName;
|
||||
use font_kit::handle::Handle;
|
||||
use font_kit::hinting::HintingOptions;
|
||||
|
@ -103,9 +104,10 @@ impl CanvasRenderingContext2D {
|
|||
}
|
||||
|
||||
#[inline]
|
||||
pub fn set_font<FC>(&mut self, font_collection: FC) where FC: IntoFontCollection {
|
||||
let font_collection = font_collection.into_font_collection(&self.canvas_font_context);
|
||||
pub fn set_font<FC>(&mut self, font_collection: FC) -> Result<(), FontError> where FC: IntoFontCollection {
|
||||
let font_collection = font_collection.into_font_collection(&self.canvas_font_context)?;
|
||||
self.current_state.font_collection = font_collection;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
|
@ -152,13 +154,7 @@ pub trait ToTextLayout {
|
|||
|
||||
impl ToTextLayout for str {
|
||||
fn layout(&self, state: CanvasState) -> Cow<TextMetrics> {
|
||||
let skribo_layout = Rc::new(skribo::layout(&TextStyle { size: state.0.font_size },
|
||||
&state.0.font_collection,
|
||||
self));
|
||||
Cow::Owned(TextMetrics::new(skribo_layout,
|
||||
state.0.font_size,
|
||||
state.0.text_align,
|
||||
state.0.text_baseline))
|
||||
Cow::Owned(TextMetrics::layout(self, &state.0.font_collection, state.0.font_size, state.0.text_align, state.0.text_baseline))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -188,6 +184,13 @@ impl ToTextLayout for TextMetrics {
|
|||
#[derive(Clone)]
|
||||
pub struct CanvasFontContext(pub(crate) Rc<RefCell<CanvasFontContextData>>);
|
||||
|
||||
/// The reason a font could not be loaded
|
||||
#[derive(Debug)]
|
||||
pub enum FontError {
|
||||
NotFound(SelectionError),
|
||||
LoadError(FontLoadingError),
|
||||
}
|
||||
|
||||
pub(super) struct CanvasFontContextData {
|
||||
pub(super) font_context: FontContext<Font>,
|
||||
#[allow(dead_code)]
|
||||
|
@ -224,16 +227,15 @@ impl CanvasFontContext {
|
|||
CanvasFontContext::new(Arc::new(MemSource::from_fonts(fonts).unwrap()))
|
||||
}
|
||||
|
||||
fn get_font_by_postscript_name(&self, postscript_name: &str) -> Font {
|
||||
pub fn get_font_by_postscript_name(&self, postscript_name: &str) -> Result<Font, FontError> {
|
||||
let this = self.0.borrow();
|
||||
if let Some(cached_font) = this.font_context.get_cached_font(postscript_name) {
|
||||
return (*cached_font).clone();
|
||||
return Ok((*cached_font).clone());
|
||||
}
|
||||
this.font_source
|
||||
.select_by_postscript_name(postscript_name)
|
||||
.expect("Couldn't find a font with that PostScript name!")
|
||||
.load()
|
||||
.expect("Failed to load the font!")
|
||||
.map_err(FontError::NotFound)?
|
||||
.load().map_err(FontError::LoadError)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -314,6 +316,13 @@ impl TextMetrics {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn layout(string: &str, font_collection: &FontCollection, font_size: f32, text_align: TextAlign, text_baseline: TextBaseline) -> TextMetrics {
|
||||
let skribo_layout = Rc::new(skribo::layout(&TextStyle { size: font_size },
|
||||
font_collection,
|
||||
string));
|
||||
TextMetrics::new(skribo_layout, font_size, text_align, text_baseline)
|
||||
}
|
||||
|
||||
pub fn text_x_offset(&self) -> f32 {
|
||||
if self.text_x_offset.get().is_none() {
|
||||
self.text_x_offset.set(Some(match self.align {
|
||||
|
@ -523,46 +532,46 @@ impl VerticalMetrics {
|
|||
/// Various things that can be conveniently converted into font collections for use with
|
||||
/// `CanvasRenderingContext2D::set_font()`.
|
||||
pub trait IntoFontCollection {
|
||||
fn into_font_collection(self, font_context: &CanvasFontContext) -> Arc<FontCollection>;
|
||||
fn into_font_collection(self, font_context: &CanvasFontContext) -> Result<Arc<FontCollection>, FontError>;
|
||||
}
|
||||
|
||||
impl IntoFontCollection for Arc<FontCollection> {
|
||||
#[inline]
|
||||
fn into_font_collection(self, _: &CanvasFontContext) -> Arc<FontCollection> {
|
||||
self
|
||||
fn into_font_collection(self, _: &CanvasFontContext) -> Result<Arc<FontCollection>, FontError> {
|
||||
Ok(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl IntoFontCollection for FontFamily {
|
||||
#[inline]
|
||||
fn into_font_collection(self, _: &CanvasFontContext) -> Arc<FontCollection> {
|
||||
fn into_font_collection(self, _: &CanvasFontContext) -> Result<Arc<FontCollection>, FontError> {
|
||||
let mut font_collection = FontCollection::new();
|
||||
font_collection.add_family(self);
|
||||
Arc::new(font_collection)
|
||||
Ok(Arc::new(font_collection))
|
||||
}
|
||||
}
|
||||
|
||||
impl IntoFontCollection for Vec<FontFamily> {
|
||||
#[inline]
|
||||
fn into_font_collection(self, _: &CanvasFontContext) -> Arc<FontCollection> {
|
||||
fn into_font_collection(self, _: &CanvasFontContext) -> Result<Arc<FontCollection>, FontError> {
|
||||
let mut font_collection = FontCollection::new();
|
||||
for family in self {
|
||||
font_collection.add_family(family);
|
||||
}
|
||||
Arc::new(font_collection)
|
||||
Ok(Arc::new(font_collection))
|
||||
}
|
||||
}
|
||||
|
||||
impl IntoFontCollection for Font {
|
||||
#[inline]
|
||||
fn into_font_collection(self, context: &CanvasFontContext) -> Arc<FontCollection> {
|
||||
FontFamily::new_from_font(self).into_font_collection(context)
|
||||
fn into_font_collection(self, context: &CanvasFontContext) -> Result<Arc<FontCollection>, FontError> {
|
||||
Ok(FontFamily::new_from_font(self).into_font_collection(context)?)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> IntoFontCollection for &'a [Font] {
|
||||
#[inline]
|
||||
fn into_font_collection(self, context: &CanvasFontContext) -> Arc<FontCollection> {
|
||||
fn into_font_collection(self, context: &CanvasFontContext) -> Result<Arc<FontCollection>, FontError> {
|
||||
let mut family = FontFamily::new();
|
||||
for font in self {
|
||||
family.add_font(FontRef::new((*font).clone()))
|
||||
|
@ -573,19 +582,19 @@ impl<'a> IntoFontCollection for &'a [Font] {
|
|||
|
||||
impl<'a> IntoFontCollection for &'a str {
|
||||
#[inline]
|
||||
fn into_font_collection(self, context: &CanvasFontContext) -> Arc<FontCollection> {
|
||||
context.get_font_by_postscript_name(self).into_font_collection(context)
|
||||
fn into_font_collection(self, context: &CanvasFontContext) -> Result<Arc<FontCollection>, FontError> {
|
||||
context.get_font_by_postscript_name(self)?.into_font_collection(context)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'b> IntoFontCollection for &'a [&'b str] {
|
||||
#[inline]
|
||||
fn into_font_collection(self, context: &CanvasFontContext) -> Arc<FontCollection> {
|
||||
fn into_font_collection(self, context: &CanvasFontContext) -> Result<Arc<FontCollection>, FontError> {
|
||||
let mut font_collection = FontCollection::new();
|
||||
for postscript_name in self {
|
||||
let font = context.get_font_by_postscript_name(postscript_name);
|
||||
let font = context.get_font_by_postscript_name(postscript_name)?;
|
||||
font_collection.add_family(FontFamily::new_from_font(font));
|
||||
}
|
||||
Arc::new(font_collection)
|
||||
Ok(Arc::new(font_collection))
|
||||
}
|
||||
}
|
||||
|
|
|
@ -367,14 +367,14 @@ impl Contour {
|
|||
return Contour::from_rect(rect);
|
||||
}
|
||||
let radius = radius.min(rect.size() * 0.5);
|
||||
let contol_point_offset = radius * QUARTER_ARC_CP_FROM_OUTSIDE;
|
||||
let control_point_offset = radius * QUARTER_ARC_CP_FROM_OUTSIDE;
|
||||
|
||||
let mut contour = Contour::with_capacity(8);
|
||||
|
||||
// upper left corner
|
||||
{
|
||||
let p0 = rect.origin();
|
||||
let p1 = p0 + contol_point_offset;
|
||||
let p1 = p0 + control_point_offset;
|
||||
let p2 = p0 + radius;
|
||||
contour.push_endpoint(vec2f(p0.x(), p2.y()));
|
||||
contour.push_cubic(
|
||||
|
@ -387,7 +387,7 @@ impl Contour {
|
|||
// upper right
|
||||
{
|
||||
let p0 = rect.upper_right();
|
||||
let p1 = p0 + contol_point_offset * vec2f(-1.0, 1.0);
|
||||
let p1 = p0 + control_point_offset * vec2f(-1.0, 1.0);
|
||||
let p2 = p0 + radius * vec2f(-1.0, 1.0);
|
||||
contour.push_endpoint(vec2f(p2.x(), p0.y()));
|
||||
contour.push_cubic(
|
||||
|
@ -400,7 +400,7 @@ impl Contour {
|
|||
// lower right
|
||||
{
|
||||
let p0 = rect.lower_right();
|
||||
let p1 = p0 + contol_point_offset * vec2f(-1.0, -1.0);
|
||||
let p1 = p0 + control_point_offset * vec2f(-1.0, -1.0);
|
||||
let p2 = p0 + radius * vec2f(-1.0, -1.0);
|
||||
contour.push_endpoint(vec2f(p0.x(), p2.y()));
|
||||
contour.push_cubic(
|
||||
|
@ -413,7 +413,7 @@ impl Contour {
|
|||
// lower left
|
||||
{
|
||||
let p0 = rect.lower_left();
|
||||
let p1 = p0 + contol_point_offset * vec2f(1.0, -1.0);
|
||||
let p1 = p0 + control_point_offset * vec2f(1.0, -1.0);
|
||||
let p2 = p0 + radius * vec2f(1.0, -1.0);
|
||||
contour.push_endpoint(vec2f(p2.x(), p0.y()));
|
||||
contour.push_cubic(
|
||||
|
|
|
@ -50,8 +50,8 @@ use std::path::PathBuf;
|
|||
use std::thread;
|
||||
use std::time::Duration;
|
||||
use usvg::{Options as UsvgOptions, Tree as SvgTree};
|
||||
use pdf::file::File as PdfFile;
|
||||
use pdf_render::Cache as PdfRenderCache;
|
||||
use pdf::file::{CachedFile, FileOptions};
|
||||
use pdf_render::{Cache as PdfRenderCache, SceneBackend};
|
||||
|
||||
#[cfg(any(not(target_os = "macos"), feature = "pf-gl"))]
|
||||
use pathfinder_gl::GLDevice as DeviceImpl;
|
||||
|
@ -86,7 +86,7 @@ mod ui;
|
|||
enum Content {
|
||||
Svg(SvgTree),
|
||||
Pdf {
|
||||
file: PdfFile<Vec<u8>>,
|
||||
file: CachedFile<Vec<u8>>,
|
||||
cache: PdfRenderCache,
|
||||
page_nr: u32
|
||||
}
|
||||
|
@ -773,8 +773,9 @@ impl Content {
|
|||
}
|
||||
Content::Pdf { ref file, ref mut cache, page_nr } => {
|
||||
let page = file.get_page(page_nr).expect("no such page");
|
||||
let (scene, _) = cache.render_page(file, &page, Transform2F::default()).unwrap();
|
||||
(scene, String::new())
|
||||
let mut backend = SceneBackend::new(cache);
|
||||
pdf_render::render_page(&mut backend, &file.resolver(), &page, Transform2F::default()).unwrap();
|
||||
(backend.finish(), String::new())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -791,7 +792,7 @@ fn load_scene(resource_loader: &dyn ResourceLoader,
|
|||
|
||||
if let Ok(tree) = SvgTree::from_data(&data, &UsvgOptions::default()) {
|
||||
Content::Svg(tree)
|
||||
} else if let Ok(file) = PdfFile::from_data(data) {
|
||||
} else if let Ok(file) = FileOptions::cached().load(data) {
|
||||
Content::Pdf { file, cache: PdfRenderCache::new(), page_nr: 0 }
|
||||
} else {
|
||||
panic!("can't load data");
|
||||
|
|
|
@ -25,6 +25,7 @@ use sdl2::keyboard::Keycode;
|
|||
use sdl2::video::GLProfile;
|
||||
use std::iter;
|
||||
use std::sync::Arc;
|
||||
use std::time::{Duration, Instant};
|
||||
|
||||
fn main() {
|
||||
// Set up SDL2.
|
||||
|
@ -34,7 +35,10 @@ fn main() {
|
|||
// 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);
|
||||
gl_attributes.set_context_version(4, 1);
|
||||
gl_attributes.set_context_flags()
|
||||
.forward_compatible()
|
||||
.set();
|
||||
|
||||
// Open a window.
|
||||
let window_size = vec2i(640, 480);
|
||||
|
@ -66,17 +70,32 @@ fn main() {
|
|||
|
||||
// Wait for a keypress.
|
||||
let mut event_pump = sdl_context.event_pump().unwrap();
|
||||
let mut n = 0;
|
||||
let mut last_update = Instant::now();
|
||||
let mut fps_buf = String::new();
|
||||
loop {
|
||||
match event_pump.wait_event() {
|
||||
Event::Quit {..} | Event::KeyDown { keycode: Some(Keycode::Escape), .. } => return,
|
||||
Event::Window { win_event: WindowEvent::Exposed, .. } => {
|
||||
match event_pump.poll_event() {
|
||||
Some(Event::Quit {..} | Event::KeyDown { keycode: Some(Keycode::Escape), .. }) => return,
|
||||
Some(Event::Window { win_event: WindowEvent::Exposed, .. }) | None => {
|
||||
// Make a canvas.
|
||||
let mut canvas = Canvas::new(window_size.to_f32()).get_context_2d(font_context.clone());
|
||||
|
||||
// Draw the text.
|
||||
canvas.set_font("Overpass-Regular");
|
||||
canvas.set_font("Overpass-Regular").unwrap();
|
||||
canvas.set_font_size(32.0);
|
||||
let now = Instant::now();
|
||||
let elapsed = now.duration_since(last_update);
|
||||
if elapsed >= Duration::from_millis(50) {
|
||||
last_update = now;
|
||||
let fps = (n as f64) * ((Duration::from_secs(1).as_micros() as f64) / (elapsed.as_micros() as f64));
|
||||
fps_buf.clear();
|
||||
fps_buf.push_str("FPS: ");
|
||||
use std::fmt::Write;
|
||||
write!(fps_buf, "{fps:.2}").unwrap();
|
||||
n = 0;
|
||||
}
|
||||
canvas.fill_text("Hello Pathfinder!", vec2f(32.0, 48.0));
|
||||
canvas.fill_text(&fps_buf, vec2f(32.0, 96.0));
|
||||
canvas.set_text_align(TextAlign::Right);
|
||||
canvas.stroke_text("Goodbye Pathfinder!", vec2f(608.0, 464.0));
|
||||
|
||||
|
@ -86,6 +105,8 @@ fn main() {
|
|||
RayonExecutor);
|
||||
scene.build_and_render(&mut renderer, BuildOptions::default());
|
||||
window.gl_swap_window();
|
||||
|
||||
n += 1;
|
||||
},
|
||||
_ => {}
|
||||
}
|
||||
|
|
|
@ -31,5 +31,5 @@ export SPIRVCROSS=spirv-cross.exe
|
|||
|
||||
Note: the Windows versions of `glslangValidator` and `spirv-cross` may change
|
||||
the line endings of the generated output. Please take care to ensure that
|
||||
unintended line ending changes aren't accidentally commited, for instance by
|
||||
unintended line ending changes aren't accidentally committed, for instance by
|
||||
[configuring Git to automatically handle line endings](https://docs.github.com/en/github/using-git/configuring-git-to-handle-line-endings#global-settings-for-line-endings).
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "pathfinder_simd"
|
||||
version = "0.5.2"
|
||||
version = "0.5.3"
|
||||
edition = "2018"
|
||||
authors = ["Patrick Walton <pcwalton@mimiga.net>"]
|
||||
build = "build.rs"
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
|
||||
use std::arch::aarch64::{self, float32x2_t, float32x4_t, int32x2_t, int32x4_t};
|
||||
use std::arch::aarch64::{uint32x2_t, uint32x4_t};
|
||||
use std::intrinsics::simd::*;
|
||||
use std::f32;
|
||||
use std::fmt::{self, Debug, Formatter};
|
||||
use std::mem;
|
||||
|
@ -869,33 +870,6 @@ impl Index<usize> for U32x4 {
|
|||
}
|
||||
}
|
||||
|
||||
// Intrinsics
|
||||
|
||||
extern "platform-intrinsic" {
|
||||
fn simd_add<T>(x: T, y: T) -> T;
|
||||
fn simd_div<T>(x: T, y: T) -> T;
|
||||
fn simd_mul<T>(x: T, y: T) -> T;
|
||||
fn simd_sub<T>(x: T, y: T) -> T;
|
||||
|
||||
fn simd_shr<T>(x: T, y: T) -> T;
|
||||
|
||||
fn simd_and<T>(x: T, y: T) -> T;
|
||||
fn simd_or<T>(x: T, y: T) -> T;
|
||||
fn simd_xor<T>(x: T, y: T) -> T;
|
||||
|
||||
fn simd_fmin<T>(x: T, y: T) -> T;
|
||||
fn simd_fmax<T>(x: T, y: T) -> T;
|
||||
|
||||
fn simd_eq<T, U>(x: T, y: T) -> U;
|
||||
fn simd_gt<T, U>(x: T, y: T) -> U;
|
||||
fn simd_le<T, U>(x: T, y: T) -> U;
|
||||
fn simd_lt<T, U>(x: T, y: T) -> U;
|
||||
|
||||
fn simd_shuffle<T, I, U>(x: T, y: T, idx: I) -> U;
|
||||
|
||||
fn simd_cast<T, U>(x: T) -> U;
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
#[link_name = "llvm.fabs.v2f32"]
|
||||
fn fabs_v2f32(a: float32x2_t) -> float32x2_t;
|
||||
|
|
|
@ -8,8 +8,8 @@
|
|||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
#![cfg_attr(pf_rustc_nightly, feature(link_llvm_intrinsics, platform_intrinsics))]
|
||||
#![cfg_attr(all(target_arch = "aarch64", pf_rustc_nightly), feature(stdarch_arm_crc32))]
|
||||
#![cfg_attr(pf_rustc_nightly, allow(internal_features))]
|
||||
#![cfg_attr(pf_rustc_nightly, feature(link_llvm_intrinsics, core_intrinsics))]
|
||||
#![cfg_attr(pf_rustc_nightly, feature(simd_ffi))]
|
||||
|
||||
//! A minimal SIMD abstraction, usable outside of Pathfinder.
|
||||
|
|
Loading…
Reference in New Issue