mirror of
https://github.com/overte-org/overte.git
synced 2025-08-06 17:00:13 +02:00
Added defaultPoseFlags to avatar protocol
Change rotationSet to rotationIsDefaultPose for JointData Also for translation. Fixed all code to flip boolean value. Created EntityJointData so that the ModelEntity stuff doesn't need to change.
This commit is contained in:
parent
c5efcf5d6a
commit
cd4d9255bd
12 changed files with 234 additions and 77 deletions
|
@ -123,12 +123,12 @@ void ScriptableAvatar::update(float deltatime) {
|
||||||
AnimPose& absPose = absPoses[i];
|
AnimPose& absPose = absPoses[i];
|
||||||
if (data.rotation != absPose.rot()) {
|
if (data.rotation != absPose.rot()) {
|
||||||
data.rotation = absPose.rot();
|
data.rotation = absPose.rot();
|
||||||
data.rotationSet = true;
|
data.rotationIsDefaultPose = false;
|
||||||
}
|
}
|
||||||
AnimPose& relPose = poses[i];
|
AnimPose& relPose = poses[i];
|
||||||
if (data.translation != relPose.trans()) {
|
if (data.translation != relPose.trans()) {
|
||||||
data.translation = relPose.trans();
|
data.translation = relPose.trans();
|
||||||
data.translationSet = true;
|
data.translationIsDefaultPose = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -566,9 +566,9 @@ void ModelOverlay::animate() {
|
||||||
rotationMat * fbxJoints[index].postTransform);
|
rotationMat * fbxJoints[index].postTransform);
|
||||||
auto& jointData = jointsData[j];
|
auto& jointData = jointsData[j];
|
||||||
jointData.translation = extractTranslation(finalMat);
|
jointData.translation = extractTranslation(finalMat);
|
||||||
jointData.translationSet = true;
|
jointData.translationIsDefaultPose = false;
|
||||||
jointData.rotation = glmExtractRotation(finalMat);
|
jointData.rotation = glmExtractRotation(finalMat);
|
||||||
jointData.rotationSet = true;
|
jointData.rotationIsDefaultPose = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Set the data in the model
|
// Set the data in the model
|
||||||
|
|
|
@ -1705,16 +1705,16 @@ void Rig::copyJointsIntoJointData(QVector<JointData>& jointDataVec) const {
|
||||||
// rotations are in absolute rig frame.
|
// rotations are in absolute rig frame.
|
||||||
glm::quat defaultAbsRot = geometryToRigPose.rot() * _animSkeleton->getAbsoluteDefaultPose(i).rot();
|
glm::quat defaultAbsRot = geometryToRigPose.rot() * _animSkeleton->getAbsoluteDefaultPose(i).rot();
|
||||||
data.rotation = _internalPoseSet._absolutePoses[i].rot();
|
data.rotation = _internalPoseSet._absolutePoses[i].rot();
|
||||||
data.rotationSet = !isEqual(data.rotation, defaultAbsRot);
|
data.rotationIsDefaultPose = isEqual(data.rotation, defaultAbsRot);
|
||||||
|
|
||||||
// translations are in relative frame but scaled so that they are in meters,
|
// translations are in relative frame but scaled so that they are in meters,
|
||||||
// instead of geometry units.
|
// instead of geometry units.
|
||||||
glm::vec3 defaultRelTrans = _geometryOffset.scale() * _animSkeleton->getRelativeDefaultPose(i).trans();
|
glm::vec3 defaultRelTrans = _geometryOffset.scale() * _animSkeleton->getRelativeDefaultPose(i).trans();
|
||||||
data.translation = _geometryOffset.scale() * _internalPoseSet._relativePoses[i].trans();
|
data.translation = _geometryOffset.scale() * _internalPoseSet._relativePoses[i].trans();
|
||||||
data.translationSet = !isEqual(data.translation, defaultRelTrans);
|
data.translationIsDefaultPose = isEqual(data.translation, defaultRelTrans);
|
||||||
} else {
|
} else {
|
||||||
data.translationSet = false;
|
data.translationIsDefaultPose = true;
|
||||||
data.rotationSet = false;
|
data.rotationIsDefaultPose = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1739,11 +1739,11 @@ void Rig::copyJointsFromJointData(const QVector<JointData>& jointDataVec) {
|
||||||
const glm::quat rigToGeometryRot(glmExtractRotation(_rigToGeometryTransform));
|
const glm::quat rigToGeometryRot(glmExtractRotation(_rigToGeometryTransform));
|
||||||
for (int i = 0; i < numJoints; i++) {
|
for (int i = 0; i < numJoints; i++) {
|
||||||
const JointData& data = jointDataVec.at(i);
|
const JointData& data = jointDataVec.at(i);
|
||||||
if (data.rotationSet) {
|
if (data.rotationIsDefaultPose) {
|
||||||
|
rotations.push_back(absoluteDefaultPoses[i].rot());
|
||||||
|
} else {
|
||||||
// JointData rotations are in absolute rig-frame so we rotate them to absolute geometry-frame
|
// JointData rotations are in absolute rig-frame so we rotate them to absolute geometry-frame
|
||||||
rotations.push_back(rigToGeometryRot * data.rotation);
|
rotations.push_back(rigToGeometryRot * data.rotation);
|
||||||
} else {
|
|
||||||
rotations.push_back(absoluteDefaultPoses[i].rot());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1759,11 +1759,11 @@ void Rig::copyJointsFromJointData(const QVector<JointData>& jointDataVec) {
|
||||||
const JointData& data = jointDataVec.at(i);
|
const JointData& data = jointDataVec.at(i);
|
||||||
_internalPoseSet._relativePoses[i].scale() = Vectors::ONE;
|
_internalPoseSet._relativePoses[i].scale() = Vectors::ONE;
|
||||||
_internalPoseSet._relativePoses[i].rot() = rotations[i];
|
_internalPoseSet._relativePoses[i].rot() = rotations[i];
|
||||||
if (data.translationSet) {
|
if (data.translationIsDefaultPose) {
|
||||||
|
_internalPoseSet._relativePoses[i].trans() = relativeDefaultPoses[i].trans();
|
||||||
|
} else {
|
||||||
// JointData translations are in scaled relative-frame so we scale back to regular relative-frame
|
// JointData translations are in scaled relative-frame so we scale back to regular relative-frame
|
||||||
_internalPoseSet._relativePoses[i].trans() = _invGeometryOffset.scale() * data.translation;
|
_internalPoseSet._relativePoses[i].trans() = _invGeometryOffset.scale() * data.translation;
|
||||||
} else {
|
|
||||||
_internalPoseSet._relativePoses[i].trans() = relativeDefaultPoses[i].trans();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -39,6 +39,7 @@
|
||||||
#include <AudioHelpers.h>
|
#include <AudioHelpers.h>
|
||||||
#include <Profile.h>
|
#include <Profile.h>
|
||||||
#include <VariantMapToScriptValue.h>
|
#include <VariantMapToScriptValue.h>
|
||||||
|
#include <BitVectorHelpers.h>
|
||||||
|
|
||||||
#include "AvatarLogging.h"
|
#include "AvatarLogging.h"
|
||||||
|
|
||||||
|
@ -77,6 +78,12 @@ size_t AvatarDataPacket::maxJointDataSize(size_t numJoints) {
|
||||||
return totalSize;
|
return totalSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
size_t AvatarDataPacket::maxJointDefaultPoseFlagsSize(size_t numJoints) {
|
||||||
|
const size_t bitVectorSize = calcBitVectorSize((int)numJoints);
|
||||||
|
size_t totalSize = sizeof(uint8_t); // numJoints
|
||||||
|
totalSize += 2 * bitVectorSize;
|
||||||
|
return totalSize;
|
||||||
|
}
|
||||||
|
|
||||||
AvatarData::AvatarData() :
|
AvatarData::AvatarData() :
|
||||||
SpatiallyNestable(NestableType::Avatar, QUuid()),
|
SpatiallyNestable(NestableType::Avatar, QUuid()),
|
||||||
|
@ -272,6 +279,7 @@ QByteArray AvatarData::toByteArray(AvatarDataDetail dataDetail, quint64 lastSent
|
||||||
|
|
||||||
bool hasFaceTrackerInfo = false;
|
bool hasFaceTrackerInfo = false;
|
||||||
bool hasJointData = false;
|
bool hasJointData = false;
|
||||||
|
bool hasJointDefaultPoseFlags = false;
|
||||||
|
|
||||||
if (sendPALMinimum) {
|
if (sendPALMinimum) {
|
||||||
hasAudioLoudness = true;
|
hasAudioLoudness = true;
|
||||||
|
@ -290,6 +298,7 @@ QByteArray AvatarData::toByteArray(AvatarDataDetail dataDetail, quint64 lastSent
|
||||||
|
|
||||||
hasFaceTrackerInfo = !dropFaceTracking && hasFaceTracker() && (sendAll || faceTrackerInfoChangedSince(lastSentTime));
|
hasFaceTrackerInfo = !dropFaceTracking && hasFaceTracker() && (sendAll || faceTrackerInfoChangedSince(lastSentTime));
|
||||||
hasJointData = sendAll || !sendMinimum;
|
hasJointData = sendAll || !sendMinimum;
|
||||||
|
hasJointDefaultPoseFlags = hasJointData;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -314,7 +323,8 @@ QByteArray AvatarData::toByteArray(AvatarDataDetail dataDetail, quint64 lastSent
|
||||||
| (hasParentInfo ? AvatarDataPacket::PACKET_HAS_PARENT_INFO : 0)
|
| (hasParentInfo ? AvatarDataPacket::PACKET_HAS_PARENT_INFO : 0)
|
||||||
| (hasAvatarLocalPosition ? AvatarDataPacket::PACKET_HAS_AVATAR_LOCAL_POSITION : 0)
|
| (hasAvatarLocalPosition ? AvatarDataPacket::PACKET_HAS_AVATAR_LOCAL_POSITION : 0)
|
||||||
| (hasFaceTrackerInfo ? AvatarDataPacket::PACKET_HAS_FACE_TRACKER_INFO : 0)
|
| (hasFaceTrackerInfo ? AvatarDataPacket::PACKET_HAS_FACE_TRACKER_INFO : 0)
|
||||||
| (hasJointData ? AvatarDataPacket::PACKET_HAS_JOINT_DATA : 0);
|
| (hasJointData ? AvatarDataPacket::PACKET_HAS_JOINT_DATA : 0)
|
||||||
|
| (hasJointDefaultPoseFlags ? AvatarDataPacket::PACKET_HAS_JOINT_DEFAULT_POSE_FLAGS : 0);
|
||||||
|
|
||||||
memcpy(destinationBuffer, &packetStateFlags, sizeof(packetStateFlags));
|
memcpy(destinationBuffer, &packetStateFlags, sizeof(packetStateFlags));
|
||||||
destinationBuffer += sizeof(packetStateFlags);
|
destinationBuffer += sizeof(packetStateFlags);
|
||||||
|
@ -541,14 +551,19 @@ QByteArray AvatarData::toByteArray(AvatarDataDetail dataDetail, quint64 lastSent
|
||||||
|
|
||||||
for (int i = 0; i < _jointData.size(); i++) {
|
for (int i = 0; i < _jointData.size(); i++) {
|
||||||
const JointData& data = _jointData[i];
|
const JointData& data = _jointData[i];
|
||||||
|
const JointData& last = lastSentJointData[i];
|
||||||
|
|
||||||
// The dot product for smaller rotations is a smaller number.
|
if (!data.rotationIsDefaultPose) {
|
||||||
// So if the dot() is less than the value, then the rotation is a larger angle of rotation
|
if (sendAll || last.rotationIsDefaultPose || last.rotation != data.rotation) {
|
||||||
bool largeEnoughRotation = fabsf(glm::dot(data.rotation, lastSentJointData[i].rotation)) < minRotationDOT;
|
|
||||||
|
|
||||||
if (sendAll || lastSentJointData[i].rotation != data.rotation) {
|
bool largeEnoughRotation = true;
|
||||||
if (sendAll || !cullSmallChanges || largeEnoughRotation) {
|
if (cullSmallChanges) {
|
||||||
if (data.rotationSet) {
|
// The dot product for smaller rotations is a smaller number.
|
||||||
|
// So if the dot() is less than the value, then the rotation is a larger angle of rotation
|
||||||
|
largeEnoughRotation = fabsf(glm::dot(last.rotation, data.rotation)) < minRotationDOT;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sendAll || !cullSmallChanges || largeEnoughRotation) {
|
||||||
validity |= (1 << validityBit);
|
validity |= (1 << validityBit);
|
||||||
#ifdef WANT_DEBUG
|
#ifdef WANT_DEBUG
|
||||||
rotationSentCount++;
|
rotationSentCount++;
|
||||||
|
@ -557,8 +572,8 @@ QByteArray AvatarData::toByteArray(AvatarDataDetail dataDetail, quint64 lastSent
|
||||||
|
|
||||||
if (sentJointDataOut) {
|
if (sentJointDataOut) {
|
||||||
localSentJointDataOut[i].rotation = data.rotation;
|
localSentJointDataOut[i].rotation = data.rotation;
|
||||||
|
localSentJointDataOut[i].rotationIsDefaultPose = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -588,11 +603,10 @@ QByteArray AvatarData::toByteArray(AvatarDataDetail dataDetail, quint64 lastSent
|
||||||
float maxTranslationDimension = 0.0;
|
float maxTranslationDimension = 0.0;
|
||||||
for (int i = 0; i < _jointData.size(); i++) {
|
for (int i = 0; i < _jointData.size(); i++) {
|
||||||
const JointData& data = _jointData[i];
|
const JointData& data = _jointData[i];
|
||||||
if (sendAll || lastSentJointData[i].translation != data.translation) {
|
|
||||||
if (sendAll ||
|
if (!data.translationIsDefaultPose) {
|
||||||
!cullSmallChanges ||
|
if (sendAll || lastSentJointData[i].translation != data.translation) {
|
||||||
glm::distance(data.translation, lastSentJointData[i].translation) > minTranslation) {
|
if (sendAll || !cullSmallChanges || glm::distance(data.translation, lastSentJointData[i].translation) > minTranslation) {
|
||||||
if (data.translationSet) {
|
|
||||||
validity |= (1 << validityBit);
|
validity |= (1 << validityBit);
|
||||||
#ifdef WANT_DEBUG
|
#ifdef WANT_DEBUG
|
||||||
translationSentCount++;
|
translationSentCount++;
|
||||||
|
@ -606,8 +620,8 @@ QByteArray AvatarData::toByteArray(AvatarDataDetail dataDetail, quint64 lastSent
|
||||||
|
|
||||||
if (sentJointDataOut) {
|
if (sentJointDataOut) {
|
||||||
localSentJointDataOut[i].translation = data.translation;
|
localSentJointDataOut[i].translation = data.translation;
|
||||||
|
localSentJointDataOut[i].translationIsDefaultPose = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -655,6 +669,30 @@ QByteArray AvatarData::toByteArray(AvatarDataDetail dataDetail, quint64 lastSent
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (hasJointDefaultPoseFlags) {
|
||||||
|
auto startSection = destinationBuffer;
|
||||||
|
QReadLocker readLock(&_jointDataLock);
|
||||||
|
|
||||||
|
// write numJoints
|
||||||
|
int numJoints = _jointData.size();
|
||||||
|
*destinationBuffer++ = (uint8_t)numJoints;
|
||||||
|
|
||||||
|
// write rotationIsDefaultPose bits
|
||||||
|
destinationBuffer += writeBitVector(destinationBuffer, numJoints, [&](int i) {
|
||||||
|
return _jointData[i].rotationIsDefaultPose;
|
||||||
|
});
|
||||||
|
|
||||||
|
// write translationIsDefaultPose bits
|
||||||
|
destinationBuffer += writeBitVector(destinationBuffer, numJoints, [&](int i) {
|
||||||
|
return _jointData[i].translationIsDefaultPose;
|
||||||
|
});
|
||||||
|
|
||||||
|
if (outboundDataRateOut) {
|
||||||
|
size_t numBytes = destinationBuffer - startSection;
|
||||||
|
outboundDataRateOut->jointDefaultPoseFlagsRate.increment(numBytes);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
int avatarDataSize = destinationBuffer - startPosition;
|
int avatarDataSize = destinationBuffer - startPosition;
|
||||||
|
|
||||||
if (avatarDataSize > (int)byteArraySize) {
|
if (avatarDataSize > (int)byteArraySize) {
|
||||||
|
@ -664,6 +702,7 @@ QByteArray AvatarData::toByteArray(AvatarDataDetail dataDetail, quint64 lastSent
|
||||||
|
|
||||||
return avatarDataByteArray.left(avatarDataSize);
|
return avatarDataByteArray.left(avatarDataSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
// NOTE: This is never used in a "distanceAdjust" mode, so it's ok that it doesn't use a variable minimum rotation/translation
|
// NOTE: This is never used in a "distanceAdjust" mode, so it's ok that it doesn't use a variable minimum rotation/translation
|
||||||
void AvatarData::doneEncoding(bool cullSmallChanges) {
|
void AvatarData::doneEncoding(bool cullSmallChanges) {
|
||||||
// The server has finished sending this version of the joint-data to other nodes. Update _lastSentJointData.
|
// The server has finished sending this version of the joint-data to other nodes. Update _lastSentJointData.
|
||||||
|
@ -674,7 +713,7 @@ void AvatarData::doneEncoding(bool cullSmallChanges) {
|
||||||
if (_lastSentJointData[i].rotation != data.rotation) {
|
if (_lastSentJointData[i].rotation != data.rotation) {
|
||||||
if (!cullSmallChanges ||
|
if (!cullSmallChanges ||
|
||||||
fabsf(glm::dot(data.rotation, _lastSentJointData[i].rotation)) <= AVATAR_MIN_ROTATION_DOT) {
|
fabsf(glm::dot(data.rotation, _lastSentJointData[i].rotation)) <= AVATAR_MIN_ROTATION_DOT) {
|
||||||
if (data.rotationSet) {
|
if (!data.rotationIsDefaultPose) {
|
||||||
_lastSentJointData[i].rotation = data.rotation;
|
_lastSentJointData[i].rotation = data.rotation;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -682,7 +721,7 @@ void AvatarData::doneEncoding(bool cullSmallChanges) {
|
||||||
if (_lastSentJointData[i].translation != data.translation) {
|
if (_lastSentJointData[i].translation != data.translation) {
|
||||||
if (!cullSmallChanges ||
|
if (!cullSmallChanges ||
|
||||||
glm::distance(data.translation, _lastSentJointData[i].translation) > AVATAR_MIN_TRANSLATION) {
|
glm::distance(data.translation, _lastSentJointData[i].translation) > AVATAR_MIN_TRANSLATION) {
|
||||||
if (data.translationSet) {
|
if (!data.translationIsDefaultPose) {
|
||||||
_lastSentJointData[i].translation = data.translation;
|
_lastSentJointData[i].translation = data.translation;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -730,6 +769,7 @@ const unsigned char* unpackFauxJoint(const unsigned char* sourceBuffer, ThreadSa
|
||||||
|
|
||||||
// read data in packet starting at byte offset and return number of bytes parsed
|
// read data in packet starting at byte offset and return number of bytes parsed
|
||||||
int AvatarData::parseDataFromBuffer(const QByteArray& buffer) {
|
int AvatarData::parseDataFromBuffer(const QByteArray& buffer) {
|
||||||
|
|
||||||
// lazily allocate memory for HeadData in case we're not an Avatar instance
|
// lazily allocate memory for HeadData in case we're not an Avatar instance
|
||||||
lazyInitHeadData();
|
lazyInitHeadData();
|
||||||
|
|
||||||
|
@ -745,18 +785,19 @@ int AvatarData::parseDataFromBuffer(const QByteArray& buffer) {
|
||||||
|
|
||||||
#define HAS_FLAG(B,F) ((B & F) == F)
|
#define HAS_FLAG(B,F) ((B & F) == F)
|
||||||
|
|
||||||
bool hasAvatarGlobalPosition = HAS_FLAG(packetStateFlags, AvatarDataPacket::PACKET_HAS_AVATAR_GLOBAL_POSITION);
|
bool hasAvatarGlobalPosition = HAS_FLAG(packetStateFlags, AvatarDataPacket::PACKET_HAS_AVATAR_GLOBAL_POSITION);
|
||||||
bool hasAvatarBoundingBox = HAS_FLAG(packetStateFlags, AvatarDataPacket::PACKET_HAS_AVATAR_BOUNDING_BOX);
|
bool hasAvatarBoundingBox = HAS_FLAG(packetStateFlags, AvatarDataPacket::PACKET_HAS_AVATAR_BOUNDING_BOX);
|
||||||
bool hasAvatarOrientation = HAS_FLAG(packetStateFlags, AvatarDataPacket::PACKET_HAS_AVATAR_ORIENTATION);
|
bool hasAvatarOrientation = HAS_FLAG(packetStateFlags, AvatarDataPacket::PACKET_HAS_AVATAR_ORIENTATION);
|
||||||
bool hasAvatarScale = HAS_FLAG(packetStateFlags, AvatarDataPacket::PACKET_HAS_AVATAR_SCALE);
|
bool hasAvatarScale = HAS_FLAG(packetStateFlags, AvatarDataPacket::PACKET_HAS_AVATAR_SCALE);
|
||||||
bool hasLookAtPosition = HAS_FLAG(packetStateFlags, AvatarDataPacket::PACKET_HAS_LOOK_AT_POSITION);
|
bool hasLookAtPosition = HAS_FLAG(packetStateFlags, AvatarDataPacket::PACKET_HAS_LOOK_AT_POSITION);
|
||||||
bool hasAudioLoudness = HAS_FLAG(packetStateFlags, AvatarDataPacket::PACKET_HAS_AUDIO_LOUDNESS);
|
bool hasAudioLoudness = HAS_FLAG(packetStateFlags, AvatarDataPacket::PACKET_HAS_AUDIO_LOUDNESS);
|
||||||
bool hasSensorToWorldMatrix = HAS_FLAG(packetStateFlags, AvatarDataPacket::PACKET_HAS_SENSOR_TO_WORLD_MATRIX);
|
bool hasSensorToWorldMatrix = HAS_FLAG(packetStateFlags, AvatarDataPacket::PACKET_HAS_SENSOR_TO_WORLD_MATRIX);
|
||||||
bool hasAdditionalFlags = HAS_FLAG(packetStateFlags, AvatarDataPacket::PACKET_HAS_ADDITIONAL_FLAGS);
|
bool hasAdditionalFlags = HAS_FLAG(packetStateFlags, AvatarDataPacket::PACKET_HAS_ADDITIONAL_FLAGS);
|
||||||
bool hasParentInfo = HAS_FLAG(packetStateFlags, AvatarDataPacket::PACKET_HAS_PARENT_INFO);
|
bool hasParentInfo = HAS_FLAG(packetStateFlags, AvatarDataPacket::PACKET_HAS_PARENT_INFO);
|
||||||
bool hasAvatarLocalPosition = HAS_FLAG(packetStateFlags, AvatarDataPacket::PACKET_HAS_AVATAR_LOCAL_POSITION);
|
bool hasAvatarLocalPosition = HAS_FLAG(packetStateFlags, AvatarDataPacket::PACKET_HAS_AVATAR_LOCAL_POSITION);
|
||||||
bool hasFaceTrackerInfo = HAS_FLAG(packetStateFlags, AvatarDataPacket::PACKET_HAS_FACE_TRACKER_INFO);
|
bool hasFaceTrackerInfo = HAS_FLAG(packetStateFlags, AvatarDataPacket::PACKET_HAS_FACE_TRACKER_INFO);
|
||||||
bool hasJointData = HAS_FLAG(packetStateFlags, AvatarDataPacket::PACKET_HAS_JOINT_DATA);
|
bool hasJointData = HAS_FLAG(packetStateFlags, AvatarDataPacket::PACKET_HAS_JOINT_DATA);
|
||||||
|
bool hasJointDefaultPoseFlags = HAS_FLAG(packetStateFlags, AvatarDataPacket::PACKET_HAS_JOINT_DEFAULT_POSE_FLAGS);
|
||||||
|
|
||||||
quint64 now = usecTimestampNow();
|
quint64 now = usecTimestampNow();
|
||||||
|
|
||||||
|
@ -1055,7 +1096,7 @@ int AvatarData::parseDataFromBuffer(const QByteArray& buffer) {
|
||||||
if (validRotations[i]) {
|
if (validRotations[i]) {
|
||||||
sourceBuffer += unpackOrientationQuatFromSixBytes(sourceBuffer, data.rotation);
|
sourceBuffer += unpackOrientationQuatFromSixBytes(sourceBuffer, data.rotation);
|
||||||
_hasNewJointData = true;
|
_hasNewJointData = true;
|
||||||
data.rotationSet = true;
|
data.rotationIsDefaultPose = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1090,7 +1131,7 @@ int AvatarData::parseDataFromBuffer(const QByteArray& buffer) {
|
||||||
if (validTranslations[i]) {
|
if (validTranslations[i]) {
|
||||||
sourceBuffer += unpackFloatVec3FromSignedTwoByteFixed(sourceBuffer, data.translation, TRANSLATION_COMPRESSION_RADIX);
|
sourceBuffer += unpackFloatVec3FromSignedTwoByteFixed(sourceBuffer, data.translation, TRANSLATION_COMPRESSION_RADIX);
|
||||||
_hasNewJointData = true;
|
_hasNewJointData = true;
|
||||||
data.translationSet = true;
|
data.translationIsDefaultPose = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1110,6 +1151,32 @@ int AvatarData::parseDataFromBuffer(const QByteArray& buffer) {
|
||||||
_jointDataUpdateRate.increment();
|
_jointDataUpdateRate.increment();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (hasJointDefaultPoseFlags) {
|
||||||
|
auto startSection = sourceBuffer;
|
||||||
|
|
||||||
|
QWriteLocker writeLock(&_jointDataLock);
|
||||||
|
|
||||||
|
PACKET_READ_CHECK(JointDefaultPoseFlagsNumJoints, sizeof(uint8_t));
|
||||||
|
int numJoints = (int)*sourceBuffer++;
|
||||||
|
|
||||||
|
_jointData.resize(numJoints);
|
||||||
|
|
||||||
|
size_t bitVectorSize = calcBitVectorSize(numJoints);
|
||||||
|
PACKET_READ_CHECK(JointDefaultPoseFlagsRotationFlags, bitVectorSize);
|
||||||
|
sourceBuffer += readBitVector(sourceBuffer, numJoints, [&](int i, bool value) {
|
||||||
|
_jointData[i].rotationIsDefaultPose = value;
|
||||||
|
});
|
||||||
|
|
||||||
|
PACKET_READ_CHECK(JointDefaultPoseFlagsTranslationFlags, bitVectorSize);
|
||||||
|
sourceBuffer += readBitVector(sourceBuffer, numJoints, [&](int i, bool value) {
|
||||||
|
_jointData[i].translationIsDefaultPose = value;
|
||||||
|
});
|
||||||
|
|
||||||
|
int numBytesRead = sourceBuffer - startSection;
|
||||||
|
_jointDefaultPoseFlagsRate.increment(numBytesRead);
|
||||||
|
_jointDefaultPoseFlagsUpdateRate.increment();
|
||||||
|
}
|
||||||
|
|
||||||
int numBytesRead = sourceBuffer - startPosition;
|
int numBytesRead = sourceBuffer - startPosition;
|
||||||
_averageBytesReceived.updateAverage(numBytesRead);
|
_averageBytesReceived.updateAverage(numBytesRead);
|
||||||
|
|
||||||
|
@ -1146,6 +1213,8 @@ float AvatarData::getDataRate(const QString& rateName) const {
|
||||||
return _faceTrackerRate.rate() / BYTES_PER_KILOBIT;
|
return _faceTrackerRate.rate() / BYTES_PER_KILOBIT;
|
||||||
} else if (rateName == "jointData") {
|
} else if (rateName == "jointData") {
|
||||||
return _jointDataRate.rate() / BYTES_PER_KILOBIT;
|
return _jointDataRate.rate() / BYTES_PER_KILOBIT;
|
||||||
|
} else if (rateName == "jointDefaultPoseFlagsRate") {
|
||||||
|
return _jointDefaultPoseFlagsRate.rate() / BYTES_PER_KILOBIT;
|
||||||
} else if (rateName == "globalPositionOutbound") {
|
} else if (rateName == "globalPositionOutbound") {
|
||||||
return _outboundDataRate.globalPositionRate.rate() / BYTES_PER_KILOBIT;
|
return _outboundDataRate.globalPositionRate.rate() / BYTES_PER_KILOBIT;
|
||||||
} else if (rateName == "localPositionOutbound") {
|
} else if (rateName == "localPositionOutbound") {
|
||||||
|
@ -1170,6 +1239,8 @@ float AvatarData::getDataRate(const QString& rateName) const {
|
||||||
return _outboundDataRate.faceTrackerRate.rate() / BYTES_PER_KILOBIT;
|
return _outboundDataRate.faceTrackerRate.rate() / BYTES_PER_KILOBIT;
|
||||||
} else if (rateName == "jointDataOutbound") {
|
} else if (rateName == "jointDataOutbound") {
|
||||||
return _outboundDataRate.jointDataRate.rate() / BYTES_PER_KILOBIT;
|
return _outboundDataRate.jointDataRate.rate() / BYTES_PER_KILOBIT;
|
||||||
|
} else if (rateName == "jointDefaultPoseFlagsOutbound") {
|
||||||
|
return _outboundDataRate.jointDefaultPoseFlagsRate.rate() / BYTES_PER_KILOBIT;
|
||||||
}
|
}
|
||||||
return 0.0f;
|
return 0.0f;
|
||||||
}
|
}
|
||||||
|
@ -1236,9 +1307,9 @@ void AvatarData::setJointData(int index, const glm::quat& rotation, const glm::v
|
||||||
}
|
}
|
||||||
JointData& data = _jointData[index];
|
JointData& data = _jointData[index];
|
||||||
data.rotation = rotation;
|
data.rotation = rotation;
|
||||||
data.rotationSet = true;
|
data.rotationIsDefaultPose = false;
|
||||||
data.translation = translation;
|
data.translation = translation;
|
||||||
data.translationSet = true;
|
data.translationIsDefaultPose = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void AvatarData::clearJointData(int index) {
|
void AvatarData::clearJointData(int index) {
|
||||||
|
@ -1294,7 +1365,8 @@ void AvatarData::setJointData(const QString& name, const glm::quat& rotation, co
|
||||||
auto& jointData = _jointData[index];
|
auto& jointData = _jointData[index];
|
||||||
jointData.rotation = rotation;
|
jointData.rotation = rotation;
|
||||||
jointData.translation = translation;
|
jointData.translation = translation;
|
||||||
jointData.rotationSet = jointData.translationSet = true;
|
jointData.rotationIsDefaultPose = false;
|
||||||
|
jointData.translationIsDefaultPose = false;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1304,7 +1376,7 @@ void AvatarData::setJointRotation(const QString& name, const glm::quat& rotation
|
||||||
writeLockWithNamedJointIndex(name, [&](int index) {
|
writeLockWithNamedJointIndex(name, [&](int index) {
|
||||||
auto& data = _jointData[index];
|
auto& data = _jointData[index];
|
||||||
data.rotation = rotation;
|
data.rotation = rotation;
|
||||||
data.rotationSet = true;
|
data.rotationIsDefaultPose = false;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1314,7 +1386,7 @@ void AvatarData::setJointTranslation(const QString& name, const glm::vec3& trans
|
||||||
writeLockWithNamedJointIndex(name, [&](int index) {
|
writeLockWithNamedJointIndex(name, [&](int index) {
|
||||||
auto& data = _jointData[index];
|
auto& data = _jointData[index];
|
||||||
data.translation = translation;
|
data.translation = translation;
|
||||||
data.translationSet = true;
|
data.translationIsDefaultPose = false;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1328,7 +1400,7 @@ void AvatarData::setJointRotation(int index, const glm::quat& rotation) {
|
||||||
}
|
}
|
||||||
JointData& data = _jointData[index];
|
JointData& data = _jointData[index];
|
||||||
data.rotation = rotation;
|
data.rotation = rotation;
|
||||||
data.rotationSet = true;
|
data.rotationIsDefaultPose = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void AvatarData::setJointTranslation(int index, const glm::vec3& translation) {
|
void AvatarData::setJointTranslation(int index, const glm::vec3& translation) {
|
||||||
|
@ -1341,7 +1413,7 @@ void AvatarData::setJointTranslation(int index, const glm::vec3& translation) {
|
||||||
}
|
}
|
||||||
JointData& data = _jointData[index];
|
JointData& data = _jointData[index];
|
||||||
data.translation = translation;
|
data.translation = translation;
|
||||||
data.translationSet = true;
|
data.translationIsDefaultPose = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void AvatarData::clearJointData(const QString& name) {
|
void AvatarData::clearJointData(const QString& name) {
|
||||||
|
@ -1397,7 +1469,7 @@ void AvatarData::setJointRotations(const QVector<glm::quat>& jointRotations) {
|
||||||
for (int i = 0; i < size; ++i) {
|
for (int i = 0; i < size; ++i) {
|
||||||
auto& data = _jointData[i];
|
auto& data = _jointData[i];
|
||||||
data.rotation = jointRotations[i];
|
data.rotation = jointRotations[i];
|
||||||
data.rotationSet = true;
|
data.rotationIsDefaultPose = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1419,7 +1491,7 @@ void AvatarData::setJointTranslations(const QVector<glm::vec3>& jointTranslation
|
||||||
for (int i = 0; i < size; ++i) {
|
for (int i = 0; i < size; ++i) {
|
||||||
auto& data = _jointData[i];
|
auto& data = _jointData[i];
|
||||||
data.translation = jointTranslations[i];
|
data.translation = jointTranslations[i];
|
||||||
data.translationSet = true;
|
data.translationIsDefaultPose = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1996,9 +2068,9 @@ JointData jointDataFromJsonValue(const QJsonValue& json) {
|
||||||
if (json.isArray()) {
|
if (json.isArray()) {
|
||||||
QJsonArray array = json.toArray();
|
QJsonArray array = json.toArray();
|
||||||
result.rotation = quatFromJsonValue(array[0]);
|
result.rotation = quatFromJsonValue(array[0]);
|
||||||
result.rotationSet = true;
|
result.rotationIsDefaultPose = false;
|
||||||
result.translation = vec3FromJsonValue(array[1]);
|
result.translation = vec3FromJsonValue(array[1]);
|
||||||
result.translationSet = true;
|
result.translationIsDefaultPose = false;
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
|
@ -113,18 +113,19 @@ namespace AvatarDataPacket {
|
||||||
// Packet State Flags - we store the details about the existence of other records in this bitset:
|
// Packet State Flags - we store the details about the existence of other records in this bitset:
|
||||||
// AvatarGlobalPosition, Avatar face tracker, eye tracking, and existence of
|
// AvatarGlobalPosition, Avatar face tracker, eye tracking, and existence of
|
||||||
using HasFlags = uint16_t;
|
using HasFlags = uint16_t;
|
||||||
const HasFlags PACKET_HAS_AVATAR_GLOBAL_POSITION = 1U << 0;
|
const HasFlags PACKET_HAS_AVATAR_GLOBAL_POSITION = 1U << 0;
|
||||||
const HasFlags PACKET_HAS_AVATAR_BOUNDING_BOX = 1U << 1;
|
const HasFlags PACKET_HAS_AVATAR_BOUNDING_BOX = 1U << 1;
|
||||||
const HasFlags PACKET_HAS_AVATAR_ORIENTATION = 1U << 2;
|
const HasFlags PACKET_HAS_AVATAR_ORIENTATION = 1U << 2;
|
||||||
const HasFlags PACKET_HAS_AVATAR_SCALE = 1U << 3;
|
const HasFlags PACKET_HAS_AVATAR_SCALE = 1U << 3;
|
||||||
const HasFlags PACKET_HAS_LOOK_AT_POSITION = 1U << 4;
|
const HasFlags PACKET_HAS_LOOK_AT_POSITION = 1U << 4;
|
||||||
const HasFlags PACKET_HAS_AUDIO_LOUDNESS = 1U << 5;
|
const HasFlags PACKET_HAS_AUDIO_LOUDNESS = 1U << 5;
|
||||||
const HasFlags PACKET_HAS_SENSOR_TO_WORLD_MATRIX = 1U << 6;
|
const HasFlags PACKET_HAS_SENSOR_TO_WORLD_MATRIX = 1U << 6;
|
||||||
const HasFlags PACKET_HAS_ADDITIONAL_FLAGS = 1U << 7;
|
const HasFlags PACKET_HAS_ADDITIONAL_FLAGS = 1U << 7;
|
||||||
const HasFlags PACKET_HAS_PARENT_INFO = 1U << 8;
|
const HasFlags PACKET_HAS_PARENT_INFO = 1U << 8;
|
||||||
const HasFlags PACKET_HAS_AVATAR_LOCAL_POSITION = 1U << 9;
|
const HasFlags PACKET_HAS_AVATAR_LOCAL_POSITION = 1U << 9;
|
||||||
const HasFlags PACKET_HAS_FACE_TRACKER_INFO = 1U << 10;
|
const HasFlags PACKET_HAS_FACE_TRACKER_INFO = 1U << 10;
|
||||||
const HasFlags PACKET_HAS_JOINT_DATA = 1U << 11;
|
const HasFlags PACKET_HAS_JOINT_DATA = 1U << 11;
|
||||||
|
const HasFlags PACKET_HAS_JOINT_DEFAULT_POSE_FLAGS = 1U << 12;
|
||||||
const size_t AVATAR_HAS_FLAGS_SIZE = 2;
|
const size_t AVATAR_HAS_FLAGS_SIZE = 2;
|
||||||
|
|
||||||
using SixByteQuat = uint8_t[6];
|
using SixByteQuat = uint8_t[6];
|
||||||
|
@ -256,6 +257,15 @@ namespace AvatarDataPacket {
|
||||||
};
|
};
|
||||||
*/
|
*/
|
||||||
size_t maxJointDataSize(size_t numJoints);
|
size_t maxJointDataSize(size_t numJoints);
|
||||||
|
|
||||||
|
/*
|
||||||
|
struct JointDefaultPoseFlags {
|
||||||
|
uint8_t numJoints;
|
||||||
|
uint8_t rotationIsDefaultPoseBits[ceil(numJoints / 8)];
|
||||||
|
uint8_t translationIsDefaultPoseBits[ceil(numJoints / 8)];
|
||||||
|
};
|
||||||
|
*/
|
||||||
|
size_t maxJointDefaultPoseFlagsSize(size_t numJoints);
|
||||||
}
|
}
|
||||||
|
|
||||||
const float MAX_AUDIO_LOUDNESS = 1000.0f; // close enough for mouth animation
|
const float MAX_AUDIO_LOUDNESS = 1000.0f; // close enough for mouth animation
|
||||||
|
@ -321,6 +331,7 @@ public:
|
||||||
RateCounter<> parentInfoRate;
|
RateCounter<> parentInfoRate;
|
||||||
RateCounter<> faceTrackerRate;
|
RateCounter<> faceTrackerRate;
|
||||||
RateCounter<> jointDataRate;
|
RateCounter<> jointDataRate;
|
||||||
|
RateCounter<> jointDefaultPoseFlagsRate;
|
||||||
};
|
};
|
||||||
|
|
||||||
class AvatarPriority {
|
class AvatarPriority {
|
||||||
|
@ -810,6 +821,7 @@ protected:
|
||||||
RateCounter<> _parentInfoRate;
|
RateCounter<> _parentInfoRate;
|
||||||
RateCounter<> _faceTrackerRate;
|
RateCounter<> _faceTrackerRate;
|
||||||
RateCounter<> _jointDataRate;
|
RateCounter<> _jointDataRate;
|
||||||
|
RateCounter<> _jointDefaultPoseFlagsRate;
|
||||||
|
|
||||||
// Some rate data for incoming data updates
|
// Some rate data for incoming data updates
|
||||||
RateCounter<> _parseBufferUpdateRate;
|
RateCounter<> _parseBufferUpdateRate;
|
||||||
|
@ -825,6 +837,7 @@ protected:
|
||||||
RateCounter<> _parentInfoUpdateRate;
|
RateCounter<> _parentInfoUpdateRate;
|
||||||
RateCounter<> _faceTrackerUpdateRate;
|
RateCounter<> _faceTrackerUpdateRate;
|
||||||
RateCounter<> _jointDataUpdateRate;
|
RateCounter<> _jointDataUpdateRate;
|
||||||
|
RateCounter<> _jointDefaultPoseFlagsUpdateRate;
|
||||||
|
|
||||||
// Some rate data for outgoing data
|
// Some rate data for outgoing data
|
||||||
AvatarDataRate _outboundDataRate;
|
AvatarDataRate _outboundDataRate;
|
||||||
|
|
|
@ -1050,7 +1050,7 @@ void ModelEntityRenderer::animate(const TypedEntityPointer& entity) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
QVector<JointData> jointsData;
|
QVector<EntityJointData> jointsData;
|
||||||
|
|
||||||
const QVector<FBXAnimationFrame>& frames = _animation->getFramesReference(); // NOTE: getFrames() is too heavy
|
const QVector<FBXAnimationFrame>& frames = _animation->getFramesReference(); // NOTE: getFrames() is too heavy
|
||||||
int frameCount = frames.size();
|
int frameCount = frames.size();
|
||||||
|
|
|
@ -452,7 +452,7 @@ void ModelEntityItem::resizeJointArrays(int newSize) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void ModelEntityItem::setAnimationJointsData(const QVector<JointData>& jointsData) {
|
void ModelEntityItem::setAnimationJointsData(const QVector<EntityJointData>& jointsData) {
|
||||||
resizeJointArrays(jointsData.size());
|
resizeJointArrays(jointsData.size());
|
||||||
_jointDataLock.withWriteLock([&] {
|
_jointDataLock.withWriteLock([&] {
|
||||||
for (auto index = 0; index < jointsData.size(); ++index) {
|
for (auto index = 0; index < jointsData.size(); ++index) {
|
||||||
|
|
|
@ -124,7 +124,7 @@ public:
|
||||||
virtual void setJointTranslations(const QVector<glm::vec3>& translations);
|
virtual void setJointTranslations(const QVector<glm::vec3>& translations);
|
||||||
virtual void setJointTranslationsSet(const QVector<bool>& translationsSet);
|
virtual void setJointTranslationsSet(const QVector<bool>& translationsSet);
|
||||||
|
|
||||||
virtual void setAnimationJointsData(const QVector<JointData>& jointsData);
|
virtual void setAnimationJointsData(const QVector<EntityJointData>& jointsData);
|
||||||
|
|
||||||
QVector<glm::quat> getJointRotations() const;
|
QVector<glm::quat> getJointRotations() const;
|
||||||
QVector<bool> getJointRotationsSet() const;
|
QVector<bool> getJointRotationsSet() const;
|
||||||
|
@ -150,7 +150,7 @@ protected:
|
||||||
bool _jointTranslationsExplicitlySet{ false }; // were the joints set as a property or just side effect of animations
|
bool _jointTranslationsExplicitlySet{ false }; // were the joints set as a property or just side effect of animations
|
||||||
|
|
||||||
struct ModelJointData {
|
struct ModelJointData {
|
||||||
JointData joint;
|
EntityJointData joint;
|
||||||
bool rotationDirty { false };
|
bool rotationDirty { false };
|
||||||
bool translationDirty { false };
|
bool translationDirty { false };
|
||||||
};
|
};
|
||||||
|
|
|
@ -38,7 +38,7 @@ PacketVersion versionForPacketType(PacketType packetType) {
|
||||||
case PacketType::AvatarData:
|
case PacketType::AvatarData:
|
||||||
case PacketType::BulkAvatarData:
|
case PacketType::BulkAvatarData:
|
||||||
case PacketType::KillAvatar:
|
case PacketType::KillAvatar:
|
||||||
return static_cast<PacketVersion>(AvatarMixerPacketVersion::UpdatedMannequinDefaultAvatar);
|
return static_cast<PacketVersion>(AvatarMixerPacketVersion::AvatarJointDefaultPoseFlags);
|
||||||
case PacketType::MessagesData:
|
case PacketType::MessagesData:
|
||||||
return static_cast<PacketVersion>(MessageDataVersion::TextOrBinaryData);
|
return static_cast<PacketVersion>(MessageDataVersion::TextOrBinaryData);
|
||||||
case PacketType::ICEServerHeartbeat:
|
case PacketType::ICEServerHeartbeat:
|
||||||
|
|
|
@ -247,7 +247,8 @@ enum class AvatarMixerPacketVersion : PacketVersion {
|
||||||
AvatarIdentitySequenceFront,
|
AvatarIdentitySequenceFront,
|
||||||
IsReplicatedInAvatarIdentity,
|
IsReplicatedInAvatarIdentity,
|
||||||
AvatarIdentityLookAtSnapping,
|
AvatarIdentityLookAtSnapping,
|
||||||
UpdatedMannequinDefaultAvatar
|
UpdatedMannequinDefaultAvatar,
|
||||||
|
AvatarJointDefaultPoseFlags
|
||||||
};
|
};
|
||||||
|
|
||||||
enum class DomainConnectRequestVersion : PacketVersion {
|
enum class DomainConnectRequestVersion : PacketVersion {
|
||||||
|
|
58
libraries/shared/src/BitVectorHelpers.h
Normal file
58
libraries/shared/src/BitVectorHelpers.h
Normal file
|
@ -0,0 +1,58 @@
|
||||||
|
//
|
||||||
|
// BitVectorHelpers.h
|
||||||
|
// libraries/shared/src
|
||||||
|
//
|
||||||
|
// Created by Anthony Thibault on 1/19/18.
|
||||||
|
// Copyright 2018 High Fidelity, Inc.
|
||||||
|
//
|
||||||
|
// Distributed under the Apache License, Version 2.0.
|
||||||
|
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef hifi_BitVectorHelpers_h
|
||||||
|
#define hifi_BitVectorHelpers_h
|
||||||
|
|
||||||
|
size_t calcBitVectorSize(int numBits) {
|
||||||
|
return ((numBits - 1) >> 3) + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// func should be of type bool func(int index)
|
||||||
|
template <typename F>
|
||||||
|
size_t writeBitVector(uint8_t* destinationBuffer, int numBits, const F& func) {
|
||||||
|
size_t totalBytes = ((numBits - 1) >> 3) + 1;
|
||||||
|
uint8_t* cursor = destinationBuffer;
|
||||||
|
uint8_t byte = 0;
|
||||||
|
uint8_t bit = 0;
|
||||||
|
|
||||||
|
for (int i = 0; i < numBits; i++) {
|
||||||
|
if (func(i)) {
|
||||||
|
byte |= (1 << bit);
|
||||||
|
}
|
||||||
|
if (++bit == BITS_IN_BYTE) {
|
||||||
|
*cursor++ = byte;
|
||||||
|
byte = 0;
|
||||||
|
bit = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return totalBytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
// func should be of type 'void func(int index, bool value)'
|
||||||
|
template <typename F>
|
||||||
|
size_t readBitVector(const uint8_t* sourceBuffer, int numBits, const F& func) {
|
||||||
|
size_t totalBytes = ((numBits - 1) >> 3) + 1;
|
||||||
|
const uint8_t* cursor = sourceBuffer;
|
||||||
|
uint8_t bit = 0;
|
||||||
|
|
||||||
|
for (int i = 0; i < numBits; i++) {
|
||||||
|
bool value = (bool)(*cursor & (1 << bit));
|
||||||
|
func(i, value);
|
||||||
|
if (++bit == BITS_IN_BYTE) {
|
||||||
|
cursor++;
|
||||||
|
bit = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return totalBytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -5,14 +5,27 @@
|
||||||
#include <glm/glm.hpp>
|
#include <glm/glm.hpp>
|
||||||
#include <glm/gtc/quaternion.hpp>
|
#include <glm/gtc/quaternion.hpp>
|
||||||
|
|
||||||
// Used by the avatar mixer to describe a single joint
|
class EntityJointData {
|
||||||
// These are relative to their parent and translations are in meters
|
|
||||||
class JointData {
|
|
||||||
public:
|
public:
|
||||||
glm::quat rotation;
|
glm::quat rotation;
|
||||||
|
glm::vec3 translation;
|
||||||
bool rotationSet = false;
|
bool rotationSet = false;
|
||||||
glm::vec3 translation; // meters
|
|
||||||
bool translationSet = false;
|
bool translationSet = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Used by the avatar mixer to describe a single joint
|
||||||
|
// Translations relative to their parent and are in meters.
|
||||||
|
// Rotations are absolute (i.e. not relative to parent) and are in rig space.
|
||||||
|
class JointData {
|
||||||
|
public:
|
||||||
|
glm::quat rotation;
|
||||||
|
glm::vec3 translation;
|
||||||
|
|
||||||
|
// This indicates that the rotation or translation is the same as the defaultPose for the avatar.
|
||||||
|
// if true, it also means that the rotation or translation value in this structure is not valid and
|
||||||
|
// should be replaced by the avatar's actual default pose value.
|
||||||
|
bool rotationIsDefaultPose = true;
|
||||||
|
bool translationIsDefaultPose = true;
|
||||||
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
Loading…
Reference in a new issue