use crate::{
StereoKitError,
maths::{Bool32T, Pose},
system::{BtnState, IAsset, Log},
};
use std::{
ffi::{CStr, CString, c_char, c_void},
ptr::{NonNull, null_mut},
};
#[repr(C)]
#[derive(Debug, PartialEq)]
pub struct Anchor(pub NonNull<_AnchorT>);
impl Drop for Anchor {
fn drop(&mut self) {
unsafe { anchor_release(self.0.as_ptr()) };
}
}
impl AsRef<Anchor> for Anchor {
fn as_ref(&self) -> &Anchor {
self
}
}
#[repr(C)]
#[derive(Debug)]
pub struct _AnchorT {
_unused: [u8; 0],
}
pub type AnchorT = *mut _AnchorT;
bitflags::bitflags! {
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
#[repr(C)]
pub struct AnchorCaps : u32 {
const Storable = 1;
const Stability = 2;
}
}
unsafe extern "C" {
pub fn anchor_find(asset_id_utf8: *const c_char) -> AnchorT;
pub fn anchor_create(pose: Pose) -> AnchorT;
pub fn anchor_set_id(anchor: AnchorT, asset_id_utf8: *const c_char);
pub fn anchor_get_id(anchor: AnchorT) -> *const c_char;
pub fn anchor_addref(anchor: AnchorT);
pub fn anchor_release(anchor: AnchorT);
pub fn anchor_try_set_persistent(anchor: AnchorT, persistent: Bool32T) -> Bool32T;
pub fn anchor_get_persistent(anchor: AnchorT) -> Bool32T;
pub fn anchor_get_pose(anchor: AnchorT) -> Pose;
pub fn anchor_get_changed(anchor: AnchorT) -> Bool32T;
pub fn anchor_get_name(anchor: AnchorT) -> *const c_char;
pub fn anchor_get_tracked(anchor: AnchorT) -> BtnState;
pub fn anchor_clear_stored();
pub fn anchor_get_capabilities() -> AnchorCaps;
pub fn anchor_get_count() -> i32;
pub fn anchor_get_index(index: i32) -> AnchorT;
pub fn anchor_get_new_count() -> i32;
pub fn anchor_get_new_index(index: i32) -> AnchorT;
pub fn anchor_get_perception_anchor(anchor: AnchorT, perception_spatial_anchor: *mut *mut c_void) -> Bool32T;
}
impl IAsset for Anchor {
fn get_id(&self) -> &str {
self.get_id()
}
}
impl Anchor {
pub fn find<S: AsRef<str>>(id: S) -> Result<Anchor, StereoKitError> {
let c_str = CString::new(id.as_ref())
.map_err(|_| StereoKitError::AnchorFind(id.as_ref().into(), "CString conversion error".to_string()))?;
Ok(Anchor(
NonNull::new(unsafe { anchor_find(c_str.as_ptr()) })
.ok_or(StereoKitError::AnchorFind(id.as_ref().into(), "anchor_find failed".to_string()))?,
))
}
pub fn clone_ref(&self) -> Anchor {
Anchor(
NonNull::new(unsafe { anchor_find(anchor_get_id(self.0.as_ptr())) }).expect("<asset>::clone_ref failed!"),
)
}
pub fn from_pose(pose: impl Into<Pose>) -> Result<Anchor, StereoKitError> {
Ok(Anchor(
NonNull::new(unsafe { anchor_create(pose.into()) })
.ok_or(StereoKitError::AnchorCreate("anchor_create failed!".into()))?,
))
}
pub fn id<S: AsRef<str>>(&mut self, id: S) -> &mut Self {
let c_str = CString::new(id.as_ref()).unwrap();
unsafe { anchor_set_id(self.0.as_ptr(), c_str.as_ptr()) };
self
}
pub fn clear_store() {
unsafe { anchor_clear_stored() };
}
pub fn anchors() -> AnchorIter {
AnchorIter::anchors()
}
pub fn new_anchors() -> AnchorIter {
AnchorIter::new_anchors()
}
pub fn try_set_persistent(&self, persistent: bool) -> bool {
unsafe { anchor_try_set_persistent(self.0.as_ptr(), persistent as Bool32T) != 0 }
}
pub fn get_capabilities() -> AnchorCaps {
unsafe { anchor_get_capabilities() }
}
pub fn get_id(&self) -> &str {
unsafe { CStr::from_ptr(anchor_get_id(self.0.as_ptr())) }.to_str().unwrap()
}
pub fn get_pose(&self) -> Pose {
unsafe { anchor_get_pose(self.0.as_ptr()) }
}
pub fn get_tracked(&self) -> BtnState {
unsafe { anchor_get_tracked(self.0.as_ptr()) }
}
pub fn get_persistent(&self) -> bool {
unsafe { anchor_get_persistent(self.0.as_ptr()) != 0 }
}
pub fn get_name(&self) -> &str {
unsafe { CStr::from_ptr(anchor_get_name(self.0.as_ptr())).to_str().unwrap() }
}
pub fn try_get_perception_anchor<T>(&self) -> Option<*mut T> {
let out_anchor: *mut T = null_mut();
if unsafe { anchor_get_perception_anchor(self.0.as_ptr(), out_anchor as *mut *mut c_void) } != 0 {
Some(out_anchor)
} else {
None
}
}
}
pub struct AnchorIter {
index: i32,
only_new: bool,
}
impl Iterator for AnchorIter {
type Item = Anchor;
fn next(&mut self) -> Option<Self::Item> {
self.index += 1;
if self.only_new {
let count = unsafe { anchor_get_new_count() };
if self.index < count {
match NonNull::new(unsafe { anchor_get_new_index(self.index) }) {
None => {
Log::err(format!(
"new anchor at index {:?}, is missing when {:?} new anchors are expected",
self.index, count,
));
None
}
Some(anchor) => Some(Anchor(anchor)),
}
} else {
None
}
} else {
let count = unsafe { anchor_get_count() };
if self.index < count {
match NonNull::new(unsafe { anchor_get_index(self.index) }) {
None => {
Log::err(format!(
"anchor at index {:?}, is missing when {:?} anchors are expected",
self.index, count,
));
None
}
Some(anchor) => Some(Anchor(anchor)),
}
} else {
None
}
}
}
}
impl AnchorIter {
pub fn get_count(&self) -> i32 {
if self.only_new { unsafe { anchor_get_new_count() } } else { unsafe { anchor_get_count() } }
}
pub fn anchors() -> AnchorIter {
AnchorIter { index: -1, only_new: false }
}
pub fn new_anchors() -> AnchorIter {
AnchorIter { index: -1, only_new: true }
}
}