Add magicleap demo
This commit is contained in:
parent
e00e862df0
commit
838bf684fb
|
@ -2,6 +2,7 @@
|
||||||
members = [
|
members = [
|
||||||
"demo/android/rust",
|
"demo/android/rust",
|
||||||
"demo/common",
|
"demo/common",
|
||||||
|
"demo/magicleap",
|
||||||
"demo/native",
|
"demo/native",
|
||||||
"geometry",
|
"geometry",
|
||||||
"gl",
|
"gl",
|
||||||
|
|
|
@ -0,0 +1,3 @@
|
||||||
|
[target.aarch64-linux-android]
|
||||||
|
linker = "./fake-ld.sh"
|
||||||
|
ar = "aarch64-linux-android-ar"
|
|
@ -0,0 +1 @@
|
||||||
|
.out/
|
|
@ -0,0 +1,44 @@
|
||||||
|
[package]
|
||||||
|
name = "pathfinder_immersive_demo"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2018"
|
||||||
|
authors = ["Alan Jeffrey <ajeffrey@mozilla.com>"]
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
gl = "0.6"
|
||||||
|
rayon = "1.0"
|
||||||
|
usvg = "0.4"
|
||||||
|
egl = "0.2"
|
||||||
|
log = "0.4"
|
||||||
|
smallvec = "0.6"
|
||||||
|
glutin = { version = "0.19", optional = true }
|
||||||
|
|
||||||
|
[lib]
|
||||||
|
crate-type = ["staticlib"]
|
||||||
|
|
||||||
|
[features]
|
||||||
|
mocked = ["glutin"]
|
||||||
|
|
||||||
|
[dependencies.pathfinder_demo]
|
||||||
|
path = "../common"
|
||||||
|
|
||||||
|
[dependencies.pathfinder_geometry]
|
||||||
|
path = "../../geometry"
|
||||||
|
|
||||||
|
[dependencies.pathfinder_gl]
|
||||||
|
path = "../../gl"
|
||||||
|
|
||||||
|
[dependencies.pathfinder_gpu]
|
||||||
|
path = "../../gpu"
|
||||||
|
|
||||||
|
[dependencies.pathfinder_renderer]
|
||||||
|
path = "../../renderer"
|
||||||
|
|
||||||
|
[dependencies.pathfinder_simd]
|
||||||
|
path = "../../simd"
|
||||||
|
|
||||||
|
[dependencies.pathfinder_svg]
|
||||||
|
path = "../../svg"
|
||||||
|
|
||||||
|
[dependencies.pathfinder_ui]
|
||||||
|
path = "../../ui"
|
|
@ -0,0 +1,19 @@
|
||||||
|
KIND = program
|
||||||
|
SRCS = src/main.cpp
|
||||||
|
|
||||||
|
LIBPATHS.debug = \
|
||||||
|
../../target/aarch64-linux-android/debug
|
||||||
|
|
||||||
|
LIBPATHS.release = \
|
||||||
|
../../target/aarch64-linux-android/release
|
||||||
|
|
||||||
|
USES = ml_sdk OpenGL stdc++
|
||||||
|
|
||||||
|
STLIBS = \
|
||||||
|
pathfinder_immersive_demo
|
||||||
|
|
||||||
|
SHLIBS = \
|
||||||
|
ml_privileges
|
||||||
|
|
||||||
|
DATAS = \
|
||||||
|
../../resources/** : resources/
|
|
@ -0,0 +1,2 @@
|
||||||
|
REFS = PathfinderDemo
|
||||||
|
OPTIONS=package/debuggable/on
|
|
@ -0,0 +1,18 @@
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
# This shell script strips out the -landroid that is passed by default by rustc to
|
||||||
|
# the linker on aarch64-linux-android, and adds some entries to the ld search path.
|
||||||
|
|
||||||
|
set -o errexit
|
||||||
|
set -o nounset
|
||||||
|
set -o pipefail
|
||||||
|
|
||||||
|
TARGET=${TARGET:-"aarch64-linux-android"}
|
||||||
|
LD=${LD:-"${MAGICLEAP_SDK}/tools/toolchains/bin/${TARGET}-gcc"}
|
||||||
|
LDFLAGS=${LDFLAGS:-"--sysroot=${MAGICLEAP_SDK}/lumin -L${MAGICLEAP_SDK}/tools/toolchains/lib/gcc/${TARGET}/4.9.x ${MAGICLEAP_SDK}/lumin/usr/lib/crtbegin_so.o"}
|
||||||
|
|
||||||
|
# Remove the -landroid flag, grr
|
||||||
|
ARGS=("$@")
|
||||||
|
ARGS=${ARGS[@]/-landroid}
|
||||||
|
|
||||||
|
${LD} ${LDFLAGS} ${ARGS}
|
|
@ -0,0 +1,19 @@
|
||||||
|
<manifest
|
||||||
|
xmlns:ml="magicleap"
|
||||||
|
ml:package="com.mozilla.pathfinder.demo"
|
||||||
|
ml:version_code="1"
|
||||||
|
ml:version_name="1.0">
|
||||||
|
<application
|
||||||
|
ml:visible_name="Pathfinder Demo"
|
||||||
|
ml:sdk_version="0.19.0"
|
||||||
|
ml:min_api_level="3">
|
||||||
|
<uses-privilege ml:name="WorldReconstruction"/>
|
||||||
|
<uses-privilege ml:name="LowLatencyLightwear"/>
|
||||||
|
<component
|
||||||
|
ml:name=".fullscreen"
|
||||||
|
ml:visible_name="Pathfinder Demo"
|
||||||
|
ml:binary_name="bin/PathfinderDemo"
|
||||||
|
ml:type="Fullscreen">
|
||||||
|
</component>
|
||||||
|
</application>
|
||||||
|
</manifest>
|
|
@ -0,0 +1,281 @@
|
||||||
|
#![allow(dead_code)]
|
||||||
|
|
||||||
|
use gl::types::GLuint;
|
||||||
|
use std::error::Error;
|
||||||
|
use std::ffi::CStr;
|
||||||
|
use std::fmt;
|
||||||
|
#[cfg(not(feature = "mocked"))]
|
||||||
|
use std::os::raw::c_char;
|
||||||
|
use std::os::raw::c_void;
|
||||||
|
|
||||||
|
// Types from the MagicLeap C API
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||||
|
#[repr(C)]
|
||||||
|
pub struct MLHandle(u64);
|
||||||
|
|
||||||
|
impl MLHandle {
|
||||||
|
pub fn as_gl_uint(self) -> GLuint {
|
||||||
|
self.0 as GLuint
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> From<*mut T> for MLHandle {
|
||||||
|
fn from(ptr: *mut T) -> MLHandle {
|
||||||
|
MLHandle(ptr as u64)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||||
|
#[repr(C)]
|
||||||
|
pub struct MLResult(u32);
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Debug)]
|
||||||
|
#[repr(C)]
|
||||||
|
pub struct MLGraphicsOptions {
|
||||||
|
pub graphics_flags: u32,
|
||||||
|
pub color_format: MLSurfaceFormat,
|
||||||
|
pub depth_format: MLSurfaceFormat,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for MLGraphicsOptions {
|
||||||
|
fn default() -> MLGraphicsOptions {
|
||||||
|
MLGraphicsOptions {
|
||||||
|
graphics_flags: 0,
|
||||||
|
color_format: MLSurfaceFormat::RGBA8UNormSRGB,
|
||||||
|
depth_format: MLSurfaceFormat::D32Float,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Debug)]
|
||||||
|
#[repr(C)]
|
||||||
|
pub struct MLGraphicsRenderTargetsInfo {
|
||||||
|
pub min_clip: f32,
|
||||||
|
pub max_clip: f32,
|
||||||
|
pub num_virtual_cameras: u32,
|
||||||
|
pub buffers: [MLGraphicsRenderBufferInfo; ML_BUFFER_COUNT],
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Debug)]
|
||||||
|
#[repr(C)]
|
||||||
|
pub struct MLGraphicsRenderBufferInfo {
|
||||||
|
pub color: MLGraphicsRenderTarget,
|
||||||
|
pub depth: MLGraphicsRenderTarget,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Debug)]
|
||||||
|
#[repr(C)]
|
||||||
|
pub struct MLGraphicsRenderTarget {
|
||||||
|
pub width: u32,
|
||||||
|
pub height: u32,
|
||||||
|
pub id: MLHandle,
|
||||||
|
pub format: MLSurfaceFormat,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Debug)]
|
||||||
|
#[repr(u32)]
|
||||||
|
pub enum MLSurfaceFormat {
|
||||||
|
Unknown = 0,
|
||||||
|
RGBA8UNorm,
|
||||||
|
RGBA8UNormSRGB,
|
||||||
|
RGB10A2UNorm,
|
||||||
|
RGBA16Float,
|
||||||
|
D32Float,
|
||||||
|
D24NormS8,
|
||||||
|
D32FloatS8,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Debug)]
|
||||||
|
#[repr(C)]
|
||||||
|
pub struct MLGraphicsVirtualCameraInfoArray {
|
||||||
|
pub num_virtual_cameras: u32,
|
||||||
|
pub color_id: MLHandle,
|
||||||
|
pub depth_id: MLHandle,
|
||||||
|
pub viewport: MLRectf,
|
||||||
|
pub virtual_cameras: [MLGraphicsVirtualCameraInfo; ML_VIRTUAL_CAMERA_COUNT],
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Debug)]
|
||||||
|
#[repr(C)]
|
||||||
|
pub struct MLGraphicsVirtualCameraInfo {
|
||||||
|
pub left_half_angle: f32,
|
||||||
|
pub right_half_angle: f32,
|
||||||
|
pub top_half_angle: f32,
|
||||||
|
pub bottom_half_angle: f32,
|
||||||
|
pub sync_object: MLHandle,
|
||||||
|
pub projection: MLMat4f,
|
||||||
|
pub transform: MLTransform,
|
||||||
|
pub virtual_camera_name: MLGraphicsVirtualCameraName,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Debug)]
|
||||||
|
#[repr(i32)]
|
||||||
|
pub enum MLGraphicsVirtualCameraName {
|
||||||
|
Combined = -1,
|
||||||
|
Left = 0,
|
||||||
|
Right,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Debug)]
|
||||||
|
#[repr(C)]
|
||||||
|
pub struct MLGraphicsFrameParams {
|
||||||
|
pub near_clip: f32,
|
||||||
|
pub far_clip: f32,
|
||||||
|
pub focus_distance: f32,
|
||||||
|
pub surface_scale: f32,
|
||||||
|
pub protected_surface: bool,
|
||||||
|
pub projection_type: MLGraphicsProjectionType,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Debug)]
|
||||||
|
#[repr(C)]
|
||||||
|
pub struct MLSnapshotPtr(*mut c_void);
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Debug)]
|
||||||
|
#[repr(C)]
|
||||||
|
pub struct MLCoordinateFrameUID {
|
||||||
|
pub data: [u64; 2],
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Debug)]
|
||||||
|
#[repr(C)]
|
||||||
|
pub struct MLHeadTrackingStaticData {
|
||||||
|
pub coord_frame_head: MLCoordinateFrameUID,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Debug)]
|
||||||
|
#[repr(C)]
|
||||||
|
pub struct MLGraphicsClipExtentsInfo {
|
||||||
|
pub virtual_camera_name: MLGraphicsVirtualCameraName,
|
||||||
|
pub projection: MLMat4f,
|
||||||
|
pub transform: MLTransform,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Debug)]
|
||||||
|
#[repr(C)]
|
||||||
|
pub struct MLGraphicsClipExtentsInfoArray {
|
||||||
|
pub num_virtual_cameras: u32,
|
||||||
|
pub full_extents: MLGraphicsClipExtentsInfo,
|
||||||
|
pub virtual_camera_extents: [MLGraphicsClipExtentsInfo; ML_VIRTUAL_CAMERA_COUNT],
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Debug)]
|
||||||
|
#[repr(u32)]
|
||||||
|
pub enum MLGraphicsProjectionType {
|
||||||
|
SignedZ = 0,
|
||||||
|
ReversedInfiniteZ = 1,
|
||||||
|
UnsignedZ = 2,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Debug)]
|
||||||
|
#[repr(C)]
|
||||||
|
pub struct MLTransform {
|
||||||
|
pub rotation: MLQuaternionf,
|
||||||
|
pub position: MLVec3f,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Debug)]
|
||||||
|
#[repr(C)]
|
||||||
|
pub struct MLVec3f {
|
||||||
|
pub x: f32,
|
||||||
|
pub y: f32,
|
||||||
|
pub z: f32,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Debug)]
|
||||||
|
#[repr(C)]
|
||||||
|
pub struct MLRectf {
|
||||||
|
pub x: f32,
|
||||||
|
pub y: f32,
|
||||||
|
pub w: f32,
|
||||||
|
pub h: f32,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Debug)]
|
||||||
|
#[repr(C)]
|
||||||
|
pub struct MLQuaternionf {
|
||||||
|
pub x: f32,
|
||||||
|
pub y: f32,
|
||||||
|
pub z: f32,
|
||||||
|
pub w: f32,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Debug)]
|
||||||
|
#[repr(C)]
|
||||||
|
pub struct MLMat4f {
|
||||||
|
pub matrix_colmajor: [f32; 16],
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||||
|
#[repr(u32)]
|
||||||
|
pub enum MLLogLevel {
|
||||||
|
Fatal = 0,
|
||||||
|
Error = 1,
|
||||||
|
Warning = 2,
|
||||||
|
Info = 3,
|
||||||
|
Debug = 4,
|
||||||
|
Verbose = 5,
|
||||||
|
}
|
||||||
|
|
||||||
|
// Constants from the MagicLeap C API
|
||||||
|
|
||||||
|
pub const ML_RESULT_OK: MLResult = MLResult(0);
|
||||||
|
pub const ML_RESULT_TIMEOUT: MLResult = MLResult(2);
|
||||||
|
pub const ML_RESULT_UNSPECIFIED_FAILURE: MLResult = MLResult(4);
|
||||||
|
pub const ML_HANDLE_INVALID: MLHandle = MLHandle(0xFFFFFFFFFFFFFFFF);
|
||||||
|
pub const ML_BUFFER_COUNT: usize = 3;
|
||||||
|
pub const ML_VIRTUAL_CAMERA_COUNT: usize = 2;
|
||||||
|
|
||||||
|
// ML error handling
|
||||||
|
|
||||||
|
impl fmt::Display for MLResult {
|
||||||
|
fn fmt(&self, formatter: &mut fmt::Formatter) -> Result<(), fmt::Error> {
|
||||||
|
let cmessage = unsafe { CStr::from_ptr(MLGetResultString(*self)) };
|
||||||
|
let message = cmessage.to_str().or(Err(fmt::Error))?;
|
||||||
|
formatter.write_str(message)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl MLResult {
|
||||||
|
pub fn ok(self) -> Result<(), MLResult> {
|
||||||
|
if self == ML_RESULT_OK {
|
||||||
|
Ok(())
|
||||||
|
} else {
|
||||||
|
Err(self)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn unwrap(self) {
|
||||||
|
self.ok().unwrap()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Error for MLResult {
|
||||||
|
}
|
||||||
|
|
||||||
|
// Functions from the MagicLeap C API
|
||||||
|
|
||||||
|
#[cfg(not(feature = "mocked"))]
|
||||||
|
extern "C" {
|
||||||
|
pub fn MLGraphicsCreateClientGL(options: *const MLGraphicsOptions, gl_context: MLHandle, graphics_client : &mut MLHandle) -> MLResult;
|
||||||
|
pub fn MLGraphicsDestroyClient(graphics_client: *mut MLHandle) -> MLResult;
|
||||||
|
pub fn MLHeadTrackingCreate(tracker: *mut MLHandle) -> MLResult;
|
||||||
|
pub fn MLHeadTrackingGetStaticData(head_tracker: MLHandle, data: *mut MLHeadTrackingStaticData) -> MLResult;
|
||||||
|
pub fn MLPerceptionGetSnapshot(snapshot: *mut MLSnapshotPtr) -> MLResult;
|
||||||
|
pub fn MLSnapshotGetTransform(snapshot: MLSnapshotPtr, id: *const MLCoordinateFrameUID, transform: *mut MLTransform) -> MLResult;
|
||||||
|
pub fn MLPerceptionReleaseSnapshot(snapshot: MLSnapshotPtr) -> MLResult;
|
||||||
|
pub fn MLLifecycleSetReadyIndication() -> MLResult;
|
||||||
|
pub fn MLGraphicsGetClipExtents(graphics_client: MLHandle, array: *mut MLGraphicsClipExtentsInfoArray) -> MLResult;
|
||||||
|
pub fn MLGraphicsGetRenderTargets(graphics_client: MLHandle, targets: *mut MLGraphicsRenderTargetsInfo) -> MLResult;
|
||||||
|
pub fn MLGraphicsInitFrameParams(params: *mut MLGraphicsFrameParams) -> MLResult;
|
||||||
|
pub fn MLGraphicsBeginFrame(graphics_client: MLHandle, params: *const MLGraphicsFrameParams, frame_handle: *mut MLHandle, virtual_camera_array: *mut MLGraphicsVirtualCameraInfoArray) -> MLResult;
|
||||||
|
pub fn MLGraphicsEndFrame(graphics_client: MLHandle, frame_handle: MLHandle) -> MLResult;
|
||||||
|
pub fn MLGraphicsSignalSyncObjectGL(graphics_client: MLHandle, sync_object: MLHandle) -> MLResult;
|
||||||
|
pub fn MLGetResultString(result_code: MLResult) -> *const c_char;
|
||||||
|
pub fn MLLoggingLogLevelIsEnabled(lvl: MLLogLevel) -> bool;
|
||||||
|
pub fn MLLoggingLog(lvl: MLLogLevel, tag: *const c_char, message: *const c_char);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "mocked")]
|
||||||
|
pub use crate::mocked_c_api::*;
|
|
@ -0,0 +1,46 @@
|
||||||
|
// pathfinder/demo/immersive/display.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.
|
||||||
|
|
||||||
|
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_gl::GLVersion;
|
||||||
|
use pathfinder_gpu::resources::ResourceLoader;
|
||||||
|
|
||||||
|
pub trait Display: Sized {
|
||||||
|
type Error: DisplayError;
|
||||||
|
type Camera: DisplayCamera<Error = Self::Error>;
|
||||||
|
|
||||||
|
fn resource_loader(&self) -> &dyn ResourceLoader;
|
||||||
|
fn gl_version(&self) -> GLVersion;
|
||||||
|
fn make_current(&mut self) -> Result<(), Self::Error>;
|
||||||
|
|
||||||
|
fn running(&self) -> bool;
|
||||||
|
fn size(&self) -> Point2DI32;
|
||||||
|
|
||||||
|
fn begin_frame(&mut self) -> Result<&mut[Self::Camera], Self::Error>;
|
||||||
|
fn end_frame(&mut self) -> Result<(), Self::Error>;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait DisplayCamera {
|
||||||
|
type Error: DisplayError;
|
||||||
|
|
||||||
|
fn bounds(&self) -> RectI32;
|
||||||
|
fn view(&self) -> Transform3DF32;
|
||||||
|
fn perspective(&self) -> Perspective;
|
||||||
|
|
||||||
|
fn make_current(&mut self) -> Result<(), Self::Error>;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait DisplayError: Error + From<usvg::Error> + From<io::Error>{
|
||||||
|
}
|
|
@ -0,0 +1,254 @@
|
||||||
|
// pathfinder/demo/immersive/glwindow.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.
|
||||||
|
|
||||||
|
use gl;
|
||||||
|
|
||||||
|
use glutin::ContextBuilder;
|
||||||
|
use glutin::ContextError;
|
||||||
|
use glutin::CreationError;
|
||||||
|
use glutin::EventsLoop;
|
||||||
|
use glutin::Event;
|
||||||
|
use glutin::WindowEvent;
|
||||||
|
use glutin::GlContext;
|
||||||
|
use glutin::GlWindow;
|
||||||
|
use glutin::WindowBuilder;
|
||||||
|
use glutin::dpi::LogicalSize;
|
||||||
|
|
||||||
|
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_gl::GLVersion;
|
||||||
|
use pathfinder_gpu::resources::FilesystemResourceLoader;
|
||||||
|
use pathfinder_gpu::resources::ResourceLoader;
|
||||||
|
|
||||||
|
use std::env;
|
||||||
|
use std::error::Error;
|
||||||
|
use std::fmt;
|
||||||
|
use std::f32::consts::FRAC_PI_4;
|
||||||
|
use std::io;
|
||||||
|
use std::rc::Rc;
|
||||||
|
use std::time::Instant;
|
||||||
|
|
||||||
|
use usvg;
|
||||||
|
|
||||||
|
pub struct GlWindowDisplay {
|
||||||
|
events_loop: EventsLoop,
|
||||||
|
gl_window: Rc<GlWindow>,
|
||||||
|
running: bool,
|
||||||
|
cameras: Vec<GlWindowCamera>,
|
||||||
|
resource_loader: FilesystemResourceLoader,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct GlWindowCamera {
|
||||||
|
eye: Eye,
|
||||||
|
gl_window: Rc<GlWindow>,
|
||||||
|
start: Instant,
|
||||||
|
}
|
||||||
|
|
||||||
|
enum Eye {
|
||||||
|
Left,
|
||||||
|
Right,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum GlWindowError {
|
||||||
|
Creation(CreationError),
|
||||||
|
Context(ContextError),
|
||||||
|
SVG(usvg::Error),
|
||||||
|
IO(io::Error),
|
||||||
|
}
|
||||||
|
|
||||||
|
const DEFAULT_EYE_WIDTH: u32 = 1024;
|
||||||
|
const DEFAULT_EYE_HEIGHT: u32 = 768;
|
||||||
|
|
||||||
|
const CAMERA_DISTANCE: f32 = 3.0;
|
||||||
|
const NEAR_CLIP_PLANE: f32 = 0.01;
|
||||||
|
const FAR_CLIP_PLANE: f32 = 10.0;
|
||||||
|
|
||||||
|
impl Display for GlWindowDisplay {
|
||||||
|
type Error = GlWindowError;
|
||||||
|
type Camera = GlWindowCamera;
|
||||||
|
|
||||||
|
fn resource_loader(&self) -> &dyn ResourceLoader {
|
||||||
|
&self.resource_loader
|
||||||
|
}
|
||||||
|
|
||||||
|
fn gl_version(&self) -> GLVersion {
|
||||||
|
GLVersion::GL3
|
||||||
|
}
|
||||||
|
|
||||||
|
fn make_current(&mut self) -> Result<(), GlWindowError> {
|
||||||
|
let size = self.size();
|
||||||
|
unsafe {
|
||||||
|
self.gl_window.make_current()?;
|
||||||
|
gl::Viewport(0, 0, size.x(), size.y());
|
||||||
|
gl::Scissor(0, 0, size.x(), size.y());
|
||||||
|
gl::Enable(gl::SCISSOR_TEST);
|
||||||
|
}
|
||||||
|
self.handle_events();
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn begin_frame(&mut self) -> Result<&mut[GlWindowCamera], GlWindowError> {
|
||||||
|
self.handle_events();
|
||||||
|
Ok(&mut self.cameras[..])
|
||||||
|
}
|
||||||
|
|
||||||
|
fn end_frame(&mut self) -> Result<(), GlWindowError> {
|
||||||
|
self.handle_events();
|
||||||
|
self.gl_window.swap_buffers()?;
|
||||||
|
self.handle_events();
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn running(&self) -> bool {
|
||||||
|
self.running
|
||||||
|
}
|
||||||
|
|
||||||
|
fn size(&self) -> Point2DI32 {
|
||||||
|
window_size(&*self.gl_window)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DisplayCamera for GlWindowCamera {
|
||||||
|
type Error = GlWindowError;
|
||||||
|
|
||||||
|
fn make_current(&mut self) -> Result<(), GlWindowError> {
|
||||||
|
let bounds = self.bounds();
|
||||||
|
unsafe {
|
||||||
|
self.gl_window.make_current()?;
|
||||||
|
gl::Viewport(bounds.origin().x(), bounds.origin().y(), bounds.size().x(), bounds.size().y());
|
||||||
|
gl::Scissor(bounds.origin().x(), bounds.origin().y(), bounds.size().x(), bounds.size().y());
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn bounds(&self) -> RectI32 {
|
||||||
|
let window_size = window_size(&*self.gl_window);
|
||||||
|
let eye_size = Point2DI32::new(window_size.x()/2, window_size.y());
|
||||||
|
let origin = match self.eye {
|
||||||
|
Eye::Left => Point2DI32::new(0, 0),
|
||||||
|
Eye::Right => Point2DI32::new(eye_size.x(), 0),
|
||||||
|
};
|
||||||
|
RectI32::new(origin, eye_size)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn perspective(&self) -> Perspective {
|
||||||
|
// TODO: add eye offsets
|
||||||
|
let bounds = self.bounds();
|
||||||
|
let aspect = bounds.size().x() as f32 / bounds.size().y() as f32;
|
||||||
|
let transform = Transform3DF32::from_perspective(FRAC_PI_4, aspect, NEAR_CLIP_PLANE, FAR_CLIP_PLANE);
|
||||||
|
Perspective::new(&transform, bounds.size())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn view(&self) -> Transform3DF32 {
|
||||||
|
let duration = Instant::now() - self.start;
|
||||||
|
let rotation = duration.as_millis() as f32 / 1000.0;
|
||||||
|
Transform3DF32::from_rotation(rotation, 0.0, 0.0)
|
||||||
|
.pre_mul(&Transform3DF32::from_translation(0.0, 0.0, -CAMERA_DISTANCE))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl GlWindowDisplay {
|
||||||
|
pub fn new() -> Result<GlWindowDisplay, GlWindowError> {
|
||||||
|
let resource_loader = FilesystemResourceLoader::locate();
|
||||||
|
let size = default_window_size();
|
||||||
|
let events_loop = glutin::EventsLoop::new();
|
||||||
|
let window = WindowBuilder::new()
|
||||||
|
.with_title("Pathfinder Immersive Demo")
|
||||||
|
.with_dimensions(size);
|
||||||
|
let context = ContextBuilder::new()
|
||||||
|
.with_vsync(true);
|
||||||
|
let gl_window = Rc::new(glutin::GlWindow::new(window, context, &events_loop)?);
|
||||||
|
let start = Instant::now();
|
||||||
|
let cameras = vec![
|
||||||
|
GlWindowCamera { gl_window: gl_window.clone(), start, eye: Eye::Left },
|
||||||
|
GlWindowCamera { gl_window: gl_window.clone(), start, eye: Eye::Right },
|
||||||
|
];
|
||||||
|
gl::load_with(|name| gl_window.get_proc_address(name) as *const _);
|
||||||
|
Ok(GlWindowDisplay {
|
||||||
|
resource_loader,
|
||||||
|
events_loop,
|
||||||
|
gl_window,
|
||||||
|
cameras,
|
||||||
|
running: true,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn handle_events(&mut self) {
|
||||||
|
let running = &mut self.running;
|
||||||
|
self.events_loop.poll_events(|event| {
|
||||||
|
match event {
|
||||||
|
Event::WindowEvent { event: WindowEvent::CloseRequested, .. } |
|
||||||
|
Event::WindowEvent { event: WindowEvent::Destroyed, .. } => *running = false,
|
||||||
|
_ => (),
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn window_size(gl_window: &GlWindow) -> Point2DI32 {
|
||||||
|
let logical = gl_window
|
||||||
|
.get_inner_size()
|
||||||
|
.unwrap_or_else(|| default_window_size());
|
||||||
|
let hidpi = gl_window.get_hidpi_factor();
|
||||||
|
let physical = logical.to_physical(hidpi);
|
||||||
|
Point2DI32::new(physical.width as i32, physical.height as i32)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn default_window_size() -> LogicalSize {
|
||||||
|
LogicalSize::new((DEFAULT_EYE_WIDTH * 2) as f64, DEFAULT_EYE_HEIGHT as f64)
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for GlWindowError {
|
||||||
|
fn fmt(&self, formatter: &mut fmt::Formatter) -> Result<(), fmt::Error> {
|
||||||
|
match *self {
|
||||||
|
GlWindowError::Creation(ref err) => err.fmt(formatter),
|
||||||
|
GlWindowError::Context(ref err) => err.fmt(formatter),
|
||||||
|
GlWindowError::SVG(ref err) => err.fmt(formatter),
|
||||||
|
GlWindowError::IO(ref err) => err.fmt(formatter),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Error for GlWindowError {
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<CreationError> for GlWindowError {
|
||||||
|
fn from(err: CreationError) -> GlWindowError {
|
||||||
|
GlWindowError::Creation(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<ContextError> for GlWindowError {
|
||||||
|
fn from(err: ContextError) -> GlWindowError {
|
||||||
|
GlWindowError::Context(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<usvg::Error> for GlWindowError {
|
||||||
|
fn from(err: usvg::Error) -> GlWindowError {
|
||||||
|
GlWindowError::SVG(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<io::Error> for GlWindowError {
|
||||||
|
fn from(err: io::Error) -> GlWindowError {
|
||||||
|
GlWindowError::IO(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DisplayError for GlWindowError {
|
||||||
|
}
|
|
@ -0,0 +1,129 @@
|
||||||
|
#![allow(unused_imports)]
|
||||||
|
#![allow(dead_code)]
|
||||||
|
|
||||||
|
use crate::display::Display;
|
||||||
|
use crate::display::DisplayCamera;
|
||||||
|
|
||||||
|
use log::debug;
|
||||||
|
|
||||||
|
use pathfinder_demo::Options;
|
||||||
|
use pathfinder_demo::BuildOptions;
|
||||||
|
use pathfinder_demo::SceneThreadProxy;
|
||||||
|
use pathfinder_demo::MainToSceneMsg;
|
||||||
|
use pathfinder_demo::SceneToMainMsg;
|
||||||
|
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_gpu::Device;
|
||||||
|
use pathfinder_simd::default::F32x4;
|
||||||
|
use pathfinder_svg::BuiltSVG;
|
||||||
|
use pathfinder_renderer::scene::Scene;
|
||||||
|
use pathfinder_renderer::builder::RenderTransform;
|
||||||
|
|
||||||
|
use std::error::Error;
|
||||||
|
use std::fmt;
|
||||||
|
use std::path::Path;
|
||||||
|
use std::path::PathBuf;
|
||||||
|
use std::time::Instant;
|
||||||
|
|
||||||
|
use usvg;
|
||||||
|
|
||||||
|
pub struct ImmersiveDemo<D> {
|
||||||
|
display: D,
|
||||||
|
renderer: Renderer<GLDevice>,
|
||||||
|
scene_thread_proxy: SceneThreadProxy,
|
||||||
|
svg_size: Point2DF32,
|
||||||
|
svg_to_world: Option<Transform3DF32>,
|
||||||
|
}
|
||||||
|
|
||||||
|
static DEFAULT_SVG_VIRTUAL_PATH: &'static str = "svg/Ghostscript_Tiger.svg";
|
||||||
|
|
||||||
|
// SVG dimensions in metres
|
||||||
|
const MAX_SVG_HEIGHT: f32 = 1.0;
|
||||||
|
const MAX_SVG_WIDTH: f32 = 1.0;
|
||||||
|
const DEFAULT_SVG_DISTANCE: f32 = 1.5;
|
||||||
|
|
||||||
|
impl<D: Display> ImmersiveDemo<D> {
|
||||||
|
pub fn new(mut display: D) -> Result<Self, D::Error> {
|
||||||
|
display.make_current()?;
|
||||||
|
let resources = display.resource_loader();
|
||||||
|
let options = Options::get();
|
||||||
|
let svg_data = resources.slurp(DEFAULT_SVG_VIRTUAL_PATH)?;
|
||||||
|
let tree = usvg::Tree::from_data(&svg_data[..], &usvg::Options::default())?;
|
||||||
|
let svg = BuiltSVG::from_tree(tree);
|
||||||
|
let svg_size = svg.scene.view_box.size();
|
||||||
|
let scene_thread_proxy = SceneThreadProxy::new(svg.scene, options);
|
||||||
|
let _ = scene_thread_proxy.sender.send(MainToSceneMsg::SetDrawableSize(display.size()));
|
||||||
|
let device = GLDevice::new(display.gl_version());
|
||||||
|
let viewport = RectI32::new(Point2DI32::new(0, 0), display.size());
|
||||||
|
let renderer = Renderer::new(device, resources, viewport, display.size());
|
||||||
|
Ok(ImmersiveDemo {
|
||||||
|
display,
|
||||||
|
renderer,
|
||||||
|
scene_thread_proxy,
|
||||||
|
svg_size,
|
||||||
|
svg_to_world: None,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn running(&self) -> bool {
|
||||||
|
self.display.running()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn render_scene(&mut self) -> Result<(), D::Error> {
|
||||||
|
self.display.make_current()?;
|
||||||
|
let cameras = self.display.begin_frame()?;
|
||||||
|
|
||||||
|
debug!("PF rendering a frame");
|
||||||
|
let start = Instant::now();
|
||||||
|
|
||||||
|
let svg_size = self.svg_size;
|
||||||
|
let svg_to_world = self.svg_to_world.get_or_insert_with(|| {
|
||||||
|
let view: Transform3DF32 = cameras[0].view();
|
||||||
|
let svg_to_world_scale = f32::max(MAX_SVG_WIDTH / svg_size.x(), MAX_SVG_HEIGHT / svg_size.y());
|
||||||
|
let svg_width = svg_size.x() * svg_to_world_scale;
|
||||||
|
let svg_height = svg_size.y() * svg_to_world_scale;
|
||||||
|
Transform3DF32::from_uniform_scale(svg_to_world_scale)
|
||||||
|
.pre_mul(&Transform3DF32::from_translation(-svg_width / 2.0, -svg_height / 2.0, -DEFAULT_SVG_DISTANCE))
|
||||||
|
.pre_mul(&Transform3DF32::from_scale(1.0, -1.0, 1.0))
|
||||||
|
.pre_mul(&view.inverse())
|
||||||
|
});
|
||||||
|
|
||||||
|
let render_transforms = cameras.iter()
|
||||||
|
.map(|camera| RenderTransform::Perspective(
|
||||||
|
camera.perspective()
|
||||||
|
.post_mul(&camera.view())
|
||||||
|
.post_mul(&svg_to_world)
|
||||||
|
)).collect();
|
||||||
|
let msg = MainToSceneMsg::Build(BuildOptions {
|
||||||
|
render_transforms: render_transforms,
|
||||||
|
stem_darkening_font_size: None,
|
||||||
|
});
|
||||||
|
let _ = self.scene_thread_proxy.sender.send(msg);
|
||||||
|
|
||||||
|
if let Ok(reply) = self.scene_thread_proxy.receiver.recv() {
|
||||||
|
for (camera, scene) in cameras.iter_mut().zip(reply.render_scenes) {
|
||||||
|
debug!("PF rendering eye after {}ms", (Instant::now() - start).as_millis());
|
||||||
|
camera.make_current()?;
|
||||||
|
let bounds = camera.bounds();
|
||||||
|
let background = F32x4::new(0.0, 0.0, 0.0, 1.0);
|
||||||
|
self.renderer.device.clear(Some(background), Some(1.0), Some(0));
|
||||||
|
self.renderer.enable_depth();
|
||||||
|
self.renderer.set_viewport(bounds);
|
||||||
|
self.renderer.render_scene(&scene.built_scene);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
debug!("PF rendered frame after {}ms", (Instant::now() - start).as_millis());
|
||||||
|
self.display.end_frame()?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,57 @@
|
||||||
|
use crate::magicleap::MagicLeapLogger;
|
||||||
|
use crate::magicleap::MagicLeapWindow;
|
||||||
|
|
||||||
|
use egl;
|
||||||
|
use egl::EGLContext;
|
||||||
|
use egl::EGLDisplay;
|
||||||
|
|
||||||
|
use log::debug;
|
||||||
|
|
||||||
|
use pathfinder_demo::Background;
|
||||||
|
use pathfinder_demo::DemoApp;
|
||||||
|
use pathfinder_demo::Options;
|
||||||
|
use pathfinder_demo::window::Mode;
|
||||||
|
|
||||||
|
use std::ffi::CString;
|
||||||
|
|
||||||
|
mod c_api;
|
||||||
|
mod magicleap;
|
||||||
|
|
||||||
|
#[cfg(feature = "mocked")]
|
||||||
|
mod mocked_c_api;
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
pub extern "C" fn magicleap_pathfinder_demo(egl_display: EGLDisplay, egl_context: EGLContext) {
|
||||||
|
unsafe { c_api::MLLoggingLog(c_api::MLLogLevel::Info, &b"Pathfinder Demo\0"[0], &b"Initializing\0"[0]) };
|
||||||
|
|
||||||
|
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);
|
||||||
|
debug!("Initialized logging");
|
||||||
|
|
||||||
|
let window = MagicLeapWindow::new(egl_display, egl_context);
|
||||||
|
let window_size = window.size();
|
||||||
|
|
||||||
|
let mut options = Options::default();
|
||||||
|
options.ui = false;
|
||||||
|
options.background = Background::None;
|
||||||
|
options.mode = Mode::VR;
|
||||||
|
|
||||||
|
let mut app = DemoApp::new(window, window_size, options);
|
||||||
|
debug!("Initialized app");
|
||||||
|
|
||||||
|
while app.window.running() {
|
||||||
|
let mut events = Vec::new();
|
||||||
|
while let Some(event) = app.window.try_get_event() {
|
||||||
|
events.push(event);
|
||||||
|
}
|
||||||
|
|
||||||
|
let scene_count = app.prepare_frame(events);
|
||||||
|
for scene_index in 0..scene_count {
|
||||||
|
app.draw_scene(scene_index);
|
||||||
|
}
|
||||||
|
app.finish_drawing_frame();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,362 @@
|
||||||
|
// pathfinder/demo/magicleap/magicleap.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.
|
||||||
|
|
||||||
|
use crate::c_api::MLGraphicsBeginFrame;
|
||||||
|
use crate::c_api::MLGraphicsCreateClientGL;
|
||||||
|
use crate::c_api::MLGraphicsDestroyClient;
|
||||||
|
use crate::c_api::MLGraphicsEndFrame;
|
||||||
|
use crate::c_api::MLGraphicsGetRenderTargets;
|
||||||
|
use crate::c_api::MLGraphicsInitFrameParams;
|
||||||
|
use crate::c_api::MLGraphicsOptions;
|
||||||
|
use crate::c_api::MLGraphicsSignalSyncObjectGL;
|
||||||
|
use crate::c_api::MLGraphicsVirtualCameraInfoArray;
|
||||||
|
use crate::c_api::MLHandle;
|
||||||
|
use crate::c_api::MLHeadTrackingCreate;
|
||||||
|
use crate::c_api::MLLifecycleSetReadyIndication;
|
||||||
|
use crate::c_api::MLLogLevel;
|
||||||
|
use crate::c_api::MLLoggingLog;
|
||||||
|
use crate::c_api::MLMat4f;
|
||||||
|
use crate::c_api::MLQuaternionf;
|
||||||
|
use crate::c_api::MLRectf;
|
||||||
|
use crate::c_api::MLTransform;
|
||||||
|
use crate::c_api::MLVec3f;
|
||||||
|
use crate::c_api::ML_HANDLE_INVALID;
|
||||||
|
use crate::c_api::ML_RESULT_TIMEOUT;
|
||||||
|
use crate::c_api::ML_VIRTUAL_CAMERA_COUNT;
|
||||||
|
|
||||||
|
use egl;
|
||||||
|
use egl::EGL_NO_SURFACE;
|
||||||
|
use egl::EGLContext;
|
||||||
|
use egl::EGLDisplay;
|
||||||
|
|
||||||
|
use gl;
|
||||||
|
use gl::types::GLuint;
|
||||||
|
|
||||||
|
use log;
|
||||||
|
use log::debug;
|
||||||
|
use log::info;
|
||||||
|
use log::warn;
|
||||||
|
|
||||||
|
use pathfinder_demo::window::CameraTransform;
|
||||||
|
use pathfinder_demo::window::Event;
|
||||||
|
use pathfinder_demo::window::Mode;
|
||||||
|
use pathfinder_demo::window::Window;
|
||||||
|
use pathfinder_demo::window::WindowSize;
|
||||||
|
use pathfinder_geometry::basic::point::Point2DI32;
|
||||||
|
use pathfinder_geometry::basic::point::Point2DF32;
|
||||||
|
use pathfinder_geometry::basic::rect::RectF32;
|
||||||
|
use pathfinder_geometry::basic::rect::RectI32;
|
||||||
|
use pathfinder_geometry::basic::transform3d::Perspective;
|
||||||
|
use pathfinder_geometry::basic::transform3d::Transform3DF32;
|
||||||
|
use pathfinder_geometry::distortion::BarrelDistortionCoefficients;
|
||||||
|
use pathfinder_gl::GLVersion;
|
||||||
|
use pathfinder_gpu::resources::FilesystemResourceLoader;
|
||||||
|
use pathfinder_gpu::resources::ResourceLoader;
|
||||||
|
use pathfinder_simd::default::F32x4;
|
||||||
|
|
||||||
|
use smallvec::SmallVec;
|
||||||
|
|
||||||
|
use std::ffi::CString;
|
||||||
|
use std::io::Write;
|
||||||
|
use std::mem;
|
||||||
|
use std::os::raw::c_void;
|
||||||
|
use std::path::PathBuf;
|
||||||
|
use std::thread;
|
||||||
|
use std::time::Duration;
|
||||||
|
|
||||||
|
pub struct MagicLeapWindow {
|
||||||
|
framebuffer_id: GLuint,
|
||||||
|
graphics_client: MLHandle,
|
||||||
|
size: Point2DI32,
|
||||||
|
virtual_camera_array: MLGraphicsVirtualCameraInfoArray,
|
||||||
|
initial_camera_transforms: Option<Vec<Transform3DF32>>,
|
||||||
|
frame_handle: MLHandle,
|
||||||
|
resource_loader: FilesystemResourceLoader,
|
||||||
|
pose_event: Option<Vec<CameraTransform>>,
|
||||||
|
running: bool,
|
||||||
|
in_frame: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Window for MagicLeapWindow {
|
||||||
|
fn resource_loader(&self) -> &dyn ResourceLoader {
|
||||||
|
&self.resource_loader
|
||||||
|
}
|
||||||
|
|
||||||
|
fn gl_version(&self) -> GLVersion {
|
||||||
|
GLVersion::GL3
|
||||||
|
}
|
||||||
|
|
||||||
|
fn gl_default_framebuffer(&self) -> GLuint {
|
||||||
|
self.framebuffer_id
|
||||||
|
}
|
||||||
|
|
||||||
|
fn mouse_position(&self) -> Point2DI32 {
|
||||||
|
Point2DI32::new(0, 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn create_user_event_id (&self) -> u32 {
|
||||||
|
0
|
||||||
|
}
|
||||||
|
|
||||||
|
fn push_user_event(_: u32, _: u32) {
|
||||||
|
}
|
||||||
|
|
||||||
|
fn present_open_svg_dialog(&mut self) {
|
||||||
|
}
|
||||||
|
|
||||||
|
fn run_save_dialog(&self, _: &str) -> Result<PathBuf, ()> {
|
||||||
|
Err(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn view_box_size(&self, _mode: Mode) -> Point2DI32 {
|
||||||
|
self.size
|
||||||
|
}
|
||||||
|
|
||||||
|
fn barrel_distortion_coefficients(&self) -> BarrelDistortionCoefficients {
|
||||||
|
BarrelDistortionCoefficients { k0: 0.0, k1: 0.0 }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn make_current(&mut self, _mode: Mode, eye: Option<u32>) -> RectI32 {
|
||||||
|
self.begin_frame();
|
||||||
|
let eye = match eye {
|
||||||
|
Some(eye) if (eye as usize) < ML_VIRTUAL_CAMERA_COUNT => eye as usize,
|
||||||
|
_ => { warn!("Asked for eye out of range {:?}", eye); 0 }
|
||||||
|
};
|
||||||
|
debug!("Making {} current.", eye);
|
||||||
|
let viewport = self.virtual_camera_array.viewport;
|
||||||
|
let color_id = self.virtual_camera_array.color_id.as_gl_uint();
|
||||||
|
let depth_id = self.virtual_camera_array.depth_id.as_gl_uint();
|
||||||
|
let virtual_camera = self.virtual_camera_array.virtual_cameras[eye];
|
||||||
|
let layer_id = virtual_camera.virtual_camera_name as i32;
|
||||||
|
unsafe {
|
||||||
|
gl::FramebufferTextureLayer(gl::FRAMEBUFFER, gl::COLOR_ATTACHMENT0, color_id, 0, layer_id);
|
||||||
|
gl::FramebufferTextureLayer(gl::FRAMEBUFFER, gl::DEPTH_ATTACHMENT, depth_id, 0, layer_id);
|
||||||
|
gl::Viewport(viewport.x as i32, viewport.y as i32, viewport.w as i32, viewport.h as i32);
|
||||||
|
}
|
||||||
|
debug!("Made {} current.", eye);
|
||||||
|
RectI32::new(Point2DI32::new(0, 0), self.size)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn present(&mut self) {
|
||||||
|
self.end_frame();
|
||||||
|
self.begin_frame();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_proc_address(s: &str) -> *const c_void {
|
||||||
|
egl::get_proc_address(s) as *const c_void
|
||||||
|
}
|
||||||
|
|
||||||
|
impl MagicLeapWindow {
|
||||||
|
pub fn new(egl_display: EGLDisplay, egl_context: EGLContext) -> MagicLeapWindow {
|
||||||
|
debug!("Creating MagicLeapWindow");
|
||||||
|
let mut framebuffer_id = 0;
|
||||||
|
let graphics_options = MLGraphicsOptions::default();
|
||||||
|
let mut graphics_client = unsafe { mem::zeroed() };
|
||||||
|
let mut head_tracker = unsafe { mem::zeroed() };
|
||||||
|
let mut targets = unsafe { mem::zeroed() };
|
||||||
|
let virtual_camera_array = unsafe { mem::zeroed() };
|
||||||
|
let handle = MLHandle::from(egl_context);
|
||||||
|
unsafe {
|
||||||
|
egl::make_current(egl_display, EGL_NO_SURFACE, EGL_NO_SURFACE, egl_context);
|
||||||
|
gl::load_with(get_proc_address);
|
||||||
|
gl::GenFramebuffers(1, &mut framebuffer_id);
|
||||||
|
MLGraphicsCreateClientGL(&graphics_options, handle, &mut graphics_client).unwrap();
|
||||||
|
MLLifecycleSetReadyIndication().unwrap();
|
||||||
|
MLHeadTrackingCreate(&mut head_tracker).unwrap();
|
||||||
|
MLGraphicsGetRenderTargets(graphics_client, &mut targets).unwrap();
|
||||||
|
}
|
||||||
|
let (max_width, max_height) = targets.buffers.iter().map(|buffer| buffer.color)
|
||||||
|
.chain(targets.buffers.iter().map(|buffer| buffer.depth))
|
||||||
|
.map(|target| (target.width as i32, target.height as i32))
|
||||||
|
.max()
|
||||||
|
.unwrap_or_default();
|
||||||
|
let resource_loader = FilesystemResourceLoader::locate();
|
||||||
|
debug!("Created MagicLeapWindow");
|
||||||
|
MagicLeapWindow {
|
||||||
|
framebuffer_id,
|
||||||
|
graphics_client,
|
||||||
|
size: Point2DI32::new(max_width, max_height),
|
||||||
|
frame_handle: ML_HANDLE_INVALID,
|
||||||
|
virtual_camera_array,
|
||||||
|
initial_camera_transforms: None,
|
||||||
|
resource_loader,
|
||||||
|
pose_event: None,
|
||||||
|
running: true,
|
||||||
|
in_frame: false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn size(&self) -> WindowSize {
|
||||||
|
WindowSize {
|
||||||
|
logical_size: self.size,
|
||||||
|
backing_scale_factor: 1.0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn running(&self) -> bool {
|
||||||
|
self.running
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn try_get_event(&mut self) -> Option<Event> {
|
||||||
|
self.pose_event.take().map(Event::CameraTransforms)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn begin_frame(&mut self) {
|
||||||
|
if !self.in_frame {
|
||||||
|
debug!("PF beginning frame");
|
||||||
|
let mut params = unsafe { mem::zeroed() };
|
||||||
|
unsafe {
|
||||||
|
gl::BindFramebuffer(gl::FRAMEBUFFER, self.framebuffer_id);
|
||||||
|
MLGraphicsInitFrameParams(&mut params).unwrap();
|
||||||
|
let mut result = MLGraphicsBeginFrame(self.graphics_client, ¶ms, &mut self.frame_handle, &mut self.virtual_camera_array);
|
||||||
|
if result == ML_RESULT_TIMEOUT {
|
||||||
|
info!("PF frame timeout");
|
||||||
|
let mut sleep = Duration::from_millis(1);
|
||||||
|
let max_sleep = Duration::from_secs(5);
|
||||||
|
while result == ML_RESULT_TIMEOUT {
|
||||||
|
sleep = (sleep * 2).min(max_sleep);
|
||||||
|
info!("PF exponential backoff {}ms", sleep.as_millis());
|
||||||
|
thread::sleep(sleep);
|
||||||
|
result = MLGraphicsBeginFrame(self.graphics_client, ¶ms, &mut self.frame_handle, &mut self.virtual_camera_array);
|
||||||
|
}
|
||||||
|
info!("PF frame finished timeout");
|
||||||
|
}
|
||||||
|
result.unwrap();
|
||||||
|
}
|
||||||
|
let virtual_camera_array = &self.virtual_camera_array;
|
||||||
|
let initial_cameras = self.initial_camera_transforms.get_or_insert_with(||
|
||||||
|
(0..virtual_camera_array.num_virtual_cameras)
|
||||||
|
.map(|i| &virtual_camera_array.virtual_cameras[i as usize])
|
||||||
|
.map(|camera| Transform3DF32::from(camera.transform).post_mul(&Transform3DF32::from_uniform_scale(0.5)))
|
||||||
|
.collect()
|
||||||
|
);
|
||||||
|
let camera_transforms = (0..virtual_camera_array.num_virtual_cameras)
|
||||||
|
.map(|i| &virtual_camera_array.virtual_cameras[i as usize])
|
||||||
|
.zip(initial_cameras)
|
||||||
|
.map(|(camera, initial_camera)| CameraTransform {
|
||||||
|
perspective: Perspective::new(
|
||||||
|
&Transform3DF32::from(camera.projection),
|
||||||
|
RectI32::from(virtual_camera_array.viewport).size(),
|
||||||
|
),
|
||||||
|
view: Transform3DF32::from(camera.transform).inverse().post_mul(initial_camera),
|
||||||
|
}).collect();
|
||||||
|
self.in_frame = true;
|
||||||
|
self.pose_event = Some(camera_transforms);
|
||||||
|
debug!("PF begun frame");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn end_frame(&mut self) {
|
||||||
|
if self.in_frame {
|
||||||
|
debug!("PF ending frame");
|
||||||
|
unsafe {
|
||||||
|
gl::BindFramebuffer(gl::FRAMEBUFFER, 0);
|
||||||
|
for i in 0..self.virtual_camera_array.num_virtual_cameras {
|
||||||
|
let virtual_camera = &self.virtual_camera_array.virtual_cameras[i as usize];
|
||||||
|
MLGraphicsSignalSyncObjectGL(self.graphics_client, virtual_camera.sync_object).unwrap();
|
||||||
|
}
|
||||||
|
MLGraphicsEndFrame(self.graphics_client, self.frame_handle).unwrap();
|
||||||
|
}
|
||||||
|
self.in_frame = false;
|
||||||
|
debug!("PF ended frame");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Drop for MagicLeapWindow {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
self.end_frame();
|
||||||
|
unsafe {
|
||||||
|
gl::DeleteFramebuffers(1, &self.framebuffer_id);
|
||||||
|
MLGraphicsDestroyClient(&mut self.graphics_client);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Logging
|
||||||
|
|
||||||
|
pub struct MagicLeapLogger {
|
||||||
|
tag: CString,
|
||||||
|
level_filter: log::LevelFilter,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl log::Log for MagicLeapLogger {
|
||||||
|
fn enabled(&self, metadata: &log::Metadata) -> bool {
|
||||||
|
metadata.level() <= self.level_filter
|
||||||
|
}
|
||||||
|
|
||||||
|
fn log(&self, record: &log::Record) {
|
||||||
|
let lvl = match record.level() {
|
||||||
|
log::Level::Error => MLLogLevel::Error,
|
||||||
|
log::Level::Warn => MLLogLevel::Warning,
|
||||||
|
log::Level::Info => MLLogLevel::Info,
|
||||||
|
log::Level::Debug => MLLogLevel::Debug,
|
||||||
|
log::Level::Trace => MLLogLevel::Verbose,
|
||||||
|
};
|
||||||
|
let mut msg = SmallVec::<[u8; 128]>::new();
|
||||||
|
write!(msg, "{}\0", record.args()).unwrap();
|
||||||
|
unsafe {
|
||||||
|
MLLoggingLog(lvl, self.tag.as_ptr(), &msg[0] as *const _ as _);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn flush(&self) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl MagicLeapLogger {
|
||||||
|
pub fn new(tag: CString, level_filter: log::LevelFilter) -> Self {
|
||||||
|
MagicLeapLogger { tag, level_filter }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Impl pathfinder traits for c-api types
|
||||||
|
|
||||||
|
impl From<MLTransform> for Transform3DF32 {
|
||||||
|
fn from(mat: MLTransform) -> Self {
|
||||||
|
Transform3DF32::from(mat.rotation)
|
||||||
|
.pre_mul(&Transform3DF32::from(mat.position))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<MLVec3f> for Transform3DF32 {
|
||||||
|
fn from(v: MLVec3f) -> Self {
|
||||||
|
Transform3DF32::from_translation(v.x, v.y, v.z)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<MLRectf> for RectF32 {
|
||||||
|
fn from(r: MLRectf) -> Self {
|
||||||
|
RectF32::new(Point2DF32::new(r.x, r.y), Point2DF32::new(r.w, r.h))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<MLRectf> for RectI32 {
|
||||||
|
fn from(r: MLRectf) -> Self {
|
||||||
|
RectF32::from(r).to_i32()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<MLQuaternionf> for Transform3DF32 {
|
||||||
|
fn from(q: MLQuaternionf) -> Self {
|
||||||
|
Transform3DF32::from_rotation_quaternion(F32x4::new(q.x, q.y, q.z, q.w))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<MLMat4f> for Transform3DF32 {
|
||||||
|
fn from(mat: MLMat4f) -> Self {
|
||||||
|
let a = mat.matrix_colmajor;
|
||||||
|
Transform3DF32::row_major(a[0], a[4], a[8], a[12],
|
||||||
|
a[1], a[5], a[9], a[13],
|
||||||
|
a[2], a[6], a[10], a[14],
|
||||||
|
a[3], a[7], a[11], a[15])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,179 @@
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#include <chrono>
|
||||||
|
#include <cmath>
|
||||||
|
|
||||||
|
#ifndef EGL_EGLEXT_PROTOTYPES
|
||||||
|
#define EGL_EGLEXT_PROTOTYPES
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <EGL/egl.h>
|
||||||
|
#include <EGL/eglext.h>
|
||||||
|
|
||||||
|
#ifndef GL_GLEXT_PROTOTYPES
|
||||||
|
#define GL_GLEXT_PROTOTYPES
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <GLES3/gl3.h>
|
||||||
|
#include <GLES3/gl3ext.h>
|
||||||
|
|
||||||
|
#include <ml_graphics.h>
|
||||||
|
#include <ml_head_tracking.h>
|
||||||
|
#include <ml_perception.h>
|
||||||
|
#include <ml_lifecycle.h>
|
||||||
|
#include <ml_logging.h>
|
||||||
|
#include <ml_privileges.h>
|
||||||
|
|
||||||
|
// Entry point to the Rust code
|
||||||
|
extern "C" MLResult magicleap_pathfinder_demo(EGLDisplay egl_display, EGLContext egl_context);
|
||||||
|
|
||||||
|
// Constants
|
||||||
|
const char application_name[] = "com.mozilla.pathfinder.demo";
|
||||||
|
|
||||||
|
// Structures
|
||||||
|
struct application_context_t {
|
||||||
|
int dummy_value;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct graphics_context_t {
|
||||||
|
|
||||||
|
EGLDisplay egl_display;
|
||||||
|
EGLContext egl_context;
|
||||||
|
|
||||||
|
GLuint framebuffer_id;
|
||||||
|
GLuint vertex_shader_id;
|
||||||
|
GLuint fragment_shader_id;
|
||||||
|
GLuint program_id;
|
||||||
|
|
||||||
|
graphics_context_t();
|
||||||
|
~graphics_context_t();
|
||||||
|
|
||||||
|
void makeCurrent();
|
||||||
|
void swapBuffers();
|
||||||
|
void unmakeCurrent();
|
||||||
|
};
|
||||||
|
|
||||||
|
graphics_context_t::graphics_context_t() {
|
||||||
|
egl_display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
|
||||||
|
|
||||||
|
EGLint major = 4;
|
||||||
|
EGLint minor = 0;
|
||||||
|
eglInitialize(egl_display, &major, &minor);
|
||||||
|
eglBindAPI(EGL_OPENGL_API);
|
||||||
|
|
||||||
|
EGLint config_attribs[] = {
|
||||||
|
EGL_RED_SIZE, 8,
|
||||||
|
EGL_GREEN_SIZE, 8,
|
||||||
|
EGL_BLUE_SIZE, 8,
|
||||||
|
EGL_ALPHA_SIZE, 0,
|
||||||
|
EGL_DEPTH_SIZE, 24,
|
||||||
|
EGL_STENCIL_SIZE, 8,
|
||||||
|
EGL_NONE
|
||||||
|
};
|
||||||
|
EGLConfig egl_config = nullptr;
|
||||||
|
EGLint config_size = 0;
|
||||||
|
eglChooseConfig(egl_display, config_attribs, &egl_config, 1, &config_size);
|
||||||
|
|
||||||
|
EGLint context_attribs[] = {
|
||||||
|
EGL_CONTEXT_MAJOR_VERSION_KHR, 3,
|
||||||
|
EGL_CONTEXT_MINOR_VERSION_KHR, 0,
|
||||||
|
EGL_NONE
|
||||||
|
};
|
||||||
|
egl_context = eglCreateContext(egl_display, egl_config, EGL_NO_CONTEXT, context_attribs);
|
||||||
|
}
|
||||||
|
|
||||||
|
void graphics_context_t::makeCurrent() {
|
||||||
|
eglMakeCurrent(egl_display, EGL_NO_SURFACE, EGL_NO_SURFACE, egl_context);
|
||||||
|
}
|
||||||
|
|
||||||
|
void graphics_context_t::unmakeCurrent() {
|
||||||
|
eglMakeCurrent(NULL, EGL_NO_SURFACE, EGL_NO_SURFACE, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
void graphics_context_t::swapBuffers() {
|
||||||
|
// buffer swapping is implicit on device (MLGraphicsEndFrame)
|
||||||
|
}
|
||||||
|
|
||||||
|
graphics_context_t::~graphics_context_t() {
|
||||||
|
eglDestroyContext(egl_display, egl_context);
|
||||||
|
eglTerminate(egl_display);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Callbacks
|
||||||
|
static void onStop(void* application_context)
|
||||||
|
{
|
||||||
|
((struct application_context_t*)application_context)->dummy_value = 0;
|
||||||
|
ML_LOG(Info, "%s: On stop called.", application_name);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void onPause(void* application_context)
|
||||||
|
{
|
||||||
|
((struct application_context_t*)application_context)->dummy_value = 1;
|
||||||
|
ML_LOG(Info, "%s: On pause called.", application_name);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void onResume(void* application_context)
|
||||||
|
{
|
||||||
|
((struct application_context_t*)application_context)->dummy_value = 2;
|
||||||
|
ML_LOG(Info, "%s: On resume called.", application_name);
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" void logMessage(MLLogLevel lvl, char* msg) {
|
||||||
|
if (MLLoggingLogLevelIsEnabled(lvl)) {
|
||||||
|
MLLoggingLog(lvl, ML_DEFAULT_LOG_TAG, msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
// set up host-specific graphics surface
|
||||||
|
graphics_context_t graphics_context;
|
||||||
|
|
||||||
|
// let system know our app has started
|
||||||
|
MLLifecycleCallbacks lifecycle_callbacks = {};
|
||||||
|
lifecycle_callbacks.on_stop = onStop;
|
||||||
|
lifecycle_callbacks.on_pause = onPause;
|
||||||
|
lifecycle_callbacks.on_resume = onResume;
|
||||||
|
|
||||||
|
struct application_context_t application_context;
|
||||||
|
application_context.dummy_value = 2;
|
||||||
|
|
||||||
|
if (MLResult_Ok != MLLifecycleInit(&lifecycle_callbacks, (void*)&application_context)) {
|
||||||
|
ML_LOG(Error, "%s: Failed to initialize lifecycle.", application_name);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (MLResult_Ok != MLPrivilegesStartup()) {
|
||||||
|
ML_LOG(Error, "%s: Failed to initialize privileges.", application_name);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (MLPrivilegesRequestPrivilege(MLPrivilegeID_WorldReconstruction) != MLPrivilegesResult_Granted) {
|
||||||
|
ML_LOG(Error, "Privilege %d denied.", MLPrivilegeID_WorldReconstruction);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (MLPrivilegesRequestPrivilege(MLPrivilegeID_LowLatencyLightwear) != MLPrivilegesResult_Granted) {
|
||||||
|
ML_LOG(Error, "Privilege %d denied.", MLPrivilegeID_LowLatencyLightwear);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// initialize perception system
|
||||||
|
MLPerceptionSettings perception_settings;
|
||||||
|
if (MLResult_Ok != MLPerceptionInitSettings(&perception_settings)) {
|
||||||
|
ML_LOG(Error, "%s: Failed to initialize perception.", application_name);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (MLResult_Ok != MLPerceptionStartup(&perception_settings)) {
|
||||||
|
ML_LOG(Error, "%s: Failed to startup perception.", application_name);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Run the demo!
|
||||||
|
ML_LOG(Info, "%s: Begin demo.", application_name);
|
||||||
|
MLResult status = magicleap_pathfinder_demo(graphics_context.egl_display, graphics_context.egl_context);
|
||||||
|
ML_LOG(Info, "%s: End demo (%d).", application_name, status);
|
||||||
|
|
||||||
|
// Shut down
|
||||||
|
MLPerceptionShutdown();
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
|
@ -0,0 +1,86 @@
|
||||||
|
#![allow(unused_variables)]
|
||||||
|
#![allow(dead_code)]
|
||||||
|
#![allow(non_snake_case)]
|
||||||
|
|
||||||
|
use crate::c_api::MLCoordinateFrameUID;
|
||||||
|
use crate::c_api::MLGraphicsClipExtentsInfoArray;
|
||||||
|
use crate::c_api::MLGraphicsFrameParams;
|
||||||
|
use crate::c_api::MLGraphicsOptions;
|
||||||
|
use crate::c_api::MLGraphicsRenderTargetsInfo;
|
||||||
|
use crate::c_api::MLGraphicsVirtualCameraInfoArray;
|
||||||
|
use crate::c_api::MLHandle;
|
||||||
|
use crate::c_api::MLHeadTrackingStaticData;
|
||||||
|
use crate::c_api::MLLogLevel;
|
||||||
|
use crate::c_api::MLResult;
|
||||||
|
use crate::c_api::MLSnapshotPtr;
|
||||||
|
use crate::c_api::MLTransform;
|
||||||
|
use std::os::raw::c_char;
|
||||||
|
|
||||||
|
pub unsafe fn MLGraphicsCreateClientGL(options: *const MLGraphicsOptions, gl_context: MLHandle, graphics_client : &mut MLHandle) -> MLResult {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub unsafe fn MLGraphicsDestroyClient(graphics_client: *mut MLHandle) -> MLResult {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub unsafe fn MLHeadTrackingCreate(tracker: *mut MLHandle) -> MLResult {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub unsafe fn MLHeadTrackingGetStaticData(head_tracker: MLHandle, data: *mut MLHeadTrackingStaticData) -> MLResult {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub unsafe fn MLPerceptionGetSnapshot(snapshot: *mut MLSnapshotPtr) -> MLResult {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub unsafe fn MLSnapshotGetTransform(snapshot: MLSnapshotPtr, id: *const MLCoordinateFrameUID, transform: *mut MLTransform) -> MLResult {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub unsafe fn MLPerceptionReleaseSnapshot(snapshot: MLSnapshotPtr) -> MLResult {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub unsafe fn MLLifecycleSetReadyIndication() -> MLResult {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub unsafe fn MLGraphicsGetClipExtents(graphics_client: MLHandle, array: *mut MLGraphicsClipExtentsInfoArray) -> MLResult {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub unsafe fn MLGraphicsGetRenderTargets(graphics_client: MLHandle, targets: *mut MLGraphicsRenderTargetsInfo) -> MLResult {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub unsafe fn MLGraphicsInitFrameParams(params: *mut MLGraphicsFrameParams) -> MLResult {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub unsafe fn MLGraphicsBeginFrame(graphics_client: MLHandle, params: *const MLGraphicsFrameParams, frame_handle: *mut MLHandle, virtual_camera_array: *mut MLGraphicsVirtualCameraInfoArray) -> MLResult {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub unsafe fn MLGraphicsEndFrame(graphics_client: MLHandle, frame_handle: MLHandle) -> MLResult {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub unsafe fn MLGraphicsSignalSyncObjectGL(graphics_client: MLHandle, sync_object: MLHandle) -> MLResult {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub unsafe fn MLGetResultString(result_code: MLResult) -> *const c_char {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub unsafe fn MLLoggingLogLevelIsEnabled(lvl: MLLogLevel) -> bool {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub unsafe fn MLLoggingLog(lvl: MLLogLevel, tag: *const c_char, message: *const c_char) {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue