mirror of
https://github.com/overte-org/overte.git
synced 2025-07-24 00:43:49 +02:00
Merge branch 'master' of git://github.com/worklist/hifi into 19498
This commit is contained in:
commit
c78bcc6d2f
7 changed files with 192 additions and 82 deletions
|
@ -113,18 +113,18 @@
|
||||||
<context>
|
<context>
|
||||||
<name>Menu</name>
|
<name>Menu</name>
|
||||||
<message>
|
<message>
|
||||||
<location filename="src/Menu.cpp" line="449"/>
|
<location filename="src/Menu.cpp" line="455"/>
|
||||||
<source>Open .ini config file</source>
|
<source>Open .ini config file</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="src/Menu.cpp" line="451"/>
|
<location filename="src/Menu.cpp" line="457"/>
|
||||||
<location filename="src/Menu.cpp" line="463"/>
|
<location filename="src/Menu.cpp" line="469"/>
|
||||||
<source>Text files (*.ini)</source>
|
<source>Text files (*.ini)</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="src/Menu.cpp" line="461"/>
|
<location filename="src/Menu.cpp" line="467"/>
|
||||||
<source>Save .ini config file</source>
|
<source>Save .ini config file</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
|
|
|
@ -61,6 +61,7 @@ Menu* Menu::getInstance() {
|
||||||
|
|
||||||
const ViewFrustumOffset DEFAULT_FRUSTUM_OFFSET = {-135.0f, 0.0f, 0.0f, 25.0f, 0.0f};
|
const ViewFrustumOffset DEFAULT_FRUSTUM_OFFSET = {-135.0f, 0.0f, 0.0f, 25.0f, 0.0f};
|
||||||
const float DEFAULT_FACESHIFT_EYE_DEFLECTION = 0.25f;
|
const float DEFAULT_FACESHIFT_EYE_DEFLECTION = 0.25f;
|
||||||
|
const float DEFAULT_AVATAR_LOD_DISTANCE_MULTIPLIER = 1.0f;
|
||||||
const int FIVE_SECONDS_OF_FRAMES = 5 * 60;
|
const int FIVE_SECONDS_OF_FRAMES = 5 * 60;
|
||||||
|
|
||||||
Menu::Menu() :
|
Menu::Menu() :
|
||||||
|
@ -75,9 +76,11 @@ Menu::Menu() :
|
||||||
_lodToolsDialog(NULL),
|
_lodToolsDialog(NULL),
|
||||||
_maxVoxels(DEFAULT_MAX_VOXELS_PER_SYSTEM),
|
_maxVoxels(DEFAULT_MAX_VOXELS_PER_SYSTEM),
|
||||||
_voxelSizeScale(DEFAULT_OCTREE_SIZE_SCALE),
|
_voxelSizeScale(DEFAULT_OCTREE_SIZE_SCALE),
|
||||||
|
_avatarLODDistanceMultiplier(DEFAULT_AVATAR_LOD_DISTANCE_MULTIPLIER),
|
||||||
_boundaryLevelAdjust(0),
|
_boundaryLevelAdjust(0),
|
||||||
_maxVoxelPacketsPerSecond(DEFAULT_MAX_VOXEL_PPS),
|
_maxVoxelPacketsPerSecond(DEFAULT_MAX_VOXEL_PPS),
|
||||||
_lastAdjust(usecTimestampNow()),
|
_lastAdjust(usecTimestampNow()),
|
||||||
|
_lastAvatarDetailDrop(usecTimestampNow()),
|
||||||
_fpsAverage(FIVE_SECONDS_OF_FRAMES),
|
_fpsAverage(FIVE_SECONDS_OF_FRAMES),
|
||||||
_loginAction(NULL)
|
_loginAction(NULL)
|
||||||
{
|
{
|
||||||
|
@ -386,6 +389,8 @@ void Menu::loadSettings(QSettings* settings) {
|
||||||
_maxVoxels = loadSetting(settings, "maxVoxels", DEFAULT_MAX_VOXELS_PER_SYSTEM);
|
_maxVoxels = loadSetting(settings, "maxVoxels", DEFAULT_MAX_VOXELS_PER_SYSTEM);
|
||||||
_maxVoxelPacketsPerSecond = loadSetting(settings, "maxVoxelsPPS", DEFAULT_MAX_VOXEL_PPS);
|
_maxVoxelPacketsPerSecond = loadSetting(settings, "maxVoxelsPPS", DEFAULT_MAX_VOXEL_PPS);
|
||||||
_voxelSizeScale = loadSetting(settings, "voxelSizeScale", DEFAULT_OCTREE_SIZE_SCALE);
|
_voxelSizeScale = loadSetting(settings, "voxelSizeScale", DEFAULT_OCTREE_SIZE_SCALE);
|
||||||
|
_avatarLODDistanceMultiplier = loadSetting(settings, "avatarLODDistanceMultiplier",
|
||||||
|
DEFAULT_AVATAR_LOD_DISTANCE_MULTIPLIER);
|
||||||
_boundaryLevelAdjust = loadSetting(settings, "boundaryLevelAdjust", 0);
|
_boundaryLevelAdjust = loadSetting(settings, "boundaryLevelAdjust", 0);
|
||||||
|
|
||||||
settings->beginGroup("View Frustum Offset Camera");
|
settings->beginGroup("View Frustum Offset Camera");
|
||||||
|
@ -425,6 +430,7 @@ void Menu::saveSettings(QSettings* settings) {
|
||||||
settings->setValue("maxVoxels", _maxVoxels);
|
settings->setValue("maxVoxels", _maxVoxels);
|
||||||
settings->setValue("maxVoxelsPPS", _maxVoxelPacketsPerSecond);
|
settings->setValue("maxVoxelsPPS", _maxVoxelPacketsPerSecond);
|
||||||
settings->setValue("voxelSizeScale", _voxelSizeScale);
|
settings->setValue("voxelSizeScale", _voxelSizeScale);
|
||||||
|
settings->setValue("avatarLODDistanceMultiplier", _avatarLODDistanceMultiplier);
|
||||||
settings->setValue("boundaryLevelAdjust", _boundaryLevelAdjust);
|
settings->setValue("boundaryLevelAdjust", _boundaryLevelAdjust);
|
||||||
settings->beginGroup("View Frustum Offset Camera");
|
settings->beginGroup("View Frustum Offset Camera");
|
||||||
settings->setValue("viewFrustumOffsetYaw", _viewFrustumOffset.yaw);
|
settings->setValue("viewFrustumOffsetYaw", _viewFrustumOffset.yaw);
|
||||||
|
@ -1185,8 +1191,24 @@ void Menu::autoAdjustLOD(float currentFPS) {
|
||||||
}
|
}
|
||||||
_fpsAverage.updateAverage(currentFPS);
|
_fpsAverage.updateAverage(currentFPS);
|
||||||
|
|
||||||
bool changed = false;
|
|
||||||
quint64 now = usecTimestampNow();
|
quint64 now = usecTimestampNow();
|
||||||
|
|
||||||
|
if (_fpsAverage.getAverage() < ADJUST_LOD_DOWN_FPS) {
|
||||||
|
if (now - _lastAvatarDetailDrop > ADJUST_LOD_DOWN_DELAY) {
|
||||||
|
// attempt to lower the detail in proportion to the fps difference
|
||||||
|
float targetFps = (ADJUST_LOD_DOWN_FPS + ADJUST_LOD_UP_FPS) * 0.5f;
|
||||||
|
_avatarLODDistanceMultiplier *= (targetFps / _fpsAverage.getAverage());
|
||||||
|
_lastAvatarDetailDrop = now;
|
||||||
|
}
|
||||||
|
} else if (_fpsAverage.getAverage() > ADJUST_LOD_UP_FPS) {
|
||||||
|
// let the detail level creep slowly upwards
|
||||||
|
const float DISTANCE_DECREASE_RATE = 0.01f;
|
||||||
|
const float MINIMUM_DISTANCE_MULTIPLIER = 0.1f;
|
||||||
|
_avatarLODDistanceMultiplier = qMax(MINIMUM_DISTANCE_MULTIPLIER,
|
||||||
|
_avatarLODDistanceMultiplier - DISTANCE_DECREASE_RATE);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool changed = false;
|
||||||
quint64 elapsed = now - _lastAdjust;
|
quint64 elapsed = now - _lastAdjust;
|
||||||
|
|
||||||
if (elapsed > ADJUST_LOD_DOWN_DELAY && _fpsAverage.getAverage() < ADJUST_LOD_DOWN_FPS
|
if (elapsed > ADJUST_LOD_DOWN_DELAY && _fpsAverage.getAverage() < ADJUST_LOD_DOWN_FPS
|
||||||
|
|
|
@ -89,7 +89,7 @@ public:
|
||||||
void autoAdjustLOD(float currentFPS);
|
void autoAdjustLOD(float currentFPS);
|
||||||
void setVoxelSizeScale(float sizeScale);
|
void setVoxelSizeScale(float sizeScale);
|
||||||
float getVoxelSizeScale() const { return _voxelSizeScale; }
|
float getVoxelSizeScale() const { return _voxelSizeScale; }
|
||||||
float getAvatarLODDistanceMultiplier() const { return DEFAULT_OCTREE_SIZE_SCALE / _voxelSizeScale; }
|
float getAvatarLODDistanceMultiplier() const { return _avatarLODDistanceMultiplier; }
|
||||||
void setBoundaryLevelAdjust(int boundaryLevelAdjust);
|
void setBoundaryLevelAdjust(int boundaryLevelAdjust);
|
||||||
int getBoundaryLevelAdjust() const { return _boundaryLevelAdjust; }
|
int getBoundaryLevelAdjust() const { return _boundaryLevelAdjust; }
|
||||||
|
|
||||||
|
@ -202,12 +202,14 @@ private:
|
||||||
LodToolsDialog* _lodToolsDialog;
|
LodToolsDialog* _lodToolsDialog;
|
||||||
int _maxVoxels;
|
int _maxVoxels;
|
||||||
float _voxelSizeScale;
|
float _voxelSizeScale;
|
||||||
|
float _avatarLODDistanceMultiplier;
|
||||||
int _boundaryLevelAdjust;
|
int _boundaryLevelAdjust;
|
||||||
QAction* _useVoxelShader;
|
QAction* _useVoxelShader;
|
||||||
int _maxVoxelPacketsPerSecond;
|
int _maxVoxelPacketsPerSecond;
|
||||||
QMenu* _activeScriptsMenu;
|
QMenu* _activeScriptsMenu;
|
||||||
QString replaceLastOccurrence(QChar search, QChar replace, QString string);
|
QString replaceLastOccurrence(QChar search, QChar replace, QString string);
|
||||||
quint64 _lastAdjust;
|
quint64 _lastAdjust;
|
||||||
|
quint64 _lastAvatarDetailDrop;
|
||||||
SimpleMovingAverage _fpsAverage;
|
SimpleMovingAverage _fpsAverage;
|
||||||
QAction* _loginAction;
|
QAction* _loginAction;
|
||||||
QAction* _chatAction;
|
QAction* _chatAction;
|
||||||
|
|
|
@ -14,6 +14,7 @@
|
||||||
#include <glm/glm.hpp>
|
#include <glm/glm.hpp>
|
||||||
#include <glm/gtc/noise.hpp>
|
#include <glm/gtc/noise.hpp>
|
||||||
#include <glm/gtx/quaternion.hpp>
|
#include <glm/gtx/quaternion.hpp>
|
||||||
|
#include <glm/detail/func_common.hpp>
|
||||||
|
|
||||||
#include <SharedUtil.h>
|
#include <SharedUtil.h>
|
||||||
|
|
||||||
|
@ -24,12 +25,6 @@
|
||||||
|
|
||||||
#include "Util.h"
|
#include "Util.h"
|
||||||
|
|
||||||
#ifdef _WIN32
|
|
||||||
int isnan(double value) { return _isnan(value); }
|
|
||||||
#else
|
|
||||||
int isnan(double value) { return std::isnan(value); }
|
|
||||||
#endif
|
|
||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
|
||||||
// no clue which versions are affected...
|
// no clue which versions are affected...
|
||||||
|
@ -88,7 +83,7 @@ float angleBetween(const glm::vec3& v1, const glm::vec3& v2) {
|
||||||
// Helper function return the rotation from the first vector onto the second
|
// Helper function return the rotation from the first vector onto the second
|
||||||
glm::quat rotationBetween(const glm::vec3& v1, const glm::vec3& v2) {
|
glm::quat rotationBetween(const glm::vec3& v1, const glm::vec3& v2) {
|
||||||
float angle = angleBetween(v1, v2);
|
float angle = angleBetween(v1, v2);
|
||||||
if (isnan(angle) || angle < EPSILON) {
|
if (glm::isnan(angle) || angle < EPSILON) {
|
||||||
return glm::quat();
|
return glm::quat();
|
||||||
}
|
}
|
||||||
glm::vec3 axis;
|
glm::vec3 axis;
|
||||||
|
@ -586,7 +581,7 @@ void runTimingTests() {
|
||||||
|
|
||||||
float loadSetting(QSettings* settings, const char* name, float defaultValue) {
|
float loadSetting(QSettings* settings, const char* name, float defaultValue) {
|
||||||
float value = settings->value(name, defaultValue).toFloat();
|
float value = settings->value(name, defaultValue).toFloat();
|
||||||
if (isnan(value)) {
|
if (glm::isnan(value)) {
|
||||||
value = defaultValue;
|
value = defaultValue;
|
||||||
}
|
}
|
||||||
return value;
|
return value;
|
||||||
|
|
|
@ -8,6 +8,7 @@
|
||||||
|
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
|
|
||||||
|
#include <glm/detail/func_common.hpp>
|
||||||
#include <QtCore/QDataStream>
|
#include <QtCore/QDataStream>
|
||||||
|
|
||||||
#include <Node.h>
|
#include <Node.h>
|
||||||
|
@ -16,12 +17,6 @@
|
||||||
|
|
||||||
#include "PositionalAudioRingBuffer.h"
|
#include "PositionalAudioRingBuffer.h"
|
||||||
|
|
||||||
#ifdef _WIN32
|
|
||||||
int isnan(double value) { return _isnan(value); }
|
|
||||||
#else
|
|
||||||
int isnan(double value) { return std::isnan(value); }
|
|
||||||
#endif
|
|
||||||
|
|
||||||
PositionalAudioRingBuffer::PositionalAudioRingBuffer(PositionalAudioRingBuffer::Type type) :
|
PositionalAudioRingBuffer::PositionalAudioRingBuffer(PositionalAudioRingBuffer::Type type) :
|
||||||
AudioRingBuffer(NETWORK_BUFFER_LENGTH_SAMPLES_PER_CHANNEL),
|
AudioRingBuffer(NETWORK_BUFFER_LENGTH_SAMPLES_PER_CHANNEL),
|
||||||
_type(type),
|
_type(type),
|
||||||
|
@ -69,7 +64,7 @@ int PositionalAudioRingBuffer::parsePositionalData(const QByteArray& positionalB
|
||||||
packetStream.readRawData(reinterpret_cast<char*>(&_orientation), sizeof(_orientation));
|
packetStream.readRawData(reinterpret_cast<char*>(&_orientation), sizeof(_orientation));
|
||||||
|
|
||||||
// if this node sent us a NaN for first float in orientation then don't consider this good audio and bail
|
// if this node sent us a NaN for first float in orientation then don't consider this good audio and bail
|
||||||
if (isnan(_orientation.x)) {
|
if (glm::isnan(_orientation.x)) {
|
||||||
reset();
|
reset();
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,7 +25,7 @@
|
||||||
|
|
||||||
#include "AvatarData.h"
|
#include "AvatarData.h"
|
||||||
|
|
||||||
quint64 DEFAULT_FILTERED_LOG_EXPIRY = 20 * USECS_PER_SECOND;
|
quint64 DEFAULT_FILTERED_LOG_EXPIRY = 2 * USECS_PER_SECOND;
|
||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
|
||||||
|
@ -46,7 +46,7 @@ AvatarData::AvatarData() :
|
||||||
_displayNameTargetAlpha(0.0f),
|
_displayNameTargetAlpha(0.0f),
|
||||||
_displayNameAlpha(0.0f),
|
_displayNameAlpha(0.0f),
|
||||||
_billboard(),
|
_billboard(),
|
||||||
_debugLogExpiry(0)
|
_errorLogExpiry(0)
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -178,6 +178,14 @@ QByteArray AvatarData::toByteArray() {
|
||||||
return avatarDataByteArray.left(destinationBuffer - startPosition);
|
return avatarDataByteArray.left(destinationBuffer - startPosition);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool AvatarData::shouldLogError(const quint64& now) {
|
||||||
|
if (now > _errorLogExpiry) {
|
||||||
|
_errorLogExpiry = now + DEFAULT_FILTERED_LOG_EXPIRY;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
// 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::parseDataAtOffset(const QByteArray& packet, int offset) {
|
int AvatarData::parseDataAtOffset(const QByteArray& packet, int offset) {
|
||||||
// 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
|
||||||
|
@ -192,37 +200,80 @@ int AvatarData::parseDataAtOffset(const QByteArray& packet, int offset) {
|
||||||
|
|
||||||
const unsigned char* startPosition = reinterpret_cast<const unsigned char*>(packet.data()) + offset;
|
const unsigned char* startPosition = reinterpret_cast<const unsigned char*>(packet.data()) + offset;
|
||||||
const unsigned char* sourceBuffer = startPosition;
|
const unsigned char* sourceBuffer = startPosition;
|
||||||
|
quint64 now = usecTimestampNow();
|
||||||
|
|
||||||
// 50 bytes of "plain old data" (POD)
|
// The absolute minimum size of the update data is as follows:
|
||||||
// 1 byte for messageSize (0)
|
// 50 bytes of "plain old data" {
|
||||||
// 1 byte for pupilSize
|
// position = 12 bytes
|
||||||
// 1 byte for numJoints (0)
|
// bodyYaw = 2 (compressed float)
|
||||||
|
// bodyPitch = 2 (compressed float)
|
||||||
|
// bodyRoll = 2 (compressed float)
|
||||||
|
// targetScale = 2 (compressed float)
|
||||||
|
// headYaw = 2 (compressed float)
|
||||||
|
// headPitch = 2 (compressed float)
|
||||||
|
// headRoll = 2 (compressed float)
|
||||||
|
// leanSideways = 4
|
||||||
|
// leanForward = 4
|
||||||
|
// lookAt = 12
|
||||||
|
// audioLoudness = 4
|
||||||
|
// }
|
||||||
|
// + 1 byte for messageSize (0)
|
||||||
|
// + 1 byte for pupilSize
|
||||||
|
// + 1 byte for numJoints (0)
|
||||||
|
// = 53 bytes
|
||||||
int minPossibleSize = 53;
|
int minPossibleSize = 53;
|
||||||
|
|
||||||
int maxAvailableSize = packet.size() - offset;
|
int maxAvailableSize = packet.size() - offset;
|
||||||
if (minPossibleSize > maxAvailableSize) {
|
if (minPossibleSize > maxAvailableSize) {
|
||||||
// this packet is malformed so we pretend to read to the end
|
if (shouldLogError(now)) {
|
||||||
quint64 now = usecTimestampNow();
|
qDebug() << "Malformed AvatarData packet at the start; "
|
||||||
if (now > _debugLogExpiry) {
|
<< " displayName = '" << _displayName << "'"
|
||||||
qDebug() << "Malformed AvatarData packet at the start: minPossibleSize = " << minPossibleSize
|
<< " minPossibleSize = " << minPossibleSize
|
||||||
<< " but maxAvailableSize = " << maxAvailableSize;
|
<< " maxAvailableSize = " << maxAvailableSize;
|
||||||
_debugLogExpiry = now + DEFAULT_FILTERED_LOG_EXPIRY;
|
|
||||||
}
|
}
|
||||||
|
// this packet is malformed so we report all bytes as consumed
|
||||||
return maxAvailableSize;
|
return maxAvailableSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
{ // Body world position, rotation, and scale
|
{ // Body world position, rotation, and scale
|
||||||
// position
|
// position
|
||||||
memcpy(&_position, sourceBuffer, sizeof(float) * 3);
|
glm::vec3 position;
|
||||||
sourceBuffer += sizeof(float) * 3;
|
memcpy(&position, sourceBuffer, sizeof(position));
|
||||||
|
sourceBuffer += sizeof(position);
|
||||||
|
|
||||||
|
if (glm::isnan(position.x) || glm::isnan(position.y) || glm::isnan(position.z)) {
|
||||||
|
if (shouldLogError(now)) {
|
||||||
|
qDebug() << "Discard nan AvatarData::position; displayName = '" << _displayName << "'";
|
||||||
|
}
|
||||||
|
return maxAvailableSize;
|
||||||
|
}
|
||||||
|
_position = position;
|
||||||
|
|
||||||
// rotation (NOTE: This needs to become a quaternion to save two bytes)
|
// rotation (NOTE: This needs to become a quaternion to save two bytes)
|
||||||
sourceBuffer += unpackFloatAngleFromTwoByte((uint16_t*) sourceBuffer, &_bodyYaw);
|
float yaw, pitch, roll;
|
||||||
sourceBuffer += unpackFloatAngleFromTwoByte((uint16_t*) sourceBuffer, &_bodyPitch);
|
sourceBuffer += unpackFloatAngleFromTwoByte((uint16_t*) sourceBuffer, &yaw);
|
||||||
sourceBuffer += unpackFloatAngleFromTwoByte((uint16_t*) sourceBuffer, &_bodyRoll);
|
sourceBuffer += unpackFloatAngleFromTwoByte((uint16_t*) sourceBuffer, &pitch);
|
||||||
|
sourceBuffer += unpackFloatAngleFromTwoByte((uint16_t*) sourceBuffer, &roll);
|
||||||
|
if (glm::isnan(yaw) || glm::isnan(pitch) || glm::isnan(roll)) {
|
||||||
|
if (shouldLogError(now)) {
|
||||||
|
qDebug() << "Discard nan AvatarData::yaw,pitch,roll; displayName = '" << _displayName << "'";
|
||||||
|
}
|
||||||
|
return maxAvailableSize;
|
||||||
|
}
|
||||||
|
_bodyYaw = yaw;
|
||||||
|
_bodyPitch = pitch;
|
||||||
|
_bodyRoll = roll;
|
||||||
|
|
||||||
// scale
|
// scale
|
||||||
sourceBuffer += unpackFloatRatioFromTwoByte(sourceBuffer, _targetScale);
|
float scale;
|
||||||
|
sourceBuffer += unpackFloatRatioFromTwoByte(sourceBuffer, scale);
|
||||||
|
if (glm::isnan(scale)) {
|
||||||
|
if (shouldLogError(now)) {
|
||||||
|
qDebug() << "Discard nan AvatarData::scale; displayName = '" << _displayName << "'";
|
||||||
|
}
|
||||||
|
return maxAvailableSize;
|
||||||
|
}
|
||||||
|
_targetScale = scale;
|
||||||
} // 20 bytes
|
} // 20 bytes
|
||||||
|
|
||||||
{ // Head rotation
|
{ // Head rotation
|
||||||
|
@ -231,6 +282,12 @@ int AvatarData::parseDataAtOffset(const QByteArray& packet, int offset) {
|
||||||
sourceBuffer += unpackFloatAngleFromTwoByte((uint16_t*) sourceBuffer, &headYaw);
|
sourceBuffer += unpackFloatAngleFromTwoByte((uint16_t*) sourceBuffer, &headYaw);
|
||||||
sourceBuffer += unpackFloatAngleFromTwoByte((uint16_t*) sourceBuffer, &headPitch);
|
sourceBuffer += unpackFloatAngleFromTwoByte((uint16_t*) sourceBuffer, &headPitch);
|
||||||
sourceBuffer += unpackFloatAngleFromTwoByte((uint16_t*) sourceBuffer, &headRoll);
|
sourceBuffer += unpackFloatAngleFromTwoByte((uint16_t*) sourceBuffer, &headRoll);
|
||||||
|
if (glm::isnan(headYaw) || glm::isnan(headPitch) || glm::isnan(headRoll)) {
|
||||||
|
if (shouldLogError(now)) {
|
||||||
|
qDebug() << "Discard nan AvatarData::headYaw,headPitch,headRoll; displayName = '" << _displayName << "'";
|
||||||
|
}
|
||||||
|
return maxAvailableSize;
|
||||||
|
}
|
||||||
_headData->setYaw(headYaw);
|
_headData->setYaw(headYaw);
|
||||||
_headData->setPitch(headPitch);
|
_headData->setPitch(headPitch);
|
||||||
_headData->setRoll(headRoll);
|
_headData->setRoll(headRoll);
|
||||||
|
@ -238,33 +295,57 @@ int AvatarData::parseDataAtOffset(const QByteArray& packet, int offset) {
|
||||||
|
|
||||||
// Head lean (relative to pelvis)
|
// Head lean (relative to pelvis)
|
||||||
{
|
{
|
||||||
memcpy(&_headData->_leanSideways, sourceBuffer, sizeof(_headData->_leanSideways));
|
float leanSideways, leanForward;
|
||||||
|
memcpy(&leanSideways, sourceBuffer, sizeof(float));
|
||||||
sourceBuffer += sizeof(float);
|
sourceBuffer += sizeof(float);
|
||||||
memcpy(&_headData->_leanForward, sourceBuffer, sizeof(_headData->_leanForward));
|
memcpy(&leanForward, sourceBuffer, sizeof(float));
|
||||||
sourceBuffer += sizeof(float);
|
sourceBuffer += sizeof(float);
|
||||||
|
if (glm::isnan(leanSideways) || glm::isnan(leanForward)) {
|
||||||
|
if (shouldLogError(now)) {
|
||||||
|
qDebug() << "Discard nan AvatarData::leanSideways,leanForward; displayName = '" << _displayName << "'";
|
||||||
|
}
|
||||||
|
return maxAvailableSize;
|
||||||
|
}
|
||||||
|
_headData->_leanSideways = leanSideways;
|
||||||
|
_headData->_leanForward = leanForward;
|
||||||
} // 8 bytes
|
} // 8 bytes
|
||||||
|
|
||||||
{ // Lookat Position
|
{ // Lookat Position
|
||||||
memcpy(&_headData->_lookAtPosition, sourceBuffer, sizeof(_headData->_lookAtPosition));
|
glm::vec3 lookAt;
|
||||||
sourceBuffer += sizeof(_headData->_lookAtPosition);
|
memcpy(&lookAt, sourceBuffer, sizeof(lookAt));
|
||||||
|
sourceBuffer += sizeof(lookAt);
|
||||||
|
if (glm::isnan(lookAt.x) || glm::isnan(lookAt.y) || glm::isnan(lookAt.z)) {
|
||||||
|
if (shouldLogError(now)) {
|
||||||
|
qDebug() << "Discard nan AvatarData::lookAt; displayName = '" << _displayName << "'";
|
||||||
|
}
|
||||||
|
return maxAvailableSize;
|
||||||
|
}
|
||||||
|
_headData->_lookAtPosition = lookAt;
|
||||||
} // 12 bytes
|
} // 12 bytes
|
||||||
|
|
||||||
{ // AudioLoudness
|
{ // AudioLoudness
|
||||||
// Instantaneous audio loudness (used to drive facial animation)
|
// Instantaneous audio loudness (used to drive facial animation)
|
||||||
memcpy(&_headData->_audioLoudness, sourceBuffer, sizeof(float));
|
float audioLoudness;
|
||||||
|
memcpy(&audioLoudness, sourceBuffer, sizeof(float));
|
||||||
sourceBuffer += sizeof(float);
|
sourceBuffer += sizeof(float);
|
||||||
|
if (glm::isnan(audioLoudness)) {
|
||||||
|
if (shouldLogError(now)) {
|
||||||
|
qDebug() << "Discard nan AvatarData::audioLoudness; displayName = '" << _displayName << "'";
|
||||||
|
}
|
||||||
|
return maxAvailableSize;
|
||||||
|
}
|
||||||
|
_headData->_audioLoudness = audioLoudness;
|
||||||
} // 4 bytes
|
} // 4 bytes
|
||||||
|
|
||||||
// chat
|
// chat
|
||||||
int chatMessageSize = *sourceBuffer++;
|
int chatMessageSize = *sourceBuffer++;
|
||||||
minPossibleSize += chatMessageSize;
|
minPossibleSize += chatMessageSize;
|
||||||
if (minPossibleSize > maxAvailableSize) {
|
if (minPossibleSize > maxAvailableSize) {
|
||||||
// this packet is malformed so we pretend to read to the end
|
if (shouldLogError(now)) {
|
||||||
quint64 now = usecTimestampNow();
|
qDebug() << "Malformed AvatarData packet before ChatMessage;"
|
||||||
if (now > _debugLogExpiry) {
|
<< " displayName = '" << _displayName << "'"
|
||||||
qDebug() << "Malformed AvatarData packet before ChatMessage: minPossibleSize = " << minPossibleSize
|
<< " minPossibleSize = " << minPossibleSize
|
||||||
<< " but maxAvailableSize = " << maxAvailableSize;
|
<< " maxAvailableSize = " << maxAvailableSize;
|
||||||
_debugLogExpiry = now + DEFAULT_FILTERED_LOG_EXPIRY;
|
|
||||||
}
|
}
|
||||||
return maxAvailableSize;
|
return maxAvailableSize;
|
||||||
}
|
}
|
||||||
|
@ -287,40 +368,52 @@ int AvatarData::parseDataAtOffset(const QByteArray& packet, int offset) {
|
||||||
_isChatCirclingEnabled = oneAtBit(bitItems, IS_CHAT_CIRCLING_ENABLED);
|
_isChatCirclingEnabled = oneAtBit(bitItems, IS_CHAT_CIRCLING_ENABLED);
|
||||||
|
|
||||||
if (_headData->_isFaceshiftConnected) {
|
if (_headData->_isFaceshiftConnected) {
|
||||||
minPossibleSize += 4 * sizeof(float) + 1; // four floats + one byte for blendDataSize
|
float leftEyeBlink, rightEyeBlink, averageLoudness, browAudioLift;
|
||||||
|
minPossibleSize += sizeof(leftEyeBlink) + sizeof(rightEyeBlink) + sizeof(averageLoudness) + sizeof(browAudioLift);
|
||||||
|
minPossibleSize++; // one byte for blendDataSize
|
||||||
if (minPossibleSize > maxAvailableSize) {
|
if (minPossibleSize > maxAvailableSize) {
|
||||||
// this packet is malformed so we pretend to read to the end
|
if (shouldLogError(now)) {
|
||||||
quint64 now = usecTimestampNow();
|
qDebug() << "Malformed AvatarData packet after BitItems;"
|
||||||
if (now > _debugLogExpiry) {
|
<< " displayName = '" << _displayName << "'"
|
||||||
qDebug() << "Malformed AvatarData packet after BitItems: minPossibleSize = " << minPossibleSize
|
<< " minPossibleSize = " << minPossibleSize
|
||||||
<< " but maxAvailableSize = " << maxAvailableSize;
|
<< " maxAvailableSize = " << maxAvailableSize;
|
||||||
_debugLogExpiry = now + DEFAULT_FILTERED_LOG_EXPIRY;
|
|
||||||
}
|
}
|
||||||
return maxAvailableSize;
|
return maxAvailableSize;
|
||||||
}
|
}
|
||||||
// unpack face data
|
// unpack face data
|
||||||
memcpy(&_headData->_leftEyeBlink, sourceBuffer, sizeof(float));
|
memcpy(&leftEyeBlink, sourceBuffer, sizeof(float));
|
||||||
sourceBuffer += sizeof(float);
|
sourceBuffer += sizeof(float);
|
||||||
|
|
||||||
memcpy(&_headData->_rightEyeBlink, sourceBuffer, sizeof(float));
|
memcpy(&rightEyeBlink, sourceBuffer, sizeof(float));
|
||||||
sourceBuffer += sizeof(float);
|
sourceBuffer += sizeof(float);
|
||||||
|
|
||||||
memcpy(&_headData->_averageLoudness, sourceBuffer, sizeof(float));
|
memcpy(&averageLoudness, sourceBuffer, sizeof(float));
|
||||||
sourceBuffer += sizeof(float);
|
sourceBuffer += sizeof(float);
|
||||||
|
|
||||||
memcpy(&_headData->_browAudioLift, sourceBuffer, sizeof(float));
|
memcpy(&browAudioLift, sourceBuffer, sizeof(float));
|
||||||
sourceBuffer += sizeof(float);
|
sourceBuffer += sizeof(float);
|
||||||
|
|
||||||
|
if (glm::isnan(leftEyeBlink) || glm::isnan(rightEyeBlink)
|
||||||
|
|| glm::isnan(averageLoudness) || glm::isnan(browAudioLift)) {
|
||||||
|
if (shouldLogError(now)) {
|
||||||
|
qDebug() << "Discard nan AvatarData::faceData; displayName = '" << _displayName << "'";
|
||||||
|
}
|
||||||
|
return maxAvailableSize;
|
||||||
|
}
|
||||||
|
_headData->_leftEyeBlink = leftEyeBlink;
|
||||||
|
_headData->_rightEyeBlink = rightEyeBlink;
|
||||||
|
_headData->_averageLoudness = averageLoudness;
|
||||||
|
_headData->_browAudioLift = browAudioLift;
|
||||||
|
|
||||||
int numCoefficients = (int)(*sourceBuffer++);
|
int numCoefficients = (int)(*sourceBuffer++);
|
||||||
int blendDataSize = numCoefficients * sizeof(float);
|
int blendDataSize = numCoefficients * sizeof(float);
|
||||||
minPossibleSize += blendDataSize;
|
minPossibleSize += blendDataSize;
|
||||||
if (minPossibleSize > maxAvailableSize) {
|
if (minPossibleSize > maxAvailableSize) {
|
||||||
// this packet is malformed so we pretend to read to the end
|
if (shouldLogError(now)) {
|
||||||
quint64 now = usecTimestampNow();
|
qDebug() << "Malformed AvatarData packet after Blendshapes;"
|
||||||
if (now > _debugLogExpiry) {
|
<< " displayName = '" << _displayName << "'"
|
||||||
qDebug() << "Malformed AvatarData packet after Blendshapes: minPossibleSize = " << minPossibleSize
|
<< " minPossibleSize = " << minPossibleSize
|
||||||
<< " but maxAvailableSize = " << maxAvailableSize;
|
<< " maxAvailableSize = " << maxAvailableSize;
|
||||||
_debugLogExpiry = now + DEFAULT_FILTERED_LOG_EXPIRY;
|
|
||||||
}
|
}
|
||||||
return maxAvailableSize;
|
return maxAvailableSize;
|
||||||
}
|
}
|
||||||
|
@ -339,15 +432,14 @@ int AvatarData::parseDataAtOffset(const QByteArray& packet, int offset) {
|
||||||
|
|
||||||
// joint data
|
// joint data
|
||||||
int numJoints = *sourceBuffer++;
|
int numJoints = *sourceBuffer++;
|
||||||
int bytesOfValidity = (int)ceil((float)numJoints / 8.f);
|
int bytesOfValidity = (int)ceil((float)numJoints / (float)BITS_IN_BYTE);
|
||||||
minPossibleSize += bytesOfValidity;
|
minPossibleSize += bytesOfValidity;
|
||||||
if (minPossibleSize > maxAvailableSize) {
|
if (minPossibleSize > maxAvailableSize) {
|
||||||
// this packet is malformed so we pretend to read to the end
|
if (shouldLogError(now)) {
|
||||||
quint64 now = usecTimestampNow();
|
qDebug() << "Malformed AvatarData packet after JointValidityBits;"
|
||||||
if (now > _debugLogExpiry) {
|
<< " displayName = '" << _displayName << "'"
|
||||||
qDebug() << "Malformed AvatarData packet after JointValidityBits: minPossibleSize = " << minPossibleSize
|
<< " minPossibleSize = " << minPossibleSize
|
||||||
<< " but maxAvailableSize = " << maxAvailableSize;
|
<< " maxAvailableSize = " << maxAvailableSize;
|
||||||
_debugLogExpiry = now + DEFAULT_FILTERED_LOG_EXPIRY;
|
|
||||||
}
|
}
|
||||||
return maxAvailableSize;
|
return maxAvailableSize;
|
||||||
}
|
}
|
||||||
|
@ -370,14 +462,15 @@ int AvatarData::parseDataAtOffset(const QByteArray& packet, int offset) {
|
||||||
}
|
}
|
||||||
// 1 + bytesOfValidity bytes
|
// 1 + bytesOfValidity bytes
|
||||||
|
|
||||||
minPossibleSize += numValidJoints * 8; // 8 bytes per quaternion
|
// each joint rotation component is stored in two bytes (sizeof(uint16_t))
|
||||||
|
int COMPONENTS_PER_QUATERNION = 4;
|
||||||
|
minPossibleSize += numValidJoints * COMPONENTS_PER_QUATERNION * sizeof(uint16_t);
|
||||||
if (minPossibleSize > maxAvailableSize) {
|
if (minPossibleSize > maxAvailableSize) {
|
||||||
// this packet is malformed so we pretend to read to the end
|
if (shouldLogError(now)) {
|
||||||
quint64 now = usecTimestampNow();
|
qDebug() << "Malformed AvatarData packet after JointData;"
|
||||||
if (now > _debugLogExpiry) {
|
<< " displayName = '" << _displayName << "'"
|
||||||
qDebug() << "Malformed AvatarData packet after JointData: minPossibleSize = " << minPossibleSize
|
<< " minPossibleSize = " << minPossibleSize
|
||||||
<< " but maxAvailableSize = " << maxAvailableSize;
|
<< " maxAvailableSize = " << maxAvailableSize;
|
||||||
_debugLogExpiry = now + DEFAULT_FILTERED_LOG_EXPIRY;
|
|
||||||
}
|
}
|
||||||
return maxAvailableSize;
|
return maxAvailableSize;
|
||||||
}
|
}
|
||||||
|
|
|
@ -105,6 +105,9 @@ public:
|
||||||
|
|
||||||
QByteArray toByteArray();
|
QByteArray toByteArray();
|
||||||
|
|
||||||
|
/// \return true if an error should be logged
|
||||||
|
bool shouldLogError(const quint64& now);
|
||||||
|
|
||||||
/// \param packet byte array of data
|
/// \param packet byte array of data
|
||||||
/// \param offset number of bytes into packet where data starts
|
/// \param offset number of bytes into packet where data starts
|
||||||
/// \return number of bytes parsed
|
/// \return number of bytes parsed
|
||||||
|
@ -255,7 +258,7 @@ protected:
|
||||||
|
|
||||||
static QNetworkAccessManager* networkAccessManager;
|
static QNetworkAccessManager* networkAccessManager;
|
||||||
|
|
||||||
quint64 _debugLogExpiry;
|
quint64 _errorLogExpiry; ///< time in future when to log an error
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// privatize the copy constructor and assignment operator so they cannot be called
|
// privatize the copy constructor and assignment operator so they cannot be called
|
||||||
|
|
Loading…
Reference in a new issue