From 1fd37b51a2bced38a435128d327e0aa4269388b7 Mon Sep 17 00:00:00 2001 From: samcake Date: Thu, 12 Nov 2015 17:54:35 -0800 Subject: [PATCH 1/4] trying to get somewhere.... --- examples/utilities/record/recorder.js | 2 + interface/src/avatar/MyAvatar.cpp | 2 +- libraries/avatars/src/AvatarData.cpp | 67 +++++++++++++++++++-------- libraries/avatars/src/AvatarData.h | 3 ++ 4 files changed, 54 insertions(+), 20 deletions(-) diff --git a/examples/utilities/record/recorder.js b/examples/utilities/record/recorder.js index 6d49030a28..13ea1e0c72 100644 --- a/examples/utilities/record/recorder.js +++ b/examples/utilities/record/recorder.js @@ -176,6 +176,8 @@ function formatTime(time) { var SEC_PER_MIN = 60; var MSEC_PER_SEC = 1000; + time = time * (MSEC_PER_SEC * SEC_PER_MIN * MIN_PER_HOUR); + var hours = Math.floor(time / (MSEC_PER_SEC * SEC_PER_MIN * MIN_PER_HOUR)); time -= hours * (MSEC_PER_SEC * SEC_PER_MIN * MIN_PER_HOUR); diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 5e14c66ff1..4d62946a5f 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -608,7 +608,7 @@ float MyAvatar::recorderElapsed() { if (!_recorder) { return 0; } - return (float)_recorder->position() / MSECS_PER_SECOND; + return (float)_recorder->position(); } QMetaObject::Connection _audioClientRecorderConnection; diff --git a/libraries/avatars/src/AvatarData.cpp b/libraries/avatars/src/AvatarData.cpp index adf471c50e..e2d2c05ef6 100644 --- a/libraries/avatars/src/AvatarData.cpp +++ b/libraries/avatars/src/AvatarData.cpp @@ -804,12 +804,12 @@ float AvatarData::playerElapsed() { return 0; } if (QThread::currentThread() != thread()) { - qint64 result; + float result; QMetaObject::invokeMethod(this, "playerElapsed", Qt::BlockingQueuedConnection, - Q_RETURN_ARG(qint64, result)); + Q_RETURN_ARG(float, result)); return result; } - return (float)_player->position() / MSECS_PER_SECOND; + return (float)_player->position(); } float AvatarData::playerLength() { @@ -817,12 +817,12 @@ float AvatarData::playerLength() { return 0; } if (QThread::currentThread() != thread()) { - qint64 result; + float result; QMetaObject::invokeMethod(this, "playerLength", Qt::BlockingQueuedConnection, - Q_RETURN_ARG(qint64, result)); + Q_RETURN_ARG(float, result)); return result; } - return _player->length() / MSECS_PER_SECOND; + return _player->length(); } void AvatarData::loadRecording(const QString& filename) { @@ -870,7 +870,7 @@ void AvatarData::setPlayerTime(float time) { return; } - _player->seek(time * MSECS_PER_SECOND); + _player->seek(time); } void AvatarData::setPlayFromCurrentLocation(bool playFromCurrentLocation) { @@ -1532,7 +1532,7 @@ Transform AvatarData::getTransform() const { static const QString JSON_AVATAR_BASIS = QStringLiteral("basisTransform"); static const QString JSON_AVATAR_RELATIVE = QStringLiteral("relativeTransform"); -static const QString JSON_AVATAR_JOINT_ROTATIONS = QStringLiteral("jointRotations"); +static const QString JSON_AVATAR_JOINT_ARRAY = QStringLiteral("jointArray"); static const QString JSON_AVATAR_HEAD = QStringLiteral("head"); static const QString JSON_AVATAR_HEAD_ROTATION = QStringLiteral("rotation"); static const QString JSON_AVATAR_HEAD_BLENDSHAPE_COEFFICIENTS = QStringLiteral("blendShapes"); @@ -1544,6 +1544,24 @@ static const QString JSON_AVATAR_BODY_MODEL = QStringLiteral("bodyModel"); static const QString JSON_AVATAR_DISPLAY_NAME = QStringLiteral("displayName"); static const QString JSON_AVATAR_ATTACHEMENTS = QStringLiteral("attachments"); +QJsonValue toJsonValue(const JointData& joint) { + QJsonArray result; + result.push_back(toJsonValue(joint.rotation)); + result.push_back(toJsonValue(joint.translation)); + return result; +} + +JointData jointDataFromJsonValue(const QJsonValue& json) { + JointData result; + if (json.isArray()) { + QJsonArray array = json.toArray(); + result.rotation = quatFromJsonValue(array[0]); + result.rotationSet = true; + result.translation = vec3FromJsonValue(array[1]); + result.translationSet = false; + } + return result; +} // Every frame will store both a basis for the recording and a relative transform // This allows the application to decide whether playback should be relative to an avatar's @@ -1575,13 +1593,16 @@ QByteArray avatarStateToFrame(const AvatarData* _avatar) { root[JSON_AVATAR_RELATIVE] = Transform::toJson(relativeTransform); root[JSON_AVATAR_BASIS] = Transform::toJson(*recordingBasis); } + } else { + root[JSON_AVATAR_RELATIVE] = Transform::toJson(_avatar->getTransform()); } - QJsonArray jointRotations; - for (const auto& jointRotation : _avatar->getJointRotations()) { - jointRotations.push_back(toJsonValue(jointRotation)); + // Skeleton pose + QJsonArray jointArray; + for (const auto& joint : _avatar->getRawJointData()) { + jointArray.push_back(toJsonValue(joint)); } - root[JSON_AVATAR_JOINT_ROTATIONS] = jointRotations; + root[JSON_AVATAR_JOINT_ARRAY] = jointArray; const HeadData* head = _avatar->getHeadData(); if (head) { @@ -1646,21 +1667,29 @@ void avatarStateFromFrame(const QByteArray& frameData, AvatarData* _avatar) { _avatar->setTargetScale(worldTransform.getScale().x); } -#if 0 + if (root.contains(JSON_AVATAR_ATTACHEMENTS)) { // FIXME de-serialize attachment data } // Joint rotations are relative to the avatar, so they require no basis correction - if (root.contains(JSON_AVATAR_JOINT_ROTATIONS)) { - QVector jointRotations; - QJsonArray jointRotationsJson = root[JSON_AVATAR_JOINT_ROTATIONS].toArray(); - jointRotations.reserve(jointRotationsJson.size()); - for (const auto& jointRotationJson : jointRotationsJson) { - jointRotations.push_back(quatFromJsonValue(jointRotationJson)); + if (root.contains(JSON_AVATAR_JOINT_ARRAY)) { + QVector jointArray; + QJsonArray jointArrayJson = root[JSON_AVATAR_JOINT_ARRAY].toArray(); + jointArray.reserve(jointArrayJson.size()); + for (const auto& jointJson : jointArrayJson) { + jointArray.push_back(jointDataFromJsonValue(jointJson)); } + + QVector jointRotations; + jointRotations.reserve(jointArray.size()); + for (const auto& joint : jointArray) { + jointRotations.push_back(joint.rotation); + } + _avatar->setJointRotations(jointRotations); } +#if 0 // Most head data is relative to the avatar, and needs no basis correction, // but the lookat vector does need correction HeadData* head = _avatar->_headData; diff --git a/libraries/avatars/src/AvatarData.h b/libraries/avatars/src/AvatarData.h index 7716a16a1c..26bc9d83ff 100644 --- a/libraries/avatars/src/AvatarData.h +++ b/libraries/avatars/src/AvatarData.h @@ -457,6 +457,9 @@ public: bool translationSet = false; }; +QJsonValue toJsonValue(const JointData& joint); +JointData jointDataFromJsonValue(const QJsonValue& q); + class AttachmentData { public: QUrl modelURL; From 89d120ab3d42ca26f7536961d861b29e009847c2 Mon Sep 17 00:00:00 2001 From: Sam Gateau Date: Thu, 12 Nov 2015 22:24:11 -0800 Subject: [PATCH 2/4] Few fixes to make the recorder.js run --- examples/utilities/record/recorder.js | 2 +- libraries/avatars/src/AvatarData.cpp | 6 +++--- libraries/recording/src/recording/Deck.cpp | 2 ++ libraries/recording/src/recording/Frame.h | 2 +- 4 files changed, 7 insertions(+), 5 deletions(-) diff --git a/examples/utilities/record/recorder.js b/examples/utilities/record/recorder.js index 13ea1e0c72..b44cb23aa8 100644 --- a/examples/utilities/record/recorder.js +++ b/examples/utilities/record/recorder.js @@ -176,7 +176,7 @@ function formatTime(time) { var SEC_PER_MIN = 60; var MSEC_PER_SEC = 1000; - time = time * (MSEC_PER_SEC * SEC_PER_MIN * MIN_PER_HOUR); + time = time * (MSEC_PER_SEC); var hours = Math.floor(time / (MSEC_PER_SEC * SEC_PER_MIN * MIN_PER_HOUR)); time -= hours * (MSEC_PER_SEC * SEC_PER_MIN * MIN_PER_HOUR); diff --git a/libraries/avatars/src/AvatarData.cpp b/libraries/avatars/src/AvatarData.cpp index e2d2c05ef6..e44219977b 100644 --- a/libraries/avatars/src/AvatarData.cpp +++ b/libraries/avatars/src/AvatarData.cpp @@ -809,7 +809,7 @@ float AvatarData::playerElapsed() { Q_RETURN_ARG(float, result)); return result; } - return (float)_player->position(); + return (float)_player->position() / (float) MSECS_PER_SECOND; } float AvatarData::playerLength() { @@ -822,7 +822,7 @@ float AvatarData::playerLength() { Q_RETURN_ARG(float, result)); return result; } - return _player->length(); + return (float)_player->length() / (float) MSECS_PER_SECOND; } void AvatarData::loadRecording(const QString& filename) { @@ -870,7 +870,7 @@ void AvatarData::setPlayerTime(float time) { return; } - _player->seek(time); + _player->seek(time * MSECS_PER_SECOND); } void AvatarData::setPlayFromCurrentLocation(bool playFromCurrentLocation) { diff --git a/libraries/recording/src/recording/Deck.cpp b/libraries/recording/src/recording/Deck.cpp index 4349a39732..10209c26d7 100644 --- a/libraries/recording/src/recording/Deck.cpp +++ b/libraries/recording/src/recording/Deck.cpp @@ -25,6 +25,8 @@ void Deck::queueClip(ClipPointer clip, Time timeOffset) { // FIXME if the time offset is not zero, wrap the clip in a OffsetClip wrapper _clips.push_back(clip); + + _length = std::max(_length, clip->duration()); } void Deck::play() { diff --git a/libraries/recording/src/recording/Frame.h b/libraries/recording/src/recording/Frame.h index 85f5246a4e..f0f53ce144 100644 --- a/libraries/recording/src/recording/Frame.h +++ b/libraries/recording/src/recording/Frame.h @@ -27,7 +27,7 @@ public: static const FrameType TYPE_INVALID = 0xFFFF; static const FrameType TYPE_HEADER = 0x0; FrameType type { TYPE_INVALID }; - Time timeOffset { 0 }; + Time timeOffset { 0 }; // milliseconds QByteArray data; Frame() {} From 8c21ac144ee63642461e457bdcafcf0556ddf6db Mon Sep 17 00:00:00 2001 From: samcake Date: Fri, 13 Nov 2015 16:45:19 -0800 Subject: [PATCH 3/4] Fixing review comments --- interface/src/avatar/MyAvatar.cpp | 2 +- libraries/avatars/src/AvatarData.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 4d62946a5f..278cc5ff81 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -608,7 +608,7 @@ float MyAvatar::recorderElapsed() { if (!_recorder) { return 0; } - return (float)_recorder->position(); + return (float)_recorder->position() / (float) MSECS_PER_SECOND; } QMetaObject::Connection _audioClientRecorderConnection; diff --git a/libraries/avatars/src/AvatarData.cpp b/libraries/avatars/src/AvatarData.cpp index e44219977b..8537f37f84 100644 --- a/libraries/avatars/src/AvatarData.cpp +++ b/libraries/avatars/src/AvatarData.cpp @@ -1664,7 +1664,7 @@ void avatarStateFromFrame(const QByteArray& frameData, AvatarData* _avatar) { auto worldTransform = currentBasis->worldTransform(relativeTransform); _avatar->setPosition(worldTransform.getTranslation()); _avatar->setOrientation(worldTransform.getRotation()); - _avatar->setTargetScale(worldTransform.getScale().x); + // _avatar->setTargetScale(worldTransform.getScale().x); } From 89e5db11a016005e6b402cdd297ada002256d287 Mon Sep 17 00:00:00 2001 From: samcake Date: Fri, 13 Nov 2015 17:41:41 -0800 Subject: [PATCH 4/4] More fixes --- examples/utilities/record/recorder.js | 13 +++++-------- libraries/avatars/src/AvatarData.cpp | 7 +++++-- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/examples/utilities/record/recorder.js b/examples/utilities/record/recorder.js index b44cb23aa8..40476626e8 100644 --- a/examples/utilities/record/recorder.js +++ b/examples/utilities/record/recorder.js @@ -176,16 +176,13 @@ function formatTime(time) { var SEC_PER_MIN = 60; var MSEC_PER_SEC = 1000; - time = time * (MSEC_PER_SEC); + var hours = Math.floor(time / (SEC_PER_MIN * MIN_PER_HOUR)); + time -= hours * (SEC_PER_MIN * MIN_PER_HOUR); - var hours = Math.floor(time / (MSEC_PER_SEC * SEC_PER_MIN * MIN_PER_HOUR)); - time -= hours * (MSEC_PER_SEC * SEC_PER_MIN * MIN_PER_HOUR); + var minutes = Math.floor(time / (SEC_PER_MIN)); + time -= minutes * (SEC_PER_MIN); - var minutes = Math.floor(time / (MSEC_PER_SEC * SEC_PER_MIN)); - time -= minutes * (MSEC_PER_SEC * SEC_PER_MIN); - - var seconds = Math.floor(time / MSEC_PER_SEC); - seconds = time / MSEC_PER_SEC; + var seconds = time; var text = ""; text += (hours > 0) ? hours + ":" : diff --git a/libraries/avatars/src/AvatarData.cpp b/libraries/avatars/src/AvatarData.cpp index 8537f37f84..a47d5f663e 100644 --- a/libraries/avatars/src/AvatarData.cpp +++ b/libraries/avatars/src/AvatarData.cpp @@ -1513,7 +1513,8 @@ void AvatarData::setRecordingBasis(std::shared_ptr recordingBasis) { recordingBasis = std::make_shared(); recordingBasis->setRotation(getOrientation()); recordingBasis->setTranslation(getPosition()); - recordingBasis->setScale(getTargetScale()); + // TODO: find a different way to record/playback the Scale of the avatar + //recordingBasis->setScale(getTargetScale()); } _recordingBasis = recordingBasis; } @@ -1664,7 +1665,9 @@ void avatarStateFromFrame(const QByteArray& frameData, AvatarData* _avatar) { auto worldTransform = currentBasis->worldTransform(relativeTransform); _avatar->setPosition(worldTransform.getTranslation()); _avatar->setOrientation(worldTransform.getRotation()); - // _avatar->setTargetScale(worldTransform.getScale().x); + + // TODO: find a way to record/playback the Scale of the avatar + //_avatar->setTargetScale(worldTransform.getScale().x); }