Merge branch 'master' of https://github.com/highfidelity/hifi into addViewFrustumToAvatarMixer

Conflicts:
	assignment-client/src/avatars/AvatarMixer.h
	assignment-client/src/avatars/AvatarMixerClientData.h
	libraries/avatars/src/AvatarData.cpp
	libraries/networking/src/udt/PacketHeaders.h
This commit is contained in:
Brad Hefta-Gaub 2016-12-20 16:25:12 -08:00
commit d09afa9454
255 changed files with 6276 additions and 2096 deletions
assignment-client/src
domain-server
interface
libraries

View file

@ -37,6 +37,8 @@
#include "AssignmentClient.h"
#include "AssignmentClientLogging.h"
#include "avatars/ScriptableAvatar.h"
#include <Trace.h>
#include <StatTracker.h>
const QString ASSIGNMENT_CLIENT_TARGET_NAME = "assignment-client";
const long long ASSIGNMENT_REQUEST_INTERVAL_MSECS = 1 * 1000;
@ -48,6 +50,8 @@ AssignmentClient::AssignmentClient(Assignment::Type requestAssignmentType, QStri
{
LogUtils::init();
DependencyManager::set<tracing::Tracer>();
DependencyManager::set<StatTracker>();
DependencyManager::set<AccountManager>();
auto scriptableAvatar = DependencyManager::set<ScriptableAvatar>();

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";
@ -68,6 +68,20 @@ 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.
@ -231,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(
@ -299,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();
@ -446,6 +471,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));
@ -510,6 +545,7 @@ void AvatarMixer::handleAvatarIdentityPacket(QSharedPointer<ReceivedMessage> mes
if (avatar.processAvatarIdentity(identity)) {
QMutexLocker nodeDataLocker(&nodeData->getMutex());
nodeData->flagIdentityChange();
nodeData->setReceivedIdentity();
}
}
}
@ -608,7 +644,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

@ -19,6 +19,7 @@
#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 {
@ -48,6 +49,7 @@ private slots:
private:
void broadcastAvatarData();
void parseDomainServerSettings(const QJsonObject& domainSettings);
void sendIdentityPacket(AvatarMixerClientData* nodeData, const SharedNodePointer& destinationNode);
QThread _broadcastThread;
@ -69,8 +71,7 @@ private:
RateCounter<> _broadcastRate;
p_high_resolution_clock::time_point _lastDebugMessage;
QHash<QString, QPair<int, int>> _sessionDisplayNames;
};
#endif // hifi_AvatarMixer_h

View file

@ -35,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) {}
virtual ~AvatarMixerClientData() {}
using HRCTime = p_high_resolution_clock::time_point;
int parseData(ReceivedMessage& message) override;
@ -51,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; }
@ -96,6 +100,8 @@ public:
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() };
@ -105,6 +111,7 @@ private:
std::unordered_set<QUuid> _hasReceivedFirstPacketsFrom;
HRCTime _identityChangeTimestamp;
bool _gotIdentity { false };
float _fullRateDistance = FLT_MAX;
float _maxAvatarDistance = FLT_MAX;
@ -123,6 +130,7 @@ private:
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

@ -845,6 +845,78 @@
}
],
"columns": [
{
"name": "permissions_id",
"label": ""
},
{
"name": "id_can_connect",
"label": "Connect",
"type": "checkbox",
"editable": true,
"default": false
},
{
"name": "id_can_adjust_locks",
"label": "Lock / Unlock",
"type": "checkbox",
"editable": true,
"default": false
},
{
"name": "id_can_rez",
"label": "Rez",
"type": "checkbox",
"editable": true,
"default": false
},
{
"name": "id_can_rez_tmp",
"label": "Rez Temporary",
"type": "checkbox",
"editable": true,
"default": false
},
{
"name": "id_can_write_to_asset_server",
"label": "Write Assets",
"type": "checkbox",
"editable": true,
"default": false
},
{
"name": "id_can_connect_past_max_capacity",
"label": "Ignore Max Capacity",
"type": "checkbox",
"editable": true,
"default": false
},
{
"name": "id_can_kick",
"label": "Kick Users",
"type": "checkbox",
"editable": true,
"default": false
}
]
},
{
"name": "machine_fingerprint_permissions",
"type": "table",
"caption": "Permissions for Users with Machine Fingerprints",
"can_add_new_rows": true,
"groups": [
{
"label": "Machine Fingerprint",
"span": 1
},
{
"label": "Permissions <a data-toggle='tooltip' data-html='true' title='<p><strong>Domain-Wide Machine Fingerprint Permissions</strong></p><ul><li><strong>Connect</strong><br />Sets whether users with specific Machine Fingerprints can connect to the domain.</li><li><strong>Lock / Unlock</strong><br />Sets whether users from specific Machine Fingerprints can change the &ldquo;locked&rdquo; property of an entity (either from on to off or off to on).</li><li><strong>Rez</strong><br />Sets whether users with specific Machine Fingerprints can create new entities.</li><li><strong>Rez Temporary</strong><br />Sets whether users with specific Machine Fingerprints can create new entities with a finite lifetime.</li><li><strong>Write Assets</strong><br />Sets whether users with specific Machine Fingerprints can make changes to the domain&rsquo;s asset-server assets.</li><li><strong>Ignore Max Capacity</strong><br />Sets whether users with specific Machine Fingerprints can connect even if the domain has reached or exceeded its maximum allowed agents.</li></ul><p>Note that permissions assigned to a specific Machine Fingerprint will supersede any parameter-level permissions that might otherwise apply to that user (from groups or standard permissions above). Machine Fingerprint address permissions are overriden if the user has their own row in the users section.</p>'>?</a>",
"span": 7
}
],
"columns": [
{
"name": "permissions_id",

View file

@ -120,19 +120,21 @@ void DomainGatekeeper::processConnectRequestPacket(QSharedPointer<ReceivedMessag
nodeData->setPlaceName(nodeConnection.placeName);
qDebug() << "Allowed connection from node" << uuidStringWithoutCurlyBraces(node->getUUID())
<< "on" << message->getSenderSockAddr() << "with MAC" << nodeConnection.hardwareAddress;
<< "on" << message->getSenderSockAddr() << "with MAC" << nodeConnection.hardwareAddress
<< "and machine fingerprint" << nodeConnection.machineFingerprint;
// signal that we just connected a node so the DomainServer can get it a list
// and broadcast its presence right away
emit connectedNode(node);
} else {
qDebug() << "Refusing connection from node at" << message->getSenderSockAddr()
<< "with hardware address" << nodeConnection.hardwareAddress;
<< "with hardware address" << nodeConnection.hardwareAddress
<< "and machine fingerprint" << nodeConnection.machineFingerprint;
}
}
NodePermissions DomainGatekeeper::setPermissionsForUser(bool isLocalUser, QString verifiedUsername,
const QHostAddress& senderAddress, const QString& hardwareAddress) {
NodePermissions DomainGatekeeper::setPermissionsForUser(bool isLocalUser, QString verifiedUsername, const QHostAddress& senderAddress,
const QString& hardwareAddress, const QUuid& machineFingerprint) {
NodePermissions userPerms;
userPerms.setAll(false);
@ -155,6 +157,11 @@ NodePermissions DomainGatekeeper::setPermissionsForUser(bool isLocalUser, QStrin
#ifdef WANT_DEBUG
qDebug() << "| user-permissions: specific MAC matches, so:" << userPerms;
#endif
} else if (_server->_settingsManager.hasPermissionsForMachineFingerprint(machineFingerprint)) {
userPerms = _server->_settingsManager.getPermissionsForMachineFingerprint(machineFingerprint);
#ifdef WANT_DEBUG
qDebug(() << "| user-permissions: specific Machine Fingerprint matches, so: " << userPerms;
#endif
} else if (_server->_settingsManager.hasPermissionsForIP(senderAddress)) {
// this user comes from an IP we have in our permissions table, apply those permissions
@ -274,13 +281,15 @@ void DomainGatekeeper::updateNodePermissions() {
HifiSockAddr connectingAddr = node->getActiveSocket() ? *node->getActiveSocket() : node->getPublicSocket();
QString hardwareAddress;
QUuid machineFingerprint;
DomainServerNodeData* nodeData = reinterpret_cast<DomainServerNodeData*>(node->getLinkedData());
if (nodeData) {
hardwareAddress = nodeData->getHardwareAddress();
machineFingerprint = nodeData->getMachineFingerprint();
}
userPerms = setPermissionsForUser(isLocalUser, verifiedUsername, connectingAddr.getAddress(), hardwareAddress);
userPerms = setPermissionsForUser(isLocalUser, verifiedUsername, connectingAddr.getAddress(), hardwareAddress, machineFingerprint);
}
node->setPermissions(userPerms);
@ -334,6 +343,8 @@ SharedNodePointer DomainGatekeeper::processAssignmentConnectRequest(const NodeCo
nodeData->setWalletUUID(it->second.getWalletUUID());
nodeData->setNodeVersion(it->second.getNodeVersion());
nodeData->setHardwareAddress(nodeConnection.hardwareAddress);
nodeData->setMachineFingerprint(nodeConnection.machineFingerprint);
nodeData->setWasAssigned(true);
// cleanup the PendingAssignedNodeData for this assignment now that it's connecting
@ -396,7 +407,7 @@ SharedNodePointer DomainGatekeeper::processAgentConnectRequest(const NodeConnect
}
userPerms = setPermissionsForUser(isLocalUser, verifiedUsername, nodeConnection.senderSockAddr.getAddress(),
nodeConnection.hardwareAddress);
nodeConnection.hardwareAddress, nodeConnection.machineFingerprint);
if (!userPerms.can(NodePermissions::Permission::canConnectToDomain)) {
sendConnectionDeniedPacket("You lack the required permissions to connect to this domain.",
@ -455,6 +466,9 @@ SharedNodePointer DomainGatekeeper::processAgentConnectRequest(const NodeConnect
// set the hardware address passed in the connect request
nodeData->setHardwareAddress(nodeConnection.hardwareAddress);
// set the machine fingerprint passed in the connect request
nodeData->setMachineFingerprint(nodeConnection.machineFingerprint);
// also add an interpolation to DomainServerNodeData so that servers can get username in stats
nodeData->addOverrideForKey(USERNAME_UUID_REPLACEMENT_STATS_KEY,
uuidStringWithoutCurlyBraces(newNode->getUUID()), username);

View file

@ -107,8 +107,8 @@ private:
QSet<QString> _domainOwnerFriends; // keep track of friends of the domain owner
QSet<QString> _inFlightGroupMembershipsRequests; // keep track of which we've already asked for
NodePermissions setPermissionsForUser(bool isLocalUser, QString verifiedUsername,
const QHostAddress& senderAddress, const QString& hardwareAddress);
NodePermissions setPermissionsForUser(bool isLocalUser, QString verifiedUsername, const QHostAddress& senderAddress,
const QString& hardwareAddress, const QUuid& machineFingerprint);
void getGroupMemberships(const QString& username);
// void getIsGroupMember(const QString& username, const QUuid groupID);

View file

@ -43,6 +43,8 @@
#include "DomainServerNodeData.h"
#include "NodeConnectionData.h"
#include <Trace.h>
#include <StatTracker.h>
int const DomainServer::EXIT_CODE_REBOOT = 234923;
@ -73,6 +75,9 @@ DomainServer::DomainServer(int argc, char* argv[]) :
{
parseCommandLine();
DependencyManager::set<tracing::Tracer>();
DependencyManager::set<StatTracker>();
LogUtils::init();
Setting::init();
@ -527,6 +532,7 @@ void DomainServer::setupNodeListAndAssignments() {
// NodeList won't be available to the settings manager when it is created, so call registerListener here
packetReceiver.registerListener(PacketType::DomainSettingsRequest, &_settingsManager, "processSettingsRequestPacket");
packetReceiver.registerListener(PacketType::NodeKickRequest, &_settingsManager, "processNodeKickRequestPacket");
packetReceiver.registerListener(PacketType::UsernameFromIDRequest, &_settingsManager, "processUsernameFromIDRequestPacket");
// register the gatekeeper for the packets it needs to receive
packetReceiver.registerListener(PacketType::DomainConnectRequest, &_gatekeeper, "processConnectRequestPacket");

View file

@ -56,7 +56,10 @@ public:
void setHardwareAddress(const QString& hardwareAddress) { _hardwareAddress = hardwareAddress; }
const QString& getHardwareAddress() { return _hardwareAddress; }
void setMachineFingerprint(const QUuid& machineFingerprint) { _machineFingerprint = machineFingerprint; }
const QUuid& getMachineFingerprint() { return _machineFingerprint; }
void addOverrideForKey(const QString& key, const QString& value, const QString& overrideValue);
void removeOverrideForKey(const QString& key, const QString& value);
@ -85,6 +88,7 @@ private:
NodeSet _nodeInterestSet;
QString _nodeVersion;
QString _hardwareAddress;
QUuid _machineFingerprint;
QString _placeName;

View file

@ -444,6 +444,9 @@ void DomainServerSettingsManager::packPermissions() {
// save settings for MAC addresses
packPermissionsForMap("permissions", _macPermissions, MAC_PERMISSIONS_KEYPATH);
// save settings for Machine Fingerprint
packPermissionsForMap("permissions", _machineFingerprintPermissions, MACHINE_FINGERPRINT_PERMISSIONS_KEYPATH);
// save settings for groups
packPermissionsForMap("permissions", _groupPermissions, GROUP_PERMISSIONS_KEYPATH);
@ -522,6 +525,18 @@ void DomainServerSettingsManager::unpackPermissions() {
}
});
needPack |= unpackPermissionsForKeypath(MACHINE_FINGERPRINT_PERMISSIONS_KEYPATH, &_machineFingerprintPermissions,
[&](NodePermissionsPointer perms){
// make sure that this permission row has valid machine fingerprint
if (QUuid(perms->getKey().first) == QUuid()) {
_machineFingerprintPermissions.remove(perms->getKey());
// we removed a row, so we'll need a re-pack
needPack = true;
}
});
needPack |= unpackPermissionsForKeypath(GROUP_PERMISSIONS_KEYPATH, &_groupPermissions,
[&](NodePermissionsPointer perms){
@ -575,7 +590,9 @@ void DomainServerSettingsManager::unpackPermissions() {
QList<QHash<NodePermissionsKey, NodePermissionsPointer>> permissionsSets;
permissionsSets << _standardAgentPermissions.get() << _agentPermissions.get()
<< _groupPermissions.get() << _groupForbiddens.get()
<< _ipPermissions.get() << _macPermissions.get();
<< _ipPermissions.get() << _macPermissions.get()
<< _machineFingerprintPermissions.get();
foreach (auto permissionSet, permissionsSets) {
QHashIterator<NodePermissionsKey, NodePermissionsPointer> i(permissionSet);
while (i.hasNext()) {
@ -707,9 +724,10 @@ void DomainServerSettingsManager::processNodeKickRequestPacket(QSharedPointer<Re
ipPermissions->clear(NodePermissions::Permission::canConnectToDomain);
}
// potentially remove connect permissions for the MAC address
// potentially remove connect permissions for the MAC address and machine fingerprint
DomainServerNodeData* nodeData = reinterpret_cast<DomainServerNodeData*>(matchingNode->getLinkedData());
if (nodeData) {
// mac address first
NodePermissionsKey macAddressKey(nodeData->getHardwareAddress(), 0);
bool hadMACPermissions = hasPermissionsForMAC(nodeData->getHardwareAddress());
@ -721,6 +739,18 @@ void DomainServerSettingsManager::processNodeKickRequestPacket(QSharedPointer<Re
macPermissions->clear(NodePermissions::Permission::canConnectToDomain);
}
// now for machine fingerprint
NodePermissionsKey machineFingerprintKey(nodeData->getMachineFingerprint().toString(), 0);
bool hadFingerprintPermissions = hasPermissionsForMachineFingerprint(nodeData->getMachineFingerprint());
auto fingerprintPermissions = _machineFingerprintPermissions[machineFingerprintKey];
if (!hadFingerprintPermissions || fingerprintPermissions->can(NodePermissions::Permission::canConnectToDomain)) {
newPermissions = true;
fingerprintPermissions->clear(NodePermissions::Permission::canConnectToDomain);
}
}
}
@ -748,6 +778,50 @@ void DomainServerSettingsManager::processNodeKickRequestPacket(QSharedPointer<Re
}
}
// This function processes the "Get Username from ID" request.
void DomainServerSettingsManager::processUsernameFromIDRequestPacket(QSharedPointer<ReceivedMessage> message, SharedNodePointer sendingNode) {
// Before we do any processing on this packet, make sure it comes from a node that is allowed to kick (is an admin)
if (sendingNode->getCanKick()) {
// From the packet, pull the UUID we're identifying
QUuid nodeUUID = QUuid::fromRfc4122(message->readWithoutCopy(NUM_BYTES_RFC4122_UUID));
if (!nodeUUID.isNull()) {
// First, make sure we actually have a node with this UUID
auto limitedNodeList = DependencyManager::get<LimitedNodeList>();
auto matchingNode = limitedNodeList->nodeWithUUID(nodeUUID);
// If we do have a matching node...
if (matchingNode) {
// It's time to figure out the username
QString verifiedUsername = matchingNode->getPermissions().getVerifiedUserName();
// Setup the packet
auto usernameFromIDReplyPacket = NLPacket::create(PacketType::UsernameFromIDReply);
usernameFromIDReplyPacket->write(nodeUUID.toRfc4122());
usernameFromIDReplyPacket->writeString(verifiedUsername);
// 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);
} else {
qWarning() << "Node username request received for unknown node. Refusing to process.";
}
} else {
qWarning() << "Node username request received for invalid node ID. Refusing to process.";
}
} else {
qWarning() << "Refusing to process a username request packet from node" << uuidStringWithoutCurlyBraces(sendingNode->getUUID())
<< "that does not have kick permissions.";
}
}
QStringList DomainServerSettingsManager::getAllNames() const {
QStringList result;
foreach (auto key, _agentPermissions.keys()) {
@ -795,6 +869,16 @@ NodePermissions DomainServerSettingsManager::getPermissionsForMAC(const QString&
return nullPermissions;
}
NodePermissions DomainServerSettingsManager::getPermissionsForMachineFingerprint(const QUuid& machineFingerprint) const {
NodePermissionsKey fingerprintKey = NodePermissionsKey(machineFingerprint.toString(), 0);
if (_machineFingerprintPermissions.contains(fingerprintKey)) {
return *(_machineFingerprintPermissions[fingerprintKey].get());
}
NodePermissions nullPermissions;
nullPermissions.setAll(false);
return nullPermissions;
}
NodePermissions DomainServerSettingsManager::getPermissionsForGroup(const QString& groupName, QUuid rankID) const {
NodePermissionsKey groupRankKey = NodePermissionsKey(groupName, rankID);
if (_groupPermissions.contains(groupRankKey)) {

View file

@ -32,6 +32,7 @@ const QString AGENT_STANDARD_PERMISSIONS_KEYPATH = "security.standard_permission
const QString AGENT_PERMISSIONS_KEYPATH = "security.permissions";
const QString IP_PERMISSIONS_KEYPATH = "security.ip_permissions";
const QString MAC_PERMISSIONS_KEYPATH = "security.mac_permissions";
const QString MACHINE_FINGERPRINT_PERMISSIONS_KEYPATH = "security.machine_fingerprint_permissions";
const QString GROUP_PERMISSIONS_KEYPATH = "security.group_permissions";
const QString GROUP_FORBIDDENS_KEYPATH = "security.group_forbiddens";
@ -70,6 +71,10 @@ public:
bool hasPermissionsForMAC(const QString& macAddress) const { return _macPermissions.contains(macAddress, 0); }
NodePermissions getPermissionsForMAC(const QString& macAddress) const;
// these give access to permissions for specific machine fingerprints from the domain-server settings page
bool hasPermissionsForMachineFingerprint(const QUuid& machineFingerprint) { return _machineFingerprintPermissions.contains(machineFingerprint.toString(), 0); }
NodePermissions getPermissionsForMachineFingerprint(const QUuid& machineFingerprint) const;
// these give access to permissions for specific groups from the domain-server settings page
bool havePermissionsForGroup(const QString& groupName, QUuid rankID) const {
return _groupPermissions.contains(groupName, rankID);
@ -113,6 +118,7 @@ public slots:
private slots:
void processSettingsRequestPacket(QSharedPointer<ReceivedMessage> message);
void processNodeKickRequestPacket(QSharedPointer<ReceivedMessage> message, SharedNodePointer sendingNode);
void processUsernameFromIDRequestPacket(QSharedPointer<ReceivedMessage> message, SharedNodePointer sendingNode);
private:
QStringList _argumentList;
@ -151,6 +157,7 @@ private:
NodePermissionsMap _ipPermissions; // permissions granted by node IP address
NodePermissionsMap _macPermissions; // permissions granted by node MAC address
NodePermissionsMap _machineFingerprintPermissions; // permissions granted by Machine Fingerprint
NodePermissionsMap _groupPermissions; // permissions granted by membership to specific groups
NodePermissionsMap _groupForbiddens; // permissions denied due to membership in a specific group

View file

@ -32,6 +32,9 @@ NodeConnectionData NodeConnectionData::fromDataStream(QDataStream& dataStream, c
// read the hardware address sent by the client
dataStream >> newHeader.hardwareAddress;
// now the machine fingerprint
dataStream >> newHeader.machineFingerprint;
}
dataStream >> newHeader.nodeType

View file

@ -29,6 +29,7 @@ public:
QList<NodeType_t> interestList;
QString placeName;
QString hardwareAddress;
QUuid machineFingerprint;
QByteArray protocolVersion;
};

View file

@ -17,7 +17,10 @@
var KEYBOARD_HEIGHT = 200;
function shouldRaiseKeyboard() {
if (document.activeElement.nodeName === "INPUT" || document.activeElement.nodeName === "TEXTAREA") {
var nodeName = document.activeElement.nodeName;
var nodeType = document.activeElement.type;
if (nodeName === "INPUT" && (nodeType === "text" || nodeType === "number" || nodeType === "password")
|| document.activeElement.nodeName === "TEXTAREA") {
return true;
} else {
// check for contenteditable attribute

View file

@ -23,6 +23,8 @@ ScrollingWindow {
property alias eventBridge: eventBridgeWrapper.eventBridge
signal loadingChanged(int status)
x: 100
y: 100
@ -44,6 +46,10 @@ ScrollingWindow {
hidePermissionsBar();
}
function setAutoAdd(auto) {
desktop.setAutoAdd(auto);
}
Item {
id:item
width: pane.contentWidth
@ -197,7 +203,7 @@ ScrollingWindow {
WebView {
id: webview
url: "https://highfidelity.com"
url: "https://highfidelity.com/"
property alias eventBridgeWrapper: eventBridgeWrapper
@ -243,6 +249,7 @@ ScrollingWindow {
if (loadRequest.status === WebEngineView.LoadSucceededStatus) {
addressBar.text = loadRequest.url
}
root.loadingChanged(loadRequest.status);
}
onIconChanged: {
@ -254,7 +261,7 @@ ScrollingWindow {
}
Component.onCompleted: {
desktop.initWebviewProfileHandlers(webview.profile)
desktop.initWebviewProfileHandlers(webview.profile);
}
}

View file

@ -1,167 +0,0 @@
//
// Marketplaces.qml
//
// Created by Elisa Lupin-Jimenez on 3 Aug 2016
// 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
//
import QtQuick 2.5
import QtQuick.Controls 1.4
import QtWebChannel 1.0
import QtWebEngine 1.1
import QtWebSockets 1.0
import "qrc:///qtwebchannel/qwebchannel.js" as WebChannel
import "controls"
import "controls-uit" as Controls
import "styles"
import "styles-uit"
Rectangle {
HifiConstants { id: hifi }
id: marketplace
anchors.fill: parent
property var marketplacesUrl: "../../scripts/system/html/marketplaces.html"
property int statusBarHeight: 50
property int statusMargin: 50
property string standardMessage: "Check out other marketplaces."
property string claraMessage: "Choose a model and click Download -> Autodesk FBX."
property string claraError: "High Fidelity only supports Autodesk FBX models."
Controls.BaseWebView {
id: webview
url: marketplacesUrl
anchors.top: marketplace.top
width: parent.width
height: parent.height - statusBarHeight
focus: true
Timer {
id: zipTimer
running: false
repeat: false
interval: 1500
property var handler;
onTriggered: handler();
}
Timer {
id: alertTimer
running: false
repeat: false
interval: 9000
property var handler;
onTriggered: handler();
}
property var autoCancel: 'var element = $("a.btn.cancel");
element.click();'
property var simpleDownload: 'var element = $("a.download-file");
element.removeClass("download-file");
element.removeAttr("download");'
function displayErrorStatus() {
alertTimer.handler = function() {
statusLabel.text = claraMessage;
statusBar.color = hifi.colors.blueHighlight;
statusIcon.text = hifi.glyphs.info;
}
alertTimer.start();
}
property var notFbxHandler: 'var element = $("a.btn.btn-primary.viewer-button.download-file")
element.click();'
// this code is for removing other file types from Clara.io's download options
//property var checkFileType: "$('[data-extension]:not([data-extension=\"fbx\"])').parent().remove()"
onLinkHovered: {
desktop.currentUrl = hoveredUrl;
//runJavaScript(checkFileType, function(){console.log("Remove filetypes JS injection");});
if (File.isZippedFbx(desktop.currentUrl)) {
runJavaScript(simpleDownload, function(){console.log("Download JS injection");});
return;
}
if (File.isZipped(desktop.currentUrl)) {
statusLabel.text = claraError;
statusBar.color = hifi.colors.redHighlight;
statusIcon.text = hifi.glyphs.alert;
runJavaScript(notFbxHandler, displayErrorStatus());
}
}
onLoadingChanged: {
if (File.isClaraLink(webview.url)) {
statusLabel.text = claraMessage;
} else {
statusLabel.text = standardMessage;
}
statusBar.color = hifi.colors.blueHighlight;
statusIcon.text = hifi.glyphs.info;
}
onNewViewRequested: {
var component = Qt.createComponent("Browser.qml");
var newWindow = component.createObject(desktop);
request.openIn(newWindow.webView);
if (File.isZippedFbx(desktop.currentUrl)) {
runJavaScript(autoCancel);
zipTimer.handler = function() {
newWindow.destroy();
}
zipTimer.start();
}
}
}
Rectangle {
id: statusBar
anchors.top: webview.bottom
anchors.bottom: parent.bottom
anchors.left: parent.left
anchors.right: parent.right
color: hifi.colors.blueHighlight
Controls.Button {
id: switchMarketView
anchors.right: parent.right
anchors.rightMargin: statusMargin
anchors.verticalCenter: parent.verticalCenter
width: 150
text: "See all markets"
onClicked: {
webview.url = "../../scripts/system/html/marketplaces.html";
statusLabel.text = standardMessage;
}
}
Controls.Label {
id: statusLabel
anchors.verticalCenter: switchMarketView.verticalCenter
anchors.left: parent.left
anchors.leftMargin: statusMargin
color: hifi.colors.white
text: standardMessage
size: 18
}
HiFiGlyphs {
id: statusIcon
anchors.right: statusLabel.left
anchors.verticalCenter: statusLabel.verticalCenter
text: hifi.glyphs.info
color: hifi.colors.white
size: hifi.fontSizes.tableHeadingIcon
}
}
}

View file

@ -27,6 +27,7 @@ Windows.ScrollingWindow {
destroyOnCloseButton: false
property alias source: webview.url
property alias eventBridge: eventBridgeWrapper.eventBridge;
property alias scriptUrl: webview.userScriptUrl
QtObject {
id: eventBridgeWrapper
@ -71,6 +72,8 @@ Windows.ScrollingWindow {
focus: true
webChannel.registeredObjects: [eventBridgeWrapper]
property string userScriptUrl: ""
// Create a global EventBridge object for raiseAndLowerKeyboard.
WebEngineScript {
id: createGlobalEventBridge
@ -87,7 +90,25 @@ Windows.ScrollingWindow {
worldId: WebEngineScript.MainWorld
}
userScripts: [ createGlobalEventBridge, raiseAndLowerKeyboard ]
// User script.
WebEngineScript {
id: userScript
sourceUrl: webview.userScriptUrl
injectionPoint: WebEngineScript.DocumentReady // DOM ready but page load may not be finished.
worldId: WebEngineScript.MainWorld
}
userScripts: [ createGlobalEventBridge, raiseAndLowerKeyboard, userScript ]
function onWebEventReceived(event) {
if (event.slice(0, 17) === "CLARA.IO DOWNLOAD") {
ApplicationInterface.addAssetToWorldFromURL(event.slice(18));
}
}
Component.onCompleted: {
eventBridge.webEventReceived.connect(onWebEventReceived);
}
}
}
}

View file

@ -2,9 +2,8 @@
import QtQuick 2.3
import QtQuick.Controls 1.4
import QtWebChannel 1.0
import QtWebEngine 1.1
import QtWebEngine 1.2
import QtWebSockets 1.0
import "qrc:///qtwebchannel/qwebchannel.js" as WebChannel
import "windows" as Windows
import "controls"
@ -23,10 +22,22 @@ Windows.Window {
// Don't destroy on close... otherwise the JS/C++ will have a dangling pointer
destroyOnCloseButton: false
property var source;
property var eventBridge;
property var component;
property var dynamicContent;
// Keyboard control properties in case needed by QML content.
property bool keyboardEnabled: false
property bool keyboardRaised: false
property bool punctuationMode: false
// JavaScript event bridge object in case QML content includes Web content.
property alias eventBridge: eventBridgeWrapper.eventBridge;
QtObject {
id: eventBridgeWrapper
WebChannel.id: "eventBridgeWrapper"
property var eventBridge;
}
onSourceChanged: {
if (dynamicContent) {
@ -72,7 +83,6 @@ Windows.Window {
}
}
Item {
id: contentHolder
anchors.fill: parent

View file

@ -0,0 +1,27 @@
//
// Web3DOverlay.qml
//
// Created by David Rowe on 16 Dec 2016.
// 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
//
import QtQuick 2.5
import QtQuick.Controls 1.4
import "controls" as Controls
Controls.WebView {
function onWebEventReceived(event) {
if (event.slice(0, 17) === "CLARA.IO DOWNLOAD") {
ApplicationInterface.addAssetToWorldFromURL(event.slice(18));
}
}
Component.onCompleted: {
eventBridge.webEventReceived.connect(onWebEventReceived);
}
}

View file

@ -6,6 +6,7 @@ import HFWebEngineProfile 1.0
Item {
property alias url: root.url
property alias scriptURL: root.userScriptUrl
property alias eventBridge: eventBridgeWrapper.eventBridge
property bool keyboardEnabled: true // FIXME - Keyboard HMD only: Default to false
property bool keyboardRaised: false
@ -38,6 +39,8 @@ Item {
storageName: "qmlWebEngine"
}
property string userScriptUrl: ""
// creates a global EventBridge object.
WebEngineScript {
id: createGlobalEventBridge
@ -54,7 +57,15 @@ Item {
worldId: WebEngineScript.MainWorld
}
userScripts: [ createGlobalEventBridge, raiseAndLowerKeyboard ]
// User script.
WebEngineScript {
id: userScript
sourceUrl: root.userScriptUrl
injectionPoint: WebEngineScript.DocumentReady // DOM ready but page load may not be finished.
worldId: WebEngineScript.MainWorld
}
userScripts: [ createGlobalEventBridge, raiseAndLowerKeyboard, userScript ]
property string newUrl: ""

View file

@ -100,21 +100,25 @@ OriginalDesktop.Desktop {
// Accept a download through the webview
property bool webViewProfileSetup: false
property string currentUrl: ""
property string downloadUrl: ""
property string adaptedPath: ""
property string tempDir: ""
property bool autoAdd: false
function initWebviewProfileHandlers(profile) {
console.log("The webview url in desktop is: " + currentUrl);
downloadUrl = currentUrl;
if (webViewProfileSetup) return;
webViewProfileSetup = true;
profile.downloadRequested.connect(function(download){
console.log("Download start: " + download.state);
adaptedPath = File.convertUrlToPath(currentUrl);
adaptedPath = File.convertUrlToPath(downloadUrl);
tempDir = File.getTempDir();
console.log("Temp dir created: " + tempDir);
download.path = tempDir + "/" + adaptedPath;
console.log("Path where object should download: " + download.path);
console.log("Auto add: " + autoAdd);
download.accept();
if (download.state === WebEngineDownloadItem.DownloadInterrupted) {
console.log("download failed to complete");
@ -123,13 +127,18 @@ OriginalDesktop.Desktop {
profile.downloadFinished.connect(function(download){
if (download.state === WebEngineDownloadItem.DownloadCompleted) {
File.runUnzip(download.path, currentUrl);
File.runUnzip(download.path, downloadUrl, autoAdd);
} else {
console.log("The download was corrupted, state: " + download.state);
}
autoAdd = false;
})
}
function setAutoAdd(auto) {
autoAdd = auto;
}
// Create or fetch a toolbar with the given name
function getToolbar(name) {
var result = toolbars[name];

View file

@ -72,6 +72,24 @@ Rectangle {
table.selection.deselect(userIndex);
}
break;
// Received an "updateUsername()" request from the JS
case 'updateUsername':
// The User ID (UUID) is the first parameter in the message.
var userId = message.params[0];
// The text that goes in the userName field is the second parameter in the message.
var userName = message.params[1];
// If the userId is empty, we're updating "myData".
if (!userId) {
myData.userName = userName;
myCard.userName = userName; // Defensive programming
} else {
// Get the index in userModel and userData associated with the passed UUID
var userIndex = findSessionIndex(userId);
// Set the userName appropriately
userModel.get(userIndex).userName = userName;
userData[userIndex].userName = userName; // Defensive programming
}
break;
default:
console.log('Unrecognized message:', JSON.stringify(message));
}

File diff suppressed because it is too large Load diff

View file

@ -18,6 +18,7 @@
#include <QtCore/QPointer>
#include <QtCore/QSet>
#include <QtCore/QStringList>
#include <QtQuick/QQuickItem>
#include <QtGui/QImage>
@ -28,6 +29,7 @@
#include <AbstractViewStateInterface.h>
#include <EntityEditPacketSender.h>
#include <EntityTreeRenderer.h>
#include <FileScriptingInterface.h>
#include <input-plugins/KeyboardMouseDevice.h>
#include <input-plugins/TouchscreenDevice.h>
#include <OctreeQuery.h>
@ -310,6 +312,20 @@ public slots:
void toggleRunningScriptsWidget() const;
Q_INVOKABLE void showAssetServerWidget(QString filePath = "");
// FIXME: Move addAssetToWorld* methods to own class?
void addAssetToWorldFromURL(QString url);
void addAssetToWorldFromURLRequestFinished();
void addAssetToWorld(QString filePath);
void addAssetToWorldUnzipFailure(QString filePath);
void addAssetToWorldWithNewMapping(QString filePath, QString mapping, int copy);
void addAssetToWorldUpload(QString filePath, QString mapping);
void addAssetToWorldSetMapping(QString filePath, QString mapping, QString hash);
void addAssetToWorldAddEntity(QString filePath, QString mapping);
void handleUnzip(QString sourceFile, QString destinationFile, bool autoAdd);
FileScriptingInterface* getFileDownloadInterface() { return _fileDownload; }
void handleLocalServerConnection() const;
void readArgumentsFromLocalSocket() const;
@ -352,10 +368,17 @@ public slots:
static void runTests();
void setKeyboardFocusHighlight(const glm::vec3& position, const glm::quat& rotation, const glm::vec3& dimensions);
QUuid getKeyboardFocusEntity() const; // thread-safe
void setKeyboardFocusEntity(QUuid id);
void setKeyboardFocusEntity(EntityItemID entityItemID);
unsigned int getKeyboardFocusOverlay();
void setKeyboardFocusOverlay(unsigned int overlayID);
void addAssetToWorldMessageClose();
private slots:
void showDesktop();
void clearDomainOctreeDetails();
@ -392,6 +415,12 @@ private slots:
void updateDisplayMode();
void domainConnectionRefused(const QString& reasonMessage, int reason, const QString& extraInfo);
void addAssetToWorldCheckModelSize();
void onAssetToWorldMessageBoxClosed();
void addAssetToWorldInfoTimeout();
void addAssetToWorldErrorTimeout();
private:
static void initDisplay();
void init();
@ -568,7 +597,8 @@ private:
DialogsManagerScriptingInterface* _dialogsManagerScriptingInterface = new DialogsManagerScriptingInterface();
ThreadSafeValueCache<EntityItemID> _keyboardFocusedItem;
ThreadSafeValueCache<EntityItemID> _keyboardFocusedEntity;
ThreadSafeValueCache<unsigned int> _keyboardFocusedOverlay;
quint64 _lastAcceptedKeyPress = 0;
bool _isForeground = true; // starts out assumed to be in foreground
bool _inPaint = false;
@ -610,6 +640,22 @@ private:
model::SkyboxPointer _defaultSkybox { new ProceduralSkybox() } ;
gpu::TexturePointer _defaultSkyboxTexture;
gpu::TexturePointer _defaultSkyboxAmbientTexture;
QTimer _addAssetToWorldResizeTimer;
QHash<QUuid, int> _addAssetToWorldResizeList;
void addAssetToWorldInfo(QString modelName, QString infoText);
void addAssetToWorldInfoClear(QString modelName);
void addAssetToWorldInfoDone(QString modelName);
void addAssetToWorldError(QString modelName, QString errorText);
QQuickItem* _addAssetToWorldMessageBox{ nullptr };
QStringList _addAssetToWorldInfoKeys; // Model name
QStringList _addAssetToWorldInfoMessages; // Info message
QTimer _addAssetToWorldInfoTimer;
QTimer _addAssetToWorldErrorTimer;
FileScriptingInterface* _fileDownload;
};

View file

@ -184,6 +184,7 @@ void Avatar::animateScaleChanges(float deltaTime) {
}
void Avatar::updateAvatarEntities() {
PerformanceTimer perfTimer("attachments");
// - if queueEditEntityMessage sees clientOnly flag it does _myAvatar->updateAvatarEntity()
// - updateAvatarEntity saves the bytes and sets _avatarEntityDataLocallyEdited
// - MyAvatar::update notices _avatarEntityDataLocallyEdited and calls sendIdentityPacket
@ -285,28 +286,38 @@ void Avatar::simulate(float deltaTime) {
}
animateScaleChanges(deltaTime);
// update the shouldAnimate flag to match whether or not we will render the avatar.
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());
if (!_shouldAnimate) {
if (visibility > MINIMUM_VISIBILITY_FOR_ON) {
_shouldAnimate = true;
qCDebug(interfaceapp) << "Restoring" << (isMyAvatar() ? "myself" : getSessionUUID()) << "for visibility" << visibility;
bool avatarPositionInView = false;
bool avatarMeshInView = false;
{ // update the shouldAnimate flag to match whether or not we will render the avatar.
PerformanceTimer perfTimer("cull");
ViewFrustum viewFrustum;
{
PerformanceTimer perfTimer("LOD");
const float MINIMUM_VISIBILITY_FOR_ON = 0.4f;
const float MAXIMUM_VISIBILITY_FOR_OFF = 0.6f;
qApp->copyViewFrustum(viewFrustum);
float visibility = calculateRenderAccuracy(viewFrustum.getPosition(),
getBounds(), DependencyManager::get<LODManager>()->getOctreeSizeScale());
if (!_shouldAnimate) {
if (visibility > MINIMUM_VISIBILITY_FOR_ON) {
_shouldAnimate = true;
qCDebug(interfaceapp) << "Restoring" << (isMyAvatar() ? "myself" : getSessionUUID()) << "for visibility" << visibility;
}
} else if (visibility < MAXIMUM_VISIBILITY_FOR_OFF) {
_shouldAnimate = false;
qCDebug(interfaceapp) << "Optimizing" << (isMyAvatar() ? "myself" : getSessionUUID()) << "for visibility" << visibility;
}
}
} else if (visibility < MAXIMUM_VISIBILITY_FOR_OFF) {
_shouldAnimate = false;
qCDebug(interfaceapp) << "Optimizing" << (isMyAvatar() ? "myself" : getSessionUUID()) << "for visibility" << visibility;
}
// simple frustum check
float boundingRadius = getBoundingRadius();
qApp->copyDisplayViewFrustum(viewFrustum);
bool avatarPositionInView = viewFrustum.sphereIntersectsFrustum(getPosition(), boundingRadius);
bool avatarMeshInView = viewFrustum.boxIntersectsFrustum(_skeletonModel->getRenderableMeshBound());
{
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)) {
{
@ -331,6 +342,7 @@ void Avatar::simulate(float deltaTime) {
} else {
// a non-full update is still required so that the position, rotation, scale and bounds of the skeletonModel are updated.
getHead()->setPosition(getPosition());
PerformanceTimer perfTimer("skeleton");
_skeletonModel->simulate(deltaTime, false);
}
@ -379,6 +391,7 @@ void Avatar::applyPositionDelta(const glm::vec3& delta) {
}
void Avatar::measureMotionDerivatives(float deltaTime) {
PerformanceTimer perfTimer("derivatives");
// linear
float invDeltaTime = 1.0f / deltaTime;
// Floating point error prevents us from computing velocity in a naive way
@ -645,6 +658,7 @@ bool Avatar::shouldRenderHead(const RenderArgs* renderArgs) const {
// virtual
void Avatar::simulateAttachments(float deltaTime) {
PerformanceTimer perfTimer("attachments");
for (int i = 0; i < (int)_attachmentModels.size(); i++) {
const AttachmentData& attachment = _attachmentData.at(i);
auto& model = _attachmentModels.at(i);
@ -1039,6 +1053,7 @@ void Avatar::setAttachmentData(const QVector<AttachmentData>& attachmentData) {
int Avatar::parseDataFromBuffer(const QByteArray& buffer) {
PerformanceTimer perfTimer("unpack");
if (!_initialized) {
// now that we have data for this Avatar we are go for init
init();
@ -1258,6 +1273,7 @@ void Avatar::setOrientation(const glm::quat& orientation) {
}
void Avatar::updatePalms() {
PerformanceTimer perfTimer("palms");
// update thread-safe caches
_leftPalmRotationCache.set(getUncachedLeftPalmRotation());
_rightPalmRotationCache.set(getUncachedRightPalmRotation());

View file

@ -119,6 +119,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 +190,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

@ -49,12 +49,17 @@ glm::vec2 HMDScriptingInterface::overlayToSpherical(const glm::vec2 & position)
return qApp->getApplicationCompositor().overlayToSpherical(position);
}
bool HMDScriptingInterface::isHMDAvailable() {
return PluginUtils::isHMDAvailable();
bool HMDScriptingInterface::isHMDAvailable(const QString& name) {
return PluginUtils::isHMDAvailable(name);
}
bool HMDScriptingInterface::isHandControllerAvailable() {
return PluginUtils::isHandControllerAvailable();
bool HMDScriptingInterface::isHandControllerAvailable(const QString& name) {
return PluginUtils::isHandControllerAvailable(name);
}
bool HMDScriptingInterface::isSubdeviceContainingNameAvailable(const QString& name) {
return PluginUtils::isSubdeviceContainingNameAvailable(name);
}
void HMDScriptingInterface::requestShowHandControllers() {

View file

@ -38,8 +38,9 @@ public:
Q_INVOKABLE QString preferredAudioInput() const;
Q_INVOKABLE QString preferredAudioOutput() const;
Q_INVOKABLE bool isHMDAvailable();
Q_INVOKABLE bool isHandControllerAvailable();
Q_INVOKABLE bool isHMDAvailable(const QString& name = "");
Q_INVOKABLE bool isHandControllerAvailable(const QString& name = "");
Q_INVOKABLE bool isSubdeviceContainingNameAvailable(const QString& name);
Q_INVOKABLE void requestShowHandControllers();
Q_INVOKABLE void requestHideHandControllers();

View file

@ -10,6 +10,10 @@
#include "TestScriptingInterface.h"
#include <QtCore/QCoreApplication>
#include <QtCore/QLoggingCategory>
#include <DependencyManager.h>
#include <Trace.h>
TestScriptingInterface* TestScriptingInterface::getInstance() {
static TestScriptingInterface sharedInstance;
@ -28,3 +32,27 @@ void TestScriptingInterface::waitForDownloadIdle() {
void TestScriptingInterface::waitIdle() {
}
bool TestScriptingInterface::startTracing(QString logrules) {
if (!logrules.isEmpty()) {
QLoggingCategory::setFilterRules(logrules);
}
if (!DependencyManager::isSet<tracing::Tracer>()) {
return false;
}
DependencyManager::get<tracing::Tracer>()->startTracing();
return true;
}
bool TestScriptingInterface::stopTracing(QString filename) {
if (!DependencyManager::isSet<tracing::Tracer>()) {
return false;
}
auto tracer = DependencyManager::get<tracing::Tracer>();
tracer->stopTracing();
tracer->serialize(filename);
return true;
}

View file

@ -38,6 +38,17 @@ public slots:
*/
void waitIdle();
/**jsdoc
* Start recording Chrome compatible tracing events
* logRules can be used to specify a set of logging category rules to limit what gets captured
*/
bool startTracing(QString logrules = "");
/**jsdoc
* Stop recording Chrome compatible tracing events and serialize recorded events to a file
* Using a filename with a .gz extension will automatically compress the output file
*/
bool stopTracing(QString filename);
};
#endif // hifi_TestScriptingInterface_h

View file

@ -29,6 +29,7 @@
#include "ui/Stats.h"
#include "ui/AvatarInputs.h"
#include "OffscreenUi.h"
#include "InterfaceLogging.h"
#include <QQmlContext>
const vec4 CONNECTION_STATUS_BORDER_COLOR{ 1.0f, 0.0f, 0.0f, 0.8f };
@ -56,7 +57,7 @@ ApplicationOverlay::~ApplicationOverlay() {
// Renders the overlays either to a texture or to the screen
void ApplicationOverlay::renderOverlay(RenderArgs* renderArgs) {
PROFILE_RANGE(__FUNCTION__);
PROFILE_RANGE(render, __FUNCTION__);
PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), "ApplicationOverlay::displayOverlay()");
buildFramebufferObject();
@ -95,7 +96,7 @@ void ApplicationOverlay::renderOverlay(RenderArgs* renderArgs) {
}
void ApplicationOverlay::renderQmlUi(RenderArgs* renderArgs) {
PROFILE_RANGE(__FUNCTION__);
PROFILE_RANGE(app, __FUNCTION__);
if (!_uiTexture) {
_uiTexture = gpu::TexturePointer(gpu::Texture::createExternal2D(OffscreenQmlSurface::getDiscardLambda()));
@ -123,7 +124,7 @@ void ApplicationOverlay::renderQmlUi(RenderArgs* renderArgs) {
}
void ApplicationOverlay::renderAudioScope(RenderArgs* renderArgs) {
PROFILE_RANGE(__FUNCTION__);
PROFILE_RANGE(app, __FUNCTION__);
gpu::Batch& batch = *renderArgs->_batch;
auto geometryCache = DependencyManager::get<GeometryCache>();
@ -142,7 +143,7 @@ void ApplicationOverlay::renderAudioScope(RenderArgs* renderArgs) {
}
void ApplicationOverlay::renderOverlays(RenderArgs* renderArgs) {
PROFILE_RANGE(__FUNCTION__);
PROFILE_RANGE(app, __FUNCTION__);
gpu::Batch& batch = *renderArgs->_batch;
auto geometryCache = DependencyManager::get<GeometryCache>();
@ -261,7 +262,7 @@ static const auto DEFAULT_SAMPLER = gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_LI
static const auto DEPTH_FORMAT = gpu::Element(gpu::SCALAR, gpu::FLOAT, gpu::DEPTH);
void ApplicationOverlay::buildFramebufferObject() {
PROFILE_RANGE(__FUNCTION__);
PROFILE_RANGE(app, __FUNCTION__);
auto uiSize = qApp->getUiSize();
if (!_overlayFramebuffer || uiSize != _overlayFramebuffer->getSize()) {
@ -287,4 +288,4 @@ gpu::TexturePointer ApplicationOverlay::getOverlayTexture() {
return gpu::TexturePointer();
}
return _overlayFramebuffer->getRenderBuffer(0);
}
}

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

@ -202,9 +202,8 @@ bool Image3DOverlay::findRayIntersection(const glm::vec3& origin, const glm::vec
if (_texture && _texture->isLoaded()) {
// Make sure position and rotation is updated.
Transform transform = getTransform();
// XXX this code runs too often for this...
// applyTransformTo(transform, true);
// setTransform(transform);
// Don't call applyTransformTo() or setTransform() here because this code runs too frequently.
// Produce the dimensions of the overlay based on the image's aspect ratio and the overlay's scale.
bool isNull = _fromImage.isNull();

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

@ -81,6 +81,7 @@ void ModelOverlay::render(RenderArgs* args) {
}
_model->setVisibleInScene(_visible, scene);
_model->setLayeredInFront(getDrawInFront(), scene);
scene->enqueuePendingChanges(pendingChanges);
}

View file

@ -19,6 +19,7 @@
#include <RegisteredMetaTypes.h>
#include "Application.h"
#include "InterfaceLogging.h"
#include "Image3DOverlay.h"
#include "Circle3DOverlay.h"
#include "Cube3DOverlay.h"
@ -36,6 +37,7 @@
#include "Web3DOverlay.h"
#include <QtQuick/QQuickWindow>
Q_LOGGING_CATEGORY(trace_render_overlays, "trace.render.overlays")
Overlays::Overlays() :
_nextOverlayID(1) {}
@ -101,7 +103,7 @@ void Overlays::cleanupOverlaysToDelete() {
}
void Overlays::renderHUD(RenderArgs* renderArgs) {
PROFILE_RANGE(__FUNCTION__);
PROFILE_RANGE(render_overlays, __FUNCTION__);
QReadLocker lock(&_lock);
gpu::Batch& batch = *renderArgs->_batch;
@ -292,6 +294,14 @@ QString Overlays::getOverlayType(unsigned int overlayId) const {
return "";
}
QObject* Overlays::getOverlayObject(unsigned int id) {
Overlay::Pointer thisOverlay = getOverlay(id);
if (thisOverlay) {
return qobject_cast<QObject*>(&(*thisOverlay));
}
return nullptr;
}
unsigned int Overlays::getParentPanel(unsigned int childId) const {
Overlay::Pointer overlay = getOverlay(childId);
auto attachable = std::dynamic_pointer_cast<PanelAttachable>(overlay);
@ -388,7 +398,7 @@ QScriptValue OverlayPropertyResultToScriptValue(QScriptEngine* engine, const Ove
if (!value.value.isValid()) {
return QScriptValue::UndefinedValue;
}
return engine->newVariant(value.value);
return engine->toScriptValue(value.value);
}
void OverlayPropertyResultFromScriptValue(const QScriptValue& object, OverlayPropertyResult& value) {
@ -596,6 +606,38 @@ bool Overlays::isAddedOverlay(unsigned int id) {
return _overlaysHUD.contains(id) || _overlaysWorld.contains(id);
}
void Overlays::sendMousePressOnOverlay(unsigned int overlayID, const PointerEvent& event) {
emit mousePressOnOverlay(overlayID, event);
}
void Overlays::sendMouseReleaseOnOverlay(unsigned int overlayID, const PointerEvent& event) {
emit mouseReleaseOnOverlay(overlayID, event);
}
void Overlays::sendMouseMoveOnOverlay(unsigned int overlayID, const PointerEvent& event) {
emit mouseMoveOnOverlay(overlayID, event);
}
void Overlays::sendHoverEnterOverlay(unsigned int id, PointerEvent event) {
emit hoverEnterOverlay(id, event);
}
void Overlays::sendHoverOverOverlay(unsigned int id, PointerEvent event) {
emit hoverOverOverlay(id, event);
}
void Overlays::sendHoverLeaveOverlay(unsigned int id, PointerEvent event) {
emit hoverLeaveOverlay(id, event);
}
unsigned int Overlays::getKeyboardFocusOverlay() const {
return qApp->getKeyboardFocusOverlay();
}
void Overlays::setKeyboardFocusOverlay(unsigned int id) {
qApp->setKeyboardFocusOverlay(id);
}
float Overlays::width() const {
auto offscreenUi = DependencyManager::get<OffscreenUi>();
return offscreenUi->getWindow()->size().width();
@ -605,3 +647,152 @@ float Overlays::height() const {
auto offscreenUi = DependencyManager::get<OffscreenUi>();
return offscreenUi->getWindow()->size().height();
}
static const uint32_t MOUSE_POINTER_ID = 0;
static glm::vec2 projectOntoOverlayXYPlane(glm::vec3 position, glm::quat rotation, glm::vec2 dimensions, const PickRay& pickRay,
const RayToOverlayIntersectionResult& rayPickResult) {
// Project the intersection point onto the local xy plane of the overlay.
float distance;
glm::vec3 planePosition = position;
glm::vec3 planeNormal = rotation * Vectors::UNIT_Z;
glm::vec3 overlayDimensions = glm::vec3(dimensions.x, dimensions.y, 0.0f);
glm::vec3 rayDirection = pickRay.direction;
glm::vec3 rayStart = pickRay.origin;
glm::vec3 p;
if (rayPlaneIntersection(planePosition, planeNormal, rayStart, rayDirection, distance)) {
p = rayStart + rayDirection * distance;
} else {
p = rayPickResult.intersection;
}
glm::vec3 localP = glm::inverse(rotation) * (p - position);
glm::vec3 normalizedP = (localP / overlayDimensions) + glm::vec3(0.5f);
return glm::vec2(normalizedP.x * overlayDimensions.x,
(1.0f - normalizedP.y) * overlayDimensions.y); // flip y-axis
}
static uint32_t toPointerButtons(const QMouseEvent& event) {
uint32_t buttons = 0;
buttons |= event.buttons().testFlag(Qt::LeftButton) ? PointerEvent::PrimaryButton : 0;
buttons |= event.buttons().testFlag(Qt::RightButton) ? PointerEvent::SecondaryButton : 0;
buttons |= event.buttons().testFlag(Qt::MiddleButton) ? PointerEvent::TertiaryButton : 0;
return buttons;
}
static PointerEvent::Button toPointerButton(const QMouseEvent& event) {
switch (event.button()) {
case Qt::LeftButton:
return PointerEvent::PrimaryButton;
case Qt::RightButton:
return PointerEvent::SecondaryButton;
case Qt::MiddleButton:
return PointerEvent::TertiaryButton;
default:
return PointerEvent::NoButtons;
}
}
PointerEvent Overlays::calculatePointerEvent(Overlay::Pointer overlay, PickRay ray,
RayToOverlayIntersectionResult rayPickResult, QMouseEvent* event, PointerEvent::EventType eventType) {
auto thisOverlay = std::dynamic_pointer_cast<Web3DOverlay>(overlay);
QReadLocker lock(&_lock);
auto position = thisOverlay->getPosition();
auto rotation = thisOverlay->getRotation();
auto dimensions = thisOverlay->getSize();
glm::vec2 pos2D = projectOntoOverlayXYPlane(position, rotation, dimensions, ray, rayPickResult);
PointerEvent pointerEvent(eventType, MOUSE_POINTER_ID,
pos2D, rayPickResult.intersection,
rayPickResult.surfaceNormal, ray.direction,
toPointerButton(*event), toPointerButtons(*event));
return pointerEvent;
}
void Overlays::mousePressEvent(QMouseEvent* event) {
PerformanceTimer perfTimer("Overlays::mousePressEvent");
PickRay ray = qApp->computePickRay(event->x(), event->y());
RayToOverlayIntersectionResult rayPickResult = findRayIntersection(ray);
if (rayPickResult.intersects) {
_currentClickingOnOverlayID = rayPickResult.overlayID;
// Only Web overlays can have focus.
auto thisOverlay = std::dynamic_pointer_cast<Web3DOverlay>(getOverlay(_currentClickingOnOverlayID));
if (thisOverlay) {
auto pointerEvent = calculatePointerEvent(thisOverlay, ray, rayPickResult, event, PointerEvent::Press);
emit mousePressOnOverlay(_currentClickingOnOverlayID, pointerEvent);
} else {
emit mousePressOffOverlay();
}
} else {
emit mousePressOffOverlay();
}
}
void Overlays::mouseReleaseEvent(QMouseEvent* event) {
PerformanceTimer perfTimer("Overlays::mouseReleaseEvent");
PickRay ray = qApp->computePickRay(event->x(), event->y());
RayToOverlayIntersectionResult rayPickResult = findRayIntersection(ray);
if (rayPickResult.intersects) {
// Only Web overlays can have focus.
auto thisOverlay = std::dynamic_pointer_cast<Web3DOverlay>(getOverlay(rayPickResult.overlayID));
if (thisOverlay) {
auto pointerEvent = calculatePointerEvent(thisOverlay, ray, rayPickResult, event, PointerEvent::Release);
emit mouseReleaseOnOverlay(rayPickResult.overlayID, pointerEvent);
}
}
_currentClickingOnOverlayID = UNKNOWN_OVERLAY_ID;
}
void Overlays::mouseMoveEvent(QMouseEvent* event) {
PerformanceTimer perfTimer("Overlays::mouseMoveEvent");
PickRay ray = qApp->computePickRay(event->x(), event->y());
RayToOverlayIntersectionResult rayPickResult = findRayIntersection(ray);
if (rayPickResult.intersects) {
// Only Web overlays can have focus.
auto thisOverlay = std::dynamic_pointer_cast<Web3DOverlay>(getOverlay(rayPickResult.overlayID));
if (thisOverlay) {
auto pointerEvent = calculatePointerEvent(thisOverlay, ray, rayPickResult, event, PointerEvent::Move);
emit mouseMoveOnOverlay(rayPickResult.overlayID, pointerEvent);
// If previously hovering over a different overlay then leave hover on that overlay.
if (_currentHoverOverOverlayID != UNKNOWN_OVERLAY_ID && rayPickResult.overlayID != _currentHoverOverOverlayID) {
auto thisOverlay = std::dynamic_pointer_cast<Web3DOverlay>(getOverlay(_currentHoverOverOverlayID));
if (thisOverlay) {
auto pointerEvent = calculatePointerEvent(thisOverlay, ray, rayPickResult, event, PointerEvent::Move);
emit hoverLeaveOverlay(_currentHoverOverOverlayID, pointerEvent);
}
}
// If hovering over a new overlay then enter hover on that overlay.
if (rayPickResult.overlayID != _currentHoverOverOverlayID) {
emit hoverEnterOverlay(rayPickResult.overlayID, pointerEvent);
}
// Hover over current overlay.
emit hoverOverOverlay(rayPickResult.overlayID, pointerEvent);
_currentHoverOverOverlayID = rayPickResult.overlayID;
}
} else {
// If previously hovering an overlay then leave hover.
if (_currentHoverOverOverlayID != UNKNOWN_OVERLAY_ID) {
auto thisOverlay = std::dynamic_pointer_cast<Web3DOverlay>(getOverlay(_currentHoverOverOverlayID));
if (thisOverlay) {
auto pointerEvent = calculatePointerEvent(thisOverlay, ray, rayPickResult, event, PointerEvent::Move);
emit hoverLeaveOverlay(_currentHoverOverOverlayID, pointerEvent);
}
_currentHoverOverOverlayID = UNKNOWN_OVERLAY_ID;
}
}
}

View file

@ -18,11 +18,13 @@
#ifndef hifi_Overlays_h
#define hifi_Overlays_h
#include <QMouseEvent>
#include <QReadWriteLock>
#include <QScriptValue>
#include "Overlay.h"
#include <PointerEvent.h>
#include "Overlay.h"
#include "OverlayPanel.h"
#include "PanelAttachable.h"
@ -51,7 +53,7 @@ class RayToOverlayIntersectionResult {
public:
RayToOverlayIntersectionResult();
bool intersects;
int overlayID;
unsigned int overlayID;
float distance;
BoxFace face;
glm::vec3 surfaceNormal;
@ -75,9 +77,13 @@ void RayToOverlayIntersectionResultFromScriptValue(const QScriptValue& object, R
* @namespace Overlays
*/
const unsigned int UNKNOWN_OVERLAY_ID = 0;
class Overlays : public QObject {
Q_OBJECT
Q_PROPERTY(unsigned int keyboardFocusOverlay READ getKeyboardFocusOverlay WRITE setKeyboardFocusOverlay)
public:
Overlays();
@ -94,6 +100,10 @@ public:
unsigned int addOverlay(Overlay* overlay) { return addOverlay(Overlay::Pointer(overlay)); }
unsigned int addOverlay(Overlay::Pointer overlay);
void mousePressEvent(QMouseEvent* event);
void mouseReleaseEvent(QMouseEvent* event);
void mouseMoveEvent(QMouseEvent* event);
void cleanupAllOverlays();
public slots:
@ -147,6 +157,15 @@ public slots:
*/
QString getOverlayType(unsigned int overlayId) const;
/**jsdoc
* Get the overlay Script object.
*
* @function Overlays.getOverlayObject
* @param {Overlays.OverlayID} overlayID The ID of the overlay to get the script object of.
* @return {Object} The script object for the overlay if found.
*/
QObject* getOverlayObject(unsigned int id);
/**jsdoc
* Get the ID of the overlay at a particular point on the HUD/screen.
*
@ -239,6 +258,17 @@ public slots:
/// return true if there is a panel with that id else false
bool isAddedPanel(unsigned int id) { return _panels.contains(id); }
void sendMousePressOnOverlay(unsigned int overlayID, const PointerEvent& event);
void sendMouseReleaseOnOverlay(unsigned int overlayID, const PointerEvent& event);
void sendMouseMoveOnOverlay(unsigned int overlayID, const PointerEvent& event);
void sendHoverEnterOverlay(unsigned int id, PointerEvent event);
void sendHoverOverOverlay(unsigned int id, PointerEvent event);
void sendHoverLeaveOverlay(unsigned int id, PointerEvent event);
unsigned int getKeyboardFocusOverlay() const;
void setKeyboardFocusOverlay(unsigned int id);
signals:
/**jsdoc
* Emitted when an overlay is deleted
@ -249,6 +279,15 @@ signals:
void overlayDeleted(unsigned int id);
void panelDeleted(unsigned int id);
void mousePressOnOverlay(unsigned int overlayID, const PointerEvent& event);
void mouseReleaseOnOverlay(unsigned int overlayID, const PointerEvent& event);
void mouseMoveOnOverlay(unsigned int overlayID, const PointerEvent& event);
void mousePressOffOverlay();
void hoverEnterOverlay(unsigned int overlayID, const PointerEvent& event);
void hoverOverOverlay(unsigned int overlayID, const PointerEvent& event);
void hoverLeaveOverlay(unsigned int overlayID, const PointerEvent& event);
private:
void cleanupOverlaysToDelete();
@ -262,8 +301,12 @@ private:
QReadWriteLock _deleteLock;
QScriptEngine* _scriptEngine;
bool _enabled = true;
PointerEvent calculatePointerEvent(Overlay::Pointer overlay, PickRay ray, RayToOverlayIntersectionResult rayPickResult,
QMouseEvent* event, PointerEvent::EventType eventType);
unsigned int _currentClickingOnOverlayID { UNKNOWN_OVERLAY_ID };
unsigned int _currentHoverOverOverlayID { UNKNOWN_OVERLAY_ID };
};
#endif // hifi_Overlays_h

View file

@ -1,7 +1,6 @@
//
// Web3DOverlay.cpp
//
//
// Created by Clement on 7/1/14.
// Modified and renamed by Zander Otavka on 8/4/15
// Copyright 2014 High Fidelity, Inc.
@ -12,8 +11,12 @@
#include "Web3DOverlay.h"
#include <Application.h>
#include <QQuickWindow>
#include <QtGui/QOpenGLContext>
#include <QtQuick/QQuickItem>
#include <QtQml/QQmlContext>
#include <DependencyManager.h>
#include <GeometryCache.h>
@ -28,17 +31,24 @@
static const float DPI = 30.47f;
static const float INCHES_TO_METERS = 1.0f / 39.3701f;
static float OPAQUE_ALPHA_THRESHOLD = 0.99f;
static const float METERS_TO_INCHES = 39.3701f;
static const float OPAQUE_ALPHA_THRESHOLD = 0.99f;
QString const Web3DOverlay::TYPE = "web3d";
Web3DOverlay::Web3DOverlay() : _dpi(DPI) {
_touchDevice.setCapabilities(QTouchDevice::Position);
_touchDevice.setType(QTouchDevice::TouchScreen);
_touchDevice.setName("RenderableWebEntityItemTouchDevice");
_touchDevice.setMaximumTouchPoints(4);
_geometryId = DependencyManager::get<GeometryCache>()->allocateID();
}
Web3DOverlay::Web3DOverlay(const Web3DOverlay* Web3DOverlay) :
Billboard3DOverlay(Web3DOverlay),
_url(Web3DOverlay->_url),
_scriptURL(Web3DOverlay->_scriptURL),
_dpi(Web3DOverlay->_dpi),
_resolution(Web3DOverlay->_resolution)
{
@ -50,6 +60,19 @@ Web3DOverlay::~Web3DOverlay() {
_webSurface->pause();
_webSurface->disconnect(_connection);
QObject::disconnect(_mousePressConnection);
_mousePressConnection = QMetaObject::Connection();
QObject::disconnect(_mouseReleaseConnection);
_mouseReleaseConnection = QMetaObject::Connection();
QObject::disconnect(_mouseMoveConnection);
_mouseMoveConnection = QMetaObject::Connection();
QObject::disconnect(_hoverLeaveConnection);
_hoverLeaveConnection = QMetaObject::Connection();
QObject::disconnect(_emitScriptEventConnection);
_emitScriptEventConnection = QMetaObject::Connection();
QObject::disconnect(_webEventReceivedConnection);
_webEventReceivedConnection = QMetaObject::Connection();
// The lifetime of the QML surface MUST be managed by the main thread
// Additionally, we MUST use local variables copied by value, rather than
@ -67,11 +90,15 @@ Web3DOverlay::~Web3DOverlay() {
}
void Web3DOverlay::update(float deltatime) {
// FIXME: applyTransformTo causes tablet overlay to detach from tablet entity.
// Perhaps rather than deleting the following code it should be run only if isFacingAvatar() is true?
/*
if (usecTimestampNow() > _transformExpiry) {
Transform transform = getTransform();
applyTransformTo(transform);
setTransform(transform);
}
*/
}
void Web3DOverlay::render(RenderArgs* args) {
@ -92,21 +119,62 @@ void Web3DOverlay::render(RenderArgs* args) {
// and the current rendering load)
_webSurface->setMaxFps(10);
_webSurface->create(currentContext);
_webSurface->setBaseUrl(QUrl::fromLocalFile(PathUtils::resourcesPath() + "/qml/controls/"));
_webSurface->load("WebView.qml");
_webSurface->setBaseUrl(QUrl::fromLocalFile(PathUtils::resourcesPath() + "/qml/"));
_webSurface->load("Web3DOverlay.qml");
_webSurface->resume();
_webSurface->getRootItem()->setProperty("url", _url);
_webSurface->getRootItem()->setProperty("scriptURL", _scriptURL);
_webSurface->getRootContext()->setContextProperty("ApplicationInterface", qApp);
_webSurface->resize(QSize(_resolution.x, _resolution.y));
currentContext->makeCurrent(currentSurface);
auto forwardPointerEvent = [=](unsigned int overlayID, const PointerEvent& event) {
if (overlayID == getOverlayID()) {
handlePointerEvent(event);
}
};
_mousePressConnection = connect(&(qApp->getOverlays()), &Overlays::mousePressOnOverlay, forwardPointerEvent);
_mouseReleaseConnection = connect(&(qApp->getOverlays()), &Overlays::mouseReleaseOnOverlay, forwardPointerEvent);
_mouseMoveConnection = connect(&(qApp->getOverlays()), &Overlays::mouseMoveOnOverlay, forwardPointerEvent);
_hoverLeaveConnection = connect(&(qApp->getOverlays()), &Overlays::hoverLeaveOverlay,
[=](unsigned int overlayID, const PointerEvent& event) {
if (this->_pressed && this->getOverlayID() == overlayID) {
// If the user mouses off the overlay while the button is down, simulate a touch end.
QTouchEvent::TouchPoint point;
point.setId(event.getID());
point.setState(Qt::TouchPointReleased);
glm::vec2 windowPos = event.getPos2D() * (METERS_TO_INCHES * _dpi);
QPointF windowPoint(windowPos.x, windowPos.y);
point.setScenePos(windowPoint);
point.setPos(windowPoint);
QList<QTouchEvent::TouchPoint> touchPoints;
touchPoints.push_back(point);
QTouchEvent* touchEvent = new QTouchEvent(QEvent::TouchEnd, nullptr, Qt::NoModifier, Qt::TouchPointReleased,
touchPoints);
touchEvent->setWindow(_webSurface->getWindow());
touchEvent->setDevice(&_touchDevice);
touchEvent->setTarget(_webSurface->getRootItem());
QCoreApplication::postEvent(_webSurface->getWindow(), touchEvent);
}
});
_emitScriptEventConnection = connect(this, &Web3DOverlay::scriptEventReceived, _webSurface.data(), &OffscreenQmlSurface::emitScriptEvent);
_webEventReceivedConnection = connect(_webSurface.data(), &OffscreenQmlSurface::webEventReceived, this, &Web3DOverlay::webEventReceived);
}
vec2 size = _resolution / _dpi * INCHES_TO_METERS;
vec2 halfSize = size / 2.0f;
vec2 halfSize = getSize() / 2.0f;
vec4 color(toGlm(getColor()), getAlpha());
Transform transform = getTransform();
// FIXME: applyTransformTo causes tablet overlay to detach from tablet entity.
// Perhaps rather than deleting the following code it should be run only if isFacingAvatar() is true?
/*
applyTransformTo(transform, true);
setTransform(transform);
*/
if (glm::length2(getDimensions()) != 1.0f) {
transform.postScale(vec3(getDimensions(), 1.0f));
}
@ -144,6 +212,78 @@ const render::ShapeKey Web3DOverlay::getShapeKey() {
return builder.build();
}
QObject* Web3DOverlay::getEventHandler() {
if (!_webSurface) {
return nullptr;
}
return _webSurface->getEventHandler();
}
void Web3DOverlay::setProxyWindow(QWindow* proxyWindow) {
if (!_webSurface) {
return;
}
_webSurface->setProxyWindow(proxyWindow);
}
void Web3DOverlay::handlePointerEvent(const PointerEvent& event) {
if (!_webSurface) {
return;
}
glm::vec2 windowPos = event.getPos2D() * (METERS_TO_INCHES * _dpi);
QPointF windowPoint(windowPos.x, windowPos.y);
if (event.getType() == PointerEvent::Move) {
// Forward a mouse move event to the Web surface.
QMouseEvent* mouseEvent = new QMouseEvent(QEvent::MouseMove, windowPoint, windowPoint, windowPoint, Qt::NoButton,
Qt::NoButton, Qt::NoModifier);
QCoreApplication::postEvent(_webSurface->getWindow(), mouseEvent);
}
if (event.getType() == PointerEvent::Press) {
this->_pressed = true;
} else if (event.getType() == PointerEvent::Release) {
this->_pressed = false;
}
QEvent::Type type;
Qt::TouchPointState touchPointState;
switch (event.getType()) {
case PointerEvent::Press:
type = QEvent::TouchBegin;
touchPointState = Qt::TouchPointPressed;
break;
case PointerEvent::Release:
type = QEvent::TouchEnd;
touchPointState = Qt::TouchPointReleased;
break;
case PointerEvent::Move:
default:
type = QEvent::TouchUpdate;
touchPointState = Qt::TouchPointMoved;
break;
}
QTouchEvent::TouchPoint point;
point.setId(event.getID());
point.setState(touchPointState);
point.setPos(windowPoint);
point.setScreenPos(windowPoint);
QList<QTouchEvent::TouchPoint> touchPoints;
touchPoints.push_back(point);
QTouchEvent* touchEvent = new QTouchEvent(type);
touchEvent->setWindow(_webSurface->getWindow());
touchEvent->setDevice(&_touchDevice);
touchEvent->setTarget(_webSurface->getRootItem());
touchEvent->setTouchPoints(touchPoints);
touchEvent->setTouchPointStates(touchPointState);
QCoreApplication::postEvent(_webSurface->getWindow(), touchEvent);
}
void Web3DOverlay::setProperties(const QVariantMap& properties) {
Billboard3DOverlay::setProperties(properties);
@ -155,6 +295,14 @@ void Web3DOverlay::setProperties(const QVariantMap& properties) {
}
}
auto scriptURLValue = properties["scriptURL"];
if (scriptURLValue.isValid()) {
QString newScriptURL = scriptURLValue.toString();
if (newScriptURL != _scriptURL) {
setScriptURL(newScriptURL);
}
}
auto resolution = properties["resolution"];
if (resolution.isValid()) {
bool valid;
@ -164,7 +312,6 @@ void Web3DOverlay::setProperties(const QVariantMap& properties) {
}
}
auto dpi = properties["dpi"];
if (dpi.isValid()) {
_dpi = dpi.toFloat();
@ -175,6 +322,12 @@ QVariant Web3DOverlay::getProperty(const QString& property) {
if (property == "url") {
return _url;
}
if (property == "scriptURL") {
return _scriptURL;
}
if (property == "resolution") {
return vec2toVariant(_resolution);
}
if (property == "dpi") {
return _dpi;
}
@ -188,22 +341,38 @@ void Web3DOverlay::setURL(const QString& url) {
_webSurface->getRootItem()->setProperty("url", url);
});
}
}
void Web3DOverlay::setScriptURL(const QString& scriptURL) {
_scriptURL = scriptURL;
if (_webSurface) {
AbstractViewStateInterface::instance()->postLambdaEvent([this, scriptURL] {
_webSurface->getRootItem()->setProperty("scriptURL", scriptURL);
});
}
}
glm::vec2 Web3DOverlay::getSize() {
return _resolution / _dpi * INCHES_TO_METERS * getDimensions();
};
bool Web3DOverlay::findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, float& distance, BoxFace& face, glm::vec3& surfaceNormal) {
// FIXME - face and surfaceNormal not being returned
// Make sure position and rotation is updated.
Transform transform;
applyTransformTo(transform, true);
setTransform(transform);
// Don't call applyTransformTo() or setTransform() here because this code runs too frequently.
vec2 size = _resolution / _dpi * INCHES_TO_METERS * vec2(getDimensions());
// Produce the dimensions of the overlay based on the image's aspect ratio and the overlay's scale.
return findRayRectangleIntersection(origin, direction, getRotation(), getPosition(), size, distance);
return findRayRectangleIntersection(origin, direction, getRotation(), getPosition(), getSize(), distance);
}
Web3DOverlay* Web3DOverlay::createClone() const {
return new Web3DOverlay(this);
}
void Web3DOverlay::emitScriptEvent(const QVariant& message) {
if (QThread::currentThread() != thread()) {
QMetaObject::invokeMethod(this, "emitScriptEvent", Qt::QueuedConnection, Q_ARG(QVariant, message));
} else {
emit scriptEventReceived(message);
}
}

View file

@ -11,6 +11,10 @@
#include "Billboard3DOverlay.h"
#include <QTouchEvent>
#include <PointerEvent.h>
class OffscreenQmlSurface;
class Web3DOverlay : public Billboard3DOverlay {
@ -29,25 +33,51 @@ public:
virtual void update(float deltatime) override;
QObject* getEventHandler();
void setProxyWindow(QWindow* proxyWindow);
void handlePointerEvent(const PointerEvent& event);
// setters
void setURL(const QString& url);
void setScriptURL(const QString& script);
void setProperties(const QVariantMap& properties) override;
QVariant getProperty(const QString& property) override;
glm::vec2 getSize();
virtual bool findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, float& distance,
BoxFace& face, glm::vec3& surfaceNormal) override;
virtual Web3DOverlay* createClone() const override;
public slots:
void emitScriptEvent(const QVariant& scriptMessage);
signals:
void scriptEventReceived(const QVariant& message);
void webEventReceived(const QVariant& message);
private:
QSharedPointer<OffscreenQmlSurface> _webSurface;
QMetaObject::Connection _connection;
gpu::TexturePointer _texture;
QString _url;
QString _scriptURL;
float _dpi;
vec2 _resolution{ 640, 480 };
int _geometryId { 0 };
bool _pressed{ false };
QTouchDevice _touchDevice;
QMetaObject::Connection _mousePressConnection;
QMetaObject::Connection _mouseReleaseConnection;
QMetaObject::Connection _mouseMoveConnection;
QMetaObject::Connection _hoverLeaveConnection;
QMetaObject::Connection _emitScriptEventConnection;
QMetaObject::Connection _webEventReceivedConnection;
};
#endif // hifi_Web3DOverlay_h

View file

@ -394,7 +394,7 @@ const AnimPoseVec& AnimInverseKinematics::overlay(const AnimVariantMap& animVars
loadPoses(underPoses);
} else {
PROFILE_RANGE_EX("ik/relax", 0xffff00ff, 0);
PROFILE_RANGE_EX(simulation_animation, "ik/relax", 0xffff00ff, 0);
// relax toward underPoses
// HACK: this relaxation needs to be constant per-frame rather than per-realtime
@ -433,7 +433,7 @@ const AnimPoseVec& AnimInverseKinematics::overlay(const AnimVariantMap& animVars
// build a list of targets from _targetVarVec
std::vector<IKTarget> targets;
{
PROFILE_RANGE_EX("ik/computeTargets", 0xffff00ff, 0);
PROFILE_RANGE_EX(simulation_animation, "ik/computeTargets", 0xffff00ff, 0);
computeTargets(animVars, targets, underPoses);
}
@ -450,7 +450,7 @@ const AnimPoseVec& AnimInverseKinematics::overlay(const AnimVariantMap& animVars
} else {
{
PROFILE_RANGE_EX("ik/shiftHips", 0xffff00ff, 0);
PROFILE_RANGE_EX(simulation_animation, "ik/shiftHips", 0xffff00ff, 0);
// shift hips according to the _hipsOffset from the previous frame
float offsetLength = glm::length(_hipsOffset);
@ -476,12 +476,12 @@ const AnimPoseVec& AnimInverseKinematics::overlay(const AnimVariantMap& animVars
}
{
PROFILE_RANGE_EX("ik/ccd", 0xffff00ff, 0);
PROFILE_RANGE_EX(simulation_animation, "ik/ccd", 0xffff00ff, 0);
solveWithCyclicCoordinateDescent(targets);
}
{
PROFILE_RANGE_EX("ik/measureHipsOffset", 0xffff00ff, 0);
PROFILE_RANGE_EX(simulation_animation, "ik/measureHipsOffset", 0xffff00ff, 0);
// measure new _hipsOffset for next frame
// by looking for discrepancies between where a targeted endEffector is

View file

@ -14,6 +14,9 @@
#include "AnimationCache.h"
#include "AnimationLogging.h"
#include <Trace.h>
#include <StatTracker.h>
#include <Profile.h>
int animationPointerMetaTypeId = qRegisterMetaType<AnimationPointer>();
@ -45,9 +48,14 @@ Animation::Animation(const QUrl& url) : Resource(url) {}
AnimationReader::AnimationReader(const QUrl& url, const QByteArray& data) :
_url(url),
_data(data) {
DependencyManager::get<StatTracker>()->incrementStat("PendingProcessing");
}
void AnimationReader::run() {
DependencyManager::get<StatTracker>()->decrementStat("PendingProcessing");
CounterStat counter("Processing");
PROFILE_RANGE_EX(resource_parse, __FUNCTION__, 0xFF00FF00, 0, { { "url", _url.toString() } });
auto originalPriority = QThread::currentThread()->priority();
if (originalPriority == QThread::InheritPriority) {
originalPriority = QThread::NormalPriority;

View file

@ -65,6 +65,8 @@ public:
explicit Animation(const QUrl& url);
QString getType() const override { return "Animation"; }
const FBXGeometry& getGeometry() const { return *_geometry; }
virtual bool isLoaded() const override;

View file

@ -20,6 +20,7 @@
#include <GeometryUtil.h>
#include <NumericalConstants.h>
#include <DebugDraw.h>
#include <PerfStat.h>
#include <ScriptValueUtils.h>
#include <shared/NsightHelpers.h>
@ -882,7 +883,7 @@ void Rig::updateAnimationStateHandlers() { // called on avatar update thread (wh
void Rig::updateAnimations(float deltaTime, glm::mat4 rootTransform) {
PROFILE_RANGE_EX(__FUNCTION__, 0xffff00ff, 0);
PROFILE_RANGE_EX(simulation_animation, __FUNCTION__, 0xffff00ff, 0);
setModelOffset(rootTransform);
@ -1249,6 +1250,7 @@ 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.

View file

@ -1135,8 +1135,9 @@ void AudioClient::mixLocalAudioInjectors(float* mixBuffer) {
} else if (injector->isStereo()) {
// stereo gets directly mixed into mixBuffer
float gain = injector->getVolume();
for (int i = 0; i < AudioConstants::NETWORK_FRAME_SAMPLES_STEREO; i++) {
mixBuffer[i] += (float)_scratchBuffer[i] * (1/32768.0f);
mixBuffer[i] += (float)_scratchBuffer[i] * (1/32768.0f) * gain;
}
} else {

View file

@ -166,7 +166,6 @@ bool AudioInjector::injectLocally() {
_localBuffer->open(QIODevice::ReadOnly);
_localBuffer->setShouldLoop(_options.loop);
_localBuffer->setVolume(_options.volume);
// give our current send position to the local buffer
_localBuffer->setCurrentOffset(_currentSendOffset);
@ -209,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;
}
@ -232,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);
}
@ -298,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;
}
}
@ -389,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

@ -63,7 +63,7 @@ public:
AudioFOA& getLocalFOA() { return _localFOA; }
bool isLocalOnly() const { return _options.localOnly; }
float getVolume() const { return _options.volume; }
float getVolume() const { return glm::clamp(_options.volume, 0.0f, 1.0f); }
glm::vec3 getPosition() const { return _options.position; }
glm::quat getOrientation() const { return _options.orientation; }
bool isStereo() const { return _options.stereo; }

View file

@ -16,8 +16,7 @@ AudioInjectorLocalBuffer::AudioInjectorLocalBuffer(const QByteArray& rawAudioArr
_rawAudioArray(rawAudioArray),
_shouldLoop(false),
_isStopped(false),
_currentOffset(0),
_volume(1.0f)
_currentOffset(0)
{
}
@ -36,17 +35,6 @@ bool AudioInjectorLocalBuffer::seek(qint64 pos) {
}
}
void copy(char* to, char* from, int size, qreal factor) {
int16_t* toArray = (int16_t*) to;
int16_t* fromArray = (int16_t*) from;
int sampleSize = size / sizeof(int16_t);
for (int i = 0; i < sampleSize; i++) {
*toArray = factor * (*fromArray);
toArray++;
fromArray++;
}
}
qint64 AudioInjectorLocalBuffer::readData(char* data, qint64 maxSize) {
if (!_isStopped) {
@ -60,7 +48,7 @@ qint64 AudioInjectorLocalBuffer::readData(char* data, qint64 maxSize) {
bytesRead = bytesToEnd;
}
copy(data, _rawAudioArray.data() + _currentOffset, bytesRead, _volume);
memcpy(data, _rawAudioArray.data() + _currentOffset, bytesRead);
// now check if we are supposed to loop and if we can copy more from the beginning
if (_shouldLoop && maxSize != bytesRead) {
@ -88,7 +76,7 @@ qint64 AudioInjectorLocalBuffer::recursiveReadFromFront(char* data, qint64 maxSi
}
// copy that amount
copy(data, _rawAudioArray.data(), bytesRead, _volume);
memcpy(data, _rawAudioArray.data(), bytesRead);
// check if we need to call ourselves again and pull from the front again
if (bytesRead < maxSize) {
@ -97,4 +85,4 @@ qint64 AudioInjectorLocalBuffer::recursiveReadFromFront(char* data, qint64 maxSi
_currentOffset = bytesRead;
return bytesRead;
}
}
}

View file

@ -30,7 +30,6 @@ public:
void setShouldLoop(bool shouldLoop) { _shouldLoop = shouldLoop; }
void setCurrentOffset(int currentOffset) { _currentOffset = currentOffset; }
void setVolume(float volume) { _volume = glm::clamp(volume, 0.0f, 1.0f); }
private:
qint64 recursiveReadFromFront(char* data, qint64 maxSize);
@ -40,7 +39,6 @@ private:
bool _isStopped;
int _currentOffset;
float _volume;
};
#endif // hifi_AudioInjectorLocalBuffer_h

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;
}

File diff suppressed because it is too large Load diff

View file

@ -14,7 +14,7 @@
#include <stdint.h>
static const int SRC_MAX_CHANNELS = 2;
static const int SRC_MAX_CHANNELS = 4;
// polyphase filter
static const int SRC_PHASEBITS = 8;
@ -48,8 +48,6 @@ public:
int getMinInput(int outputFrames);
int getMaxInput(int outputFrames);
int getExactInput(int outputFrames);
private:
float* _polyphaseFilter;
int* _stepTable;
@ -77,12 +75,18 @@ private:
int multirateFilter1(const float* input0, float* output0, int inputFrames);
int multirateFilter2(const float* input0, const float* input1, float* output0, float* output1, int inputFrames);
int multirateFilter4(const float* input0, const float* input1, const float* input2, const float* input3,
float* output0, float* output1, float* output2, float* output3, int inputFrames);
int multirateFilter1_SSE(const float* input0, float* output0, int inputFrames);
int multirateFilter2_SSE(const float* input0, const float* input1, float* output0, float* output1, int inputFrames);
int multirateFilter1_ref(const float* input0, float* output0, int inputFrames);
int multirateFilter2_ref(const float* input0, const float* input1, float* output0, float* output1, int inputFrames);
int multirateFilter4_ref(const float* input0, const float* input1, const float* input2, const float* input3,
float* output0, float* output1, float* output2, float* output3, int inputFrames);
int multirateFilter1_AVX2(const float* input0, float* output0, int inputFrames);
int multirateFilter2_AVX2(const float* input0, const float* input1, float* output0, float* output1, int inputFrames);
int multirateFilter4_AVX2(const float* input0, const float* input1, const float* input2, const float* input3,
float* output0, float* output1, float* output2, float* output3, int inputFrames);
void convertInput(const int16_t* input, float** outputs, int numFrames);
void convertOutput(float** inputs, int16_t* output, int numFrames);

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

@ -97,54 +97,9 @@ void Sound::downSample(const QByteArray& rawAudioByteArray, int sampleRate) {
// no resampling needed
_byteArray = rawAudioByteArray;
} else if (_isAmbisonic) {
// FIXME: add a proper Ambisonic resampler!
int numChannels = 4;
AudioSRC resampler[4] { {sampleRate, AudioConstants::SAMPLE_RATE, 1},
{sampleRate, AudioConstants::SAMPLE_RATE, 1},
{sampleRate, AudioConstants::SAMPLE_RATE, 1},
{sampleRate, AudioConstants::SAMPLE_RATE, 1} };
// resize to max possible output
int numSourceFrames = rawAudioByteArray.size() / (numChannels * sizeof(AudioConstants::AudioSample));
int maxDestinationFrames = resampler[0].getMaxOutput(numSourceFrames);
int maxDestinationBytes = maxDestinationFrames * numChannels * sizeof(AudioConstants::AudioSample);
_byteArray.resize(maxDestinationBytes);
int numDestinationFrames = 0;
// iterate over channels
int16_t* srcBuffer = new int16_t[numSourceFrames];
int16_t* dstBuffer = new int16_t[maxDestinationFrames];
for (int ch = 0; ch < 4; ch++) {
int16_t* src = (int16_t*)rawAudioByteArray.data();
int16_t* dst = (int16_t*)_byteArray.data();
// deinterleave samples
for (int i = 0; i < numSourceFrames; i++) {
srcBuffer[i] = src[4*i + ch];
}
// resample one channel
numDestinationFrames = resampler[ch].render(srcBuffer, dstBuffer, numSourceFrames);
// reinterleave samples
for (int i = 0; i < numDestinationFrames; i++) {
dst[4*i + ch] = dstBuffer[i];
}
}
delete[] srcBuffer;
delete[] dstBuffer;
// truncate to actual output
int numDestinationBytes = numDestinationFrames * numChannels * sizeof(AudioConstants::AudioSample);
_byteArray.resize(numDestinationBytes);
} else {
int numChannels = _isStereo ? 2 : 1;
int numChannels = _isAmbisonic ? AudioConstants::AMBISONIC : (_isStereo ? AudioConstants::STEREO : AudioConstants::MONO);
AudioSRC resampler(sampleRate, AudioConstants::SAMPLE_RATE, numChannels);
// resize to max possible output

View file

@ -198,4 +198,109 @@ int AudioSRC::multirateFilter2_AVX2(const float* input0, const float* input1, fl
return outputFrames;
}
int AudioSRC::multirateFilter4_AVX2(const float* input0, const float* input1, const float* input2, const float* input3,
float* output0, float* output1, float* output2, float* output3, int inputFrames) {
int outputFrames = 0;
assert(_numTaps % 8 == 0); // SIMD8
if (_step == 0) { // rational
int32_t i = HI32(_offset);
while (i < inputFrames) {
const float* c0 = &_polyphaseFilter[_numTaps * _phase];
__m256 acc0 = _mm256_setzero_ps();
__m256 acc1 = _mm256_setzero_ps();
__m256 acc2 = _mm256_setzero_ps();
__m256 acc3 = _mm256_setzero_ps();
for (int j = 0; j < _numTaps; j += 8) {
//float coef = c0[j];
__m256 coef0 = _mm256_loadu_ps(&c0[j]);
//acc += input[i + j] * coef;
acc0 = _mm256_fmadd_ps(_mm256_loadu_ps(&input0[i + j]), coef0, acc0);
acc1 = _mm256_fmadd_ps(_mm256_loadu_ps(&input1[i + j]), coef0, acc1);
acc2 = _mm256_fmadd_ps(_mm256_loadu_ps(&input2[i + j]), coef0, acc2);
acc3 = _mm256_fmadd_ps(_mm256_loadu_ps(&input3[i + j]), coef0, acc3);
}
// horizontal sum
acc0 = _mm256_hadd_ps(acc0, acc1);
acc2 = _mm256_hadd_ps(acc2, acc3);
acc0 = _mm256_hadd_ps(acc0, acc2);
__m128 t0 = _mm_add_ps(_mm256_castps256_ps128(acc0), _mm256_extractf128_ps(acc0, 1));
_mm_store_ss(&output0[outputFrames], t0);
_mm_store_ss(&output1[outputFrames], _mm_shuffle_ps(t0, t0, _MM_SHUFFLE(0,0,0,1)));
_mm_store_ss(&output2[outputFrames], _mm_shuffle_ps(t0, t0, _MM_SHUFFLE(0,0,0,2)));
_mm_store_ss(&output3[outputFrames], _mm_shuffle_ps(t0, t0, _MM_SHUFFLE(0,0,0,3)));
outputFrames += 1;
i += _stepTable[_phase];
if (++_phase == _upFactor) {
_phase = 0;
}
}
_offset = (int64_t)(i - inputFrames) << 32;
} else { // irrational
while (HI32(_offset) < inputFrames) {
int32_t i = HI32(_offset);
uint32_t f = LO32(_offset);
uint32_t phase = f >> SRC_FRACBITS;
float ftmp = (f & SRC_FRACMASK) * QFRAC_TO_FLOAT;
const float* c0 = &_polyphaseFilter[_numTaps * (phase + 0)];
const float* c1 = &_polyphaseFilter[_numTaps * (phase + 1)];
__m256 acc0 = _mm256_setzero_ps();
__m256 acc1 = _mm256_setzero_ps();
__m256 acc2 = _mm256_setzero_ps();
__m256 acc3 = _mm256_setzero_ps();
__m256 frac = _mm256_broadcast_ss(&ftmp);
for (int j = 0; j < _numTaps; j += 8) {
//float coef = c0[j] + frac * (c1[j] - c0[j]);
__m256 coef0 = _mm256_loadu_ps(&c0[j]);
__m256 coef1 = _mm256_loadu_ps(&c1[j]);
coef1 = _mm256_sub_ps(coef1, coef0);
coef0 = _mm256_fmadd_ps(coef1, frac, coef0);
//acc += input[i + j] * coef;
acc0 = _mm256_fmadd_ps(_mm256_loadu_ps(&input0[i + j]), coef0, acc0);
acc1 = _mm256_fmadd_ps(_mm256_loadu_ps(&input1[i + j]), coef0, acc1);
acc2 = _mm256_fmadd_ps(_mm256_loadu_ps(&input2[i + j]), coef0, acc2);
acc3 = _mm256_fmadd_ps(_mm256_loadu_ps(&input3[i + j]), coef0, acc3);
}
// horizontal sum
acc0 = _mm256_hadd_ps(acc0, acc1);
acc2 = _mm256_hadd_ps(acc2, acc3);
acc0 = _mm256_hadd_ps(acc0, acc2);
__m128 t0 = _mm_add_ps(_mm256_castps256_ps128(acc0), _mm256_extractf128_ps(acc0, 1));
_mm_store_ss(&output0[outputFrames], t0);
_mm_store_ss(&output1[outputFrames], _mm_shuffle_ps(t0, t0, _MM_SHUFFLE(0,0,0,1)));
_mm_store_ss(&output2[outputFrames], _mm_shuffle_ps(t0, t0, _MM_SHUFFLE(0,0,0,2)));
_mm_store_ss(&output3[outputFrames], _mm_shuffle_ps(t0, t0, _MM_SHUFFLE(0,0,0,3)));
outputFrames += 1;
_offset += _step;
}
_offset -= (int64_t)inputFrames << 32;
}
_mm256_zeroupper();
return outputFrames;
}
#endif

View file

@ -147,14 +147,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();
}
@ -403,7 +403,7 @@ QByteArray AvatarData::toByteArray(bool cullSmallChanges, bool sendAll, bool sen
#ifdef WANT_DEBUG
if (sendAll) {
qDebug() << "AvatarData::toByteArray" << cullSmallChanges << sendAll
qCDebug(avatars) << "AvatarData::toByteArray" << cullSmallChanges << sendAll
<< "rotations:" << rotationSentCount << "translations:" << translationSentCount
<< "largest:" << maxTranslationDimension
<< "size:"
@ -705,9 +705,9 @@ int AvatarData::parseDataFromBuffer(const QByteArray& buffer) {
#ifdef WANT_DEBUG
if (numValidJointRotations > 15) {
qDebug() << "RECEIVING -- rotations:" << numValidJointRotations
<< "translations:" << numValidJointTranslations
<< "size:" << (int)(sourceBuffer - startPosition);
qCDebug(avatars) << "RECEIVING -- rotations:" << numValidJointRotations
<< "translations:" << numValidJointTranslations
<< "size:" << (int)(sourceBuffer - startPosition);
}
#endif
@ -1011,7 +1011,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("");
@ -1033,6 +1033,7 @@ bool AvatarData::processAvatarIdentity(const Identity& identity) {
setDisplayName(identity.displayName);
hasIdentityChanged = true;
}
maybeUpdateSessionDisplayNameFromTransport(identity.sessionDisplayName);
if (identity.attachmentData != _attachmentData) {
setAttachmentData(identity.attachmentData);
@ -1057,7 +1058,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;
@ -1412,6 +1413,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");
@ -1475,7 +1477,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) {
@ -1620,7 +1622,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();
@ -1633,7 +1635,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

@ -176,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)
@ -318,6 +321,7 @@ public:
QUrl skeletonModelURL;
QVector<AttachmentData> attachmentData;
QString displayName;
QString sessionDisplayName;
AvatarEntityMap avatarEntityData;
};
@ -330,9 +334,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);
@ -395,6 +401,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;
@ -422,6 +430,7 @@ protected:
QUrl _skeletonFBXURL;
QVector<AttachmentData> _attachmentData;
QString _displayName;
QString _sessionDisplayName { };
const QUrl& cannonicalSkeletonModelURL(const QUrl& empty);
float _displayNameTargetAlpha;

View file

@ -13,6 +13,7 @@
#include <NodeList.h>
#include <udt/PacketHeaders.h>
#include <PerfStat.h>
#include <SharedUtil.h>
#include "AvatarLogging.h"
@ -98,6 +99,7 @@ AvatarSharedPointer AvatarHashMap::findAvatar(const QUuid& sessionUUID) {
}
void AvatarHashMap::processAvatarDataPacket(QSharedPointer<ReceivedMessage> message, SharedNodePointer sendingNode) {
PerformanceTimer perfTimer("receiveAvatar");
// enumerate over all of the avatars in this packet
// only add them if mixerWeakPointer points to something (meaning that mixer is still around)
while (message->getBytesLeftToRead()) {
@ -131,6 +133,13 @@ void AvatarHashMap::processAvatarIdentityPacket(QSharedPointer<ReceivedMessage>
// make sure this isn't for an ignored avatar
auto nodeList = DependencyManager::get<NodeList>();
static auto EMPTY = QUuid();
if (identity.uuid == _avatarHash.value(EMPTY)->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);
@ -158,7 +167,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

@ -16,7 +16,6 @@
#include <QtOpenGL/QGLWidget>
#include <QtGui/QImage>
#if defined(Q_OS_MAC)
#include <OpenGL/CGLCurrent.h>
#endif
@ -44,6 +43,7 @@
#include <CursorManager.h>
#include "CompositorHelper.h"
#include "Logging.h"
const char* SRGB_TO_LINEAR_FRAG = R"SCRIBE(
@ -96,7 +96,7 @@ public:
Lock lock(_mutex);
_shutdown = true;
_condition.wait(lock, [&] { return !_shutdown; });
qDebug() << "Present thread shutdown";
qCDebug(displayPlugins) << "Present thread shutdown";
}
}
@ -129,7 +129,7 @@ public:
_context->makeCurrent();
while (!_shutdown) {
if (_pendingMainThreadOperation) {
PROFILE_RANGE("MainThreadOp")
PROFILE_RANGE(render, "MainThreadOp")
{
Lock lock(_mutex);
_context->doneCurrent();
@ -203,7 +203,7 @@ public:
// Execute the frame and present it to the display device.
_context->makeCurrent();
{
PROFILE_RANGE("PluginPresent")
PROFILE_RANGE(render, "PluginPresent")
currentPlugin->present();
CHECK_GL_ERROR();
}
@ -560,22 +560,22 @@ void OpenGLDisplayPlugin::compositeLayers() {
updateCompositeFramebuffer();
{
PROFILE_RANGE_EX("compositeScene", 0xff0077ff, (uint64_t)presentCount())
PROFILE_RANGE_EX(render, "compositeScene", 0xff0077ff, (uint64_t)presentCount())
compositeScene();
}
{
PROFILE_RANGE_EX("compositeOverlay", 0xff0077ff, (uint64_t)presentCount())
PROFILE_RANGE_EX(render, "compositeOverlay", 0xff0077ff, (uint64_t)presentCount())
compositeOverlay();
}
auto compositorHelper = DependencyManager::get<CompositorHelper>();
if (compositorHelper->getReticleVisible()) {
PROFILE_RANGE_EX("compositePointer", 0xff0077ff, (uint64_t)presentCount())
PROFILE_RANGE_EX(render, "compositePointer", 0xff0077ff, (uint64_t)presentCount())
compositePointer();
}
{
PROFILE_RANGE_EX("compositeExtra", 0xff0077ff, (uint64_t)presentCount())
PROFILE_RANGE_EX(render, "compositeExtra", 0xff0077ff, (uint64_t)presentCount())
compositeExtra();
}
}
@ -595,12 +595,12 @@ void OpenGLDisplayPlugin::internalPresent() {
}
void OpenGLDisplayPlugin::present() {
PROFILE_RANGE_EX(__FUNCTION__, 0xffffff00, (uint64_t)presentCount())
PROFILE_RANGE_EX(render, __FUNCTION__, 0xffffff00, (uint64_t)presentCount())
updateFrameData();
incrementPresentCount();
{
PROFILE_RANGE_EX("recycle", 0xff00ff00, (uint64_t)presentCount())
PROFILE_RANGE_EX(render, "recycle", 0xff00ff00, (uint64_t)presentCount())
_gpuContext->recycle();
}
@ -614,19 +614,19 @@ void OpenGLDisplayPlugin::present() {
_lastFrame = _currentFrame.get();
});
// Execute the frame rendering commands
PROFILE_RANGE_EX("execute", 0xff00ff00, (uint64_t)presentCount())
PROFILE_RANGE_EX(render, "execute", 0xff00ff00, (uint64_t)presentCount())
_gpuContext->executeFrame(_currentFrame);
}
// Write all layers to a local framebuffer
{
PROFILE_RANGE_EX("composite", 0xff00ffff, (uint64_t)presentCount())
PROFILE_RANGE_EX(render, "composite", 0xff00ffff, (uint64_t)presentCount())
compositeLayers();
}
// Take the composite framebuffer and send it to the output device
{
PROFILE_RANGE_EX("internalPresent", 0xff00ffff, (uint64_t)presentCount())
PROFILE_RANGE_EX(render, "internalPresent", 0xff00ffff, (uint64_t)presentCount())
internalPresent();
}

View file

@ -206,7 +206,7 @@ float HmdDisplayPlugin::getLeftCenterPixel() const {
}
void HmdDisplayPlugin::internalPresent() {
PROFILE_RANGE_EX(__FUNCTION__, 0xff00ff00, (uint64_t)presentCount())
PROFILE_RANGE_EX(render, __FUNCTION__, 0xff00ff00, (uint64_t)presentCount())
// Composite together the scene, overlay and mouse cursor
hmdPresent();
@ -741,7 +741,6 @@ void HmdDisplayPlugin::compositeExtra() {
}
HmdDisplayPlugin::~HmdDisplayPlugin() {
qDebug() << "Destroying HmdDisplayPlugin";
}
float HmdDisplayPlugin::stutterRate() const {

View file

@ -836,6 +836,7 @@ void EntityTreeRenderer::mouseMoveEvent(QMouseEvent* event) {
// If the new hover entity does not match the previous hover entity then we are entering the new one
// this is true if the _currentHoverOverEntityID is known or unknown
if (rayPickResult.entityID != _currentHoverOverEntityID) {
emit hoverEnterEntity(rayPickResult.entityID, pointerEvent);
if (_entitiesScriptEngine) {
_entitiesScriptEngine->callEntityScriptMethod(rayPickResult.entityID, "hoverEnterEntity", pointerEvent);
}

View file

@ -211,7 +211,7 @@ namespace render {
template <> void payloadRender(const RenderableModelEntityItemMeta::Pointer& payload, RenderArgs* args) {
if (args) {
if (payload && payload->entity) {
PROFILE_RANGE("MetaModelRender");
PROFILE_RANGE(render, "MetaModelRender");
payload->entity->render(args);
}
}
@ -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;
@ -533,7 +533,8 @@ void RenderableModelEntityItem::update(const quint64& now) {
properties.setLastEdited(usecTimestampNow()); // we must set the edit time since we're editing it
auto extents = _model->getMeshExtents();
properties.setDimensions(extents.maximum - extents.minimum);
qCDebug(entitiesrenderer) << "Autoresizing:" << (!getName().isEmpty() ? getName() : getModelURL());
qCDebug(entitiesrenderer) << "Autoresizing" << (!getName().isEmpty() ? getName() : getModelURL())
<< "from mesh extents";
QMetaObject::invokeMethod(DependencyManager::get<EntityScriptingInterface>().data(), "editEntity",
Qt::QueuedConnection,
Q_ARG(QUuid, getEntityItemID()),
@ -1169,6 +1170,7 @@ void RenderableModelEntityItem::setJointTranslationsSet(const QVector<bool>& tra
void RenderableModelEntityItem::locationChanged(bool tellPhysics) {
PerformanceTimer pertTimer("locationChanged");
EntityItem::locationChanged(tellPhysics);
if (_model && _model->isActive()) {
_model->setRotation(getRotation());

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,7 +46,7 @@ EntityItemPointer RenderableWebEntityItem::factory(const EntityItemID& entityID,
RenderableWebEntityItem::RenderableWebEntityItem(const EntityItemID& entityItemID) :
WebEntityItem(entityItemID) {
qDebug() << "Created web entity " << getID();
qCDebug(entities) << "Created web entity " << getID();
_touchDevice.setCapabilities(QTouchDevice::Position);
_touchDevice.setType(QTouchDevice::TouchScreen);
@ -57,7 +57,7 @@ RenderableWebEntityItem::RenderableWebEntityItem(const EntityItemID& entityItemI
RenderableWebEntityItem::~RenderableWebEntityItem() {
destroyWebSurface();
qDebug() << "Destroyed web entity " << getID();
qCDebug(entities) << "Destroyed web entity " << getID();
auto geometryCache = DependencyManager::get<GeometryCache>();
if (geometryCache) {
geometryCache->releaseID(_geometryId);
@ -90,7 +90,7 @@ bool RenderableWebEntityItem::buildWebSurface(QSharedPointer<EntityTreeRenderer>
}
++_currentWebCount;
qDebug() << "Building web surface: " << getID() << ", #" << _currentWebCount << ", url = " << _sourceUrl;
qCDebug(entities) << "Building web surface: " << getID() << ", #" << _currentWebCount << ", url = " << _sourceUrl;
QSurface * currentSurface = currentContext->surface();
@ -247,7 +247,7 @@ void RenderableWebEntityItem::render(RenderArgs* args) {
void RenderableWebEntityItem::setSourceUrl(const QString& value) {
if (_sourceUrl != value) {
qDebug() << "Setting web entity source URL to " << value;
qCDebug(entities) << "Setting web entity source URL to " << value;
_sourceUrl = value;
if (_webSurface) {
AbstractViewStateInterface::instance()->postLambdaEvent([this] {
@ -326,8 +326,6 @@ void RenderableWebEntityItem::handlePointerEvent(const PointerEvent& event) {
touchEvent->setTouchPoints(touchPoints);
touchEvent->setTouchPointStates(touchPointState);
_lastTouchEvent = *touchEvent;
QCoreApplication::postEvent(_webSurface->getWindow(), touchEvent);
}
}
@ -358,7 +356,7 @@ void RenderableWebEntityItem::destroyWebSurface() {
_hoverLeaveConnection = QMetaObject::Connection();
_webSurface.reset();
qDebug() << "Delete web surface: " << getID() << ", #" << _currentWebCount << ", url = " << _sourceUrl;
qCDebug(entities) << "Delete web surface: " << getID() << ", #" << _currentWebCount << ", url = " << _sourceUrl;
}
}

View file

@ -59,9 +59,7 @@ private:
QSharedPointer<OffscreenQmlSurface> _webSurface;
QMetaObject::Connection _connection;
gpu::TexturePointer _texture;
ivec2 _lastPress { INT_MIN };
bool _pressed{ false };
QTouchEvent _lastTouchEvent { QEvent::TouchUpdate };
uint64_t _lastRenderTime{ 0 };
QTouchDevice _touchDevice;

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

@ -316,7 +316,7 @@ private:
float _localRenderAlpha;
bool _localRenderAlphaChanged;
bool _defaultSettings;
bool _dimensionsInitialized = true; // Only false if creating an entity localy with no dimensions properties
bool _dimensionsInitialized = true; // Only false if creating an entity locally with no dimensions properties
// NOTE: The following are pseudo client only properties. They are only used in clients which can access
// properties of model geometry. But these properties are not serialized like other properties.

View file

@ -35,6 +35,7 @@ EntityScriptingInterface::EntityScriptingInterface(bool bidOnSimulationOwnership
connect(nodeList.data(), &NodeList::isAllowedEditorChanged, this, &EntityScriptingInterface::canAdjustLocksChanged);
connect(nodeList.data(), &NodeList::canRezChanged, this, &EntityScriptingInterface::canRezChanged);
connect(nodeList.data(), &NodeList::canRezTmpChanged, this, &EntityScriptingInterface::canRezTmpChanged);
connect(nodeList.data(), &NodeList::canWriteAssetsChanged, this, &EntityScriptingInterface::canWriteAssetsChanged);
}
void EntityScriptingInterface::queueEntityMessage(PacketType packetType,
@ -63,6 +64,11 @@ bool EntityScriptingInterface::canRezTmp() {
return nodeList->getThisNodeCanRezTmp();
}
bool EntityScriptingInterface::canWriteAssets() {
auto nodeList = DependencyManager::get<NodeList>();
return nodeList->getThisNodeCanWriteAssets();
}
void EntityScriptingInterface::setEntityTree(EntityTreePointer elementTree) {
if (_entityTree) {
disconnect(_entityTree.get(), &EntityTree::addingEntity, this, &EntityScriptingInterface::addingEntity);
@ -183,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());
}
@ -364,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()) {
@ -925,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;
}
@ -1045,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;
}
@ -1305,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

@ -110,6 +110,12 @@ public slots:
*/
Q_INVOKABLE bool canRezTmp();
/**jsdoc
* @function Entities.canWriteAsseets
* @return {bool} `true` if the DomainServer will allow this Node/Avatar to write to the asset server
*/
Q_INVOKABLE bool canWriteAssets();
/**jsdoc
* Add a new entity with the specified properties. If `clientOnly` is true, the entity will
* not be sent to the server and will only be visible/accessible on the local client.
@ -282,6 +288,7 @@ signals:
void canAdjustLocksChanged(bool canAdjustLocks);
void canRezChanged(bool canRez);
void canRezTmpChanged(bool canRez);
void canWriteAssetsChanged(bool canWriteAssets);
void mousePressOnEntity(const EntityItemID& entityItemID, const PointerEvent& event);
void mouseMoveOnEntity(const EntityItemID& entityItemID, const PointerEvent& event);

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

@ -321,7 +321,7 @@ FBXNode parseTextFBXNode(Tokenizer& tokenizer) {
}
FBXNode FBXReader::parseFBX(QIODevice* device) {
PROFILE_RANGE_EX(__FUNCTION__, 0xff0000ff, device);
PROFILE_RANGE_EX(resource_parse, __FUNCTION__, 0xff0000ff, device);
// verify the prolog
const QByteArray BINARY_PROLOG = "Kaydara FBX Binary ";
if (device->peek(BINARY_PROLOG.size()) != BINARY_PROLOG) {

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

@ -420,7 +420,7 @@ done:
FBXGeometry* OBJReader::readOBJ(QByteArray& model, const QVariantHash& mapping, const QUrl& url) {
PROFILE_RANGE_EX(__FUNCTION__, 0xffff0000, nullptr);
PROFILE_RANGE_EX(resource_parse, __FUNCTION__, 0xffff0000, nullptr);
QBuffer buffer { &model };
buffer.open(QIODevice::ReadOnly);

View file

@ -11,4 +11,4 @@
#include "GLLogging.h"
Q_LOGGING_CATEGORY(glLogging, "hifi.glLogging")
Q_LOGGING_CATEGORY(glLogging, "hifi.gl")

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