Merge branch 'master' into tablet-ui

This commit is contained in:
Anthony J. Thibault 2017-01-03 09:45:23 -08:00
commit 00980366d6
173 changed files with 5930 additions and 1768 deletions

View file

@ -499,7 +499,8 @@ void Agent::processAgentAvatar() {
if (!_scriptEngine->isFinished() && _isAvatar) {
auto scriptedAvatar = DependencyManager::get<ScriptableAvatar>();
QByteArray avatarByteArray = scriptedAvatar->toByteArray(true, randFloat() < AVATAR_SEND_FULL_UPDATE_RATIO);
QByteArray avatarByteArray = scriptedAvatar->toByteArray((randFloat() < AVATAR_SEND_FULL_UPDATE_RATIO)
? AvatarData::SendAllData : AvatarData::CullSmallData);
scriptedAvatar->doneEncoding(true);
static AvatarDataSequenceNumber sequenceNumber = 0;

View file

@ -16,6 +16,7 @@
#include <QtCore/QCoreApplication>
#include <QtCore/QDateTime>
#include <QtCore/QJsonObject>
#include <QtCore/QRegularExpression>
#include <QtCore/QTimer>
#include <QtCore/QThread>
@ -27,7 +28,6 @@
#include <UUID.h>
#include <TryLocker.h>
#include "AvatarMixerClientData.h"
#include "AvatarMixer.h"
const QString AVATAR_MIXER_LOGGING_NAME = "avatar-mixer";
@ -44,6 +44,7 @@ AvatarMixer::AvatarMixer(ReceivedMessage& message) :
connect(DependencyManager::get<NodeList>().data(), &NodeList::nodeKilled, this, &AvatarMixer::nodeKilled);
auto& packetReceiver = DependencyManager::get<NodeList>()->getPacketReceiver();
packetReceiver.registerListener(PacketType::ViewFrustum, this, "handleViewFrustumPacket");
packetReceiver.registerListener(PacketType::AvatarData, this, "handleAvatarDataPacket");
packetReceiver.registerListener(PacketType::AvatarIdentity, this, "handleAvatarIdentityPacket");
packetReceiver.registerListener(PacketType::KillAvatar, this, "handleKillAvatarPacket");
@ -67,10 +68,26 @@ AvatarMixer::~AvatarMixer() {
// assuming 60 htz update rate.
const float IDENTITY_SEND_PROBABILITY = 1.0f / 187.0f;
void AvatarMixer::sendIdentityPacket(AvatarMixerClientData* nodeData, const SharedNodePointer& destinationNode) {
QByteArray individualData = nodeData->getAvatar().identityByteArray();
auto identityPacket = NLPacket::create(PacketType::AvatarIdentity, individualData.size());
individualData.replace(0, NUM_BYTES_RFC4122_UUID, nodeData->getNodeID().toRfc4122());
identityPacket->write(individualData);
DependencyManager::get<NodeList>()->sendPacket(std::move(identityPacket), *destinationNode);
++_sumIdentityPackets;
}
// NOTE: some additional optimizations to consider.
// 1) use the view frustum to cull those avatars that are out of view. Since avatar data doesn't need to be present
// if the avatar is not in view or in the keyhole.
void AvatarMixer::broadcastAvatarData() {
_broadcastRate.increment();
int idleTime = AVATAR_DATA_SEND_INTERVAL_MSECS;
if (_lastFrameTimestamp.time_since_epoch().count() > 0) {
@ -159,6 +176,7 @@ void AvatarMixer::broadcastAvatarData() {
return;
}
++_sumListeners;
nodeData->resetInViewStats();
AvatarData& avatar = nodeData->getAvatar();
glm::vec3 myPosition = avatar.getClientGlobalPosition();
@ -227,6 +245,27 @@ void AvatarMixer::broadcastAvatarData() {
// setup a PacketList for the avatarPackets
auto avatarPacketList = NLPacketList::create(PacketType::BulkAvatarData);
if (avatar.getSessionDisplayName().isEmpty() && // We haven't set it yet...
nodeData->getReceivedIdentity()) { // ... but we have processed identity (with possible displayName).
QString baseName = avatar.getDisplayName().trimmed();
const QRegularExpression curses{ "fuck|shit|damn|cock|cunt" }; // POC. We may eventually want something much more elaborate (subscription?).
baseName = baseName.replace(curses, "*"); // Replace rather than remove, so that people have a clue that the person's a jerk.
const QRegularExpression trailingDigits{ "\\s*_\\d+$" }; // whitespace "_123"
baseName = baseName.remove(trailingDigits);
if (baseName.isEmpty()) {
baseName = "anonymous";
}
QPair<int, int>& soFar = _sessionDisplayNames[baseName]; // Inserts and answers 0, 0 if not already present, which is what we want.
int& highWater = soFar.first;
nodeData->setBaseDisplayName(baseName);
avatar.setSessionDisplayName((highWater > 0) ? baseName + "_" + QString::number(highWater) : baseName);
highWater++;
soFar.second++; // refcount
nodeData->flagIdentityChange();
sendIdentityPacket(nodeData, node); // Tell new node about its sessionUUID. Others will find out below.
}
// this is an AGENT we have received head data from
// send back a packet with other active node data to this node
nodeList->eachMatchingNode(
@ -295,17 +334,7 @@ void AvatarMixer::broadcastAvatarData() {
|| otherNodeData->getIdentityChangeTimestamp() > _lastFrameTimestamp
|| distribution(generator) < IDENTITY_SEND_PROBABILITY)) {
QByteArray individualData = otherNodeData->getAvatar().identityByteArray();
auto identityPacket = NLPacket::create(PacketType::AvatarIdentity, individualData.size());
individualData.replace(0, NUM_BYTES_RFC4122_UUID, otherNode->getUUID().toRfc4122());
identityPacket->write(individualData);
nodeList->sendPacket(std::move(identityPacket), *node);
++_sumIdentityPackets;
sendIdentityPacket(otherNodeData, node);
}
AvatarData& otherAvatar = otherNodeData->getAvatar();
@ -354,9 +383,22 @@ void AvatarMixer::broadcastAvatarData() {
// start a new segment in the PacketList for this avatar
avatarPacketList->startSegment();
// determine if avatar is in view, to determine how much data to include...
glm::vec3 otherNodeBoxScale = (otherNodeData->getPosition() - otherNodeData->getGlobalBoundingBoxCorner()) * 2.0f;
AABox otherNodeBox(otherNodeData->getGlobalBoundingBoxCorner(), otherNodeBoxScale);
AvatarData::AvatarDataDetail detail;
if (!nodeData->otherAvatarInView(otherNodeBox)) {
detail = AvatarData::MinimumData;
nodeData->incrementAvatarOutOfView();
} else {
detail = distribution(generator) < AVATAR_SEND_FULL_UPDATE_RATIO
? AvatarData::SendAllData : AvatarData::IncludeSmallData;
nodeData->incrementAvatarInView();
}
numAvatarDataBytes += avatarPacketList->write(otherNode->getUUID().toRfc4122());
numAvatarDataBytes +=
avatarPacketList->write(otherAvatar.toByteArray(false, distribution(generator) < AVATAR_SEND_FULL_UPDATE_RATIO));
numAvatarDataBytes += avatarPacketList->write(otherAvatar.toByteArray(detail));
avatarPacketList->endSegment();
});
@ -385,6 +427,9 @@ void AvatarMixer::broadcastAvatarData() {
// We're done encoding this version of the otherAvatars. Update their "lastSent" joint-states so
// that we can notice differences, next time around.
//
// FIXME - this seems suspicious, the code seems to consider all avatars, but not all avatars will
// have had their joints sent, so actually we should consider the time since they actually were sent????
nodeList->eachMatchingNode(
[&](const SharedNodePointer& otherNode)->bool {
if (!otherNode->getLinkedData()) {
@ -409,6 +454,18 @@ void AvatarMixer::broadcastAvatarData() {
});
_lastFrameTimestamp = p_high_resolution_clock::now();
#ifdef WANT_DEBUG
auto sinceLastDebug = p_high_resolution_clock::now() - _lastDebugMessage;
auto sinceLastDebugUsecs = std::chrono::duration_cast<std::chrono::microseconds>(sinceLastDebug).count();
quint64 DEBUG_INTERVAL = USECS_PER_SECOND * 5;
if (sinceLastDebugUsecs > DEBUG_INTERVAL) {
qDebug() << "broadcast rate:" << _broadcastRate.rate() << "hz";
_lastDebugMessage = p_high_resolution_clock::now();
}
#endif
}
void AvatarMixer::nodeKilled(SharedNodePointer killedNode) {
@ -416,6 +473,16 @@ void AvatarMixer::nodeKilled(SharedNodePointer killedNode) {
&& killedNode->getLinkedData()) {
auto nodeList = DependencyManager::get<NodeList>();
{ // decrement sessionDisplayNames table and possibly remove
QMutexLocker nodeDataLocker(&killedNode->getLinkedData()->getMutex());
AvatarMixerClientData* nodeData = dynamic_cast<AvatarMixerClientData*>(killedNode->getLinkedData());
const QString& baseDisplayName = nodeData->getBaseDisplayName();
// No sense guarding against very rare case of a node with no entry, as this will work without the guard and do one less lookup in the common case.
if (--_sessionDisplayNames[baseDisplayName].second <= 0) {
_sessionDisplayNames.remove(baseDisplayName);
}
}
// this was an avatar we were sending to other people
// send a kill packet for it to our other nodes
auto killPacket = NLPacket::create(PacketType::KillAvatar, NUM_BYTES_RFC4122_UUID + sizeof(KillAvatarReason));
@ -448,6 +515,18 @@ void AvatarMixer::nodeKilled(SharedNodePointer killedNode) {
}
}
void AvatarMixer::handleViewFrustumPacket(QSharedPointer<ReceivedMessage> message, SharedNodePointer senderNode) {
auto nodeList = DependencyManager::get<NodeList>();
nodeList->getOrCreateLinkedData(senderNode);
if (senderNode->getLinkedData()) {
AvatarMixerClientData* nodeData = dynamic_cast<AvatarMixerClientData*>(senderNode->getLinkedData());
if (nodeData != nullptr) {
nodeData->readViewFrustumPacket(message->getMessage());
}
}
}
void AvatarMixer::handleAvatarDataPacket(QSharedPointer<ReceivedMessage> message, SharedNodePointer senderNode) {
auto nodeList = DependencyManager::get<NodeList>();
nodeList->updateNodeWithDataFromPacket(message, senderNode);
@ -468,6 +547,7 @@ void AvatarMixer::handleAvatarIdentityPacket(QSharedPointer<ReceivedMessage> mes
if (avatar.processAvatarIdentity(identity)) {
QMutexLocker nodeDataLocker(&nodeData->getMutex());
nodeData->flagIdentityChange();
nodeData->setReceivedIdentity();
}
}
}
@ -493,6 +573,7 @@ void AvatarMixer::sendStatsPacket() {
statsObject["trailing_sleep_percentage"] = _trailingSleepRatio * 100;
statsObject["performance_throttling_ratio"] = _performanceThrottlingRatio;
statsObject["broadcast_loop_rate"] = _broadcastRate.rate();
QJsonObject avatarsObject;
@ -545,6 +626,7 @@ void AvatarMixer::run() {
// setup the timer that will be fired on the broadcast thread
_broadcastTimer = new QTimer;
_broadcastTimer->setTimerType(Qt::PreciseTimer);
_broadcastTimer->setInterval(AVATAR_DATA_SEND_INTERVAL_MSECS);
_broadcastTimer->moveToThread(&_broadcastThread);
@ -564,7 +646,7 @@ void AvatarMixer::domainSettingsRequestComplete() {
float domainMaximumScale = _domainMaximumScale;
nodeList->linkedDataCreateCallback = [domainMinimumScale, domainMaximumScale] (Node* node) {
auto clientData = std::unique_ptr<AvatarMixerClientData> { new AvatarMixerClientData };
auto clientData = std::unique_ptr<AvatarMixerClientData> { new AvatarMixerClientData(node->getUUID()) };
clientData->getAvatar().setDomainMinimumScale(domainMinimumScale);
clientData->getAvatar().setDomainMaximumScale(domainMaximumScale);

View file

@ -15,9 +15,11 @@
#ifndef hifi_AvatarMixer_h
#define hifi_AvatarMixer_h
#include <shared/RateCounter.h>
#include <PortableHighResolutionClock.h>
#include <ThreadedAssignment.h>
#include "AvatarMixerClientData.h"
/// Handles assignments of type AvatarMixer - distribution of avatar data to various clients
class AvatarMixer : public ThreadedAssignment {
@ -34,6 +36,7 @@ public slots:
void sendStatsPacket() override;
private slots:
void handleViewFrustumPacket(QSharedPointer<ReceivedMessage> message, SharedNodePointer senderNode);
void handleAvatarDataPacket(QSharedPointer<ReceivedMessage> message, SharedNodePointer senderNode);
void handleAvatarIdentityPacket(QSharedPointer<ReceivedMessage> message, SharedNodePointer senderNode);
void handleKillAvatarPacket(QSharedPointer<ReceivedMessage> message);
@ -46,6 +49,7 @@ private slots:
private:
void broadcastAvatarData();
void parseDomainServerSettings(const QJsonObject& domainSettings);
void sendIdentityPacket(AvatarMixerClientData* nodeData, const SharedNodePointer& destinationNode);
QThread _broadcastThread;
@ -64,6 +68,10 @@ private:
float _domainMaximumScale { MAX_AVATAR_SCALE };
QTimer* _broadcastTimer = nullptr;
RateCounter<> _broadcastRate;
p_high_resolution_clock::time_point _lastDebugMessage;
QHash<QString, QPair<int, int>> _sessionDisplayNames;
};
#endif // hifi_AvatarMixer_h

View file

@ -57,6 +57,14 @@ void AvatarMixerClientData::ignoreOther(SharedNodePointer self, SharedNodePointe
}
}
void AvatarMixerClientData::readViewFrustumPacket(const QByteArray& message) {
_currentViewFrustum.fromByteArray(message);
}
bool AvatarMixerClientData::otherAvatarInView(const AABox& otherAvatarBox) {
return _currentViewFrustum.boxIntersectsKeyhole(otherAvatarBox);
}
void AvatarMixerClientData::loadJSONStats(QJsonObject& jsonObject) const {
jsonObject["display_name"] = _avatar->getDisplayName();
jsonObject["full_rate_distance"] = _fullRateDistance;
@ -70,4 +78,6 @@ void AvatarMixerClientData::loadJSONStats(QJsonObject& jsonObject) const {
jsonObject[INBOUND_AVATAR_DATA_STATS_KEY] = _avatar->getAverageBytesReceivedPerSecond() / (float) BYTES_PER_KILOBIT;
jsonObject["av_data_receive_rate"] = _avatar->getReceiveRate();
jsonObject["recent_other_av_in_view"] = _recentOtherAvatarsInView;
jsonObject["recent_other_av_out_of_view"] = _recentOtherAvatarsOutOfView;
}

View file

@ -27,6 +27,7 @@
#include <PortableHighResolutionClock.h>
#include <SimpleMovingAverage.h>
#include <UUIDHasher.h>
#include <ViewFrustum.h>
const QString OUTBOUND_AVATAR_DATA_STATS_KEY = "outbound_av_data_kbps";
const QString INBOUND_AVATAR_DATA_STATS_KEY = "inbound_av_data_kbps";
@ -34,6 +35,8 @@ const QString INBOUND_AVATAR_DATA_STATS_KEY = "inbound_av_data_kbps";
class AvatarMixerClientData : public NodeData {
Q_OBJECT
public:
AvatarMixerClientData(const QUuid& nodeID = QUuid()) : NodeData(nodeID) { _currentViewFrustum.invalidate(); }
virtual ~AvatarMixerClientData() {}
using HRCTime = p_high_resolution_clock::time_point;
int parseData(ReceivedMessage& message) override;
@ -50,6 +53,8 @@ public:
HRCTime getIdentityChangeTimestamp() const { return _identityChangeTimestamp; }
void flagIdentityChange() { _identityChangeTimestamp = p_high_resolution_clock::now(); }
bool getReceivedIdentity() const { return _gotIdentity; }
void setReceivedIdentity() { _gotIdentity = true; }
void setFullRateDistance(float fullRateDistance) { _fullRateDistance = fullRateDistance; }
float getFullRateDistance() const { return _fullRateDistance; }
@ -87,6 +92,16 @@ public:
void removeFromRadiusIgnoringSet(const QUuid& other) { _radiusIgnoredOthers.erase(other); }
void ignoreOther(SharedNodePointer self, SharedNodePointer other);
void readViewFrustumPacket(const QByteArray& message);
bool otherAvatarInView(const AABox& otherAvatarBox);
void resetInViewStats() { _recentOtherAvatarsInView = _recentOtherAvatarsOutOfView = 0; }
void incrementAvatarInView() { _recentOtherAvatarsInView++; }
void incrementAvatarOutOfView() { _recentOtherAvatarsOutOfView++; }
const QString& getBaseDisplayName() { return _baseDisplayName; }
void setBaseDisplayName(const QString& baseDisplayName) { _baseDisplayName = baseDisplayName; }
private:
AvatarSharedPointer _avatar { new AvatarData() };
@ -95,6 +110,7 @@ private:
std::unordered_set<QUuid> _hasReceivedFirstPacketsFrom;
HRCTime _identityChangeTimestamp;
bool _gotIdentity { false };
float _fullRateDistance = FLT_MAX;
float _maxAvatarDistance = FLT_MAX;
@ -108,6 +124,11 @@ private:
SimpleMovingAverage _avgOtherAvatarDataRate;
std::unordered_set<QUuid> _radiusIgnoredOthers;
ViewFrustum _currentViewFrustum;
int _recentOtherAvatarsInView { 0 };
int _recentOtherAvatarsOutOfView { 0 };
QString _baseDisplayName{}; // The santized key used in determinging unique sessionDisplayName, so that we can remove from dictionary.
};
#endif // hifi_AvatarMixerClientData_h

View file

@ -38,13 +38,13 @@ set(${EXTERNAL_NAME_UPPER}_DLL_PATH ${INSTALL_DIR}/lib CACHE FILEPATH "Location
if (APPLE)
set(${EXTERNAL_NAME_UPPER}_LIBRARY_RELEASE ${INSTALL_DIR}/lib/libquazip5.1.0.0.dylib CACHE FILEPATH "Location of QuaZip release library")
set(${EXTERNAL_NAME_UPPER}_LIBRARY_DEBUG ${INSTALL_DIR}/lib/libquazip5d.1.0.0.dylib CACHE FILEPATH "Location of QuaZip release library")
set(${EXTERNAL_NAME_UPPER}_LIBRARY_DEBUG ${INSTALL_DIR}/lib/libquazip5.1.0.0.dylib CACHE FILEPATH "Location of QuaZip release library")
elseif (WIN32)
set(${EXTERNAL_NAME_UPPER}_LIBRARY_RELEASE ${INSTALL_DIR}/lib/quazip5.lib CACHE FILEPATH "Location of QuaZip release library")
set(${EXTERNAL_NAME_UPPER}_LIBRARY_DEBUG ${INSTALL_DIR}/lib/quazip5d.lib CACHE FILEPATH "Location of QuaZip release library")
set(${EXTERNAL_NAME_UPPER}_LIBRARY_DEBUG ${INSTALL_DIR}/lib/quazip5.lib CACHE FILEPATH "Location of QuaZip release library")
else ()
set(${EXTERNAL_NAME_UPPER}_LIBRARY_RELEASE ${INSTALL_DIR}/lib/libquazip5.so CACHE FILEPATH "Location of QuaZip release library")
set(${EXTERNAL_NAME_UPPER}_LIBRARY_DEBUG ${INSTALL_DIR}/lib/libquazip5d.so CACHE FILEPATH "Location of QuaZip release library")
set(${EXTERNAL_NAME_UPPER}_LIBRARY_DEBUG ${INSTALL_DIR}/lib/libquazip5.so CACHE FILEPATH "Location of QuaZip release library")
endif ()
include(SelectLibraryConfigurations)
@ -52,4 +52,4 @@ select_library_configurations(${EXTERNAL_NAME_UPPER})
# Force selected libraries into the cache
set(${EXTERNAL_NAME_UPPER}_LIBRARY ${${EXTERNAL_NAME_UPPER}_LIBRARY} CACHE FILEPATH "Location of QuaZip libraries")
set(${EXTERNAL_NAME_UPPER}_LIBRARIES ${${EXTERNAL_NAME_UPPER}_LIBRARIES} CACHE FILEPATH "Location of QuaZip libraries")
set(${EXTERNAL_NAME_UPPER}_LIBRARIES ${${EXTERNAL_NAME_UPPER}_LIBRARIES} CACHE FILEPATH "Location of QuaZip libraries")

View file

@ -800,7 +800,12 @@ void DomainServerSettingsManager::processUsernameFromIDRequestPacket(QSharedPoin
usernameFromIDReplyPacket->write(nodeUUID.toRfc4122());
usernameFromIDReplyPacket->writeString(verifiedUsername);
qDebug() << "Sending username" << verifiedUsername << "associated with node" << nodeUUID;
// now put in the machine fingerprint
DomainServerNodeData* nodeData = reinterpret_cast<DomainServerNodeData*>(matchingNode->getLinkedData());
QUuid machineFingerprint = nodeData ? nodeData->getMachineFingerprint() : QUuid();
usernameFromIDReplyPacket->write(machineFingerprint.toRfc4122());
qDebug() << "Sending username" << verifiedUsername << "and machine fingerprint" << machineFingerprint << "associated with node" << nodeUUID;
// Ship it!
limitedNodeList->sendPacket(std::move(usernameFromIDReplyPacket), *sendingNode);

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

View file

@ -21,9 +21,9 @@ Original.CheckBox {
property int colorScheme: hifi.colorSchemes.light
readonly property bool isLightColorScheme: colorScheme == hifi.colorSchemes.light
readonly property int boxSize: 14
property int boxSize: 14
readonly property int boxRadius: 3
readonly property int checkSize: 10
readonly property int checkSize: Math.max(boxSize - 8, 10)
readonly property int checkRadius: 2
style: CheckBoxStyle {
@ -32,21 +32,35 @@ Original.CheckBox {
width: boxSize
height: boxSize
radius: boxRadius
border.width: 1
border.color: pressed || hovered
? hifi.colors.checkboxCheckedBorder
: (checkBox.isLightColorScheme ? hifi.colors.checkboxLightFinish : hifi.colors.checkboxDarkFinish)
gradient: Gradient {
GradientStop {
position: 0.2
color: pressed || hovered
? (checkBox.isLightColorScheme ? hifi.colors.checkboxDarkStart : hifi.colors.checkboxLightStart)
? (checkBox.isLightColorScheme ? hifi.colors.checkboxChecked : hifi.colors.checkboxLightStart)
: (checkBox.isLightColorScheme ? hifi.colors.checkboxLightStart : hifi.colors.checkboxDarkStart)
}
GradientStop {
position: 1.0
color: pressed || hovered
? (checkBox.isLightColorScheme ? hifi.colors.checkboxDarkFinish : hifi.colors.checkboxLightFinish)
? (checkBox.isLightColorScheme ? hifi.colors.checkboxChecked : hifi.colors.checkboxLightFinish)
: (checkBox.isLightColorScheme ? hifi.colors.checkboxLightFinish : hifi.colors.checkboxDarkFinish)
}
}
Rectangle {
visible: pressed || hovered
anchors.centerIn: parent
id: innerBox
width: checkSize - 4
height: width
radius: checkRadius
color: hifi.colors.checkboxCheckedBorder
}
Rectangle {
id: check
width: checkSize
@ -54,7 +68,7 @@ Original.CheckBox {
radius: checkRadius
anchors.centerIn: parent
color: hifi.colors.checkboxChecked
border.width: 1
border.width: 2
border.color: hifi.colors.checkboxCheckedBorder
visible: checked && !pressed || !checked && pressed
}

View file

@ -20,6 +20,7 @@ TableView {
property int colorScheme: hifi.colorSchemes.light
readonly property bool isLightColorScheme: colorScheme == hifi.colorSchemes.light
property bool expandSelectedRow: false
property bool centerHeaderText: false
model: ListModel { }
@ -34,9 +35,12 @@ TableView {
size: hifi.fontSizes.tableHeading
font.capitalization: Font.AllUppercase
color: hifi.colors.baseGrayHighlight
horizontalAlignment: (centerHeaderText ? Text.AlignHCenter : Text.AlignLeft)
anchors {
left: parent.left
leftMargin: hifi.dimensions.tablePadding
right: parent.right
rightMargin: hifi.dimensions.tablePadding
verticalCenter: parent.verticalCenter
}
}
@ -48,7 +52,7 @@ TableView {
size: hifi.fontSizes.tableHeadingIcon
anchors {
left: titleText.right
leftMargin: -hifi.fontSizes.tableHeadingIcon / 3
leftMargin: -hifi.fontSizes.tableHeadingIcon / 3 - (centerHeaderText ? 3 : 0)
right: parent.right
rightMargin: hifi.dimensions.tablePadding
verticalCenter: titleText.verticalCenter

View file

@ -9,28 +9,128 @@
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
import Hifi 1.0
import Hifi 1.0 as Hifi
import QtQuick 2.5
import QtGraphicalEffects 1.0
import "../styles-uit"
Column {
property string displayName: "";
property string userName: "";
property int displayTextHeight: 18;
property int usernameTextHeight: 12;
RalewaySemiBold {
text: parent.displayName;
size: parent.displayTextHeight;
elide: Text.ElideRight;
width: parent.width;
Row {
id: thisNameCard
// Spacing
spacing: 10
// Anchors
anchors.top: parent.top
anchors {
topMargin: (parent.height - contentHeight)/2
bottomMargin: (parent.height - contentHeight)/2
leftMargin: 10
rightMargin: 10
}
RalewayLight {
visible: parent.displayName;
text: parent.userName;
size: parent.usernameTextHeight;
elide: Text.ElideRight;
width: parent.width;
// Properties
property int contentHeight: 50
property string displayName: ""
property string userName: ""
property int displayTextHeight: 18
property int usernameTextHeight: 12
property real audioLevel: 0.0
Column {
id: avatarImage
// Size
height: contentHeight
width: height
Image {
id: userImage
source: "../../icons/defaultNameCardUser.png"
// Anchors
width: parent.width
height: parent.height
}
}
Column {
id: textContainer
// Size
width: parent.width - avatarImage.width - parent.anchors.leftMargin - parent.anchors.rightMargin - parent.spacing
height: contentHeight
// DisplayName Text
FiraSansSemiBold {
id: displayNameText
// Properties
text: thisNameCard.displayName
elide: Text.ElideRight
// Size
width: parent.width
// Text Size
size: thisNameCard.displayTextHeight
// Text Positioning
verticalAlignment: Text.AlignVCenter
}
// UserName Text
FiraSansRegular {
id: userNameText
// Properties
text: thisNameCard.userName
elide: Text.ElideRight
visible: thisNameCard.displayName
// Size
width: parent.width
// Text Size
size: thisNameCard.usernameTextHeight
// Text Positioning
verticalAlignment: Text.AlignVCenter
}
// Spacer
Item {
height: 4
width: parent.width
}
// VU Meter
Rectangle { // CHANGEME to the appropriate type!
id: nameCardVUMeter
// Size
width: parent.width
height: 8
// Style
radius: 4
// Rectangle for the VU meter base
Rectangle {
id: vuMeterBase
// Anchors
anchors.fill: parent
// Style
color: "#dbdbdb" // Very appropriate hex value here
radius: parent.radius
}
// Rectangle for the VU meter audio level
Rectangle {
id: vuMeterLevel
// Size
width: (thisNameCard.audioLevel) * parent.width
// Style
color: "#dbdbdb" // Very appropriate hex value here
radius: parent.radius
// Anchors
anchors.bottom: parent.bottom
anchors.top: parent.top
anchors.left: parent.left
}
// Gradient for the VU meter audio level
LinearGradient {
anchors.fill: vuMeterLevel
source: vuMeterLevel
start: Qt.point(0, 0)
end: Qt.point(parent.width, 0)
gradient: Gradient {
GradientStop { position: 0.05; color: "#00CFEF" }
GradientStop { position: 0.5; color: "#9450A5" }
GradientStop { position: 0.95; color: "#EA4C5F" }
}
}
}
}
}

View file

@ -28,19 +28,314 @@
import QtQuick 2.5
import QtQuick.Controls 1.4
import "../styles-uit"
import "../controls-uit" as HifiControls
Rectangle {
id: pal;
property int keepFromHorizontalScroll: 1;
width: parent.width - keepFromHorizontalScroll;
height: parent.height;
Item {
id: pal
// Size
width: parent.width
height: parent.height
// Properties
property int myCardHeight: 70
property int rowHeight: 70
property int actionButtonWidth: 75
property int nameCardWidth: width - actionButtonWidth*(iAmAdmin ? 4 : 2)
property int nameWidth: width/2;
property int actionWidth: nameWidth / (table.columnCount - 1);
property int rowHeight: 50;
property var userData: [];
property var myData: ({displayName: "", userName: ""}); // valid dummy until set
property bool iAmAdmin: false;
// This contains the current user's NameCard and will contain other information in the future
Rectangle {
id: myInfo
// Size
width: pal.width
height: myCardHeight + 20
// Anchors
anchors.top: pal.top
// Properties
radius: hifi.dimensions.borderRadius
// This NameCard refers to the current user's NameCard (the one above the table)
NameCard {
id: myCard
// Properties
displayName: myData.displayName
userName: myData.userName
audioLevel: myData.audioLevel
// Size
width: nameCardWidth
height: parent.height
// Anchors
anchors.left: parent.left
}
}
// Rectangles used to cover up rounded edges on bottom of MyInfo Rectangle
Rectangle {
color: "#FFFFFF"
width: pal.width
height: 10
anchors.top: myInfo.bottom
anchors.left: parent.left
}
Rectangle {
color: "#FFFFFF"
width: pal.width
height: 10
anchors.bottom: table.top
anchors.left: parent.left
}
// Rectangle that houses "ADMIN" string
Rectangle {
id: adminTab
// Size
width: actionButtonWidth * 2 - 2
height: 40
// Anchors
anchors.bottom: myInfo.bottom
anchors.bottomMargin: -10
anchors.right: myInfo.right
// Properties
visible: iAmAdmin
// Style
color: hifi.colors.tableRowLightEven
radius: hifi.dimensions.borderRadius
border.color: hifi.colors.lightGrayText
border.width: 2
// "ADMIN" text
RalewaySemiBold {
text: "ADMIN"
// Text size
size: hifi.fontSizes.tableHeading + 2
// Anchors
anchors.top: parent.top
anchors.topMargin: 8
anchors.left: parent.left
anchors.right: parent.right
// Style
font.capitalization: Font.AllUppercase
color: hifi.colors.redHighlight
// Alignment
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignTop
}
}
// This TableView refers to the table (below the current user's NameCard)
HifiControls.Table {
id: table
// Size
height: pal.height - myInfo.height - 4
width: pal.width - 4
// Anchors
anchors.left: parent.left
anchors.top: myInfo.bottom
// Properties
centerHeaderText: true
sortIndicatorVisible: true
headerVisible: true
onSortIndicatorColumnChanged: sortModel()
onSortIndicatorOrderChanged: sortModel()
TableViewColumn {
role: "displayName"
title: "NAMES"
width: nameCardWidth
movable: false
resizable: false
}
TableViewColumn {
role: "personalMute"
title: "MUTE"
width: actionButtonWidth
movable: false
resizable: false
}
TableViewColumn {
role: "ignore"
title: "IGNORE"
width: actionButtonWidth
movable: false
resizable: false
}
TableViewColumn {
visible: iAmAdmin
role: "mute"
title: "SILENCE"
width: actionButtonWidth
movable: false
resizable: false
}
TableViewColumn {
visible: iAmAdmin
role: "kick"
title: "BAN"
width: actionButtonWidth
movable: false
resizable: false
}
model: userModel
// This Rectangle refers to each Row in the table.
rowDelegate: Rectangle { // The only way I know to specify a row height.
// Size
height: rowHeight
color: styleData.selected
? "#afafaf"
: styleData.alternate ? hifi.colors.tableRowLightEven : hifi.colors.tableRowLightOdd
}
// This Item refers to the contents of each Cell
itemDelegate: Item {
id: itemCell
property bool isCheckBox: typeof(styleData.value) === 'boolean'
// This NameCard refers to the cell that contains an avatar's
// DisplayName and UserName
NameCard {
id: nameCard
// Properties
displayName: styleData.value
userName: model.userName
audioLevel: model.audioLevel
visible: !isCheckBox
// Size
width: nameCardWidth
height: parent.height
// Anchors
anchors.left: parent.left
}
// This CheckBox belongs in the columns that contain the action buttons ("Mute", "Ban", etc)
HifiControls.CheckBox {
visible: isCheckBox
anchors.centerIn: parent
boxSize: 24
onClicked: {
var newValue = !model[styleData.role]
var datum = userData[model.userIndex]
datum[styleData.role] = model[styleData.role] = newValue
Users[styleData.role](model.sessionId)
// Just for now, while we cannot undo things:
userData.splice(model.userIndex, 1)
sortModel()
}
}
}
}
// Refresh button
Rectangle {
// Size
width: hifi.dimensions.tableHeaderHeight-1
height: hifi.dimensions.tableHeaderHeight-1
// Anchors
anchors.left: table.left
anchors.leftMargin: 4
anchors.top: table.top
// Style
color: hifi.colors.tableBackgroundLight
// Actual refresh icon
HiFiGlyphs {
id: reloadButton
text: hifi.glyphs.reloadSmall
// Size
size: parent.width*1.5
// Anchors
anchors.fill: parent
// Style
horizontalAlignment: Text.AlignHCenter
color: hifi.colors.darkGray
}
MouseArea {
id: reloadButtonArea
// Anchors
anchors.fill: parent
hoverEnabled: true
// Everyone likes a responsive refresh button!
// So use onPressed instead of onClicked
onPressed: {
reloadButton.color = hifi.colors.lightGrayText
pal.sendToScript({method: 'refresh'})
}
onReleased: reloadButton.color = (containsMouse ? hifi.colors.baseGrayHighlight : hifi.colors.darkGray)
onEntered: reloadButton.color = hifi.colors.baseGrayHighlight
onExited: reloadButton.color = (pressed ? hifi.colors.lightGrayText: hifi.colors.darkGray)
}
}
// Separator between user and admin functions
Rectangle {
// Size
width: 2
height: table.height
// Anchors
anchors.left: adminTab.left
anchors.top: table.top
// Properties
visible: iAmAdmin
color: hifi.colors.lightGrayText
}
// This Rectangle refers to the [?] popup button
Rectangle {
color: hifi.colors.tableBackgroundLight
width: 20
height: hifi.dimensions.tableHeaderHeight - 2
anchors.left: table.left
anchors.top: table.top
anchors.topMargin: 1
anchors.leftMargin: nameCardWidth/2 + 24
RalewayRegular {
id: helpText
text: "[?]"
size: hifi.fontSizes.tableHeading + 2
font.capitalization: Font.AllUppercase
color: hifi.colors.darkGray
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
anchors.fill: parent
}
MouseArea {
anchors.fill: parent
acceptedButtons: Qt.LeftButton
hoverEnabled: true
onClicked: namesPopup.visible = true
onEntered: helpText.color = hifi.colors.baseGrayHighlight
onExited: helpText.color = hifi.colors.darkGray
}
}
// Explanitory popup upon clicking "[?]"
Item {
visible: false
id: namesPopup
anchors.fill: pal
Rectangle {
anchors.fill: parent
color: "black"
opacity: 0.5
radius: hifi.dimensions.borderRadius
}
Rectangle {
width: Math.min(parent.width * 0.75, 400)
height: popupText.contentHeight*2
anchors.centerIn: parent
radius: hifi.dimensions.borderRadius
color: "white"
FiraSansSemiBold {
id: popupText
text: "This is temporary text. It will eventually be used to explain what 'Names' means."
size: hifi.fontSizes.textFieldInput
color: hifi.colors.darkGray
horizontalAlignment: Text.AlignHCenter
anchors.fill: parent
wrapMode: Text.WordWrap
}
}
MouseArea {
anchors.fill: parent
acceptedButtons: Qt.LeftButton
onClicked: {
namesPopup.visible = false
}
}
}
property var userData: []
property var myData: ({displayName: "", userName: "", audioLevel: 0.0}) // valid dummy until set
property bool iAmAdmin: false
function findSessionIndex(sessionId, optionalData) { // no findIndex in .qml
var i, data = optionalData || userData, length = data.length;
for (var i = 0; i < length; i++) {
@ -90,6 +385,21 @@ Rectangle {
userData[userIndex].userName = userName; // Defensive programming
}
break;
case 'updateAudioLevel':
for (var userId in message.params) {
var audioLevel = message.params[userId];
// If the userId is 0, we're updating "myData".
if (userId == 0) {
myData.audioLevel = audioLevel;
myCard.audioLevel = audioLevel; // Defensive programming
} else {
console.log("userid:" + userId);
var userIndex = findSessionIndex(userId);
userModel.get(userIndex).audioLevel = audioLevel;
userData[userIndex].audioLevel = audioLevel; // Defensive programming
}
}
break;
default:
console.log('Unrecognized message:', JSON.stringify(message));
}
@ -118,7 +428,7 @@ Rectangle {
datum[property] = false;
}
}
['ignore', 'spacer', 'mute', 'kick'].forEach(init);
['personalMute', 'ignore', 'mute', 'kick'].forEach(init);
datum.userIndex = userIndex++;
userModel.append(datum);
});
@ -135,91 +445,4 @@ Rectangle {
target: table.selection
onSelectionChanged: pal.noticeSelection()
}
Column {
NameCard {
id: myCard;
width: nameWidth;
displayName: myData.displayName;
userName: myData.userName;
}
TableView {
id: table;
TableViewColumn {
role: "displayName";
title: "Name";
width: nameWidth
}
TableViewColumn {
role: "ignore";
title: "Ignore"
width: actionWidth
}
TableViewColumn {
title: "";
width: actionWidth
}
TableViewColumn {
visible: iAmAdmin;
role: "mute";
title: "Mute";
width: actionWidth
}
TableViewColumn {
visible: iAmAdmin;
role: "kick";
title: "Ban"
width: actionWidth
}
model: userModel;
rowDelegate: Rectangle { // The only way I know to specify a row height.
height: rowHeight;
// The rest of this is cargo-culted to restore the default styling
SystemPalette {
id: myPalette;
colorGroup: SystemPalette.Active
}
color: {
var baseColor = styleData.alternate?myPalette.alternateBase:myPalette.base
return styleData.selected?myPalette.highlight:baseColor
}
}
itemDelegate: Item {
id: itemCell;
property bool isCheckBox: typeof(styleData.value) === 'boolean';
NameCard {
id: nameCard;
visible: !isCheckBox;
width: nameWidth;
displayName: styleData.value;
userName: model.userName;
}
Rectangle {
radius: itemCell.height / 4;
visible: isCheckBox;
color: styleData.value ? "green" : "red";
anchors.fill: parent;
MouseArea {
anchors.fill: parent;
acceptedButtons: Qt.LeftButton;
hoverEnabled: true;
onClicked: {
var newValue = !model[styleData.role];
var datum = userData[model.userIndex];
datum[styleData.role] = model[styleData.role] = newValue;
Users[styleData.role](model.sessionId);
// Just for now, while we cannot undo things:
userData.splice(model.userIndex, 1);
sortModel();
}
}
}
}
height: pal.height - myCard.height;
width: pal.width;
sortIndicatorVisible: true;
onSortIndicatorColumnChanged: sortModel();
onSortIndicatorOrderChanged: sortModel();
}
}
}

View file

@ -22,7 +22,7 @@ ScrollingWindow {
objectName: "RunningScripts"
title: "Running Scripts"
resizable: true
destroyOnHidden: true
destroyOnHidden: false
implicitWidth: 424
implicitHeight: isHMD ? 695 : 728
minSize: Qt.vector2d(424, 300)

View file

@ -89,8 +89,8 @@ Item {
readonly property color transparent: "#00ffffff"
// Control specific colors
readonly property color tableRowLightOdd: "#eaeaea" // Equivalent to white50 over #e3e3e3 background
readonly property color tableRowLightEven: "#c6c6c6" // Equivavlent to "#1a575757" over #e3e3e3 background
readonly property color tableRowLightOdd: "#fafafa"
readonly property color tableRowLightEven: "#eeeeee" // Equivavlent to "#1a575757" over #e3e3e3 background
readonly property color tableRowDarkOdd: "#2e2e2e" // Equivalent to "#80393939" over #404040 background
readonly property color tableRowDarkEven: "#1c1c1c" // Equivalent to "#a6181818" over #404040 background
readonly property color tableBackgroundLight: tableRowLightEven

View file

@ -66,7 +66,6 @@
#include <ErrorDialog.h>
#include <FileScriptingInterface.h>
#include <Finally.h>
#include <FingerprintUtils.h>
#include <FramebufferCache.h>
#include <gpu/Batch.h>
#include <gpu/Context.h>
@ -616,9 +615,6 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo
Model::setAbstractViewStateInterface(this); // The model class will sometimes need to know view state details from us
// TODO: This is temporary, while developing
FingerprintUtils::getMachineFingerprint();
// End TODO
auto nodeList = DependencyManager::get<NodeList>();
// Set up a watchdog thread to intentionally crash the application on deadlocks
@ -1141,7 +1137,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo
connect(&_settingsThread, SIGNAL(finished()), &_settingsTimer, SLOT(stop()));
_settingsTimer.moveToThread(&_settingsThread);
_settingsTimer.setSingleShot(false);
_settingsTimer.setInterval(SAVE_SETTINGS_INTERVAL);
_settingsTimer.setInterval(SAVE_SETTINGS_INTERVAL); // 10s, Qt::CoarseTimer acceptable
_settingsThread.start();
if (Menu::getInstance()->isOptionChecked(MenuOption::FirstPerson)) {
@ -1246,7 +1242,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo
// Periodically send fps as a user activity event
QTimer* sendStatsTimer = new QTimer(this);
sendStatsTimer->setInterval(SEND_STATS_INTERVAL_MS);
sendStatsTimer->setInterval(SEND_STATS_INTERVAL_MS); // 10s, Qt::CoarseTimer acceptable
connect(sendStatsTimer, &QTimer::timeout, this, [this]() {
QJsonObject properties = {};
@ -1277,6 +1273,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo
properties["sim_rate"] = getAverageSimsPerSecond();
properties["avatar_sim_rate"] = getAvatarSimrate();
properties["has_async_reprojection"] = displayPlugin->hasAsyncReprojection();
properties["hardware_stats"] = displayPlugin->getHardwareStats();
auto bandwidthRecorder = DependencyManager::get<BandwidthRecorder>();
properties["packet_rate_in"] = bandwidthRecorder->getCachedTotalAverageInputPacketsPerSecond();
@ -1347,7 +1344,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo
// Periodically check for count of nearby avatars
static int lastCountOfNearbyAvatars = -1;
QTimer* checkNearbyAvatarsTimer = new QTimer(this);
checkNearbyAvatarsTimer->setInterval(CHECK_NEARBY_AVATARS_INTERVAL_MS);
checkNearbyAvatarsTimer->setInterval(CHECK_NEARBY_AVATARS_INTERVAL_MS); // 10 seconds, Qt::CoarseTimer ok
connect(checkNearbyAvatarsTimer, &QTimer::timeout, this, [this]() {
auto avatarManager = DependencyManager::get<AvatarManager>();
int nearbyAvatars = avatarManager->numberOfAvatarsInRange(avatarManager->getMyAvatar()->getPosition(),
@ -1505,16 +1502,16 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo
// Monitor model assets (e.g., from Clara.io) added to the world that may need resizing.
static const int ADD_ASSET_TO_WORLD_TIMER_INTERVAL_MS = 1000;
_addAssetToWorldResizeTimer.setInterval(ADD_ASSET_TO_WORLD_TIMER_INTERVAL_MS);
_addAssetToWorldResizeTimer.setInterval(ADD_ASSET_TO_WORLD_TIMER_INTERVAL_MS); // 1s, Qt::CoarseTimer acceptable
connect(&_addAssetToWorldResizeTimer, &QTimer::timeout, this, &Application::addAssetToWorldCheckModelSize);
// Auto-update and close adding asset to world info message box.
static const int ADD_ASSET_TO_WORLD_INFO_TIMEOUT_MS = 5000;
_addAssetToWorldInfoTimer.setInterval(ADD_ASSET_TO_WORLD_INFO_TIMEOUT_MS);
_addAssetToWorldInfoTimer.setInterval(ADD_ASSET_TO_WORLD_INFO_TIMEOUT_MS); // 5s, Qt::CoarseTimer acceptable
_addAssetToWorldInfoTimer.setSingleShot(true);
connect(&_addAssetToWorldInfoTimer, &QTimer::timeout, this, &Application::addAssetToWorldInfoTimeout);
static const int ADD_ASSET_TO_WORLD_ERROR_TIMEOUT_MS = 8000;
_addAssetToWorldErrorTimer.setInterval(ADD_ASSET_TO_WORLD_ERROR_TIMEOUT_MS);
_addAssetToWorldErrorTimer.setInterval(ADD_ASSET_TO_WORLD_ERROR_TIMEOUT_MS); // 8s, Qt::CoarseTimer acceptable
_addAssetToWorldErrorTimer.setSingleShot(true);
connect(&_addAssetToWorldErrorTimer, &QTimer::timeout, this, &Application::addAssetToWorldErrorTimeout);
@ -4326,7 +4323,7 @@ void Application::update(float deltaTime) {
// AvatarManager update
{
PerformanceTimer perfTimer("AvatarManger");
PerformanceTimer perfTimer("AvatarManager");
_avatarSimCounter.increment();
{
@ -4376,6 +4373,7 @@ void Application::update(float deltaTime) {
if (DependencyManager::get<SceneScriptingInterface>()->shouldRenderEntities()) {
queryOctree(NodeType::EntityServer, PacketType::EntityQuery, _entityServerJurisdictions);
}
sendAvatarViewFrustum();
_lastQueriedViewFrustum = _viewFrustum;
}
}
@ -4415,6 +4413,14 @@ void Application::update(float deltaTime) {
AnimDebugDraw::getInstance().update();
}
void Application::sendAvatarViewFrustum() {
QByteArray viewFrustumByteArray = _viewFrustum.toByteArray();
auto avatarPacket = NLPacket::create(PacketType::ViewFrustum, viewFrustumByteArray.size());
avatarPacket->write(viewFrustumByteArray);
DependencyManager::get<NodeList>()->broadcastToNodes(std::move(avatarPacket), NodeSet() << NodeType::AvatarMixer);
}
int Application::sendNackPackets() {
@ -5397,6 +5403,12 @@ void Application::registerScriptEngineWithApplicationServices(ScriptEngine* scri
auto scriptingInterface = DependencyManager::get<controller::ScriptingInterface>();
scriptEngine->registerGlobalObject("Controller", scriptingInterface.data());
UserInputMapper::registerControllerTypes(scriptEngine);
// connect this script engines printedMessage signal to the global ScriptEngines these various messages
connect(scriptEngine, &ScriptEngine::printedMessage, DependencyManager::get<ScriptEngines>().data(), &ScriptEngines::onPrintedMessage);
connect(scriptEngine, &ScriptEngine::errorMessage, DependencyManager::get<ScriptEngines>().data(), &ScriptEngines::onErrorMessage);
connect(scriptEngine, &ScriptEngine::warningMessage, DependencyManager::get<ScriptEngines>().data(), &ScriptEngines::onWarningMessage);
connect(scriptEngine, &ScriptEngine::infoMessage, DependencyManager::get<ScriptEngines>().data(), &ScriptEngines::onInfoMessage);
}
bool Application::canAcceptURL(const QString& urlString) const {

View file

@ -444,6 +444,7 @@ private:
void renderRearViewMirror(RenderArgs* renderArgs, const QRect& region, bool isZoomed);
int sendNackPackets();
void sendAvatarViewFrustum();
std::shared_ptr<MyAvatar> getMyAvatar() const;

View file

@ -704,6 +704,15 @@ Menu::Menu() {
addActionToQMenuAndActionHash(developerMenu, MenuOption::Log, Qt::CTRL | Qt::SHIFT | Qt::Key_L,
qApp, SLOT(toggleLogDialog()));
action = addActionToQMenuAndActionHash(developerMenu, "Script Log (HMD friendly)...");
connect(action, &QAction::triggered, [] {
auto scriptEngines = DependencyManager::get<ScriptEngines>();
QUrl defaultScriptsLoc = defaultScriptsLocation();
defaultScriptsLoc.setPath(defaultScriptsLoc.path() + "developer/debugging/debugWindow.js");
scriptEngines->loadScript(defaultScriptsLoc.toString());
});
// Developer > Stats
addCheckableActionToQMenuAndActionHash(developerMenu, MenuOption::Stats);

View file

@ -75,6 +75,19 @@ namespace render {
}
}
static uint64_t timeProcessingJoints = 0;
static int32_t numJointsProcessed = 0;
float Avatar::getNumJointsProcessedPerSecond() {
float rate = 0.0f;
if (timeProcessingJoints > 0) {
rate = (float)(numJointsProcessed * USECS_PER_SECOND) / (float)timeProcessingJoints;
}
timeProcessingJoints = 0;
numJointsProcessed = 0;
return rate;
}
Avatar::Avatar(RigPointer rig) :
AvatarData(),
_skeletonOffset(0.0f),
@ -262,13 +275,16 @@ void Avatar::updateAvatarEntities() {
}
AvatarEntityIDs recentlyDettachedAvatarEntities = getAndClearRecentlyDetachedIDs();
_avatarEntitiesLock.withReadLock([&] {
foreach (auto entityID, recentlyDettachedAvatarEntities) {
if (!_avatarEntityData.contains(entityID)) {
entityTree->deleteEntity(entityID, true, true);
if (!recentlyDettachedAvatarEntities.empty()) {
// only lock this thread when absolutely necessary
_avatarEntitiesLock.withReadLock([&] {
foreach (auto entityID, recentlyDettachedAvatarEntities) {
if (!_avatarEntityData.contains(entityID)) {
entityTree->deleteEntity(entityID, true, true);
}
}
}
});
});
}
});
if (success) {
@ -286,18 +302,25 @@ void Avatar::simulate(float deltaTime) {
}
animateScaleChanges(deltaTime);
bool avatarPositionInView = false;
bool avatarMeshInView = false;
bool avatarInView = false;
{ // update the shouldAnimate flag to match whether or not we will render the avatar.
PerformanceTimer perfTimer("cull");
ViewFrustum viewFrustum;
{
PerformanceTimer perfTimer("LOD");
// simple frustum check
PerformanceTimer perfTimer("inView");
ViewFrustum viewFrustum;
qApp->copyDisplayViewFrustum(viewFrustum);
avatarInView = viewFrustum.sphereIntersectsFrustum(getPosition(), getBoundingRadius())
|| viewFrustum.boxIntersectsFrustum(_skeletonModel->getRenderableMeshBound());
}
PerformanceTimer lodPerfTimer("LOD");
if (avatarInView) {
const float MINIMUM_VISIBILITY_FOR_ON = 0.4f;
const float MAXIMUM_VISIBILITY_FOR_OFF = 0.6f;
ViewFrustum viewFrustum;
qApp->copyViewFrustum(viewFrustum);
float visibility = calculateRenderAccuracy(viewFrustum.getPosition(),
getBounds(), DependencyManager::get<LODManager>()->getOctreeSizeScale());
getBounds(), DependencyManager::get<LODManager>()->getOctreeSizeScale());
if (!_shouldAnimate) {
if (visibility > MINIMUM_VISIBILITY_FOR_ON) {
_shouldAnimate = true;
@ -308,18 +331,11 @@ void Avatar::simulate(float deltaTime) {
qCDebug(interfaceapp) << "Optimizing" << (isMyAvatar() ? "myself" : getSessionUUID()) << "for visibility" << visibility;
}
}
{
PerformanceTimer perfTimer("inView");
// simple frustum check
float boundingRadius = getBoundingRadius();
qApp->copyDisplayViewFrustum(viewFrustum);
avatarPositionInView = viewFrustum.sphereIntersectsFrustum(getPosition(), boundingRadius);
avatarMeshInView = viewFrustum.boxIntersectsFrustum(_skeletonModel->getRenderableMeshBound());
}
}
if (_shouldAnimate && !_shouldSkipRender && (avatarPositionInView || avatarMeshInView)) {
uint64_t start = usecTimestampNow();
// CRUFT? _shouldSkipRender is never set 'true'
if (_shouldAnimate && avatarInView && !_shouldSkipRender) {
{
PerformanceTimer perfTimer("skeleton");
_skeletonModel->getRig()->copyJointsFromJointData(_jointData);
@ -345,6 +361,8 @@ void Avatar::simulate(float deltaTime) {
PerformanceTimer perfTimer("skeleton");
_skeletonModel->simulate(deltaTime, false);
}
timeProcessingJoints += usecTimestampNow() - start;
numJointsProcessed += _jointData.size();
// update animation for display name fade in/out
if ( _displayNameTargetAlpha != _displayNameAlpha) {
@ -709,7 +727,7 @@ glm::vec3 Avatar::getDisplayNamePosition() const {
glm::vec3 bodyUpDirection = getBodyUpDirection();
DEBUG_VALUE("bodyUpDirection =", bodyUpDirection);
if (getSkeletonModel()->getNeckPosition(namePosition)) {
if (_skeletonModel->getNeckPosition(namePosition)) {
float headHeight = getHeadHeight();
DEBUG_VALUE("namePosition =", namePosition);
DEBUG_VALUE("headHeight =", headHeight);
@ -1228,8 +1246,8 @@ glm::vec3 Avatar::getUncachedLeftPalmPosition() const {
return leftPalmPosition;
}
// avatar didn't have a LeftHandMiddle1 joint, fall back on this:
getSkeletonModel()->getJointRotationInWorldFrame(getSkeletonModel()->getLeftHandJointIndex(), leftPalmRotation);
getSkeletonModel()->getLeftHandPosition(leftPalmPosition);
_skeletonModel->getJointRotationInWorldFrame(_skeletonModel->getLeftHandJointIndex(), leftPalmRotation);
_skeletonModel->getLeftHandPosition(leftPalmPosition);
leftPalmPosition += HAND_TO_PALM_OFFSET * glm::inverse(leftPalmRotation);
return leftPalmPosition;
}
@ -1237,7 +1255,7 @@ glm::vec3 Avatar::getUncachedLeftPalmPosition() const {
glm::quat Avatar::getUncachedLeftPalmRotation() const {
assert(QThread::currentThread() == thread()); // main thread access only
glm::quat leftPalmRotation;
getSkeletonModel()->getJointRotationInWorldFrame(getSkeletonModel()->getLeftHandJointIndex(), leftPalmRotation);
_skeletonModel->getJointRotationInWorldFrame(_skeletonModel->getLeftHandJointIndex(), leftPalmRotation);
return leftPalmRotation;
}
@ -1249,8 +1267,8 @@ glm::vec3 Avatar::getUncachedRightPalmPosition() const {
return rightPalmPosition;
}
// avatar didn't have a RightHandMiddle1 joint, fall back on this:
getSkeletonModel()->getJointRotationInWorldFrame(getSkeletonModel()->getRightHandJointIndex(), rightPalmRotation);
getSkeletonModel()->getRightHandPosition(rightPalmPosition);
_skeletonModel->getJointRotationInWorldFrame(_skeletonModel->getRightHandJointIndex(), rightPalmRotation);
_skeletonModel->getRightHandPosition(rightPalmPosition);
rightPalmPosition += HAND_TO_PALM_OFFSET * glm::inverse(rightPalmRotation);
return rightPalmPosition;
}
@ -1258,7 +1276,7 @@ glm::vec3 Avatar::getUncachedRightPalmPosition() const {
glm::quat Avatar::getUncachedRightPalmRotation() const {
assert(QThread::currentThread() == thread()); // main thread access only
glm::quat rightPalmRotation;
getSkeletonModel()->getJointRotationInWorldFrame(getSkeletonModel()->getRightHandJointIndex(), rightPalmRotation);
_skeletonModel->getJointRotationInWorldFrame(_skeletonModel->getRightHandJointIndex(), rightPalmRotation);
return rightPalmRotation;
}

View file

@ -57,6 +57,8 @@ class Avatar : public AvatarData {
Q_PROPERTY(glm::vec3 skeletonOffset READ getSkeletonOffset WRITE setSkeletonOffset)
public:
static float getNumJointsProcessedPerSecond();
explicit Avatar(RigPointer rig = nullptr);
~Avatar();
@ -119,6 +121,7 @@ public:
virtual void setAttachmentData(const QVector<AttachmentData>& attachmentData) override;
void setShowDisplayName(bool showDisplayName);
virtual void setSessionDisplayName(const QString& sessionDisplayName) override { }; // no-op
virtual int parseDataFromBuffer(const QByteArray& buffer) override;
@ -189,6 +192,10 @@ public slots:
protected:
friend class AvatarManager;
virtual const QString& getSessionDisplayNameForTransport() const override { return _empty; } // Save a tiny bit of bandwidth. Mixer won't look at what we send.
QString _empty{};
virtual void maybeUpdateSessionDisplayNameFromTransport(const QString& sessionDisplayName) override { _sessionDisplayName = sessionDisplayName; } // don't use no-op setter!
void setMotionState(AvatarMotionState* motionState);
SkeletonModelPointer _skeletonModel;

View file

@ -25,13 +25,13 @@
#endif
#include <AvatarData.h>
#include <PerfStat.h>
#include <RegisteredMetaTypes.h>
#include <Rig.h>
#include <SettingHandle.h>
#include <UsersScriptingInterface.h>
#include <UUID.h>
#include <AvatarData.h>
#include "Application.h"
#include "Avatar.h"
@ -124,6 +124,9 @@ void AvatarManager::updateMyAvatar(float deltaTime) {
}
}
Q_LOGGING_CATEGORY(trace_simulation_avatar, "trace.simulation.avatar");
void AvatarManager::updateOtherAvatars(float deltaTime) {
// lock the hash for read to check the size
QReadLocker lock(&_hashLock);
@ -143,6 +146,7 @@ void AvatarManager::updateOtherAvatars(float deltaTime) {
// simulate avatars
auto hashCopy = getHashCopy();
uint64_t start = usecTimestampNow();
AvatarHash::iterator avatarIterator = hashCopy.begin();
while (avatarIterator != hashCopy.end()) {
auto avatar = std::static_pointer_cast<Avatar>(avatarIterator.value());
@ -165,6 +169,10 @@ void AvatarManager::updateOtherAvatars(float deltaTime) {
// simulate avatar fades
simulateAvatarFades(deltaTime);
PROFILE_COUNTER(simulation_avatar, "NumAvatarsPerSec",
{ { "NumAvatarsPerSec", (float)(size() * USECS_PER_SECOND) / (float)(usecTimestampNow() - start) } });
PROFILE_COUNTER(simulation_avatar, "NumJointsPerSec", { { "NumJointsPerSec", Avatar::getNumJointsProcessedPerSecond() } });
}
void AvatarManager::postUpdate(float deltaTime) {

View file

@ -226,7 +226,7 @@ void MyAvatar::simulateAttachments(float deltaTime) {
// don't update attachments here, do it in harvestResultsFromPhysicsSimulation()
}
QByteArray MyAvatar::toByteArray(bool cullSmallChanges, bool sendAll) {
QByteArray MyAvatar::toByteArray(AvatarDataDetail dataDetail) {
CameraMode mode = qApp->getCamera()->getMode();
_globalPosition = getPosition();
_globalBoundingBoxCorner.x = _characterController.getCapsuleRadius();
@ -237,12 +237,12 @@ QByteArray MyAvatar::toByteArray(bool cullSmallChanges, bool sendAll) {
// fake the avatar position that is sent up to the AvatarMixer
glm::vec3 oldPosition = getPosition();
setPosition(getSkeletonPosition());
QByteArray array = AvatarData::toByteArray(cullSmallChanges, sendAll);
QByteArray array = AvatarData::toByteArray(dataDetail);
// copy the correct position back
setPosition(oldPosition);
return array;
}
return AvatarData::toByteArray(cullSmallChanges, sendAll);
return AvatarData::toByteArray(dataDetail);
}
void MyAvatar::centerBody() {

View file

@ -333,7 +333,7 @@ private:
glm::vec3 getWorldBodyPosition() const;
glm::quat getWorldBodyOrientation() const;
QByteArray toByteArray(bool cullSmallChanges, bool sendAll) override;
QByteArray toByteArray(AvatarDataDetail dataDetail) override;
void simulate(float deltaTime);
void updateFromTrackers(float deltaTime);
virtual void render(RenderArgs* renderArgs, const glm::vec3& cameraPositio) override;

View file

@ -5,15 +5,18 @@
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#include "TestScriptingInterface.h"
#include <QtCore/QCoreApplication>
#include <QtCore/QLoggingCategory>
#include <QtCore/QThread>
#include <DependencyManager.h>
#include <Trace.h>
#include <StatTracker.h>
#include <OffscreenUi.h>
#include "Application.h"
TestScriptingInterface* TestScriptingInterface::getInstance() {
static TestScriptingInterface sharedInstance;
@ -25,12 +28,47 @@ void TestScriptingInterface::quit() {
}
void TestScriptingInterface::waitForTextureIdle() {
waitForCondition(0, []()->bool {
return (0 == gpu::Context::getTextureGPUTransferCount());
});
}
void TestScriptingInterface::waitForDownloadIdle() {
waitForCondition(0, []()->bool {
return (0 == ResourceCache::getLoadingRequestCount()) && (0 == ResourceCache::getPendingRequestCount());
});
}
void TestScriptingInterface::waitForProcessingIdle() {
auto statTracker = DependencyManager::get<StatTracker>();
waitForCondition(0, [statTracker]()->bool {
return (0 == statTracker->getStat("Processing").toInt() && 0 == statTracker->getStat("PendingProcessing").toInt());
});
}
void TestScriptingInterface::waitIdle() {
// Initial wait for some incoming work
QThread::sleep(1);
waitForDownloadIdle();
waitForProcessingIdle();
waitForTextureIdle();
}
bool TestScriptingInterface::loadTestScene(QString scene) {
static const QString TEST_ROOT = "https://raw.githubusercontent.com/highfidelity/hifi_tests/master/";
static const QString TEST_BINARY_ROOT = "https://hifi-public.s3.amazonaws.com/test_scene_data/";
static const QString TEST_SCRIPTS_ROOT = TEST_ROOT + "scripts/";
static const QString TEST_SCENES_ROOT = TEST_ROOT + "scenes/";
return DependencyManager::get<OffscreenUi>()->returnFromUiThread([scene]()->QVariant {
ResourceManager::setUrlPrefixOverride("atp:/", TEST_BINARY_ROOT + scene + ".atp/");
auto tree = qApp->getEntities()->getTree();
auto treeIsClient = tree->getIsClient();
// Force the tree to accept the load regardless of permissions
tree->setIsClient(false);
auto result = tree->readFromURL(TEST_SCENES_ROOT + scene + ".json");
tree->setIsClient(treeIsClient);
return result;
}).toBool();
}
bool TestScriptingInterface::startTracing(QString logrules) {
@ -55,4 +93,35 @@ bool TestScriptingInterface::stopTracing(QString filename) {
tracer->stopTracing();
tracer->serialize(filename);
return true;
}
}
void TestScriptingInterface::clear() {
qApp->postLambdaEvent([] {
qApp->getEntities()->clear();
});
}
bool TestScriptingInterface::waitForConnection(qint64 maxWaitMs) {
// Wait for any previous connection to die
QThread::sleep(1);
return waitForCondition(maxWaitMs, []()->bool {
return DependencyManager::get<NodeList>()->getDomainHandler().isConnected();
});
}
void TestScriptingInterface::wait(int milliseconds) {
QThread::msleep(milliseconds);
}
bool TestScriptingInterface::waitForCondition(qint64 maxWaitMs, std::function<bool()> condition) {
QElapsedTimer elapsed;
elapsed.start();
while (!condition()) {
if (maxWaitMs > 0 && elapsed.elapsed() > maxWaitMs) {
return false;
}
QThread::msleep(1);
}
return condition();
}

View file

@ -10,6 +10,7 @@
#ifndef hifi_TestScriptingInterface_h
#define hifi_TestScriptingInterface_h
#include <functional>
#include <QtCore/QObject>
class TestScriptingInterface : public QObject {
@ -34,10 +35,24 @@ public slots:
void waitForDownloadIdle();
/**jsdoc
* Waits for all pending downloads and texture transfers to be complete
* Waits for all file parsing operations to be complete
*/
void waitForProcessingIdle();
/**jsdoc
* Waits for all pending downloads, parsing and texture transfers to be complete
*/
void waitIdle();
bool waitForConnection(qint64 maxWaitMs = 10000);
void wait(int milliseconds);
bool loadTestScene(QString sceneFile);
void clear();
/**jsdoc
* Start recording Chrome compatible tracing events
* logRules can be used to specify a set of logging category rules to limit what gets captured
@ -49,6 +64,9 @@ public slots:
* Using a filename with a .gz extension will automatically compress the output file
*/
bool stopTracing(QString filename);
private:
bool waitForCondition(qint64 maxWaitMs, std::function<bool()> condition);
};
#endif // hifi_TestScriptingInterface_h

View file

@ -91,7 +91,7 @@ void DiskCacheEditor::makeDialog() {
static const int REFRESH_INTERVAL = 100; // msec
_refreshTimer = new QTimer(_dialog);
_refreshTimer->setInterval(REFRESH_INTERVAL);
_refreshTimer->setInterval(REFRESH_INTERVAL); // Qt::CoarseTimer acceptable, no need for real time accuracy
_refreshTimer->setSingleShot(false);
QObject::connect(_refreshTimer.data(), &QTimer::timeout, this, &DiskCacheEditor::refresh);
_refreshTimer->start();

View file

@ -19,7 +19,6 @@ QString const Circle3DOverlay::TYPE = "circle3d";
Circle3DOverlay::Circle3DOverlay() {
memset(&_minorTickMarksColor, 0, sizeof(_minorTickMarksColor));
memset(&_majorTickMarksColor, 0, sizeof(_majorTickMarksColor));
qDebug() << "Building circle3d overlay";
}
Circle3DOverlay::Circle3DOverlay(const Circle3DOverlay* circle3DOverlay) :
@ -40,7 +39,6 @@ Circle3DOverlay::Circle3DOverlay(const Circle3DOverlay* circle3DOverlay) :
_majorTicksVerticesID(GeometryCache::UNKNOWN_ID),
_minorTicksVerticesID(GeometryCache::UNKNOWN_ID)
{
qDebug() << "Building circle3d overlay";
}
Circle3DOverlay::~Circle3DOverlay() {
@ -59,7 +57,6 @@ Circle3DOverlay::~Circle3DOverlay() {
geometryCache->releaseID(_minorTicksVerticesID);
}
}
qDebug() << "Destroying circle3d overlay";
}
void Circle3DOverlay::render(RenderArgs* args) {
if (!_visible) {

View file

@ -19,7 +19,6 @@ QString const Line3DOverlay::TYPE = "line3d";
Line3DOverlay::Line3DOverlay() :
_geometryCacheID(DependencyManager::get<GeometryCache>()->allocateID())
{
qDebug() << "Building line3D overlay";
}
Line3DOverlay::Line3DOverlay(const Line3DOverlay* line3DOverlay) :
@ -28,11 +27,9 @@ Line3DOverlay::Line3DOverlay(const Line3DOverlay* line3DOverlay) :
_end(line3DOverlay->_end),
_geometryCacheID(DependencyManager::get<GeometryCache>()->allocateID())
{
qDebug() << "Building line3D overlay";
}
Line3DOverlay::~Line3DOverlay() {
qDebug() << "Destryoing line3D overlay";
auto geometryCache = DependencyManager::get<GeometryCache>();
if (_geometryCacheID && geometryCache) {
geometryCache->releaseID(_geometryCacheID);

View file

@ -161,6 +161,7 @@ void Rig::destroyAnimGraph() {
_internalPoseSet._absolutePoses.clear();
_internalPoseSet._overridePoses.clear();
_internalPoseSet._overrideFlags.clear();
_numOverrides = 0;
}
void Rig::initJointStates(const FBXGeometry& geometry, const glm::mat4& modelOffset) {
@ -180,6 +181,7 @@ void Rig::initJointStates(const FBXGeometry& geometry, const glm::mat4& modelOff
_internalPoseSet._overrideFlags.clear();
_internalPoseSet._overrideFlags.resize(_animSkeleton->getNumJoints(), false);
_numOverrides = 0;
buildAbsoluteRigPoses(_animSkeleton->getRelativeDefaultPoses(), _absoluteDefaultPoses);
@ -207,6 +209,7 @@ void Rig::reset(const FBXGeometry& geometry) {
_internalPoseSet._overrideFlags.clear();
_internalPoseSet._overrideFlags.resize(_animSkeleton->getNumJoints(), false);
_numOverrides = 0;
buildAbsoluteRigPoses(_animSkeleton->getRelativeDefaultPoses(), _absoluteDefaultPoses);
@ -276,13 +279,17 @@ void Rig::setModelOffset(const glm::mat4& modelOffsetMat) {
void Rig::clearJointState(int index) {
if (isIndexValid(index)) {
_internalPoseSet._overrideFlags[index] = false;
if (_internalPoseSet._overrideFlags[index]) {
_internalPoseSet._overrideFlags[index] = false;
--_numOverrides;
}
_internalPoseSet._overridePoses[index] = _animSkeleton->getRelativeDefaultPose(index);
}
}
void Rig::clearJointStates() {
_internalPoseSet._overrideFlags.clear();
_numOverrides = 0;
if (_animSkeleton) {
_internalPoseSet._overrideFlags.resize(_animSkeleton->getNumJoints());
_internalPoseSet._overridePoses = _animSkeleton->getRelativeDefaultPoses();
@ -291,7 +298,10 @@ void Rig::clearJointStates() {
void Rig::clearJointAnimationPriority(int index) {
if (isIndexValid(index)) {
_internalPoseSet._overrideFlags[index] = false;
if (_internalPoseSet._overrideFlags[index]) {
_internalPoseSet._overrideFlags[index] = false;
--_numOverrides;
}
_internalPoseSet._overridePoses[index] = _animSkeleton->getRelativeDefaultPose(index);
}
}
@ -320,7 +330,10 @@ void Rig::setJointTranslation(int index, bool valid, const glm::vec3& translatio
if (isIndexValid(index)) {
if (valid) {
assert(_internalPoseSet._overrideFlags.size() == _internalPoseSet._overridePoses.size());
_internalPoseSet._overrideFlags[index] = true;
if (!_internalPoseSet._overrideFlags[index]) {
_internalPoseSet._overrideFlags[index] = true;
++_numOverrides;
}
_internalPoseSet._overridePoses[index].trans = translation;
}
}
@ -329,7 +342,10 @@ void Rig::setJointTranslation(int index, bool valid, const glm::vec3& translatio
void Rig::setJointState(int index, bool valid, const glm::quat& rotation, const glm::vec3& translation, float priority) {
if (isIndexValid(index)) {
assert(_internalPoseSet._overrideFlags.size() == _internalPoseSet._overridePoses.size());
_internalPoseSet._overrideFlags[index] = true;
if (!_internalPoseSet._overrideFlags[index]) {
_internalPoseSet._overrideFlags[index] = true;
++_numOverrides;
}
_internalPoseSet._overridePoses[index].rot = rotation;
_internalPoseSet._overridePoses[index].trans = translation;
}
@ -339,7 +355,10 @@ void Rig::setJointRotation(int index, bool valid, const glm::quat& rotation, flo
if (isIndexValid(index)) {
if (valid) {
ASSERT(_internalPoseSet._overrideFlags.size() == _internalPoseSet._overridePoses.size());
_internalPoseSet._overrideFlags[index] = true;
if (!_internalPoseSet._overrideFlags[index]) {
_internalPoseSet._overrideFlags[index] = true;
++_numOverrides;
}
_internalPoseSet._overridePoses[index].rot = rotation;
}
}
@ -518,7 +537,7 @@ void Rig::computeMotionAnimationState(float deltaTime, const glm::vec3& worldPos
// sine wave LFO var for testing.
static float t = 0.0f;
_animVars.set("sine", 2.0f * static_cast<float>(0.5 * sin(t) + 0.5));
_animVars.set("sine", 2.0f * 0.5f * sinf(t) + 0.5f);
float moveForwardAlpha = 0.0f;
float moveBackwardAlpha = 0.0f;
@ -884,10 +903,12 @@ void Rig::updateAnimationStateHandlers() { // called on avatar update thread (wh
void Rig::updateAnimations(float deltaTime, glm::mat4 rootTransform) {
PROFILE_RANGE_EX(simulation_animation, __FUNCTION__, 0xffff00ff, 0);
PerformanceTimer perfTimer("updateAnimations");
setModelOffset(rootTransform);
if (_animNode) {
PerformanceTimer perfTimer("handleTriggers");
updateAnimationStateHandlers();
_animVars.setRigToGeometryTransform(_rigToGeometryTransform);
@ -904,7 +925,6 @@ void Rig::updateAnimations(float deltaTime, glm::mat4 rootTransform) {
_animVars.setTrigger(trigger);
}
}
applyOverridePoses();
buildAbsoluteRigPoses(_internalPoseSet._relativePoses, _internalPoseSet._absolutePoses);
@ -1176,7 +1196,8 @@ bool Rig::getModelRegistrationPoint(glm::vec3& modelRegistrationPointOut) const
}
void Rig::applyOverridePoses() {
if (!_animSkeleton) {
PerformanceTimer perfTimer("override");
if (_numOverrides == 0 || !_animSkeleton) {
return;
}
@ -1192,28 +1213,24 @@ void Rig::applyOverridePoses() {
}
void Rig::buildAbsoluteRigPoses(const AnimPoseVec& relativePoses, AnimPoseVec& absolutePosesOut) {
PerformanceTimer perfTimer("buildAbsolute");
if (!_animSkeleton) {
return;
}
ASSERT(_animSkeleton->getNumJoints() == (int)relativePoses.size());
// flatten all poses out so they are absolute not relative
absolutePosesOut.resize(relativePoses.size());
AnimPose geometryToRigTransform(_geometryToRigTransform);
for (int i = 0; i < (int)relativePoses.size(); i++) {
int parentIndex = _animSkeleton->getParentIndex(i);
if (parentIndex == -1) {
absolutePosesOut[i] = relativePoses[i];
// transform all root absolute poses into rig space
absolutePosesOut[i] = geometryToRigTransform * relativePoses[i];
} else {
absolutePosesOut[i] = absolutePosesOut[parentIndex] * relativePoses[i];
}
}
// transform all absolute poses into rig space.
AnimPose geometryToRigTransform(_geometryToRigTransform);
for (int i = 0; i < (int)absolutePosesOut.size(); i++) {
absolutePosesOut[i] = geometryToRigTransform * absolutePosesOut[i];
}
}
glm::mat4 Rig::getJointTransform(int jointIndex) const {
@ -1251,62 +1268,36 @@ void Rig::copyJointsIntoJointData(QVector<JointData>& jointDataVec) const {
void Rig::copyJointsFromJointData(const QVector<JointData>& jointDataVec) {
PerformanceTimer perfTimer("copyJoints");
if (_animSkeleton && jointDataVec.size() == (int)_internalPoseSet._overrideFlags.size()) {
// transform all the default poses into rig space.
const AnimPose geometryToRigPose(_geometryToRigTransform);
std::vector<bool> overrideFlags(_internalPoseSet._overridePoses.size(), false);
// start with the default rotations in absolute rig frame
if (_animSkeleton && jointDataVec.size() == (int)_internalPoseSet._relativePoses.size()) {
// make a vector of rotations in absolute-geometry-frame
const AnimPoseVec& absoluteDefaultPoses = _animSkeleton->getAbsoluteDefaultPoses();
std::vector<glm::quat> rotations;
rotations.reserve(_animSkeleton->getAbsoluteDefaultPoses().size());
for (auto& pose : _animSkeleton->getAbsoluteDefaultPoses()) {
rotations.push_back(geometryToRigPose.rot * pose.rot);
}
// start translations in relative frame but scaled to meters.
std::vector<glm::vec3> translations;
translations.reserve(_animSkeleton->getRelativeDefaultPoses().size());
for (auto& pose : _animSkeleton->getRelativeDefaultPoses()) {
translations.push_back(_geometryOffset.scale * pose.trans);
}
ASSERT(overrideFlags.size() == rotations.size());
// copy over rotations from the jointDataVec, which is also in absolute rig frame
const glm::quat rigToGeometryRot(glmExtractRotation(_rigToGeometryTransform));
for (int i = 0; i < jointDataVec.size(); i++) {
if (isIndexValid(i)) {
const JointData& data = jointDataVec.at(i);
if (data.rotationSet) {
overrideFlags[i] = true;
rotations[i] = data.rotation;
}
if (data.translationSet) {
overrideFlags[i] = true;
translations[i] = data.translation;
}
const JointData& data = jointDataVec.at(i);
if (data.rotationSet) {
// JointData rotations are in absolute rig-frame so we rotate them to absolute geometry-frame
rotations.push_back(rigToGeometryRot * data.rotation);
} else {
rotations.push_back(absoluteDefaultPoses[i].rot);
}
}
ASSERT(_internalPoseSet._overrideFlags.size() == _internalPoseSet._overridePoses.size());
// convert resulting rotations into geometry space.
const glm::quat rigToGeometryRot(glmExtractRotation(_rigToGeometryTransform));
for (auto& rot : rotations) {
rot = rigToGeometryRot * rot;
}
// convert all rotations from absolute to parent relative.
// convert rotations from absolute to parent relative.
_animSkeleton->convertAbsoluteRotationsToRelative(rotations);
// copy the geometry space parent relative poses into _overridePoses
// store new relative poses
const AnimPoseVec& relativeDefaultPoses = _animSkeleton->getRelativeDefaultPoses();
for (int i = 0; i < jointDataVec.size(); i++) {
if (overrideFlags[i]) {
_internalPoseSet._overrideFlags[i] = true;
_internalPoseSet._overridePoses[i].scale = Vectors::ONE;
_internalPoseSet._overridePoses[i].rot = rotations[i];
// scale translations from meters back into geometry units.
_internalPoseSet._overridePoses[i].trans = _invGeometryOffset.scale * translations[i];
const JointData& data = jointDataVec.at(i);
_internalPoseSet._relativePoses[i].scale = Vectors::ONE;
_internalPoseSet._relativePoses[i].rot = rotations[i];
if (data.translationSet) {
// JointData translations are in scaled relative-frame so we scale back to regular relative-frame
_internalPoseSet._relativePoses[i].trans = _invGeometryOffset.scale * data.translation;
} else {
_internalPoseSet._relativePoses[i].trans = relativeDefaultPoses[i].trans;
}
}
}

View file

@ -311,6 +311,7 @@ protected:
std::map<QString, AnimNode::Pointer> _origRoleAnimations;
int32_t _numOverrides { 0 };
bool _lastEnableInverseKinematics { true };
bool _enableInverseKinematics { true };

View file

@ -16,6 +16,14 @@
#include "AudioHRTF.h"
#include "AudioHRTFData.h"
#if defined(_MSC_VER)
#define ALIGN32 __declspec(align(32))
#elif defined(__GNUC__)
#define ALIGN32 __attribute__((aligned(32)))
#else
#define ALIGN32
#endif
#ifndef MAX
#define MAX(a,b) (((a) > (b)) ? (a) : (b))
#endif
@ -30,7 +38,7 @@
// Transients in the time-varying Thiran allpass filter are eliminated by the initial delay.
// Valimaki, Laakso. "Elimination of Transients in Time-Varying Allpass Fractional Delay Filters"
//
static const float crossfadeTable[HRTF_BLOCK] = {
ALIGN32 static const float crossfadeTable[HRTF_BLOCK] = {
1.0000000000f, 1.0000000000f, 1.0000000000f, 1.0000000000f, 1.0000000000f, 1.0000000000f, 1.0000000000f, 1.0000000000f,
0.9999545513f, 0.9998182135f, 0.9995910114f, 0.9992729863f, 0.9988641959f, 0.9983647147f, 0.9977746334f, 0.9970940592f,
0.9963231160f, 0.9954619438f, 0.9945106993f, 0.9934695553f, 0.9923387012f, 0.9911183425f, 0.9898087010f, 0.9884100149f,
@ -192,25 +200,29 @@ static void FIR_1x4_SSE(float* src, float* dst0, float* dst1, float* dst2, float
for (int k = 0; k < HRTF_TAPS; k += 4) {
acc0 = _mm_add_ps(acc0, _mm_mul_ps(_mm_load1_ps(&coef0[-k-0]), _mm_loadu_ps(&ps[k+0])));
acc1 = _mm_add_ps(acc1, _mm_mul_ps(_mm_load1_ps(&coef1[-k-0]), _mm_loadu_ps(&ps[k+0])));
acc2 = _mm_add_ps(acc2, _mm_mul_ps(_mm_load1_ps(&coef2[-k-0]), _mm_loadu_ps(&ps[k+0])));
acc3 = _mm_add_ps(acc3, _mm_mul_ps(_mm_load1_ps(&coef3[-k-0]), _mm_loadu_ps(&ps[k+0])));
__m128 x0 = _mm_loadu_ps(&ps[k+0]);
acc0 = _mm_add_ps(acc0, _mm_mul_ps(_mm_load1_ps(&coef0[-k-0]), x0));
acc1 = _mm_add_ps(acc1, _mm_mul_ps(_mm_load1_ps(&coef1[-k-0]), x0));
acc2 = _mm_add_ps(acc2, _mm_mul_ps(_mm_load1_ps(&coef2[-k-0]), x0));
acc3 = _mm_add_ps(acc3, _mm_mul_ps(_mm_load1_ps(&coef3[-k-0]), x0));
acc0 = _mm_add_ps(acc0, _mm_mul_ps(_mm_load1_ps(&coef0[-k-1]), _mm_loadu_ps(&ps[k+1])));
acc1 = _mm_add_ps(acc1, _mm_mul_ps(_mm_load1_ps(&coef1[-k-1]), _mm_loadu_ps(&ps[k+1])));
acc2 = _mm_add_ps(acc2, _mm_mul_ps(_mm_load1_ps(&coef2[-k-1]), _mm_loadu_ps(&ps[k+1])));
acc3 = _mm_add_ps(acc3, _mm_mul_ps(_mm_load1_ps(&coef3[-k-1]), _mm_loadu_ps(&ps[k+1])));
__m128 x1 = _mm_loadu_ps(&ps[k+1]);
acc0 = _mm_add_ps(acc0, _mm_mul_ps(_mm_load1_ps(&coef0[-k-1]), x1));
acc1 = _mm_add_ps(acc1, _mm_mul_ps(_mm_load1_ps(&coef1[-k-1]), x1));
acc2 = _mm_add_ps(acc2, _mm_mul_ps(_mm_load1_ps(&coef2[-k-1]), x1));
acc3 = _mm_add_ps(acc3, _mm_mul_ps(_mm_load1_ps(&coef3[-k-1]), x1));
acc0 = _mm_add_ps(acc0, _mm_mul_ps(_mm_load1_ps(&coef0[-k-2]), _mm_loadu_ps(&ps[k+2])));
acc1 = _mm_add_ps(acc1, _mm_mul_ps(_mm_load1_ps(&coef1[-k-2]), _mm_loadu_ps(&ps[k+2])));
acc2 = _mm_add_ps(acc2, _mm_mul_ps(_mm_load1_ps(&coef2[-k-2]), _mm_loadu_ps(&ps[k+2])));
acc3 = _mm_add_ps(acc3, _mm_mul_ps(_mm_load1_ps(&coef3[-k-2]), _mm_loadu_ps(&ps[k+2])));
__m128 x2 = _mm_loadu_ps(&ps[k+2]);
acc0 = _mm_add_ps(acc0, _mm_mul_ps(_mm_load1_ps(&coef0[-k-2]), x2));
acc1 = _mm_add_ps(acc1, _mm_mul_ps(_mm_load1_ps(&coef1[-k-2]), x2));
acc2 = _mm_add_ps(acc2, _mm_mul_ps(_mm_load1_ps(&coef2[-k-2]), x2));
acc3 = _mm_add_ps(acc3, _mm_mul_ps(_mm_load1_ps(&coef3[-k-2]), x2));
acc0 = _mm_add_ps(acc0, _mm_mul_ps(_mm_load1_ps(&coef0[-k-3]), _mm_loadu_ps(&ps[k+3])));
acc1 = _mm_add_ps(acc1, _mm_mul_ps(_mm_load1_ps(&coef1[-k-3]), _mm_loadu_ps(&ps[k+3])));
acc2 = _mm_add_ps(acc2, _mm_mul_ps(_mm_load1_ps(&coef2[-k-3]), _mm_loadu_ps(&ps[k+3])));
acc3 = _mm_add_ps(acc3, _mm_mul_ps(_mm_load1_ps(&coef3[-k-3]), _mm_loadu_ps(&ps[k+3])));
__m128 x3 = _mm_loadu_ps(&ps[k+3]);
acc0 = _mm_add_ps(acc0, _mm_mul_ps(_mm_load1_ps(&coef0[-k-3]), x3));
acc1 = _mm_add_ps(acc1, _mm_mul_ps(_mm_load1_ps(&coef1[-k-3]), x3));
acc2 = _mm_add_ps(acc2, _mm_mul_ps(_mm_load1_ps(&coef2[-k-3]), x3));
acc3 = _mm_add_ps(acc3, _mm_mul_ps(_mm_load1_ps(&coef3[-k-3]), x3));
}
_mm_storeu_ps(&dst0[i], acc0);
@ -226,11 +238,11 @@ static void FIR_1x4_SSE(float* src, float* dst0, float* dst1, float* dst2, float
#include "CPUDetect.h"
void FIR_1x4_AVX(float* src, float* dst0, float* dst1, float* dst2, float* dst3, float coef[4][HRTF_TAPS], int numFrames);
void FIR_1x4_AVX2(float* src, float* dst0, float* dst1, float* dst2, float* dst3, float coef[4][HRTF_TAPS], int numFrames);
static void FIR_1x4(float* src, float* dst0, float* dst1, float* dst2, float* dst3, float coef[4][HRTF_TAPS], int numFrames) {
static auto f = cpuSupportsAVX() ? FIR_1x4_AVX : FIR_1x4_SSE;
static auto f = cpuSupportsAVX2() ? FIR_1x4_AVX2 : FIR_1x4_SSE;
(*f)(src, dst0, dst1, dst2, dst3, coef, numFrames); // dispatch
}
@ -842,12 +854,12 @@ void AudioHRTF::render(int16_t* input, float* output, int index, float azimuth,
assert(index < HRTF_TABLES);
assert(numFrames == HRTF_BLOCK);
float in[HRTF_TAPS + HRTF_BLOCK]; // mono
float firCoef[4][HRTF_TAPS]; // 4-channel
float firBuffer[4][HRTF_DELAY + HRTF_BLOCK]; // 4-channel
float bqCoef[5][8]; // 4-channel (interleaved)
float bqBuffer[4 * HRTF_BLOCK]; // 4-channel (interleaved)
int delay[4]; // 4-channel (interleaved)
ALIGN32 float in[HRTF_TAPS + HRTF_BLOCK]; // mono
ALIGN32 float firCoef[4][HRTF_TAPS]; // 4-channel
ALIGN32 float firBuffer[4][HRTF_DELAY + HRTF_BLOCK]; // 4-channel
ALIGN32 float bqCoef[5][8]; // 4-channel (interleaved)
ALIGN32 float bqBuffer[4 * HRTF_BLOCK]; // 4-channel (interleaved)
int delay[4]; // 4-channel (interleaved)
// to avoid polluting the cache, old filters are recomputed instead of stored
setFilters(firCoef, bqCoef, delay, index, _azimuthState, _distanceState, _gainState, L0);

View file

@ -30,6 +30,14 @@
// 6) Truncate filter length to 2.5ms using rectangular window with 8-tap Hanning taper
//
#if defined(_MSC_VER)
#define ALIGN32 __declspec(align(32))
#elif defined(__GNUC__)
#define ALIGN32 __attribute__((aligned(32)))
#else
#define ALIGN32
#endif
static const float itd_1002_table[HRTF_AZIMUTHS] = {
-0.07851f, 0.85414f, 1.77170f, 2.71137f, 3.71065f, 4.74907f, 5.79892f, 6.82396f,
7.82837f, 8.80796f, 9.75426f, 10.68332f, 11.59979f, 12.48520f, 13.36135f, 14.19234f,
@ -42,7 +50,7 @@ static const float itd_1002_table[HRTF_AZIMUTHS] = {
-8.39670f, -7.23606f, -6.09663f, -5.05593f, -4.06186f, -3.07465f, -2.06122f, -1.05417f,
};
static const float ir_1002_table[HRTF_AZIMUTHS][2][HRTF_TAPS] = {
ALIGN32 static const float ir_1002_table[HRTF_AZIMUTHS][2][HRTF_TAPS] = {
// azimuth = 0
{{
8.341559e-01f, 1.886116e-02f, 2.677664e-01f, -7.037183e-02f, -4.147236e-02f, -2.761588e-01f, 2.310035e-01f, -1.643133e-01f,
@ -1497,7 +1505,7 @@ static const float itd_1003_table[HRTF_AZIMUTHS] = {
-6.64380f, -5.73462f, -4.83364f, -3.97025f, -3.08925f, -2.16621f, -1.19364f, -0.20709f,
};
static const float ir_1003_table[HRTF_AZIMUTHS][2][HRTF_TAPS] = {
ALIGN32 static const float ir_1003_table[HRTF_AZIMUTHS][2][HRTF_TAPS] = {
// azimuth = 0
{{
9.266240e-01f, 1.260510e-01f, 5.051008e-02f, -3.536678e-01f, 2.462246e-02f, 4.465557e-02f, 6.813228e-02f, -6.063477e-02f,
@ -2952,7 +2960,7 @@ static const float itd_1004_table[HRTF_AZIMUTHS] = {
-7.55720f, -6.55578f, -5.59246f, -4.69657f, -3.80733f, -2.88567f, -1.90337f, -0.89923f,
};
static const float ir_1004_table[HRTF_AZIMUTHS][2][HRTF_TAPS] = {
ALIGN32 static const float ir_1004_table[HRTF_AZIMUTHS][2][HRTF_TAPS] = {
// azimuth = 0
{{
7.326633e-01f, 4.279429e-01f, -5.910516e-02f, -2.480760e-01f, -9.903029e-02f, 9.215562e-02f, -2.893536e-02f, 5.464364e-02f,
@ -4407,7 +4415,7 @@ static const float itd_1005_table[HRTF_AZIMUTHS] = {
-6.80079f, -6.03878f, -5.25100f, -4.34973f, -3.39268f, -2.41226f, -1.45444f, -0.50375f,
};
static const float ir_1005_table[HRTF_AZIMUTHS][2][HRTF_TAPS] = {
ALIGN32 static const float ir_1005_table[HRTF_AZIMUTHS][2][HRTF_TAPS] = {
// azimuth = 0
{{
8.515557e-01f, 1.208618e-01f, 3.238278e-01f, -3.605847e-01f, -3.354420e-02f, -1.829174e-01f, 2.309960e-01f, -1.744711e-01f,
@ -5862,7 +5870,7 @@ static const float itd_1007_table[HRTF_AZIMUTHS] = {
-7.68135f, -6.69801f, -5.72186f, -4.72708f, -3.74413f, -2.77373f, -1.79032f, -0.81823f,
};
static const float ir_1007_table[HRTF_AZIMUTHS][2][HRTF_TAPS] = {
ALIGN32 static const float ir_1007_table[HRTF_AZIMUTHS][2][HRTF_TAPS] = {
// azimuth = 0
{{
6.544936e-01f, 2.820574e-01f, 1.850652e-01f, -2.597811e-01f, -5.585250e-02f, -7.975905e-02f, 8.143960e-02f, -5.044548e-02f,
@ -7317,7 +7325,7 @@ static const float itd_1012_table[HRTF_AZIMUTHS] = {
-7.32159f, -6.30684f, -5.31969f, -4.40260f, -3.50567f, -2.60925f, -1.70893f, -0.80401f,
};
static const float ir_1012_table[HRTF_AZIMUTHS][2][HRTF_TAPS] = {
ALIGN32 static const float ir_1012_table[HRTF_AZIMUTHS][2][HRTF_TAPS] = {
// azimuth = 0
{{
8.505165e-01f, 9.074762e-02f, 3.296598e-01f, -5.213905e-01f, 1.348379e-01f, -1.828924e-01f, 1.400077e-01f, -4.071996e-02f,
@ -8772,7 +8780,7 @@ static const float itd_1014_table[HRTF_AZIMUTHS] = {
-7.51312f, -6.52705f, -5.56262f, -4.72113f, -3.90664f, -3.07768f, -2.22719f, -1.37514f,
};
static const float ir_1014_table[HRTF_AZIMUTHS][2][HRTF_TAPS] = {
ALIGN32 static const float ir_1014_table[HRTF_AZIMUTHS][2][HRTF_TAPS] = {
// azimuth = 0
{{
6.542071e-01f, 4.575563e-01f, 1.118072e-02f, -1.823464e-01f, -2.222339e-01f, 1.371357e-01f, 7.027919e-03f, -5.534852e-02f,
@ -10227,7 +10235,7 @@ static const float itd_1017_table[HRTF_AZIMUTHS] = {
-7.46925f, -6.49073f, -5.52501f, -4.62178f, -3.74041f, -2.86207f, -1.97362f, -1.07512f,
};
static const float ir_1017_table[HRTF_AZIMUTHS][2][HRTF_TAPS] = {
ALIGN32 static const float ir_1017_table[HRTF_AZIMUTHS][2][HRTF_TAPS] = {
// azimuth = 0
{{
7.470867e-01f, 2.686078e-01f, 2.097923e-01f, -2.935018e-01f, -8.687224e-02f, -4.547367e-02f, 6.920631e-03f, 3.752071e-02f,
@ -11682,7 +11690,7 @@ static const float itd_1020_table[HRTF_AZIMUTHS] = {
-8.28071f, -7.36311f, -6.43732f, -5.49298f, -4.53728f, -3.57601f, -2.59830f, -1.63297f,
};
static const float ir_1020_table[HRTF_AZIMUTHS][2][HRTF_TAPS] = {
ALIGN32 static const float ir_1020_table[HRTF_AZIMUTHS][2][HRTF_TAPS] = {
// azimuth = 0
{{
6.953847e-01f, 3.081256e-01f, 2.474324e-01f, -3.025226e-01f, -1.119181e-01f, -4.966299e-02f, 5.727889e-02f, 6.715016e-03f,
@ -13137,7 +13145,7 @@ static const float itd_1021_table[HRTF_AZIMUTHS] = {
-8.12772f, -7.17689f, -6.23068f, -5.27554f, -4.32391f, -3.38489f, -2.46445f, -1.54407f,
};
static const float ir_1021_table[HRTF_AZIMUTHS][2][HRTF_TAPS] = {
ALIGN32 static const float ir_1021_table[HRTF_AZIMUTHS][2][HRTF_TAPS] = {
// azimuth = 0
{{
7.807186e-01f, 3.835520e-01f, 1.208801e-01f, -4.044311e-01f, -5.188029e-02f, -7.750225e-02f, 1.739668e-01f, -6.599168e-02f,
@ -14592,7 +14600,7 @@ static const float itd_1022_table[HRTF_AZIMUTHS] = {
-7.19675f, -6.30334f, -5.39609f, -4.47018f, -3.53964f, -2.62393f, -1.75389f, -0.90222f,
};
static const float ir_1022_table[HRTF_AZIMUTHS][2][HRTF_TAPS] = {
ALIGN32 static const float ir_1022_table[HRTF_AZIMUTHS][2][HRTF_TAPS] = {
// azimuth = 0
{{
7.053226e-01f, 2.645844e-01f, 2.462055e-01f, -2.145682e-01f, -1.333283e-01f, -1.751403e-01f, 2.721890e-01f, -1.743790e-01f,
@ -16047,7 +16055,7 @@ static const float itd_1026_table[HRTF_AZIMUTHS] = {
-7.45209f, -6.46598f, -5.49746f, -4.54220f, -3.60610f, -2.68084f, -1.74087f, -0.80841f,
};
static const float ir_1026_table[HRTF_AZIMUTHS][2][HRTF_TAPS] = {
ALIGN32 static const float ir_1026_table[HRTF_AZIMUTHS][2][HRTF_TAPS] = {
// azimuth = 0
{{
7.150396e-01f, 3.144234e-01f, 9.132840e-02f, -2.128668e-01f, -1.899010e-01f, 1.362356e-01f, -4.105226e-02f, 4.896281e-02f,
@ -17502,7 +17510,7 @@ static const float itd_1028_table[HRTF_AZIMUTHS] = {
-7.80099f, -6.89255f, -5.95721f, -5.04107f, -4.11968f, -3.20233f, -2.33316f, -1.46289f,
};
static const float ir_1028_table[HRTF_AZIMUTHS][2][HRTF_TAPS] = {
ALIGN32 static const float ir_1028_table[HRTF_AZIMUTHS][2][HRTF_TAPS] = {
// azimuth = 0
{{
9.491360e-01f, 2.952796e-01f, -1.585342e-01f, -3.497386e-01f, 1.204260e-01f, -4.886012e-02f, 5.238760e-02f, -8.209077e-03f,
@ -18957,7 +18965,7 @@ static const float itd_1038_table[HRTF_AZIMUTHS] = {
-6.69661f, -5.65906f, -4.62851f, -3.63493f, -2.66802f, -1.71997f, -0.76853f, 0.18497f,
};
static const float ir_1038_table[HRTF_AZIMUTHS][2][HRTF_TAPS] = {
ALIGN32 static const float ir_1038_table[HRTF_AZIMUTHS][2][HRTF_TAPS] = {
// azimuth = 0
{{
9.325991e-01f, 1.817283e-01f, 5.397613e-02f, -4.121773e-01f, -7.921759e-03f, -4.009945e-02f, 1.499187e-01f, -1.838252e-02f,
@ -20412,7 +20420,7 @@ static const float itd_1041_table[HRTF_AZIMUTHS] = {
-7.03257f, -6.07458f, -5.13664f, -4.24453f, -3.37177f, -2.49083f, -1.55807f, -0.62014f,
};
static const float ir_1041_table[HRTF_AZIMUTHS][2][HRTF_TAPS] = {
ALIGN32 static const float ir_1041_table[HRTF_AZIMUTHS][2][HRTF_TAPS] = {
// azimuth = 0
{{
7.012368e-01f, 2.006662e-01f, 3.173636e-01f, -2.865733e-01f, 1.345042e-01f, -5.030394e-01f, 3.717757e-01f, -1.138039e-01f,
@ -21867,7 +21875,7 @@ static const float itd_1042_table[HRTF_AZIMUTHS] = {
-7.79822f, -6.84403f, -5.88862f, -4.94525f, -3.99704f, -3.03547f, -2.06207f, -1.07916f,
};
static const float ir_1042_table[HRTF_AZIMUTHS][2][HRTF_TAPS] = {
ALIGN32 static const float ir_1042_table[HRTF_AZIMUTHS][2][HRTF_TAPS] = {
// azimuth = 0
{{
9.114429e-01f, 2.201994e-03f, 3.703525e-01f, -4.825957e-01f, 1.210277e-01f, -2.471091e-01f, 1.766662e-01f, -5.840113e-03f,
@ -23322,7 +23330,7 @@ static const float itd_1043_table[HRTF_AZIMUTHS] = {
-6.81973f, -5.86664f, -4.92096f, -3.99232f, -3.07973f, -2.16321f, -1.20142f, -0.22538f,
};
static const float ir_1043_table[HRTF_AZIMUTHS][2][HRTF_TAPS] = {
ALIGN32 static const float ir_1043_table[HRTF_AZIMUTHS][2][HRTF_TAPS] = {
// azimuth = 0
{{
7.339447e-01f, 1.339343e-01f, 4.031645e-01f, -4.891909e-01f, 8.751389e-02f, -2.110783e-01f, 2.573841e-01f, -1.050324e-01f,
@ -24777,7 +24785,7 @@ static const float itd_1044_table[HRTF_AZIMUTHS] = {
-7.31965f, -6.37963f, -5.45379f, -4.54748f, -3.59370f, -2.59525f, -1.67705f, -0.73882f,
};
static const float ir_1044_table[HRTF_AZIMUTHS][2][HRTF_TAPS] = {
ALIGN32 static const float ir_1044_table[HRTF_AZIMUTHS][2][HRTF_TAPS] = {
// azimuth = 0
{{
7.028871e-01f, 2.381998e-01f, 4.686725e-01f, -5.412304e-01f, 1.262568e-01f, -3.198619e-01f, 1.963468e-01f, -4.016186e-02f,
@ -26232,7 +26240,7 @@ static const float itd_1047_table[HRTF_AZIMUTHS] = {
-9.01225f, -7.93667f, -6.85884f, -5.78919f, -4.72064f, -3.66640f, -2.66295f, -1.65780f,
};
static const float ir_1047_table[HRTF_AZIMUTHS][2][HRTF_TAPS] = {
ALIGN32 static const float ir_1047_table[HRTF_AZIMUTHS][2][HRTF_TAPS] = {
// azimuth = 0
{{
7.788578e-01f, 1.598904e-01f, 2.366520e-01f, -3.524184e-01f, -8.784474e-03f, -5.144472e-02f, 8.679429e-02f, -1.634258e-02f,
@ -27687,7 +27695,7 @@ static const float itd_1048_table[HRTF_AZIMUTHS] = {
-7.15985f, -6.30472f, -5.41513f, -4.54994f, -3.62385f, -2.66142f, -1.79111f, -0.94033f,
};
static const float ir_1048_table[HRTF_AZIMUTHS][2][HRTF_TAPS] = {
ALIGN32 static const float ir_1048_table[HRTF_AZIMUTHS][2][HRTF_TAPS] = {
// azimuth = 0
{{
8.865287e-01f, 2.972076e-01f, -1.305391e-01f, -1.213860e-01f, -1.948535e-01f, 1.458427e-01f, -8.912857e-02f, 9.493978e-02f,
@ -29142,7 +29150,7 @@ static const float itd_1050_table[HRTF_AZIMUTHS] = {
-6.52690f, -5.58085f, -4.64474f, -3.71658f, -2.80444f, -1.92096f, -1.07543f, -0.23450f,
};
static const float ir_1050_table[HRTF_AZIMUTHS][2][HRTF_TAPS] = {
ALIGN32 static const float ir_1050_table[HRTF_AZIMUTHS][2][HRTF_TAPS] = {
// azimuth = 0
{{
9.005889e-01f, -6.452200e-02f, 3.675525e-01f, -4.309962e-01f, 7.086621e-02f, -9.161573e-02f, -4.290351e-02f, 9.057393e-02f,
@ -30597,7 +30605,7 @@ static const float itd_1052_table[HRTF_AZIMUTHS] = {
-6.50194f, -5.61262f, -4.72534f, -3.84869f, -2.97504f, -2.10269f, -1.23783f, -0.36766f,
};
static const float ir_1052_table[HRTF_AZIMUTHS][2][HRTF_TAPS] = {
ALIGN32 static const float ir_1052_table[HRTF_AZIMUTHS][2][HRTF_TAPS] = {
// azimuth = 0
{{
6.650009e-01f, 3.507944e-01f, -3.274164e-02f, -1.830690e-01f, -7.720853e-02f, 1.030789e-01f, 3.877069e-02f, -5.674440e-02f,
@ -32052,7 +32060,7 @@ static const float itd_1054_table[HRTF_AZIMUTHS] = {
-7.35642f, -6.36606f, -5.37262f, -4.40394f, -3.44967f, -2.51333f, -1.59834f, -0.68300f,
};
static const float ir_1054_table[HRTF_AZIMUTHS][2][HRTF_TAPS] = {
ALIGN32 static const float ir_1054_table[HRTF_AZIMUTHS][2][HRTF_TAPS] = {
// azimuth = 0
{{
8.629450e-01f, 1.677356e-01f, 1.467365e-01f, -3.248726e-01f, -5.105235e-02f, -5.031096e-02f, 1.796471e-01f, -1.298094e-01f,
@ -33507,7 +33515,7 @@ static const float itd_1056_table[HRTF_AZIMUTHS] = {
-6.99437f, -5.82430f, -4.73408f, -3.76713f, -2.88870f, -2.05251f, -1.18172f, -0.32736f,
};
static const float ir_1056_table[HRTF_AZIMUTHS][2][HRTF_TAPS] = {
ALIGN32 static const float ir_1056_table[HRTF_AZIMUTHS][2][HRTF_TAPS] = {
// azimuth = 0
{{
8.031418e-01f, 2.411323e-01f, 1.417951e-01f, -2.476192e-01f, -1.076012e-01f, 1.009190e-01f, 7.761394e-02f, -1.250722e-01f,
@ -34962,7 +34970,7 @@ static const float itd_1058_table[HRTF_AZIMUTHS] = {
-7.78555f, -6.81447f, -5.85685f, -4.89466f, -3.93902f, -2.98660f, -2.01925f, -1.05758f,
};
static const float ir_1058_table[HRTF_AZIMUTHS][2][HRTF_TAPS] = {
ALIGN32 static const float ir_1058_table[HRTF_AZIMUTHS][2][HRTF_TAPS] = {
// azimuth = 0
{{
9.307292e-01f, 5.592706e-02f, 2.567367e-01f, -4.525413e-01f, 1.378666e-01f, -2.503950e-01f, 1.983286e-01f, 5.925522e-03f,

View file

@ -208,7 +208,7 @@ qint64 writeStringToStream(const QString& string, QDataStream& stream) {
int64_t AudioInjector::injectNextFrame() {
if (stateHas(AudioInjectorState::NetworkInjectionFinished)) {
qDebug() << "AudioInjector::injectNextFrame called but AudioInjector has finished and was not restarted. Returning.";
qCDebug(audio) << "AudioInjector::injectNextFrame called but AudioInjector has finished and was not restarted. Returning.";
return NEXT_FRAME_DELTA_ERROR_OR_FINISHED;
}
@ -231,7 +231,7 @@ int64_t AudioInjector::injectNextFrame() {
auto numSamples = static_cast<int>(_audioData.size() / sampleSize);
auto targetSize = numSamples * sampleSize;
if (targetSize != _audioData.size()) {
qDebug() << "Resizing audio that doesn't end at multiple of sample size, resizing from "
qCDebug(audio) << "Resizing audio that doesn't end at multiple of sample size, resizing from "
<< _audioData.size() << " to " << targetSize;
_audioData.resize(targetSize);
}
@ -297,7 +297,7 @@ int64_t AudioInjector::injectNextFrame() {
} else {
// no samples to inject, return immediately
qDebug() << "AudioInjector::injectNextFrame() called with no samples to inject. Returning.";
qCDebug(audio) << "AudioInjector::injectNextFrame() called with no samples to inject. Returning.";
return NEXT_FRAME_DELTA_ERROR_OR_FINISHED;
}
}
@ -388,7 +388,7 @@ int64_t AudioInjector::injectNextFrame() {
if (currentFrameBasedOnElapsedTime - _nextFrame > MAX_ALLOWED_FRAMES_TO_FALL_BEHIND) {
// If we are falling behind by more frames than our threshold, let's skip the frames ahead
qDebug() << this << "injectNextFrame() skipping ahead, fell behind by " << (currentFrameBasedOnElapsedTime - _nextFrame) << " frames";
qCDebug(audio) << this << "injectNextFrame() skipping ahead, fell behind by " << (currentFrameBasedOnElapsedTime - _nextFrame) << " frames";
_nextFrame = currentFrameBasedOnElapsedTime;
_currentSendOffset = _nextFrame * AudioConstants::NETWORK_FRAME_BYTES_PER_CHANNEL * (_options.stereo ? 2 : 1) % _audioData.size();
}

View file

@ -17,6 +17,7 @@
#include "AudioConstants.h"
#include "AudioInjector.h"
#include "AudioLogging.h"
AudioInjectorManager::~AudioInjectorManager() {
_shouldStop = true;
@ -131,7 +132,7 @@ static const int MAX_INJECTORS_PER_THREAD = 40; // calculated based on AudioInje
bool AudioInjectorManager::wouldExceedLimits() { // Should be called inside of a lock.
if (_injectors.size() >= MAX_INJECTORS_PER_THREAD) {
qDebug() << "AudioInjectorManager::threadInjector could not thread AudioInjector - at max of"
qCDebug(audio) << "AudioInjectorManager::threadInjector could not thread AudioInjector - at max of"
<< MAX_INJECTORS_PER_THREAD << "current audio injectors.";
return true;
}
@ -140,7 +141,7 @@ bool AudioInjectorManager::wouldExceedLimits() { // Should be called inside of a
bool AudioInjectorManager::threadInjector(AudioInjector* injector) {
if (_shouldStop) {
qDebug() << "AudioInjectorManager::threadInjector asked to thread injector but is shutting down.";
qCDebug(audio) << "AudioInjectorManager::threadInjector asked to thread injector but is shutting down.";
return false;
}
@ -169,7 +170,7 @@ bool AudioInjectorManager::threadInjector(AudioInjector* injector) {
bool AudioInjectorManager::restartFinishedInjector(AudioInjector* injector) {
if (_shouldStop) {
qDebug() << "AudioInjectorManager::threadInjector asked to thread injector but is shutting down.";
qCDebug(audio) << "AudioInjectorManager::threadInjector asked to thread injector but is shutting down.";
return false;
}

View file

@ -211,6 +211,49 @@ static inline int32_t peaklog2(float* input0, float* input1) {
return (e << LOG2_FRACBITS) - (c2 >> 3);
}
//
// Peak detection and -log2(x) for float input (quad)
// x < 2^(31-LOG2_HEADROOM) returns 0x7fffffff
// x > 2^LOG2_HEADROOM undefined
//
static inline int32_t peaklog2(float* input0, float* input1, float* input2, float* input3) {
// float as integer bits
int32_t u0 = *(int32_t*)input0;
int32_t u1 = *(int32_t*)input1;
int32_t u2 = *(int32_t*)input2;
int32_t u3 = *(int32_t*)input3;
// max absolute value
u0 &= IEEE754_FABS_MASK;
u1 &= IEEE754_FABS_MASK;
u2 &= IEEE754_FABS_MASK;
u3 &= IEEE754_FABS_MASK;
int32_t peak = MAX(MAX(u0, u1), MAX(u2, u3));
// split into e and x - 1.0
int32_t e = IEEE754_EXPN_BIAS - (peak >> IEEE754_MANT_BITS) + LOG2_HEADROOM;
int32_t x = (peak << (31 - IEEE754_MANT_BITS)) & 0x7fffffff;
// saturate
if (e > 31) {
return 0x7fffffff;
}
int k = x >> (31 - LOG2_TABBITS);
// polynomial for log2(1+x) over x=[0,1]
int32_t c0 = log2Table[k][0];
int32_t c1 = log2Table[k][1];
int32_t c2 = log2Table[k][2];
c1 += MULHI(c0, x);
c2 += MULHI(c1, x);
// reconstruct result in Q26
return (e << LOG2_FRACBITS) - (c2 >> 3);
}
//
// Compute exp2(-x) for x=[0,32] in Q26, result in Q31
// x < 0 undefined
@ -258,7 +301,7 @@ class PeakFilterT {
static_assert((CIC1 - 1) + (CIC2 - 1) == (N - 1), "Total CIC delay must be N-1");
int32_t _buffer[2*N] = {}; // shared FIFO
int _index = 0;
size_t _index = 0;
int32_t _acc1 = 0; // CIC1 integrator
int32_t _acc2 = 0; // CIC2 integrator
@ -267,21 +310,21 @@ public:
PeakFilterT() {
// fill history
for (int n = 0; n < N-1; n++) {
for (size_t n = 0; n < N-1; n++) {
process(0x7fffffff);
}
}
int32_t process(int32_t x) {
const int MASK = 2*N - 1; // buffer wrap
int i = _index;
const size_t MASK = 2*N - 1; // buffer wrap
size_t i = _index;
// Fast peak-hold using a running-min filter. Finds the peak (min) value
// in the sliding window of N-1 samples, using only log2(N) comparisons.
// Hold time of N-1 samples exactly cancels the step response of FIR filter.
for (int n = 1; n < N; n <<= 1) {
for (size_t n = 1; n < N; n <<= 1) {
_buffer[i] = x;
i = (i + n) & MASK;
@ -329,13 +372,13 @@ class MonoDelay {
static_assert((N & (N - 1)) == 0, "N must be a power of 2");
float _buffer[N] = {};
int _index = 0;
size_t _index = 0;
public:
void process(float& x) {
const int MASK = N - 1; // buffer wrap
int i = _index;
const size_t MASK = N - 1; // buffer wrap
size_t i = _index;
_buffer[i] = x;
@ -356,13 +399,13 @@ class StereoDelay {
static_assert((N & (N - 1)) == 0, "N must be a power of 2");
float _buffer[2*N] = {};
int _index = 0;
size_t _index = 0;
public:
void process(float& x0, float& x1) {
const int MASK = 2*N - 1; // buffer wrap
int i = _index;
const size_t MASK = 2*N - 1; // buffer wrap
size_t i = _index;
_buffer[i+0] = x0;
_buffer[i+1] = x1;
@ -376,6 +419,39 @@ public:
}
};
//
// N-1 sample delay (quad)
//
template<int N>
class QuadDelay {
static_assert((N & (N - 1)) == 0, "N must be a power of 2");
float _buffer[4*N] = {};
size_t _index = 0;
public:
void process(float& x0, float& x1, float& x2, float& x3) {
const size_t MASK = 4*N - 1; // buffer wrap
size_t i = _index;
_buffer[i+0] = x0;
_buffer[i+1] = x1;
_buffer[i+2] = x2;
_buffer[i+3] = x3;
i = (i + 4*(N - 1)) & MASK;
x0 = _buffer[i+0];
x1 = _buffer[i+1];
x2 = _buffer[i+2];
x3 = _buffer[i+3];
_index = i;
}
};
//
// Limiter (common)
//
@ -428,7 +504,7 @@ LimiterImpl::LimiterImpl(int sampleRate) {
//
void LimiterImpl::setThreshold(float threshold) {
const double OUT_CEILING = -0.3;
const double OUT_CEILING = -0.3; // cannot be 0.0, due to dither
const double Q31_TO_Q15 = 32768 / 2147483648.0;
// limiter threshold = -48dB to 0dB
@ -537,12 +613,12 @@ int32_t LimiterImpl::envelope(int32_t attn) {
// arc = (attn-rms)*6/attn for attn = 1dB to 6dB
// arc = (attn-rms)*6/6 for attn > 6dB
int bits = MIN(attn >> 20, 0x3f); // saturate 1/attn at 6dB
_arc = MAX(attn - _rms, 0); // peak/rms = (attn-rms)
_arc = MULHI(_arc, invTable[bits]); // normalized peak/rms = (attn-rms)/attn
_arc = MIN(_arc, NARC - 1); // saturate at 6dB
size_t bits = MIN(attn >> 20, 0x3f); // saturate 1/attn at 6dB
_arc = MAX(attn - _rms, 0); // peak/rms = (attn-rms)
_arc = MULHI(_arc, invTable[bits]); // normalized peak/rms = (attn-rms)/attn
_arc = MIN(_arc, NARC - 1); // saturate at 6dB
_arcRelease = 0x7fffffff; // reset release
_arcRelease = 0x7fffffff; // reset release
}
_attn = attn;
@ -571,8 +647,8 @@ public:
};
template<int N>
void LimiterMono<N>::process(float* input, int16_t* output, int numFrames)
{
void LimiterMono<N>::process(float* input, int16_t* output, int numFrames) {
for (int n = 0; n < numFrames; n++) {
// peak detect and convert to log2 domain
@ -623,8 +699,8 @@ public:
};
template<int N>
void LimiterStereo<N>::process(float* input, int16_t* output, int numFrames)
{
void LimiterStereo<N>::process(float* input, int16_t* output, int numFrames) {
for (int n = 0; n < numFrames; n++) {
// peak detect and convert to log2 domain
@ -663,6 +739,71 @@ void LimiterStereo<N>::process(float* input, int16_t* output, int numFrames)
}
}
//
// Limiter (quad)
//
template<int N>
class LimiterQuad : public LimiterImpl {
PeakFilter<N> _filter;
QuadDelay<N> _delay;
public:
LimiterQuad(int sampleRate) : LimiterImpl(sampleRate) {}
// interleaved quad input/output
void process(float* input, int16_t* output, int numFrames) override;
};
template<int N>
void LimiterQuad<N>::process(float* input, int16_t* output, int numFrames) {
for (int n = 0; n < numFrames; n++) {
// peak detect and convert to log2 domain
int32_t peak = peaklog2(&input[4*n+0], &input[4*n+1], &input[4*n+2], &input[4*n+3]);
// compute limiter attenuation
int32_t attn = MAX(_threshold - peak, 0);
// apply envelope
attn = envelope(attn);
// convert from log2 domain
attn = fixexp2(attn);
// lowpass filter
attn = _filter.process(attn);
float gain = attn * _outGain;
// delay audio
float x0 = input[4*n+0];
float x1 = input[4*n+1];
float x2 = input[4*n+2];
float x3 = input[4*n+3];
_delay.process(x0, x1, x2, x3);
// apply gain
x0 *= gain;
x1 *= gain;
x2 *= gain;
x3 *= gain;
// apply dither
float d = dither();
x0 += d;
x1 += d;
x2 += d;
x3 += d;
// store 16-bit output
output[4*n+0] = (int16_t)floatToInt(x0);
output[4*n+1] = (int16_t)floatToInt(x1);
output[4*n+2] = (int16_t)floatToInt(x2);
output[4*n+3] = (int16_t)floatToInt(x3);
}
}
//
// Public API
//
@ -695,6 +836,19 @@ AudioLimiter::AudioLimiter(int sampleRate, int numChannels) {
_impl = new LimiterStereo<128>(sampleRate);
}
} else if (numChannels == 4) {
// ~1.5ms lookahead for all rates
if (sampleRate < 16000) {
_impl = new LimiterQuad<16>(sampleRate);
} else if (sampleRate < 32000) {
_impl = new LimiterQuad<32>(sampleRate);
} else if (sampleRate < 64000) {
_impl = new LimiterQuad<64>(sampleRate);
} else {
_impl = new LimiterQuad<128>(sampleRate);
}
} else {
assert(0); // unsupported
}

View file

@ -99,18 +99,22 @@ static void cubicInterpolation(const float* input, float* output, int inputSize,
}
}
int AudioSRC::createRationalFilter(int upFactor, int downFactor, float gain) {
int numTaps = PROTOTYPE_TAPS;
int AudioSRC::createRationalFilter(int upFactor, int downFactor, float gain, Quality quality) {
int prototypeTaps = prototypeFilterTable[quality].taps;
int prototypeCoefs = prototypeFilterTable[quality].coefs;
const float* prototypeFilter = prototypeFilterTable[quality].filter;
int numTaps = prototypeTaps;
int numPhases = upFactor;
int numCoefs = numTaps * numPhases;
int oldCoefs = numCoefs;
int prototypeCoefs = PROTOTYPE_TAPS * PROTOTYPE_PHASES;
//
// When downsampling, we can lower the filter cutoff by downFactor/upFactor using the
// time-scaling property of the Fourier transform. The gain is adjusted accordingly.
//
if (downFactor > upFactor) {
int oldCoefs = numCoefs;
numCoefs = ((int64_t)oldCoefs * downFactor) / upFactor;
numTaps = (numCoefs + upFactor - 1) / upFactor;
gain *= (float)oldCoefs / numCoefs;
@ -149,18 +153,22 @@ int AudioSRC::createRationalFilter(int upFactor, int downFactor, float gain) {
return numTaps;
}
int AudioSRC::createIrrationalFilter(int upFactor, int downFactor, float gain) {
int numTaps = PROTOTYPE_TAPS;
int AudioSRC::createIrrationalFilter(int upFactor, int downFactor, float gain, Quality quality) {
int prototypeTaps = prototypeFilterTable[quality].taps;
int prototypeCoefs = prototypeFilterTable[quality].coefs;
const float* prototypeFilter = prototypeFilterTable[quality].filter;
int numTaps = prototypeTaps;
int numPhases = upFactor;
int numCoefs = numTaps * numPhases;
int oldCoefs = numCoefs;
int prototypeCoefs = PROTOTYPE_TAPS * PROTOTYPE_PHASES;
//
// When downsampling, we can lower the filter cutoff by downFactor/upFactor using the
// time-scaling property of the Fourier transform. The gain is adjusted accordingly.
//
if (downFactor > upFactor) {
int oldCoefs = numCoefs;
numCoefs = ((int64_t)oldCoefs * downFactor) / upFactor;
numTaps = (numCoefs + upFactor - 1) / upFactor;
gain *= (float)oldCoefs / numCoefs;
@ -1405,7 +1413,8 @@ int AudioSRC::render(float** inputs, float** outputs, int inputFrames) {
return outputFrames;
}
AudioSRC::AudioSRC(int inputSampleRate, int outputSampleRate, int numChannels) {
AudioSRC::AudioSRC(int inputSampleRate, int outputSampleRate, int numChannels, Quality quality) {
assert(inputSampleRate > 0);
assert(outputSampleRate > 0);
assert(numChannels > 0);
@ -1433,9 +1442,9 @@ AudioSRC::AudioSRC(int inputSampleRate, int outputSampleRate, int numChannels) {
// create the polyphase filter
if (_step == 0) {
_numTaps = createRationalFilter(_upFactor, _downFactor, 1.0f);
_numTaps = createRationalFilter(_upFactor, _downFactor, 1.0f, quality);
} else {
_numTaps = createIrrationalFilter(_upFactor, _downFactor, 1.0f);
_numTaps = createIrrationalFilter(_upFactor, _downFactor, 1.0f, quality);
}
//printf("up=%d down=%.3f taps=%d\n", _upFactor, _downFactor + (LO32(_step)<<SRC_PHASEBITS) * Q32_TO_FLOAT, _numTaps);

View file

@ -17,7 +17,7 @@
static const int SRC_MAX_CHANNELS = 4;
// polyphase filter
static const int SRC_PHASEBITS = 8;
static const int SRC_PHASEBITS = 9;
static const int SRC_PHASES = (1 << SRC_PHASEBITS);
static const int SRC_FRACBITS = 32 - SRC_PHASEBITS;
static const uint32_t SRC_FRACMASK = (1 << SRC_FRACBITS) - 1;
@ -31,7 +31,13 @@ static const int SRC_BLOCK = 256;
class AudioSRC {
public:
AudioSRC(int inputSampleRate, int outputSampleRate, int numChannels);
enum Quality {
LOW_QUALITY,
MEDIUM_QUALITY,
HIGH_QUALITY
};
AudioSRC(int inputSampleRate, int outputSampleRate, int numChannels, Quality quality = MEDIUM_QUALITY);
~AudioSRC();
// deinterleaved float input/output (native format)
@ -70,8 +76,8 @@ private:
int64_t _offset;
int64_t _step;
int createRationalFilter(int upFactor, int downFactor, float gain);
int createIrrationalFilter(int upFactor, int downFactor, float gain);
int createRationalFilter(int upFactor, int downFactor, float gain, Quality quality);
int createIrrationalFilter(int upFactor, int downFactor, float gain, Quality quality);
int multirateFilter1(const float* input0, float* output0, int inputFrames);
int multirateFilter2(const float* input0, const float* input1, float* output0, float* output1, int inputFrames);

File diff suppressed because it is too large Load diff

View file

@ -153,7 +153,7 @@ int InboundAudioStream::parseData(ReceivedMessage& message) {
auto afterProperties = message.readWithoutCopy(message.getBytesLeftToRead());
parseAudioData(message.getType(), afterProperties);
} else {
qDebug() << "Codec mismatch: expected" << _selectedCodecName << "got" << codecInPacket << "writing silence";
qDebug(audio) << "Codec mismatch: expected" << _selectedCodecName << "got" << codecInPacket << "writing silence";
writeDroppableSilentFrames(networkFrames);
// inform others of the mismatch
auto sendingNode = DependencyManager::get<NodeList>()->nodeWithUUID(message.getSourceID());

View file

@ -1,96 +0,0 @@
//
// AudioHRTF_avx.cpp
// libraries/audio/src/avx
//
// Created by Ken Cooke on 1/17/16.
// Copyright 2016 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
//
#if defined(_M_IX86) || defined(_M_X64) || defined(__i386__) || defined(__x86_64__)
#include <assert.h>
#include <immintrin.h>
#include "../AudioHRTF.h"
#ifndef __AVX__
#error Must be compiled with /arch:AVX or -mavx.
#endif
// 1 channel input, 4 channel output
void FIR_1x4_AVX(float* src, float* dst0, float* dst1, float* dst2, float* dst3, float coef[4][HRTF_TAPS], int numFrames) {
float* coef0 = coef[0] + HRTF_TAPS - 1; // process backwards
float* coef1 = coef[1] + HRTF_TAPS - 1;
float* coef2 = coef[2] + HRTF_TAPS - 1;
float* coef3 = coef[3] + HRTF_TAPS - 1;
assert(numFrames % 8 == 0);
for (int i = 0; i < numFrames; i += 8) {
__m256 acc0 = _mm256_setzero_ps();
__m256 acc1 = _mm256_setzero_ps();
__m256 acc2 = _mm256_setzero_ps();
__m256 acc3 = _mm256_setzero_ps();
float* ps = &src[i - HRTF_TAPS + 1]; // process forwards
assert(HRTF_TAPS % 8 == 0);
for (int k = 0; k < HRTF_TAPS; k += 8) {
acc0 = _mm256_add_ps(acc0, _mm256_mul_ps(_mm256_broadcast_ss(&coef0[-k-0]), _mm256_loadu_ps(&ps[k+0])));
acc1 = _mm256_add_ps(acc1, _mm256_mul_ps(_mm256_broadcast_ss(&coef1[-k-0]), _mm256_loadu_ps(&ps[k+0])));
acc2 = _mm256_add_ps(acc2, _mm256_mul_ps(_mm256_broadcast_ss(&coef2[-k-0]), _mm256_loadu_ps(&ps[k+0])));
acc3 = _mm256_add_ps(acc3, _mm256_mul_ps(_mm256_broadcast_ss(&coef3[-k-0]), _mm256_loadu_ps(&ps[k+0])));
acc0 = _mm256_add_ps(acc0, _mm256_mul_ps(_mm256_broadcast_ss(&coef0[-k-1]), _mm256_loadu_ps(&ps[k+1])));
acc1 = _mm256_add_ps(acc1, _mm256_mul_ps(_mm256_broadcast_ss(&coef1[-k-1]), _mm256_loadu_ps(&ps[k+1])));
acc2 = _mm256_add_ps(acc2, _mm256_mul_ps(_mm256_broadcast_ss(&coef2[-k-1]), _mm256_loadu_ps(&ps[k+1])));
acc3 = _mm256_add_ps(acc3, _mm256_mul_ps(_mm256_broadcast_ss(&coef3[-k-1]), _mm256_loadu_ps(&ps[k+1])));
acc0 = _mm256_add_ps(acc0, _mm256_mul_ps(_mm256_broadcast_ss(&coef0[-k-2]), _mm256_loadu_ps(&ps[k+2])));
acc1 = _mm256_add_ps(acc1, _mm256_mul_ps(_mm256_broadcast_ss(&coef1[-k-2]), _mm256_loadu_ps(&ps[k+2])));
acc2 = _mm256_add_ps(acc2, _mm256_mul_ps(_mm256_broadcast_ss(&coef2[-k-2]), _mm256_loadu_ps(&ps[k+2])));
acc3 = _mm256_add_ps(acc3, _mm256_mul_ps(_mm256_broadcast_ss(&coef3[-k-2]), _mm256_loadu_ps(&ps[k+2])));
acc0 = _mm256_add_ps(acc0, _mm256_mul_ps(_mm256_broadcast_ss(&coef0[-k-3]), _mm256_loadu_ps(&ps[k+3])));
acc1 = _mm256_add_ps(acc1, _mm256_mul_ps(_mm256_broadcast_ss(&coef1[-k-3]), _mm256_loadu_ps(&ps[k+3])));
acc2 = _mm256_add_ps(acc2, _mm256_mul_ps(_mm256_broadcast_ss(&coef2[-k-3]), _mm256_loadu_ps(&ps[k+3])));
acc3 = _mm256_add_ps(acc3, _mm256_mul_ps(_mm256_broadcast_ss(&coef3[-k-3]), _mm256_loadu_ps(&ps[k+3])));
acc0 = _mm256_add_ps(acc0, _mm256_mul_ps(_mm256_broadcast_ss(&coef0[-k-4]), _mm256_loadu_ps(&ps[k+4])));
acc1 = _mm256_add_ps(acc1, _mm256_mul_ps(_mm256_broadcast_ss(&coef1[-k-4]), _mm256_loadu_ps(&ps[k+4])));
acc2 = _mm256_add_ps(acc2, _mm256_mul_ps(_mm256_broadcast_ss(&coef2[-k-4]), _mm256_loadu_ps(&ps[k+4])));
acc3 = _mm256_add_ps(acc3, _mm256_mul_ps(_mm256_broadcast_ss(&coef3[-k-4]), _mm256_loadu_ps(&ps[k+4])));
acc0 = _mm256_add_ps(acc0, _mm256_mul_ps(_mm256_broadcast_ss(&coef0[-k-5]), _mm256_loadu_ps(&ps[k+5])));
acc1 = _mm256_add_ps(acc1, _mm256_mul_ps(_mm256_broadcast_ss(&coef1[-k-5]), _mm256_loadu_ps(&ps[k+5])));
acc2 = _mm256_add_ps(acc2, _mm256_mul_ps(_mm256_broadcast_ss(&coef2[-k-5]), _mm256_loadu_ps(&ps[k+5])));
acc3 = _mm256_add_ps(acc3, _mm256_mul_ps(_mm256_broadcast_ss(&coef3[-k-5]), _mm256_loadu_ps(&ps[k+5])));
acc0 = _mm256_add_ps(acc0, _mm256_mul_ps(_mm256_broadcast_ss(&coef0[-k-6]), _mm256_loadu_ps(&ps[k+6])));
acc1 = _mm256_add_ps(acc1, _mm256_mul_ps(_mm256_broadcast_ss(&coef1[-k-6]), _mm256_loadu_ps(&ps[k+6])));
acc2 = _mm256_add_ps(acc2, _mm256_mul_ps(_mm256_broadcast_ss(&coef2[-k-6]), _mm256_loadu_ps(&ps[k+6])));
acc3 = _mm256_add_ps(acc3, _mm256_mul_ps(_mm256_broadcast_ss(&coef3[-k-6]), _mm256_loadu_ps(&ps[k+6])));
acc0 = _mm256_add_ps(acc0, _mm256_mul_ps(_mm256_broadcast_ss(&coef0[-k-7]), _mm256_loadu_ps(&ps[k+7])));
acc1 = _mm256_add_ps(acc1, _mm256_mul_ps(_mm256_broadcast_ss(&coef1[-k-7]), _mm256_loadu_ps(&ps[k+7])));
acc2 = _mm256_add_ps(acc2, _mm256_mul_ps(_mm256_broadcast_ss(&coef2[-k-7]), _mm256_loadu_ps(&ps[k+7])));
acc3 = _mm256_add_ps(acc3, _mm256_mul_ps(_mm256_broadcast_ss(&coef3[-k-7]), _mm256_loadu_ps(&ps[k+7])));
}
_mm256_storeu_ps(&dst0[i], acc0);
_mm256_storeu_ps(&dst1[i], acc1);
_mm256_storeu_ps(&dst2[i], acc2);
_mm256_storeu_ps(&dst3[i], acc3);
}
_mm256_zeroupper();
}
#endif

View file

@ -0,0 +1,94 @@
//
// AudioHRTF_avx2.cpp
// libraries/audio/src
//
// Created by Ken Cooke on 1/17/16.
// Copyright 2016 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
//
#if defined(_M_IX86) || defined(_M_X64) || defined(__i386__) || defined(__x86_64__)
#include <assert.h>
#include <immintrin.h> // AVX2
#include "../AudioHRTF.h"
#ifndef __AVX2__
#error Must be compiled with /arch:AVX2 or -mavx2 -mfma.
#endif
#if defined(__GNUC__) && !defined(__clang__)
// for some reason, GCC -O2 results in poorly optimized code
#pragma GCC optimize("Os")
#endif
// 1 channel input, 4 channel output
void FIR_1x4_AVX2(float* src, float* dst0, float* dst1, float* dst2, float* dst3, float coef[4][HRTF_TAPS], int numFrames) {
float* coef0 = coef[0] + HRTF_TAPS - 1; // process backwards
float* coef1 = coef[1] + HRTF_TAPS - 1;
float* coef2 = coef[2] + HRTF_TAPS - 1;
float* coef3 = coef[3] + HRTF_TAPS - 1;
assert(numFrames % 8 == 0);
for (int i = 0; i < numFrames; i += 8) {
__m256 acc0 = _mm256_setzero_ps();
__m256 acc1 = _mm256_setzero_ps();
__m256 acc2 = _mm256_setzero_ps();
__m256 acc3 = _mm256_setzero_ps();
__m256 acc4 = _mm256_setzero_ps();
__m256 acc5 = _mm256_setzero_ps();
__m256 acc6 = _mm256_setzero_ps();
__m256 acc7 = _mm256_setzero_ps();
float* ps = &src[i - HRTF_TAPS + 1]; // process forwards
assert(HRTF_TAPS % 4 == 0);
for (int k = 0; k < HRTF_TAPS; k += 4) {
__m256 x0 = _mm256_loadu_ps(&ps[k+0]);
acc0 = _mm256_fmadd_ps(_mm256_broadcast_ss(&coef0[-k-0]), x0, acc0);
acc1 = _mm256_fmadd_ps(_mm256_broadcast_ss(&coef1[-k-0]), x0, acc1);
acc2 = _mm256_fmadd_ps(_mm256_broadcast_ss(&coef2[-k-0]), x0, acc2);
acc3 = _mm256_fmadd_ps(_mm256_broadcast_ss(&coef3[-k-0]), x0, acc3);
__m256 x1 = _mm256_loadu_ps(&ps[k+1]);
acc4 = _mm256_fmadd_ps(_mm256_broadcast_ss(&coef0[-k-1]), x1, acc4);
acc5 = _mm256_fmadd_ps(_mm256_broadcast_ss(&coef1[-k-1]), x1, acc5);
acc6 = _mm256_fmadd_ps(_mm256_broadcast_ss(&coef2[-k-1]), x1, acc6);
acc7 = _mm256_fmadd_ps(_mm256_broadcast_ss(&coef3[-k-1]), x1, acc7);
__m256 x2 = _mm256_loadu_ps(&ps[k+2]);
acc0 = _mm256_fmadd_ps(_mm256_broadcast_ss(&coef0[-k-2]), x2, acc0);
acc1 = _mm256_fmadd_ps(_mm256_broadcast_ss(&coef1[-k-2]), x2, acc1);
acc2 = _mm256_fmadd_ps(_mm256_broadcast_ss(&coef2[-k-2]), x2, acc2);
acc3 = _mm256_fmadd_ps(_mm256_broadcast_ss(&coef3[-k-2]), x2, acc3);
__m256 x3 = _mm256_loadu_ps(&ps[k+3]);
acc4 = _mm256_fmadd_ps(_mm256_broadcast_ss(&coef0[-k-3]), x3, acc4);
acc5 = _mm256_fmadd_ps(_mm256_broadcast_ss(&coef1[-k-3]), x3, acc5);
acc6 = _mm256_fmadd_ps(_mm256_broadcast_ss(&coef2[-k-3]), x3, acc6);
acc7 = _mm256_fmadd_ps(_mm256_broadcast_ss(&coef3[-k-3]), x3, acc7);
}
acc0 = _mm256_add_ps(acc0, acc4);
acc1 = _mm256_add_ps(acc1, acc5);
acc2 = _mm256_add_ps(acc2, acc6);
acc3 = _mm256_add_ps(acc3, acc7);
_mm256_storeu_ps(&dst0[i], acc0);
_mm256_storeu_ps(&dst1[i], acc1);
_mm256_storeu_ps(&dst2[i], acc2);
_mm256_storeu_ps(&dst3[i], acc3);
}
_mm256_zeroupper();
}
#endif

View file

@ -50,9 +50,20 @@ const glm::vec3 DEFAULT_LOCAL_AABOX_SCALE(1.0f);
const QString AvatarData::FRAME_NAME = "com.highfidelity.recording.AvatarData";
namespace AvatarDataPacket {
// NOTE: AvatarDataPackets start with a uint16_t sequence number that is not reflected in the Header structure.
PACKED_BEGIN struct Header {
uint8_t packetStateFlags; // state flags, currently used to indicate if the packet is a minimal or fuller packet
} PACKED_END;
const size_t HEADER_SIZE = 1;
PACKED_BEGIN struct MinimalAvatarInfo {
float globalPosition[3]; // avatar's position
} PACKED_END;
const size_t MINIMAL_AVATAR_INFO_SIZE = 12;
PACKED_BEGIN struct AvatarInfo {
float position[3]; // skeletal model's position
float globalPosition[3]; // avatar's position
float globalBoundingBoxCorner[3]; // global position of the lowest corner of the avatar's bounding box
@ -65,16 +76,16 @@ namespace AvatarDataPacket {
float sensorToWorldTrans[3]; // fourth column of sensor to world matrix
uint8_t flags;
} PACKED_END;
const size_t HEADER_SIZE = 81;
const size_t AVATAR_INFO_SIZE = 81;
// only present if HAS_REFERENTIAL flag is set in header.flags
// only present if HAS_REFERENTIAL flag is set in AvatarInfo.flags
PACKED_BEGIN struct ParentInfo {
uint8_t parentUUID[16]; // rfc 4122 encoded
uint16_t parentJointIndex;
} PACKED_END;
const size_t PARENT_INFO_SIZE = 18;
// only present if IS_FACESHIFT_CONNECTED flag is set in header.flags
// only present if IS_FACESHIFT_CONNECTED flag is set in AvatarInfo.flags
PACKED_BEGIN struct FaceTrackerInfo {
float leftEyeBlink;
float rightEyeBlink;
@ -124,6 +135,8 @@ AvatarData::AvatarData() :
setBodyRoll(0.0f);
ASSERT(sizeof(AvatarDataPacket::Header) == AvatarDataPacket::HEADER_SIZE);
ASSERT(sizeof(AvatarDataPacket::MinimalAvatarInfo) == AvatarDataPacket::MINIMAL_AVATAR_INFO_SIZE);
ASSERT(sizeof(AvatarDataPacket::AvatarInfo) == AvatarDataPacket::AVATAR_INFO_SIZE);
ASSERT(sizeof(AvatarDataPacket::ParentInfo) == AvatarDataPacket::PARENT_INFO_SIZE);
ASSERT(sizeof(AvatarDataPacket::FaceTrackerInfo) == AvatarDataPacket::FACE_TRACKER_INFO_SIZE);
}
@ -132,9 +145,9 @@ AvatarData::~AvatarData() {
delete _headData;
}
// We cannot have a file-level variable (const or otherwise) in the header if it uses PathUtils, because that references Application, which will not yet initialized.
// We cannot have a file-level variable (const or otherwise) in the AvatarInfo if it uses PathUtils, because that references Application, which will not yet initialized.
// Thus we have a static class getter, referencing a static class var.
QUrl AvatarData::_defaultFullAvatarModelUrl = {}; // In C++, if this initialization were in the header, every file would have it's own copy, even for class vars.
QUrl AvatarData::_defaultFullAvatarModelUrl = {}; // In C++, if this initialization were in the AvatarInfo, every file would have it's own copy, even for class vars.
const QUrl& AvatarData::defaultFullAvatarModelUrl() {
if (_defaultFullAvatarModelUrl.isEmpty()) {
_defaultFullAvatarModelUrl = QUrl::fromLocalFile(PathUtils::resourcesPath() + "meshes/defaultAvatar_full.fst");
@ -147,14 +160,14 @@ void AvatarData::nextAttitude(glm::vec3 position, glm::quat orientation) {
bool success;
Transform trans = getTransform(success);
if (!success) {
qDebug() << "Warning -- AvatarData::nextAttitude failed";
qCWarning(avatars) << "Warning -- AvatarData::nextAttitude failed";
return;
}
trans.setTranslation(position);
trans.setRotation(orientation);
SpatiallyNestable::setTransform(trans, success);
if (!success) {
qDebug() << "Warning -- AvatarData::nextAttitude failed";
qCWarning(avatars) << "Warning -- AvatarData::nextAttitude failed";
}
updateAttitude();
}
@ -181,7 +194,11 @@ void AvatarData::setHandPosition(const glm::vec3& handPosition) {
_handPosition = glm::inverse(getOrientation()) * (handPosition - getPosition());
}
QByteArray AvatarData::toByteArray(bool cullSmallChanges, bool sendAll) {
QByteArray AvatarData::toByteArray(AvatarDataDetail dataDetail) {
bool cullSmallChanges = (dataDetail == CullSmallData);
bool sendAll = (dataDetail == SendAllData);
bool sendMinimum = (dataDetail == MinimumData);
// TODO: DRY this up to a shared method
// that can pack any type given the number of bytes
// and return the number of bytes to push the pointer
@ -199,207 +216,221 @@ QByteArray AvatarData::toByteArray(bool cullSmallChanges, bool sendAll) {
unsigned char* destinationBuffer = reinterpret_cast<unsigned char*>(avatarDataByteArray.data());
unsigned char* startPosition = destinationBuffer;
auto header = reinterpret_cast<AvatarDataPacket::Header*>(destinationBuffer);
header->position[0] = getLocalPosition().x;
header->position[1] = getLocalPosition().y;
header->position[2] = getLocalPosition().z;
header->globalPosition[0] = _globalPosition.x;
header->globalPosition[1] = _globalPosition.y;
header->globalPosition[2] = _globalPosition.z;
header->globalBoundingBoxCorner[0] = getPosition().x - _globalBoundingBoxCorner.x;
header->globalBoundingBoxCorner[1] = getPosition().y - _globalBoundingBoxCorner.y;
header->globalBoundingBoxCorner[2] = getPosition().z - _globalBoundingBoxCorner.z;
glm::vec3 bodyEulerAngles = glm::degrees(safeEulerAngles(getLocalOrientation()));
packFloatAngleToTwoByte((uint8_t*)(header->localOrientation + 0), bodyEulerAngles.y);
packFloatAngleToTwoByte((uint8_t*)(header->localOrientation + 1), bodyEulerAngles.x);
packFloatAngleToTwoByte((uint8_t*)(header->localOrientation + 2), bodyEulerAngles.z);
packFloatRatioToTwoByte((uint8_t*)(&header->scale), getDomainLimitedScale());
header->lookAtPosition[0] = _headData->_lookAtPosition.x;
header->lookAtPosition[1] = _headData->_lookAtPosition.y;
header->lookAtPosition[2] = _headData->_lookAtPosition.z;
header->audioLoudness = _headData->_audioLoudness;
glm::mat4 sensorToWorldMatrix = getSensorToWorldMatrix();
packOrientationQuatToSixBytes(header->sensorToWorldQuat, glmExtractRotation(sensorToWorldMatrix));
glm::vec3 scale = extractScale(sensorToWorldMatrix);
packFloatScalarToSignedTwoByteFixed((uint8_t*)&header->sensorToWorldScale, scale.x, SENSOR_TO_WORLD_SCALE_RADIX);
header->sensorToWorldTrans[0] = sensorToWorldMatrix[3][0];
header->sensorToWorldTrans[1] = sensorToWorldMatrix[3][1];
header->sensorToWorldTrans[2] = sensorToWorldMatrix[3][2];
setSemiNibbleAt(header->flags, KEY_STATE_START_BIT, _keyState);
// hand state
bool isFingerPointing = _handState & IS_FINGER_POINTING_FLAG;
setSemiNibbleAt(header->flags, HAND_STATE_START_BIT, _handState & ~IS_FINGER_POINTING_FLAG);
if (isFingerPointing) {
setAtBit(header->flags, HAND_STATE_FINGER_POINTING_BIT);
}
// faceshift state
if (_headData->_isFaceTrackerConnected) {
setAtBit(header->flags, IS_FACESHIFT_CONNECTED);
}
// eye tracker state
if (_headData->_isEyeTrackerConnected) {
setAtBit(header->flags, IS_EYE_TRACKER_CONNECTED);
}
// referential state
QUuid parentID = getParentID();
if (!parentID.isNull()) {
setAtBit(header->flags, HAS_REFERENTIAL);
}
destinationBuffer += sizeof(AvatarDataPacket::Header);
if (!parentID.isNull()) {
auto parentInfo = reinterpret_cast<AvatarDataPacket::ParentInfo*>(destinationBuffer);
QByteArray referentialAsBytes = parentID.toRfc4122();
memcpy(parentInfo->parentUUID, referentialAsBytes.data(), referentialAsBytes.size());
parentInfo->parentJointIndex = _parentJointIndex;
destinationBuffer += sizeof(AvatarDataPacket::ParentInfo);
// Leading flags, to indicate how much data is actually included in the packet...
uint8_t packetStateFlags = 0;
if (sendMinimum) {
setAtBit(packetStateFlags, AVATARDATA_FLAGS_MINIMUM);
}
// If it is connected, pack up the data
if (_headData->_isFaceTrackerConnected) {
auto faceTrackerInfo = reinterpret_cast<AvatarDataPacket::FaceTrackerInfo*>(destinationBuffer);
memcpy(destinationBuffer, &packetStateFlags, sizeof(packetStateFlags));
destinationBuffer += sizeof(packetStateFlags);
faceTrackerInfo->leftEyeBlink = _headData->_leftEyeBlink;
faceTrackerInfo->rightEyeBlink = _headData->_rightEyeBlink;
faceTrackerInfo->averageLoudness = _headData->_averageLoudness;
faceTrackerInfo->browAudioLift = _headData->_browAudioLift;
faceTrackerInfo->numBlendshapeCoefficients = _headData->_blendshapeCoefficients.size();
destinationBuffer += sizeof(AvatarDataPacket::FaceTrackerInfo);
if (sendMinimum) {
memcpy(destinationBuffer, &_globalPosition, sizeof(_globalPosition));
destinationBuffer += sizeof(_globalPosition);
} else {
auto avatarInfo = reinterpret_cast<AvatarDataPacket::AvatarInfo*>(destinationBuffer);
avatarInfo->position[0] = getLocalPosition().x;
avatarInfo->position[1] = getLocalPosition().y;
avatarInfo->position[2] = getLocalPosition().z;
avatarInfo->globalPosition[0] = _globalPosition.x;
avatarInfo->globalPosition[1] = _globalPosition.y;
avatarInfo->globalPosition[2] = _globalPosition.z;
avatarInfo->globalBoundingBoxCorner[0] = getPosition().x - _globalBoundingBoxCorner.x;
avatarInfo->globalBoundingBoxCorner[1] = getPosition().y - _globalBoundingBoxCorner.y;
avatarInfo->globalBoundingBoxCorner[2] = getPosition().z - _globalBoundingBoxCorner.z;
// followed by a variable number of float coefficients
memcpy(destinationBuffer, _headData->_blendshapeCoefficients.data(), _headData->_blendshapeCoefficients.size() * sizeof(float));
destinationBuffer += _headData->_blendshapeCoefficients.size() * sizeof(float);
}
glm::vec3 bodyEulerAngles = glm::degrees(safeEulerAngles(getLocalOrientation()));
packFloatAngleToTwoByte((uint8_t*)(avatarInfo->localOrientation + 0), bodyEulerAngles.y);
packFloatAngleToTwoByte((uint8_t*)(avatarInfo->localOrientation + 1), bodyEulerAngles.x);
packFloatAngleToTwoByte((uint8_t*)(avatarInfo->localOrientation + 2), bodyEulerAngles.z);
packFloatRatioToTwoByte((uint8_t*)(&avatarInfo->scale), getDomainLimitedScale());
avatarInfo->lookAtPosition[0] = _headData->_lookAtPosition.x;
avatarInfo->lookAtPosition[1] = _headData->_lookAtPosition.y;
avatarInfo->lookAtPosition[2] = _headData->_lookAtPosition.z;
avatarInfo->audioLoudness = _headData->_audioLoudness;
QReadLocker readLock(&_jointDataLock);
glm::mat4 sensorToWorldMatrix = getSensorToWorldMatrix();
packOrientationQuatToSixBytes(avatarInfo->sensorToWorldQuat, glmExtractRotation(sensorToWorldMatrix));
glm::vec3 scale = extractScale(sensorToWorldMatrix);
packFloatScalarToSignedTwoByteFixed((uint8_t*)&avatarInfo->sensorToWorldScale, scale.x, SENSOR_TO_WORLD_SCALE_RADIX);
avatarInfo->sensorToWorldTrans[0] = sensorToWorldMatrix[3][0];
avatarInfo->sensorToWorldTrans[1] = sensorToWorldMatrix[3][1];
avatarInfo->sensorToWorldTrans[2] = sensorToWorldMatrix[3][2];
// joint rotation data
*destinationBuffer++ = _jointData.size();
unsigned char* validityPosition = destinationBuffer;
unsigned char validity = 0;
int validityBit = 0;
setSemiNibbleAt(avatarInfo->flags, KEY_STATE_START_BIT, _keyState);
// hand state
bool isFingerPointing = _handState & IS_FINGER_POINTING_FLAG;
setSemiNibbleAt(avatarInfo->flags, HAND_STATE_START_BIT, _handState & ~IS_FINGER_POINTING_FLAG);
if (isFingerPointing) {
setAtBit(avatarInfo->flags, HAND_STATE_FINGER_POINTING_BIT);
}
// faceshift state
if (_headData->_isFaceTrackerConnected) {
setAtBit(avatarInfo->flags, IS_FACESHIFT_CONNECTED);
}
// eye tracker state
if (_headData->_isEyeTrackerConnected) {
setAtBit(avatarInfo->flags, IS_EYE_TRACKER_CONNECTED);
}
// referential state
QUuid parentID = getParentID();
if (!parentID.isNull()) {
setAtBit(avatarInfo->flags, HAS_REFERENTIAL);
}
destinationBuffer += sizeof(AvatarDataPacket::AvatarInfo);
#ifdef WANT_DEBUG
int rotationSentCount = 0;
unsigned char* beforeRotations = destinationBuffer;
#endif
if (!parentID.isNull()) {
auto parentInfo = reinterpret_cast<AvatarDataPacket::ParentInfo*>(destinationBuffer);
QByteArray referentialAsBytes = parentID.toRfc4122();
memcpy(parentInfo->parentUUID, referentialAsBytes.data(), referentialAsBytes.size());
parentInfo->parentJointIndex = _parentJointIndex;
destinationBuffer += sizeof(AvatarDataPacket::ParentInfo);
}
_lastSentJointData.resize(_jointData.size());
// If it is connected, pack up the data
if (_headData->_isFaceTrackerConnected) {
auto faceTrackerInfo = reinterpret_cast<AvatarDataPacket::FaceTrackerInfo*>(destinationBuffer);
for (int i=0; i < _jointData.size(); i++) {
const JointData& data = _jointData[i];
if (sendAll || _lastSentJointData[i].rotation != data.rotation) {
if (sendAll ||
!cullSmallChanges ||
fabsf(glm::dot(data.rotation, _lastSentJointData[i].rotation)) <= AVATAR_MIN_ROTATION_DOT) {
if (data.rotationSet) {
validity |= (1 << validityBit);
#ifdef WANT_DEBUG
rotationSentCount++;
#endif
faceTrackerInfo->leftEyeBlink = _headData->_leftEyeBlink;
faceTrackerInfo->rightEyeBlink = _headData->_rightEyeBlink;
faceTrackerInfo->averageLoudness = _headData->_averageLoudness;
faceTrackerInfo->browAudioLift = _headData->_browAudioLift;
faceTrackerInfo->numBlendshapeCoefficients = _headData->_blendshapeCoefficients.size();
destinationBuffer += sizeof(AvatarDataPacket::FaceTrackerInfo);
// followed by a variable number of float coefficients
memcpy(destinationBuffer, _headData->_blendshapeCoefficients.data(), _headData->_blendshapeCoefficients.size() * sizeof(float));
destinationBuffer += _headData->_blendshapeCoefficients.size() * sizeof(float);
}
QReadLocker readLock(&_jointDataLock);
// joint rotation data
*destinationBuffer++ = _jointData.size();
unsigned char* validityPosition = destinationBuffer;
unsigned char validity = 0;
int validityBit = 0;
#ifdef WANT_DEBUG
int rotationSentCount = 0;
unsigned char* beforeRotations = destinationBuffer;
#endif
_lastSentJointData.resize(_jointData.size());
for (int i=0; i < _jointData.size(); i++) {
const JointData& data = _jointData[i];
if (sendAll || _lastSentJointData[i].rotation != data.rotation) {
if (sendAll ||
!cullSmallChanges ||
fabsf(glm::dot(data.rotation, _lastSentJointData[i].rotation)) <= AVATAR_MIN_ROTATION_DOT) {
if (data.rotationSet) {
validity |= (1 << validityBit);
#ifdef WANT_DEBUG
rotationSentCount++;
#endif
}
}
}
}
if (++validityBit == BITS_IN_BYTE) {
*destinationBuffer++ = validity;
validityBit = validity = 0;
}
}
if (validityBit != 0) {
*destinationBuffer++ = validity;
}
validityBit = 0;
validity = *validityPosition++;
for (int i = 0; i < _jointData.size(); i ++) {
const JointData& data = _jointData[i];
if (validity & (1 << validityBit)) {
destinationBuffer += packOrientationQuatToSixBytes(destinationBuffer, data.rotation);
}
if (++validityBit == BITS_IN_BYTE) {
validityBit = 0;
validity = *validityPosition++;
}
}
// joint translation data
validityPosition = destinationBuffer;
validity = 0;
validityBit = 0;
#ifdef WANT_DEBUG
int translationSentCount = 0;
unsigned char* beforeTranslations = destinationBuffer;
#endif
float maxTranslationDimension = 0.0;
for (int i=0; i < _jointData.size(); i++) {
const JointData& data = _jointData[i];
if (sendAll || _lastSentJointData[i].translation != data.translation) {
if (sendAll ||
!cullSmallChanges ||
glm::distance(data.translation, _lastSentJointData[i].translation) > AVATAR_MIN_TRANSLATION) {
if (data.translationSet) {
validity |= (1 << validityBit);
#ifdef WANT_DEBUG
translationSentCount++;
#endif
maxTranslationDimension = glm::max(fabsf(data.translation.x), maxTranslationDimension);
maxTranslationDimension = glm::max(fabsf(data.translation.y), maxTranslationDimension);
maxTranslationDimension = glm::max(fabsf(data.translation.z), maxTranslationDimension);
}
if (++validityBit == BITS_IN_BYTE) {
*destinationBuffer++ = validity;
validityBit = validity = 0;
}
}
if (++validityBit == BITS_IN_BYTE) {
if (validityBit != 0) {
*destinationBuffer++ = validity;
validityBit = validity = 0;
}
}
if (validityBit != 0) {
*destinationBuffer++ = validity;
}
validityBit = 0;
validity = *validityPosition++;
for (int i = 0; i < _jointData.size(); i ++) {
const JointData& data = _jointData[i];
if (validity & (1 << validityBit)) {
destinationBuffer +=
packFloatVec3ToSignedTwoByteFixed(destinationBuffer, data.translation, TRANSLATION_COMPRESSION_RADIX);
validityBit = 0;
validity = *validityPosition++;
for (int i = 0; i < _jointData.size(); i ++) {
const JointData& data = _jointData[i];
if (validity & (1 << validityBit)) {
destinationBuffer += packOrientationQuatToSixBytes(destinationBuffer, data.rotation);
}
if (++validityBit == BITS_IN_BYTE) {
validityBit = 0;
validity = *validityPosition++;
}
}
if (++validityBit == BITS_IN_BYTE) {
validityBit = 0;
validity = *validityPosition++;
// joint translation data
validityPosition = destinationBuffer;
validity = 0;
validityBit = 0;
#ifdef WANT_DEBUG
int translationSentCount = 0;
unsigned char* beforeTranslations = destinationBuffer;
#endif
float maxTranslationDimension = 0.0;
for (int i=0; i < _jointData.size(); i++) {
const JointData& data = _jointData[i];
if (sendAll || _lastSentJointData[i].translation != data.translation) {
if (sendAll ||
!cullSmallChanges ||
glm::distance(data.translation, _lastSentJointData[i].translation) > AVATAR_MIN_TRANSLATION) {
if (data.translationSet) {
validity |= (1 << validityBit);
#ifdef WANT_DEBUG
translationSentCount++;
#endif
maxTranslationDimension = glm::max(fabsf(data.translation.x), maxTranslationDimension);
maxTranslationDimension = glm::max(fabsf(data.translation.y), maxTranslationDimension);
maxTranslationDimension = glm::max(fabsf(data.translation.z), maxTranslationDimension);
}
}
}
if (++validityBit == BITS_IN_BYTE) {
*destinationBuffer++ = validity;
validityBit = validity = 0;
}
}
}
// faux joints
Transform controllerLeftHandTransform = Transform(getControllerLeftHandMatrix());
destinationBuffer += packOrientationQuatToSixBytes(destinationBuffer, controllerLeftHandTransform.getRotation());
destinationBuffer += packFloatVec3ToSignedTwoByteFixed(destinationBuffer, controllerLeftHandTransform.getTranslation(),
TRANSLATION_COMPRESSION_RADIX);
Transform controllerRightHandTransform = Transform(getControllerRightHandMatrix());
destinationBuffer += packOrientationQuatToSixBytes(destinationBuffer, controllerRightHandTransform.getRotation());
destinationBuffer += packFloatVec3ToSignedTwoByteFixed(destinationBuffer, controllerRightHandTransform.getTranslation(),
TRANSLATION_COMPRESSION_RADIX);
if (validityBit != 0) {
*destinationBuffer++ = validity;
}
#ifdef WANT_DEBUG
if (sendAll) {
qDebug() << "AvatarData::toByteArray" << cullSmallChanges << sendAll
<< "rotations:" << rotationSentCount << "translations:" << translationSentCount
<< "largest:" << maxTranslationDimension
<< "size:"
<< (beforeRotations - startPosition) << "+"
<< (beforeTranslations - beforeRotations) << "+"
<< (destinationBuffer - beforeTranslations) << "="
<< (destinationBuffer - startPosition);
validityBit = 0;
validity = *validityPosition++;
for (int i = 0; i < _jointData.size(); i ++) {
const JointData& data = _jointData[i];
if (validity & (1 << validityBit)) {
destinationBuffer +=
packFloatVec3ToSignedTwoByteFixed(destinationBuffer, data.translation, TRANSLATION_COMPRESSION_RADIX);
}
if (++validityBit == BITS_IN_BYTE) {
validityBit = 0;
validity = *validityPosition++;
}
}
// faux joints
Transform controllerLeftHandTransform = Transform(getControllerLeftHandMatrix());
destinationBuffer += packOrientationQuatToSixBytes(destinationBuffer, controllerLeftHandTransform.getRotation());
destinationBuffer += packFloatVec3ToSignedTwoByteFixed(destinationBuffer, controllerLeftHandTransform.getTranslation(),
TRANSLATION_COMPRESSION_RADIX);
Transform controllerRightHandTransform = Transform(getControllerRightHandMatrix());
destinationBuffer += packOrientationQuatToSixBytes(destinationBuffer, controllerRightHandTransform.getRotation());
destinationBuffer += packFloatVec3ToSignedTwoByteFixed(destinationBuffer, controllerRightHandTransform.getTranslation(),
TRANSLATION_COMPRESSION_RADIX);
#ifdef WANT_DEBUG
if (sendAll) {
qCDebug(avatars) << "AvatarData::toByteArray" << cullSmallChanges << sendAll
<< "rotations:" << rotationSentCount << "translations:" << translationSentCount
<< "largest:" << maxTranslationDimension
<< "size:"
<< (beforeRotations - startPosition) << "+"
<< (beforeTranslations - beforeRotations) << "+"
<< (destinationBuffer - beforeTranslations) << "="
<< (destinationBuffer - startPosition);
}
#endif
}
#endif
return avatarDataByteArray.left(destinationBuffer - startPosition);
}
@ -474,18 +505,31 @@ int AvatarData::parseDataFromBuffer(const QByteArray& buffer) {
_headData = new HeadData(this);
}
uint8_t packetStateFlags = buffer.at(0);
bool minimumSent = oneAtBit(packetStateFlags, AVATARDATA_FLAGS_MINIMUM);
const unsigned char* startPosition = reinterpret_cast<const unsigned char*>(buffer.data());
const unsigned char* endPosition = startPosition + buffer.size();
const unsigned char* sourceBuffer = startPosition;
const unsigned char* sourceBuffer = startPosition + sizeof(packetStateFlags); // skip the flags!!
// if this is the minimum, then it only includes the flags
if (minimumSent) {
memcpy(&_globalPosition, sourceBuffer, sizeof(_globalPosition));
sourceBuffer += sizeof(_globalPosition);
int numBytesRead = (sourceBuffer - startPosition);
_averageBytesReceived.updateAverage(numBytesRead);
return numBytesRead;
}
quint64 now = usecTimestampNow();
PACKET_READ_CHECK(Header, sizeof(AvatarDataPacket::Header));
auto header = reinterpret_cast<const AvatarDataPacket::Header*>(sourceBuffer);
sourceBuffer += sizeof(AvatarDataPacket::Header);
PACKET_READ_CHECK(AvatarInfo, sizeof(AvatarDataPacket::AvatarInfo));
auto avatarInfo = reinterpret_cast<const AvatarDataPacket::AvatarInfo*>(sourceBuffer);
sourceBuffer += sizeof(AvatarDataPacket::AvatarInfo);
glm::vec3 position = glm::vec3(header->position[0], header->position[1], header->position[2]);
_globalPosition = glm::vec3(header->globalPosition[0], header->globalPosition[1], header->globalPosition[2]);
_globalBoundingBoxCorner = glm::vec3(header->globalBoundingBoxCorner[0], header->globalBoundingBoxCorner[1], header->globalBoundingBoxCorner[2]);
glm::vec3 position = glm::vec3(avatarInfo->position[0], avatarInfo->position[1], avatarInfo->position[2]);
_globalPosition = glm::vec3(avatarInfo->globalPosition[0], avatarInfo->globalPosition[1], avatarInfo->globalPosition[2]);
_globalBoundingBoxCorner = glm::vec3(avatarInfo->globalBoundingBoxCorner[0], avatarInfo->globalBoundingBoxCorner[1], avatarInfo->globalBoundingBoxCorner[2]);
if (isNaN(position)) {
if (shouldLogError(now)) {
qCWarning(avatars) << "Discard AvatarData packet: position NaN, uuid " << getSessionUUID();
@ -495,9 +539,9 @@ int AvatarData::parseDataFromBuffer(const QByteArray& buffer) {
setLocalPosition(position);
float pitch, yaw, roll;
unpackFloatAngleFromTwoByte(header->localOrientation + 0, &yaw);
unpackFloatAngleFromTwoByte(header->localOrientation + 1, &pitch);
unpackFloatAngleFromTwoByte(header->localOrientation + 2, &roll);
unpackFloatAngleFromTwoByte(avatarInfo->localOrientation + 0, &yaw);
unpackFloatAngleFromTwoByte(avatarInfo->localOrientation + 1, &pitch);
unpackFloatAngleFromTwoByte(avatarInfo->localOrientation + 2, &roll);
if (isNaN(yaw) || isNaN(pitch) || isNaN(roll)) {
if (shouldLogError(now)) {
qCWarning(avatars) << "Discard AvatarData packet: localOriention is NaN, uuid " << getSessionUUID();
@ -514,7 +558,7 @@ int AvatarData::parseDataFromBuffer(const QByteArray& buffer) {
}
float scale;
unpackFloatRatioFromTwoByte((uint8_t*)&header->scale, scale);
unpackFloatRatioFromTwoByte((uint8_t*)&avatarInfo->scale, scale);
if (isNaN(scale)) {
if (shouldLogError(now)) {
qCWarning(avatars) << "Discard AvatarData packet: scale NaN, uuid " << getSessionUUID();
@ -523,7 +567,7 @@ int AvatarData::parseDataFromBuffer(const QByteArray& buffer) {
}
setTargetScale(scale);
glm::vec3 lookAt = glm::vec3(header->lookAtPosition[0], header->lookAtPosition[1], header->lookAtPosition[2]);
glm::vec3 lookAt = glm::vec3(avatarInfo->lookAtPosition[0], avatarInfo->lookAtPosition[1], avatarInfo->lookAtPosition[2]);
if (isNaN(lookAt)) {
if (shouldLogError(now)) {
qCWarning(avatars) << "Discard AvatarData packet: lookAtPosition is NaN, uuid " << getSessionUUID();
@ -532,7 +576,7 @@ int AvatarData::parseDataFromBuffer(const QByteArray& buffer) {
}
_headData->_lookAtPosition = lookAt;
float audioLoudness = header->audioLoudness;
float audioLoudness = avatarInfo->audioLoudness;
if (isNaN(audioLoudness)) {
if (shouldLogError(now)) {
qCWarning(avatars) << "Discard AvatarData packet: audioLoudness is NaN, uuid " << getSessionUUID();
@ -542,16 +586,16 @@ int AvatarData::parseDataFromBuffer(const QByteArray& buffer) {
_headData->_audioLoudness = audioLoudness;
glm::quat sensorToWorldQuat;
unpackOrientationQuatFromSixBytes(header->sensorToWorldQuat, sensorToWorldQuat);
unpackOrientationQuatFromSixBytes(avatarInfo->sensorToWorldQuat, sensorToWorldQuat);
float sensorToWorldScale;
unpackFloatScalarFromSignedTwoByteFixed((int16_t*)&header->sensorToWorldScale, &sensorToWorldScale, SENSOR_TO_WORLD_SCALE_RADIX);
glm::vec3 sensorToWorldTrans(header->sensorToWorldTrans[0], header->sensorToWorldTrans[1], header->sensorToWorldTrans[2]);
unpackFloatScalarFromSignedTwoByteFixed((int16_t*)&avatarInfo->sensorToWorldScale, &sensorToWorldScale, SENSOR_TO_WORLD_SCALE_RADIX);
glm::vec3 sensorToWorldTrans(avatarInfo->sensorToWorldTrans[0], avatarInfo->sensorToWorldTrans[1], avatarInfo->sensorToWorldTrans[2]);
glm::mat4 sensorToWorldMatrix = createMatFromScaleQuatAndPos(glm::vec3(sensorToWorldScale), sensorToWorldQuat, sensorToWorldTrans);
_sensorToWorldMatrixCache.set(sensorToWorldMatrix);
{ // bitFlags and face data
uint8_t bitItems = header->flags;
uint8_t bitItems = avatarInfo->flags;
// key state, stored as a semi-nibble in the bitItems
_keyState = (KeyState)getSemiNibbleAt(bitItems, KEY_STATE_START_BIT);
@ -678,7 +722,7 @@ int AvatarData::parseDataFromBuffer(const QByteArray& buffer) {
#ifdef WANT_DEBUG
if (numValidJointRotations > 15) {
qDebug() << "RECEIVING -- rotations:" << numValidJointRotations
qCDebug(avatars) << "RECEIVING -- rotations:" << numValidJointRotations
<< "translations:" << numValidJointTranslations
<< "size:" << (int)(sourceBuffer - startPosition);
}
@ -984,7 +1028,7 @@ QStringList AvatarData::getJointNames() const {
void AvatarData::parseAvatarIdentityPacket(const QByteArray& data, Identity& identityOut) {
QDataStream packetStream(data);
packetStream >> identityOut.uuid >> identityOut.skeletonModelURL >> identityOut.attachmentData >> identityOut.displayName >> identityOut.avatarEntityData;
packetStream >> identityOut.uuid >> identityOut.skeletonModelURL >> identityOut.attachmentData >> identityOut.displayName >> identityOut.sessionDisplayName >> identityOut.avatarEntityData;
}
static const QUrl emptyURL("");
@ -1006,6 +1050,7 @@ bool AvatarData::processAvatarIdentity(const Identity& identity) {
setDisplayName(identity.displayName);
hasIdentityChanged = true;
}
maybeUpdateSessionDisplayNameFromTransport(identity.sessionDisplayName);
if (identity.attachmentData != _attachmentData) {
setAttachmentData(identity.attachmentData);
@ -1030,7 +1075,7 @@ QByteArray AvatarData::identityByteArray() {
const QUrl& urlToSend = cannonicalSkeletonModelURL(emptyURL);
_avatarEntitiesLock.withReadLock([&] {
identityStream << getSessionUUID() << urlToSend << _attachmentData << _displayName << _avatarEntityData;
identityStream << getSessionUUID() << urlToSend << _attachmentData << _displayName << getSessionDisplayNameForTransport() << _avatarEntityData;
});
return identityData;
@ -1180,9 +1225,9 @@ void AvatarData::sendAvatarDataPacket() {
// about 2% of the time, we send a full update (meaning, we transmit all the joint data), even if nothing has changed.
// this is to guard against a joint moving once, the packet getting lost, and the joint never moving again.
bool sendFullUpdate = randFloat() < AVATAR_SEND_FULL_UPDATE_RATIO;
QByteArray avatarByteArray = toByteArray(true, sendFullUpdate);
doneEncoding(true);
QByteArray avatarByteArray = toByteArray((randFloat() < AVATAR_SEND_FULL_UPDATE_RATIO) ? SendAllData : CullSmallData);
doneEncoding(true); // FIXME - doneEncoding() takes a bool for culling small changes, that's janky!
static AvatarDataSequenceNumber sequenceNumber = 0;
@ -1385,6 +1430,7 @@ static const QString JSON_AVATAR_HEAD = QStringLiteral("head");
static const QString JSON_AVATAR_HEAD_MODEL = QStringLiteral("headModel");
static const QString JSON_AVATAR_BODY_MODEL = QStringLiteral("bodyModel");
static const QString JSON_AVATAR_DISPLAY_NAME = QStringLiteral("displayName");
// It isn't meaningful to persist sessionDisplayName.
static const QString JSON_AVATAR_ATTACHEMENTS = QStringLiteral("attachments");
static const QString JSON_AVATAR_ENTITIES = QStringLiteral("attachedEntities");
static const QString JSON_AVATAR_SCALE = QStringLiteral("scale");
@ -1448,7 +1494,7 @@ QJsonObject AvatarData::toJson() const {
bool success;
Transform avatarTransform = getTransform(success);
if (!success) {
qDebug() << "Warning -- AvatarData::toJson couldn't get avatar transform";
qCWarning(avatars) << "Warning -- AvatarData::toJson couldn't get avatar transform";
}
avatarTransform.setScale(getDomainLimitedScale());
if (recordingBasis) {
@ -1593,7 +1639,7 @@ QByteArray AvatarData::toFrame(const AvatarData& avatar) {
{
QJsonObject obj = root;
obj.remove(JSON_AVATAR_JOINT_ARRAY);
qDebug().noquote() << QJsonDocument(obj).toJson(QJsonDocument::JsonFormat::Indented);
qCDebug(avatars).noquote() << QJsonDocument(obj).toJson(QJsonDocument::JsonFormat::Indented);
}
#endif
return QJsonDocument(root).toBinaryData();
@ -1606,7 +1652,7 @@ void AvatarData::fromFrame(const QByteArray& frameData, AvatarData& result) {
{
QJsonObject obj = doc.object();
obj.remove(JSON_AVATAR_JOINT_ARRAY);
qDebug().noquote() << QJsonDocument(obj).toJson(QJsonDocument::JsonFormat::Indented);
qCDebug(avatars).noquote() << QJsonDocument(obj).toJson(QJsonDocument::JsonFormat::Indented);
}
#endif
result.fromJson(doc.object());

View file

@ -106,6 +106,11 @@ const char LEFT_HAND_POINTING_FLAG = 1;
const char RIGHT_HAND_POINTING_FLAG = 2;
const char IS_FINGER_POINTING_FLAG = 4;
// AvatarData state flags - we store the details about the packet encoding in the first byte,
// before the "header" structure
const char AVATARDATA_FLAGS_MINIMUM = 0;
static const float MAX_AVATAR_SCALE = 1000.0f;
static const float MIN_AVATAR_SCALE = .005f;
@ -171,6 +176,9 @@ class AvatarData : public QObject, public SpatiallyNestable {
Q_PROPERTY(float audioAverageLoudness READ getAudioAverageLoudness WRITE setAudioAverageLoudness)
Q_PROPERTY(QString displayName READ getDisplayName WRITE setDisplayName)
// sessionDisplayName is sanitized, defaulted version displayName that is defined by the AvatarMixer rather than by Interface clients.
// The result is unique among all avatars present at the time.
Q_PROPERTY(QString sessionDisplayName READ getSessionDisplayName WRITE setSessionDisplayName)
Q_PROPERTY(QString skeletonModelURL READ getSkeletonModelURLFromScript WRITE setSkeletonModelURLFromScript)
Q_PROPERTY(QVector<AttachmentData> attachmentData READ getAttachmentData WRITE setAttachmentData)
@ -201,7 +209,14 @@ public:
glm::vec3 getHandPosition() const;
void setHandPosition(const glm::vec3& handPosition);
virtual QByteArray toByteArray(bool cullSmallChanges, bool sendAll);
typedef enum {
MinimumData,
CullSmallData,
IncludeSmallData,
SendAllData
} AvatarDataDetail;
virtual QByteArray toByteArray(AvatarDataDetail dataDetail);
virtual void doneEncoding(bool cullSmallChanges);
/// \return true if an error should be logged
@ -313,6 +328,7 @@ public:
QUrl skeletonModelURL;
QVector<AttachmentData> attachmentData;
QString displayName;
QString sessionDisplayName;
AvatarEntityMap avatarEntityData;
};
@ -325,9 +341,11 @@ public:
const QUrl& getSkeletonModelURL() const { return _skeletonModelURL; }
const QString& getDisplayName() const { return _displayName; }
const QString& getSessionDisplayName() const { return _sessionDisplayName; }
virtual void setSkeletonModelURL(const QUrl& skeletonModelURL);
virtual void setDisplayName(const QString& displayName);
virtual void setSessionDisplayName(const QString& sessionDisplayName) { _sessionDisplayName = sessionDisplayName; };
Q_INVOKABLE QVector<AttachmentData> getAttachmentData() const;
Q_INVOKABLE virtual void setAttachmentData(const QVector<AttachmentData>& attachmentData);
@ -390,6 +408,8 @@ public slots:
protected:
glm::vec3 _handPosition;
virtual const QString& getSessionDisplayNameForTransport() const { return _sessionDisplayName; }
virtual void maybeUpdateSessionDisplayNameFromTransport(const QString& sessionDisplayName) { } // No-op in AvatarMixer
// Body scale
float _targetScale;
@ -417,6 +437,7 @@ protected:
QUrl _skeletonFBXURL;
QVector<AttachmentData> _attachmentData;
QString _displayName;
QString _sessionDisplayName { };
const QUrl& cannonicalSkeletonModelURL(const QUrl& empty);
float _displayNameTargetAlpha;

View file

@ -133,6 +133,18 @@ void AvatarHashMap::processAvatarIdentityPacket(QSharedPointer<ReceivedMessage>
// make sure this isn't for an ignored avatar
auto nodeList = DependencyManager::get<NodeList>();
static auto EMPTY = QUuid();
{
QReadLocker locker(&_hashLock);
auto me = _avatarHash.find(EMPTY);
if ((me != _avatarHash.end()) && (identity.uuid == me.value()->getSessionUUID())) {
// We add MyAvatar to _avatarHash with an empty UUID. Code relies on this. In order to correctly handle an
// identity packet for ourself (such as when we are assigned a sessionDisplayName by the mixer upon joining),
// we make things match here.
identity.uuid = EMPTY;
}
}
if (!nodeList->isIgnoringNode(identity.uuid)) {
// mesh URL for a UUID, find avatar in our list
auto avatar = newOrExistingAvatar(identity.uuid, sendingNode);
@ -160,7 +172,7 @@ void AvatarHashMap::removeAvatar(const QUuid& sessionUUID, KillAvatarReason remo
}
void AvatarHashMap::handleRemovedAvatar(const AvatarSharedPointer& removedAvatar, KillAvatarReason removalReason) {
qDebug() << "Removed avatar with UUID" << uuidStringWithoutCurlyBraces(removedAvatar->getSessionUUID())
qCDebug(avatars) << "Removed avatar with UUID" << uuidStringWithoutCurlyBraces(removedAvatar->getSessionUUID())
<< "from AvatarHashMap";
emit avatarRemovedEvent(removedAvatar->getSessionUUID());
}

View file

@ -152,7 +152,6 @@ CompositorHelper::CompositorHelper() :
// auto cursor = Cursor::Manager::instance().getCursor();
// cursor->setIcon(Cursor::Icon::DEFAULT);
// if (!_tooltipId.isEmpty()) {
// qDebug() << "Closing tooltip " << _tooltipId;
// Tooltip::closeTip(_tooltipId);
// _tooltipId.clear();
// }

View file

@ -96,7 +96,7 @@ public:
Lock lock(_mutex);
_shutdown = true;
_condition.wait(lock, [&] { return !_shutdown; });
qDebug() << "Present thread shutdown";
qCDebug(displayPlugins) << "Present thread shutdown";
}
}

View file

@ -741,7 +741,6 @@ void HmdDisplayPlugin::compositeExtra() {
}
HmdDisplayPlugin::~HmdDisplayPlugin() {
qDebug() << "Destroying HmdDisplayPlugin";
}
float HmdDisplayPlugin::stutterRate() const {

View file

@ -286,7 +286,7 @@ bool RenderableModelEntityItem::getAnimationFrame() {
resizeJointArrays();
if (_jointMapping.size() != _model->getJointStateCount()) {
qDebug() << "RenderableModelEntityItem::getAnimationFrame -- joint count mismatch"
qCDebug(entities) << "RenderableModelEntityItem::getAnimationFrame -- joint count mismatch"
<< _jointMapping.size() << _model->getJointStateCount();
assert(false);
return false;

View file

@ -890,7 +890,7 @@ void RenderablePolyVoxEntityItem::decompressVolumeData() {
if (voxelXSize == 0 || voxelXSize > PolyVoxEntityItem::MAX_VOXEL_DIMENSION ||
voxelYSize == 0 || voxelYSize > PolyVoxEntityItem::MAX_VOXEL_DIMENSION ||
voxelZSize == 0 || voxelZSize > PolyVoxEntityItem::MAX_VOXEL_DIMENSION) {
qDebug() << "voxelSize is not reasonable, skipping decompressions."
qCDebug(entities) << "voxelSize is not reasonable, skipping decompressions."
<< voxelXSize << voxelYSize << voxelZSize << getName() << getID();
entity->setVoxelDataDirty(false);
return;
@ -903,7 +903,7 @@ void RenderablePolyVoxEntityItem::decompressVolumeData() {
QByteArray uncompressedData = qUncompress(compressedData);
if (uncompressedData.size() != rawSize) {
qDebug() << "PolyVox decompress -- size is (" << voxelXSize << voxelYSize << voxelZSize << ")"
qCDebug(entities) << "PolyVox decompress -- size is (" << voxelXSize << voxelYSize << voxelZSize << ")"
<< "so expected uncompressed length of" << rawSize << "but length is" << uncompressedData.size()
<< getName() << getID();
entity->setVoxelDataDirty(false);
@ -973,7 +973,7 @@ void RenderablePolyVoxEntityItem::compressVolumeDataAndSendEditPacket() {
if (newVoxelData.size() > 1150) {
// HACK -- until we have a way to allow for properties larger than MTU, don't update.
// revert the active voxel-space to the last version that fit.
qDebug() << "compressed voxel data is too large" << entity->getName() << entity->getID();
qCDebug(entities) << "compressed voxel data is too large" << entity->getName() << entity->getID();
return;
}

View file

@ -46,6 +46,9 @@ EntityItemPointer RenderableWebEntityItem::factory(const EntityItemID& entityID,
RenderableWebEntityItem::RenderableWebEntityItem(const EntityItemID& entityItemID) :
WebEntityItem(entityItemID) {
qCDebug(entities) << "Created web entity " << getID();
_touchDevice.setCapabilities(QTouchDevice::Position);
_touchDevice.setType(QTouchDevice::TouchScreen);
_touchDevice.setName("RenderableWebEntityItemTouchDevice");
@ -55,6 +58,9 @@ RenderableWebEntityItem::RenderableWebEntityItem(const EntityItemID& entityItemI
RenderableWebEntityItem::~RenderableWebEntityItem() {
destroyWebSurface();
qCDebug(entities) << "Destroyed web entity " << getID();
auto geometryCache = DependencyManager::get<GeometryCache>();
if (geometryCache) {
geometryCache->releaseID(_geometryId);
@ -88,6 +94,8 @@ bool RenderableWebEntityItem::buildWebSurface(QSharedPointer<EntityTreeRenderer>
++_currentWebCount;
qCDebug(entities) << "Building web surface: " << getID() << ", #" << _currentWebCount << ", url = " << _sourceUrl;
QSurface * currentSurface = currentContext->surface();
auto deleter = [](OffscreenQmlSurface* webSurface) {
@ -268,6 +276,9 @@ void RenderableWebEntityItem::loadSourceURL() {
void RenderableWebEntityItem::setSourceUrl(const QString& value) {
if (_sourceUrl != value) {
qCDebug(entities) << "Setting web entity source URL to " << value;
_sourceUrl = value;
if (_webSurface) {
AbstractViewStateInterface::instance()->postLambdaEvent([this] {
@ -386,6 +397,8 @@ void RenderableWebEntityItem::destroyWebSurface() {
QObject::disconnect(_hoverLeaveConnection);
_hoverLeaveConnection = QMetaObject::Connection();
_webSurface.reset();
qCDebug(entities) << "Delete web surface: " << getID() << ", #" << _currentWebCount << ", url = " << _sourceUrl;
}
}

View file

@ -167,10 +167,10 @@ void AnimationPropertyGroup::setFromOldAnimationSettings(const QString& value) {
void AnimationPropertyGroup::debugDump() const {
qDebug() << " AnimationPropertyGroup: ---------------------------------------------";
qDebug() << " url:" << getURL() << " has changed:" << urlChanged();
qDebug() << " fps:" << getFPS() << " has changed:" << fpsChanged();
qDebug() << "currentFrame:" << getCurrentFrame() << " has changed:" << currentFrameChanged();
qCDebug(entities) << " AnimationPropertyGroup: ---------------------------------------------";
qCDebug(entities) << " url:" << getURL() << " has changed:" << urlChanged();
qCDebug(entities) << " fps:" << getFPS() << " has changed:" << fpsChanged();
qCDebug(entities) << "currentFrame:" << getCurrentFrame() << " has changed:" << currentFrameChanged();
}
void AnimationPropertyGroup::listChangedProperties(QList<QString>& out) {

View file

@ -104,7 +104,7 @@ EntityActionType EntityActionInterface::actionTypeFromString(QString actionTypeS
return ACTION_TYPE_TRAVEL_ORIENTED;
}
qDebug() << "Warning -- EntityActionInterface::actionTypeFromString got unknown action-type name" << actionTypeString;
qCDebug(entities) << "Warning -- EntityActionInterface::actionTypeFromString got unknown action-type name" << actionTypeString;
return ACTION_TYPE_NONE;
}
@ -129,7 +129,7 @@ glm::vec3 EntityActionInterface::extractVec3Argument(QString objectName, QVarian
QString argumentName, bool& ok, bool required) {
if (!arguments.contains(argumentName)) {
if (required) {
qDebug() << objectName << "requires argument:" << argumentName;
qCDebug(entities) << objectName << "requires argument:" << argumentName;
}
ok = false;
return glm::vec3(0.0f);
@ -137,14 +137,14 @@ glm::vec3 EntityActionInterface::extractVec3Argument(QString objectName, QVarian
QVariant resultV = arguments[argumentName];
if (resultV.type() != (QVariant::Type) QMetaType::QVariantMap) {
qDebug() << objectName << "argument" << argumentName << "must be a map";
qCDebug(entities) << objectName << "argument" << argumentName << "must be a map";
ok = false;
return glm::vec3(0.0f);
}
QVariantMap resultVM = resultV.toMap();
if (!resultVM.contains("x") || !resultVM.contains("y") || !resultVM.contains("z")) {
qDebug() << objectName << "argument" << argumentName << "must be a map with keys: x, y, z";
qCDebug(entities) << objectName << "argument" << argumentName << "must be a map with keys: x, y, z";
ok = false;
return glm::vec3(0.0f);
}
@ -160,7 +160,7 @@ glm::vec3 EntityActionInterface::extractVec3Argument(QString objectName, QVarian
float y = yV.toFloat(&yOk);
float z = zV.toFloat(&zOk);
if (!xOk || !yOk || !zOk) {
qDebug() << objectName << "argument" << argumentName << "must be a map with keys: x, y, and z of type float.";
qCDebug(entities) << objectName << "argument" << argumentName << "must be a map with keys: x, y, and z of type float.";
ok = false;
return glm::vec3(0.0f);
}
@ -178,7 +178,7 @@ glm::quat EntityActionInterface::extractQuatArgument(QString objectName, QVarian
QString argumentName, bool& ok, bool required) {
if (!arguments.contains(argumentName)) {
if (required) {
qDebug() << objectName << "requires argument:" << argumentName;
qCDebug(entities) << objectName << "requires argument:" << argumentName;
}
ok = false;
return glm::quat();
@ -186,14 +186,14 @@ glm::quat EntityActionInterface::extractQuatArgument(QString objectName, QVarian
QVariant resultV = arguments[argumentName];
if (resultV.type() != (QVariant::Type) QMetaType::QVariantMap) {
qDebug() << objectName << "argument" << argumentName << "must be a map, not" << resultV.typeName();
qCDebug(entities) << objectName << "argument" << argumentName << "must be a map, not" << resultV.typeName();
ok = false;
return glm::quat();
}
QVariantMap resultVM = resultV.toMap();
if (!resultVM.contains("x") || !resultVM.contains("y") || !resultVM.contains("z") || !resultVM.contains("w")) {
qDebug() << objectName << "argument" << argumentName << "must be a map with keys: x, y, z, and w";
qCDebug(entities) << objectName << "argument" << argumentName << "must be a map with keys: x, y, z, and w";
ok = false;
return glm::quat();
}
@ -212,7 +212,7 @@ glm::quat EntityActionInterface::extractQuatArgument(QString objectName, QVarian
float z = zV.toFloat(&zOk);
float w = wV.toFloat(&wOk);
if (!xOk || !yOk || !zOk || !wOk) {
qDebug() << objectName << "argument" << argumentName
qCDebug(entities) << objectName << "argument" << argumentName
<< "must be a map with keys: x, y, z, and w of type float.";
ok = false;
return glm::quat();
@ -231,7 +231,7 @@ float EntityActionInterface::extractFloatArgument(QString objectName, QVariantMa
QString argumentName, bool& ok, bool required) {
if (!arguments.contains(argumentName)) {
if (required) {
qDebug() << objectName << "requires argument:" << argumentName;
qCDebug(entities) << objectName << "requires argument:" << argumentName;
}
ok = false;
return 0.0f;
@ -253,7 +253,7 @@ int EntityActionInterface::extractIntegerArgument(QString objectName, QVariantMa
QString argumentName, bool& ok, bool required) {
if (!arguments.contains(argumentName)) {
if (required) {
qDebug() << objectName << "requires argument:" << argumentName;
qCDebug(entities) << objectName << "requires argument:" << argumentName;
}
ok = false;
return 0.0f;
@ -275,7 +275,7 @@ QString EntityActionInterface::extractStringArgument(QString objectName, QVarian
QString argumentName, bool& ok, bool required) {
if (!arguments.contains(argumentName)) {
if (required) {
qDebug() << objectName << "requires argument:" << argumentName;
qCDebug(entities) << objectName << "requires argument:" << argumentName;
}
ok = false;
return "";
@ -287,7 +287,7 @@ bool EntityActionInterface::extractBooleanArgument(QString objectName, QVariantM
QString argumentName, bool& ok, bool required) {
if (!arguments.contains(argumentName)) {
if (required) {
qDebug() << objectName << "requires argument:" << argumentName;
qCDebug(entities) << objectName << "requires argument:" << argumentName;
}
ok = false;
return false;

View file

@ -52,12 +52,12 @@ void EntityEditPacketSender::queueEditAvatarEntityMessage(PacketType type,
assert(_myAvatar);
if (!entityTree) {
qDebug() << "EntityEditPacketSender::queueEditEntityMessage null entityTree.";
qCDebug(entities) << "EntityEditPacketSender::queueEditEntityMessage null entityTree.";
return;
}
EntityItemPointer entity = entityTree->findEntityByEntityItemID(entityItemID);
if (!entity) {
qDebug() << "EntityEditPacketSender::queueEditEntityMessage can't find entity.";
qCDebug(entities) << "EntityEditPacketSender::queueEditEntityMessage can't find entity.";
return;
}

View file

@ -189,7 +189,7 @@ QUuid EntityScriptingInterface::addEntity(const EntityItemProperties& properties
}
if (propertiesWithSimID.getParentID() == AVATAR_SELF_ID) {
qDebug() << "ERROR: Cannot set entity parent ID to the local-only MyAvatar ID";
qCDebug(entities) << "ERROR: Cannot set entity parent ID to the local-only MyAvatar ID";
propertiesWithSimID.setParentID(QUuid());
}
@ -370,7 +370,7 @@ QUuid EntityScriptingInterface::editEntity(QUuid id, const EntityItemProperties&
if (!scriptSideProperties.parentIDChanged()) {
properties.setParentID(entity->getParentID());
} else if (scriptSideProperties.getParentID() == AVATAR_SELF_ID) {
qDebug() << "ERROR: Cannot set entity parent ID to the local-only MyAvatar ID";
qCDebug(entities) << "ERROR: Cannot set entity parent ID to the local-only MyAvatar ID";
properties.setParentID(QUuid());
}
if (!scriptSideProperties.parentJointIndexChanged()) {
@ -931,12 +931,12 @@ bool EntityScriptingInterface::actionWorker(const QUuid& entityID,
EntitySimulationPointer simulation = _entityTree->getSimulation();
entity = _entityTree->findEntityByEntityItemID(entityID);
if (!entity) {
qDebug() << "actionWorker -- unknown entity" << entityID;
qCDebug(entities) << "actionWorker -- unknown entity" << entityID;
return;
}
if (!simulation) {
qDebug() << "actionWorker -- no simulation" << entityID;
qCDebug(entities) << "actionWorker -- no simulation" << entityID;
return;
}
@ -1051,7 +1051,7 @@ EntityItemPointer EntityScriptingInterface::checkForTreeEntityAndTypeMatch(const
EntityItemPointer entity = _entityTree->findEntityByEntityItemID(entityID);
if (!entity) {
qDebug() << "EntityScriptingInterface::checkForTreeEntityAndTypeMatch - no entity with ID" << entityID;
qCDebug(entities) << "EntityScriptingInterface::checkForTreeEntityAndTypeMatch - no entity with ID" << entityID;
return entity;
}
@ -1311,7 +1311,7 @@ QVector<QUuid> EntityScriptingInterface::getChildrenIDs(const QUuid& parentID) {
EntityItemPointer entity = _entityTree->findEntityByEntityItemID(parentID);
if (!entity) {
qDebug() << "EntityScriptingInterface::getChildrenIDs - no entity with ID" << parentID;
qCDebug(entities) << "EntityScriptingInterface::getChildrenIDs - no entity with ID" << parentID;
return result;
}

View file

@ -343,7 +343,7 @@ EntityItemPointer EntityTree::addEntity(const EntityItemID& entityID, const Enti
auto nodeList = DependencyManager::get<NodeList>();
if (!nodeList) {
qDebug() << "EntityTree::addEntity -- can't get NodeList";
qCDebug(entities) << "EntityTree::addEntity -- can't get NodeList";
return nullptr;
}
@ -1243,7 +1243,7 @@ bool EntityTree::hasEntitiesDeletedSince(quint64 sinceTime) {
if (hasSomethingNewer) {
int elapsed = usecTimestampNow() - considerEntitiesSince;
int difference = considerEntitiesSince - sinceTime;
qDebug() << "EntityTree::hasEntitiesDeletedSince() sinceTime:" << sinceTime
qCDebug(entities) << "EntityTree::hasEntitiesDeletedSince() sinceTime:" << sinceTime
<< "considerEntitiesSince:" << considerEntitiesSince << "elapsed:" << elapsed << "difference:" << difference;
}
#endif
@ -1276,7 +1276,7 @@ void EntityTree::forgetEntitiesDeletedBefore(quint64 sinceTime) {
// TODO: consider consolidating processEraseMessageDetails() and processEraseMessage()
int EntityTree::processEraseMessage(ReceivedMessage& message, const SharedNodePointer& sourceNode) {
#ifdef EXTRA_ERASE_DEBUGGING
qDebug() << "EntityTree::processEraseMessage()";
qCDebug(entities) << "EntityTree::processEraseMessage()";
#endif
withWriteLock([&] {
message.seek(sizeof(OCTREE_PACKET_FLAGS) + sizeof(OCTREE_PACKET_SEQUENCE) + sizeof(OCTREE_PACKET_SENT_TIME));
@ -1296,7 +1296,7 @@ int EntityTree::processEraseMessage(ReceivedMessage& message, const SharedNodePo
QUuid entityID = QUuid::fromRfc4122(message.readWithoutCopy(NUM_BYTES_RFC4122_UUID));
#ifdef EXTRA_ERASE_DEBUGGING
qDebug() << " ---- EntityTree::processEraseMessage() contained ID:" << entityID;
qCDebug(entities) << " ---- EntityTree::processEraseMessage() contained ID:" << entityID;
#endif
EntityItemID entityItemID(entityID);
@ -1318,7 +1318,7 @@ int EntityTree::processEraseMessage(ReceivedMessage& message, const SharedNodePo
// TODO: consider consolidating processEraseMessageDetails() and processEraseMessage()
int EntityTree::processEraseMessageDetails(const QByteArray& dataByteArray, const SharedNodePointer& sourceNode) {
#ifdef EXTRA_ERASE_DEBUGGING
qDebug() << "EntityTree::processEraseMessageDetails()";
qCDebug(entities) << "EntityTree::processEraseMessageDetails()";
#endif
const unsigned char* packetData = (const unsigned char*)dataByteArray.constData();
const unsigned char* dataAt = packetData;
@ -1347,7 +1347,7 @@ int EntityTree::processEraseMessageDetails(const QByteArray& dataByteArray, cons
processedBytes += encodedID.size();
#ifdef EXTRA_ERASE_DEBUGGING
qDebug() << " ---- EntityTree::processEraseMessageDetails() contains id:" << entityID;
qCDebug(entities) << " ---- EntityTree::processEraseMessageDetails() contains id:" << entityID;
#endif
EntityItemID entityItemID(entityID);

View file

@ -329,7 +329,7 @@ OctreeElement::AppendState EntityTreeElement::appendElementData(OctreePacketData
includeThisEntity = false; // too small, don't include it
#ifdef WANT_LOD_DEBUGGING
qDebug() << "skipping entity - TOO SMALL - \n"
qCDebug(entities) << "skipping entity - TOO SMALL - \n"
<< "......id:" << entity->getID() << "\n"
<< "....name:" << entity->getName() << "\n"
<< "..bounds:" << entityBounds << "\n"
@ -341,7 +341,7 @@ OctreeElement::AppendState EntityTreeElement::appendElementData(OctreePacketData
if (includeThisEntity) {
#ifdef WANT_LOD_DEBUGGING
qDebug() << "including entity - \n"
qCDebug(entities) << "including entity - \n"
<< "......id:" << entity->getID() << "\n"
<< "....name:" << entity->getName() << "\n"
<< "....cell:" << getAACube();
@ -472,7 +472,7 @@ bool EntityTreeElement::bestFitEntityBounds(EntityItemPointer entity) const {
bool success;
auto queryCube = entity->getQueryAACube(success);
if (!success) {
qDebug() << "EntityTreeElement::bestFitEntityBounds couldn't get queryCube for" << entity->getName() << entity->getID();
qCDebug(entities) << "EntityTreeElement::bestFitEntityBounds couldn't get queryCube for" << entity->getName() << entity->getID();
return false;
}
return bestFitBounds(queryCube);
@ -973,7 +973,7 @@ int EntityTreeElement::readElementDataFromBuffer(const unsigned char* data, int
}
} else {
#ifdef WANT_DEBUG
qDebug() << "Received packet for previously deleted entity [" <<
qCDebug(entities) << "Received packet for previously deleted entity [" <<
entityItem->getID() << "] ignoring. (inside " << __FUNCTION__ << ")";
#endif
}

View file

@ -19,6 +19,8 @@
#include <OctreeRenderer.h> // for RenderArgs
#include "EntitiesLogging.h"
class EntityItem;
using EntityItemPointer = std::shared_ptr<EntityItem>;
using EntityItemWeakPointer = std::weak_ptr<EntityItem>;
@ -77,7 +79,7 @@ private:
struct EntityRegistrationChecker {
EntityRegistrationChecker(bool result, const char* debugMessage) {
if (!result) {
qDebug() << debugMessage;
qCDebug(entities) << debugMessage;
}
}
};

View file

@ -60,12 +60,12 @@ void KeyLightPropertyGroup::merge(const KeyLightPropertyGroup& other) {
void KeyLightPropertyGroup::debugDump() const {
qDebug() << " KeyLightPropertyGroup: ---------------------------------------------";
qDebug() << " color:" << getColor(); // << "," << getColor()[1] << "," << getColor()[2];
qDebug() << " intensity:" << getIntensity();
qDebug() << " direction:" << getDirection();
qDebug() << " ambientIntensity:" << getAmbientIntensity();
qDebug() << " ambientURL:" << getAmbientURL();
qCDebug(entities) << " KeyLightPropertyGroup: ---------------------------------------------";
qCDebug(entities) << " color:" << getColor(); // << "," << getColor()[1] << "," << getColor()[2];
qCDebug(entities) << " intensity:" << getIntensity();
qCDebug(entities) << " direction:" << getDirection();
qCDebug(entities) << " ambientIntensity:" << getAmbientIntensity();
qCDebug(entities) << " ambientURL:" << getAmbientURL();
}
void KeyLightPropertyGroup::listChangedProperties(QList<QString>& out) {

View file

@ -80,12 +80,12 @@ bool LineEntityItem::setProperties(const EntityItemProperties& properties) {
bool LineEntityItem::appendPoint(const glm::vec3& point) {
if (_points.size() > MAX_POINTS_PER_LINE - 1) {
qDebug() << "MAX POINTS REACHED!";
qCDebug(entities) << "MAX POINTS REACHED!";
return false;
}
glm::vec3 halfBox = getDimensions() * 0.5f;
if ( (point.x < - halfBox.x || point.x > halfBox.x) || (point.y < -halfBox.y || point.y > halfBox.y) || (point.z < - halfBox.z || point.z > halfBox.z) ) {
qDebug() << "Point is outside entity's bounding box";
qCDebug(entities) << "Point is outside entity's bounding box";
return false;
}
_points << point;
@ -101,7 +101,7 @@ bool LineEntityItem::setLinePoints(const QVector<glm::vec3>& points) {
for (int i = 0; i < points.size(); i++) {
glm::vec3 point = points.at(i);
if ( (point.x < - halfBox.x || point.x > halfBox.x) || (point.y < -halfBox.y || point.y > halfBox.y) || (point.z < - halfBox.z || point.z > halfBox.z) ) {
qDebug() << "Point is outside entity's bounding box";
qCDebug(entities) << "Point is outside entity's bounding box";
return false;
}
}

View file

@ -89,12 +89,12 @@ bool PolyLineEntityItem::setProperties(const EntityItemProperties& properties) {
bool PolyLineEntityItem::appendPoint(const glm::vec3& point) {
if (_points.size() > MAX_POINTS_PER_LINE - 1) {
qDebug() << "MAX POINTS REACHED!";
qCDebug(entities) << "MAX POINTS REACHED!";
return false;
}
glm::vec3 halfBox = getDimensions() * 0.5f;
if ((point.x < -halfBox.x || point.x > halfBox.x) || (point.y < -halfBox.y || point.y > halfBox.y) || (point.z < -halfBox.z || point.z > halfBox.z)) {
qDebug() << "Point is outside entity's bounding box";
qCDebug(entities) << "Point is outside entity's bounding box";
return false;
}
_points << point;
@ -142,7 +142,7 @@ bool PolyLineEntityItem::setLinePoints(const QVector<glm::vec3>& points) {
if ((point.x < -halfBox.x || point.x > halfBox.x) ||
(point.y < -halfBox.y || point.y > halfBox.y) ||
(point.z < -halfBox.z || point.z > halfBox.z)) {
qDebug() << "Point is outside entity's bounding box";
qCDebug(entities) << "Point is outside entity's bounding box";
return false;
}
}

View file

@ -71,29 +71,29 @@ void PolyVoxEntityItem::setVoxelVolumeSize(glm::vec3 voxelVolumeSize) {
_voxelVolumeSize = glm::vec3(roundf(voxelVolumeSize.x), roundf(voxelVolumeSize.y), roundf(voxelVolumeSize.z));
if (_voxelVolumeSize.x < 1) {
qDebug() << "PolyVoxEntityItem::setVoxelVolumeSize clamping x of" << _voxelVolumeSize.x << "to 1";
qCDebug(entities) << "PolyVoxEntityItem::setVoxelVolumeSize clamping x of" << _voxelVolumeSize.x << "to 1";
_voxelVolumeSize.x = 1;
}
if (_voxelVolumeSize.x > MAX_VOXEL_DIMENSION) {
qDebug() << "PolyVoxEntityItem::setVoxelVolumeSize clamping x of" << _voxelVolumeSize.x << "to max";
qCDebug(entities) << "PolyVoxEntityItem::setVoxelVolumeSize clamping x of" << _voxelVolumeSize.x << "to max";
_voxelVolumeSize.x = MAX_VOXEL_DIMENSION;
}
if (_voxelVolumeSize.y < 1) {
qDebug() << "PolyVoxEntityItem::setVoxelVolumeSize clamping y of" << _voxelVolumeSize.y << "to 1";
qCDebug(entities) << "PolyVoxEntityItem::setVoxelVolumeSize clamping y of" << _voxelVolumeSize.y << "to 1";
_voxelVolumeSize.y = 1;
}
if (_voxelVolumeSize.y > MAX_VOXEL_DIMENSION) {
qDebug() << "PolyVoxEntityItem::setVoxelVolumeSize clamping y of" << _voxelVolumeSize.y << "to max";
qCDebug(entities) << "PolyVoxEntityItem::setVoxelVolumeSize clamping y of" << _voxelVolumeSize.y << "to max";
_voxelVolumeSize.y = MAX_VOXEL_DIMENSION;
}
if (_voxelVolumeSize.z < 1) {
qDebug() << "PolyVoxEntityItem::setVoxelVolumeSize clamping z of" << _voxelVolumeSize.z << "to 1";
qCDebug(entities) << "PolyVoxEntityItem::setVoxelVolumeSize clamping z of" << _voxelVolumeSize.z << "to 1";
_voxelVolumeSize.z = 1;
}
if (_voxelVolumeSize.z > MAX_VOXEL_DIMENSION) {
qDebug() << "PolyVoxEntityItem::setVoxelVolumeSize clamping z of" << _voxelVolumeSize.z << "to max";
qCDebug(entities) << "PolyVoxEntityItem::setVoxelVolumeSize clamping z of" << _voxelVolumeSize.z << "to max";
_voxelVolumeSize.z = MAX_VOXEL_DIMENSION;
}
});

View file

@ -34,9 +34,9 @@ void SkyboxPropertyGroup::merge(const SkyboxPropertyGroup& other) {
void SkyboxPropertyGroup::debugDump() const {
qDebug() << " SkyboxPropertyGroup: ---------------------------------------------";
qDebug() << " Color:" << getColor() << " has changed:" << colorChanged();
qDebug() << " URL:" << getURL() << " has changed:" << urlChanged();
qCDebug(entities) << " SkyboxPropertyGroup: ---------------------------------------------";
qCDebug(entities) << " Color:" << getColor() << " has changed:" << colorChanged();
qCDebug(entities) << " URL:" << getURL() << " has changed:" << urlChanged();
}
void SkyboxPropertyGroup::listChangedProperties(QList<QString>& out) {

View file

@ -67,14 +67,14 @@ void StagePropertyGroup::merge(const StagePropertyGroup& other) {
void StagePropertyGroup::debugDump() const {
qDebug() << " StagePropertyGroup: ---------------------------------------------";
qDebug() << " _sunModelEnabled:" << _sunModelEnabled;
qDebug() << " _latitude:" << _latitude;
qDebug() << " _longitude:" << _longitude;
qDebug() << " _altitude:" << _altitude;
qDebug() << " _day:" << _day;
qDebug() << " _hour:" << _hour;
qDebug() << " _automaticHourDay:" << _automaticHourDay;
qCDebug(entities) << " StagePropertyGroup: ---------------------------------------------";
qCDebug(entities) << " _sunModelEnabled:" << _sunModelEnabled;
qCDebug(entities) << " _latitude:" << _latitude;
qCDebug(entities) << " _longitude:" << _longitude;
qCDebug(entities) << " _altitude:" << _altitude;
qCDebug(entities) << " _day:" << _day;
qCDebug(entities) << " _hour:" << _hour;
qCDebug(entities) << " _automaticHourDay:" << _automaticHourDay;
}
void StagePropertyGroup::listChangedProperties(QList<QString>& out) {

View file

@ -194,7 +194,6 @@ QVariantHash FSTReader::downloadMapping(const QString& url) {
networkRequest.setAttribute(QNetworkRequest::FollowRedirectsAttribute, true);
networkRequest.setHeader(QNetworkRequest::UserAgentHeader, HIGH_FIDELITY_USER_AGENT);
QNetworkReply* reply = networkAccessManager.get(networkRequest);
qDebug() << "Downloading avatar file at " << url;
QEventLoop loop;
QObject::connect(reply, &QNetworkReply::finished, &loop, &QEventLoop::quit);
loop.exec();

View file

@ -103,11 +103,14 @@ public:
}
void report() {
uint64_t now = usecTimestampNow();
if ((now - _lastReport) > USECS_PER_SECOND * 5) {
_lastReport = now;
qCDebug(glLogging) << "Current offscreen texture count " << _allTextureCount;
qCDebug(glLogging) << "Current offscreen active texture count " << _activeTextureCount;
if (randFloat() < 0.01f) {
PROFILE_COUNTER(render_qml_gl, "offscreenTextures", {
{ "total", QVariant::fromValue(_allTextureCount.load()) },
{ "active", QVariant::fromValue(_activeTextureCount.load()) },
});
PROFILE_COUNTER(render_qml_gl, "offscreenTextureMemory", {
{ "value", QVariant::fromValue(_totalTextureUsage) }
});
}
}
@ -189,7 +192,6 @@ private:
std::unordered_map<GLuint, uvec2> _textureSizes;
Mutex _mutex;
std::list<OffscreenQmlSurface::TextureAndFence> _returnedTextures;
uint64_t _lastReport { 0 };
size_t _totalTextureUsage { 0 };
} offscreenTextures;
@ -424,7 +426,8 @@ void OffscreenQmlSurface::create(QOpenGLContext* shareContext) {
// a timer with a small interval is used to get better performance.
QObject::connect(&_updateTimer, &QTimer::timeout, this, &OffscreenQmlSurface::updateQuick);
QObject::connect(qApp, &QCoreApplication::aboutToQuit, this, &OffscreenQmlSurface::onAboutToQuit);
_updateTimer.setInterval(MIN_TIMER_MS);
_updateTimer.setTimerType(Qt::PreciseTimer);
_updateTimer.setInterval(MIN_TIMER_MS); // 5ms, Qt::PreciseTimer required
_updateTimer.start();
auto rootContext = getRootContext();

View file

@ -11,6 +11,8 @@
#include "GLBackend.h"
#include "GLState.h"
#include <gpu/GPULogging.h>
using namespace gpu;
using namespace gpu::gl;
@ -172,7 +174,7 @@ void GLBackend::do_setStateDepthTest(State::DepthTest test) {
glDepthFunc(COMPARISON_TO_GL[test.getFunction()]);
}
if (CHECK_GL_ERROR()) {
qDebug() << "DepthTest" << (test.isEnabled() ? "Enabled" : "Disabled")
qCDebug(gpulogging) << "DepthTest" << (test.isEnabled() ? "Enabled" : "Disabled")
<< "Mask=" << (test.getWriteMask() ? "Write" : "no Write")
<< "Func=" << test.getFunction()
<< "Raw=" << test.getRaw();

View file

@ -10,6 +10,8 @@
#include <gl/GLHelpers.h>
#include <gl/Context.h>
#include <gpu/GPULogging.h>
#include "GLShared.h"
#include "GLTexture.h"
@ -155,7 +157,7 @@ bool GLTextureTransferHelper::process() {
auto lastReportInterval = now - lastReport;
if (lastReportInterval > USECS_PER_SECOND * 4) {
lastReport = now;
qDebug() << "Texture list " << _transferringTextures.size();
qCDebug(gpulogging) << "Texture list " << _transferringTextures.size();
}
size_t transferCount = 0;

View file

@ -398,9 +398,13 @@ bool GL45Texture::continueTransfer() {
glTextureSubImage2D(_id, mipLevel, 0, 0, size.x, size.y, texelFormat.format, texelFormat.type, mip->readData());
} else if (GL_TEXTURE_CUBE_MAP == _target) {
// DSA ARB does not work on AMD, so use EXT
// glTextureSubImage3D(_id, mipLevel, 0, 0, face, size.x, size.y, 1, texelFormat.format, texelFormat.type, mip->readData());
auto target = CUBE_FACE_LAYOUT[face];
glTextureSubImage2DEXT(_id, target, mipLevel, 0, 0, size.x, size.y, texelFormat.format, texelFormat.type, mip->readData());
// unless EXT is not available on the driver
if (glTextureSubImage2DEXT) {
auto target = CUBE_FACE_LAYOUT[face];
glTextureSubImage2DEXT(_id, target, mipLevel, 0, 0, size.x, size.y, texelFormat.format, texelFormat.type, mip->readData());
} else {
glTextureSubImage3D(_id, mipLevel, 0, 0, face, size.x, size.y, 1, texelFormat.format, texelFormat.type, mip->readData());
}
} else {
Q_ASSERT(false);
}

View file

@ -13,6 +13,7 @@
#if _DEBUG
#include <QtCore/QDebug>
#include "GPULogging.h"
#endif
#include "Forward.h"
@ -318,13 +319,13 @@ public:
template <typename T> const T& get() const {
#if _DEBUG
if (!_buffer) {
qDebug() << "Accessing null gpu::buffer!";
qCDebug(gpulogging) << "Accessing null gpu::buffer!";
}
if (sizeof(T) > (_buffer->getSize() - _offset)) {
qDebug() << "Accessing buffer in non allocated memory, element size = " << sizeof(T) << " available space in buffer at offset is = " << (_buffer->getSize() - _offset);
qCDebug(gpulogging) << "Accessing buffer in non allocated memory, element size = " << sizeof(T) << " available space in buffer at offset is = " << (_buffer->getSize() - _offset);
}
if (sizeof(T) > _size) {
qDebug() << "Accessing buffer outside the BufferView range, element size = " << sizeof(T) << " when bufferView size = " << _size;
qCDebug(gpulogging) << "Accessing buffer outside the BufferView range, element size = " << sizeof(T) << " when bufferView size = " << _size;
}
#endif
const T* t = (reinterpret_cast<const T*> (_buffer->getData() + _offset));
@ -334,13 +335,13 @@ public:
template <typename T> T& edit() {
#if _DEBUG
if (!_buffer) {
qDebug() << "Accessing null gpu::buffer!";
qCDebug(gpulogging) << "Accessing null gpu::buffer!";
}
if (sizeof(T) > (_buffer->getSize() - _offset)) {
qDebug() << "Accessing buffer in non allocated memory, element size = " << sizeof(T) << " available space in buffer at offset is = " << (_buffer->getSize() - _offset);
qCDebug(gpulogging) << "Accessing buffer in non allocated memory, element size = " << sizeof(T) << " available space in buffer at offset is = " << (_buffer->getSize() - _offset);
}
if (sizeof(T) > _size) {
qDebug() << "Accessing buffer outside the BufferView range, element size = " << sizeof(T) << " when bufferView size = " << _size;
qCDebug(gpulogging) << "Accessing buffer outside the BufferView range, element size = " << sizeof(T) << " when bufferView size = " << _size;
}
#endif
_buffer->markDirty(_offset, sizeof(T));
@ -352,13 +353,13 @@ public:
Resource::Size elementOffset = index * _stride + _offset;
#if _DEBUG
if (!_buffer) {
qDebug() << "Accessing null gpu::buffer!";
qCDebug(gpulogging) << "Accessing null gpu::buffer!";
}
if (sizeof(T) > (_buffer->getSize() - elementOffset)) {
qDebug() << "Accessing buffer in non allocated memory, index = " << index << ", element size = " << sizeof(T) << " available space in buffer at offset is = " << (_buffer->getSize() - elementOffset);
qCDebug(gpulogging) << "Accessing buffer in non allocated memory, index = " << index << ", element size = " << sizeof(T) << " available space in buffer at offset is = " << (_buffer->getSize() - elementOffset);
}
if (index > getNum<T>()) {
qDebug() << "Accessing buffer outside the BufferView range, index = " << index << " number elements = " << getNum<T>();
qCDebug(gpulogging) << "Accessing buffer outside the BufferView range, index = " << index << " number elements = " << getNum<T>();
}
#endif
return *(reinterpret_cast<const T*> (_buffer->getData() + elementOffset));
@ -368,13 +369,13 @@ public:
Resource::Size elementOffset = index * _stride + _offset;
#if _DEBUG
if (!_buffer) {
qDebug() << "Accessing null gpu::buffer!";
qCDebug(gpulogging) << "Accessing null gpu::buffer!";
}
if (sizeof(T) > (_buffer->getSize() - elementOffset)) {
qDebug() << "Accessing buffer in non allocated memory, index = " << index << ", element size = " << sizeof(T) << " available space in buffer at offset is = " << (_buffer->getSize() - elementOffset);
qCDebug(gpulogging) << "Accessing buffer in non allocated memory, index = " << index << ", element size = " << sizeof(T) << " available space in buffer at offset is = " << (_buffer->getSize() - elementOffset);
}
if (index > getNum<T>()) {
qDebug() << "Accessing buffer outside the BufferView range, index = " << index << " number elements = " << getNum<T>();
qCDebug(gpulogging) << "Accessing buffer outside the BufferView range, index = " << index << " number elements = " << getNum<T>();
}
#endif
_buffer->markDirty(elementOffset, sizeof(T));

View file

@ -42,7 +42,7 @@ std::atomic<bool> Texture::_enableSparseTextures { recommendedSparseTextures };
struct ReportTextureState {
ReportTextureState() {
qDebug() << "[TEXTURE TRANSFER SUPPORT]"
qCDebug(gpulogging) << "[TEXTURE TRANSFER SUPPORT]"
<< "\n\tidealThreadCount:" << QThread::idealThreadCount()
<< "\n\tRECOMMENDED enableSparseTextures:" << recommendedSparseTextures;
}
@ -50,10 +50,10 @@ struct ReportTextureState {
void Texture::setEnableSparseTextures(bool enabled) {
#ifdef Q_OS_WIN
qDebug() << "[TEXTURE TRANSFER SUPPORT] SETTING - Enable Sparse Textures and Dynamic Texture Management:" << enabled;
qCDebug(gpulogging) << "[TEXTURE TRANSFER SUPPORT] SETTING - Enable Sparse Textures and Dynamic Texture Management:" << enabled;
_enableSparseTextures = enabled;
#else
qDebug() << "[TEXTURE TRANSFER SUPPORT] Sparse Textures and Dynamic Texture Management not supported on this platform.";
qCDebug(gpulogging) << "[TEXTURE TRANSFER SUPPORT] Sparse Textures and Dynamic Texture Management not supported on this platform.";
#endif
}
@ -114,7 +114,7 @@ Texture::Size Texture::getAllowedGPUMemoryUsage() {
}
void Texture::setAllowedGPUMemoryUsage(Size size) {
qDebug() << "New MAX texture memory " << BYTES_TO_MB(size) << " MB";
qCDebug(gpulogging) << "New MAX texture memory " << BYTES_TO_MB(size) << " MB";
_allowedCPUMemoryUsage = size;
}

View file

@ -72,7 +72,7 @@ QImage processSourceImage(const QImage& srcImage, bool cubemap) {
}
if (targetSize != srcImageSize) {
qDebug() << "Resizing texture from " << srcImageSize.x << "x" << srcImageSize.y << " to " << targetSize.x << "x" << targetSize.y;
qDebug(modelLog) << "Resizing texture from " << srcImageSize.x << "x" << srcImageSize.y << " to " << targetSize.x << "x" << targetSize.y;
return srcImage.scaled(fromGlm(targetSize));
}

View file

@ -633,7 +633,7 @@ void AccountManager::generateNewKeypair(bool isUserKeypair, const QUuid& domainI
_isWaitingForKeypairResponse = true;
// clear the current private key
qDebug() << "Clearing current private key in DataServerAccountInfo";
qCDebug(networking) << "Clearing current private key in DataServerAccountInfo";
_accountInfo.setPrivateKey(QByteArray());
// setup a new QThread to generate the keypair on, in case it takes a while
@ -727,7 +727,7 @@ void AccountManager::processGeneratedKeypair() {
}
void AccountManager::publicKeyUploadSucceeded(QNetworkReply& reply) {
qDebug() << "Uploaded public key to Metaverse API. RSA keypair generation is completed.";
qCDebug(networking) << "Uploaded public key to Metaverse API. RSA keypair generation is completed.";
// public key upload complete - store the matching private key and persist the account to settings
_accountInfo.setPrivateKey(_pendingPrivateKey);

View file

@ -76,7 +76,7 @@ void AssetResourceRequest::requestMappingForPath(const AssetPath& path) {
switch (request->getError()) {
case MappingRequest::NoError:
// we have no error, we should have a resulting hash - use that to send of a request for that asset
qDebug() << "Got mapping for:" << path << "=>" << request->getHash();
qCDebug(networking) << "Got mapping for:" << path << "=>" << request->getHash();
requestHash(request->getHash());

View file

@ -41,12 +41,12 @@ DomainHandler::DomainHandler(QObject* parent) :
// setup a timeout for failure on settings requests
static const int DOMAIN_SETTINGS_TIMEOUT_MS = 5000;
_settingsTimer.setInterval(DOMAIN_SETTINGS_TIMEOUT_MS);
_settingsTimer.setInterval(DOMAIN_SETTINGS_TIMEOUT_MS); // 5s, Qt::CoarseTimer acceptable
connect(&_settingsTimer, &QTimer::timeout, this, &DomainHandler::settingsReceiveFail);
// setup the API refresh timer for auto connection information refresh from API when failing to connect
const int API_REFRESH_TIMEOUT_MSEC = 2500;
_apiRefreshTimer.setInterval(API_REFRESH_TIMEOUT_MSEC);
_apiRefreshTimer.setInterval(API_REFRESH_TIMEOUT_MSEC); // 2.5s, Qt::CoarseTimer acceptable
auto addressManager = DependencyManager::get<AddressManager>();
connect(&_apiRefreshTimer, &QTimer::timeout, addressManager.data(), &AddressManager::refreshPreviousLookup);
@ -247,7 +247,7 @@ void DomainHandler::completedHostnameLookup(const QHostInfo& hostInfo) {
}
void DomainHandler::completedIceServerHostnameLookup() {
qDebug() << "ICE server socket is at" << _iceServerSockAddr;
qCDebug(networking) << "ICE server socket is at" << _iceServerSockAddr;
DependencyManager::get<NodeList>()->flagTimeForConnectionStep(LimitedNodeList::ConnectionStep::SetICEServerSocket);
@ -335,7 +335,7 @@ void DomainHandler::processDTLSRequirementPacket(QSharedPointer<ReceivedMessage>
void DomainHandler::processICEResponsePacket(QSharedPointer<ReceivedMessage> message) {
if (_icePeer.hasSockets()) {
qDebug() << "Received an ICE peer packet for domain-server but we already have sockets. Not processing.";
qCDebug(networking) << "Received an ICE peer packet for domain-server but we already have sockets. Not processing.";
// bail on processing this packet if our ice peer already has sockets
return;
}

View file

@ -10,6 +10,7 @@
//
#include "FingerprintUtils.h"
#include "NetworkLogging.h"
#include <QDebug>
@ -42,7 +43,7 @@ QString FingerprintUtils::getMachineFingerprintString() {
IOObjectRelease(ioRegistryRoot);
uuidString = QString::fromCFString(uuidCf);
CFRelease(uuidCf);
qDebug() << "Mac serial number: " << uuidString;
qCDebug(networking) << "Mac serial number: " << uuidString;
#endif //Q_OS_MAC
#ifdef Q_OS_WIN
@ -53,7 +54,7 @@ QString FingerprintUtils::getMachineFingerprintString() {
// users of this lib don't necessarily do so.
hres = CoInitializeEx(0, COINIT_MULTITHREADED);
if (FAILED(hres)) {
qDebug() << "Failed to initialize COM library!";
qCDebug(networking) << "Failed to initialize COM library!";
return uuidString;
}
@ -65,7 +66,7 @@ QString FingerprintUtils::getMachineFingerprintString() {
IID_IWbemLocator, (LPVOID *) &pLoc);
if (FAILED(hres)) {
qDebug() << "Failed to initialize WbemLocator";
qCDebug(networking) << "Failed to initialize WbemLocator";
return uuidString;
}
@ -88,7 +89,7 @@ QString FingerprintUtils::getMachineFingerprintString() {
if (FAILED(hres)) {
pLoc->Release();
qDebug() << "Failed to connect to WMI";
qCDebug(networking) << "Failed to connect to WMI";
return uuidString;
}
@ -107,7 +108,7 @@ QString FingerprintUtils::getMachineFingerprintString() {
if (FAILED(hres)) {
pSvc->Release();
pLoc->Release();
qDebug() << "Failed to set security on proxy blanket";
qCDebug(networking) << "Failed to set security on proxy blanket";
return uuidString;
}
@ -123,7 +124,7 @@ QString FingerprintUtils::getMachineFingerprintString() {
if (FAILED(hres)) {
pSvc->Release();
pLoc->Release();
qDebug() << "query to get Win32_ComputerSystemProduct info";
qCDebug(networking) << "query to get Win32_ComputerSystemProduct info";
return uuidString;
}
@ -161,7 +162,7 @@ QString FingerprintUtils::getMachineFingerprintString() {
pSvc->Release();
pLoc->Release();
qDebug() << "Windows BIOS UUID: " << uuidString;
qCDebug(networking) << "Windows BIOS UUID: " << uuidString;
#endif //Q_OS_WIN
return uuidString;
@ -185,12 +186,12 @@ QUuid FingerprintUtils::getMachineFingerprint() {
// read fallback key (if any)
Settings settings;
uuid = QUuid(settings.value(FALLBACK_FINGERPRINT_KEY).toString());
qDebug() << "read fallback maching fingerprint: " << uuid.toString();
qCDebug(networking) << "read fallback maching fingerprint: " << uuid.toString();
if (uuid == QUuid()) {
// no fallback yet, set one
uuid = QUuid::createUuid();
settings.setValue(FALLBACK_FINGERPRINT_KEY, uuid.toString());
qDebug() << "no fallback machine fingerprint, setting it to: " << uuid.toString();
qCDebug(networking) << "no fallback machine fingerprint, setting it to: " << uuid.toString();
}
}
return uuid;

View file

@ -108,7 +108,7 @@ void HTTPResourceRequest::onRequestFinished() {
case QNetworkReply::UnknownServerError: // Script.include('QUrl("https://httpbin.org/status/504")')
case QNetworkReply::InternalServerError: // Script.include('QUrl("https://httpbin.org/status/500")')
default:
qDebug() << "HTTPResourceRequest error:" << QMetaEnum::fromType<QNetworkReply::NetworkError>().valueToKey(_reply->error());
qCDebug(networking) << "HTTPResourceRequest error:" << QMetaEnum::fromType<QNetworkReply::NetworkError>().valueToKey(_reply->error());
_result = Error;
break;
}

View file

@ -902,7 +902,7 @@ void LimitedNodeList::startSTUNPublicSocketUpdate() {
connect(_initialSTUNTimer.data(), &QTimer::timeout, this, &LimitedNodeList::sendSTUNRequest);
const int STUN_INITIAL_UPDATE_INTERVAL_MSECS = 250;
_initialSTUNTimer->setInterval(STUN_INITIAL_UPDATE_INTERVAL_MSECS);
_initialSTUNTimer->setInterval(STUN_INITIAL_UPDATE_INTERVAL_MSECS); // 250ms, Qt::CoarseTimer acceptable
// if we don't know the STUN IP yet we need to wait until it is known to start STUN requests
if (_stunSockAddr.getAddress().isNull()) {

View file

@ -158,7 +158,7 @@ void NetworkPeer::activateMatchingOrNewSymmetricSocket(const HifiSockAddr& match
}
void NetworkPeer::softReset() {
qDebug() << "Soft reset ";
qCDebug(networking) << "Soft reset ";
// a soft reset should clear the sockets and reset the number of connection attempts
_localSocket.clear();
_publicSocket.clear();

View file

@ -102,7 +102,7 @@ NodeList::NodeList(char newOwnerType, int socketListenPort, int dtlsListenPort)
connect(this, &LimitedNodeList::nodeActivated, this, &NodeList::maybeSendIgnoreSetToNode);
// setup our timer to send keepalive pings (it's started and stopped on domain connect/disconnect)
_keepAlivePingTimer.setInterval(KEEPALIVE_PING_INTERVAL_MS);
_keepAlivePingTimer.setInterval(KEEPALIVE_PING_INTERVAL_MS); // 1s, Qt::CoarseTimer acceptable
connect(&_keepAlivePingTimer, &QTimer::timeout, this, &NodeList::sendKeepAlivePings);
connect(&_domainHandler, SIGNAL(connectedToDomain(QString)), &_keepAlivePingTimer, SLOT(start()));
connect(&_domainHandler, &DomainHandler::disconnectedFromDomain, &_keepAlivePingTimer, &QTimer::stop);
@ -373,9 +373,9 @@ void NodeList::sendDomainServerCheckIn() {
packetStream << hardwareAddress;
// add in machine fingerprint
QUuid machineFingerprint = FingerprintUtils::getMachineFingerprint();
packetStream << machineFingerprint;
// now add the machine fingerprint - a null UUID if logged in, real one if not logged in
auto accountManager = DependencyManager::get<AccountManager>();
packetStream << (accountManager->isLoggedIn() ? QUuid() : FingerprintUtils::getMachineFingerprint());
}
// pack our data to send to the domain-server including
@ -401,7 +401,7 @@ void NodeList::sendDomainServerCheckIn() {
if (_numNoReplyDomainCheckIns >= MAX_SILENT_DOMAIN_SERVER_CHECK_INS) {
// we haven't heard back from DS in MAX_SILENT_DOMAIN_SERVER_CHECK_INS
// so emit our signal that says that
qDebug() << "Limit of silent domain checkins reached";
qCDebug(networking) << "Limit of silent domain checkins reached";
emit limitOfSilentDomainCheckInsReached();
}
@ -629,7 +629,7 @@ void NodeList::processDomainServerAddedNode(QSharedPointer<ReceivedMessage> mess
void NodeList::processDomainServerRemovedNode(QSharedPointer<ReceivedMessage> message) {
// read the UUID from the packet, remove it if it exists
QUuid nodeUUID = QUuid::fromRfc4122(message->readWithoutCopy(NUM_BYTES_RFC4122_UUID));
qDebug() << "Received packet from domain-server to remove node with UUID" << uuidStringWithoutCurlyBraces(nodeUUID);
qCDebug(networking) << "Received packet from domain-server to remove node with UUID" << uuidStringWithoutCurlyBraces(nodeUUID);
killNodeWithUUID(nodeUUID);
}
@ -793,7 +793,7 @@ void NodeList::ignoreNodeBySessionID(const QUuid& nodeID) {
// write the node ID to the packet
ignorePacket->write(nodeID.toRfc4122());
qDebug() << "Sending packet to ignore node" << uuidStringWithoutCurlyBraces(nodeID);
qCDebug(networking) << "Sending packet to ignore node" << uuidStringWithoutCurlyBraces(nodeID);
// send off this ignore packet reliably to the matching node
sendPacket(std::move(ignorePacket), *destinationNode);
@ -855,7 +855,7 @@ void NodeList::kickNodeBySessionID(const QUuid& nodeID) {
// write the node ID to the packet
kickPacket->write(nodeID.toRfc4122());
qDebug() << "Sending packet to kick node" << uuidStringWithoutCurlyBraces(nodeID);
qCDebug(networking) << "Sending packet to kick node" << uuidStringWithoutCurlyBraces(nodeID);
sendPacket(std::move(kickPacket), _domainHandler.getSockAddr());
} else {
@ -880,7 +880,7 @@ void NodeList::muteNodeBySessionID(const QUuid& nodeID) {
// write the node ID to the packet
mutePacket->write(nodeID.toRfc4122());
qDebug() << "Sending packet to mute node" << uuidStringWithoutCurlyBraces(nodeID);
qCDebug(networking) << "Sending packet to mute node" << uuidStringWithoutCurlyBraces(nodeID);
sendPacket(std::move(mutePacket), *audioMixer);
} else {
@ -909,7 +909,7 @@ void NodeList::requestUsernameFromSessionID(const QUuid& nodeID) {
usernameFromIDRequestPacket->write(nodeID.toRfc4122());
}
qDebug() << "Sending packet to get username of node" << uuidStringWithoutCurlyBraces(nodeID);
qCDebug(networking) << "Sending packet to get username of node" << uuidStringWithoutCurlyBraces(nodeID);
sendPacket(std::move(usernameFromIDRequestPacket), _domainHandler.getSockAddr());
} else {
@ -923,8 +923,10 @@ void NodeList::processUsernameFromIDReply(QSharedPointer<ReceivedMessage> messag
QString nodeUUIDString = (QUuid::fromRfc4122(message->readWithoutCopy(NUM_BYTES_RFC4122_UUID))).toString();
// read the username from the packet
QString username = message->readString();
// read the machine fingerprint from the packet
QString machineFingerprintString = (QUuid::fromRfc4122(message->readWithoutCopy(NUM_BYTES_RFC4122_UUID))).toString();
qDebug() << "Got username" << username << "for node" << nodeUUIDString;
qCDebug(networking) << "Got username" << username << "and machine fingerprint" << machineFingerprintString << "for node" << nodeUUIDString;
emit usernameFromIDReply(nodeUUIDString, username);
emit usernameFromIDReply(nodeUUIDString, username, machineFingerprintString);
}

View file

@ -111,7 +111,7 @@ signals:
void receivedDomainServerList();
void ignoredNode(const QUuid& nodeID);
void ignoreRadiusEnabledChanged(bool isIgnored);
void usernameFromIDReply(const QString& nodeID, const QString& username);
void usernameFromIDReply(const QString& nodeID, const QString& username, const QString& machineFingerprint);
private slots:
void stopKeepalivePingTimer();

View file

@ -324,8 +324,6 @@ void PacketReceiver::handleVerifiedMessage(QSharedPointer<ReceivedMessage> recei
listenerIsDead = true;
}
} else {
// qDebug() << "Got verified unsourced packet list: " << QString(nlPacketList->getMessage());
// one final check on the QPointer before we invoke
if (listener.object) {
success = listener.method.invoke(listener.object,

View file

@ -71,6 +71,11 @@ QList<QSharedPointer<Resource>> ResourceCacheSharedItems::getLoadingRequests() {
return result;
}
uint32_t ResourceCacheSharedItems::getLoadingRequestsCount() const {
Lock lock(_mutex);
return _loadingRequests.size();
}
void ResourceCacheSharedItems::removeRequest(QWeakPointer<Resource> resource) {
Lock lock(_mutex);
@ -463,6 +468,10 @@ int ResourceCache::getPendingRequestCount() {
return DependencyManager::get<ResourceCacheSharedItems>()->getPendingRequestsCount();
}
int ResourceCache::getLoadingRequestCount() {
return DependencyManager::get<ResourceCacheSharedItems>()->getLoadingRequestsCount();
}
bool ResourceCache::attemptRequest(QSharedPointer<Resource> resource) {
Q_ASSERT(!resource.isNull());
auto sharedItems = DependencyManager::get<ResourceCacheSharedItems>();

View file

@ -73,6 +73,7 @@ public:
uint32_t getPendingRequestsCount() const;
QList<QSharedPointer<Resource>> getLoadingRequests();
QSharedPointer<Resource> getHighestPendingRequest();
uint32_t getLoadingRequestsCount() const;
private:
ResourceCacheSharedItems() = default;
@ -241,6 +242,8 @@ public:
static int getPendingRequestCount();
static int getLoadingRequestCount();
ResourceCache(QObject* parent = nullptr);
virtual ~ResourceCache();

View file

@ -22,7 +22,7 @@
#include "FileResourceRequest.h"
#include "HTTPResourceRequest.h"
#include "NetworkAccessManager.h"
#include "NetworkLogging.h"
QThread ResourceManager::_thread;
ResourceManager::PrefixMap ResourceManager::_prefixMap;
@ -51,7 +51,7 @@ QString ResourceManager::normalizeURL(const QString& urlString) {
const auto& prefix = entry.first;
const auto& replacement = entry.second;
if (result.startsWith(prefix)) {
qDebug() << "Replacing " << prefix << " with " << replacement;
qCDebug(networking) << "Replacing " << prefix << " with " << replacement;
result.replace(0, prefix.size(), replacement);
}
}
@ -105,7 +105,7 @@ ResourceRequest* ResourceManager::createResourceRequest(QObject* parent, const Q
} else if (scheme == URL_SCHEME_ATP) {
request = new AssetResourceRequest(normalizedURL);
} else {
qDebug() << "Unknown scheme (" << scheme << ") for URL: " << url.url();
qCDebug(networking) << "Unknown scheme (" << scheme << ") for URL: " << url.url();
return nullptr;
}
Q_ASSERT(request);

View file

@ -27,6 +27,7 @@
#include "SandboxUtils.h"
#include "NetworkAccessManager.h"
#include "NetworkLogging.h"
void SandboxUtils::ifLocalSandboxRunningElse(std::function<void()> localSandboxRunningDoThis,
@ -64,10 +65,10 @@ void SandboxUtils::ifLocalSandboxRunningElse(std::function<void()> localSandboxR
void SandboxUtils::runLocalSandbox(QString contentPath, bool autoShutdown, QString runningMarkerName, bool noUpdater) {
QString applicationDirPath = QFileInfo(QCoreApplication::applicationFilePath()).path();
QString serverPath = applicationDirPath + "/server-console/server-console.exe";
qDebug() << "Application dir path is: " << applicationDirPath;
qDebug() << "Server path is: " << serverPath;
qDebug() << "autoShutdown: " << autoShutdown;
qDebug() << "noUpdater: " << noUpdater;
qCDebug(networking) << "Application dir path is: " << applicationDirPath;
qCDebug(networking) << "Server path is: " << serverPath;
qCDebug(networking) << "autoShutdown: " << autoShutdown;
qCDebug(networking) << "noUpdater: " << noUpdater;
bool hasContentPath = !contentPath.isEmpty();
bool passArgs = autoShutdown || hasContentPath || noUpdater;
@ -92,9 +93,9 @@ void SandboxUtils::runLocalSandbox(QString contentPath, bool autoShutdown, QStri
args << "--noUpdater";
}
qDebug() << applicationDirPath;
qDebug() << "Launching sandbox with:" << args;
qDebug() << QProcess::startDetached(serverPath, args);
qCDebug(networking) << applicationDirPath;
qCDebug(networking) << "Launching sandbox with:" << args;
qCDebug(networking) << QProcess::startDetached(serverPath, args);
// Sleep a short amount of time to give the server a chance to start
usleep(2000000); /// do we really need this??

View file

@ -18,6 +18,8 @@
#include "ThreadedAssignment.h"
#include "NetworkLogging.h"
ThreadedAssignment::ThreadedAssignment(ReceivedMessage& message) :
Assignment(message),
_isFinished(false),
@ -25,11 +27,11 @@ ThreadedAssignment::ThreadedAssignment(ReceivedMessage& message) :
_statsTimer(this)
{
static const int STATS_TIMEOUT_MS = 1000;
_statsTimer.setInterval(STATS_TIMEOUT_MS);
_statsTimer.setInterval(STATS_TIMEOUT_MS); // 1s, Qt::CoarseTimer acceptable
connect(&_statsTimer, &QTimer::timeout, this, &ThreadedAssignment::sendStatsPacket);
connect(&_domainServerTimer, &QTimer::timeout, this, &ThreadedAssignment::checkInWithDomainServerOrExit);
_domainServerTimer.setInterval(DOMAIN_SERVER_CHECK_IN_MSECS);
_domainServerTimer.setInterval(DOMAIN_SERVER_CHECK_IN_MSECS); // 1s, Qt::CoarseTimer acceptable
// if the NL tells us we got a DS response, clear our member variable of queued check-ins
auto nodeList = DependencyManager::get<NodeList>();
@ -42,7 +44,7 @@ void ThreadedAssignment::setFinished(bool isFinished) {
if (_isFinished) {
qDebug() << "ThreadedAssignment::setFinished(true) called - finishing up.";
qCDebug(networking) << "ThreadedAssignment::setFinished(true) called - finishing up.";
auto nodeList = DependencyManager::get<NodeList>();
@ -109,7 +111,7 @@ void ThreadedAssignment::checkInWithDomainServerOrExit() {
// verify that the number of queued check-ins is not >= our max
// the number of queued check-ins is cleared anytime we get a response from the domain-server
if (_numQueuedCheckIns >= MAX_SILENT_DOMAIN_SERVER_CHECK_INS) {
qDebug() << "At least" << MAX_SILENT_DOMAIN_SERVER_CHECK_INS << "have been queued without a response from domain-server"
qCDebug(networking) << "At least" << MAX_SILENT_DOMAIN_SERVER_CHECK_INS << "have been queued without a response from domain-server"
<< "Stopping the current assignment";
setFinished(true);
} else {
@ -122,6 +124,6 @@ void ThreadedAssignment::checkInWithDomainServerOrExit() {
}
void ThreadedAssignment::domainSettingsRequestFailed() {
qDebug() << "Failed to retreive settings object from domain-server. Bailing on assignment.";
qCDebug(networking) << "Failed to retreive settings object from domain-server. Bailing on assignment.";
setFinished(true);
}

View file

@ -11,6 +11,8 @@
#include "BasePacket.h"
#include "../NetworkLogging.h"
using namespace udt;
const qint64 BasePacket::PACKET_WRITE_ERROR = -1;
@ -131,7 +133,7 @@ void BasePacket::setPayloadSize(qint64 payloadSize) {
Q_ASSERT(payloadSize <= _payloadCapacity);
_payloadSize = payloadSize;
} else {
qDebug() << "You can not call setPayloadSize for a non-writeable Packet.";
qCDebug(networking) << "You can not call setPayloadSize for a non-writeable Packet.";
Q_ASSERT(false);
}
}

View file

@ -17,6 +17,8 @@
#include "Socket.h"
#include "../NetworkLogging.h"
using namespace udt;
int packetMetaTypeId = qRegisterMetaType<Packet*>("Packet*");
@ -106,7 +108,7 @@ Packet::Packet(std::unique_ptr<char[]> data, qint64 size, const HifiSockAddr& se
}
static QString repeatedMessage = LogHandler::getInstance().addRepeatedMessageRegex("^Unobfuscating packet .*");
qDebug() << qPrintable(debugString);
qCDebug(networking) << qPrintable(debugString);
#endif
obfuscate(NoObfuscation); // Undo obfuscation

View file

@ -44,7 +44,7 @@ const QSet<PacketType> NON_SOURCED_PACKETS = QSet<PacketType>()
PacketVersion versionForPacketType(PacketType packetType) {
switch (packetType) {
case PacketType::DomainList:
return static_cast<PacketVersion>(DomainListVersion::GetUsernameFromUUIDSupport);
return static_cast<PacketVersion>(DomainListVersion::GetMachineFingerprintFromUUIDSupport);
case PacketType::EntityAdd:
case PacketType::EntityEdit:
case PacketType::EntityData:
@ -53,7 +53,7 @@ PacketVersion versionForPacketType(PacketType packetType) {
case PacketType::AvatarData:
case PacketType::BulkAvatarData:
case PacketType::KillAvatar:
return static_cast<PacketVersion>(AvatarMixerPacketVersion::HasKillAvatarReason);
return static_cast<PacketVersion>(AvatarMixerPacketVersion::SessionDisplayName);
case PacketType::ICEServerHeartbeat:
return 18; // ICE Server Heartbeat signing
case PacketType::AssetGetInfo:

View file

@ -103,7 +103,8 @@ public:
RadiusIgnoreRequest,
UsernameFromIDRequest,
UsernameFromIDReply,
LAST_PACKET_TYPE = UsernameFromIDReply
ViewFrustum,
LAST_PACKET_TYPE = ViewFrustum
};
};
@ -205,7 +206,8 @@ enum class AvatarMixerPacketVersion : PacketVersion {
AbsoluteSixByteRotations,
SensorToWorldMat,
HandControllerJoints,
HasKillAvatarReason
HasKillAvatarReason,
SessionDisplayName
};
enum class DomainConnectRequestVersion : PacketVersion {
@ -230,7 +232,8 @@ enum class DomainServerAddedNodeVersion : PacketVersion {
enum class DomainListVersion : PacketVersion {
PrePermissionsGrid = 18,
PermissionsGrid,
GetUsernameFromUUIDSupport
GetUsernameFromUUIDSupport,
GetMachineFingerprintFromUUIDSupport
};
enum class AudioVersion : PacketVersion {

View file

@ -11,6 +11,8 @@
#include "PacketList.h"
#include "../NetworkLogging.h"
#include <QDebug>
using namespace udt;
@ -102,7 +104,7 @@ std::unique_ptr<Packet> PacketList::createPacketWithExtendedHeader() {
if (!_extendedHeader.isEmpty()) {
// add the extended header to the front of the packet
if (packet->write(_extendedHeader) == -1) {
qDebug() << "Could not write extendedHeader in PacketList::createPacketWithExtendedHeader"
qCDebug(networking) << "Could not write extendedHeader in PacketList::createPacketWithExtendedHeader"
<< "- make sure that _extendedHeader is not larger than the payload capacity.";
}
}
@ -195,7 +197,7 @@ qint64 PacketList::writeData(const char* data, qint64 maxSize) {
if (segmentSize + sizeRemaining > newPacket->getPayloadCapacity()) {
// this is an unsupported case - the segment is bigger than the size of an individual packet
// but the PacketList is not going to be sent ordered
qDebug() << "Error in PacketList::writeData - attempted to write a segment to an unordered packet that is"
qCDebug(networking) << "Error in PacketList::writeData - attempted to write a segment to an unordered packet that is"
<< "larger than the payload size.";
Q_ASSERT(false);
@ -220,7 +222,7 @@ qint64 PacketList::writeData(const char* data, qint64 maxSize) {
if (sizeRemaining > newPacket->getPayloadCapacity()) {
// this is an unsupported case - attempting to write a block of data larger
// than the capacity of a new packet in an unordered PacketList
qDebug() << "Error in PacketList::writeData - attempted to write data to an unordered packet that is"
qCDebug(networking) << "Error in PacketList::writeData - attempted to write data to an unordered packet that is"
<< "larger than the payload size.";
Q_ASSERT(false);

View file

@ -33,6 +33,8 @@
#include <Trace.h>
#include <Profile.h>
#include "../NetworkLogging.h"
using namespace udt;
using namespace std::chrono;
@ -299,12 +301,12 @@ void SendQueue::run() {
// we've already been asked to stop before we even got a chance to start
// don't start now
#ifdef UDT_CONNECTION_DEBUG
qDebug() << "SendQueue asked to run after being told to stop. Will not run.";
qCDebug(networking) << "SendQueue asked to run after being told to stop. Will not run.";
#endif
return;
} else if (_state == State::Running) {
#ifdef UDT_CONNECTION_DEBUG
qDebug() << "SendQueue asked to run but is already running (according to state). Will not re-run.";
qCDebug(networking) << "SendQueue asked to run but is already running (according to state). Will not re-run.";
#endif
return;
}

View file

@ -282,7 +282,7 @@ void Socket::clearConnections() {
if (_connectionsHash.size() > 0) {
// clear all of the current connections in the socket
qDebug() << "Clearing all remaining connections in Socket.";
qCDebug(networking) << "Clearing all remaining connections in Socket.";
_connectionsHash.clear();
}
}

View file

@ -0,0 +1,16 @@
//
// Created by Brad Hefta-Gaub on 2016-12-19
// Copyright 2013-2016 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_octree_Logging_h
#define hifi_octree_Logging_h
#include <QLoggingCategory>
Q_DECLARE_LOGGING_CATEGORY(octree)
#endif // hifi_octree_Logging_h

View file

@ -23,6 +23,7 @@
#include <PerfStat.h>
#include "AACube.h"
#include "Logging.h"
#include "OctalCode.h"
#include "Octree.h"
#include "OctreeConstants.h"
@ -444,18 +445,12 @@ void OctreeElement::printDebugDetails(const char* label) const {
}
}
QDebug elementDebug = qDebug().nospace();
QString resultString;
resultString.sprintf("%s - Voxel at corner=(%f,%f,%f) size=%f\n isLeaf=%s isDirty=%s shouldRender=%s\n children=", label,
(double)_cube.getCorner().x, (double)_cube.getCorner().y, (double)_cube.getCorner().z,
(double)_cube.getScale(),
debug::valueOf(isLeaf()), debug::valueOf(isDirty()), debug::valueOf(getShouldRender()));
elementDebug << resultString;
outputBits(childBits, &elementDebug);
qDebug("octalCode=");
printOctalCode(getOctalCode());
qCDebug(octree).nospace() << resultString;
}
float OctreeElement::getEnclosingRadius() const {

View file

@ -234,7 +234,7 @@ void EntityMotionState::setWorldTransform(const btTransform& worldTrans) {
static QString repeatedMessage =
LogHandler::getInstance().addRepeatedMessageRegex("EntityMotionState::setWorldTransform "
"setPosition failed.*");
qDebug() << "EntityMotionState::setWorldTransform setPosition failed" << _entity->getID();
qCDebug(physics) << "EntityMotionState::setWorldTransform setPosition failed" << _entity->getID();
}
bool orientationSuccess;
_entity->setOrientation(bulletToGLM(worldTrans.getRotation()), orientationSuccess, false);
@ -242,7 +242,7 @@ void EntityMotionState::setWorldTransform(const btTransform& worldTrans) {
static QString repeatedMessage =
LogHandler::getInstance().addRepeatedMessageRegex("EntityMotionState::setWorldTransform "
"setOrientation failed.*");
qDebug() << "EntityMotionState::setWorldTransform setOrientation failed" << _entity->getID();
qCDebug(physics) << "EntityMotionState::setWorldTransform setOrientation failed" << _entity->getID();
}
_entity->setVelocity(getBodyLinearVelocity());
_entity->setAngularVelocity(getBodyAngularVelocity());

View file

@ -13,6 +13,9 @@
#include "ObjectAction.h"
#include "PhysicsLogging.h"
ObjectAction::ObjectAction(EntityActionType type, const QUuid& id, EntityItemPointer ownerEntity) :
btActionInterface(),
EntityActionInterface(type, id),
@ -32,7 +35,7 @@ void ObjectAction::updateAction(btCollisionWorld* collisionWorld, btScalar delta
});
if (!ownerEntity) {
qDebug() << "warning -- action with no entity removing self from btCollisionWorld.";
qCDebug(physics) << "warning -- action with no entity removing self from btCollisionWorld.";
btDynamicsWorld* dynamicsWorld = static_cast<btDynamicsWorld*>(collisionWorld);
if (dynamicsWorld) {
dynamicsWorld->removeAction(this);
@ -242,7 +245,7 @@ void ObjectAction::activateBody(bool forceActivation) {
if (rigidBody) {
rigidBody->activate(forceActivation);
} else {
qDebug() << "ObjectAction::activateBody -- no rigid body" << (void*)rigidBody;
qCDebug(physics) << "ObjectAction::activateBody -- no rigid body" << (void*)rigidBody;
}
}

View file

@ -13,6 +13,9 @@
#include "ObjectActionOffset.h"
#include "PhysicsLogging.h"
const uint16_t ObjectActionOffset::offsetVersion = 1;
ObjectActionOffset::ObjectActionOffset(const QUuid& id, EntityItemPointer ownerEntity) :
@ -22,13 +25,13 @@ ObjectActionOffset::ObjectActionOffset(const QUuid& id, EntityItemPointer ownerE
_linearTimeScale(FLT_MAX),
_positionalTargetSet(false) {
#if WANT_DEBUG
qDebug() << "ObjectActionOffset::ObjectActionOffset";
qCDebug(physics) << "ObjectActionOffset::ObjectActionOffset";
#endif
}
ObjectActionOffset::~ObjectActionOffset() {
#if WANT_DEBUG
qDebug() << "ObjectActionOffset::~ObjectActionOffset";
qCDebug(physics) << "ObjectActionOffset::~ObjectActionOffset";
#endif
}
@ -47,7 +50,7 @@ void ObjectActionOffset::updateActionWorker(btScalar deltaTimeStep) {
ObjectMotionState* motionState = static_cast<ObjectMotionState*>(physicsInfo);
btRigidBody* rigidBody = motionState->getRigidBody();
if (!rigidBody) {
qDebug() << "ObjectActionOffset::updateActionWorker no rigidBody";
qCDebug(physics) << "ObjectActionOffset::updateActionWorker no rigidBody";
return;
}

View file

@ -13,6 +13,8 @@
#include "ObjectActionSpring.h"
#include "PhysicsLogging.h"
const float SPRING_MAX_SPEED = 10.0f;
const uint16_t ObjectActionSpring::springVersion = 1;
@ -29,13 +31,13 @@ ObjectActionSpring::ObjectActionSpring(const QUuid& id, EntityItemPointer ownerE
_angularTimeScale(FLT_MAX),
_rotationalTargetSet(true) {
#if WANT_DEBUG
qDebug() << "ObjectActionSpring::ObjectActionSpring";
qCDebug(physics) << "ObjectActionSpring::ObjectActionSpring";
#endif
}
ObjectActionSpring::~ObjectActionSpring() {
#if WANT_DEBUG
qDebug() << "ObjectActionSpring::~ObjectActionSpring";
qCDebug(physics) << "ObjectActionSpring::~ObjectActionSpring";
#endif
}
@ -126,7 +128,7 @@ void ObjectActionSpring::updateActionWorker(btScalar deltaTimeStep) {
ObjectMotionState* motionState = static_cast<ObjectMotionState*>(physicsInfo);
btRigidBody* rigidBody = motionState->getRigidBody();
if (!rigidBody) {
qDebug() << "ObjectActionSpring::updateActionWorker no rigidBody";
qCDebug(physics) << "ObjectActionSpring::updateActionWorker no rigidBody";
return;
}

View file

@ -13,6 +13,7 @@
#include "QVariantGLM.h"
#include "ObjectActionTravelOriented.h"
#include "PhysicsLogging.h"
const uint16_t ObjectActionTravelOriented::actionVersion = 1;
@ -20,13 +21,13 @@ const uint16_t ObjectActionTravelOriented::actionVersion = 1;
ObjectActionTravelOriented::ObjectActionTravelOriented(const QUuid& id, EntityItemPointer ownerEntity) :
ObjectAction(ACTION_TYPE_TRAVEL_ORIENTED, id, ownerEntity) {
#if WANT_DEBUG
qDebug() << "ObjectActionTravelOriented::ObjectActionTravelOriented";
qCDebug(physics) << "ObjectActionTravelOriented::ObjectActionTravelOriented";
#endif
}
ObjectActionTravelOriented::~ObjectActionTravelOriented() {
#if WANT_DEBUG
qDebug() << "ObjectActionTravelOriented::~ObjectActionTravelOriented";
qCDebug(physics) << "ObjectActionTravelOriented::~ObjectActionTravelOriented";
#endif
}
@ -43,7 +44,7 @@ void ObjectActionTravelOriented::updateActionWorker(btScalar deltaTimeStep) {
ObjectMotionState* motionState = static_cast<ObjectMotionState*>(physicsInfo);
btRigidBody* rigidBody = motionState->getRigidBody();
if (!rigidBody) {
qDebug() << "ObjectActionTravelOriented::updateActionWorker no rigidBody";
qCDebug(physics) << "ObjectActionTravelOriented::updateActionWorker no rigidBody";
return;
}
const float MAX_TIMESCALE = 600.0f; // 10 min is a long time

View file

@ -16,6 +16,7 @@
#include <QtCore/QSize>
#include <QtCore/QPoint>
#include <QtCore/QElapsedTimer>
#include <QtCore/QJsonObject>
#include <GLMHelpers.h>
#include <RegisteredMetaTypes.h>
@ -194,6 +195,9 @@ public:
virtual float newFramePresentRate() const { return -1.0f; }
// Rate at which rendered frames are being skipped
virtual float droppedFrameRate() const { return -1.0f; }
// Hardware specific stats
virtual QJsonObject getHardwareStats() const { return QJsonObject(); }
uint32_t presentCount() const { return _presentedFrameIndex; }
// Time since last call to incrementPresentCount (only valid if DEBUG_PAINT_DELAY is defined)

Some files were not shown because too many files have changed in this diff Show more