mirror of
https://github.com/JulianGro/overte.git
synced 2025-04-25 16:55:07 +02:00
merge from upstream
This commit is contained in:
commit
dc996bee95
179 changed files with 6145 additions and 1708 deletions
|
@ -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>();
|
||||
|
|
|
@ -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 “locked” 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’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",
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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,45 @@ 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);
|
||||
|
||||
qDebug() << "Sending username" << verifiedUsername << "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 +864,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)) {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -29,6 +29,7 @@ public:
|
|||
QList<NodeType_t> interestList;
|
||||
QString placeName;
|
||||
QString hardwareAddress;
|
||||
QUuid machineFingerprint;
|
||||
|
||||
QByteArray protocolVersion;
|
||||
};
|
||||
|
|
|
@ -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
|
||||
|
|
BIN
interface/resources/meshes/controller/touch/Oculus-Labels-L.fbx
Normal file
BIN
interface/resources/meshes/controller/touch/Oculus-Labels-L.fbx
Normal file
Binary file not shown.
BIN
interface/resources/meshes/controller/touch/Oculus-Labels-R.fbx
Normal file
BIN
interface/resources/meshes/controller/touch/Oculus-Labels-R.fbx
Normal file
Binary file not shown.
BIN
interface/resources/meshes/controller/touch/touch_l.fbx
Normal file
BIN
interface/resources/meshes/controller/touch/touch_l.fbx
Normal file
Binary file not shown.
BIN
interface/resources/meshes/controller/touch/touch_l_body.fbx
Normal file
BIN
interface/resources/meshes/controller/touch/touch_l_body.fbx
Normal file
Binary file not shown.
BIN
interface/resources/meshes/controller/touch/touch_l_bumper.fbx
Normal file
BIN
interface/resources/meshes/controller/touch/touch_l_bumper.fbx
Normal file
Binary file not shown.
BIN
interface/resources/meshes/controller/touch/touch_l_button_x.fbx
Normal file
BIN
interface/resources/meshes/controller/touch/touch_l_button_x.fbx
Normal file
Binary file not shown.
BIN
interface/resources/meshes/controller/touch/touch_l_button_y.fbx
Normal file
BIN
interface/resources/meshes/controller/touch/touch_l_button_y.fbx
Normal file
Binary file not shown.
BIN
interface/resources/meshes/controller/touch/touch_l_joystick.fbx
Normal file
BIN
interface/resources/meshes/controller/touch/touch_l_joystick.fbx
Normal file
Binary file not shown.
BIN
interface/resources/meshes/controller/touch/touch_l_trigger.fbx
Normal file
BIN
interface/resources/meshes/controller/touch/touch_l_trigger.fbx
Normal file
Binary file not shown.
BIN
interface/resources/meshes/controller/touch/touch_r.fbx
Normal file
BIN
interface/resources/meshes/controller/touch/touch_r.fbx
Normal file
Binary file not shown.
BIN
interface/resources/meshes/controller/touch/touch_r_body.fbx
Normal file
BIN
interface/resources/meshes/controller/touch/touch_r_body.fbx
Normal file
Binary file not shown.
BIN
interface/resources/meshes/controller/touch/touch_r_bumper.fbx
Normal file
BIN
interface/resources/meshes/controller/touch/touch_r_bumper.fbx
Normal file
Binary file not shown.
BIN
interface/resources/meshes/controller/touch/touch_r_button_a.fbx
Normal file
BIN
interface/resources/meshes/controller/touch/touch_r_button_a.fbx
Normal file
Binary file not shown.
BIN
interface/resources/meshes/controller/touch/touch_r_button_b.fbx
Normal file
BIN
interface/resources/meshes/controller/touch/touch_r_button_b.fbx
Normal file
Binary file not shown.
BIN
interface/resources/meshes/controller/touch/touch_r_joystick.fbx
Normal file
BIN
interface/resources/meshes/controller/touch/touch_r_joystick.fbx
Normal file
Binary file not shown.
BIN
interface/resources/meshes/controller/touch/touch_r_trigger.fbx
Normal file
BIN
interface/resources/meshes/controller/touch/touch_r_trigger.fbx
Normal file
Binary file not shown.
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
27
interface/resources/qml/Web3DOverlay.qml
Normal file
27
interface/resources/qml/Web3DOverlay.qml
Normal 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);
|
||||
}
|
||||
}
|
|
@ -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: ""
|
||||
|
||||
|
|
|
@ -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];
|
||||
|
|
36
interface/resources/qml/hifi/NameCard.qml
Normal file
36
interface/resources/qml/hifi/NameCard.qml
Normal file
|
@ -0,0 +1,36 @@
|
|||
//
|
||||
// NameCard.qml
|
||||
// qml/hifi
|
||||
//
|
||||
// Created by Howard Stearns on 12/9/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 Hifi 1.0
|
||||
import QtQuick 2.5
|
||||
import "../styles-uit"
|
||||
|
||||
|
||||
Column {
|
||||
property string displayName: "";
|
||||
property string userName: "";
|
||||
property int displayTextHeight: 18;
|
||||
property int usernameTextHeight: 12;
|
||||
|
||||
RalewaySemiBold {
|
||||
text: parent.displayName;
|
||||
size: parent.displayTextHeight;
|
||||
elide: Text.ElideRight;
|
||||
width: parent.width;
|
||||
}
|
||||
RalewayLight {
|
||||
visible: parent.displayName;
|
||||
text: parent.userName;
|
||||
size: parent.usernameTextHeight;
|
||||
elide: Text.ElideRight;
|
||||
width: parent.width;
|
||||
}
|
||||
}
|
225
interface/resources/qml/hifi/Pal.qml
Normal file
225
interface/resources/qml/hifi/Pal.qml
Normal file
|
@ -0,0 +1,225 @@
|
|||
//
|
||||
// Pal.qml
|
||||
// qml/hifi
|
||||
//
|
||||
// People Action List
|
||||
//
|
||||
// Created by Howard Stearns on 12/12/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
|
||||
//
|
||||
|
||||
/* TODO:
|
||||
|
||||
prototype:
|
||||
- only show kick/mute when canKick
|
||||
- margins everywhere
|
||||
- column head centering
|
||||
- column head font
|
||||
- proper button .svg on toolbar
|
||||
|
||||
mvp:
|
||||
- Show all participants, including ignored, and populate initial ignore/mute status.
|
||||
- If name is elided, hover should scroll name left so the full name can be read.
|
||||
|
||||
*/
|
||||
|
||||
import QtQuick 2.5
|
||||
import QtQuick.Controls 1.4
|
||||
|
||||
Rectangle {
|
||||
id: pal;
|
||||
property int keepFromHorizontalScroll: 1;
|
||||
width: parent.width - keepFromHorizontalScroll;
|
||||
height: parent.height;
|
||||
|
||||
property int nameWidth: width/2;
|
||||
property int actionWidth: nameWidth / (table.columnCount - 1);
|
||||
property int rowHeight: 50;
|
||||
property var userData: [];
|
||||
property var myData: ({displayName: "", userName: ""}); // valid dummy until set
|
||||
property bool iAmAdmin: false;
|
||||
function findSessionIndex(sessionId, optionalData) { // no findIndex in .qml
|
||||
var i, data = optionalData || userData, length = data.length;
|
||||
for (var i = 0; i < length; i++) {
|
||||
if (data[i].sessionId === sessionId) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
function fromScript(message) {
|
||||
switch (message.method) {
|
||||
case 'users':
|
||||
var data = message.params;
|
||||
var myIndex = findSessionIndex('', data);
|
||||
iAmAdmin = Users.canKick;
|
||||
myData = data[myIndex];
|
||||
data.splice(myIndex, 1);
|
||||
userData = data;
|
||||
sortModel();
|
||||
break;
|
||||
case 'select':
|
||||
var sessionId = message.params[0];
|
||||
var selected = message.params[1];
|
||||
var userIndex = findSessionIndex(sessionId);
|
||||
if (selected) {
|
||||
table.selection.clear(); // for now, no multi-select
|
||||
table.selection.select(userIndex);
|
||||
} else {
|
||||
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));
|
||||
}
|
||||
}
|
||||
ListModel {
|
||||
id: userModel
|
||||
}
|
||||
function sortModel() {
|
||||
var sortProperty = table.getColumn(table.sortIndicatorColumn).role;
|
||||
var before = (table.sortIndicatorOrder === Qt.AscendingOrder) ? -1 : 1;
|
||||
var after = -1 * before;
|
||||
userData.sort(function (a, b) {
|
||||
var aValue = a[sortProperty].toString().toLowerCase(), bValue = b[sortProperty].toString().toLowerCase();
|
||||
switch (true) {
|
||||
case (aValue < bValue): return before;
|
||||
case (aValue > bValue): return after;
|
||||
default: return 0;
|
||||
}
|
||||
});
|
||||
table.selection.clear();
|
||||
userModel.clear();
|
||||
var userIndex = 0;
|
||||
userData.forEach(function (datum) {
|
||||
function init(property) {
|
||||
if (datum[property] === undefined) {
|
||||
datum[property] = false;
|
||||
}
|
||||
}
|
||||
['ignore', 'spacer', 'mute', 'kick'].forEach(init);
|
||||
datum.userIndex = userIndex++;
|
||||
userModel.append(datum);
|
||||
});
|
||||
}
|
||||
signal sendToScript(var message);
|
||||
function noticeSelection() {
|
||||
var userIds = [];
|
||||
table.selection.forEach(function (userIndex) {
|
||||
userIds.push(userData[userIndex].sessionId);
|
||||
});
|
||||
pal.sendToScript({method: 'selected', params: userIds});
|
||||
}
|
||||
Connections {
|
||||
target: table.selection
|
||||
onSelectionChanged: pal.noticeSelection()
|
||||
}
|
||||
|
||||
Column {
|
||||
NameCard {
|
||||
id: myCard;
|
||||
width: nameWidth;
|
||||
displayName: myData.displayName;
|
||||
userName: myData.userName;
|
||||
}
|
||||
TableView {
|
||||
id: table;
|
||||
TableViewColumn {
|
||||
role: "displayName";
|
||||
title: "Name";
|
||||
width: nameWidth
|
||||
}
|
||||
TableViewColumn {
|
||||
role: "ignore";
|
||||
title: "Ignore"
|
||||
width: actionWidth
|
||||
}
|
||||
TableViewColumn {
|
||||
title: "";
|
||||
width: actionWidth
|
||||
}
|
||||
TableViewColumn {
|
||||
visible: iAmAdmin;
|
||||
role: "mute";
|
||||
title: "Mute";
|
||||
width: actionWidth
|
||||
}
|
||||
TableViewColumn {
|
||||
visible: iAmAdmin;
|
||||
role: "kick";
|
||||
title: "Ban"
|
||||
width: actionWidth
|
||||
}
|
||||
model: userModel;
|
||||
rowDelegate: Rectangle { // The only way I know to specify a row height.
|
||||
height: rowHeight;
|
||||
// The rest of this is cargo-culted to restore the default styling
|
||||
SystemPalette {
|
||||
id: myPalette;
|
||||
colorGroup: SystemPalette.Active
|
||||
}
|
||||
color: {
|
||||
var baseColor = styleData.alternate?myPalette.alternateBase:myPalette.base
|
||||
return styleData.selected?myPalette.highlight:baseColor
|
||||
}
|
||||
}
|
||||
itemDelegate: Item {
|
||||
id: itemCell;
|
||||
property bool isCheckBox: typeof(styleData.value) === 'boolean';
|
||||
NameCard {
|
||||
id: nameCard;
|
||||
visible: !isCheckBox;
|
||||
width: nameWidth;
|
||||
displayName: styleData.value;
|
||||
userName: model.userName;
|
||||
}
|
||||
Rectangle {
|
||||
radius: itemCell.height / 4;
|
||||
visible: isCheckBox;
|
||||
color: styleData.value ? "green" : "red";
|
||||
anchors.fill: parent;
|
||||
MouseArea {
|
||||
anchors.fill: parent;
|
||||
acceptedButtons: Qt.LeftButton;
|
||||
hoverEnabled: true;
|
||||
onClicked: {
|
||||
var newValue = !model[styleData.role];
|
||||
var datum = userData[model.userIndex];
|
||||
datum[styleData.role] = model[styleData.role] = newValue;
|
||||
Users[styleData.role](model.sessionId);
|
||||
// Just for now, while we cannot undo things:
|
||||
userData.splice(model.userIndex, 1);
|
||||
sortModel();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
height: pal.height - myCard.height;
|
||||
width: pal.width;
|
||||
sortIndicatorVisible: true;
|
||||
onSortIndicatorColumnChanged: sortModel();
|
||||
onSortIndicatorOrderChanged: sortModel();
|
||||
}
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load diff
|
@ -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;
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -50,12 +50,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() {
|
||||
|
|
|
@ -40,8 +40,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();
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -81,6 +81,7 @@ void ModelOverlay::render(RenderArgs* args) {
|
|||
}
|
||||
|
||||
_model->setVisibleInScene(_visible, scene);
|
||||
_model->setLayeredInFront(getDrawInFront(), scene);
|
||||
|
||||
scene->enqueuePendingChanges(pendingChanges);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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; }
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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()) {
|
||||
|
|
|
@ -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(
|
||||
|
||||
|
@ -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();
|
||||
}
|
||||
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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());
|
||||
|
|
|
@ -350,8 +350,6 @@ void RenderableWebEntityItem::handlePointerEvent(const PointerEvent& event) {
|
|||
touchEvent->setTouchPoints(touchPoints);
|
||||
touchEvent->setTouchPointStates(touchPointState);
|
||||
|
||||
_lastTouchEvent = *touchEvent;
|
||||
|
||||
QCoreApplication::postEvent(_webSurface->getWindow(), touchEvent);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -65,9 +65,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;
|
||||
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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.
|
||||
|
@ -284,6 +290,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);
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -11,4 +11,4 @@
|
|||
|
||||
#include "GLLogging.h"
|
||||
|
||||
Q_LOGGING_CATEGORY(glLogging, "hifi.glLogging")
|
||||
Q_LOGGING_CATEGORY(glLogging, "hifi.gl")
|
||||
|
|
|
@ -38,6 +38,9 @@
|
|||
#include "GLLogging.h"
|
||||
#include "Context.h"
|
||||
|
||||
Q_LOGGING_CATEGORY(trace_render_qml, "trace.render.qml")
|
||||
Q_LOGGING_CATEGORY(trace_render_qml_gl, "trace.render.qml.gl")
|
||||
|
||||
struct TextureSet {
|
||||
// The number of surfaces with this size
|
||||
size_t count { 0 };
|
||||
|
@ -276,6 +279,7 @@ void OffscreenQmlSurface::render() {
|
|||
return;
|
||||
}
|
||||
|
||||
PROFILE_RANGE(render_qml_gl, __FUNCTION__)
|
||||
_canvas->makeCurrent();
|
||||
|
||||
_renderControl->sync();
|
||||
|
@ -284,7 +288,6 @@ void OffscreenQmlSurface::render() {
|
|||
GLuint texture = offscreenTextures.getNextTexture(_size);
|
||||
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, _fbo);
|
||||
glFramebufferTexture(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, texture, 0);
|
||||
PROFILE_RANGE("qml_render->rendercontrol")
|
||||
_renderControl->render();
|
||||
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
|
||||
glBindTexture(GL_TEXTURE_2D, texture);
|
||||
|
@ -617,12 +620,12 @@ void OffscreenQmlSurface::updateQuick() {
|
|||
}
|
||||
|
||||
if (_polish) {
|
||||
PROFILE_RANGE(render_qml, "OffscreenQML polish")
|
||||
_renderControl->polishItems();
|
||||
_polish = false;
|
||||
}
|
||||
|
||||
if (_render) {
|
||||
PROFILE_RANGE(__FUNCTION__);
|
||||
render();
|
||||
_render = false;
|
||||
}
|
||||
|
|
|
@ -30,6 +30,7 @@
|
|||
|
||||
#include "GLTexture.h"
|
||||
#include "GLShader.h"
|
||||
|
||||
using namespace gpu;
|
||||
using namespace gpu::gl;
|
||||
|
||||
|
@ -199,7 +200,7 @@ void GLBackend::renderPassTransfer(const Batch& batch) {
|
|||
|
||||
_inRenderTransferPass = true;
|
||||
{ // Sync all the buffers
|
||||
PROFILE_RANGE("syncGPUBuffer");
|
||||
PROFILE_RANGE(render_gpu_gl, "syncGPUBuffer");
|
||||
|
||||
for (auto& cached : batch._buffers._items) {
|
||||
if (cached._data) {
|
||||
|
@ -209,7 +210,7 @@ void GLBackend::renderPassTransfer(const Batch& batch) {
|
|||
}
|
||||
|
||||
{ // Sync all the buffers
|
||||
PROFILE_RANGE("syncCPUTransform");
|
||||
PROFILE_RANGE(render_gpu_gl, "syncCPUTransform");
|
||||
_transform._cameras.clear();
|
||||
_transform._cameraOffsets.clear();
|
||||
|
||||
|
@ -241,7 +242,7 @@ void GLBackend::renderPassTransfer(const Batch& batch) {
|
|||
}
|
||||
|
||||
{ // Sync the transform buffers
|
||||
PROFILE_RANGE("syncGPUTransform");
|
||||
PROFILE_RANGE(render_gpu_gl, "syncGPUTransform");
|
||||
transferTransformState(batch);
|
||||
}
|
||||
|
||||
|
@ -303,7 +304,7 @@ void GLBackend::render(const Batch& batch) {
|
|||
}
|
||||
|
||||
{
|
||||
PROFILE_RANGE("Transfer");
|
||||
PROFILE_RANGE(render_gpu_gl, "Transfer");
|
||||
renderPassTransfer(batch);
|
||||
}
|
||||
|
||||
|
@ -313,7 +314,7 @@ void GLBackend::render(const Batch& batch) {
|
|||
}
|
||||
#endif
|
||||
{
|
||||
PROFILE_RANGE(_stereo._enable ? "Render Stereo" : "Render");
|
||||
PROFILE_RANGE(render_gpu_gl, _stereo._enable ? "Render Stereo" : "Render");
|
||||
renderPassDraw(batch);
|
||||
}
|
||||
#ifdef GPU_STEREO_DRAWCALL_INSTANCED
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
//
|
||||
#include "GLBackend.h"
|
||||
#include "GLQuery.h"
|
||||
#include "GLShared.h"
|
||||
|
||||
using namespace gpu;
|
||||
using namespace gpu::gl;
|
||||
|
@ -27,7 +28,7 @@ void GLBackend::do_beginQuery(const Batch& batch, size_t paramOffset) {
|
|||
auto query = batch._queries.get(batch._params[paramOffset]._uint);
|
||||
GLQuery* glquery = syncGPUObject(*query);
|
||||
if (glquery) {
|
||||
PROFILE_RANGE_BEGIN(glquery->_profileRangeId, query->getName().c_str(), 0xFFFF7F00);
|
||||
PROFILE_RANGE_BEGIN(render_gpu_gl, glquery->_profileRangeId, query->getName().c_str(), 0xFFFF7F00);
|
||||
|
||||
++_queryStage._rangeQueryDepth;
|
||||
glGetInteger64v(GL_TIMESTAMP, (GLint64*)&glquery->_batchElapsedTime);
|
||||
|
@ -61,7 +62,7 @@ void GLBackend::do_endQuery(const Batch& batch, size_t paramOffset) {
|
|||
glGetInteger64v(GL_TIMESTAMP, &now);
|
||||
glquery->_batchElapsedTime = now - glquery->_batchElapsedTime;
|
||||
|
||||
PROFILE_RANGE_END(glquery->_profileRangeId);
|
||||
PROFILE_RANGE_END(render_gpu_gl, glquery->_profileRangeId);
|
||||
|
||||
(void)CHECK_GL_ERROR();
|
||||
}
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
#include <fstream>
|
||||
|
||||
Q_LOGGING_CATEGORY(gpugllogging, "hifi.gpu.gl")
|
||||
Q_LOGGING_CATEGORY(trace_render_gpu_gl, "trace.render.gpu.gl")
|
||||
|
||||
namespace gpu { namespace gl {
|
||||
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
#include <QLoggingCategory>
|
||||
|
||||
Q_DECLARE_LOGGING_CATEGORY(gpugllogging)
|
||||
Q_DECLARE_LOGGING_CATEGORY(trace_render_gpu_gl)
|
||||
|
||||
namespace gpu { namespace gl {
|
||||
|
||||
|
|
|
@ -12,7 +12,6 @@
|
|||
|
||||
#include <unordered_set>
|
||||
#include <unordered_map>
|
||||
#include <QtCore/QThread>
|
||||
|
||||
#include "../gl/GLTexelFormat.h"
|
||||
|
||||
|
@ -123,7 +122,7 @@ void GL41Texture::transferMip(uint16_t mipLevel, uint8_t face) const {
|
|||
}
|
||||
|
||||
void GL41Texture::startTransfer() {
|
||||
PROFILE_RANGE(__FUNCTION__);
|
||||
PROFILE_RANGE(render_gpu_gl, __FUNCTION__);
|
||||
Parent::startTransfer();
|
||||
|
||||
glBindTexture(_target, _id);
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
|
||||
#include <QtCore/QDebug>
|
||||
#include <QtCore/QThread>
|
||||
#include <Trace.h>
|
||||
|
||||
#include <NumericalConstants.h>
|
||||
|
||||
|
@ -757,6 +758,9 @@ bool sphericalHarmonicsFromTexture(const gpu::Texture& cubeTexture, std::vector<
|
|||
if(width != cubeTexture.getHeight()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
PROFILE_RANGE(render_gpu, "sphericalHarmonicsFromTexture");
|
||||
|
||||
const uint sqOrder = order*order;
|
||||
|
||||
// allocate memory for calculations
|
||||
|
@ -788,6 +792,7 @@ bool sphericalHarmonicsFromTexture(const gpu::Texture& cubeTexture, std::vector<
|
|||
|
||||
// for each face of cube texture
|
||||
for(int face=0; face < gpu::Texture::NUM_CUBE_FACES; face++) {
|
||||
PROFILE_RANGE(render_gpu, "ProcessFace");
|
||||
|
||||
auto numComponents = cubeTexture.accessStoredMipFace(0,face)->getFormat().getScalarCount();
|
||||
auto data = cubeTexture.accessStoredMipFace(0,face)->readData();
|
||||
|
@ -995,4 +1000,4 @@ Texture::ExternalUpdates Texture::getUpdates() const {
|
|||
_externalUpdates.swap(result);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -21,6 +21,10 @@
|
|||
#include <QThreadPool>
|
||||
|
||||
#include "ModelNetworkingLogging.h"
|
||||
#include <Trace.h>
|
||||
#include <StatTracker.h>
|
||||
|
||||
Q_LOGGING_CATEGORY(trace_resource_parse_geometry, "trace.resource.parse.geometry")
|
||||
|
||||
class GeometryReader;
|
||||
|
||||
|
@ -39,6 +43,8 @@ class GeometryMappingResource : public GeometryResource {
|
|||
public:
|
||||
GeometryMappingResource(const QUrl& url) : GeometryResource(url) {};
|
||||
|
||||
QString getType() const override { return "GeometryMapping"; }
|
||||
|
||||
virtual void downloadFinished(const QByteArray& data) override;
|
||||
|
||||
private slots:
|
||||
|
@ -50,6 +56,9 @@ private:
|
|||
};
|
||||
|
||||
void GeometryMappingResource::downloadFinished(const QByteArray& data) {
|
||||
PROFILE_ASYNC_BEGIN(resource_parse_geometry, "GeometryMappingResource::downloadFinished", _url.toString(),
|
||||
{ { "url", _url.toString() } });
|
||||
|
||||
auto mapping = FSTReader::readMapping(data);
|
||||
|
||||
QString filename = mapping.value("filename").toString();
|
||||
|
@ -113,6 +122,7 @@ void GeometryMappingResource::onGeometryMappingLoaded(bool success) {
|
|||
disconnect(_connection); // FIXME Should not have to do this
|
||||
}
|
||||
|
||||
PROFILE_ASYNC_END(resource_parse_geometry, "GeometryMappingResource::downloadFinished", _url.toString());
|
||||
finishedLoading(success);
|
||||
}
|
||||
|
||||
|
@ -120,8 +130,10 @@ class GeometryReader : public QRunnable {
|
|||
public:
|
||||
GeometryReader(QWeakPointer<Resource>& resource, const QUrl& url, const QVariantHash& mapping,
|
||||
const QByteArray& data) :
|
||||
_resource(resource), _url(url), _mapping(mapping), _data(data) {}
|
||||
virtual ~GeometryReader() = default;
|
||||
_resource(resource), _url(url), _mapping(mapping), _data(data) {
|
||||
|
||||
DependencyManager::get<StatTracker>()->incrementStat("PendingProcessing");
|
||||
}
|
||||
|
||||
virtual void run() override;
|
||||
|
||||
|
@ -133,6 +145,9 @@ private:
|
|||
};
|
||||
|
||||
void GeometryReader::run() {
|
||||
DependencyManager::get<StatTracker>()->decrementStat("PendingProcessing");
|
||||
CounterStat counter("Processing");
|
||||
PROFILE_RANGE_EX(resource_parse_geometry, "GeometryReader::run", 0xFF00FF00, 0, { { "url", _url.toString() } });
|
||||
auto originalPriority = QThread::currentThread()->priority();
|
||||
if (originalPriority == QThread::InheritPriority) {
|
||||
originalPriority = QThread::NormalPriority;
|
||||
|
@ -197,6 +212,8 @@ public:
|
|||
GeometryDefinitionResource(const QUrl& url, const QVariantHash& mapping, const QUrl& textureBaseUrl) :
|
||||
GeometryResource(url, resolveTextureBaseUrl(url, textureBaseUrl)), _mapping(mapping) {}
|
||||
|
||||
QString getType() const override { return "GeometryDefinition"; }
|
||||
|
||||
virtual void downloadFinished(const QByteArray& data) override;
|
||||
|
||||
protected:
|
||||
|
|
|
@ -14,6 +14,9 @@
|
|||
class NetworkShader : public Resource {
|
||||
public:
|
||||
NetworkShader(const QUrl& url);
|
||||
|
||||
QString getType() const override { return "NetworkShader"; }
|
||||
|
||||
virtual void downloadFinished(const QByteArray& data) override;
|
||||
|
||||
QString _source;
|
||||
|
|
|
@ -33,6 +33,10 @@
|
|||
#include <PathUtils.h>
|
||||
|
||||
#include "ModelNetworkingLogging.h"
|
||||
#include <Trace.h>
|
||||
#include <StatTracker.h>
|
||||
|
||||
Q_LOGGING_CATEGORY(trace_resource_parse_image, "trace.resource.parse.image")
|
||||
|
||||
TextureCache::TextureCache() {
|
||||
setUnusedResourceCacheSize(0);
|
||||
|
@ -331,6 +335,7 @@ ImageReader::ImageReader(const QWeakPointer<Resource>& resource, const QByteArra
|
|||
outFile.close();
|
||||
}
|
||||
#endif
|
||||
DependencyManager::get<StatTracker>()->incrementStat("PendingProcessing");
|
||||
}
|
||||
|
||||
void ImageReader::listSupportedImageFormats() {
|
||||
|
@ -342,7 +347,11 @@ void ImageReader::listSupportedImageFormats() {
|
|||
}
|
||||
|
||||
void ImageReader::run() {
|
||||
PROFILE_RANGE_EX(__FUNCTION__, 0xffff0000, nullptr);
|
||||
DependencyManager::get<StatTracker>()->decrementStat("PendingProcessing");
|
||||
|
||||
CounterStat counter("Processing");
|
||||
|
||||
PROFILE_RANGE_EX(resource_parse_image, __FUNCTION__, 0xffff0000, 0, { { "url", _url.toString() } });
|
||||
auto originalPriority = QThread::currentThread()->priority();
|
||||
if (originalPriority == QThread::InheritPriority) {
|
||||
originalPriority = QThread::NormalPriority;
|
||||
|
@ -356,7 +365,6 @@ void ImageReader::run() {
|
|||
qCWarning(modelnetworking) << "Abandoning load of" << _url << "; could not get strong ref";
|
||||
return;
|
||||
}
|
||||
|
||||
listSupportedImageFormats();
|
||||
|
||||
// Help the QImage loader by extracting the image file format from the url filename ext.
|
||||
|
@ -378,7 +386,6 @@ void ImageReader::run() {
|
|||
}
|
||||
return;
|
||||
}
|
||||
|
||||
gpu::TexturePointer texture = nullptr;
|
||||
{
|
||||
// Double-check the resource still exists between long operations.
|
||||
|
@ -390,7 +397,7 @@ void ImageReader::run() {
|
|||
|
||||
auto url = _url.toString().toStdString();
|
||||
|
||||
PROFILE_RANGE_EX(__FUNCTION__"::textureLoader", 0xffffff00, nullptr);
|
||||
PROFILE_RANGE_EX(resource_parse_image, __FUNCTION__, 0xffffff00, 0);
|
||||
texture.reset(resource.dynamicCast<NetworkTexture>()->getTextureLoader()(image, url));
|
||||
}
|
||||
|
||||
|
|
|
@ -63,10 +63,13 @@ public:
|
|||
NetworkTexture(const QUrl& url, Type type, const QByteArray& content);
|
||||
NetworkTexture(const QUrl& url, const TextureLoaderFunc& textureLoader, const QByteArray& content);
|
||||
|
||||
QString getType() const override { return "NetworkTexture"; }
|
||||
|
||||
int getOriginalWidth() const { return _originalWidth; }
|
||||
int getOriginalHeight() const { return _originalHeight; }
|
||||
int getWidth() const { return _width; }
|
||||
int getHeight() const { return _height; }
|
||||
Type getTextureType() const { return _type; }
|
||||
|
||||
TextureLoaderFunc getTextureLoader() const;
|
||||
|
||||
|
|
|
@ -14,6 +14,8 @@
|
|||
#include <QPainter>
|
||||
#include <QDebug>
|
||||
|
||||
#include <Profile.h>
|
||||
|
||||
#include "ModelLogging.h"
|
||||
|
||||
using namespace model;
|
||||
|
@ -744,6 +746,8 @@ const CubeLayout CubeLayout::CUBEMAP_LAYOUTS[] = {
|
|||
const int CubeLayout::NUM_CUBEMAP_LAYOUTS = sizeof(CubeLayout::CUBEMAP_LAYOUTS) / sizeof(CubeLayout);
|
||||
|
||||
gpu::Texture* TextureUsage::processCubeTextureColorFromImage(const QImage& srcImage, const std::string& srcImageName, bool isLinear, bool doCompress, bool generateMips, bool generateIrradiance) {
|
||||
PROFILE_RANGE(resource_parse, "processCubeTextureColorFromImage");
|
||||
|
||||
gpu::Texture* theTexture = nullptr;
|
||||
if ((srcImage.width() > 0) && (srcImage.height() > 0)) {
|
||||
QImage image = processSourceImage(srcImage, true);
|
||||
|
@ -801,11 +805,13 @@ gpu::Texture* TextureUsage::processCubeTextureColorFromImage(const QImage& srcIm
|
|||
}
|
||||
|
||||
if (generateMips) {
|
||||
PROFILE_RANGE(resource_parse, "generateMips");
|
||||
theTexture->autoGenerateMips(-1);
|
||||
}
|
||||
|
||||
// Generate irradiance while we are at it
|
||||
if (generateIrradiance) {
|
||||
PROFILE_RANGE(resource_parse, "generateIrradiance");
|
||||
theTexture->generateIrradiance();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,6 +17,7 @@ find_package(TBB REQUIRED)
|
|||
|
||||
if (APPLE)
|
||||
find_library(FRAMEWORK_IOKIT IOKit)
|
||||
find_library(CORE_FOUNDATION CoreFoundation)
|
||||
endif ()
|
||||
|
||||
if (APPLE AND ${OPENSSL_INCLUDE_DIR} STREQUAL "/usr/include")
|
||||
|
@ -32,7 +33,7 @@ target_link_libraries(${TARGET_NAME} ${OPENSSL_LIBRARIES} ${TBB_LIBRARIES})
|
|||
|
||||
# IOKit is needed for getting machine fingerprint
|
||||
if (APPLE)
|
||||
target_link_libraries(${TARGET_NAME} ${FRAMEWORK_IOKIT})
|
||||
target_link_libraries(${TARGET_NAME} ${FRAMEWORK_IOKIT} ${CORE_FOUNDATION})
|
||||
endif (APPLE)
|
||||
|
||||
# libcrypto uses dlopen in libdl
|
||||
|
|
|
@ -604,7 +604,7 @@ bool AssetClient::cancelGetAssetRequest(MessageID id) {
|
|||
for (auto& kv : _pendingRequests) {
|
||||
auto& messageCallbackMap = kv.second;
|
||||
auto requestIt = messageCallbackMap.find(id);
|
||||
if (requestIt != kv.second.end()) {
|
||||
if (requestIt != messageCallbackMap.end()) {
|
||||
|
||||
auto& message = requestIt->second.message;
|
||||
if (message) {
|
||||
|
|
|
@ -19,8 +19,12 @@
|
|||
#include "NetworkLogging.h"
|
||||
#include "NodeList.h"
|
||||
#include "ResourceCache.h"
|
||||
#include <Trace.h>
|
||||
|
||||
static int requestID = 0;
|
||||
|
||||
AssetRequest::AssetRequest(const QString& hash) :
|
||||
_requestID(++requestID),
|
||||
_hash(hash)
|
||||
{
|
||||
}
|
||||
|
|
|
@ -56,6 +56,7 @@ signals:
|
|||
void progress(qint64 totalReceived, qint64 total);
|
||||
|
||||
private:
|
||||
int _requestID;
|
||||
State _state = NotStarted;
|
||||
Error _error = NoError;
|
||||
AssetInfo _info;
|
||||
|
|
|
@ -17,6 +17,8 @@
|
|||
#include "AssetUtils.h"
|
||||
#include "MappingRequest.h"
|
||||
#include "NetworkLogging.h"
|
||||
#include <Trace.h>
|
||||
#include <Profile.h>
|
||||
|
||||
static const int DOWNLOAD_PROGRESS_LOG_INTERVAL_SECONDS = 5;
|
||||
|
||||
|
@ -27,12 +29,14 @@ AssetResourceRequest::AssetResourceRequest(const QUrl& url) :
|
|||
}
|
||||
|
||||
AssetResourceRequest::~AssetResourceRequest() {
|
||||
if (_assetMappingRequest) {
|
||||
_assetMappingRequest->deleteLater();
|
||||
}
|
||||
|
||||
if (_assetRequest) {
|
||||
_assetRequest->deleteLater();
|
||||
if (_assetRequest || _assetMappingRequest) {
|
||||
if (_assetMappingRequest) {
|
||||
_assetMappingRequest->deleteLater();
|
||||
}
|
||||
|
||||
if (_assetRequest) {
|
||||
_assetRequest->deleteLater();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -108,7 +112,6 @@ void AssetResourceRequest::requestMappingForPath(const AssetPath& path) {
|
|||
}
|
||||
|
||||
void AssetResourceRequest::requestHash(const AssetHash& hash) {
|
||||
|
||||
// Make request to atp
|
||||
auto assetClient = DependencyManager::get<AssetClient>();
|
||||
_assetRequest = assetClient->createRequest(hash);
|
||||
|
@ -118,7 +121,7 @@ void AssetResourceRequest::requestHash(const AssetHash& hash) {
|
|||
Q_ASSERT(_state == InProgress);
|
||||
Q_ASSERT(req == _assetRequest);
|
||||
Q_ASSERT(req->getState() == AssetRequest::Finished);
|
||||
|
||||
|
||||
switch (req->getError()) {
|
||||
case AssetRequest::Error::NoError:
|
||||
_data = req->getData();
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
#include <BuildInfo.h>
|
||||
#include "Assignment.h"
|
||||
#include <QtCore/QStandardPaths>
|
||||
#include <QtCore/QDir>
|
||||
|
||||
Assignment::Type Assignment::typeForNodeType(NodeType_t nodeType) {
|
||||
switch (nodeType) {
|
||||
|
@ -51,7 +52,7 @@ Assignment::Assignment() :
|
|||
|
||||
}
|
||||
|
||||
Assignment::Assignment(Assignment::Command command, Assignment::Type type, const QString& pool, Assignment::Location location) :
|
||||
Assignment::Assignment(Assignment::Command command, Assignment::Type type, const QString& pool, Assignment::Location location, QString dataDirectory) :
|
||||
_uuid(),
|
||||
_command(command),
|
||||
_type(type),
|
||||
|
@ -60,7 +61,8 @@ Assignment::Assignment(Assignment::Command command, Assignment::Type type, const
|
|||
_payload(),
|
||||
_isStatic(false),
|
||||
_walletUUID(),
|
||||
_nodeVersion()
|
||||
_nodeVersion(),
|
||||
_dataDirectory(dataDirectory)
|
||||
{
|
||||
if (_command == Assignment::CreateCommand) {
|
||||
// this is a newly created assignment, generate a random UUID
|
||||
|
|
|
@ -55,7 +55,8 @@ public:
|
|||
Assignment(Assignment::Command command,
|
||||
Assignment::Type type,
|
||||
const QString& pool = emptyPool,
|
||||
Assignment::Location location = Assignment::LocalLocation);
|
||||
Assignment::Location location = Assignment::LocalLocation,
|
||||
QString dataDirectory = QString());
|
||||
Assignment(const Assignment& otherAssignment);
|
||||
Assignment& operator=(const Assignment &rhsAssignment);
|
||||
|
||||
|
@ -103,6 +104,7 @@ protected:
|
|||
bool _isStatic; /// defines if this assignment needs to be re-queued in the domain-server if it stops being fulfilled
|
||||
QUuid _walletUUID; /// the UUID for the wallet that should be paid for this assignment
|
||||
QString _nodeVersion;
|
||||
QString _dataDirectory;
|
||||
};
|
||||
|
||||
uint qHash(const Assignment::Type& key, uint seed);
|
||||
|
|
|
@ -10,8 +10,13 @@
|
|||
//
|
||||
|
||||
#include "FingerprintUtils.h"
|
||||
|
||||
#include <QDebug>
|
||||
|
||||
#include <SettingHandle.h>
|
||||
#include <SettingManager.h>
|
||||
#include <DependencyManager.h>
|
||||
|
||||
#ifdef Q_OS_WIN
|
||||
#include <comdef.h>
|
||||
#include <Wbemidl.h>
|
||||
|
@ -44,7 +49,15 @@ QString FingerprintUtils::getMachineFingerprintString() {
|
|||
HRESULT hres;
|
||||
IWbemLocator *pLoc = NULL;
|
||||
|
||||
// initialize com
|
||||
// initialize com. Interface already does, but other
|
||||
// users of this lib don't necessarily do so.
|
||||
hres = CoInitializeEx(0, COINIT_MULTITHREADED);
|
||||
if (FAILED(hres)) {
|
||||
qDebug() << "Failed to initialize COM library!";
|
||||
return uuidString;
|
||||
}
|
||||
|
||||
// initialize WbemLocator
|
||||
hres = CoCreateInstance(
|
||||
CLSID_WbemLocator,
|
||||
0,
|
||||
|
@ -164,6 +177,11 @@ QUuid FingerprintUtils::getMachineFingerprint() {
|
|||
// any errors in getting the string
|
||||
QUuid uuid(uuidString);
|
||||
if (uuid == QUuid()) {
|
||||
// if you cannot read a fallback key cuz we aren't saving them, just generate one for
|
||||
// this session and move on
|
||||
if (DependencyManager::get<Setting::Manager>().isNull()) {
|
||||
return QUuid::createUuid();
|
||||
}
|
||||
// read fallback key (if any)
|
||||
Settings settings;
|
||||
uuid = QUuid(settings.value(FALLBACK_FINGERPRINT_KEY).toString());
|
||||
|
|
|
@ -109,6 +109,10 @@ void HifiSockAddr::handleLookupResult(const QHostInfo& hostInfo) {
|
|||
}
|
||||
}
|
||||
|
||||
QString HifiSockAddr::toString() const {
|
||||
return _address.toString() + ":" + QString::number(_port);
|
||||
}
|
||||
|
||||
QDebug operator<<(QDebug debug, const HifiSockAddr& sockAddr) {
|
||||
debug.nospace() << sockAddr._address.toString().toLocal8Bit().constData() << ":" << sockAddr._port;
|
||||
return debug.space();
|
||||
|
|
|
@ -53,6 +53,8 @@ public:
|
|||
static int packSockAddr(unsigned char* packetData, const HifiSockAddr& packSockAddr);
|
||||
static int unpackSockAddr(const unsigned char* packetData, HifiSockAddr& unpackDestSockAddr);
|
||||
|
||||
QString toString() const;
|
||||
|
||||
friend QDebug operator<<(QDebug debug, const HifiSockAddr& sockAddr);
|
||||
friend QDataStream& operator<<(QDataStream& dataStream, const HifiSockAddr& sockAddr);
|
||||
friend QDataStream& operator>>(QDataStream& dataStream, HifiSockAddr& sockAddr);
|
||||
|
|
|
@ -37,6 +37,7 @@
|
|||
#include "HifiSockAddr.h"
|
||||
#include "NetworkLogging.h"
|
||||
#include "udt/Packet.h"
|
||||
#include <Trace.h>
|
||||
|
||||
static Setting::Handle<quint16> LIMITED_NODELIST_LOCAL_PORT("LimitedNodeList.LocalPort", 0);
|
||||
|
||||
|
@ -1116,7 +1117,6 @@ void LimitedNodeList::flagTimeForConnectionStep(ConnectionStep connectionStep) {
|
|||
}
|
||||
|
||||
void LimitedNodeList::flagTimeForConnectionStep(ConnectionStep connectionStep, quint64 timestamp) {
|
||||
|
||||
if (connectionStep == ConnectionStep::LookupAddress) {
|
||||
QWriteLocker writeLock(&_connectionTimeLock);
|
||||
|
||||
|
|
|
@ -103,8 +103,7 @@ public:
|
|||
ReceiveFirstAudioPacket
|
||||
};
|
||||
|
||||
Q_ENUMS(ConnectionStep);
|
||||
|
||||
Q_ENUM(ConnectionStep);
|
||||
const QUuid& getSessionUUID() const { return _sessionUUID; }
|
||||
void setSessionUUID(const QUuid& sessionUUID);
|
||||
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue