1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162
//! Lower level FFI stuff. Mostly used internally, but exposed in case the abstractions
//! of this library are too restrictive.
//! Using this should not be necessary for the usage of this crate, but the
//! public APIs have been provided while this crate is still feature-incomplete.
use wasm_bindgen::{JsCast, prelude::*};
use std::convert::TryFrom;
use js_sys::{Array, Object};
use once_cell::sync::Lazy;
static AFRAME: Lazy<Option<Aframe>> = Lazy::new(Aframe::get);
#[wasm_bindgen]
extern
{
/// [registering-a-primitive](https://aframe.io/docs/1.2.0/introduction/html-and-primitives.html#registering-a-primitive)
#[wasm_bindgen(js_namespace = AFRAME)]
pub fn registerPrimitive(name: &str, definition: JsValue);
/// [register-component-name-definition](https://aframe.io/docs/1.2.0/core/component.html#aframe-registercomponent-name-definition)
#[wasm_bindgen(js_namespace = AFRAME)]
pub fn registerComponent(name: &str, data: JsValue);
/// [registering-a-system](https://aframe.io/docs/1.2.0/core/systems.html#registering-a-system)
#[wasm_bindgen(js_namespace = AFRAME)]
pub fn registerSystem(name: &str, data: JsValue);
/// [register-a-custom-shader-material](https://aframe.io/docs/1.2.0/components/material.html#register-a-custom-shader-material)
#[wasm_bindgen(js_namespace = AFRAME)]
pub fn registerShader(name: &str, data: JsValue);
/// [register-a-custom-geometry](https://aframe.io/docs/1.2.0/components/geometry.html#register-a-custom-geometry)
#[wasm_bindgen(js_namespace = AFRAME)]
pub fn registerGeometry(name: &str, data: JsValue);
/// [aframe_properties_registerelement](https://aframe.io/docs/1.2.0/core/globals.html#aframe_properties_registerelement)
#[wasm_bindgen(js_namespace = AFRAME)]
pub fn registerElement(name: &str, data: JsValue);
// /// Checks if a VR headset is connected by looking for orientation data.
// #[wasm_bindgen(js_namespace = ["AFRAME", "utils", "device"])]
// pub fn checkHeadsetConnected() -> bool;
// /// Checks if device is Gear VR.
// #[wasm_bindgen(js_namespace = ["AFRAME", "utils", "device"])]
// pub fn isGearVR() -> bool;
// /// Checks if device is Oculus Go.
// #[wasm_bindgen(js_namespace = ["AFRAME", "utils", "device"])]
// pub fn isOculusGo() -> bool;
// /// Checks if device is a smartphone.
// #[wasm_bindgen(js_namespace = ["AFRAME", "utils", "device"])]
// pub fn isMobile() -> bool;
}
/// Access a field from an object
pub(crate) fn access_field(obj: &Object, field_name: &'static str) -> Option<JsValue>
{
Object::entries(obj)
.iter()
.find(|e| e.dyn_ref::<Array>()
.filter(|entry| entry
.iter()
.next()
.and_then(|key| key.as_string())
.filter(|key_str| key_str == field_name)
.is_some())
.is_some())
}
/// Global [three.js](https://threejs.org/) object.
pub fn three_js() -> Option<JsValue>
{
AFRAME.as_ref().and_then(|aframe| access_field(&aframe.0, "THREE"))
}
/// Object of registered components.
pub fn components() -> Option<JsValue>
{
AFRAME.as_ref().and_then(|aframe| access_field(&aframe.0, "components"))
}
/// Object of registered geometries.
pub fn geometries() -> Option<JsValue>
{
AFRAME.as_ref().and_then(|aframe| access_field(&aframe.0, "geometries"))
}
/// Object of registered primitives.
pub fn primitives() -> Option<JsValue>
{
AFRAME.as_ref()
.and_then(|aframe| access_field(&aframe.0, "primitives"))
.and_then(|primitives|
{
primitives.unchecked_into::<Array>()
.iter()
.skip(1)
.next()
.and_then(|primitives| access_field(primitives.unchecked_ref(), "primitives"))
})
}
/// Object of registered shaders.
pub fn shaders() -> Option<JsValue>
{
AFRAME.as_ref().and_then(|aframe| access_field(&aframe.0, "shaders"))
}
/// Object of registered systems.
pub fn systems() -> Option<JsValue>
{
AFRAME.as_ref().and_then(|aframe| access_field(&aframe.0, "systems"))
}
/// Version of A-Frame build.
pub fn version() -> Option<JsValue>
{
AFRAME.as_ref().and_then(|aframe| access_field(&aframe.0, "version"))
}
pub fn utils() -> Option<JsValue>
{
AFRAME.as_ref()
.and_then(|aframe| access_field(&aframe.0, "utils"))
.and_then(|utils| utils.unchecked_into::<Array>().iter().skip(1).next())
}
pub fn device() -> Option<JsValue>
{
utils()
.and_then(|utils|
{
access_field(utils.unchecked_ref(), "device")
.and_then(|utils| utils.unchecked_into::<Array>().iter().skip(1).next())
})
}
struct Aframe(Object);
unsafe impl Send for Aframe {}
unsafe impl Sync for Aframe {}
impl Aframe
{
fn get() -> Option<Self>
{
web_sys::window()
.ok_or("Failed to access window")
.and_then(Aframe::try_from)
.ok()
}
}
impl TryFrom<web_sys::Window> for Aframe
{
type Error = &'static str;
fn try_from(window: web_sys::Window) -> Result<Self, Self::Error>
{
window.get("AFRAME")
.map(Aframe)
.ok_or("Failed to access AFRAME global")
}
}