///|
/// Error categories returned by the tokenizer, parser, validator, and report API.
pub(all) enum BvhErrorKind {
ErrorNone
ErrorEmptyInput
ErrorUnexpectedToken
ErrorUnexpectedEof
ErrorInvalidNumber
ErrorInvalidHierarchy
ErrorInvalidMotion
ErrorFrameWidthMismatch
ErrorUnsupportedFeature
} derive(Eq, @debug.Debug)
///|
pub fn BvhErrorKind::code(self : BvhErrorKind) -> String {
match self {
ErrorNone => "none"
ErrorEmptyInput => "empty-input"
ErrorUnexpectedToken => "unexpected-token"
ErrorUnexpectedEof => "unexpected-eof"
ErrorInvalidNumber => "invalid-number"
ErrorInvalidHierarchy => "invalid-hierarchy"
ErrorInvalidMotion => "invalid-motion"
ErrorFrameWidthMismatch => "frame-width-mismatch"
ErrorUnsupportedFeature => "unsupported-feature"
}
}
///|
pub(all) struct BvhError {
kind : BvhErrorKind
line : Int
column : Int
token : String
message : String
} derive(Eq, @debug.Debug)
///|
pub fn BvhError::none() -> BvhError {
{ kind: ErrorNone, line: 0, column: 0, token: "", message: "" }
}
///|
pub fn BvhError::new(
kind : BvhErrorKind,
message : String,
line? : Int = 0,
column? : Int = 0,
token? : String = "",
) -> BvhError {
{ kind, line, column, token, message }
}
///|
pub fn BvhError::is_error(self : BvhError) -> Bool {
self.kind != ErrorNone
}
///|
pub fn BvhError::code(self : BvhError) -> String {
self.kind.code()
}
///|
pub(all) enum BvhTokenKind {
TokenWord
TokenOpenBrace
TokenCloseBrace
} derive(Eq, @debug.Debug)
///|
pub(all) struct BvhToken {
kind : BvhTokenKind
text : String
line : Int
column : Int
} derive(Eq, @debug.Debug)
///|
pub fn BvhToken::new(
kind : BvhTokenKind,
text : String,
line : Int,
column : Int,
) -> BvhToken {
{ kind, text, line, column }
}
///|
pub fn BvhToken::is_text(self : BvhToken, text : String) -> Bool {
self.text == text
}
///|
pub(all) struct BvhTokenizeResult {
ok : Bool
tokens : Array[BvhToken]
error : BvhError
} derive(Eq, @debug.Debug)
///|
pub fn BvhTokenizeResult::success(
tokens : Array[BvhToken],
) -> BvhTokenizeResult {
{ ok: true, tokens, error: BvhError::none() }
}
///|
pub fn BvhTokenizeResult::failure(error : BvhError) -> BvhTokenizeResult {
{ ok: false, tokens: [], error }
}
///|
pub(all) enum BvhChannel {
ChannelXPosition
ChannelYPosition
ChannelZPosition
ChannelXRotation
ChannelYRotation
ChannelZRotation
ChannelUnknown(String)
} derive(Eq, @debug.Debug)
///|
pub fn BvhChannel::from_string(name : String) -> BvhChannel {
match name {
"Xposition" | "XPOSITION" | "XPosition" => ChannelXPosition
"Yposition" | "YPOSITION" | "YPosition" => ChannelYPosition
"Zposition" | "ZPOSITION" | "ZPosition" => ChannelZPosition
"Xrotation" | "XROTATION" | "XRotation" => ChannelXRotation
"Yrotation" | "YROTATION" | "YRotation" => ChannelYRotation
"Zrotation" | "ZROTATION" | "ZRotation" => ChannelZRotation
_ => ChannelUnknown(name)
}
}
///|
pub fn BvhChannel::to_string(self : BvhChannel) -> String {
match self {
ChannelXPosition => "Xposition"
ChannelYPosition => "Yposition"
ChannelZPosition => "Zposition"
ChannelXRotation => "Xrotation"
ChannelYRotation => "Yrotation"
ChannelZRotation => "Zrotation"
ChannelUnknown(name) => name
}
}
///|
pub fn BvhChannel::axis(self : BvhChannel) -> String {
match self {
ChannelXPosition | ChannelXRotation => "x"
ChannelYPosition | ChannelYRotation => "y"
ChannelZPosition | ChannelZRotation => "z"
ChannelUnknown(_) => "unknown"
}
}
///|
pub fn BvhChannel::is_position(self : BvhChannel) -> Bool {
match self {
ChannelXPosition | ChannelYPosition | ChannelZPosition => true
_ => false
}
}
///|
pub fn BvhChannel::is_rotation(self : BvhChannel) -> Bool {
match self {
ChannelXRotation | ChannelYRotation | ChannelZRotation => true
_ => false
}
}
///|
pub fn BvhChannel::is_known(self : BvhChannel) -> Bool {
match self {
ChannelUnknown(_) => false
_ => true
}
}
///|
pub(all) enum BvhJointKind {
JointRoot
JointRegular
} derive(Eq, @debug.Debug)
///|
pub fn BvhJointKind::to_string(self : BvhJointKind) -> String {
match self {
JointRoot => "ROOT"
JointRegular => "JOINT"
}
}
///|
pub(all) struct BvhVec3 {
x : Double
y : Double
z : Double
} derive(Eq, @debug.Debug)
///|
pub fn BvhVec3::new(x : Double, y : Double, z : Double) -> BvhVec3 {
{ x, y, z }
}
///|
pub fn BvhVec3::zero() -> BvhVec3 {
{ x: 0.0, y: 0.0, z: 0.0 }
}
///|
pub fn BvhVec3::add(self : BvhVec3, other : BvhVec3) -> BvhVec3 {
{ x: self.x + other.x, y: self.y + other.y, z: self.z + other.z }
}
///|
pub fn BvhVec3::sub(self : BvhVec3, other : BvhVec3) -> BvhVec3 {
{ x: self.x - other.x, y: self.y - other.y, z: self.z - other.z }
}
///|
pub fn BvhVec3::scale(self : BvhVec3, factor : Double) -> BvhVec3 {
{ x: self.x * factor, y: self.y * factor, z: self.z * factor }
}
///|
pub fn BvhVec3::magnitude(self : BvhVec3) -> Double {
(self.x * self.x + self.y * self.y + self.z * self.z).sqrt()
}
///|
pub fn BvhVec3::to_csv(self : BvhVec3) -> String {
"\{self.x},\{self.y},\{self.z}"
}
///|
pub(all) struct BvhEndSite {
path : String
offset : BvhVec3
depth : Int
} derive(Eq, @debug.Debug)
///|
pub fn BvhEndSite::new(
path : String,
offset : BvhVec3,
depth : Int,
) -> BvhEndSite {
{ path, offset, depth }
}
///|
pub fn BvhEndSite::empty() -> BvhEndSite {
{ path: "", offset: BvhVec3::zero(), depth: 0 }
}
///|
pub(all) struct BvhJoint {
name : String
path : String
kind : BvhJointKind
offset : BvhVec3
channels : Array[BvhChannel]
channel_start : Int
channel_count : Int
depth : Int
children : Array[BvhJoint]
end_sites : Array[BvhEndSite]
} derive(Eq, @debug.Debug)
///|
pub fn BvhJoint::empty() -> BvhJoint {
{
name: "",
path: "",
kind: JointRegular,
offset: BvhVec3::zero(),
channels: [],
channel_start: 0,
channel_count: 0,
depth: 0,
children: [],
end_sites: [],
}
}
///|
pub fn BvhJoint::is_root(self : BvhJoint) -> Bool {
self.kind == JointRoot
}
///|
pub fn BvhJoint::has_channel(self : BvhJoint, channel : BvhChannel) -> Bool {
for item in self.channels {
if item == channel {
break true
}
} nobreak {
false
}
}
///|
pub fn BvhJoint::position_channel_count(self : BvhJoint) -> Int {
for channel in self.channels; count = 0 {
if channel.is_position() {
continue count + 1
} else {
continue count
}
} nobreak {
count
}
}
///|
pub fn BvhJoint::rotation_channel_count(self : BvhJoint) -> Int {
for channel in self.channels; count = 0 {
if channel.is_rotation() {
continue count + 1
} else {
continue count
}
} nobreak {
count
}
}
///|
pub(all) struct BvhMotion {
frame_count : Int
frame_time : Double
channel_count : Int
frames : Array[Array[Double]]
} derive(Eq, @debug.Debug)
///|
pub fn BvhMotion::empty() -> BvhMotion {
{ frame_count: 0, frame_time: 0.0, channel_count: 0, frames: [] }
}
///|
pub fn BvhMotion::duration_seconds(self : BvhMotion) -> Double {
self.frame_count.to_double() * self.frame_time
}
///|
pub fn BvhMotion::is_empty(self : BvhMotion) -> Bool {
self.frame_count == 0 || self.frames.length() == 0
}
///|
pub(all) struct BvhDocument {
root : BvhJoint
motion : BvhMotion
source_length : Int
token_count : Int
} derive(Eq, @debug.Debug)
///|
pub fn BvhDocument::empty() -> BvhDocument {
{
root: BvhJoint::empty(),
motion: BvhMotion::empty(),
source_length: 0,
token_count: 0,
}
}
///|
pub fn BvhDocument::channel_count(self : BvhDocument) -> Int {
self.motion.channel_count
}
///|
pub fn BvhDocument::joint_count(self : BvhDocument) -> Int {
count_joints(self.root)
}
///|
pub fn BvhDocument::end_site_count(self : BvhDocument) -> Int {
count_end_sites(self.root)
}
///|
pub fn BvhDocument::duration_seconds(self : BvhDocument) -> Double {
self.motion.duration_seconds()
}
///|
pub fn BvhDocument::is_complete(self : BvhDocument) -> Bool {
self.root.name.length() > 0 &&
self.motion.frame_count == self.motion.frames.length() &&
self.motion.channel_count > 0
}
///|
pub(all) struct BvhParseResult {
ok : Bool
document : BvhDocument
error : BvhError
} derive(Eq, @debug.Debug)
///|
pub fn BvhParseResult::success(document : BvhDocument) -> BvhParseResult {
{ ok: true, document, error: BvhError::none() }
}
///|
pub fn BvhParseResult::failure(error : BvhError) -> BvhParseResult {
{ ok: false, document: BvhDocument::empty(), error }
}
///|
pub fn BvhParseResult::is_ok(self : BvhParseResult) -> Bool {
self.ok
}
///|
pub(all) enum BvhIssueSeverity {
IssueError
IssueWarning
IssueInfo
} derive(Eq, @debug.Debug)
///|
pub fn BvhIssueSeverity::to_string(self : BvhIssueSeverity) -> String {
match self {
IssueError => "error"
IssueWarning => "warning"
IssueInfo => "info"
}
}
///|
pub(all) struct BvhValidationIssue {
severity : BvhIssueSeverity
path : String
code : String
message : String
} derive(Eq, @debug.Debug)
///|
pub fn BvhValidationIssue::new(
severity : BvhIssueSeverity,
code : String,
message : String,
path? : String = "$",
) -> BvhValidationIssue {
{ severity, path, code, message }
}
///|
pub fn BvhValidationIssue::error(
code : String,
message : String,
path? : String = "$",
) -> BvhValidationIssue {
BvhValidationIssue::new(IssueError, code, message, path~)
}
///|
pub fn BvhValidationIssue::warning(
code : String,
message : String,
path? : String = "$",
) -> BvhValidationIssue {
BvhValidationIssue::new(IssueWarning, code, message, path~)
}
///|
pub fn BvhValidationIssue::info(
code : String,
message : String,
path? : String = "$",
) -> BvhValidationIssue {
BvhValidationIssue::new(IssueInfo, code, message, path~)
}
///|
pub(all) struct BvhValidationReport {
issues : Array[BvhValidationIssue]
error_count : Int
warning_count : Int
info_count : Int
} derive(Eq, @debug.Debug)
///|
pub fn BvhValidationReport::new(
issues : Array[BvhValidationIssue],
) -> BvhValidationReport {
let mut errors = 0
let mut warnings = 0
let mut infos = 0
for issue in issues {
match issue.severity {
IssueError => errors += 1
IssueWarning => warnings += 1
IssueInfo => infos += 1
}
}
{ issues, error_count: errors, warning_count: warnings, info_count: infos }
}
///|
pub fn BvhValidationReport::ok(self : BvhValidationReport) -> Bool {
self.error_count == 0
}
///|
pub(all) struct BvhStats {
joint_count : Int
end_site_count : Int
max_depth : Int
channel_count : Int
frame_count : Int
frame_time : Double
duration_seconds : Double
root_motion_distance : Double
} derive(Eq, @debug.Debug)
///|
pub fn BvhStats::empty() -> BvhStats {
{
joint_count: 0,
end_site_count: 0,
max_depth: 0,
channel_count: 0,
frame_count: 0,
frame_time: 0.0,
duration_seconds: 0.0,
root_motion_distance: 0.0,
}
}
///|
pub(all) enum BvhReportFormat {
ReportText
ReportJson
ReportCsv
} derive(Eq, @debug.Debug)