Render model components

This commit is contained in:
Benjamin Saunders
2017-07-15 16:12:21 -07:00
parent ac7832fdac
commit 8894438fd8
4 changed files with 147 additions and 32 deletions

View File

@ -21,28 +21,14 @@ use super::*;
impl<'a> Compositor<'a> {
pub fn vulkan_instance_extensions_required(&self) -> Vec<CString> {
let temp = unsafe {
let n = self.0.GetVulkanInstanceExtensionsRequired.unwrap()(ptr::null_mut(), 0);
let mut buffer: Vec<u8> = Vec::new();
buffer.resize(n as usize, mem::uninitialized());
(self.0.GetVulkanInstanceExtensionsRequired.unwrap())(buffer.as_mut_ptr() as *mut i8, n);
buffer.truncate((n-1) as usize); // Strip trailing null
buffer
};
temp.split(|&x| x == b' ').map(|x| CString::new(x.to_vec()).expect("extension name contained null byte")).collect()
let temp = unsafe { get_string(|ptr, n| self.0.GetVulkanInstanceExtensionsRequired.unwrap()(ptr, n)) }.unwrap();
temp.as_bytes().split(|&x| x == b' ').map(|x| CString::new(x.to_vec()).expect("extension name contained null byte")).collect()
}
/// Safety: physical_device must be a valid VkPhysicalDevice
pub unsafe fn vulkan_device_extensions_required(&self, physical_device: *mut VkPhysicalDevice_T) -> Vec<CString> {
let temp = {
let n = self.0.GetVulkanDeviceExtensionsRequired.unwrap()(physical_device, ptr::null_mut(), 0);
let mut buffer: Vec<u8> = Vec::new();
buffer.resize(n as usize, mem::uninitialized());
(self.0.GetVulkanDeviceExtensionsRequired.unwrap())(physical_device as *mut _, buffer.as_mut_ptr() as *mut i8, n);
buffer.truncate((n-1) as usize); // Strip trailing null
buffer
};
temp.split(|&x| x == b' ').map(|x| CString::new(x.to_vec()).expect("extension name contained null byte")).collect()
let temp = get_string(|ptr, n| self.0.GetVulkanDeviceExtensionsRequired.unwrap()(physical_device, ptr, n)).unwrap();
temp.as_bytes().split(|&x| x == b' ').map(|x| CString::new(x.to_vec()).expect("extension name contained null byte")).collect()
}
/// Sets tracking space returned by WaitGetPoses

View File

@ -1,8 +1,8 @@
extern crate openvr_sys;
use std::sync::atomic::{Ordering, AtomicBool, ATOMIC_BOOL_INIT};
use std::{fmt, error};
use std::ffi::CStr;
use std::{fmt, error, ptr, mem};
use std::ffi::{CStr, CString};
use openvr_sys as sys;
@ -130,3 +130,32 @@ pub enum Eye {
Left = sys::EVREye_Eye_Left as isize,
Right = sys::EVREye_Eye_Right as isize,
}
/// Helper to call OpenVR functions that return strings
unsafe fn get_string<F: FnMut(*mut std::os::raw::c_char, u32) -> u32>(mut f: F) -> Option<CString> {
let n = f(ptr::null_mut(), 0);
if n == 0 { return None }
let mut storage = Vec::new();
storage.reserve_exact(n as usize);
storage.resize(n as usize, mem::uninitialized());
let n_ = f(storage.as_mut_ptr() as *mut _, n);
assert!(n == n_);
storage.truncate((n-1) as usize); // Strip trailing null
Some(CString::from_vec_unchecked(storage))
}
#[repr(C)]
#[derive(Debug, Copy, Clone)]
pub struct ControllerAxis {
pub x: f32,
pub y: f32,
}
#[repr(C)]
#[derive(Debug, Copy, Clone)]
pub struct ControllerState {
pub packet_num: u32,
pub button_pressed: u64,
pub button_touched: u64,
pub axis: [ControllerAxis; 5],
}

View File

@ -1,9 +1,9 @@
use std::{fmt, ptr, slice};
use std::ffi::CStr;
use std::{fmt, ptr, slice, mem};
use std::ffi::{CStr, CString};
use openvr_sys as sys;
use {RenderModels};
use {RenderModels, ControllerState, get_string};
impl<'a> RenderModels<'a> {
/// Loads and returns a render model for use in the application. `name` should be a render model name from the
@ -14,7 +14,7 @@ impl<'a> RenderModels<'a> {
pub fn load_render_model(&self, name: &CStr) -> Result<Option<Model>> {
let mut ptr = ptr::null_mut();
let r = unsafe {
self.0.LoadRenderModel_Async.unwrap()(name as *const _ as *mut _, &mut ptr)
self.0.LoadRenderModel_Async.unwrap()(name.as_ptr() as *mut _, &mut ptr)
};
match Error(r) {
error::NONE => Ok(Some(Model { ptr: ptr, sys: self.0 })),
@ -23,6 +23,64 @@ impl<'a> RenderModels<'a> {
}
}
/// Returns the number of components of the specified render model.
///
/// Components are useful when client application wish to draw, label, or otherwise interact with components of tracked objects.
/// Examples controller components:
/// renderable things such as triggers, buttons
/// non-renderable things which include coordinate systems such as 'tip', 'base', a neutral controller agnostic hand-pose
/// If all controller components are enumerated and rendered, it will be equivalent to drawing the traditional render model
/// Returns 0 if components not supported, >0 otherwise
pub fn component_count(&self, model: &CStr) -> u32 {
unsafe { self.0.GetComponentCount.unwrap()(model.as_ptr() as *mut _) }
}
/// Get the names of available components.
///
/// `component` does not correlate to a tracked device index, but is only used for iterating over all available
/// components. If it's out of range, this function will return None. Otherwise, it will return the size of the
/// buffer required for the name.
pub fn component_name(&self, model: &CStr, component: u32) -> Option<CString> {
unsafe { get_string(|ptr, n| self.0.GetComponentName.unwrap()(model.as_ptr() as *mut _, component, ptr, n)) }
}
/// Gets all component names of a given model
pub fn component_names(&self, model: &CStr) -> ::std::vec::IntoIter<CString> { // FIXME: impl Iterator rather than allocating
let n = self.component_count(model);
(0..n).map(|i| self.component_name(model, i).expect("inconsistent component presence reported by OpenVR")).collect::<Vec<_>>().into_iter()
}
/// Use this to get the render model name for the specified rendermode/component combination, to be passed to
/// `load_render_model`.
///
/// If the component name is out of range, this function will return None.
/// Otherwise, it will return the size of the buffer required for the name.
pub fn component_render_model_name(&self, model: &CStr, component: &CStr) -> Option<CString> {
unsafe {
get_string(|ptr, n| self.0.GetComponentRenderModelName.unwrap()(
model.as_ptr() as *mut _, component.as_ptr() as *mut _, ptr, n))
}
}
/// Use this to query information about the component, as a function of the controller state.
///
/// Returns None if the component is invalid or should not be rendered in the current state.
///
/// For dynamic controller components (ex: trigger) values will reflect component motions
/// For static components this will return a consistent value independent of the VRControllerState_t
pub fn component_state(&self, model: &CStr, component: &CStr, state: &ControllerState, mode: &ControllerMode) -> Option<ComponentState> {
unsafe {
let mut out = mem::uninitialized();
if self.0.GetComponentState.unwrap()(model.as_ptr() as *mut _, component.as_ptr() as *mut _,
state as *const _ as *mut _, mode as *const _ as *mut _,
&mut out as *mut _ as *mut _) {
Some(out)
} else {
None
}
}
}
/// Loads and returns a texture for use in the application. Texture IDs can be obtained from
/// `Model::diffuse_texture_id()`.
///
@ -162,3 +220,33 @@ pub struct Vertex {
pub normal: [f32; 3],
pub texture_coord: [f32; 2],
}
#[repr(C)]
#[derive(Debug, Copy, Clone)]
pub struct ControllerMode {
pub scroll_wheel_visible: bool,
}
impl Default for ControllerMode {
fn default() -> Self { ControllerMode { scroll_wheel_visible: false } }
}
#[repr(C)]
#[derive(Debug, Copy, Clone)]
pub struct ComponentState {
pub tracking_to_component_render_model: [[f32; 4]; 3],
pub tracking_to_component_local: [[f32; 4]; 3],
pub properties: ComponentProperties,
}
type ComponentProperties = sys::VRComponentProperties;
pub mod component_properties {
use super::{sys, ComponentProperties};
pub const IS_STATIC: ComponentProperties = sys::EVRComponentProperty_VRComponentProperty_IsStatic;
pub const IS_VISIBLE: ComponentProperties = sys::EVRComponentProperty_VRComponentProperty_IsVisible;
pub const IS_TOUCHED: ComponentProperties = sys::EVRComponentProperty_VRComponentProperty_IsTouched;
pub const IS_PRESSED: ComponentProperties = sys::EVRComponentProperty_VRComponentProperty_IsPressed;
pub const IS_SCROLLED: ComponentProperties = sys::EVRComponentProperty_VRComponentProperty_IsScrolled;
}

View File

@ -1,7 +1,7 @@
//! The `System` interface provides access to display configuration information, tracking data, controller state,
//! events, and device properties. It is the main interface of OpenVR.
use std::{mem, ptr};
use std::mem;
use std::ffi::CString;
use openvr_sys as sys;
@ -205,13 +205,25 @@ impl<'a> System<'a> {
pub fn string_tracked_device_property(&self, device: TrackedDeviceIndex, property: TrackedDeviceProperty) -> Result<CString, TrackedPropertyError> {
unsafe {
let mut error = mem::uninitialized();
let n = self.0.GetStringTrackedDeviceProperty.unwrap()(device, property, ptr::null_mut(), 0, &mut error);
if n == 0 { return Err(TrackedPropertyError(error)); }
let mut storage = Vec::new();
storage.reserve_exact(n as usize);
storage.resize(n as usize, mem::uninitialized());
self.0.GetStringTrackedDeviceProperty.unwrap()(device, property, storage.as_mut_ptr() as *mut i8, n, ptr::null_mut());
Ok(CString::from_vec_unchecked(storage))
let res = get_string(|ptr, n| self.0.GetStringTrackedDeviceProperty.unwrap()(device, property, ptr, n, &mut error));
res.map_or(Err(TrackedPropertyError(error)), Ok)
}
}
/// Looks up the current input state of a controller.
///
/// Returns None if the device is not a controller, or if the user is currently in the system menu.
///
/// Needed for rendering controller components (e.g. trigger) accurately wrt. user input using the `render_models`
/// API.
pub fn controller_state(&self, device: TrackedDeviceIndex) -> Option<ControllerState> {
unsafe {
let mut state = mem::uninitialized();
if self.0.GetControllerState.unwrap()(device, &mut state as *mut _ as *mut _, mem::size_of_val(&state) as u32) {
Some(state)
} else {
None
}
}
}
}