Translate avatar and animesh parity tests
This commit is contained in:
@@ -2656,7 +2656,7 @@ impl TokenBucket {
|
||||
}
|
||||
|
||||
/// C# type: `T:LibreMetaverse.UUID`.
|
||||
#[derive(Clone, Copy, Debug, Default)]
|
||||
#[derive(Clone, Copy, Debug, Default, Eq, Hash, PartialEq)]
|
||||
pub struct UUID {
|
||||
bytes: [u8; 16],
|
||||
}
|
||||
|
||||
938
crates/libremetaverse/src/avatar_animesh_semantics.rs
Normal file
938
crates/libremetaverse/src/avatar_animesh_semantics.rs
Normal file
@@ -0,0 +1,938 @@
|
||||
#![allow(clippy::float_cmp, clippy::too_many_lines)]
|
||||
|
||||
// Exact BSD-3-Clause fixture provenance at LibreMetaverse
|
||||
// 2aa70bb68513b39795da5d13c88f31b86e85a3ba (see LICENSE.md):
|
||||
// AnimationTrackTests.cs 9f83830d4278906e4edf8d5ad71d59f96e63ae5860e3b3cc9e191de05741f3d0
|
||||
// AnimeshPlayerTests.cs b79a4f667c73c30376ee6f550436b26e76efd0fa0383d67bc388a74f07f679ce
|
||||
// AnimeshSkinningTests.cs 72f51e5dc4fa59e87c150aacb93aae26aabad71fb45e1830cd46e7c5216e1266
|
||||
// AvatarManagerTests.cs f7547d5caed1d4669eccfad57836f4d2243c8275b1d182e7cb363660b3eabb68
|
||||
// LindenSkeletonTests.cs 23f7e3ffaf8c4422e8dc2e42ed4223b16175228153aba8eb69cd7ef7e2037b76
|
||||
|
||||
use crate::animesh::{AnimationTrack, AnimeshPlayer, JointPose};
|
||||
use crate::rendering::{
|
||||
Face, FaceMask, Joint, JointSupportCategory, LindenSkeleton, MeshSkinData, Vertex, VertexWeight,
|
||||
};
|
||||
use crate::{AnimeshSkinning, BinBVHAnimationReader, GridClient, PrimitiveTextureEntryFace};
|
||||
use libremetaverse_types::compat::Object;
|
||||
use libremetaverse_types::{Error, Matrix4, UUID, Vector2, Vector3};
|
||||
use std::collections::{HashMap, HashSet};
|
||||
use std::sync::Arc;
|
||||
|
||||
fn random_uuid() -> UUID {
|
||||
UUID::random().expect("UUID.Random")
|
||||
}
|
||||
|
||||
fn vector3(x: f32, y: f32, z: f32) -> Vector3 {
|
||||
Vector3::new_with_single_single_single(x, y, z).expect("Vector3 constructor")
|
||||
}
|
||||
|
||||
fn assert_close(actual: f32, expected: f32, tolerance: f32) {
|
||||
assert!(
|
||||
(actual - expected).abs() <= tolerance,
|
||||
"expected {expected} +/- {tolerance}, got {actual}"
|
||||
);
|
||||
}
|
||||
|
||||
fn make_animation(
|
||||
in_point: f32,
|
||||
out_point: f32,
|
||||
loop_: bool,
|
||||
ease_in: f32,
|
||||
ease_out: f32,
|
||||
) -> BinBVHAnimationReader {
|
||||
let mut data = Vec::new();
|
||||
data.extend_from_slice(&1_u16.to_le_bytes());
|
||||
data.extend_from_slice(&0_u16.to_le_bytes());
|
||||
data.extend_from_slice(&2_i32.to_le_bytes());
|
||||
data.extend_from_slice(&(out_point - in_point).to_le_bytes());
|
||||
data.push(0);
|
||||
data.extend_from_slice(&in_point.to_le_bytes());
|
||||
data.extend_from_slice(&out_point.to_le_bytes());
|
||||
data.extend_from_slice(&i32::from(loop_).to_le_bytes());
|
||||
data.extend_from_slice(&ease_in.to_le_bytes());
|
||||
data.extend_from_slice(&ease_out.to_le_bytes());
|
||||
data.extend_from_slice(&0_u32.to_le_bytes());
|
||||
data.extend_from_slice(&0_u32.to_le_bytes());
|
||||
BinBVHAnimationReader::new(data).expect("BinBVHAnimationReader constructor")
|
||||
}
|
||||
|
||||
fn make_track(
|
||||
in_point: f32,
|
||||
out_point: f32,
|
||||
loop_: bool,
|
||||
ease_in: f32,
|
||||
ease_out: f32,
|
||||
) -> AnimationTrack {
|
||||
let mut track = AnimationTrack::new(random_uuid()).expect("AnimationTrack constructor");
|
||||
track.set_data(Some(make_animation(
|
||||
in_point, out_point, loop_, ease_in, ease_out,
|
||||
)));
|
||||
track
|
||||
}
|
||||
|
||||
// parity-case: LibreMetaverse.Tests/AnimationTrackTests.cs::AnimationTrackTests.DecodeRotation_ZeroVector_ReturnsIdentity::test fd67db1a9689e3e624fbe8bea98d6278774e4d67f85e611aac6f76105240a6b1 translated
|
||||
#[test]
|
||||
fn animation_track_decode_rotation_zero_vector_returns_identity() {
|
||||
let quaternion = AnimationTrack::decode_rotation(Vector3::zero()).expect("DecodeRotation");
|
||||
assert_close(quaternion.w, 1.0, 1.0e-5);
|
||||
assert_close(quaternion.x, 0.0, 1.0e-5);
|
||||
assert_close(quaternion.y, 0.0, 1.0e-5);
|
||||
assert_close(quaternion.z, 0.0, 1.0e-5);
|
||||
}
|
||||
|
||||
// parity-case: LibreMetaverse.Tests/AnimationTrackTests.cs::AnimationTrackTests.DecodeRotation_Result_IsNormalized::test 880fdfb75fd9318afa21d3b5296790b3ebad944b43a998a924691fa74efbb2fe translated
|
||||
#[test]
|
||||
fn animation_track_decode_rotation_result_is_normalized() {
|
||||
let vectors = [
|
||||
vector3(0.1, 0.2, 0.3),
|
||||
vector3(0.5, 0.0, 0.0),
|
||||
vector3(0.0, 0.0, 0.99),
|
||||
Vector3::zero(),
|
||||
];
|
||||
for value in vectors {
|
||||
let quaternion = AnimationTrack::decode_rotation(value).expect("DecodeRotation");
|
||||
let magnitude = (quaternion.x * quaternion.x
|
||||
+ quaternion.y * quaternion.y
|
||||
+ quaternion.z * quaternion.z
|
||||
+ quaternion.w * quaternion.w)
|
||||
.sqrt();
|
||||
assert_close(magnitude, 1.0, 1.0e-5);
|
||||
}
|
||||
}
|
||||
|
||||
// parity-case: LibreMetaverse.Tests/AnimationTrackTests.cs::AnimationTrackTests.DecodeRotation_WIsRecoveredFromXyz::test 738fd51ea71da85b3b2d43ec30b8e9883b5364c9cbd7c3cbe87de3ea6778daa8 translated
|
||||
#[test]
|
||||
fn animation_track_decode_rotation_w_is_recovered_from_xyz() {
|
||||
let quaternion =
|
||||
AnimationTrack::decode_rotation(vector3(0.6, 0.0, 0.0)).expect("DecodeRotation");
|
||||
assert_close(quaternion.x, 0.6, 1.0e-5);
|
||||
assert_close(quaternion.w, 0.8, 1.0e-5);
|
||||
}
|
||||
|
||||
// parity-case: LibreMetaverse.Tests/AnimationTrackTests.cs::AnimationTrackTests.DecodeRotation_WAlwaysNonNegative::test 679c12e5cdaac7a970f15606229b1843d82e68b28883f87cc5d73567b04c9b57 translated
|
||||
#[test]
|
||||
fn animation_track_decode_rotation_w_always_non_negative() {
|
||||
for value in [
|
||||
vector3(0.5, 0.5, 0.5),
|
||||
vector3(-0.5, -0.5, -0.5),
|
||||
vector3(0.0, 0.0, 0.9),
|
||||
] {
|
||||
let quaternion = AnimationTrack::decode_rotation(value).expect("DecodeRotation");
|
||||
assert!(quaternion.w >= 0.0);
|
||||
}
|
||||
}
|
||||
|
||||
// parity-case: LibreMetaverse.Tests/AnimationTrackTests.cs::AnimationTrackTests.Advance_WithNullData_DoesNotChangeCurrentTime::test cfd6f6ed1f568fe0dda207cc3222c487a3f8b509a5aa0743109c04032a29b808 translated
|
||||
#[test]
|
||||
fn animation_track_advance_with_null_data_does_not_change_current_time() {
|
||||
let mut track = AnimationTrack::new(random_uuid()).expect("AnimationTrack constructor");
|
||||
track.advance(1.0).expect("Advance");
|
||||
assert_eq!(track.current_time(), 0.0);
|
||||
assert!(!track.is_finished());
|
||||
}
|
||||
|
||||
// parity-case: LibreMetaverse.Tests/AnimationTrackTests.cs::AnimationTrackTests.EaseWeight_WithNullData_ReturnsZero::test 7e74e5323ca9870782821a6985f446030d1a8858182bdf82d7718617eacd8ef5 translated
|
||||
#[test]
|
||||
fn animation_track_ease_weight_with_null_data_returns_zero() {
|
||||
let track = AnimationTrack::new(random_uuid()).expect("AnimationTrack constructor");
|
||||
assert_eq!(track.ease_weight(), 0.0);
|
||||
}
|
||||
|
||||
// parity-case: LibreMetaverse.Tests/AnimationTrackTests.cs::AnimationTrackTests.EvaluatePose_WithNullData_LeavesEmptyDictionaryUnchanged::test 287210ac2f57c80bd77688a97720b0a7ca63118ce3c8da591274b53aeef88769 translated
|
||||
#[test]
|
||||
fn animation_track_evaluate_pose_with_null_data_leaves_empty_dictionary_unchanged() {
|
||||
let track = AnimationTrack::new(random_uuid()).expect("AnimationTrack constructor");
|
||||
let mut pose = HashMap::<String, JointPose>::new();
|
||||
track.evaluate_pose(&mut pose).expect("EvaluatePose");
|
||||
assert!(pose.is_empty());
|
||||
}
|
||||
|
||||
// parity-case: LibreMetaverse.Tests/AnimationTrackTests.cs::AnimationTrackTests.Advance_NonLooping_BeforeOutPoint_AdvancesTime::test da6ab7efced5ff86e83c320685d6fef33df2a2eb62795206b9f78e87a51ca93d translated
|
||||
#[test]
|
||||
fn animation_track_advance_non_looping_before_out_point_advances_time() {
|
||||
let mut track = make_track(0.0, 10.0, false, 0.0, 0.0);
|
||||
track.advance(3.0).expect("Advance");
|
||||
assert_close(track.current_time(), 3.0, 1.0e-5);
|
||||
assert!(!track.is_finished());
|
||||
}
|
||||
|
||||
// parity-case: LibreMetaverse.Tests/AnimationTrackTests.cs::AnimationTrackTests.Advance_NonLooping_PastOutPoint_ClampsAndSetsFinished::test 02acfe2c10a27a6222e8d222de47255c68afc46ba97cc9319f8239af021fb365 translated
|
||||
#[test]
|
||||
fn animation_track_advance_non_looping_past_out_point_clamps_and_sets_finished() {
|
||||
let mut track = make_track(0.0, 5.0, false, 0.0, 0.0);
|
||||
track.advance(10.0).expect("Advance");
|
||||
assert_close(track.current_time(), 5.0, 1.0e-5);
|
||||
assert!(track.is_finished());
|
||||
}
|
||||
|
||||
// parity-case: LibreMetaverse.Tests/AnimationTrackTests.cs::AnimationTrackTests.Advance_Looping_WrapsAroundToInPoint::test e5e29dec8ece4c3ed19691aa0da0b0199de14902184a91548451c40390af4f8e translated
|
||||
#[test]
|
||||
fn animation_track_advance_looping_wraps_around_to_in_point() {
|
||||
let mut track = make_track(1.0, 4.0, true, 0.0, 0.0);
|
||||
track.advance(6.0).expect("Advance");
|
||||
assert_close(track.current_time(), 3.0, 1.0e-4);
|
||||
assert!(!track.is_finished());
|
||||
}
|
||||
|
||||
// parity-case: LibreMetaverse.Tests/AnimationTrackTests.cs::AnimationTrackTests.Advance_Finished_DoesNotAdvanceFurther::test 17680a41433f4f274645b15f49c4b4f7efea42af4542ee3f6c2e16aa8614f994 translated
|
||||
#[test]
|
||||
fn animation_track_advance_finished_does_not_advance_further() {
|
||||
let mut track = make_track(0.0, 5.0, false, 0.0, 0.0);
|
||||
track.advance(10.0).expect("Advance");
|
||||
let stopped_at = track.current_time();
|
||||
track.advance(5.0).expect("Advance");
|
||||
assert_eq!(track.current_time(), stopped_at);
|
||||
}
|
||||
|
||||
// parity-case: LibreMetaverse.Tests/AnimationTrackTests.cs::AnimationTrackTests.EaseWeight_InMiddle_IsOne::test 49a02b2910e60254f80760d40b62b41fc02a4747d85a7b41ee8d082d0352d3cf translated
|
||||
#[test]
|
||||
fn animation_track_ease_weight_in_middle_is_one() {
|
||||
let mut track = make_track(0.0, 10.0, false, 1.0, 1.0);
|
||||
track.advance(5.0).expect("Advance");
|
||||
assert_close(track.ease_weight(), 1.0, 1.0e-5);
|
||||
}
|
||||
|
||||
// parity-case: LibreMetaverse.Tests/AnimationTrackTests.cs::AnimationTrackTests.EaseWeight_DuringEaseIn_IsFractional::test 419c26af8c1a989a7f99d1b32ca28a41768d7171a4452466f909e1fe61cea186 translated
|
||||
#[test]
|
||||
fn animation_track_ease_weight_during_ease_in_is_fractional() {
|
||||
let mut track = make_track(0.0, 10.0, false, 2.0, 0.0);
|
||||
track.advance(1.0).expect("Advance");
|
||||
assert_close(track.ease_weight(), 0.5, 1.0e-5);
|
||||
}
|
||||
|
||||
// parity-case: LibreMetaverse.Tests/AnimationTrackTests.cs::AnimationTrackTests.EaseWeight_DuringEaseOut_DecreasesTowardZero::test 18fd883c525f528f0ead69d3df187b106980ff939091c3ad56b156c2d05c91b0 translated
|
||||
#[test]
|
||||
fn animation_track_ease_weight_during_ease_out_decreases_toward_zero() {
|
||||
let mut track = make_track(0.0, 10.0, false, 0.0, 4.0);
|
||||
track.advance(8.0).expect("Advance");
|
||||
assert_close(track.ease_weight(), 0.5, 1.0e-5);
|
||||
}
|
||||
|
||||
// parity-case: LibreMetaverse.Tests/AnimationTrackTests.cs::AnimationTrackTests.EaseWeight_NoEaseCurves_IsAlwaysOne::test 49421472fcd3dcdb56cb9bb2448b2808bf76757454a67f2ced7524d9a6f89d6e translated
|
||||
#[test]
|
||||
fn animation_track_ease_weight_no_ease_curves_is_always_one() {
|
||||
let mut track = make_track(0.0, 10.0, false, 0.0, 0.0);
|
||||
track.advance(5.0).expect("Advance");
|
||||
assert_eq!(track.ease_weight(), 1.0);
|
||||
}
|
||||
|
||||
// parity-case: LibreMetaverse.Tests/AnimeshPlayerTests.cs::AnimeshPlayerTests.GetOrAddTrack_CreatesNewTrack::test b7fcdc9f7c02167a6307facaf720390298d68e9c909792d4feab3b78d9b87d7f translated
|
||||
#[test]
|
||||
fn animesh_player_get_or_add_track_creates_new_track() {
|
||||
let mut player = AnimeshPlayer::new(random_uuid()).expect("AnimeshPlayer constructor");
|
||||
let id = random_uuid();
|
||||
let track = player.get_or_add_track(id).expect("GetOrAddTrack");
|
||||
assert!(track.animation_id().equals_with_uuid(id));
|
||||
}
|
||||
|
||||
// parity-case: LibreMetaverse.Tests/AnimeshPlayerTests.cs::AnimeshPlayerTests.GetOrAddTrack_SameId_ReturnsSameTrack::test aaec517ee073f26f6ed324cb4391a945221ff0349348bba3757b2378b38df610 translated
|
||||
#[test]
|
||||
fn animesh_player_get_or_add_track_same_id_returns_same_track() {
|
||||
let mut player = AnimeshPlayer::new(random_uuid()).expect("AnimeshPlayer constructor");
|
||||
let id = random_uuid();
|
||||
let first = player.get_or_add_track(id).expect("GetOrAddTrack");
|
||||
let second = player.get_or_add_track(id).expect("GetOrAddTrack");
|
||||
assert!(Arc::ptr_eq(&first, &second));
|
||||
}
|
||||
|
||||
// parity-case: LibreMetaverse.Tests/AnimeshPlayerTests.cs::AnimeshPlayerTests.GetOrAddTrack_DifferentIds_ReturnDifferentTracks::test fe47b6dabc58df9078751501e3bb7e65b0aeb4c0929f4523aded0cb624d64bb1 translated
|
||||
#[test]
|
||||
fn animesh_player_get_or_add_track_different_ids_return_different_tracks() {
|
||||
let mut player = AnimeshPlayer::new(random_uuid()).expect("AnimeshPlayer constructor");
|
||||
let first = player
|
||||
.get_or_add_track(random_uuid())
|
||||
.expect("GetOrAddTrack");
|
||||
let second = player
|
||||
.get_or_add_track(random_uuid())
|
||||
.expect("GetOrAddTrack");
|
||||
assert!(!Arc::ptr_eq(&first, &second));
|
||||
}
|
||||
|
||||
// parity-case: LibreMetaverse.Tests/AnimeshPlayerTests.cs::AnimeshPlayerTests.TrackCount_IncreasesWithNewTracks::test 241b4b3606c0d5c8625701bd21ec41438ac9a410eb11620d1609ddd4d2d58dda translated
|
||||
#[test]
|
||||
fn animesh_player_track_count_increases_with_new_tracks() {
|
||||
let mut player = AnimeshPlayer::new(random_uuid()).expect("AnimeshPlayer constructor");
|
||||
player
|
||||
.get_or_add_track(random_uuid())
|
||||
.expect("GetOrAddTrack");
|
||||
player
|
||||
.get_or_add_track(random_uuid())
|
||||
.expect("GetOrAddTrack");
|
||||
assert_eq!(player.track_count(), 2);
|
||||
}
|
||||
|
||||
// parity-case: LibreMetaverse.Tests/AnimeshPlayerTests.cs::AnimeshPlayerTests.TrackCount_StableForDuplicateId::test b36dfe47c90dd24fe489ae408cfb299f7214eddb3dc9d5ba42830ab9950d9268 translated
|
||||
#[test]
|
||||
fn animesh_player_track_count_stable_for_duplicate_id() {
|
||||
let mut player = AnimeshPlayer::new(random_uuid()).expect("AnimeshPlayer constructor");
|
||||
let id = random_uuid();
|
||||
player.get_or_add_track(id).expect("GetOrAddTrack");
|
||||
player.get_or_add_track(id).expect("GetOrAddTrack");
|
||||
assert_eq!(player.track_count(), 1);
|
||||
}
|
||||
|
||||
// parity-case: LibreMetaverse.Tests/AnimeshPlayerTests.cs::AnimeshPlayerTests.RetainOnly_RemovesAbsentIds::test d4f15706802d59901e8f07fc17f1d11063b6c182a7a40833d988191edd556f46 translated
|
||||
#[test]
|
||||
fn animesh_player_retain_only_removes_absent_ids() {
|
||||
let mut player = AnimeshPlayer::new(random_uuid()).expect("AnimeshPlayer constructor");
|
||||
let keep = random_uuid();
|
||||
let drop = random_uuid();
|
||||
player.get_or_add_track(keep).expect("GetOrAddTrack");
|
||||
player.get_or_add_track(drop).expect("GetOrAddTrack");
|
||||
player
|
||||
.retain_only(HashSet::from([keep]))
|
||||
.expect("RetainOnly");
|
||||
assert_eq!(player.track_count(), 1);
|
||||
}
|
||||
|
||||
// parity-case: LibreMetaverse.Tests/AnimeshPlayerTests.cs::AnimeshPlayerTests.RetainOnly_KeepsPresentIds::test eb568b72c8930dea6678a4b54ff2dd47101cef0ed8f6380875cb3fdd27ec6ad2 translated
|
||||
#[test]
|
||||
fn animesh_player_retain_only_keeps_present_ids() {
|
||||
let mut player = AnimeshPlayer::new(random_uuid()).expect("AnimeshPlayer constructor");
|
||||
let id = random_uuid();
|
||||
let original = player.get_or_add_track(id).expect("GetOrAddTrack");
|
||||
player.retain_only(HashSet::from([id])).expect("RetainOnly");
|
||||
let retained = player.get_or_add_track(id).expect("GetOrAddTrack");
|
||||
assert!(Arc::ptr_eq(&original, &retained));
|
||||
}
|
||||
|
||||
// parity-case: LibreMetaverse.Tests/AnimeshPlayerTests.cs::AnimeshPlayerTests.RetainOnly_EmptySet_RemovesAllTracks::test 8a8ee666933d4bd920c1d239f5180b9b4ee0d6eb7be67a6965fe29ca6f22edff translated
|
||||
#[test]
|
||||
fn animesh_player_retain_only_empty_set_removes_all_tracks() {
|
||||
let mut player = AnimeshPlayer::new(random_uuid()).expect("AnimeshPlayer constructor");
|
||||
player
|
||||
.get_or_add_track(random_uuid())
|
||||
.expect("GetOrAddTrack");
|
||||
player
|
||||
.get_or_add_track(random_uuid())
|
||||
.expect("GetOrAddTrack");
|
||||
player.retain_only(HashSet::new()).expect("RetainOnly");
|
||||
assert_eq!(player.track_count(), 0);
|
||||
}
|
||||
|
||||
// parity-case: LibreMetaverse.Tests/AnimeshPlayerTests.cs::AnimeshPlayerTests.Update_WithNoTracks_DoesNotThrow::test 866542d8e7e14a1f52a4f6b79aa8284cc5347d1a78a44ed9b4950b67078ff592 translated
|
||||
#[test]
|
||||
fn animesh_player_update_with_no_tracks_does_not_throw() {
|
||||
let mut player = AnimeshPlayer::new(random_uuid()).expect("AnimeshPlayer constructor");
|
||||
player.update(0.016).expect("Update");
|
||||
}
|
||||
|
||||
// parity-case: LibreMetaverse.Tests/AnimeshPlayerTests.cs::AnimeshPlayerTests.Update_WithTracksButNoData_DoesNotThrow::test b29bcf3676a3fca8d1e352ff672350a7bcb92a101dd6f622c53ee2b9a64a3536 translated
|
||||
#[test]
|
||||
fn animesh_player_update_with_tracks_but_no_data_does_not_throw() {
|
||||
let mut player = AnimeshPlayer::new(random_uuid()).expect("AnimeshPlayer constructor");
|
||||
player
|
||||
.get_or_add_track(random_uuid())
|
||||
.expect("GetOrAddTrack");
|
||||
player
|
||||
.get_or_add_track(random_uuid())
|
||||
.expect("GetOrAddTrack");
|
||||
player.update(0.016).expect("Update");
|
||||
}
|
||||
|
||||
// parity-case: LibreMetaverse.Tests/AnimeshPlayerTests.cs::AnimeshPlayerTests.EvaluatePose_NoLoadedData_ReturnsEmptyDictionary::test 3427b5c94f64a7465a8f3d4d13a1b67e2d002df81a4e736398e1934c8b08cb4b translated
|
||||
#[test]
|
||||
fn animesh_player_evaluate_pose_no_loaded_data_returns_empty_dictionary() {
|
||||
let mut player = AnimeshPlayer::new(random_uuid()).expect("AnimeshPlayer constructor");
|
||||
player
|
||||
.get_or_add_track(random_uuid())
|
||||
.expect("GetOrAddTrack");
|
||||
let pose = player.evaluate_pose().expect("EvaluatePose");
|
||||
assert!(pose.is_empty());
|
||||
}
|
||||
|
||||
// parity-case: LibreMetaverse.Tests/AnimeshPlayerTests.cs::AnimeshPlayerTests.ObjectID_StoresConstructorValue::test f2a2efabccbf63c110336cb5785487eb65ee7347e1ff0bb499295e4d5e255654 translated
|
||||
#[test]
|
||||
fn animesh_player_object_id_stores_constructor_value() {
|
||||
let id = random_uuid();
|
||||
let player = AnimeshPlayer::new(id).expect("AnimeshPlayer constructor");
|
||||
assert!(player.object_id().equals_with_uuid(id));
|
||||
}
|
||||
|
||||
fn make_joint(name: &str, children: Vec<Joint>) -> Joint {
|
||||
let mut joint = Joint::new().expect("Joint constructor");
|
||||
joint.base.set_name(name.to_owned());
|
||||
joint.set_bone(Some(children));
|
||||
joint
|
||||
}
|
||||
|
||||
fn make_skeleton(root_name: &str, root_children: Vec<Joint>) -> LindenSkeleton {
|
||||
let mut skeleton = LindenSkeleton::new().expect("LindenSkeleton constructor");
|
||||
skeleton.set_bone(make_joint(root_name, root_children));
|
||||
skeleton
|
||||
}
|
||||
|
||||
fn make_single_joint_skeleton(joint_name: &str) -> LindenSkeleton {
|
||||
let mut joint = Joint::new().expect("Joint constructor");
|
||||
joint.base.set_name(joint_name.to_owned());
|
||||
joint.base.set_pos(vec![0.0, 0.0, 0.0]);
|
||||
joint.base.set_rot(vec![0.0, 0.0, 0.0]);
|
||||
let mut skeleton = LindenSkeleton::new().expect("LindenSkeleton constructor");
|
||||
skeleton.set_bone(joint);
|
||||
skeleton
|
||||
}
|
||||
|
||||
fn identity_floats() -> Vec<f32> {
|
||||
vec![
|
||||
1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0,
|
||||
]
|
||||
}
|
||||
|
||||
fn make_skin_data(joint_name: &str) -> MeshSkinData {
|
||||
let mut skin_data = MeshSkinData::new().expect("MeshSkinData constructor");
|
||||
skin_data.joint_names = vec![joint_name.to_owned()];
|
||||
skin_data.inverse_bind_matrices = identity_floats();
|
||||
skin_data.bind_shape_matrix = identity_floats();
|
||||
skin_data
|
||||
}
|
||||
|
||||
fn assert_matrix_identity(matrix: Matrix4, tolerance: f32) {
|
||||
let identity = Matrix4::identity();
|
||||
assert_close(matrix.m11, identity.m11, tolerance);
|
||||
assert_close(matrix.m12, identity.m12, tolerance);
|
||||
assert_close(matrix.m13, identity.m13, tolerance);
|
||||
assert_close(matrix.m14, identity.m14, tolerance);
|
||||
assert_close(matrix.m21, identity.m21, tolerance);
|
||||
assert_close(matrix.m22, identity.m22, tolerance);
|
||||
assert_close(matrix.m23, identity.m23, tolerance);
|
||||
assert_close(matrix.m24, identity.m24, tolerance);
|
||||
assert_close(matrix.m31, identity.m31, tolerance);
|
||||
assert_close(matrix.m32, identity.m32, tolerance);
|
||||
assert_close(matrix.m33, identity.m33, tolerance);
|
||||
assert_close(matrix.m34, identity.m34, tolerance);
|
||||
assert_close(matrix.m41, identity.m41, tolerance);
|
||||
assert_close(matrix.m42, identity.m42, tolerance);
|
||||
assert_close(matrix.m43, identity.m43, tolerance);
|
||||
assert_close(matrix.m44, identity.m44, tolerance);
|
||||
}
|
||||
|
||||
fn vertex(position: Vector3) -> Vertex {
|
||||
Vertex {
|
||||
position,
|
||||
normal: Vector3::zero(),
|
||||
tex_coord: Vector2::zero(),
|
||||
}
|
||||
}
|
||||
|
||||
fn face(vertices: Vec<Vertex>, weights: Option<Vec<VertexWeight>>) -> Face {
|
||||
Face {
|
||||
begin_s: 0,
|
||||
begin_t: 0,
|
||||
center: Vector3::zero(),
|
||||
edge: Vec::new(),
|
||||
id: 0,
|
||||
indices: Vec::new(),
|
||||
mask: FaceMask(0),
|
||||
max_extent: Vector3::zero(),
|
||||
min_extent: Vector3::zero(),
|
||||
normalized_scale: Vector3::zero(),
|
||||
num_s: 0,
|
||||
num_t: 0,
|
||||
tex_coords1: None,
|
||||
texture_face: PrimitiveTextureEntryFace,
|
||||
user_data: Object::from(""),
|
||||
vertices,
|
||||
weights,
|
||||
}
|
||||
}
|
||||
|
||||
// parity-case: LibreMetaverse.Tests/AnimeshSkinningTests.cs::AnimeshSkinningTests.ComputeSkinningMatrices_NullPose_ThrowsArgumentNullException::test 877768309d784145e02873759fa3726bc2ca6eb4b9d35b0974b98d3c0a06b97a translated
|
||||
#[test]
|
||||
fn animesh_skinning_compute_matrices_null_pose_throws_argument_null() {
|
||||
let skeleton = make_single_joint_skeleton("mRoot");
|
||||
let skin_data = make_skin_data("mRoot");
|
||||
let Err(error) =
|
||||
AnimeshSkinning::compute_skinning_matrices(None, Some(skeleton), Some(skin_data))
|
||||
else {
|
||||
panic!("null pose must fail");
|
||||
};
|
||||
assert_eq!(error, Error::ArgumentNull);
|
||||
}
|
||||
|
||||
// parity-case: LibreMetaverse.Tests/AnimeshSkinningTests.cs::AnimeshSkinningTests.ComputeSkinningMatrices_NullSkeleton_ThrowsArgumentNullException::test 97d7eef733424588868943400ef2a9664243d5b0c1df884e3cf3e2bc3fa299d6 translated
|
||||
#[test]
|
||||
fn animesh_skinning_compute_matrices_null_skeleton_throws_argument_null() {
|
||||
let pose = HashMap::<String, JointPose>::new();
|
||||
let skin_data = make_skin_data("mRoot");
|
||||
let Err(error) = AnimeshSkinning::compute_skinning_matrices(Some(pose), None, Some(skin_data))
|
||||
else {
|
||||
panic!("null skeleton must fail");
|
||||
};
|
||||
assert_eq!(error, Error::ArgumentNull);
|
||||
}
|
||||
|
||||
// parity-case: LibreMetaverse.Tests/AnimeshSkinningTests.cs::AnimeshSkinningTests.ComputeSkinningMatrices_NullSkinData_ThrowsArgumentNullException::test a0e41b5457d413f4fb8da3d159c74318bf9b74333ce8962612610c862fca8b06 translated
|
||||
#[test]
|
||||
fn animesh_skinning_compute_matrices_null_skin_data_throws_argument_null() {
|
||||
let pose = HashMap::<String, JointPose>::new();
|
||||
let skeleton = make_single_joint_skeleton("mRoot");
|
||||
let Err(error) = AnimeshSkinning::compute_skinning_matrices(Some(pose), Some(skeleton), None)
|
||||
else {
|
||||
panic!("null skin data must fail");
|
||||
};
|
||||
assert_eq!(error, Error::ArgumentNull);
|
||||
}
|
||||
|
||||
// parity-case: LibreMetaverse.Tests/AnimeshSkinningTests.cs::AnimeshSkinningTests.ComputeSkinningMatrices_EmptySkinData_ReturnsEmptyArray::test 412f936f350e1aba601fb736a91087c89976c751a38e1653eec24a958f7c71ba translated
|
||||
#[test]
|
||||
fn animesh_skinning_compute_matrices_empty_skin_data_returns_empty_array() {
|
||||
let pose = HashMap::<String, JointPose>::new();
|
||||
let skeleton = make_single_joint_skeleton("mRoot");
|
||||
let mut skin_data = MeshSkinData::new().expect("MeshSkinData constructor");
|
||||
skin_data.joint_names = Vec::new();
|
||||
skin_data.inverse_bind_matrices = Vec::new();
|
||||
let matrices =
|
||||
AnimeshSkinning::compute_skinning_matrices(Some(pose), Some(skeleton), Some(skin_data))
|
||||
.expect("ComputeSkinningMatrices");
|
||||
assert!(matrices.is_empty());
|
||||
}
|
||||
|
||||
// parity-case: LibreMetaverse.Tests/AnimeshSkinningTests.cs::AnimeshSkinningTests.ComputeSkinningMatrices_JointNotInSkeleton_ProducesIdentity::test c0807fdb1975324c81bda29c46ab84faaad2d19b61b257180f47b6eaa2800146 translated
|
||||
#[test]
|
||||
fn animesh_skinning_compute_matrices_joint_not_in_skeleton_produces_identity() {
|
||||
let pose = HashMap::<String, JointPose>::new();
|
||||
let skeleton = make_single_joint_skeleton("mRoot");
|
||||
let skin_data = make_skin_data("nonexistent");
|
||||
let matrices =
|
||||
AnimeshSkinning::compute_skinning_matrices(Some(pose), Some(skeleton), Some(skin_data))
|
||||
.expect("ComputeSkinningMatrices");
|
||||
assert_eq!(matrices.len(), 1);
|
||||
assert_matrix_identity(matrices[0], 0.0);
|
||||
}
|
||||
|
||||
// parity-case: LibreMetaverse.Tests/AnimeshSkinningTests.cs::AnimeshSkinningTests.ComputeSkinningMatrices_IdentitySkeletonAndBindPose_ProducesIdentityMatrix::test 78e0605212c88c8ae33dd68ebe8a3ece75627761f81225b188801dc7ef9e5b32 translated
|
||||
#[test]
|
||||
fn animesh_skinning_compute_matrices_identity_skeleton_and_bind_pose_produces_identity() {
|
||||
let pose = HashMap::<String, JointPose>::new();
|
||||
let skeleton = make_single_joint_skeleton("mRoot");
|
||||
let skin_data = make_skin_data("mRoot");
|
||||
let matrices =
|
||||
AnimeshSkinning::compute_skinning_matrices(Some(pose), Some(skeleton), Some(skin_data))
|
||||
.expect("ComputeSkinningMatrices");
|
||||
assert_eq!(matrices.len(), 1);
|
||||
assert_matrix_identity(matrices[0], 1.0e-5);
|
||||
}
|
||||
|
||||
// parity-case: LibreMetaverse.Tests/AnimeshSkinningTests.cs::AnimeshSkinningTests.DeformVertices_NullWeights_PassesPositionsThrough::test bbeb45d84770e6b766272bf9a5d48bd415ba98681d9da70d256598429566144d translated
|
||||
#[test]
|
||||
fn animesh_skinning_deform_vertices_null_weights_passes_positions_through() {
|
||||
let face = face(
|
||||
vec![
|
||||
vertex(vector3(1.0, 2.0, 3.0)),
|
||||
vertex(vector3(4.0, 5.0, 6.0)),
|
||||
],
|
||||
None,
|
||||
);
|
||||
let mut positions = [Vector3::zero(), Vector3::zero()];
|
||||
AnimeshSkinning::deform_vertices(face, Vec::new(), Matrix4::identity(), &mut positions, None)
|
||||
.expect("DeformVertices");
|
||||
assert_eq!(
|
||||
(positions[0].x, positions[0].y, positions[0].z),
|
||||
(1.0, 2.0, 3.0)
|
||||
);
|
||||
assert_eq!(
|
||||
(positions[1].x, positions[1].y, positions[1].z),
|
||||
(4.0, 5.0, 6.0)
|
||||
);
|
||||
}
|
||||
|
||||
// parity-case: LibreMetaverse.Tests/AnimeshSkinningTests.cs::AnimeshSkinningTests.DeformVertices_ShortOutputSpan_ThrowsArgumentException::test dfb10b33cedddadbaa5431f1fdf8a1c59369441e94618f97ef13f53ab931907b translated
|
||||
#[test]
|
||||
fn animesh_skinning_deform_vertices_short_output_span_throws_argument() {
|
||||
let face = face(vec![vertex(Vector3::zero()), vertex(Vector3::zero())], None);
|
||||
let mut positions = [Vector3::zero()];
|
||||
let Err(error) = AnimeshSkinning::deform_vertices(
|
||||
face,
|
||||
Vec::new(),
|
||||
Matrix4::identity(),
|
||||
&mut positions,
|
||||
None,
|
||||
) else {
|
||||
panic!("short output span must fail");
|
||||
};
|
||||
assert_eq!(error, Error::Argument);
|
||||
}
|
||||
|
||||
// parity-case: LibreMetaverse.Tests/AnimeshSkinningTests.cs::AnimeshSkinningTests.DeformVertices_IdentitySkinning_FullWeight_PreservesPositions::test fcf305a633047e7a4181954fee4990db3537e549f2cb940b08e6d3f0f544c8e1 translated
|
||||
#[test]
|
||||
fn animesh_skinning_deform_vertices_identity_skinning_full_weight_preserves_positions() {
|
||||
let expected = vector3(3.0, 7.0, -2.0);
|
||||
let face = face(
|
||||
vec![vertex(expected)],
|
||||
Some(vec![VertexWeight {
|
||||
joint0: 0,
|
||||
joint1: 0,
|
||||
joint2: 0,
|
||||
joint3: 0,
|
||||
weight0: 1.0,
|
||||
weight1: 0.0,
|
||||
weight2: 0.0,
|
||||
weight3: 0.0,
|
||||
}]),
|
||||
);
|
||||
let mut positions = [Vector3::zero()];
|
||||
AnimeshSkinning::deform_vertices(
|
||||
face,
|
||||
vec![Matrix4::identity()],
|
||||
Matrix4::identity(),
|
||||
&mut positions,
|
||||
None,
|
||||
)
|
||||
.expect("DeformVertices");
|
||||
assert_close(positions[0].x, expected.x, 1.0e-5);
|
||||
assert_close(positions[0].y, expected.y, 1.0e-5);
|
||||
assert_close(positions[0].z, expected.z, 1.0e-5);
|
||||
}
|
||||
|
||||
// parity-case: LibreMetaverse.Tests/AvatarManagerTests.cs::AvatarManagerTests.RequestOwnAvatarTextures_WhenNotConnected_DoesNotThrow::test bf3539f68a0adc58c2166289ca1c75f6ff03906f71ffe2fb749f6990404b541a translated
|
||||
#[test]
|
||||
fn avatar_manager_request_own_avatar_textures_when_not_connected_does_not_throw() {
|
||||
let client = GridClient::new().expect("GridClient constructor");
|
||||
client
|
||||
.avatars()
|
||||
.request_own_avatar_textures()
|
||||
.expect("RequestOwnAvatarTextures");
|
||||
}
|
||||
|
||||
// parity-case: LibreMetaverse.Tests/AvatarManagerTests.cs::AvatarManagerTests.UpdateLastReceivedCOFVersion_AcceptsHigherVersion::test 3656364491dcd7a05c868b11ea0d8be48609d10c6054b9696f54cbac10cfe6df translated
|
||||
#[test]
|
||||
fn appearance_manager_update_last_received_cof_version_accepts_higher_version() {
|
||||
let client = GridClient::new().expect("GridClient constructor");
|
||||
client
|
||||
.appearance()
|
||||
.update_last_received_cof_version(3)
|
||||
.expect("UpdateLastReceivedCOFVersion");
|
||||
client
|
||||
.appearance()
|
||||
.update_last_received_cof_version(8)
|
||||
.expect("UpdateLastReceivedCOFVersion");
|
||||
assert_eq!(client.appearance().last_update_received_cof_version(), 8);
|
||||
}
|
||||
|
||||
// parity-case: LibreMetaverse.Tests/AvatarManagerTests.cs::AvatarManagerTests.UpdateLastReceivedCOFVersion_RejectsLowerVersion::test f4a827fcace9d50306a8c375183e056140996d2a39b02e4dd12fc6cc79e5d0f0 translated
|
||||
#[test]
|
||||
fn appearance_manager_update_last_received_cof_version_rejects_lower_version() {
|
||||
let client = GridClient::new().expect("GridClient constructor");
|
||||
client
|
||||
.appearance()
|
||||
.update_last_received_cof_version(10)
|
||||
.expect("UpdateLastReceivedCOFVersion");
|
||||
client
|
||||
.appearance()
|
||||
.update_last_received_cof_version(4)
|
||||
.expect("UpdateLastReceivedCOFVersion");
|
||||
assert_eq!(client.appearance().last_update_received_cof_version(), 10);
|
||||
}
|
||||
|
||||
// parity-case: LibreMetaverse.Tests/AvatarManagerTests.cs::AvatarManagerTests.UpdateLastReceivedCOFVersion_EqualVersion_IsNotAdvanced::test e3db5962cdad5e18ad27a36d0d7cca2d471e96df7513315d0f34bb0db99d723c translated
|
||||
#[test]
|
||||
fn appearance_manager_update_last_received_cof_version_equal_version_is_not_advanced() {
|
||||
let client = GridClient::new().expect("GridClient constructor");
|
||||
client
|
||||
.appearance()
|
||||
.update_last_received_cof_version(6)
|
||||
.expect("UpdateLastReceivedCOFVersion");
|
||||
client
|
||||
.appearance()
|
||||
.update_last_received_cof_version(6)
|
||||
.expect("UpdateLastReceivedCOFVersion");
|
||||
assert_eq!(client.appearance().last_update_received_cof_version(), 6);
|
||||
}
|
||||
|
||||
// parity-case: LibreMetaverse.Tests/LindenSkeletonTests.cs::LindenSkeletonTests.BuildExpandedJointList_EmptyFilter_ReturnsEmptyList::test 59857e0c12d374a3063e98311f7d262ca9e4fe3bde43af4698d20a6e6e550a64 translated
|
||||
#[test]
|
||||
fn linden_skeleton_build_expanded_joint_list_empty_filter_returns_empty_list() {
|
||||
let skeleton = make_skeleton(
|
||||
"mPelvis",
|
||||
vec![make_joint("mTorso", vec![make_joint("mChest", Vec::new())])],
|
||||
);
|
||||
let result = skeleton
|
||||
.build_expanded_joint_list(Box::new(Vec::<String>::new().into_iter()))
|
||||
.expect("BuildExpandedJointList");
|
||||
assert!(result.is_empty());
|
||||
}
|
||||
|
||||
// parity-case: LibreMetaverse.Tests/LindenSkeletonTests.cs::LindenSkeletonTests.BuildExpandedJointList_NoBoneChildren_ReturnsEmptyList::test c744ad17de5b5dd0e594973181307ddaba0d9b0ecf0ce3ff258e108de45e82be translated
|
||||
#[test]
|
||||
fn linden_skeleton_build_expanded_joint_list_no_bone_children_returns_empty_list() {
|
||||
let mut root = Joint::new().expect("Joint constructor");
|
||||
root.base.set_name("mPelvis".to_owned());
|
||||
root.set_bone(None);
|
||||
let mut skeleton = LindenSkeleton::new().expect("LindenSkeleton constructor");
|
||||
skeleton.set_bone(root);
|
||||
let result = skeleton
|
||||
.build_expanded_joint_list(Box::new(vec!["mPelvis".to_owned()].into_iter()))
|
||||
.expect("BuildExpandedJointList");
|
||||
assert!(result.is_empty());
|
||||
}
|
||||
|
||||
// parity-case: LibreMetaverse.Tests/LindenSkeletonTests.cs::LindenSkeletonTests.BuildExpandedJointList_LinearChain_AllInFilter_ProducesCorrectSequence::test c2fa9fc02df25cb6eb083746a100abf551d208ea036cadb26a1e94649d33e560 translated
|
||||
#[test]
|
||||
fn linden_skeleton_build_expanded_joint_list_linear_chain_all_in_filter() {
|
||||
let skeleton = make_skeleton(
|
||||
"root",
|
||||
vec![make_joint(
|
||||
"A",
|
||||
vec![make_joint("B", vec![make_joint("C", Vec::new())])],
|
||||
)],
|
||||
);
|
||||
let result = skeleton
|
||||
.build_expanded_joint_list(Box::new(["A", "B", "C"].map(str::to_owned).into_iter()))
|
||||
.expect("BuildExpandedJointList");
|
||||
assert_eq!(result, vec!["A", "B", "C"]);
|
||||
}
|
||||
|
||||
// parity-case: LibreMetaverse.Tests/LindenSkeletonTests.cs::LindenSkeletonTests.BuildExpandedJointList_IntermediateBoneNotInFilter_IsSkippedAsPlaceholder::test 872b6dae196f3700d62b44b6fc3ec50cd41ca78cf36fa3f63d5967b6e1e47bce translated
|
||||
#[test]
|
||||
fn linden_skeleton_build_expanded_joint_list_intermediate_not_in_filter_is_skipped() {
|
||||
let skeleton = make_skeleton(
|
||||
"root",
|
||||
vec![make_joint(
|
||||
"A",
|
||||
vec![make_joint("B", vec![make_joint("C", Vec::new())])],
|
||||
)],
|
||||
);
|
||||
let result = skeleton
|
||||
.build_expanded_joint_list(Box::new(["A", "C"].map(str::to_owned).into_iter()))
|
||||
.expect("BuildExpandedJointList");
|
||||
assert!(!result.contains(&"B".to_owned()));
|
||||
assert_eq!(result, vec!["A", "C"]);
|
||||
}
|
||||
|
||||
// parity-case: LibreMetaverse.Tests/LindenSkeletonTests.cs::LindenSkeletonTests.BuildExpandedJointList_MultipleConsecutiveIntermediates_AllSkipped::test 033ff727d7f4585321f81b2e4584395bdcbf22ad89eac601be67a1887735f944 translated
|
||||
#[test]
|
||||
fn linden_skeleton_build_expanded_joint_list_multiple_intermediates_all_skipped() {
|
||||
let skeleton = make_skeleton(
|
||||
"root",
|
||||
vec![make_joint(
|
||||
"A",
|
||||
vec![make_joint(
|
||||
"inter1",
|
||||
vec![make_joint("inter2", vec![make_joint("B", Vec::new())])],
|
||||
)],
|
||||
)],
|
||||
);
|
||||
let result = skeleton
|
||||
.build_expanded_joint_list(Box::new(["A", "B"].map(str::to_owned).into_iter()))
|
||||
.expect("BuildExpandedJointList");
|
||||
assert!(!result.contains(&"inter1".to_owned()));
|
||||
assert!(!result.contains(&"inter2".to_owned()));
|
||||
assert_eq!(result, vec!["A", "B"]);
|
||||
}
|
||||
|
||||
// parity-case: LibreMetaverse.Tests/LindenSkeletonTests.cs::LindenSkeletonTests.BuildExpandedJointList_BranchingHierarchy_BranchPointRepeatedPerChild::test ff01368c80870ec7d9b4e5eed52bbb3254e8fbf0c06d09f245abf2a450eae6c6 translated
|
||||
#[test]
|
||||
fn linden_skeleton_build_expanded_joint_list_branch_point_repeated_per_child() {
|
||||
let skeleton = make_skeleton(
|
||||
"root",
|
||||
vec![make_joint(
|
||||
"A",
|
||||
vec![
|
||||
make_joint("B", vec![make_joint("C", Vec::new())]),
|
||||
make_joint("D", Vec::new()),
|
||||
],
|
||||
)],
|
||||
);
|
||||
let result = skeleton
|
||||
.build_expanded_joint_list(Box::new(
|
||||
["A", "B", "C", "D"].map(str::to_owned).into_iter(),
|
||||
))
|
||||
.expect("BuildExpandedJointList");
|
||||
assert_eq!(result, vec!["A", "B", "C", "A", "D"]);
|
||||
}
|
||||
|
||||
// parity-case: LibreMetaverse.Tests/LindenSkeletonTests.cs::LindenSkeletonTests.BuildExpandedJointList_BranchingWithIntermediates_EffectiveParentUsedForAllBranches::test 5145f5db024a09f833a903f992f42ecc827973f7eddae31a7164e91df0b03ab3 translated
|
||||
#[test]
|
||||
fn linden_skeleton_build_expanded_joint_list_branching_uses_effective_parent() {
|
||||
let skeleton = make_skeleton(
|
||||
"root",
|
||||
vec![make_joint(
|
||||
"A",
|
||||
vec![
|
||||
make_joint("B", vec![make_joint("C", Vec::new())]),
|
||||
make_joint("D", Vec::new()),
|
||||
],
|
||||
)],
|
||||
);
|
||||
let result = skeleton
|
||||
.build_expanded_joint_list(Box::new(["A", "C", "D"].map(str::to_owned).into_iter()))
|
||||
.expect("BuildExpandedJointList");
|
||||
assert!(!result.contains(&"B".to_owned()));
|
||||
assert_eq!(result, vec!["A", "C", "A", "D"]);
|
||||
}
|
||||
|
||||
// parity-case: LibreMetaverse.Tests/LindenSkeletonTests.cs::LindenSkeletonTests.BuildExpandedJointList_OnlyLeafInFilter_ReachableViaRootPlaceholder::test e4b894c6b0479350e3ef57aab2ccb8d720a7d37df02e09ad4317953804f098fe translated
|
||||
#[test]
|
||||
fn linden_skeleton_build_expanded_joint_list_only_leaf_in_filter() {
|
||||
let skeleton = make_skeleton(
|
||||
"root",
|
||||
vec![make_joint(
|
||||
"inter1",
|
||||
vec![make_joint("inter2", vec![make_joint("leaf", Vec::new())])],
|
||||
)],
|
||||
);
|
||||
let result = skeleton
|
||||
.build_expanded_joint_list(Box::new(vec!["leaf".to_owned()].into_iter()))
|
||||
.expect("BuildExpandedJointList");
|
||||
assert_eq!(result, vec!["leaf"]);
|
||||
}
|
||||
|
||||
// parity-case: LibreMetaverse.Tests/LindenSkeletonTests.cs::LindenSkeletonTests.BuildExpandedJointList_SingleFilteredDirectChild_ProducesTwoEntries::test f9191747ebd65cf4bbe5b7780400a526f26db86545a08e581348b78f2bf61d18 translated
|
||||
#[test]
|
||||
fn linden_skeleton_build_expanded_joint_list_single_filtered_direct_child() {
|
||||
let skeleton = make_skeleton("root", vec![make_joint("A", Vec::new())]);
|
||||
let result = skeleton
|
||||
.build_expanded_joint_list(Box::new(vec!["A".to_owned()].into_iter()))
|
||||
.expect("BuildExpandedJointList");
|
||||
assert_eq!(result, vec!["A"]);
|
||||
}
|
||||
|
||||
// parity-case: LibreMetaverse.Tests/LindenSkeletonTests.cs::LindenSkeletonTests.BuildExpandedJointList_SpineBonesSkipped_DownstreamIndicesNotShifted::test 779aefe6b9fb007f17fed5d2bb6da5d81cf908d938fdceff7c9b155747d5dad9 translated
|
||||
#[test]
|
||||
fn linden_skeleton_build_expanded_joint_list_spine_bones_skipped() {
|
||||
let skeleton = make_skeleton(
|
||||
"mPelvis",
|
||||
vec![make_joint(
|
||||
"mTorso",
|
||||
vec![make_joint(
|
||||
"mSpine1",
|
||||
vec![make_joint(
|
||||
"mChest",
|
||||
vec![make_joint("mNeck", vec![make_joint("mHead", Vec::new())])],
|
||||
)],
|
||||
)],
|
||||
)],
|
||||
);
|
||||
let result = skeleton
|
||||
.build_expanded_joint_list(Box::new(
|
||||
["mTorso", "mChest", "mHead"].map(str::to_owned).into_iter(),
|
||||
))
|
||||
.expect("BuildExpandedJointList");
|
||||
assert!(!result.contains(&"mSpine1".to_owned()));
|
||||
assert!(!result.contains(&"mNeck".to_owned()));
|
||||
assert_eq!(result, vec!["mTorso", "mChest", "mHead"]);
|
||||
}
|
||||
|
||||
// parity-case: LibreMetaverse.Tests/LindenSkeletonTests.cs::LindenSkeletonTests.JointBase_SupportCategory_ReturnsBase_WhenAttributeIsBase::test 809bde18eab918a7ba51c1af1659718ec7f3a7ffc91c3dd8d462b298c78ce968 translated
|
||||
#[test]
|
||||
fn joint_base_support_category_returns_base_when_attribute_is_base() {
|
||||
let mut joint = Joint::new().expect("Joint constructor");
|
||||
joint.base.set_name("mTorso".to_owned());
|
||||
joint.base.set_support("base".to_owned());
|
||||
assert_eq!(joint.base.support_category(), JointSupportCategory::Base);
|
||||
}
|
||||
|
||||
// parity-case: LibreMetaverse.Tests/LindenSkeletonTests.cs::LindenSkeletonTests.JointBase_SupportCategory_ReturnsExtended_WhenAttributeIsExtended::test 47c16fd9e292b4d5de4e28f3b932ef8f7e04e087fd1a0023db3666e85e28762b translated
|
||||
#[test]
|
||||
fn joint_base_support_category_returns_extended_when_attribute_is_extended() {
|
||||
let mut joint = Joint::new().expect("Joint constructor");
|
||||
joint.base.set_name("mTail1".to_owned());
|
||||
joint.base.set_support("extended".to_owned());
|
||||
assert_eq!(
|
||||
joint.base.support_category(),
|
||||
JointSupportCategory::Extended
|
||||
);
|
||||
}
|
||||
|
||||
// parity-case: LibreMetaverse.Tests/LindenSkeletonTests.cs::LindenSkeletonTests.JointBase_SupportCategory_DefaultsToBase_WhenAttributeIsMissing::test 4e5faf4477a615488ac257c511ec1a02c8f53f64e34260fd48af297807dae723 translated
|
||||
#[test]
|
||||
fn joint_base_support_category_defaults_to_base_when_attribute_is_missing() {
|
||||
let mut joint = Joint::new().expect("Joint constructor");
|
||||
joint.base.set_name("mTest".to_owned());
|
||||
assert_eq!(joint.base.support_category(), JointSupportCategory::Base);
|
||||
}
|
||||
|
||||
// parity-case: LibreMetaverse.Tests/LindenSkeletonTests.cs::LindenSkeletonTests.Joint_GetAliasesList_ReturnsSplitAliases_WhenAttributeIsSet::test b28dd565d89d53fd1e5f75fa0cc4956661e9ceab65a30290c60d72f619a5e533 translated
|
||||
#[test]
|
||||
fn joint_get_aliases_list_returns_split_aliases_when_attribute_is_set() {
|
||||
let mut joint = Joint::new().expect("Joint constructor");
|
||||
joint.base.set_name("mPelvis".to_owned());
|
||||
joint.set_aliases("hip avatar_mPelvis".to_owned());
|
||||
assert_eq!(
|
||||
joint.get_aliases_list().expect("GetAliasesList"),
|
||||
vec!["hip", "avatar_mPelvis"]
|
||||
);
|
||||
}
|
||||
|
||||
// parity-case: LibreMetaverse.Tests/LindenSkeletonTests.cs::LindenSkeletonTests.Joint_GetAliasesList_ReturnsEmpty_WhenAttributeIsEmpty::test fdab4aa0aafa3739c96c673e974ad89cbdaca458c8f1c0e12a38dd6074b9850a translated
|
||||
#[test]
|
||||
fn joint_get_aliases_list_returns_empty_when_attribute_is_empty() {
|
||||
let mut joint = Joint::new().expect("Joint constructor");
|
||||
joint.base.set_name("mHead".to_owned());
|
||||
assert!(joint.get_aliases_list().expect("GetAliasesList").is_empty());
|
||||
}
|
||||
|
||||
// parity-case: LibreMetaverse.Tests/LindenSkeletonTests.cs::LindenSkeletonTests.GetAllJoints_ReturnsAllJointsDepthFirst::test 93b9b834a8f87acb434c927512fd355e171890afe7a50499f6bed1f7c020d218 translated
|
||||
#[test]
|
||||
fn linden_skeleton_get_all_joints_returns_all_joints_depth_first() {
|
||||
let skeleton = make_skeleton(
|
||||
"root",
|
||||
vec![
|
||||
make_joint("A", vec![make_joint("B", Vec::new())]),
|
||||
make_joint("C", Vec::new()),
|
||||
],
|
||||
);
|
||||
let names: Vec<String> = skeleton
|
||||
.get_all_joints()
|
||||
.expect("GetAllJoints")
|
||||
.map(|joint| joint.base.name())
|
||||
.collect();
|
||||
assert_eq!(names, vec!["root", "A", "B", "C"]);
|
||||
}
|
||||
|
||||
// parity-case: LibreMetaverse.Tests/LindenSkeletonTests.cs::LindenSkeletonTests.BuildJointDictionary_ContainsCanonicalNamesAndAliases::test d9fd2e8103d19e2c399b0e8a4dd11db2dfd0290bffd678253f64f3c07bd98c24 translated
|
||||
#[test]
|
||||
fn linden_skeleton_build_joint_dictionary_contains_names_and_aliases() {
|
||||
let mut child = Joint::new().expect("Joint constructor");
|
||||
child.base.set_name("mPelvis".to_owned());
|
||||
child.set_aliases("hip avatar_mPelvis".to_owned());
|
||||
let skeleton = make_skeleton("root", vec![child]);
|
||||
let dictionary = skeleton
|
||||
.build_joint_dictionary()
|
||||
.expect("BuildJointDictionary");
|
||||
assert!(dictionary.contains_key("root"));
|
||||
assert!(dictionary.contains_key("mPelvis"));
|
||||
assert!(dictionary.contains_key("hip"));
|
||||
assert!(dictionary.contains_key("avatar_mPelvis"));
|
||||
assert!(Arc::ptr_eq(
|
||||
dictionary.get("hip").expect("hip alias"),
|
||||
dictionary.get("mPelvis").expect("canonical name")
|
||||
));
|
||||
}
|
||||
|
||||
// parity-case: LibreMetaverse.Tests/LindenSkeletonTests.cs::LindenSkeletonTests.GetBone_ReturnsBone_ByCanonicalName::test 87761df2ed95f6dc61a89717a794956faca53a28092464c276406bd777e888a1 translated
|
||||
#[test]
|
||||
fn linden_skeleton_get_bone_returns_bone_by_canonical_name() {
|
||||
let skeleton = make_skeleton("root", vec![make_joint("mTorso", Vec::new())]);
|
||||
let joint = skeleton
|
||||
.get_bone("mTorso".to_owned())
|
||||
.expect("GetBone")
|
||||
.expect("mTorso joint");
|
||||
assert_eq!(joint.base.name(), "mTorso");
|
||||
}
|
||||
|
||||
// parity-case: LibreMetaverse.Tests/LindenSkeletonTests.cs::LindenSkeletonTests.GetBone_ReturnsBone_ByAlias::test 2bad9d7c6ad2b2944537bbf30c89370957f4ce54785c797e0bf234b44aacce2a translated
|
||||
#[test]
|
||||
fn linden_skeleton_get_bone_returns_bone_by_alias() {
|
||||
let mut child = Joint::new().expect("Joint constructor");
|
||||
child.base.set_name("mPelvis".to_owned());
|
||||
child.set_aliases("hip".to_owned());
|
||||
let skeleton = make_skeleton("root", vec![child]);
|
||||
let joint = skeleton
|
||||
.get_bone("hip".to_owned())
|
||||
.expect("GetBone")
|
||||
.expect("hip alias");
|
||||
assert_eq!(joint.base.name(), "mPelvis");
|
||||
}
|
||||
|
||||
// parity-case: LibreMetaverse.Tests/LindenSkeletonTests.cs::LindenSkeletonTests.GetBone_ReturnsNull_ForUnknownName::test 19b80d25352f1181a0ccb5e96d068840440dc9352e0e8760ee7774edd414451c translated
|
||||
#[test]
|
||||
fn linden_skeleton_get_bone_returns_none_for_unknown_name() {
|
||||
let skeleton = make_skeleton("root", vec![make_joint("mTorso", Vec::new())]);
|
||||
assert!(
|
||||
skeleton
|
||||
.get_bone("nonexistent".to_owned())
|
||||
.expect("GetBone")
|
||||
.is_none()
|
||||
);
|
||||
}
|
||||
@@ -4055,9 +4055,9 @@ pub struct AnimeshSkinning;
|
||||
impl AnimeshSkinning {
|
||||
/// C# member: `M:LibreMetaverse.AnimeshSkinning.ComputeSkinningMatrices(System.Collections.Generic.Dictionary{System.String,LibreMetaverse.Animesh.JointPose},LibreMetaverse.Rendering.LindenSkeleton,LibreMetaverse.Rendering.MeshSkinData)`.
|
||||
pub fn compute_skinning_matrices(
|
||||
pose: std::collections::HashMap<String, libremetaverse::animesh::JointPose>,
|
||||
skeleton: libremetaverse::rendering::LindenSkeleton,
|
||||
skin_data: libremetaverse::rendering::MeshSkinData,
|
||||
pose: Option<std::collections::HashMap<String, libremetaverse::animesh::JointPose>>,
|
||||
skeleton: Option<libremetaverse::rendering::LindenSkeleton>,
|
||||
skin_data: Option<libremetaverse::rendering::MeshSkinData>,
|
||||
) -> Result<Vec<libremetaverse_types::Matrix4>, crate::Error> {
|
||||
libremetaverse_types::not_implemented(
|
||||
"M:LibreMetaverse.AnimeshSkinning.ComputeSkinningMatrices(System.Collections.Generic.Dictionary{System.String,LibreMetaverse.Animesh.JointPose},LibreMetaverse.Rendering.LindenSkeleton,LibreMetaverse.Rendering.MeshSkinData)",
|
||||
@@ -4068,8 +4068,8 @@ impl AnimeshSkinning {
|
||||
face: libremetaverse::rendering::Face,
|
||||
skinning_matrices: Vec<libremetaverse_types::Matrix4>,
|
||||
bind_shape_matrix: libremetaverse_types::Matrix4,
|
||||
out_positions: libremetaverse_types::compat::Span<libremetaverse_types::Vector3>,
|
||||
out_normals: Option<libremetaverse_types::compat::Span<libremetaverse_types::Vector3>>,
|
||||
out_positions: &mut [libremetaverse_types::Vector3],
|
||||
out_normals: Option<&mut [libremetaverse_types::Vector3]>,
|
||||
) -> Result<(), crate::Error> {
|
||||
libremetaverse_types::not_implemented(
|
||||
"M:LibreMetaverse.AnimeshSkinning.DeformVertices(LibreMetaverse.Rendering.Face,LibreMetaverse.Matrix4[],LibreMetaverse.Matrix4,System.Span{LibreMetaverse.Vector3},System.Span{LibreMetaverse.Vector3})",
|
||||
@@ -4618,7 +4618,10 @@ impl AppearanceManager {
|
||||
)
|
||||
}
|
||||
/// C# member: `M:LibreMetaverse.AppearanceManager.UpdateLastReceivedCOFVersion(System.Int32)`.
|
||||
pub fn update_last_received_cof_version(&self, cof_version: i32) -> Result<(), crate::Error> {
|
||||
pub fn update_last_received_cof_version(
|
||||
&mut self,
|
||||
cof_version: i32,
|
||||
) -> Result<(), crate::Error> {
|
||||
libremetaverse_types::not_implemented(
|
||||
"M:LibreMetaverse.AppearanceManager.UpdateLastReceivedCOFVersion(System.Int32)",
|
||||
)
|
||||
@@ -28997,7 +29000,7 @@ pub mod animesh {
|
||||
pub struct AnimationTrack;
|
||||
impl AnimationTrack {
|
||||
/// C# member: `M:LibreMetaverse.Animesh.AnimationTrack.Advance(System.Single)`.
|
||||
pub fn advance(&self, dt: f32) -> Result<(), crate::Error> {
|
||||
pub fn advance(&mut self, dt: f32) -> Result<(), crate::Error> {
|
||||
libremetaverse_types::not_implemented(
|
||||
"M:LibreMetaverse.Animesh.AnimationTrack.Advance(System.Single)",
|
||||
)
|
||||
@@ -29005,7 +29008,7 @@ pub mod animesh {
|
||||
/// C# member: `M:LibreMetaverse.Animesh.AnimationTrack.EvaluatePose(System.Collections.Generic.Dictionary{System.String,LibreMetaverse.Animesh.JointPose})`.
|
||||
pub fn evaluate_pose(
|
||||
&self,
|
||||
pose: std::collections::HashMap<String, libremetaverse::animesh::JointPose>,
|
||||
pose: &mut std::collections::HashMap<String, libremetaverse::animesh::JointPose>,
|
||||
) -> Result<(), crate::Error> {
|
||||
libremetaverse_types::not_implemented(
|
||||
"M:LibreMetaverse.Animesh.AnimationTrack.EvaluatePose(System.Collections.Generic.Dictionary{System.String,LibreMetaverse.Animesh.JointPose})",
|
||||
@@ -29109,7 +29112,7 @@ pub mod animesh {
|
||||
)
|
||||
}
|
||||
/// C# member: `M:LibreMetaverse.Animesh.AnimeshPlayer.Update(System.Single)`.
|
||||
pub fn update(&self, dt: f32) -> Result<(), crate::Error> {
|
||||
pub fn update(&mut self, dt: f32) -> Result<(), crate::Error> {
|
||||
libremetaverse_types::not_implemented(
|
||||
"M:LibreMetaverse.Animesh.AnimeshPlayer.Update(System.Single)",
|
||||
)
|
||||
@@ -180601,7 +180604,7 @@ pub mod rendering {
|
||||
/// C# member: `F:LibreMetaverse.Rendering.Face.Vertices`.
|
||||
pub vertices: Vec<libremetaverse::rendering::Vertex>,
|
||||
/// C# member: `F:LibreMetaverse.Rendering.Face.Weights`.
|
||||
pub weights: Vec<libremetaverse::rendering::VertexWeight>,
|
||||
pub weights: Option<Vec<libremetaverse::rendering::VertexWeight>>,
|
||||
}
|
||||
impl Face {
|
||||
/// C# member: `M:LibreMetaverse.Rendering.Face.ToString`.
|
||||
@@ -180769,11 +180772,11 @@ pub mod rendering {
|
||||
libremetaverse_types::unimplemented_api!("P:LibreMetaverse.Rendering.Joint.aliases")
|
||||
}
|
||||
/// C# member: `P:LibreMetaverse.Rendering.Joint.bone`.
|
||||
pub fn bone(&self) -> Vec<libremetaverse::rendering::Joint> {
|
||||
pub fn bone(&self) -> Option<Vec<libremetaverse::rendering::Joint>> {
|
||||
libremetaverse_types::unimplemented_api!("P:LibreMetaverse.Rendering.Joint.bone")
|
||||
}
|
||||
/// Setter for C# member: `P:LibreMetaverse.Rendering.Joint.bone`.
|
||||
pub fn set_bone(&mut self, value: Vec<libremetaverse::rendering::Joint>) {
|
||||
pub fn set_bone(&mut self, value: Option<Vec<libremetaverse::rendering::Joint>>) {
|
||||
libremetaverse_types::unimplemented_api!("P:LibreMetaverse.Rendering.Joint.bone")
|
||||
}
|
||||
/// C# member: `P:LibreMetaverse.Rendering.Joint.collision_volume`.
|
||||
@@ -181382,8 +181385,10 @@ pub mod rendering {
|
||||
/// C# member: `M:LibreMetaverse.Rendering.LindenSkeleton.BuildJointDictionary`.
|
||||
pub fn build_joint_dictionary(
|
||||
&self,
|
||||
) -> Result<std::collections::HashMap<String, libremetaverse::rendering::Joint>, crate::Error>
|
||||
{
|
||||
) -> Result<
|
||||
std::collections::HashMap<String, std::sync::Arc<libremetaverse::rendering::Joint>>,
|
||||
crate::Error,
|
||||
> {
|
||||
libremetaverse_types::not_implemented(
|
||||
"M:LibreMetaverse.Rendering.LindenSkeleton.BuildJointDictionary",
|
||||
)
|
||||
@@ -181391,8 +181396,10 @@ pub mod rendering {
|
||||
/// C# member: `M:LibreMetaverse.Rendering.LindenSkeleton.GetAllJoints`.
|
||||
pub fn get_all_joints(
|
||||
&self,
|
||||
) -> Result<Box<dyn Iterator<Item = libremetaverse::rendering::Joint>>, crate::Error>
|
||||
{
|
||||
) -> Result<
|
||||
Box<dyn Iterator<Item = std::sync::Arc<libremetaverse::rendering::Joint>>>,
|
||||
crate::Error,
|
||||
> {
|
||||
libremetaverse_types::not_implemented(
|
||||
"M:LibreMetaverse.Rendering.LindenSkeleton.GetAllJoints",
|
||||
)
|
||||
@@ -181401,7 +181408,8 @@ pub mod rendering {
|
||||
pub fn get_bone(
|
||||
&self,
|
||||
name_or_alias: String,
|
||||
) -> Result<Option<libremetaverse::rendering::Joint>, crate::Error> {
|
||||
) -> Result<Option<std::sync::Arc<libremetaverse::rendering::Joint>>, crate::Error>
|
||||
{
|
||||
libremetaverse_types::not_implemented(
|
||||
"M:LibreMetaverse.Rendering.LindenSkeleton.GetBone(System.String)",
|
||||
)
|
||||
|
||||
@@ -6,6 +6,8 @@ mod generated;
|
||||
|
||||
#[cfg(test)]
|
||||
mod asset_archive_semantics;
|
||||
#[cfg(test)]
|
||||
mod avatar_animesh_semantics;
|
||||
|
||||
type Terrain = Vec<Vec<f32>>;
|
||||
type TerrainLoaded = Box<dyn Fn(Terrain, i64, i64) + Send + Sync>;
|
||||
@@ -25,6 +27,50 @@ impl assets::OarFile {
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
impl animesh::AnimationTrack {
|
||||
fn new(_animation_id: libremetaverse_types::UUID) -> Result<Self, Error> {
|
||||
libremetaverse_types::not_implemented(
|
||||
"M:LibreMetaverse.Animesh.AnimationTrack.#ctor(LibreMetaverse.UUID)",
|
||||
)
|
||||
}
|
||||
|
||||
fn decode_rotation(
|
||||
_value: libremetaverse_types::Vector3,
|
||||
) -> Result<libremetaverse_types::Quaternion, Error> {
|
||||
libremetaverse_types::not_implemented(
|
||||
"M:LibreMetaverse.Animesh.AnimationTrack.DecodeRotation(LibreMetaverse.Vector3)",
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(clippy::unused_self, dead_code)]
|
||||
impl animesh::AnimeshPlayer {
|
||||
fn new(_object_id: libremetaverse_types::UUID) -> Result<Self, Error> {
|
||||
libremetaverse_types::not_implemented(
|
||||
"M:LibreMetaverse.Animesh.AnimeshPlayer.#ctor(LibreMetaverse.UUID)",
|
||||
)
|
||||
}
|
||||
|
||||
fn get_or_add_track(
|
||||
&mut self,
|
||||
_animation_id: libremetaverse_types::UUID,
|
||||
) -> Result<std::sync::Arc<animesh::AnimationTrack>, Error> {
|
||||
libremetaverse_types::not_implemented(
|
||||
"M:LibreMetaverse.Animesh.AnimeshPlayer.GetOrAddTrack(LibreMetaverse.UUID)",
|
||||
)
|
||||
}
|
||||
|
||||
fn retain_only(
|
||||
&mut self,
|
||||
_animation_ids: std::collections::HashSet<libremetaverse_types::UUID>,
|
||||
) -> Result<(), Error> {
|
||||
libremetaverse_types::not_implemented(
|
||||
"M:LibreMetaverse.Animesh.AnimeshPlayer.RetainOnly(System.Collections.Generic.ISet{LibreMetaverse.UUID})",
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
pub use generated::*;
|
||||
pub use libremetaverse_imaging as imaging_abstractions;
|
||||
pub use libremetaverse_structured_data as structured_data;
|
||||
|
||||
Reference in New Issue
Block a user