#![warn(unused_imports, missing_docs)]
#![deny(bare_trait_objects)]
#[macro_use]
mod macros;
pub mod builder;
pub mod errors;
#[cfg(feature = "ffi")]
pub mod ffi;
pub mod write;
mod joint;
mod parse;
use bstr::{
io::{BufReadExt, ByteLines},
BStr, BString, B,
};
use mint::Vector3;
use num_traits::{one, zero, One, Zero};
use std::{
convert::TryFrom,
fmt,
io::{self, Cursor, Write},
iter::Enumerate,
mem,
ops::{Index, IndexMut, Range},
str::{self, FromStr},
time::Duration,
};
pub use joint::{Joint, JointData, JointMut, JointName, Joints, JointsMut};
#[doc(hidden)]
pub use macros::BvhLiteralBuilder;
use errors::{LoadError, ParseChannelError, SetMotionError};
struct CachedEnumerate<I> {
iter: Enumerate<I>,
last_enumerator: Option<usize>,
}
impl<I> CachedEnumerate<I> {
#[inline]
fn new(iter: Enumerate<I>) -> Self {
CachedEnumerate {
iter,
last_enumerator: None,
}
}
#[inline]
fn last_enumerator(&self) -> Option<usize> {
self.last_enumerator
}
}
impl<I: Iterator> Iterator for CachedEnumerate<I> {
type Item = <Enumerate<I> as Iterator>::Item;
#[inline]
fn next(&mut self) -> Option<Self::Item> {
let (curr, item) = self.iter.next()?;
self.last_enumerator = Some(curr);
Some((curr, item))
}
#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
self.iter.size_hint()
}
}
type EnumeratedLines<'a> = CachedEnumerate<ByteLines<&'a mut dyn BufReadExt>>;
impl EnumeratedLines<'_> {
pub fn next_non_empty_line(&mut self) -> Option<<Self as Iterator>::Item> {
let mut next = self.next();
loop {
match next {
None => return None,
Some((idx, result)) => {
let string = match result {
Ok(s) => s,
Err(e) => return Some((idx, Err(e))),
};
if string.trim().is_empty() {
next = self.next()
} else {
return Some((idx, Ok(string)));
}
}
}
}
}
}
#[inline]
pub fn from_reader<R: BufReadExt>(data: R) -> Result<Bvh, LoadError> {
Bvh::from_reader(data)
}
#[inline]
pub fn from_bytes<B: AsRef<[u8]>>(bytes: B) -> Result<Bvh, LoadError> {
Bvh::from_bytes(bytes)
}
#[inline]
pub fn from_str(string: &str) -> Result<Bvh, LoadError> {
Bvh::from_str(string)
}
#[derive(Clone, Default, Debug, PartialEq)]
pub struct Bvh {
joints: Vec<JointData>,
motion_values: Vec<f32>,
num_frames: usize,
num_channels: usize,
frame_time: Duration,
}
impl Bvh {
#[inline]
pub fn new() -> Self {
Default::default()
}
#[inline]
pub fn from_bytes<B: AsRef<[u8]>>(bytes: B) -> Result<Self, LoadError> {
Bvh::from_reader(Cursor::new(bytes))
}
pub fn from_reader<R: BufReadExt>(mut reader: R) -> Result<Self, LoadError> {
let reader: &mut dyn BufReadExt = reader.by_ref();
let mut lines = CachedEnumerate::new(reader.byte_lines().enumerate());
let mut bvh = Bvh::default();
bvh.read_joints(&mut lines)?;
bvh.read_motion(&mut lines)?;
Ok(bvh)
}
#[inline]
pub fn write_to<W: Write>(&self, writer: &mut W) -> io::Result<()> {
write::WriteOptions::default().write(self, writer)
}
#[inline]
pub fn to_bstring(&self) -> BString {
write::WriteOptions::default().write_to_string(self)
}
#[inline]
pub fn root_joint(&self) -> Option<Joint<'_>> {
if self.joints.is_empty() {
None
} else {
Some(Joint {
index: 0,
joints: &self.joints[..],
})
}
}
#[inline]
pub fn joints(&self) -> Joints<'_> {
Joints::iter_root(&self.joints[..])
}
pub fn joints_mut(&mut self) -> JointsMut<'_> {
JointsMut::iter_root(&mut self.joints[..])
}
#[inline]
pub fn frames(&self) -> Frames<'_> {
Frames {
motion_values: &self.motion_values[..],
num_channels: self.num_channels,
num_frames: self.num_frames,
curr_frame: 0,
}
}
#[inline]
pub fn frames_mut(&mut self) -> FramesMut<'_> {
FramesMut {
motion_values: &mut self.motion_values[..],
num_channels: self.num_channels,
num_frames: self.num_frames,
curr_frame: 0,
}
}
#[inline]
pub fn get_motion(&self, frame: usize, channel: &Channel) -> f32 {
*self.frames().nth(frame).unwrap().index(channel)
}
#[inline]
pub fn try_get_motion(&self, frame: usize, channel: &Channel) -> Option<f32> {
self.frames()
.nth(frame)
.and_then(|f| f.get(channel))
.map(|m| *m)
}
#[inline]
pub fn set_motion(&mut self, frame: usize, channel: &Channel, new_motion: f32) {
self.try_set_motion(frame, channel, new_motion).unwrap();
}
#[inline]
pub fn try_set_motion<'a>(
&mut self,
frame: usize,
channel: &'a Channel,
new_motion: f32,
) -> Result<(), SetMotionError<'a>> {
let m = self
.frames_mut()
.nth(frame)
.ok_or(SetMotionError::BadFrame(frame))
.and_then(|f| {
f.get_mut(channel)
.ok_or(SetMotionError::BadChannel(channel))
})?;
*m = new_motion;
Ok(())
}
#[inline]
pub const fn num_frames(&self) -> usize {
self.num_frames
}
#[inline]
pub const fn num_channels(&self) -> usize {
self.num_channels
}
#[inline]
pub const fn frame_time(&self) -> &Duration {
&self.frame_time
}
#[inline]
pub fn set_frame_time(&mut self, new_frame_time: Duration) {
self.frame_time = new_frame_time;
}
}
impl fmt::Display for Bvh {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Display::fmt(&self.to_bstring(), f)
}
}
impl FromStr for Bvh {
type Err = LoadError;
#[inline]
fn from_str(string: &str) -> Result<Self, Self::Err> {
Bvh::from_bytes(string.as_bytes())
}
}
impl TryFrom<&'_ str> for Bvh {
type Error = LoadError;
#[inline]
fn try_from(string: &'_ str) -> Result<Self, Self::Error> {
FromStr::from_str(string)
}
}
impl TryFrom<&'_ BStr> for Bvh {
type Error = LoadError;
#[inline]
fn try_from(string: &'_ BStr) -> Result<Self, Self::Error> {
Bvh::from_bytes(string.as_bytes())
}
}
impl TryFrom<&'_ [u8]> for Bvh {
type Error = LoadError;
#[inline]
fn try_from(bytes: &'_ [u8]) -> Result<Self, Self::Error> {
Bvh::from_bytes(bytes)
}
}
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub struct Channel {
channel_type: ChannelType,
motion_index: usize,
}
impl Channel {
#[inline]
const fn new(channel_type: ChannelType, motion_index: usize) -> Self {
Channel {
channel_type,
motion_index,
}
}
#[inline]
pub const fn channel_type(&self) -> ChannelType {
self.channel_type
}
#[inline]
pub const fn motion_index(&self) -> usize {
self.motion_index
}
}
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub enum ChannelType {
RotationX,
RotationY,
RotationZ,
PositionX,
PositionY,
PositionZ,
}
impl ChannelType {
#[inline]
pub fn from_bytes<B>(s: &B) -> Result<Self, ParseChannelError>
where
B: AsRef<[u8]> + ?Sized,
{
let s = BStr::new(s);
match s.as_bytes() {
b"Xrotation" => Ok(ChannelType::RotationX),
b"Yrotation" => Ok(ChannelType::RotationY),
b"Zrotation" => Ok(ChannelType::RotationZ),
b"Xposition" => Ok(ChannelType::PositionX),
b"Yposition" => Ok(ChannelType::PositionY),
b"Zposition" => Ok(ChannelType::PositionZ),
_ => Err(ParseChannelError::from(s)),
}
}
#[inline]
pub fn is_rotation(&self) -> bool {
match *self {
ChannelType::RotationX | ChannelType::RotationY | ChannelType::RotationZ => true,
_ => false,
}
}
#[inline]
pub fn is_position(&self) -> bool {
!self.is_rotation()
}
#[inline]
pub fn axis(&self) -> Axis {
match *self {
ChannelType::RotationX | ChannelType::PositionX => Axis::X,
ChannelType::RotationY | ChannelType::PositionY => Axis::Y,
ChannelType::RotationZ | ChannelType::PositionZ => Axis::Z,
}
}
#[inline]
pub fn axis_vector<T: Clone + One + Zero>(&self) -> Vector3<T> {
self.axis().vector::<T>()
}
#[inline]
pub fn as_str(&self) -> &'static str {
match *self {
ChannelType::RotationX => "Xrotation",
ChannelType::RotationY => "Yrotation",
ChannelType::RotationZ => "Zrotation",
ChannelType::PositionX => "Xposition",
ChannelType::PositionY => "Yposition",
ChannelType::PositionZ => "Zposition",
}
}
#[inline]
pub fn as_bstr(&self) -> &'static BStr {
B(self.as_str())
}
}
impl TryFrom<&'_ BStr> for ChannelType {
type Error = ParseChannelError;
#[inline]
fn try_from(string: &BStr) -> Result<Self, Self::Error> {
ChannelType::from_bytes(string)
}
}
impl TryFrom<&'_ [u8]> for ChannelType {
type Error = ParseChannelError;
#[inline]
fn try_from(string: &[u8]) -> Result<Self, Self::Error> {
ChannelType::from_bytes(string)
}
}
impl TryFrom<&'_ str> for ChannelType {
type Error = ParseChannelError;
#[inline]
fn try_from(string: &str) -> Result<Self, Self::Error> {
ChannelType::from_str(string)
}
}
impl FromStr for ChannelType {
type Err = ParseChannelError;
#[inline]
fn from_str(s: &str) -> Result<Self, Self::Err> {
ChannelType::from_bytes(s)
}
}
impl fmt::Display for ChannelType {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.write_str(self.as_str())
}
}
#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
pub enum Axis {
X,
Y,
Z,
}
impl Axis {
#[inline]
pub fn vector<T: Clone + One + Zero>(&self) -> Vector3<T> {
let (_1, _0) = (one, zero);
match *self {
Axis::X => [_1(), _0(), _0()].into(),
Axis::Y => [_0(), _1(), _0()].into(),
Axis::Z => [_0(), _0(), _1()].into(),
}
}
}
impl fmt::Display for Axis {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let s = match *self {
Axis::X => "x",
Axis::Y => "y",
Axis::Z => "z",
};
f.write_str(s)
}
}
#[derive(Debug)]
pub struct Frames<'a> {
motion_values: &'a [f32],
num_channels: usize,
num_frames: usize,
curr_frame: usize,
}
impl Frames<'_> {
#[inline]
pub const fn len(&self) -> usize {
self.num_frames - self.curr_frame
}
#[inline]
pub const fn is_empty(&self) -> bool {
self.len() == 0
}
}
impl<'a> Iterator for Frames<'a> {
type Item = &'a Frame;
fn next(&mut self) -> Option<Self::Item> {
let range = frames_iter_logic(self.num_channels, self.num_frames, self.curr_frame)?;
self.curr_frame += 1;
Some(Frame::from_slice(&self.motion_values[range]))
}
}
#[derive(Debug)]
pub struct FramesMut<'a> {
motion_values: &'a mut [f32],
num_channels: usize,
num_frames: usize,
curr_frame: usize,
}
impl FramesMut<'_> {
#[inline]
pub const fn len(&self) -> usize {
self.num_frames - self.curr_frame
}
#[inline]
pub const fn is_empty(&self) -> bool {
self.len() == 0
}
}
impl<'a> Iterator for FramesMut<'a> {
type Item = &'a mut Frame;
fn next(&mut self) -> Option<Self::Item> {
let range = frames_iter_logic(self.num_channels, self.num_frames, self.curr_frame)?;
self.curr_frame += 1;
unsafe {
Some(mem::transmute::<&mut Frame, &'a mut Frame>(
Frame::from_mut_slice(&mut self.motion_values[range]),
))
}
}
}
#[inline(always)]
fn frames_iter_logic(
num_channels: usize,
num_frames: usize,
curr_frame: usize,
) -> Option<Range<usize>> {
if num_frames == 0 || curr_frame >= num_frames {
return None;
}
let start = curr_frame * num_channels;
let end = start + num_channels;
Some(Range { start, end })
}
#[derive(PartialEq)]
pub struct Frame([f32]);
impl fmt::Debug for Frame {
#[inline]
fn fmt(&self, fmtr: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Debug::fmt(&self.0, fmtr)
}
}
impl Frame {
#[inline]
fn from_slice<'a>(frame_motions: &'a [f32]) -> &'a Frame {
unsafe { &*(frame_motions as *const [f32] as *const Frame) }
}
#[inline]
fn from_mut_slice<'a>(frame_motions: &'a mut [f32]) -> &'a mut Frame {
unsafe { &mut *(frame_motions as *mut [f32] as *mut Frame) }
}
#[inline]
pub fn len(&self) -> usize {
self.0.len()
}
pub fn is_empty(&self) -> bool {
self.0.is_empty()
}
#[inline]
pub fn get(&self, channel: &Channel) -> Option<&f32> {
self.0.get(channel.motion_index)
}
#[inline]
pub fn get_mut(&mut self, channel: &Channel) -> Option<&mut f32> {
self.0.get_mut(channel.motion_index)
}
pub fn as_slice(&self) -> &[f32] {
&self.0[..]
}
pub fn as_mut_slice(&mut self) -> &mut [f32] {
&mut self.0[..]
}
}
impl Index<&Channel> for Frame {
type Output = f32;
#[inline]
fn index(&self, channel: &Channel) -> &Self::Output {
self.0.index(channel.motion_index)
}
}
impl IndexMut<&Channel> for Frame {
fn index_mut(&mut self, channel: &Channel) -> &mut Self::Output {
self.0.index_mut(channel.motion_index)
}
}
const NSEC_FACTOR: f64 = 1000_000_000.0;
#[inline]
fn fraction_seconds_to_duration(x: f64) -> Duration {
Duration::from_nanos((x * NSEC_FACTOR) as u64)
}
#[inline]
fn duation_to_fractional_seconds(duration: &Duration) -> f64 {
duration.subsec_nanos() as f64 / NSEC_FACTOR
}