///|
fn count_joints(joint : BvhJoint) -> Int {
for child in joint.children; count = 1 {
continue count + count_joints(child)
} nobreak {
count
}
}
///|
fn count_end_sites(joint : BvhJoint) -> Int {
let self_count = joint.end_sites.length()
for child in joint.children; count = self_count {
continue count + count_end_sites(child)
} nobreak {
count
}
}
///|
fn max_int(a : Int, b : Int) -> Int {
if a >= b {
a
} else {
b
}
}
///|
fn abs_double(value : Double) -> Double {
if value < 0.0 {
-value
} else {
value
}
}
///|
fn max_double(a : Double, b : Double) -> Double {
if a >= b {
a
} else {
b
}
}
///|
fn min_double(a : Double, b : Double) -> Double {
if a <= b {
a
} else {
b
}
}
///|
pub fn max_joint_depth(joint : BvhJoint) -> Int {
for child in joint.children; depth = joint.depth {
continue max_int(depth, max_joint_depth(child))
} nobreak {
depth
}
}
///|
fn collect_joint_paths_into(joint : BvhJoint, out : Array[String]) -> Unit {
out.push(joint.path)
for child in joint.children {
collect_joint_paths_into(child, out)
}
}
///|
pub fn joint_paths(document : BvhDocument) -> Array[String] {
let out : Array[String] = []
if document.root.name.length() > 0 {
collect_joint_paths_into(document.root, out)
}
out
}
///|
fn collect_joint_names_into(joint : BvhJoint, out : Array[String]) -> Unit {
out.push(joint.name)
for child in joint.children {
collect_joint_names_into(child, out)
}
}
///|
pub fn joint_names(document : BvhDocument) -> Array[String] {
let out : Array[String] = []
if document.root.name.length() > 0 {
collect_joint_names_into(document.root, out)
}
out
}
///|
fn find_joint_by_name_in(joint : BvhJoint, name : String) -> BvhJoint? {
if joint.name == name {
Some(joint)
} else {
for child in joint.children {
match find_joint_by_name_in(child, name) {
Some(found) => break Some(found)
None => ()
}
} nobreak {
None
}
}
}
///|
pub fn find_joint(document : BvhDocument, name : String) -> BvhJoint? {
if document.root.name.length() == 0 {
None
} else {
find_joint_by_name_in(document.root, name)
}
}
///|
fn find_joint_by_path_in(joint : BvhJoint, path : String) -> BvhJoint? {
if joint.path == path {
Some(joint)
} else {
for child in joint.children {
match find_joint_by_path_in(child, path) {
Some(found) => break Some(found)
None => ()
}
} nobreak {
None
}
}
}
///|
pub fn find_joint_by_path(document : BvhDocument, path : String) -> BvhJoint? {
if document.root.name.length() == 0 {
None
} else {
find_joint_by_path_in(document.root, path)
}
}
///|
pub fn channel_names(channels : Array[BvhChannel]) -> Array[String] {
let out : Array[String] = []
for channel in channels {
out.push(channel.to_string())
}
out
}
///|
pub fn joint_channel_names(joint : BvhJoint) -> Array[String] {
channel_names(joint.channels)
}
///|
pub fn frame_values_for_joint(
document : BvhDocument,
joint : BvhJoint,
frame_index : Int,
) -> Array[Double] {
if frame_index < 0 ||
frame_index >= document.motion.frames.length() ||
joint.channel_count <= 0 {
[]
} else {
let frame = document.motion.frames[frame_index]
if joint.channel_start < 0 ||
joint.channel_start + joint.channel_count > frame.length() {
[]
} else {
frame[joint.channel_start:joint.channel_start + joint.channel_count].to_owned()
}
}
}
///|
pub fn frame_values_for_joint_name(
document : BvhDocument,
name : String,
frame_index : Int,
) -> Array[Double] {
match find_joint(document, name) {
Some(joint) => frame_values_for_joint(document, joint, frame_index)
None => []
}
}
///|
fn channel_value(
document : BvhDocument,
joint : BvhJoint,
frame_index : Int,
wanted : BvhChannel,
default : Double,
) -> Double {
if frame_index < 0 || frame_index >= document.motion.frames.length() {
return default
}
let channel_offset = for i in 0.. {
let absolute = joint.channel_start + i
let frame = document.motion.frames[frame_index]
if absolute >= 0 && absolute < frame.length() {
frame[absolute]
} else {
default
}
}
None => default
}
}
///|
pub fn root_position_at(document : BvhDocument, frame_index : Int) -> BvhVec3 {
let root = document.root
BvhVec3::new(
channel_value(document, root, frame_index, ChannelXPosition, 0.0),
channel_value(document, root, frame_index, ChannelYPosition, 0.0),
channel_value(document, root, frame_index, ChannelZPosition, 0.0),
)
}
///|
pub fn joint_rotation_at(
document : BvhDocument,
joint : BvhJoint,
frame_index : Int,
) -> BvhVec3 {
BvhVec3::new(
channel_value(document, joint, frame_index, ChannelXRotation, 0.0),
channel_value(document, joint, frame_index, ChannelYRotation, 0.0),
channel_value(document, joint, frame_index, ChannelZRotation, 0.0),
)
}
///|
pub fn root_motion_delta(document : BvhDocument) -> BvhVec3 {
if document.motion.frames.length() == 0 {
BvhVec3::zero()
} else {
let first = root_position_at(document, 0)
let last = root_position_at(document, document.motion.frames.length() - 1)
last.sub(first)
}
}
///|
pub fn root_motion_distance(document : BvhDocument) -> Double {
if document.motion.frames.length() <= 1 {
0.0
} else {
for i in 1.. Int {
match find_joint_by_path(document, path) {
Some(joint) =>
for i in 0.. -1
}
}
///|
pub fn has_joint(document : BvhDocument, name : String) -> Bool {
find_joint(document, name) != None
}
///|
pub fn contains_unknown_channels(joint : BvhJoint) -> Bool {
for channel in joint.channels {
if !channel.is_known() {
break true
}
} nobreak {
for child in joint.children {
if contains_unknown_channels(child) {
break true
}
} nobreak {
false
}
}
}
///|
fn collect_channels_in_order_into(
joint : BvhJoint,
out : Array[String],
) -> Unit {
for channel in joint.channels {
out.push(joint.path + "." + channel.to_string())
}
for child in joint.children {
collect_channels_in_order_into(child, out)
}
}
///|
pub fn channels_in_motion_order(document : BvhDocument) -> Array[String] {
let out : Array[String] = []
if document.root.name.length() > 0 {
collect_channels_in_order_into(document.root, out)
}
out
}