pathfinder/demo/magicleap/src/lib.rs

255 lines
9.2 KiB
Rust
Raw Normal View History

// pathfinder/demo/magicleap/src/lib.rs
//
// Copyright © 2019 The Pathfinder Project Developers.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
//! A demo app for Pathfinder on ML1.
2019-03-09 12:57:44 -05:00
use crate::magicleap::MagicLeapLogger;
use crate::magicleap::MagicLeapWindow;
use egl;
use egl::EGLContext;
use egl::EGLDisplay;
use egl::EGLSurface;
2019-03-09 12:57:44 -05:00
use gl::types::GLuint;
use log::info;
2019-03-09 12:57:44 -05:00
use pathfinder_demo::DemoApp;
use pathfinder_demo::Options;
2019-04-09 15:35:52 -04:00
use pathfinder_demo::UIVisibility;
2019-04-10 12:32:03 -04:00
use pathfinder_demo::BackgroundColor;
use pathfinder_demo::Mode;
use pathfinder_demo::window::Event;
use pathfinder_demo::window::SVGPath;
use pathfinder_geometry::basic::point::Point2DF32;
2019-04-10 12:32:03 -04:00
use pathfinder_geometry::basic::point::Point2DI32;
use pathfinder_geometry::basic::rect::RectI32;
use pathfinder_geometry::basic::transform2d::Transform2DF32;
use pathfinder_gl::GLDevice;
use pathfinder_gl::GLVersion;
use pathfinder_gpu::Device;
use pathfinder_gpu::resources::FilesystemResourceLoader;
2019-04-10 12:32:03 -04:00
use pathfinder_gpu::resources::ResourceLoader;
use pathfinder_renderer::builder::RenderOptions;
use pathfinder_renderer::builder::RenderTransform;
2019-04-10 12:32:03 -04:00
use pathfinder_renderer::builder::SceneBuilder;
use pathfinder_renderer::builder::SceneBuilderContext;
use pathfinder_renderer::gpu::renderer::Renderer;
use pathfinder_renderer::gpu_data::BuiltScene;
use pathfinder_simd::default::F32x4;
use pathfinder_svg::BuiltSVG;
use std::collections::HashMap;
use std::ffi::CStr;
2019-03-09 12:57:44 -05:00
use std::ffi::CString;
2019-03-29 16:28:16 -04:00
use std::os::raw::c_char;
use std::os::raw::c_void;
use std::sync::mpsc;
2019-03-09 12:57:44 -05:00
use usvg::Options as UsvgOptions;
use usvg::Tree;
2019-03-09 12:57:44 -05:00
mod c_api;
mod magicleap;
#[cfg(feature = "mocked")]
mod mocked_c_api;
struct ImmersiveApp {
sender: mpsc::Sender<Event>,
receiver: mpsc::Receiver<Event>,
demo: DemoApp<MagicLeapWindow>,
}
2019-03-09 12:57:44 -05:00
#[no_mangle]
2019-04-09 15:58:28 -04:00
pub extern "C" fn magicleap_pathfinder_demo_init(egl_display: EGLDisplay, egl_context: EGLContext) -> *mut c_void {
2019-04-10 12:32:03 -04:00
unsafe { c_api::MLLoggingLog(c_api::MLLogLevel::Info,
b"Pathfinder Demo\0".as_ptr() as *const _,
b"Initializing\0".as_ptr() as *const _) };
2019-03-09 12:57:44 -05:00
let tag = CString::new("Pathfinder Demo").unwrap();
let level = log::LevelFilter::Warn;
let logger = MagicLeapLogger::new(tag, level);
log::set_boxed_logger(Box::new(logger)).unwrap();
log::set_max_level(level);
info!("Initialized logging");
2019-03-09 12:57:44 -05:00
let window = MagicLeapWindow::new(egl_display, egl_context);
let window_size = window.size();
let mut options = Options::default();
2019-04-10 12:32:03 -04:00
options.ui = UIVisibility::Stats;
options.background_color = BackgroundColor::Transparent;
2019-03-09 12:57:44 -05:00
options.mode = Mode::VR;
2019-03-28 15:36:27 -04:00
options.jobs = Some(3);
let demo = DemoApp::new(window, window_size, options);
info!("Initialized app");
let (sender, receiver) = mpsc::channel();
Box::into_raw(Box::new(ImmersiveApp { sender, receiver, demo })) as *mut c_void
}
#[no_mangle]
pub unsafe extern "C" fn magicleap_pathfinder_demo_run(app: *mut c_void) {
let app = app as *mut ImmersiveApp;
if let Some(app) = app.as_mut() {
while app.demo.window.running() {
let mut events = Vec::new();
while let Some(event) = app.demo.window.try_get_event() {
events.push(event);
}
while let Ok(event) = app.receiver.try_recv() {
events.push(event);
}
let scene_count = app.demo.prepare_frame(events);
for scene_index in 0..scene_count {
app.demo.draw_scene(scene_index);
}
app.demo.finish_drawing_frame();
2019-04-10 12:32:03 -04:00
}
}
}
#[no_mangle]
pub unsafe extern "C" fn magicleap_pathfinder_demo_load(app: *mut c_void, svg_filename: *const c_char) {
let app = app as *mut ImmersiveApp;
if let Some(app) = app.as_mut() {
let svg_filename = CStr::from_ptr(svg_filename).to_string_lossy().into_owned();
info!("Loading {}.", svg_filename);
let _ = app.sender.send(Event::OpenSVG(SVGPath::Resource(svg_filename)));
2019-03-09 12:57:44 -05:00
}
2019-03-29 16:28:16 -04:00
}
struct MagicLeapPathfinder {
renderers: HashMap<(EGLSurface, EGLDisplay), Renderer<GLDevice>>,
svgs: HashMap<String, BuiltSVG>,
resources: FilesystemResourceLoader,
2019-04-10 12:32:03 -04:00
scene_builder_context: SceneBuilderContext,
}
#[repr(C)]
pub struct MagicLeapPathfinderRenderOptions {
display: EGLDisplay,
surface: EGLSurface,
bg_color: [f32; 4],
viewport: [u32; 4],
svg_filename: *const c_char,
}
#[no_mangle]
pub extern "C" fn magicleap_pathfinder_init() -> *mut c_void {
2019-04-10 12:32:03 -04:00
unsafe { c_api::MLLoggingLog(c_api::MLLogLevel::Info,
b"Pathfinder Demo\0".as_ptr() as *const _,
b"Initializing\0".as_ptr() as *const _) };
let tag = CString::new("Pathfinder Demo").unwrap();
let level = log::LevelFilter::Info;
let logger = MagicLeapLogger::new(tag, level);
log::set_boxed_logger(Box::new(logger)).unwrap();
log::set_max_level(level);
info!("Initialized logging");
gl::load_with(|s| egl::get_proc_address(s) as *const c_void);
info!("Initialized gl");
let pf = MagicLeapPathfinder {
renderers: HashMap::new(),
svgs: HashMap::new(),
resources: FilesystemResourceLoader::locate(),
2019-04-10 12:32:03 -04:00
scene_builder_context: SceneBuilderContext::new(),
};
info!("Initialized pf");
Box::into_raw(Box::new(pf)) as *mut c_void
}
#[no_mangle]
pub unsafe extern "C" fn magicleap_pathfinder_render(pf: *mut c_void, options: *const MagicLeapPathfinderRenderOptions) {
let pf = pf as *mut MagicLeapPathfinder;
if let (Some(pf), Some(options)) = (pf.as_mut(), options.as_ref()) {
let resources = &pf.resources;
let svg_filename = CStr::from_ptr(options.svg_filename).to_string_lossy().into_owned();
2019-04-10 12:32:03 -04:00
let svg = pf.svgs.entry(svg_filename).or_insert_with(|| {
let svg_filename = CStr::from_ptr(options.svg_filename).to_string_lossy();
2019-04-10 12:32:03 -04:00
let data = resources.slurp(&*svg_filename).unwrap();
let tree = Tree::from_data(&data, &UsvgOptions::default()).unwrap();
BuiltSVG::from_tree(tree)
});
let mut width = 0;
2019-04-10 12:32:03 -04:00
let mut height = 0;
egl::query_surface(options.display, options.surface, egl::EGL_WIDTH, &mut width);
egl::query_surface(options.display, options.surface, egl::EGL_HEIGHT, &mut height);
let size = Point2DI32::new(width, height);
let viewport_origin = Point2DI32::new(options.viewport[0] as i32, options.viewport[1] as i32);
2019-04-10 12:32:03 -04:00
let viewport_size = Point2DI32::new(options.viewport[2] as i32, options.viewport[3] as i32);
let viewport = RectI32::new(viewport_origin, viewport_size);
2019-04-10 12:32:03 -04:00
let bg_color = F32x4::new(options.bg_color[0], options.bg_color[1], options.bg_color[2], options.bg_color[3]);
let renderer = pf.renderers.entry((options.display, options.surface)).or_insert_with(|| {
let mut fbo = 0;
gl::GetIntegerv(gl::DRAW_FRAMEBUFFER_BINDING, &mut fbo);
let device = GLDevice::new(GLVersion::GLES3, fbo as GLuint);
Renderer::new(device, resources, viewport, size)
});
renderer.set_main_framebuffer_size(size);
renderer.set_viewport(viewport);
2019-04-10 12:32:03 -04:00
renderer.device.bind_default_framebuffer(viewport);
renderer.device.clear(Some(bg_color), Some(1.0), Some(0));
renderer.disable_depth();
2019-04-10 12:32:03 -04:00
svg.scene.view_box = viewport.to_f32();
let scale = i32::min(viewport_size.x(), viewport_size.y()) as f32 /
2019-04-10 12:32:03 -04:00
f32::max(svg.scene.bounds.size().x(), svg.scene.bounds.size().y());
let transform = Transform2DF32::from_translation(&svg.scene.bounds.size().scale(-0.5))
2019-04-10 12:32:03 -04:00
.post_mul(&Transform2DF32::from_scale(&Point2DF32::splat(scale)))
.post_mul(&Transform2DF32::from_translation(&viewport_size.to_f32().scale(0.5)));
2019-04-10 12:32:03 -04:00
let render_options = RenderOptions {
transform: RenderTransform::Transform2D(transform),
dilation: Point2DF32::default(),
barrel_distortion: None,
2019-04-10 12:32:03 -04:00
subpixel_aa_enabled: false,
};
let built_options = render_options.prepare(svg.scene.bounds);
let quad = built_options.quad();
2019-04-10 12:32:03 -04:00
let mut built_scene = BuiltScene::new(svg.scene.view_box, &quad, svg.scene.objects.len() as u32);
built_scene.shaders = svg.scene.build_shaders();
2019-04-10 12:32:03 -04:00
let (command_sender, command_receiver) = mpsc::channel();
let command_sender_clone = command_sender.clone();
SceneBuilder::new(&pf.scene_builder_context, &svg.scene, &built_options)
.build_sequentially(Box::new(move |command| { let _ = command_sender.send(Some(command)); }));
let _ = command_sender_clone.send(None);
renderer.begin_scene(&built_scene);
while let Ok(Some(command)) = command_receiver.recv() {
renderer.render_command(&command);
}
2019-04-10 12:32:03 -04:00
renderer.end_scene();
}
}
#[no_mangle]
pub unsafe extern "C" fn magicleap_pathfinder_deinit(pf: *mut c_void) {
Box::from_raw(pf as *mut MagicLeapPathfinder);
2019-04-10 12:32:03 -04:00
}