Improve C bindings and canvas_text example

This commit is contained in:
Michael Pfaff 2024-06-18 18:01:18 -04:00
parent 30419d0766
commit e5912d7d70
3 changed files with 65 additions and 7 deletions

View File

@ -8,7 +8,7 @@ edition = "2018"
capi = [] capi = []
[lib] [lib]
crate-type = ["staticlib"] crate-type = ["staticlib", "cdylib"]
name = "pathfinder" name = "pathfinder"
[dependencies] [dependencies]
@ -16,8 +16,13 @@ font-kit = "0.6"
foreign-types = "0.3" foreign-types = "0.3"
gl = "0.14" gl = "0.14"
libc = "0.2" libc = "0.2"
simple_logger = "4.3"
usvg = "0.9" usvg = "0.9"
[dependencies.log]
version = "0.4"
features = ["max_level_info"]
[dependencies.pathfinder_canvas] [dependencies.pathfinder_canvas]
features = ["pf-text"] features = ["pf-text"]
path = "../canvas" path = "../canvas"

View File

@ -27,6 +27,7 @@ use pathfinder_gpu::Device;
use pathfinder_resources::ResourceLoader; use pathfinder_resources::ResourceLoader;
use pathfinder_resources::fs::FilesystemResourceLoader; use pathfinder_resources::fs::FilesystemResourceLoader;
use pathfinder_resources::embedded::EmbeddedResourceLoader; use pathfinder_resources::embedded::EmbeddedResourceLoader;
use pathfinder_renderer::concurrent::executor::SequentialExecutor;
use pathfinder_renderer::concurrent::rayon::RayonExecutor; use pathfinder_renderer::concurrent::rayon::RayonExecutor;
use pathfinder_renderer::concurrent::scene_proxy::SceneProxy; use pathfinder_renderer::concurrent::scene_proxy::SceneProxy;
use pathfinder_renderer::gpu::options::{DestFramebuffer, RendererLevel}; use pathfinder_renderer::gpu::options::{DestFramebuffer, RendererLevel};
@ -51,6 +52,11 @@ use metal::{self, CoreAnimationDrawableRef, DeviceRef as NativeMetalDeviceRef};
#[cfg(all(target_os = "macos", not(feature = "pf-gl")))] #[cfg(all(target_os = "macos", not(feature = "pf-gl")))]
use pathfinder_metal::MetalDevice; use pathfinder_metal::MetalDevice;
#[no_mangle]
pub extern "system" fn init_logging() {
simple_logger::init_with_env().unwrap();
}
// Constants // Constants
// `canvas` // `canvas`
@ -272,6 +278,13 @@ pub unsafe extern "C" fn PFCanvasCreateScene(canvas: PFCanvasRef) -> PFSceneRef
Box::into_raw(Box::new(Box::from_raw(canvas).into_canvas().into_scene())) 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 // Drawing rectangles
#[no_mangle] #[no_mangle]
@ -284,6 +297,11 @@ pub unsafe extern "C" fn PFCanvasStrokeRect(canvas: PFCanvasRef, rect: *const PF
(*canvas).stroke_rect((*rect).to_rust()) (*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 // Drawing text
#[no_mangle] #[no_mangle]
@ -378,9 +396,13 @@ pub unsafe extern "C" fn PFCanvasSetLineDashOffset(canvas: PFCanvasRef, new_offs
pub unsafe extern "C" fn PFCanvasSetFontByPostScriptName(canvas: PFCanvasRef, pub unsafe extern "C" fn PFCanvasSetFontByPostScriptName(canvas: PFCanvasRef,
postscript_name: *const c_char, postscript_name: *const c_char,
postscript_name_len: usize) -> i32 { postscript_name_len: usize) -> i32 {
match (*canvas).set_font(to_rust_string(&postscript_name, postscript_name_len)) { let name = to_rust_string(&postscript_name, postscript_name_len);
match (*canvas).set_font(name) {
Ok(_) => 0, Ok(_) => 0,
Err(_) => 1 Err(e) => {
log::error!("Failed to set font to {:?}: {:?}", name, e);
1
}
} }
} }
@ -787,6 +809,15 @@ pub unsafe extern "C" fn PFSceneDestroy(scene: PFSceneRef) {
drop(Box::from_raw(scene)) drop(Box::from_raw(scene))
} }
#[no_mangle]
pub unsafe extern "C" fn PFSceneProxyCreateFromSceneAndSequentialExecutor(scene: PFSceneRef,
level: PFRendererLevel)
-> PFSceneProxyRef {
Box::into_raw(Box::new(SceneProxy::from_scene(*Box::from_raw(scene),
to_rust_renderer_level(level),
SequentialExecutor)))
}
#[no_mangle] #[no_mangle]
pub unsafe extern "C" fn PFSceneProxyCreateFromSceneAndRayonExecutor(scene: PFSceneRef, pub unsafe extern "C" fn PFSceneProxyCreateFromSceneAndRayonExecutor(scene: PFSceneRef,
level: PFRendererLevel) level: PFRendererLevel)

View File

@ -25,6 +25,7 @@ use sdl2::keyboard::Keycode;
use sdl2::video::GLProfile; use sdl2::video::GLProfile;
use std::iter; use std::iter;
use std::sync::Arc; use std::sync::Arc;
use std::time::{Duration, Instant};
fn main() { fn main() {
// Set up SDL2. // Set up SDL2.
@ -34,7 +35,10 @@ fn main() {
// Make sure we have at least a GL 3.0 context. Pathfinder requires this. // Make sure we have at least a GL 3.0 context. Pathfinder requires this.
let gl_attributes = video.gl_attr(); let gl_attributes = video.gl_attr();
gl_attributes.set_context_profile(GLProfile::Core); 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. // Open a window.
let window_size = vec2i(640, 480); let window_size = vec2i(640, 480);
@ -66,17 +70,33 @@ fn main() {
// Wait for a keypress. // Wait for a keypress.
let mut event_pump = sdl_context.event_pump().unwrap(); let mut event_pump = sdl_context.event_pump().unwrap();
let mut n = 0;
let start = Instant::now();
let mut last_update = Instant::now();
let mut fps_buf = String::new();
loop { loop {
match event_pump.wait_event() { match event_pump.poll_event() {
Event::Quit {..} | Event::KeyDown { keycode: Some(Keycode::Escape), .. } => return, Some(Event::Quit {..} | Event::KeyDown { keycode: Some(Keycode::Escape), .. }) => return,
Event::Window { win_event: WindowEvent::Exposed, .. } => { Some(Event::Window { win_event: WindowEvent::Exposed, .. }) | None => {
// Make a canvas. // Make a canvas.
let mut canvas = Canvas::new(window_size.to_f32()).get_context_2d(font_context.clone()); let mut canvas = Canvas::new(window_size.to_f32()).get_context_2d(font_context.clone());
// Draw the text. // Draw the text.
canvas.set_font("Overpass-Regular"); canvas.set_font("Overpass-Regular");
canvas.set_font_size(32.0); canvas.set_font_size(32.0);
let now = Instant::now();
let elapsed = now.duration_since(last_update);
if elapsed >= Duration::from_millis(500) {
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("Hello Pathfinder!", vec2f(32.0, 48.0));
canvas.fill_text(&fps_buf, vec2f(32.0, 96.0));
canvas.set_text_align(TextAlign::Right); canvas.set_text_align(TextAlign::Right);
canvas.stroke_text("Goodbye Pathfinder!", vec2f(608.0, 464.0)); canvas.stroke_text("Goodbye Pathfinder!", vec2f(608.0, 464.0));
@ -86,6 +106,8 @@ fn main() {
RayonExecutor); RayonExecutor);
scene.build_and_render(&mut renderer, BuildOptions::default()); scene.build_and_render(&mut renderer, BuildOptions::default());
window.gl_swap_window(); window.gl_swap_window();
n += 1;
}, },
_ => {} _ => {}
} }