Merge branch 'master' into bug/5950

This commit is contained in:
utkarshgautamnyu 2017-07-06 12:52:13 -07:00 committed by GitHub
commit d5c88bc6de
178 changed files with 5247 additions and 2289 deletions

View file

@ -16,6 +16,7 @@
#include <QThread> #include <QThread>
#include <QTimer> #include <QTimer>
#include <shared/QtHelpers.h>
#include <AccountManager.h> #include <AccountManager.h>
#include <AddressManager.h> #include <AddressManager.h>
#include <Assignment.h> #include <Assignment.h>
@ -141,7 +142,7 @@ void AssignmentClient::stopAssignmentClient() {
QThread* currentAssignmentThread = _currentAssignment->thread(); QThread* currentAssignmentThread = _currentAssignment->thread();
// ask the current assignment to stop // ask the current assignment to stop
QMetaObject::invokeMethod(_currentAssignment, "stop", Qt::BlockingQueuedConnection); BLOCKING_INVOKE_METHOD(_currentAssignment, "stop");
// ask the current assignment to delete itself on its thread // ask the current assignment to delete itself on its thread
_currentAssignment->deleteLater(); _currentAssignment->deleteLater();

View file

@ -9,8 +9,12 @@
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
// //
#include <QCommandLineParser> #include "AssignmentClientApp.h"
#include <QThread>
#include <QtCore/QCommandLineParser>
#include <QtCore/QDir>
#include <QtCore/QStandardPaths>
#include <QtCore/QThread>
#include <LogHandler.h> #include <LogHandler.h>
#include <SharedUtil.h> #include <SharedUtil.h>
@ -20,10 +24,6 @@
#include "Assignment.h" #include "Assignment.h"
#include "AssignmentClient.h" #include "AssignmentClient.h"
#include "AssignmentClientMonitor.h" #include "AssignmentClientMonitor.h"
#include "AssignmentClientApp.h"
#include <QtCore/QDir>
#include <QtCore/QStandardPaths>
AssignmentClientApp::AssignmentClientApp(int argc, char* argv[]) : AssignmentClientApp::AssignmentClientApp(int argc, char* argv[]) :
QCoreApplication(argc, argv) QCoreApplication(argc, argv)
@ -87,6 +87,9 @@ AssignmentClientApp::AssignmentClientApp(int argc, char* argv[]) :
const QCommandLineOption logDirectoryOption(ASSIGNMENT_LOG_DIRECTORY, "directory to store logs", "log-directory"); const QCommandLineOption logDirectoryOption(ASSIGNMENT_LOG_DIRECTORY, "directory to store logs", "log-directory");
parser.addOption(logDirectoryOption); parser.addOption(logDirectoryOption);
const QCommandLineOption parentPIDOption(PARENT_PID_OPTION, "PID of the parent process", "parent-pid");
parser.addOption(parentPIDOption);
if (!parser.parse(QCoreApplication::arguments())) { if (!parser.parse(QCoreApplication::arguments())) {
qCritical() << parser.errorText() << endl; qCritical() << parser.errorText() << endl;
parser.showHelp(); parser.showHelp();
@ -203,6 +206,16 @@ AssignmentClientApp::AssignmentClientApp(int argc, char* argv[]) :
} }
} }
if (parser.isSet(parentPIDOption)) {
bool ok = false;
int parentPID = parser.value(parentPIDOption).toInt(&ok);
if (ok) {
qDebug() << "Parent process PID is" << parentPID;
watchParentProcess(parentPID);
}
}
QThread::currentThread()->setObjectName("main thread"); QThread::currentThread()->setObjectName("main thread");
DependencyManager::registerInheritance<LimitedNodeList, NodeList>(); DependencyManager::registerInheritance<LimitedNodeList, NodeList>();

View file

@ -131,7 +131,6 @@ void AssignmentClientMonitor::aboutToQuit() {
void AssignmentClientMonitor::spawnChildClient() { void AssignmentClientMonitor::spawnChildClient() {
QProcess* assignmentClient = new QProcess(this); QProcess* assignmentClient = new QProcess(this);
// unparse the parts of the command-line that the child cares about // unparse the parts of the command-line that the child cares about
QStringList _childArguments; QStringList _childArguments;
if (_assignmentPool != "") { if (_assignmentPool != "") {
@ -160,6 +159,9 @@ void AssignmentClientMonitor::spawnChildClient() {
_childArguments.append("--" + ASSIGNMENT_CLIENT_MONITOR_PORT_OPTION); _childArguments.append("--" + ASSIGNMENT_CLIENT_MONITOR_PORT_OPTION);
_childArguments.append(QString::number(DependencyManager::get<NodeList>()->getLocalSockAddr().getPort())); _childArguments.append(QString::number(DependencyManager::get<NodeList>()->getLocalSockAddr().getPort()));
_childArguments.append("--" + PARENT_PID_OPTION);
_childArguments.append(QString::number(QCoreApplication::applicationPid()));
QString nowString, stdoutFilenameTemp, stderrFilenameTemp, stdoutPathTemp, stderrPathTemp; QString nowString, stdoutFilenameTemp, stderrFilenameTemp, stdoutPathTemp, stderrPathTemp;

View file

@ -285,6 +285,13 @@ void AvatarMixer::start() {
// is guaranteed to not be accessed by other thread // is guaranteed to not be accessed by other thread
void AvatarMixer::manageIdentityData(const SharedNodePointer& node) { void AvatarMixer::manageIdentityData(const SharedNodePointer& node) {
AvatarMixerClientData* nodeData = reinterpret_cast<AvatarMixerClientData*>(node->getLinkedData()); AvatarMixerClientData* nodeData = reinterpret_cast<AvatarMixerClientData*>(node->getLinkedData());
// there is no need to manage identity data we haven't received yet
// so bail early if we've never received an identity packet for this avatar
if (!nodeData || !nodeData->getAvatar().hasProcessedFirstIdentity()) {
return;
}
bool sendIdentity = false; bool sendIdentity = false;
if (nodeData && nodeData->getAvatarSessionDisplayNameMustChange()) { if (nodeData && nodeData->getAvatarSessionDisplayNameMustChange()) {
AvatarData& avatar = nodeData->getAvatar(); AvatarData& avatar = nodeData->getAvatar();

View file

@ -320,14 +320,18 @@ void AvatarMixerSlave::broadcastAvatarDataToAgent(const SharedNodePointer& node)
++numOtherAvatars; ++numOtherAvatars;
const AvatarMixerClientData* otherNodeData = reinterpret_cast<const AvatarMixerClientData*>(otherNode->getLinkedData()); const AvatarMixerClientData* otherNodeData = reinterpret_cast<const AvatarMixerClientData*>(otherNode->getLinkedData());
const AvatarData* otherAvatar = otherNodeData->getConstAvatarData();
// If the time that the mixer sent AVATAR DATA about Avatar B to Avatar A is BEFORE OR EQUAL TO // If the time that the mixer sent AVATAR DATA about Avatar B to Avatar A is BEFORE OR EQUAL TO
// the time that Avatar B flagged an IDENTITY DATA change, send IDENTITY DATA about Avatar B to Avatar A. // the time that Avatar B flagged an IDENTITY DATA change, send IDENTITY DATA about Avatar B to Avatar A.
if (nodeData->getLastBroadcastTime(otherNode->getUUID()) <= otherNodeData->getIdentityChangeTimestamp()) { if (otherAvatar->hasProcessedFirstIdentity()
&& nodeData->getLastBroadcastTime(otherNode->getUUID()) <= otherNodeData->getIdentityChangeTimestamp()) {
identityBytesSent += sendIdentityPacket(otherNodeData, node); identityBytesSent += sendIdentityPacket(otherNodeData, node);
// remember the last time we sent identity details about this other node to the receiver
nodeData->setLastBroadcastTime(otherNode->getUUID(), usecTimestampNow());
} }
const AvatarData* otherAvatar = otherNodeData->getConstAvatarData();
glm::vec3 otherPosition = otherAvatar->getClientGlobalPosition(); glm::vec3 otherPosition = otherAvatar->getClientGlobalPosition();
// determine if avatar is in view, to determine how much data to include... // determine if avatar is in view, to determine how much data to include...
@ -400,9 +404,6 @@ void AvatarMixerSlave::broadcastAvatarDataToAgent(const SharedNodePointer& node)
// set the last sent sequence number for this sender on the receiver // set the last sent sequence number for this sender on the receiver
nodeData->setLastBroadcastSequenceNumber(otherNode->getUUID(), nodeData->setLastBroadcastSequenceNumber(otherNode->getUUID(),
otherNodeData->getLastReceivedSequenceNumber()); otherNodeData->getLastReceivedSequenceNumber());
// remember the last time we sent details about this other node to the receiver
nodeData->setLastBroadcastTime(otherNode->getUUID(), start);
} }
} }

View file

@ -13,6 +13,7 @@
#include <QThread> #include <QThread>
#include <glm/gtx/transform.hpp> #include <glm/gtx/transform.hpp>
#include <shared/QtHelpers.h>
#include <GLMHelpers.h> #include <GLMHelpers.h>
#include <AnimUtil.h> #include <AnimUtil.h>
#include "ScriptableAvatar.h" #include "ScriptableAvatar.h"
@ -49,7 +50,7 @@ void ScriptableAvatar::stopAnimation() {
AnimationDetails ScriptableAvatar::getAnimationDetails() { AnimationDetails ScriptableAvatar::getAnimationDetails() {
if (QThread::currentThread() != thread()) { if (QThread::currentThread() != thread()) {
AnimationDetails result; AnimationDetails result;
QMetaObject::invokeMethod(this, "getAnimationDetails", Qt::BlockingQueuedConnection, BLOCKING_INVOKE_METHOD(this, "getAnimationDetails",
Q_RETURN_ARG(AnimationDetails, result)); Q_RETURN_ARG(AnimationDetails, result));
return result; return result;
} }

View file

@ -0,0 +1,12 @@
#
# Created by David Rowe on 16 Jun 2017.
# Copyright 2017 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
#
macro(TARGET_LEAPMOTION)
target_include_directories(${TARGET_NAME} PRIVATE ${LEAPMOTION_INCLUDE_DIRS})
target_link_libraries(${TARGET_NAME} ${LEAPMOTION_LIBRARIES})
endmacro()

View file

@ -56,19 +56,17 @@ elseif (${CMAKE_CXX_COMPILER_ID} MATCHES "GNU")
endif() endif()
function(_fbx_find_library _name _lib _suffix) function(_fbx_find_library _name _lib _suffix)
if (MSVC12) if (MSVC_VERSION EQUAL 1910)
set(VS_PREFIX vs2017)
elseif (MSVC_VERSION EQUAL 1900)
set(VS_PREFIX vs2015)
elseif (MSVC_VERSION EQUAL 1800)
set(VS_PREFIX vs2013) set(VS_PREFIX vs2013)
endif() elseif (MSVC_VERSION EQUAL 1700)
if (MSVC11)
set(VS_PREFIX vs2012) set(VS_PREFIX vs2012)
endif() elseif (MSVC_VERSION EQUAL 1600)
if (MSVC10)
set(VS_PREFIX vs2010) set(VS_PREFIX vs2010)
endif() elseif (MSVC_VERSION EQUAL 1500)
if (MSVC90)
set(VS_PREFIX vs2008) set(VS_PREFIX vs2008)
endif() endif()

View file

@ -76,6 +76,7 @@
{ {
"name": "descriptors", "name": "descriptors",
"label": "Description", "label": "Description",
"restart": false,
"help": "This data will be queryable from your server. It may be collected by High Fidelity and used to share your domain with others.", "help": "This data will be queryable from your server. It may be collected by High Fidelity and used to share your domain with others.",
"settings": [ "settings": [
{ {

View file

@ -162,8 +162,10 @@ DomainServer::DomainServer(int argc, char* argv[]) :
_gatekeeper.preloadAllowedUserPublicKeys(); // so they can connect on first request _gatekeeper.preloadAllowedUserPublicKeys(); // so they can connect on first request
//send signal to DomainMetadata when descriptors changed
_metadata = new DomainMetadata(this); _metadata = new DomainMetadata(this);
connect(&_settingsManager, &DomainServerSettingsManager::settingsUpdated,
_metadata, &DomainMetadata::descriptorsChanged);
qDebug() << "domain-server is running"; qDebug() << "domain-server is running";
static const QString AC_SUBNET_WHITELIST_SETTING_PATH = "security.ac_subnet_whitelist"; static const QString AC_SUBNET_WHITELIST_SETTING_PATH = "security.ac_subnet_whitelist";
@ -221,6 +223,8 @@ void DomainServer::parseCommandLine() {
const QCommandLineOption masterConfigOption("master-config", "Deprecated config-file option"); const QCommandLineOption masterConfigOption("master-config", "Deprecated config-file option");
parser.addOption(masterConfigOption); parser.addOption(masterConfigOption);
const QCommandLineOption parentPIDOption(PARENT_PID_OPTION, "PID of the parent process", "parent-pid");
parser.addOption(parentPIDOption);
if (!parser.parse(QCoreApplication::arguments())) { if (!parser.parse(QCoreApplication::arguments())) {
qWarning() << parser.errorText() << endl; qWarning() << parser.errorText() << endl;
@ -249,6 +253,17 @@ void DomainServer::parseCommandLine() {
_overrideDomainID = true; _overrideDomainID = true;
qDebug() << "domain-server ID is" << _overridingDomainID; qDebug() << "domain-server ID is" << _overridingDomainID;
} }
if (parser.isSet(parentPIDOption)) {
bool ok = false;
int parentPID = parser.value(parentPIDOption).toInt(&ok);
if (ok) {
qDebug() << "Parent process PID is" << parentPID;
watchParentProcess(parentPID);
}
}
} }
DomainServer::~DomainServer() { DomainServer::~DomainServer() {

View file

@ -1198,7 +1198,8 @@ bool DomainServerSettingsManager::recurseJSONObjectAndOverwriteSettings(const QJ
static const QString SECURITY_ROOT_KEY = "security"; static const QString SECURITY_ROOT_KEY = "security";
static const QString AC_SUBNET_WHITELIST_KEY = "ac_subnet_whitelist"; static const QString AC_SUBNET_WHITELIST_KEY = "ac_subnet_whitelist";
static const QString BROADCASTING_KEY = "broadcasting"; static const QString BROADCASTING_KEY = "broadcasting";
static const QString DESCRIPTION_ROOT_KEY = "descriptors";
auto& settingsVariant = _configMap.getConfig(); auto& settingsVariant = _configMap.getConfig();
bool needRestart = false; bool needRestart = false;
@ -1265,7 +1266,7 @@ bool DomainServerSettingsManager::recurseJSONObjectAndOverwriteSettings(const QJ
if (!matchingDescriptionObject.isEmpty()) { if (!matchingDescriptionObject.isEmpty()) {
const QJsonValue& settingValue = rootValue.toObject()[settingKey]; const QJsonValue& settingValue = rootValue.toObject()[settingKey];
updateSetting(settingKey, settingValue, *thisMap, matchingDescriptionObject); updateSetting(settingKey, settingValue, *thisMap, matchingDescriptionObject);
if ((rootKey != SECURITY_ROOT_KEY && rootKey != BROADCASTING_KEY) if ((rootKey != SECURITY_ROOT_KEY && rootKey != BROADCASTING_KEY && rootKey != DESCRIPTION_ROOT_KEY)
|| settingKey == AC_SUBNET_WHITELIST_KEY) { || settingKey == AC_SUBNET_WHITELIST_KEY) {
needRestart = true; needRestart = true;
} }

View file

@ -63,10 +63,7 @@ void RenderingClient::sendAvatarPacket() {
} }
void RenderingClient::cleanupBeforeQuit() { void RenderingClient::cleanupBeforeQuit() {
DependencyManager::get<AudioClient>()->cleanupBeforeQuit();
QMetaObject::invokeMethod(DependencyManager::get<AudioClient>().data(),
"stop", Qt::BlockingQueuedConnection);
// destroy the AudioClient so it and its thread will safely go down // destroy the AudioClient so it and its thread will safely go down
DependencyManager::destroy<AudioClient>(); DependencyManager::destroy<AudioClient>();
} }

View file

@ -10,7 +10,7 @@ Interface has been tested with SDK versions:
1. Copy the LeapSDK folders from the LeapDeveloperKit installation directory (Lib, Include) into the interface/externals/leapmotion folder. 1. Copy the LeapSDK folders from the LeapDeveloperKit installation directory (Lib, Include) into the interface/externals/leapmotion folder.
This readme.txt should be there as well. This readme.txt should be there as well.
The files neeeded in the folders are: The files needed in the folders are:
include/ include/
- Leap.h - Leap.h
@ -21,8 +21,8 @@ Interface has been tested with SDK versions:
x86/ x86/
- Leap.dll - Leap.dll
- Leap.lib - Leap.lib
- mscvcp120.dll (optional if you already have the Msdev 2012 SDK redistriuable installed) - mscvcp120.dll (optional if you already have the Msdev 2012 SDK redistributable installed)
- mscvcr120.dll (optional if you already have the Msdev 2012 SDK redistriuable installed) - mscvcr120.dll (optional if you already have the Msdev 2012 SDK redistributable installed)
- lipLeap.dylib - lipLeap.dylib
libc++/ libc++/
-libLeap.dylib -libLeap.dylib
@ -30,4 +30,4 @@ Interface has been tested with SDK versions:
You may optionally choose to copy the SDK folders to a location outside the repository (so you can re-use with different checkouts and different projects). You may optionally choose to copy the SDK folders to a location outside the repository (so you can re-use with different checkouts and different projects).
If so our CMake find module expects you to set the ENV variable 'HIFI_LIB_DIR' to a directory containing a subfolder 'leapmotion' that contains the 2 folders mentioned above (Include, Lib). If so our CMake find module expects you to set the ENV variable 'HIFI_LIB_DIR' to a directory containing a subfolder 'leapmotion' that contains the 2 folders mentioned above (Include, Lib).
2. Clear your build directory, run cmake and build, and you should be all set. 2. Clear your build directory, run cmake and build, and you should be all set.

View file

@ -0,0 +1,48 @@
{
"name": "Leap Motion to Standard",
"channels": [
{ "from": "LeapMotion.LeftHand", "to": "Standard.LeftHand" },
{ "from": "LeapMotion.LeftHandThumb1", "to": "Standard.LeftHandThumb1"},
{ "from": "LeapMotion.LeftHandThumb2", "to": "Standard.LeftHandThumb2"},
{ "from": "LeapMotion.LeftHandThumb3", "to": "Standard.LeftHandThumb3"},
{ "from": "LeapMotion.LeftHandThumb4", "to": "Standard.LeftHandThumb4"},
{ "from": "LeapMotion.LeftHandIndex1", "to": "Standard.LeftHandIndex1"},
{ "from": "LeapMotion.LeftHandIndex2", "to": "Standard.LeftHandIndex2"},
{ "from": "LeapMotion.LeftHandIndex3", "to": "Standard.LeftHandIndex3"},
{ "from": "LeapMotion.LeftHandIndex4", "to": "Standard.LeftHandIndex4"},
{ "from": "LeapMotion.LeftHandMiddle1", "to": "Standard.LeftHandMiddle1"},
{ "from": "LeapMotion.LeftHandMiddle2", "to": "Standard.LeftHandMiddle2"},
{ "from": "LeapMotion.LeftHandMiddle3", "to": "Standard.LeftHandMiddle3"},
{ "from": "LeapMotion.LeftHandMiddle4", "to": "Standard.LeftHandMiddle4"},
{ "from": "LeapMotion.LeftHandRing1", "to": "Standard.LeftHandRing1"},
{ "from": "LeapMotion.LeftHandRing2", "to": "Standard.LeftHandRing2"},
{ "from": "LeapMotion.LeftHandRing3", "to": "Standard.LeftHandRing3"},
{ "from": "LeapMotion.LeftHandRing4", "to": "Standard.LeftHandRing4"},
{ "from": "LeapMotion.LeftHandPinky1", "to": "Standard.LeftHandPinky1"},
{ "from": "LeapMotion.LeftHandPinky2", "to": "Standard.LeftHandPinky2"},
{ "from": "LeapMotion.LeftHandPinky3", "to": "Standard.LeftHandPinky3"},
{ "from": "LeapMotion.LeftHandPinky4", "to": "Standard.LeftHandPinky4"},
{ "from": "LeapMotion.RightHand", "to": "Standard.RightHand" },
{ "from": "LeapMotion.RightHandThumb1", "to": "Standard.RightHandThumb1"},
{ "from": "LeapMotion.RightHandThumb2", "to": "Standard.RightHandThumb2"},
{ "from": "LeapMotion.RightHandThumb3", "to": "Standard.RightHandThumb3"},
{ "from": "LeapMotion.RightHandThumb4", "to": "Standard.RightHandThumb4"},
{ "from": "LeapMotion.RightHandIndex1", "to": "Standard.RightHandIndex1"},
{ "from": "LeapMotion.RightHandIndex2", "to": "Standard.RightHandIndex2"},
{ "from": "LeapMotion.RightHandIndex3", "to": "Standard.RightHandIndex3"},
{ "from": "LeapMotion.RightHandIndex4", "to": "Standard.RightHandIndex4"},
{ "from": "LeapMotion.RightHandMiddle1", "to": "Standard.RightHandMiddle1"},
{ "from": "LeapMotion.RightHandMiddle2", "to": "Standard.RightHandMiddle2"},
{ "from": "LeapMotion.RightHandMiddle3", "to": "Standard.RightHandMiddle3"},
{ "from": "LeapMotion.RightHandMiddle4", "to": "Standard.RightHandMiddle4"},
{ "from": "LeapMotion.RightHandRing1", "to": "Standard.RightHandRing1"},
{ "from": "LeapMotion.RightHandRing2", "to": "Standard.RightHandRing2"},
{ "from": "LeapMotion.RightHandRing3", "to": "Standard.RightHandRing3"},
{ "from": "LeapMotion.RightHandRing4", "to": "Standard.RightHandRing4"},
{ "from": "LeapMotion.RightHandPinky1", "to": "Standard.RightHandPinky1"},
{ "from": "LeapMotion.RightHandPinky2", "to": "Standard.RightHandPinky2"},
{ "from": "LeapMotion.RightHandPinky3", "to": "Standard.RightHandPinky3"},
{ "from": "LeapMotion.RightHandPinky4", "to": "Standard.RightHandPinky4"}
]
}

View file

@ -58,7 +58,48 @@
{ "from": "Standard.RT", "to": "Actions.RightHandClick" }, { "from": "Standard.RT", "to": "Actions.RightHandClick" },
{ "from": "Standard.LeftHand", "to": "Actions.LeftHand" }, { "from": "Standard.LeftHand", "to": "Actions.LeftHand" },
{ "from": "Standard.LeftHandThumb1", "to": "Actions.LeftHandThumb1"},
{ "from": "Standard.LeftHandThumb2", "to": "Actions.LeftHandThumb2"},
{ "from": "Standard.LeftHandThumb3", "to": "Actions.LeftHandThumb3"},
{ "from": "Standard.LeftHandThumb4", "to": "Actions.LeftHandThumb4"},
{ "from": "Standard.LeftHandIndex1", "to": "Actions.LeftHandIndex1"},
{ "from": "Standard.LeftHandIndex2", "to": "Actions.LeftHandIndex2"},
{ "from": "Standard.LeftHandIndex3", "to": "Actions.LeftHandIndex3"},
{ "from": "Standard.LeftHandIndex4", "to": "Actions.LeftHandIndex4"},
{ "from": "Standard.LeftHandMiddle1", "to": "Actions.LeftHandMiddle1"},
{ "from": "Standard.LeftHandMiddle2", "to": "Actions.LeftHandMiddle2"},
{ "from": "Standard.LeftHandMiddle3", "to": "Actions.LeftHandMiddle3"},
{ "from": "Standard.LeftHandMiddle4", "to": "Actions.LeftHandMiddle4"},
{ "from": "Standard.LeftHandRing1", "to": "Actions.LeftHandRing1"},
{ "from": "Standard.LeftHandRing2", "to": "Actions.LeftHandRing2"},
{ "from": "Standard.LeftHandRing3", "to": "Actions.LeftHandRing3"},
{ "from": "Standard.LeftHandRing4", "to": "Actions.LeftHandRing4"},
{ "from": "Standard.LeftHandPinky1", "to": "Actions.LeftHandPinky1"},
{ "from": "Standard.LeftHandPinky2", "to": "Actions.LeftHandPinky2"},
{ "from": "Standard.LeftHandPinky3", "to": "Actions.LeftHandPinky3"},
{ "from": "Standard.LeftHandPinky4", "to": "Actions.LeftHandPinky4"},
{ "from": "Standard.RightHand", "to": "Actions.RightHand" }, { "from": "Standard.RightHand", "to": "Actions.RightHand" },
{ "from": "Standard.RightHandThumb1", "to": "Actions.RightHandThumb1"},
{ "from": "Standard.RightHandThumb2", "to": "Actions.RightHandThumb2"},
{ "from": "Standard.RightHandThumb3", "to": "Actions.RightHandThumb3"},
{ "from": "Standard.RightHandThumb4", "to": "Actions.RightHandThumb4"},
{ "from": "Standard.RightHandIndex1", "to": "Actions.RightHandIndex1"},
{ "from": "Standard.RightHandIndex2", "to": "Actions.RightHandIndex2"},
{ "from": "Standard.RightHandIndex3", "to": "Actions.RightHandIndex3"},
{ "from": "Standard.RightHandIndex4", "to": "Actions.RightHandIndex4"},
{ "from": "Standard.RightHandMiddle1", "to": "Actions.RightHandMiddle1"},
{ "from": "Standard.RightHandMiddle2", "to": "Actions.RightHandMiddle2"},
{ "from": "Standard.RightHandMiddle3", "to": "Actions.RightHandMiddle3"},
{ "from": "Standard.RightHandMiddle4", "to": "Actions.RightHandMiddle4"},
{ "from": "Standard.RightHandRing1", "to": "Actions.RightHandRing1"},
{ "from": "Standard.RightHandRing2", "to": "Actions.RightHandRing2"},
{ "from": "Standard.RightHandRing3", "to": "Actions.RightHandRing3"},
{ "from": "Standard.RightHandRing4", "to": "Actions.RightHandRing4"},
{ "from": "Standard.RightHandPinky1", "to": "Actions.RightHandPinky1"},
{ "from": "Standard.RightHandPinky2", "to": "Actions.RightHandPinky2"},
{ "from": "Standard.RightHandPinky3", "to": "Actions.RightHandPinky3"},
{ "from": "Standard.RightHandPinky4", "to": "Actions.RightHandPinky4"},
{ "from": "Standard.LeftFoot", "to": "Actions.LeftFoot" }, { "from": "Standard.LeftFoot", "to": "Actions.LeftFoot" },
{ "from": "Standard.RightFoot", "to": "Actions.RightFoot" }, { "from": "Standard.RightFoot", "to": "Actions.RightFoot" },

View file

@ -34,36 +34,32 @@
{ "from": "Vive.RSCenter", "to": "Standard.RightPrimaryThumb" }, { "from": "Vive.RSCenter", "to": "Standard.RightPrimaryThumb" },
{ "from": "Vive.RightApplicationMenu", "to": "Standard.RightSecondaryThumb" }, { "from": "Vive.RightApplicationMenu", "to": "Standard.RightSecondaryThumb" },
{ "from": "Vive.LeftHand", "to": "Standard.LeftHand", "when": [ "Application.InHMD" ] }, { "from": "Vive.LeftHand", "to": "Standard.LeftHand"},
{ "from": "Vive.RightHand", "to": "Standard.RightHand", "when": [ "Application.InHMD" ] }, { "from": "Vive.RightHand", "to": "Standard.RightHand"},
{ {
"from": "Vive.LeftFoot", "to" : "Standard.LeftFoot", "from": "Vive.LeftFoot", "to" : "Standard.LeftFoot",
"filters" : [{"type" : "lowVelocity", "rotation" : 1.0, "translation": 1.0}], "filters" : [{"type" : "lowVelocity", "rotation" : 1.0, "translation": 1.0}]
"when": [ "Application.InHMD" ]
}, },
{ {
"from": "Vive.RightFoot", "to" : "Standard.RightFoot", "from": "Vive.RightFoot", "to" : "Standard.RightFoot",
"filters" : [{"type" : "lowVelocity", "rotation" : 1.0, "translation": 1.0}], "filters" : [{"type" : "lowVelocity", "rotation" : 1.0, "translation": 1.0}]
"when": [ "Application.InHMD" ]
}, },
{ {
"from": "Vive.Hips", "to" : "Standard.Hips", "from": "Vive.Hips", "to" : "Standard.Hips",
"filters" : [{"type" : "lowVelocity", "rotation" : 0.01, "translation": 0.01}], "filters" : [{"type" : "lowVelocity", "rotation" : 0.01, "translation": 0.01}]
"when": [ "Application.InHMD" ]
}, },
{ {
"from": "Vive.Spine2", "to" : "Standard.Spine2", "from": "Vive.Spine2", "to" : "Standard.Spine2",
"filters" : [{"type" : "lowVelocity", "rotation" : 0.01, "translation": 0.01}], "filters" : [{"type" : "lowVelocity", "rotation" : 0.01, "translation": 0.01}]
"when": [ "Application.InHMD" ]
}, },
{ "from": "Vive.Head", "to" : "Standard.Head", "when": [ "Application.InHMD" ] }, { "from": "Vive.Head", "to" : "Standard.Head"},
{ "from": "Vive.RightArm", "to" : "Standard.RightArm", "when": [ "Application.InHMD" ] }, { "from": "Vive.RightArm", "to" : "Standard.RightArm"},
{ "from": "Vive.LeftArm", "to" : "Standard.LeftArm", "when": [ "Application.InHMD" ] } { "from": "Vive.LeftArm", "to" : "Standard.LeftArm"}
] ]
} }

View file

@ -17,7 +17,7 @@ PreferencesDialog {
id: root id: root
objectName: "GeneralPreferencesDialog" objectName: "GeneralPreferencesDialog"
title: "General Settings" title: "General Settings"
showCategories: ["UI", "Snapshots", "Scripts", "Privacy", "Octree", "HMD", "Sixense Controllers", "Perception Neuron", "Kinect"] showCategories: ["UI", "Snapshots", "Scripts", "Privacy", "Octree", "HMD", "Sixense Controllers", "Perception Neuron", "Kinect", "Leap Motion"]
property var settings: Settings { property var settings: Settings {
category: root.objectName category: root.objectName
property alias x: root.x property alias x: root.x

View file

@ -25,11 +25,12 @@ Rectangle {
signal canceled() signal canceled()
signal restart() signal restart()
property int count: 3 property int count: 5
property string calibratingText: "CALIBRATING..." property string calibratingText: "CALIBRATING..."
property string calibratingCountText: "CALIBRATION STARTING IN" property string calibratingCountText: "CALIBRATION STARTING IN"
property string calibrationSuccess: "CALIBRATION COMPLETED" property string calibrationSuccess: "CALIBRATION COMPLETED"
property string calibrationFailed: "CALIBRATION FAILED" property string calibrationFailed: "CALIBRATION FAILED"
property string instructionText: "Please stand in a T-Pose during calibration"
HifiConstants { id: hifi } HifiConstants { id: hifi }
visible: true visible: true
@ -158,6 +159,15 @@ Rectangle {
onClicked: { onClicked: {
restart(); restart();
statusText.color = hifi.colors.blueHighlight;
statusText.text = info.calibratingCountText;
directions.text = instructionText;
countDown.visible = true;
busyIndicator.running = true;
busyRotation.from = 0
busyRotation.to = 360
busyIndicator.source = blueIndicator;
closeWindow.stop();
numberAnimation.stop(); numberAnimation.stop();
info.count = (timer.interval / 1000); info.count = (timer.interval / 1000);
numberAnimation.start(); numberAnimation.start();
@ -178,6 +188,7 @@ Rectangle {
} }
} }
function start(interval, countNumber) { function start(interval, countNumber) {
countDown.visible = true; countDown.visible = true;
statusText.color = hifi.colors.blueHighlight; statusText.color = hifi.colors.blueHighlight;
@ -201,6 +212,7 @@ Rectangle {
busyIndicator.running = false; busyIndicator.running = false;
statusText.text = info.calibrationSuccess statusText.text = info.calibrationSuccess
statusText.color = hifi.colors.greenHighlight statusText.color = hifi.colors.greenHighlight
directions.text = "SUCCESS"
closeWindow.start(); closeWindow.start();
} }

View file

@ -458,7 +458,7 @@ Rectangle {
width: glyphButton.width + calibrationText.width + padding width: glyphButton.width + calibrationText.width + padding
height: hifi.dimensions.controlLineHeight height: hifi.dimensions.controlLineHeight
anchors.top: bottomSeperator.bottom anchors.top: bottomSeperator.bottom
anchors.topMargin: 10 anchors.topMargin: 15
anchors.left: parent.left anchors.left: parent.left
anchors.leftMargin: leftMargin anchors.leftMargin: leftMargin
@ -590,16 +590,24 @@ Rectangle {
lastConfiguration = composeConfigurationSettings(); lastConfiguration = composeConfigurationSettings();
} }
Component.onDestruction: {
var settings = InputConfiguration.configurationSettings(pluginName);
var data = {
"num_pucks": settings["puckCount"]
}
UserActivityLogger.logAction("mocap_ui_close_dialog", data);
}
HifiControls.SpinBox { HifiControls.SpinBox {
id: timeToCalibrate id: timeToCalibrate
width: 70 width: 70
anchors.top: calibrationButton.bottom anchors.top: calibrationButton.bottom
anchors.topMargin: 40 anchors.topMargin: 20
anchors.left: parent.left anchors.left: parent.left
anchors.leftMargin: leftMargin anchors.leftMargin: leftMargin
minimumValue: 3 minimumValue: 5
value: 3 value: 5
colorScheme: hifi.colorSchemes.dark colorScheme: hifi.colorSchemes.dark
onEditingFinished: { onEditingFinished: {
@ -634,6 +642,57 @@ Rectangle {
} }
} }
Separator {
id: advanceSeperator
width: parent.width
anchors.top: timeToCalibrate.bottom
anchors.topMargin: 10
}
RalewayBold {
id: advanceSettings
text: "Advance Settings"
size: 12
color: hifi.colors.white
anchors.top: advanceSeperator.bottom
anchors.topMargin: 10
anchors.left: parent.left
anchors.leftMargin: leftMargin
}
HifiControls.CheckBox {
id: viveInDesktop
width: 15
height: 15
boxRadius: 7
anchors.top: advanceSettings.bottom
anchors.topMargin: 5
anchors.left: openVrConfiguration.left
anchors.leftMargin: leftMargin + 10
onClicked: {
sendConfigurationSettings();
}
}
RalewayBold {
id: viveDesktopText
size: 10
text: "Use vive devices in desktop mode"
color: hifi.colors.white
anchors {
left: viveInDesktop.right
leftMargin: 5
verticalCenter: viveInDesktop.verticalCenter
}
}
NumberAnimation { NumberAnimation {
id: numberAnimation id: numberAnimation
target: openVrConfiguration target: openVrConfiguration
@ -641,17 +700,39 @@ Rectangle {
to: 0 to: 0
} }
function logAction(action, status) {
console.log("calibrated from ui");
var data = {
"num_pucks": status["puckCount"],
"puck_configuration": status["configuration"],
"head_puck": status["head_puck"],
"hand_puck": status["hand_pucks"]
}
UserActivityLogger.logAction(action, data);
}
function calibrationStatusInfo(status) { function calibrationStatusInfo(status) {
var calibrationScreen = stack.currentItem; var calibrationScreen = stack.currentItem;
if (!status["UI"]) {
calibratingScreen = screen.createObject();
stack.push(calibratingScreen);
}
if (status["calibrated"]) { if (status["calibrated"]) {
calibrationScreen.success(); calibrationScreen.success();
if (status["UI"]) {
logAction("mocap_ui_success", status);
}
} else if (!status["calibrated"]) { } else if (!status["calibrated"]) {
var uncalibrated = status["success"]; calibrationScreen.failure();
if (!uncalibrated) {
calibrationScreen.failure(); if (status["UI"]) {
logAction("mocap_ui_failed", status);
} }
} }
updateCalibrationButton(); updateCalibrationButton();
} }
@ -698,6 +779,7 @@ Rectangle {
var HmdHead = settings["HMDHead"]; var HmdHead = settings["HMDHead"];
var viveController = settings["handController"]; var viveController = settings["handController"];
var desktopMode = settings["desktopMode"];
if (HmdHead) { if (HmdHead) {
headBox.checked = true; headBox.checked = true;
@ -715,8 +797,16 @@ Rectangle {
handBox.checked = false; handBox.checked = false;
} }
viveInDesktop.checked = desktopMode;
initializeButtonState(); initializeButtonState();
updateCalibrationText(); updateCalibrationText();
var data = {
"num_pucks": settings["puckCount"]
};
UserActivityLogger.logAction("mocap_ui_open_dialog", data);
} }
function displayTrackerConfiguration(type) { function displayTrackerConfiguration(type) {
@ -865,7 +955,8 @@ Rectangle {
var settingsObject = { var settingsObject = {
"bodyConfiguration": trackerConfiguration, "bodyConfiguration": trackerConfiguration,
"headConfiguration": headObject, "headConfiguration": headObject,
"handConfiguration": handObject "handConfiguration": handObject,
"desktopMode": viveInDesktop.checked
} }
return settingsObject; return settingsObject;

View file

@ -94,10 +94,20 @@ StackView {
property bool keyboardEnabled: false property bool keyboardEnabled: false
property bool keyboardRaised: false property bool keyboardRaised: false
property bool punctuationMode: false property bool punctuationMode: false
width: parent.width width: parent.width
height: parent.height height: parent.height
MouseArea {
anchors.fill: parent
propagateComposedEvents: true
onPressed: {
parent.forceActiveFocus();
addressBarDialog.keyboardEnabled = false;
mouse.accepted = false;
}
}
anchors { anchors {
right: parent.right right: parent.right
left: parent.left left: parent.left
@ -227,9 +237,9 @@ StackView {
MouseArea { MouseArea {
anchors.fill: parent; anchors.fill: parent;
onClicked: { onClicked: {
if (!addressLine.focus || !HMD.active) { addressLine.focus = true;
addressLine.focus = true; addressLine.forceActiveFocus();
addressLine.forceActiveFocus(); if (HMD.active) {
addressBarDialog.keyboardEnabled = HMD.active; addressBarDialog.keyboardEnabled = HMD.active;
} }
tabletRoot.playButtonClickSound(); tabletRoot.playButtonClickSound();

View file

@ -32,6 +32,6 @@ StackView {
TabletPreferencesDialog { TabletPreferencesDialog {
id: root id: root
objectName: "TabletGeneralPreferences" objectName: "TabletGeneralPreferences"
showCategories: ["UI", "Snapshots", "Scripts", "Privacy", "Octree", "HMD", "Sixense Controllers", "Perception Neuron", "Kinect", "Vive Pucks Configuration"] showCategories: ["UI", "Snapshots", "Scripts", "Privacy", "Octree", "HMD", "Sixense Controllers", "Perception Neuron", "Kinect", "Vive Pucks Configuration", "Leap Motion"]
} }
} }

View file

@ -25,6 +25,7 @@
#include <QtCore/QCommandLineParser> #include <QtCore/QCommandLineParser>
#include <QtCore/QMimeData> #include <QtCore/QMimeData>
#include <QtCore/QThreadPool> #include <QtCore/QThreadPool>
#include <QtConcurrent/QtConcurrentRun>
#include <QtGui/QScreen> #include <QtGui/QScreen>
#include <QtGui/QWindow> #include <QtGui/QWindow>
@ -48,6 +49,7 @@
#include <gl/QOpenGLContextWrapper.h> #include <gl/QOpenGLContextWrapper.h>
#include <shared/QtHelpers.h>
#include <shared/GlobalAppProperties.h> #include <shared/GlobalAppProperties.h>
#include <StatTracker.h> #include <StatTracker.h>
#include <Trace.h> #include <Trace.h>
@ -145,7 +147,6 @@
#include "avatar/MyHead.h" #include "avatar/MyHead.h"
#include "CrashHandler.h" #include "CrashHandler.h"
#include "devices/DdeFaceTracker.h" #include "devices/DdeFaceTracker.h"
#include "devices/Leapmotion.h"
#include "DiscoverabilityManager.h" #include "DiscoverabilityManager.h"
#include "GLCanvas.h" #include "GLCanvas.h"
#include "InterfaceDynamicFactory.h" #include "InterfaceDynamicFactory.h"
@ -480,6 +481,12 @@ bool setupEssentials(int& argc, char** argv, bool runningMarkerExisted) {
static const auto SUPPRESS_SETTINGS_RESET = "--suppress-settings-reset"; static const auto SUPPRESS_SETTINGS_RESET = "--suppress-settings-reset";
bool suppressPrompt = cmdOptionExists(argc, const_cast<const char**>(argv), SUPPRESS_SETTINGS_RESET); bool suppressPrompt = cmdOptionExists(argc, const_cast<const char**>(argv), SUPPRESS_SETTINGS_RESET);
bool previousSessionCrashed = CrashHandler::checkForResetSettings(runningMarkerExisted, suppressPrompt); bool previousSessionCrashed = CrashHandler::checkForResetSettings(runningMarkerExisted, suppressPrompt);
// get dir to use for cache
static const auto CACHE_SWITCH = "--cache";
QString cacheDir = getCmdOption(argc, const_cast<const char**>(argv), CACHE_SWITCH);
if (!cacheDir.isEmpty()) {
qApp->setProperty(hifi::properties::APP_LOCAL_DATA_PATH, cacheDir);
}
Setting::init(); Setting::init();
@ -1208,15 +1215,26 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo
// Make sure we don't time out during slow operations at startup // Make sure we don't time out during slow operations at startup
updateHeartbeat(); updateHeartbeat();
int SAVE_SETTINGS_INTERVAL = 10 * MSECS_PER_SECOND; // Let's save every seconds for now
connect(&_settingsTimer, &QTimer::timeout, this, &Application::saveSettings); QTimer* settingsTimer = new QTimer();
connect(&_settingsThread, SIGNAL(started()), &_settingsTimer, SLOT(start())); moveToNewNamedThread(settingsTimer, "Settings Thread", [this, settingsTimer]{
connect(&_settingsThread, SIGNAL(finished()), &_settingsTimer, SLOT(stop())); connect(qApp, &Application::beforeAboutToQuit, [this, settingsTimer]{
_settingsTimer.moveToThread(&_settingsThread); // Disconnect the signal from the save settings
_settingsTimer.setSingleShot(false); QObject::disconnect(settingsTimer, &QTimer::timeout, this, &Application::saveSettings);
_settingsTimer.setInterval(SAVE_SETTINGS_INTERVAL); // 10s, Qt::CoarseTimer acceptable // Stop the settings timer
_settingsThread.setPriority(QThread::LowestPriority); settingsTimer->stop();
_settingsThread.start(); // Delete it (this will trigger the thread destruction
settingsTimer->deleteLater();
// Mark the settings thread as finished, so we know we can safely save in the main application
// shutdown code
_settingsGuard.trigger();
});
int SAVE_SETTINGS_INTERVAL = 10 * MSECS_PER_SECOND; // Let's save every seconds for now
settingsTimer->setSingleShot(false);
settingsTimer->setInterval(SAVE_SETTINGS_INTERVAL); // 10s, Qt::CoarseTimer acceptable
QObject::connect(settingsTimer, &QTimer::timeout, this, &Application::saveSettings);
}, QThread::LowestPriority);
if (Menu::getInstance()->isOptionChecked(MenuOption::FirstPerson)) { if (Menu::getInstance()->isOptionChecked(MenuOption::FirstPerson)) {
getMyAvatar()->setBoomLength(MyAvatar::ZOOM_MIN); // So that camera doesn't auto-switch to third person. getMyAvatar()->setBoomLength(MyAvatar::ZOOM_MIN); // So that camera doesn't auto-switch to third person.
@ -1644,7 +1662,7 @@ QString Application::getUserAgent() {
if (QThread::currentThread() != thread()) { if (QThread::currentThread() != thread()) {
QString userAgent; QString userAgent;
QMetaObject::invokeMethod(this, "getUserAgent", Qt::BlockingQueuedConnection, Q_RETURN_ARG(QString, userAgent)); BLOCKING_INVOKE_METHOD(this, "getUserAgent", Q_RETURN_ARG(QString, userAgent));
return userAgent; return userAgent;
} }
@ -1802,11 +1820,13 @@ void Application::cleanupBeforeQuit() {
locationUpdateTimer.stop(); locationUpdateTimer.stop();
identityPacketTimer.stop(); identityPacketTimer.stop();
pingTimer.stop(); pingTimer.stop();
QMetaObject::invokeMethod(&_settingsTimer, "stop", Qt::BlockingQueuedConnection);
// save state // Wait for the settings thread to shut down, and save the settings one last time when it's safe
_settingsThread.quit(); if (_settingsGuard.wait()) {
saveSettings(); // save state
saveSettings();
}
_window->saveGeometry(); _window->saveGeometry();
// Destroy third party processes after scripts have finished using them. // Destroy third party processes after scripts have finished using them.
@ -1830,8 +1850,7 @@ void Application::cleanupBeforeQuit() {
// FIXME: something else is holding a reference to AudioClient, // FIXME: something else is holding a reference to AudioClient,
// so it must be explicitly synchronously stopped here // so it must be explicitly synchronously stopped here
QMetaObject::invokeMethod(DependencyManager::get<AudioClient>().data(), DependencyManager::get<AudioClient>()->cleanupBeforeQuit();
"cleanupBeforeQuit", Qt::BlockingQueuedConnection);
// destroy Audio so it and its threads have a chance to go down safely // destroy Audio so it and its threads have a chance to go down safely
// this must happen after QML, as there are unexplained audio crashes originating in qtwebengine // this must happen after QML, as there are unexplained audio crashes originating in qtwebengine
@ -1886,8 +1905,6 @@ Application::~Application() {
// remove the NodeList from the DependencyManager // remove the NodeList from the DependencyManager
DependencyManager::destroy<NodeList>(); DependencyManager::destroy<NodeList>();
Leapmotion::destroy();
if (auto steamClient = PluginManager::getInstance()->getSteamClientPlugin()) { if (auto steamClient = PluginManager::getInstance()->getSteamClientPlugin()) {
steamClient->shutdown(); steamClient->shutdown();
} }
@ -2154,48 +2171,74 @@ void Application::paintGL() {
return; return;
} }
auto displayPlugin = getActiveDisplayPlugin(); DisplayPluginPointer displayPlugin;
// FIXME not needed anymore? {
_offscreenContext->makeCurrent(); PROFILE_RANGE(render, "/getActiveDisplayPlugin");
displayPlugin = getActiveDisplayPlugin();
}
// If a display plugin loses it's underlying support, it {
// needs to be able to signal us to not use it PROFILE_RANGE(render, "/offscreenMakeCurrent");
if (!displayPlugin->beginFrameRender(_frameCount)) { // FIXME not needed anymore?
_inPaint = false; _offscreenContext->makeCurrent();
updateDisplayMode(); }
return;
{
PROFILE_RANGE(render, "/pluginBeginFrameRender");
// If a display plugin loses it's underlying support, it
// needs to be able to signal us to not use it
if (!displayPlugin->beginFrameRender(_frameCount)) {
_inPaint = false;
updateDisplayMode();
return;
}
} }
// update the avatar with a fresh HMD pose // update the avatar with a fresh HMD pose
getMyAvatar()->updateFromHMDSensorMatrix(getHMDSensorPose()); {
PROFILE_RANGE(render, "/updateAvatar");
getMyAvatar()->updateFromHMDSensorMatrix(getHMDSensorPose());
}
auto lodManager = DependencyManager::get<LODManager>(); auto lodManager = DependencyManager::get<LODManager>();
RenderArgs renderArgs;
{ {
QMutexLocker viewLocker(&_viewMutex); PROFILE_RANGE(render, "/buildFrustrumAndArgs");
_viewFrustum.calculate(); {
} QMutexLocker viewLocker(&_viewMutex);
RenderArgs renderArgs(_gpuContext, getEntities(), lodManager->getOctreeSizeScale(), _viewFrustum.calculate();
lodManager->getBoundaryLevelAdjust(), RenderArgs::DEFAULT_RENDER_MODE, }
RenderArgs::MONO, RenderArgs::RENDER_DEBUG_NONE); renderArgs = RenderArgs(_gpuContext, getEntities(), lodManager->getOctreeSizeScale(),
{ lodManager->getBoundaryLevelAdjust(), RenderArgs::DEFAULT_RENDER_MODE,
QMutexLocker viewLocker(&_viewMutex); RenderArgs::MONO, RenderArgs::RENDER_DEBUG_NONE);
renderArgs.setViewFrustum(_viewFrustum); {
QMutexLocker viewLocker(&_viewMutex);
renderArgs.setViewFrustum(_viewFrustum);
}
} }
PerformanceWarning::setSuppressShortTimings(Menu::getInstance()->isOptionChecked(MenuOption::SuppressShortTimings)); {
bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings); PROFILE_RANGE(render, "/resizeGL");
PerformanceWarning warn(showWarnings, "Application::paintGL()"); PerformanceWarning::setSuppressShortTimings(Menu::getInstance()->isOptionChecked(MenuOption::SuppressShortTimings));
resizeGL(); bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings);
PerformanceWarning warn(showWarnings, "Application::paintGL()");
_gpuContext->beginFrame(getHMDSensorPose()); resizeGL();
// Reset the gpu::Context Stages }
// Back to the default framebuffer;
gpu::doInBatch(_gpuContext, [&](gpu::Batch& batch) {
batch.resetStages();
});
{ {
PROFILE_RANGE(render, "/gpuContextReset");
_gpuContext->beginFrame(getHMDSensorPose());
// Reset the gpu::Context Stages
// Back to the default framebuffer;
gpu::doInBatch(_gpuContext, [&](gpu::Batch& batch) {
batch.resetStages();
});
}
{
PROFILE_RANGE(render, "/renderOverlay");
PerformanceTimer perfTimer("renderOverlay"); PerformanceTimer perfTimer("renderOverlay");
// NOTE: There is no batch associated with this renderArgs // NOTE: There is no batch associated with this renderArgs
// the ApplicationOverlay class assumes it's viewport is setup to be the device size // the ApplicationOverlay class assumes it's viewport is setup to be the device size
@ -2206,114 +2249,127 @@ void Application::paintGL() {
glm::vec3 boomOffset; glm::vec3 boomOffset;
{ {
PerformanceTimer perfTimer("CameraUpdates"); PROFILE_RANGE(render, "/updateCamera");
{
PerformanceTimer perfTimer("CameraUpdates");
auto myAvatar = getMyAvatar(); auto myAvatar = getMyAvatar();
boomOffset = myAvatar->getScale() * myAvatar->getBoomLength() * -IDENTITY_FORWARD; boomOffset = myAvatar->getScale() * myAvatar->getBoomLength() * -IDENTITY_FORWARD;
if (_myCamera.getMode() == CAMERA_MODE_FIRST_PERSON || _myCamera.getMode() == CAMERA_MODE_THIRD_PERSON) { if (_myCamera.getMode() == CAMERA_MODE_FIRST_PERSON || _myCamera.getMode() == CAMERA_MODE_THIRD_PERSON) {
Menu::getInstance()->setIsOptionChecked(MenuOption::FirstPerson, myAvatar->getBoomLength() <= MyAvatar::ZOOM_MIN); Menu::getInstance()->setIsOptionChecked(MenuOption::FirstPerson, myAvatar->getBoomLength() <= MyAvatar::ZOOM_MIN);
Menu::getInstance()->setIsOptionChecked(MenuOption::ThirdPerson, !(myAvatar->getBoomLength() <= MyAvatar::ZOOM_MIN)); Menu::getInstance()->setIsOptionChecked(MenuOption::ThirdPerson, !(myAvatar->getBoomLength() <= MyAvatar::ZOOM_MIN));
cameraMenuChanged(); cameraMenuChanged();
}
// The render mode is default or mirror if the camera is in mirror mode, assigned further below
renderArgs._renderMode = RenderArgs::DEFAULT_RENDER_MODE;
// Always use the default eye position, not the actual head eye position.
// Using the latter will cause the camera to wobble with idle animations,
// or with changes from the face tracker
if (_myCamera.getMode() == CAMERA_MODE_FIRST_PERSON) {
if (isHMDMode()) {
mat4 camMat = myAvatar->getSensorToWorldMatrix() * myAvatar->getHMDSensorMatrix();
_myCamera.setPosition(extractTranslation(camMat));
_myCamera.setOrientation(glm::quat_cast(camMat));
} else {
_myCamera.setPosition(myAvatar->getDefaultEyePosition());
_myCamera.setOrientation(myAvatar->getMyHead()->getHeadOrientation());
} }
} else if (_myCamera.getMode() == CAMERA_MODE_THIRD_PERSON) {
if (isHMDMode()) {
auto hmdWorldMat = myAvatar->getSensorToWorldMatrix() * myAvatar->getHMDSensorMatrix();
_myCamera.setOrientation(glm::normalize(glm::quat_cast(hmdWorldMat)));
_myCamera.setPosition(extractTranslation(hmdWorldMat) +
myAvatar->getOrientation() * boomOffset);
} else {
_myCamera.setOrientation(myAvatar->getHead()->getOrientation());
if (Menu::getInstance()->isOptionChecked(MenuOption::CenterPlayerInView)) {
_myCamera.setPosition(myAvatar->getDefaultEyePosition()
+ _myCamera.getOrientation() * boomOffset);
} else {
_myCamera.setPosition(myAvatar->getDefaultEyePosition()
+ myAvatar->getOrientation() * boomOffset);
}
}
} else if (_myCamera.getMode() == CAMERA_MODE_MIRROR) {
if (isHMDMode()) {
auto mirrorBodyOrientation = myAvatar->getWorldAlignedOrientation() * glm::quat(glm::vec3(0.0f, PI + _rotateMirror, 0.0f));
glm::quat hmdRotation = extractRotation(myAvatar->getHMDSensorMatrix()); // The render mode is default or mirror if the camera is in mirror mode, assigned further below
// Mirror HMD yaw and roll renderArgs._renderMode = RenderArgs::DEFAULT_RENDER_MODE;
glm::vec3 mirrorHmdEulers = glm::eulerAngles(hmdRotation);
mirrorHmdEulers.y = -mirrorHmdEulers.y;
mirrorHmdEulers.z = -mirrorHmdEulers.z;
glm::quat mirrorHmdRotation = glm::quat(mirrorHmdEulers);
glm::quat worldMirrorRotation = mirrorBodyOrientation * mirrorHmdRotation; // Always use the default eye position, not the actual head eye position.
// Using the latter will cause the camera to wobble with idle animations,
_myCamera.setOrientation(worldMirrorRotation); // or with changes from the face tracker
if (_myCamera.getMode() == CAMERA_MODE_FIRST_PERSON) {
glm::vec3 hmdOffset = extractTranslation(myAvatar->getHMDSensorMatrix());
// Mirror HMD lateral offsets
hmdOffset.x = -hmdOffset.x;
_myCamera.setPosition(myAvatar->getDefaultEyePosition()
+ glm::vec3(0, _raiseMirror * myAvatar->getUniformScale(), 0)
+ mirrorBodyOrientation * glm::vec3(0.0f, 0.0f, 1.0f) * MIRROR_FULLSCREEN_DISTANCE * _scaleMirror
+ mirrorBodyOrientation * hmdOffset);
} else {
_myCamera.setOrientation(myAvatar->getWorldAlignedOrientation()
* glm::quat(glm::vec3(0.0f, PI + _rotateMirror, 0.0f)));
_myCamera.setPosition(myAvatar->getDefaultEyePosition()
+ glm::vec3(0, _raiseMirror * myAvatar->getUniformScale(), 0)
+ (myAvatar->getOrientation() * glm::quat(glm::vec3(0.0f, _rotateMirror, 0.0f))) *
glm::vec3(0.0f, 0.0f, -1.0f) * MIRROR_FULLSCREEN_DISTANCE * _scaleMirror);
}
renderArgs._renderMode = RenderArgs::MIRROR_RENDER_MODE;
} else if (_myCamera.getMode() == CAMERA_MODE_ENTITY) {
EntityItemPointer cameraEntity = _myCamera.getCameraEntityPointer();
if (cameraEntity != nullptr) {
if (isHMDMode()) { if (isHMDMode()) {
glm::quat hmdRotation = extractRotation(myAvatar->getHMDSensorMatrix()); mat4 camMat = myAvatar->getSensorToWorldMatrix() * myAvatar->getHMDSensorMatrix();
_myCamera.setOrientation(cameraEntity->getRotation() * hmdRotation); _myCamera.setPosition(extractTranslation(camMat));
glm::vec3 hmdOffset = extractTranslation(myAvatar->getHMDSensorMatrix()); _myCamera.setOrientation(glm::quat_cast(camMat));
_myCamera.setPosition(cameraEntity->getPosition() + (hmdRotation * hmdOffset));
} else { } else {
_myCamera.setOrientation(cameraEntity->getRotation()); _myCamera.setPosition(myAvatar->getDefaultEyePosition());
_myCamera.setPosition(cameraEntity->getPosition()); _myCamera.setOrientation(myAvatar->getMyHead()->getHeadOrientation());
}
} else if (_myCamera.getMode() == CAMERA_MODE_THIRD_PERSON) {
if (isHMDMode()) {
auto hmdWorldMat = myAvatar->getSensorToWorldMatrix() * myAvatar->getHMDSensorMatrix();
_myCamera.setOrientation(glm::normalize(glm::quat_cast(hmdWorldMat)));
_myCamera.setPosition(extractTranslation(hmdWorldMat) +
myAvatar->getOrientation() * boomOffset);
} else {
_myCamera.setOrientation(myAvatar->getHead()->getOrientation());
if (Menu::getInstance()->isOptionChecked(MenuOption::CenterPlayerInView)) {
_myCamera.setPosition(myAvatar->getDefaultEyePosition()
+ _myCamera.getOrientation() * boomOffset);
} else {
_myCamera.setPosition(myAvatar->getDefaultEyePosition()
+ myAvatar->getOrientation() * boomOffset);
}
}
} else if (_myCamera.getMode() == CAMERA_MODE_MIRROR) {
if (isHMDMode()) {
auto mirrorBodyOrientation = myAvatar->getWorldAlignedOrientation() * glm::quat(glm::vec3(0.0f, PI + _rotateMirror, 0.0f));
glm::quat hmdRotation = extractRotation(myAvatar->getHMDSensorMatrix());
// Mirror HMD yaw and roll
glm::vec3 mirrorHmdEulers = glm::eulerAngles(hmdRotation);
mirrorHmdEulers.y = -mirrorHmdEulers.y;
mirrorHmdEulers.z = -mirrorHmdEulers.z;
glm::quat mirrorHmdRotation = glm::quat(mirrorHmdEulers);
glm::quat worldMirrorRotation = mirrorBodyOrientation * mirrorHmdRotation;
_myCamera.setOrientation(worldMirrorRotation);
glm::vec3 hmdOffset = extractTranslation(myAvatar->getHMDSensorMatrix());
// Mirror HMD lateral offsets
hmdOffset.x = -hmdOffset.x;
_myCamera.setPosition(myAvatar->getDefaultEyePosition()
+ glm::vec3(0, _raiseMirror * myAvatar->getUniformScale(), 0)
+ mirrorBodyOrientation * glm::vec3(0.0f, 0.0f, 1.0f) * MIRROR_FULLSCREEN_DISTANCE * _scaleMirror
+ mirrorBodyOrientation * hmdOffset);
} else {
_myCamera.setOrientation(myAvatar->getWorldAlignedOrientation()
* glm::quat(glm::vec3(0.0f, PI + _rotateMirror, 0.0f)));
_myCamera.setPosition(myAvatar->getDefaultEyePosition()
+ glm::vec3(0, _raiseMirror * myAvatar->getUniformScale(), 0)
+ (myAvatar->getOrientation() * glm::quat(glm::vec3(0.0f, _rotateMirror, 0.0f))) *
glm::vec3(0.0f, 0.0f, -1.0f) * MIRROR_FULLSCREEN_DISTANCE * _scaleMirror);
}
renderArgs._renderMode = RenderArgs::MIRROR_RENDER_MODE;
} else if (_myCamera.getMode() == CAMERA_MODE_ENTITY) {
EntityItemPointer cameraEntity = _myCamera.getCameraEntityPointer();
if (cameraEntity != nullptr) {
if (isHMDMode()) {
glm::quat hmdRotation = extractRotation(myAvatar->getHMDSensorMatrix());
_myCamera.setOrientation(cameraEntity->getRotation() * hmdRotation);
glm::vec3 hmdOffset = extractTranslation(myAvatar->getHMDSensorMatrix());
_myCamera.setPosition(cameraEntity->getPosition() + (hmdRotation * hmdOffset));
} else {
_myCamera.setOrientation(cameraEntity->getRotation());
_myCamera.setPosition(cameraEntity->getPosition());
}
} }
} }
} // Update camera position
// Update camera position if (!isHMDMode()) {
if (!isHMDMode()) { _myCamera.update(1.0f / _frameCounter.rate());
_myCamera.update(1.0f / _frameCounter.rate()); }
} }
} }
getApplicationCompositor().setFrameInfo(_frameCount, _myCamera.getTransform()); {
PROFILE_RANGE(render, "/updateCompositor");
getApplicationCompositor().setFrameInfo(_frameCount, _myCamera.getTransform());
}
// Primary rendering pass gpu::FramebufferPointer finalFramebuffer;
auto framebufferCache = DependencyManager::get<FramebufferCache>(); QSize finalFramebufferSize;
const QSize size = framebufferCache->getFrameBufferSize(); {
// Final framebuffer that will be handled to the display-plugin PROFILE_RANGE(render, "/getOutputFramebuffer");
auto finalFramebuffer = framebufferCache->getFramebuffer(); // Primary rendering pass
auto framebufferCache = DependencyManager::get<FramebufferCache>();
finalFramebufferSize = framebufferCache->getFrameBufferSize();
// Final framebuffer that will be handled to the display-plugin
finalFramebuffer = framebufferCache->getFramebuffer();
}
{ {
PROFILE_RANGE(render, "/mainRender"); PROFILE_RANGE(render, "/mainRender");
PerformanceTimer perfTimer("mainRender"); PerformanceTimer perfTimer("mainRender");
renderArgs._boomOffset = boomOffset; renderArgs._boomOffset = boomOffset;
// FIXME is this ever going to be different from the size previously set in the render args
// in the overlay render?
// Viewport is assigned to the size of the framebuffer // Viewport is assigned to the size of the framebuffer
renderArgs._viewport = ivec4(0, 0, size.width(), size.height()); renderArgs._viewport = ivec4(0, 0, finalFramebufferSize.width(), finalFramebufferSize.height());
if (displayPlugin->isStereo()) { if (displayPlugin->isStereo()) {
// Stereo modes will typically have a larger projection matrix overall, // Stereo modes will typically have a larger projection matrix overall,
// so we ask for the 'mono' projection matrix, which for stereo and HMD // so we ask for the 'mono' projection matrix, which for stereo and HMD
@ -3613,6 +3669,133 @@ bool Application::shouldPaint(float nsecsElapsed) {
#include <TCHAR.h> #include <TCHAR.h>
#include <pdh.h> #include <pdh.h>
#pragma comment(lib, "pdh.lib") #pragma comment(lib, "pdh.lib")
#pragma comment(lib, "ntdll.lib")
extern "C" {
enum SYSTEM_INFORMATION_CLASS {
SystemBasicInformation = 0,
SystemProcessorPerformanceInformation = 8,
};
struct SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION {
LARGE_INTEGER IdleTime;
LARGE_INTEGER KernelTime;
LARGE_INTEGER UserTime;
LARGE_INTEGER DpcTime;
LARGE_INTEGER InterruptTime;
ULONG InterruptCount;
};
struct SYSTEM_BASIC_INFORMATION {
ULONG Reserved;
ULONG TimerResolution;
ULONG PageSize;
ULONG NumberOfPhysicalPages;
ULONG LowestPhysicalPageNumber;
ULONG HighestPhysicalPageNumber;
ULONG AllocationGranularity;
ULONG_PTR MinimumUserModeAddress;
ULONG_PTR MaximumUserModeAddress;
ULONG_PTR ActiveProcessorsAffinityMask;
CCHAR NumberOfProcessors;
};
NTSYSCALLAPI NTSTATUS NTAPI NtQuerySystemInformation(
_In_ SYSTEM_INFORMATION_CLASS SystemInformationClass,
_Out_writes_bytes_opt_(SystemInformationLength) PVOID SystemInformation,
_In_ ULONG SystemInformationLength,
_Out_opt_ PULONG ReturnLength
);
}
template <typename T>
NTSTATUS NtQuerySystemInformation(SYSTEM_INFORMATION_CLASS SystemInformationClass, T& t) {
return NtQuerySystemInformation(SystemInformationClass, &t, (ULONG)sizeof(T), nullptr);
}
template <typename T>
NTSTATUS NtQuerySystemInformation(SYSTEM_INFORMATION_CLASS SystemInformationClass, std::vector<T>& t) {
return NtQuerySystemInformation(SystemInformationClass, t.data(), (ULONG)(sizeof(T) * t.size()), nullptr);
}
template <typename T>
void updateValueAndDelta(std::pair<T, T>& pair, T newValue) {
auto& value = pair.first;
auto& delta = pair.second;
delta = (value != 0) ? newValue - value : 0;
value = newValue;
}
struct MyCpuInfo {
using ValueAndDelta = std::pair<LONGLONG, LONGLONG>;
std::string name;
ValueAndDelta kernel { 0, 0 };
ValueAndDelta user { 0, 0 };
ValueAndDelta idle { 0, 0 };
float kernelUsage { 0.0f };
float userUsage { 0.0f };
void update(const SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION& cpuInfo) {
updateValueAndDelta(kernel, cpuInfo.KernelTime.QuadPart);
updateValueAndDelta(user, cpuInfo.UserTime.QuadPart);
updateValueAndDelta(idle, cpuInfo.IdleTime.QuadPart);
auto totalTime = kernel.second + user.second + idle.second;
if (totalTime != 0) {
kernelUsage = (FLOAT)kernel.second / totalTime;
userUsage = (FLOAT)user.second / totalTime;
} else {
kernelUsage = userUsage = 0.0f;
}
}
};
void updateCpuInformation() {
static std::once_flag once;
static SYSTEM_BASIC_INFORMATION systemInfo {};
static SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION cpuTotals;
static std::vector<SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION> cpuInfos;
static std::vector<MyCpuInfo> myCpuInfos;
static MyCpuInfo myCpuTotals;
std::call_once(once, [&] {
NtQuerySystemInformation( SystemBasicInformation, systemInfo);
cpuInfos.resize(systemInfo.NumberOfProcessors);
myCpuInfos.resize(systemInfo.NumberOfProcessors);
for (size_t i = 0; i < systemInfo.NumberOfProcessors; ++i) {
myCpuInfos[i].name = "cpu." + std::to_string(i);
}
myCpuTotals.name = "cpu.total";
});
NtQuerySystemInformation(SystemProcessorPerformanceInformation, cpuInfos);
// Zero the CPU totals.
memset(&cpuTotals, 0, sizeof(SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION));
for (size_t i = 0; i < systemInfo.NumberOfProcessors; ++i) {
auto& cpuInfo = cpuInfos[i];
// KernelTime includes IdleTime.
cpuInfo.KernelTime.QuadPart -= cpuInfo.IdleTime.QuadPart;
// Update totals
cpuTotals.IdleTime.QuadPart += cpuInfo.IdleTime.QuadPart;
cpuTotals.KernelTime.QuadPart += cpuInfo.KernelTime.QuadPart;
cpuTotals.UserTime.QuadPart += cpuInfo.UserTime.QuadPart;
// Update friendly structure
auto& myCpuInfo = myCpuInfos[i];
myCpuInfo.update(cpuInfo);
PROFILE_COUNTER(app, myCpuInfo.name.c_str(), {
{ "kernel", myCpuInfo.kernelUsage },
{ "user", myCpuInfo.userUsage }
});
}
myCpuTotals.update(cpuTotals);
PROFILE_COUNTER(app, myCpuTotals.name.c_str(), {
{ "kernel", myCpuTotals.kernelUsage },
{ "user", myCpuTotals.userUsage }
});
}
static ULARGE_INTEGER lastCPU, lastSysCPU, lastUserCPU; static ULARGE_INTEGER lastCPU, lastSysCPU, lastUserCPU;
static int numProcessors; static int numProcessors;
@ -3665,6 +3848,26 @@ void getCpuUsage(vec3& systemAndUser) {
systemAndUser.z = (float)counterVal.doubleValue; systemAndUser.z = (float)counterVal.doubleValue;
} }
void setupCpuMonitorThread() {
initCpuUsage();
auto cpuMonitorThread = QThread::currentThread();
QTimer* timer = new QTimer();
timer->setInterval(50);
QObject::connect(timer, &QTimer::timeout, [] {
updateCpuInformation();
vec3 kernelUserAndSystem;
getCpuUsage(kernelUserAndSystem);
PROFILE_COUNTER(app, "cpuProcess", { { "system", kernelUserAndSystem.x }, { "user", kernelUserAndSystem.y } });
PROFILE_COUNTER(app, "cpuSystem", { { "system", kernelUserAndSystem.z } });
});
QObject::connect(cpuMonitorThread, &QThread::finished, [=] {
timer->deleteLater();
cpuMonitorThread->deleteLater();
});
timer->start();
}
#endif #endif
@ -3685,15 +3888,17 @@ void Application::idle(float nsecsElapsed) {
} }
#ifdef Q_OS_WIN #ifdef Q_OS_WIN
// If tracing is enabled then monitor the CPU in a separate thread
static std::once_flag once; static std::once_flag once;
std::call_once(once, [] { std::call_once(once, [&] {
initCpuUsage(); if (trace_app().isDebugEnabled()) {
QThread* cpuMonitorThread = new QThread(qApp);
cpuMonitorThread->setObjectName("cpuMonitorThread");
QObject::connect(cpuMonitorThread, &QThread::started, [this] { setupCpuMonitorThread(); });
QObject::connect(qApp, &QCoreApplication::aboutToQuit, cpuMonitorThread, &QThread::quit);
cpuMonitorThread->start();
}
}); });
vec3 kernelUserAndSystem;
getCpuUsage(kernelUserAndSystem);
PROFILE_COUNTER(app, "cpuProcess", { { "system", kernelUserAndSystem.x }, { "user", kernelUserAndSystem.y } });
PROFILE_COUNTER(app, "cpuSystem", { { "system", kernelUserAndSystem.z } });
#endif #endif
@ -4055,8 +4260,6 @@ void Application::init() {
qCDebug(interfaceapp) << "Loaded settings"; qCDebug(interfaceapp) << "Loaded settings";
Leapmotion::init();
// fire off an immediate domain-server check in now that settings are loaded // fire off an immediate domain-server check in now that settings are loaded
DependencyManager::get<NodeList>()->sendDomainServerCheckIn(); DependencyManager::get<NodeList>()->sendDomainServerCheckIn();
@ -4520,7 +4723,6 @@ void Application::update(float deltaTime) {
{ {
PerformanceTimer perfTimer("devices"); PerformanceTimer perfTimer("devices");
DeviceTracker::updateAll();
FaceTracker* tracker = getSelectedFaceTracker(); FaceTracker* tracker = getSelectedFaceTracker();
if (tracker && Menu::getInstance()->isOptionChecked(MenuOption::MuteFaceTracking) != tracker->isMuted()) { if (tracker && Menu::getInstance()->isOptionChecked(MenuOption::MuteFaceTracking) != tracker->isMuted()) {
@ -4589,8 +4791,6 @@ void Application::update(float deltaTime) {
keyboardMousePlugin->pluginUpdate(deltaTime, calibrationData); keyboardMousePlugin->pluginUpdate(deltaTime, calibrationData);
} }
_controllerScriptingInterface->updateInputControllers();
// Transfer the user inputs to the driveKeys // Transfer the user inputs to the driveKeys
// FIXME can we drop drive keys and just have the avatar read the action states directly? // FIXME can we drop drive keys and just have the avatar read the action states directly?
myAvatar->clearDriveKeys(); myAvatar->clearDriveKeys();
@ -4615,6 +4815,31 @@ void Application::update(float deltaTime) {
auto avatarToSensorMatrix = worldToSensorMatrix * myAvatarMatrix; auto avatarToSensorMatrix = worldToSensorMatrix * myAvatarMatrix;
myAvatar->setHandControllerPosesInSensorFrame(leftHandPose.transform(avatarToSensorMatrix), rightHandPose.transform(avatarToSensorMatrix)); myAvatar->setHandControllerPosesInSensorFrame(leftHandPose.transform(avatarToSensorMatrix), rightHandPose.transform(avatarToSensorMatrix));
// If have previously done finger poses or there are new valid finger poses, update finger pose values. This so that if
// fingers are not being controlled, finger joints are not updated in MySkeletonModel.
// Assumption: Finger poses are either all present and valid or not present at all; thus can test just one joint.
MyAvatar::FingerPosesMap leftHandFingerPoses;
if (myAvatar->getLeftHandFingerControllerPosesInSensorFrame().size() > 0
|| userInputMapper->getPoseState(controller::Action::LEFT_HAND_THUMB1).isValid()) {
for (int i = (int)controller::Action::LEFT_HAND_THUMB1; i <= (int)controller::Action::LEFT_HAND_PINKY4; i++) {
leftHandFingerPoses[i] = {
userInputMapper->getPoseState((controller::Action)i).transform(avatarToSensorMatrix),
userInputMapper->getActionName((controller::Action)i)
};
}
}
MyAvatar::FingerPosesMap rightHandFingerPoses;
if (myAvatar->getRightHandFingerControllerPosesInSensorFrame().size() > 0
|| userInputMapper->getPoseState(controller::Action::RIGHT_HAND_THUMB1).isValid()) {
for (int i = (int)controller::Action::RIGHT_HAND_THUMB1; i <= (int)controller::Action::RIGHT_HAND_PINKY4; i++) {
rightHandFingerPoses[i] = {
userInputMapper->getPoseState((controller::Action)i).transform(avatarToSensorMatrix),
userInputMapper->getActionName((controller::Action)i)
};
}
}
myAvatar->setFingerControllerPosesInSensorFrame(leftHandFingerPoses, rightHandFingerPoses);
controller::Pose leftFootPose = userInputMapper->getPoseState(controller::Action::LEFT_FOOT); controller::Pose leftFootPose = userInputMapper->getPoseState(controller::Action::LEFT_FOOT);
controller::Pose rightFootPose = userInputMapper->getPoseState(controller::Action::RIGHT_FOOT); controller::Pose rightFootPose = userInputMapper->getPoseState(controller::Action::RIGHT_FOOT);
myAvatar->setFootControllerPosesInSensorFrame(leftFootPose.transform(avatarToSensorMatrix), rightFootPose.transform(avatarToSensorMatrix)); myAvatar->setFootControllerPosesInSensorFrame(leftFootPose.transform(avatarToSensorMatrix), rightFootPose.transform(avatarToSensorMatrix));

View file

@ -25,6 +25,7 @@
#include <QtWidgets/QApplication> #include <QtWidgets/QApplication>
#include <QtWidgets/QUndoStack> #include <QtWidgets/QUndoStack>
#include <ThreadHelpers.h>
#include <AbstractScriptingServicesInterface.h> #include <AbstractScriptingServicesInterface.h>
#include <AbstractViewStateInterface.h> #include <AbstractViewStateInterface.h>
#include <EntityEditPacketSender.h> #include <EntityEditPacketSender.h>
@ -298,7 +299,6 @@ public:
void setAvatarOverrideUrl(const QUrl& url, bool save); void setAvatarOverrideUrl(const QUrl& url, bool save);
QUrl getAvatarOverrideUrl() { return _avatarOverrideUrl; } QUrl getAvatarOverrideUrl() { return _avatarOverrideUrl; }
bool getSaveAvatarOverrideUrl() { return _saveAvatarOverrideUrl; } bool getSaveAvatarOverrideUrl() { return _saveAvatarOverrideUrl; }
void setCacheOverrideDir(const QString& dirName) { _cacheDir = dirName; }
signals: signals:
void svoImportRequested(const QString& url); void svoImportRequested(const QString& url);
@ -596,8 +596,7 @@ private:
bool _notifiedPacketVersionMismatchThisDomain; bool _notifiedPacketVersionMismatchThisDomain;
QThread _settingsThread; ConditionalGuard _settingsGuard;
QTimer _settingsTimer;
GLCanvas* _glWidget{ nullptr }; GLCanvas* _glWidget{ nullptr };
@ -691,6 +690,5 @@ private:
QUrl _avatarOverrideUrl; QUrl _avatarOverrideUrl;
bool _saveAvatarOverrideUrl { false }; bool _saveAvatarOverrideUrl { false };
QString _cacheDir;
}; };
#endif // hifi_Application_h #endif // hifi_Application_h

View file

@ -14,6 +14,7 @@
#include <QMessageBox> #include <QMessageBox>
#include <QStandardPaths> #include <QStandardPaths>
#include <QQmlContext> #include <QQmlContext>
#include <QList>
#include <Application.h> #include <Application.h>
#include <OffscreenUi.h> #include <OffscreenUi.h>
@ -24,6 +25,8 @@
#include "AvatarBookmarks.h" #include "AvatarBookmarks.h"
#include "InterfaceLogging.h" #include "InterfaceLogging.h"
#include "QVariantGLM.h"
#include <QtQuick/QQuickWindow> #include <QtQuick/QQuickWindow>
AvatarBookmarks::AvatarBookmarks() { AvatarBookmarks::AvatarBookmarks() {
@ -58,16 +61,48 @@ void AvatarBookmarks::setupMenus(Menu* menubar, MenuWrapper* menu) {
_deleteBookmarksAction = menubar->addActionToQMenuAndActionHash(menu, MenuOption::DeleteAvatarBookmark); _deleteBookmarksAction = menubar->addActionToQMenuAndActionHash(menu, MenuOption::DeleteAvatarBookmark);
QObject::connect(_deleteBookmarksAction, SIGNAL(triggered()), this, SLOT(deleteBookmark()), Qt::QueuedConnection); QObject::connect(_deleteBookmarksAction, SIGNAL(triggered()), this, SLOT(deleteBookmark()), Qt::QueuedConnection);
Bookmarks::setupMenus(menubar, menu); for (auto it = _bookmarks.begin(); it != _bookmarks.end(); ++it) {
addBookmarkToMenu(menubar, it.key(), it.value());
}
Bookmarks::sortActions(menubar, _bookmarksMenu); Bookmarks::sortActions(menubar, _bookmarksMenu);
} }
void AvatarBookmarks::changeToBookmarkedAvatar() { void AvatarBookmarks::changeToBookmarkedAvatar() {
QAction* action = qobject_cast<QAction*>(sender()); QAction* action = qobject_cast<QAction*>(sender());
const QString& address = action->data().toString();
auto myAvatar = DependencyManager::get<AvatarManager>()->getMyAvatar(); auto myAvatar = DependencyManager::get<AvatarManager>()->getMyAvatar();
myAvatar->useFullAvatarURL(address);
if (action->data().type() == QVariant::String) {
// TODO: Phase this out eventually.
// Legacy avatar bookmark.
myAvatar->useFullAvatarURL(action->data().toString());
qCDebug(interfaceapp) << " Using Legacy V1 Avatar Bookmark ";
} else {
const QMap<QString, QVariant> bookmark = action->data().toMap();
// Not magic value. This is the current made version, and if it changes this interpreter should be updated to
// handle the new one separately.
// This is where the avatar bookmark entry is parsed. If adding new Value, make sure to have backward compatability with previous
if (bookmark.value(ENTRY_VERSION) == 3) {
const QString& avatarUrl = bookmark.value(ENTRY_AVATAR_URL, "").toString();
myAvatar->useFullAvatarURL(avatarUrl);
qCDebug(interfaceapp) << "Avatar On " << avatarUrl;
const QList<QVariant>& attachments = bookmark.value(ENTRY_AVATAR_ATTACHMENTS, QList<QVariant>()).toList();
qCDebug(interfaceapp) << "Attach " << attachments;
myAvatar->setAttachmentsVariant(attachments);
const float& qScale = bookmark.value(ENTRY_AVATAR_SCALE, 1.0f).toFloat();
myAvatar->setAvatarScale(qScale);
} else {
qCDebug(interfaceapp) << " Bookmark entry does not match client version, make sure client has a handler for the new AvatarBookmark";
}
}
} }
void AvatarBookmarks::addBookmark() { void AvatarBookmarks::addBookmark() {
@ -83,13 +118,23 @@ void AvatarBookmarks::addBookmark() {
} }
auto myAvatar = DependencyManager::get<AvatarManager>()->getMyAvatar(); auto myAvatar = DependencyManager::get<AvatarManager>()->getMyAvatar();
const QString& bookmarkAddress = myAvatar->getSkeletonModelURL().toString();
Bookmarks::addBookmarkToFile(bookmarkName, bookmarkAddress); const QString& avatarUrl = myAvatar->getSkeletonModelURL().toString();
const QVariant& avatarScale = myAvatar->getAvatarScale();
// If Avatar attachments ever change, this is where to update them, when saving remember to also append to AVATAR_BOOKMARK_VERSION
QVariantMap *bookmark = new QVariantMap;
bookmark->insert(ENTRY_VERSION, AVATAR_BOOKMARK_VERSION);
bookmark->insert(ENTRY_AVATAR_URL, avatarUrl);
bookmark->insert(ENTRY_AVATAR_SCALE, avatarScale);
bookmark->insert(ENTRY_AVATAR_ATTACHMENTS, myAvatar->getAttachmentsVariant());
Bookmarks::addBookmarkToFile(bookmarkName, *bookmark);
} }
void AvatarBookmarks::addBookmarkToMenu(Menu* menubar, const QString& name, const QString& address) { void AvatarBookmarks::addBookmarkToMenu(Menu* menubar, const QString& name, const QVariant& bookmark) {
QAction* changeAction = _bookmarksMenu->newAction(); QAction* changeAction = _bookmarksMenu->newAction();
changeAction->setData(address); changeAction->setData(bookmark);
connect(changeAction, SIGNAL(triggered()), this, SLOT(changeToBookmarkedAvatar())); connect(changeAction, SIGNAL(triggered()), this, SLOT(changeToBookmarkedAvatar()));
if (!_isMenuSorted) { if (!_isMenuSorted) {
menubar->addActionToQMenuAndActionHash(_bookmarksMenu, changeAction, name, 0, QAction::NoRole); menubar->addActionToQMenuAndActionHash(_bookmarksMenu, changeAction, name, 0, QAction::NoRole);

View file

@ -21,18 +21,23 @@ class AvatarBookmarks: public Bookmarks, public Dependency {
public: public:
AvatarBookmarks(); AvatarBookmarks();
void setupMenus(Menu* menubar, MenuWrapper* menu) override; void setupMenus(Menu* menubar, MenuWrapper* menu) override;
public slots: public slots:
void addBookmark(); void addBookmark();
protected: protected:
void addBookmarkToMenu(Menu* menubar, const QString& name, const QString& address) override; void addBookmarkToMenu(Menu* menubar, const QString& name, const QVariant& bookmark) override;
void readFromFile(); void readFromFile() override;
private: private:
const QString AVATARBOOKMARKS_FILENAME = "avatarbookmarks.json"; const QString AVATARBOOKMARKS_FILENAME = "avatarbookmarks.json";
const QString ENTRY_AVATAR_URL = "avatarUrl";
const QString ENTRY_AVATAR_ATTACHMENTS = "attachments";
const QString ENTRY_AVATAR_SCALE = "avatarScale";
const QString ENTRY_VERSION = "version";
const int AVATAR_BOOKMARK_VERSION = 3;
private slots: private slots:
void changeToBookmarkedAvatar(); void changeToBookmarkedAvatar();

View file

@ -28,19 +28,6 @@ Bookmarks::Bookmarks() :
_isMenuSorted(false) _isMenuSorted(false)
{ {
} }
void Bookmarks::setupMenus(Menu* menubar, MenuWrapper* menu) {
// Enable/Disable menus as needed
enableMenuItems(_bookmarks.count() > 0);
// Load Bookmarks
for (auto it = _bookmarks.begin(); it != _bookmarks.end(); ++it) {
QString bookmarkName = it.key();
QString bookmarkAddress = it.value().toString();
addBookmarkToMenu(menubar, bookmarkName, bookmarkAddress);
}
}
void Bookmarks::deleteBookmark() { void Bookmarks::deleteBookmark() {
QStringList bookmarkList; QStringList bookmarkList;
QList<QAction*> menuItems = _bookmarksMenu->actions(); QList<QAction*> menuItems = _bookmarksMenu->actions();
@ -67,7 +54,7 @@ void Bookmarks::deleteBookmark() {
} }
} }
void Bookmarks::addBookmarkToFile(const QString& bookmarkName, const QString& bookmarkAddress) { void Bookmarks::addBookmarkToFile(const QString& bookmarkName, const QVariant& bookmark) {
Menu* menubar = Menu::getInstance(); Menu* menubar = Menu::getInstance();
if (contains(bookmarkName)) { if (contains(bookmarkName)) {
auto offscreenUi = DependencyManager::get<OffscreenUi>(); auto offscreenUi = DependencyManager::get<OffscreenUi>();
@ -75,7 +62,6 @@ void Bookmarks::addBookmarkToFile(const QString& bookmarkName, const QString& bo
"The bookmark name you entered already exists in your list.", "The bookmark name you entered already exists in your list.",
QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes); QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes);
duplicateBookmarkMessage->setProperty("informativeText", "Would you like to overwrite it?"); duplicateBookmarkMessage->setProperty("informativeText", "Would you like to overwrite it?");
auto result = offscreenUi->waitForMessageBoxResult(duplicateBookmarkMessage); auto result = offscreenUi->waitForMessageBoxResult(duplicateBookmarkMessage);
if (result != QMessageBox::Yes) { if (result != QMessageBox::Yes) {
return; return;
@ -83,19 +69,20 @@ void Bookmarks::addBookmarkToFile(const QString& bookmarkName, const QString& bo
removeBookmarkFromMenu(menubar, bookmarkName); removeBookmarkFromMenu(menubar, bookmarkName);
} }
addBookmarkToMenu(menubar, bookmarkName, bookmarkAddress); addBookmarkToMenu(menubar, bookmarkName, bookmark);
insert(bookmarkName, bookmarkAddress); // Overwrites any item with the same bookmarkName. insert(bookmarkName, bookmark); // Overwrites any item with the same bookmarkName.
enableMenuItems(true); enableMenuItems(true);
} }
void Bookmarks::insert(const QString& name, const QString& address) { void Bookmarks::insert(const QString& name, const QVariant& bookmark) {
_bookmarks.insert(name, address); _bookmarks.insert(name, bookmark);
if (contains(name)) { if (contains(name)) {
qCDebug(interfaceapp) << "Added bookmark:" << name << "," << address; qCDebug(interfaceapp) << "Added bookmark:" << name;
persistToFile(); persistToFile();
} else { }
qWarning() << "Couldn't add bookmark: " << name << "," << address; else {
qWarning() << "Couldn't add bookmark: " << name;
} }
} }

View file

@ -27,18 +27,20 @@ class Bookmarks: public QObject {
public: public:
Bookmarks(); Bookmarks();
virtual void setupMenus(Menu* menubar, MenuWrapper* menu); virtual void setupMenus(Menu* menubar, MenuWrapper* menu) = 0;
QString addressForBookmark(const QString& name) const; QString addressForBookmark(const QString& name) const;
protected: protected:
virtual void addBookmarkToFile(const QString& bookmarkName, const QString& bookmarkAddress); void addBookmarkToFile(const QString& bookmarkName, const QVariant& bookmark);
virtual void addBookmarkToMenu(Menu* menubar, const QString& name, const QString& address) = 0; virtual void addBookmarkToMenu(Menu* menubar, const QString& name, const QVariant& bookmark) = 0;
void enableMenuItems(bool enabled); void enableMenuItems(bool enabled);
void readFromFile(); virtual void readFromFile();
void insert(const QString& name, const QString& address); // Overwrites any existing entry with same name. void insert(const QString& name, const QVariant& address); // Overwrites any existing entry with same name.
void sortActions(Menu* menubar, MenuWrapper* menu); void sortActions(Menu* menubar, MenuWrapper* menu);
int getMenuItemLocation(QList<QAction*> actions, const QString& name) const; int getMenuItemLocation(QList<QAction*> actions, const QString& name) const;
bool contains(const QString& name) const;
QVariantMap _bookmarks; // { name: url, ... } QVariantMap _bookmarks; // { name: url, ... }
QPointer<MenuWrapper> _bookmarksMenu; QPointer<MenuWrapper> _bookmarksMenu;
QPointer<QAction> _deleteBookmarksAction; QPointer<QAction> _deleteBookmarksAction;
@ -50,7 +52,6 @@ protected slots:
private: private:
void remove(const QString& name); void remove(const QString& name);
bool contains(const QString& name) const;
static bool sortOrder(QAction* a, QAction* b); static bool sortOrder(QAction* a, QAction* b);
void persistToFile(); void persistToFile();

View file

@ -41,13 +41,25 @@ void LocationBookmarks::setupMenus(Menu* menubar, MenuWrapper* menu) {
_deleteBookmarksAction = menubar->addActionToQMenuAndActionHash(menu, MenuOption::DeleteBookmark); _deleteBookmarksAction = menubar->addActionToQMenuAndActionHash(menu, MenuOption::DeleteBookmark);
QObject::connect(_deleteBookmarksAction, SIGNAL(triggered()), this, SLOT(deleteBookmark()), Qt::QueuedConnection); QObject::connect(_deleteBookmarksAction, SIGNAL(triggered()), this, SLOT(deleteBookmark()), Qt::QueuedConnection);
Bookmarks::setupMenus(menubar, menu); // Legacy Location to Bookmark.
// Enable/Disable menus as needed
enableMenuItems(_bookmarks.count() > 0);
// Load Bookmarks
for (auto it = _bookmarks.begin(); it != _bookmarks.end(); ++it) {
QString bookmarkName = it.key();
QString bookmarkAddress = it.value().toString();
addBookmarkToMenu(menubar, bookmarkName, bookmarkAddress);
}
Bookmarks::sortActions(menubar, _bookmarksMenu); Bookmarks::sortActions(menubar, _bookmarksMenu);
} }
void LocationBookmarks::setHomeLocation() { void LocationBookmarks::setHomeLocation() {
auto addressManager = DependencyManager::get<AddressManager>(); auto addressManager = DependencyManager::get<AddressManager>();
QString bookmarkAddress = addressManager->currentAddress().toString(); QString bookmarkAddress = addressManager->currentAddress().toString();
Bookmarks::addBookmarkToFile(HOME_BOOKMARK, bookmarkAddress); Bookmarks::addBookmarkToFile(HOME_BOOKMARK, bookmarkAddress);
} }
@ -74,7 +86,7 @@ void LocationBookmarks::addBookmark() {
Bookmarks::addBookmarkToFile(bookmarkName, bookmarkAddress); Bookmarks::addBookmarkToFile(bookmarkName, bookmarkAddress);
} }
void LocationBookmarks::addBookmarkToMenu(Menu* menubar, const QString& name, const QString& address) { void LocationBookmarks::addBookmarkToMenu(Menu* menubar, const QString& name, const QVariant& address) {
QAction* teleportAction = _bookmarksMenu->newAction(); QAction* teleportAction = _bookmarksMenu->newAction();
teleportAction->setData(address); teleportAction->setData(address);
connect(teleportAction, SIGNAL(triggered()), this, SLOT(teleportToBookmark())); connect(teleportAction, SIGNAL(triggered()), this, SLOT(teleportToBookmark()));
@ -85,4 +97,4 @@ void LocationBookmarks::addBookmarkToMenu(Menu* menubar, const QString& name, co
menubar->addActionToQMenuAndActionHash(_bookmarksMenu, teleportAction, name, 0, QAction::NoRole); menubar->addActionToQMenuAndActionHash(_bookmarksMenu, teleportAction, name, 0, QAction::NoRole);
Bookmarks::sortActions(menubar, _bookmarksMenu); Bookmarks::sortActions(menubar, _bookmarksMenu);
} }
} }

View file

@ -29,7 +29,7 @@ public slots:
void addBookmark(); void addBookmark();
protected: protected:
void addBookmarkToMenu(Menu* menubar, const QString& name, const QString& address) override; void addBookmarkToMenu(Menu* menubar, const QString& name, const QVariant& address) override;
private: private:
const QString LOCATIONBOOKMARKS_FILENAME = "bookmarks.json"; const QString LOCATIONBOOKMARKS_FILENAME = "bookmarks.json";

View file

@ -566,9 +566,6 @@ Menu::Menu() {
addCheckableActionToQMenuAndActionHash(handOptionsMenu, MenuOption::DisplayHandTargets, 0, false, addCheckableActionToQMenuAndActionHash(handOptionsMenu, MenuOption::DisplayHandTargets, 0, false,
avatar.get(), SLOT(setEnableDebugDrawHandControllers(bool))); avatar.get(), SLOT(setEnableDebugDrawHandControllers(bool)));
MenuWrapper* leapOptionsMenu = handOptionsMenu->addMenu("Leap Motion");
addCheckableActionToQMenuAndActionHash(leapOptionsMenu, MenuOption::LeapMotionOnHMD, 0, false);
// Developer > Entities >>> // Developer > Entities >>>
MenuWrapper* entitiesOptionsMenu = developerMenu->addMenu("Entities"); MenuWrapper* entitiesOptionsMenu = developerMenu->addMenu("Entities");

View file

@ -114,7 +114,6 @@ namespace MenuOption {
const QString IncreaseAvatarSize = "Increase Avatar Size"; const QString IncreaseAvatarSize = "Increase Avatar Size";
const QString IndependentMode = "Independent Mode"; const QString IndependentMode = "Independent Mode";
const QString ActionMotorControl = "Enable Default Motor Control"; const QString ActionMotorControl = "Enable Default Motor Control";
const QString LeapMotionOnHMD = "Leap Motion on HMD";
const QString LoadScript = "Open and Run Script File..."; const QString LoadScript = "Open and Run Script File...";
const QString LoadScriptURL = "Open and Run Script from URL..."; const QString LoadScriptURL = "Open and Run Script from URL...";
const QString LodTools = "LOD Tools"; const QString LodTools = "LOD Tools";

View file

@ -79,6 +79,7 @@ public:
gpu::doInBatch(args->_context, [&](gpu::Batch& batch) { gpu::doInBatch(args->_context, [&](gpu::Batch& batch) {
batch.disableContextStereo(); batch.disableContextStereo();
batch.disableContextViewCorrection();
}); });
auto srcViewFrustum = args->getViewFrustum(); auto srcViewFrustum = args->getViewFrustum();
@ -112,6 +113,7 @@ public:
gpu::doInBatch(args->_context, [&](gpu::Batch& batch) { gpu::doInBatch(args->_context, [&](gpu::Batch& batch) {
batch.restoreContextStereo(); batch.restoreContextStereo();
batch.restoreContextViewCorrection();
}); });
} }
}; };

View file

@ -25,6 +25,7 @@
#endif #endif
#include <shared/QtHelpers.h>
#include <AvatarData.h> #include <AvatarData.h>
#include <PerfStat.h> #include <PerfStat.h>
#include <RegisteredMetaTypes.h> #include <RegisteredMetaTypes.h>
@ -482,7 +483,7 @@ RayToAvatarIntersectionResult AvatarManager::findRayIntersection(const PickRay&
const QScriptValue& avatarIdsToDiscard) { const QScriptValue& avatarIdsToDiscard) {
RayToAvatarIntersectionResult result; RayToAvatarIntersectionResult result;
if (QThread::currentThread() != thread()) { if (QThread::currentThread() != thread()) {
QMetaObject::invokeMethod(const_cast<AvatarManager*>(this), "findRayIntersection", Qt::BlockingQueuedConnection, BLOCKING_INVOKE_METHOD(const_cast<AvatarManager*>(this), "findRayIntersection",
Q_RETURN_ARG(RayToAvatarIntersectionResult, result), Q_RETURN_ARG(RayToAvatarIntersectionResult, result),
Q_ARG(const PickRay&, ray), Q_ARG(const PickRay&, ray),
Q_ARG(const QScriptValue&, avatarIdsToInclude), Q_ARG(const QScriptValue&, avatarIdsToInclude),

View file

@ -21,6 +21,7 @@
#include <QtCore/QTimer> #include <QtCore/QTimer>
#include <shared/QtHelpers.h>
#include <scripting/HMDScriptingInterface.h> #include <scripting/HMDScriptingInterface.h>
#include <AccountManager.h> #include <AccountManager.h>
#include <AddressManager.h> #include <AddressManager.h>
@ -897,7 +898,7 @@ void MyAvatar::restoreAnimation() {
QStringList MyAvatar::getAnimationRoles() { QStringList MyAvatar::getAnimationRoles() {
if (QThread::currentThread() != thread()) { if (QThread::currentThread() != thread()) {
QStringList result; QStringList result;
QMetaObject::invokeMethod(this, "getAnimationRoles", Qt::BlockingQueuedConnection, Q_RETURN_ARG(QStringList, result)); BLOCKING_INVOKE_METHOD(this, "getAnimationRoles", Q_RETURN_ARG(QStringList, result));
return result; return result;
} }
return _skeletonModel->getRig().getAnimationRoles(); return _skeletonModel->getRig().getAnimationRoles();
@ -1368,7 +1369,7 @@ void MyAvatar::resetFullAvatarURL() {
void MyAvatar::useFullAvatarURL(const QUrl& fullAvatarURL, const QString& modelName) { void MyAvatar::useFullAvatarURL(const QUrl& fullAvatarURL, const QString& modelName) {
if (QThread::currentThread() != thread()) { if (QThread::currentThread() != thread()) {
QMetaObject::invokeMethod(this, "useFullAvatarURL", Qt::BlockingQueuedConnection, BLOCKING_INVOKE_METHOD(this, "useFullAvatarURL",
Q_ARG(const QUrl&, fullAvatarURL), Q_ARG(const QUrl&, fullAvatarURL),
Q_ARG(const QString&, modelName)); Q_ARG(const QString&, modelName));
return; return;
@ -1394,7 +1395,7 @@ void MyAvatar::useFullAvatarURL(const QUrl& fullAvatarURL, const QString& modelN
void MyAvatar::setAttachmentData(const QVector<AttachmentData>& attachmentData) { void MyAvatar::setAttachmentData(const QVector<AttachmentData>& attachmentData) {
if (QThread::currentThread() != thread()) { if (QThread::currentThread() != thread()) {
QMetaObject::invokeMethod(this, "setAttachmentData", Qt::BlockingQueuedConnection, BLOCKING_INVOKE_METHOD(this, "setAttachmentData",
Q_ARG(const QVector<AttachmentData>, attachmentData)); Q_ARG(const QVector<AttachmentData>, attachmentData));
return; return;
} }
@ -1455,6 +1456,19 @@ controller::Pose MyAvatar::getRightHandControllerPoseInAvatarFrame() const {
return getRightHandControllerPoseInWorldFrame().transform(invAvatarMatrix); return getRightHandControllerPoseInWorldFrame().transform(invAvatarMatrix);
} }
void MyAvatar::setFingerControllerPosesInSensorFrame(const FingerPosesMap& left, const FingerPosesMap& right) {
_leftHandFingerPosesInSensorFramceCache.set(left);
_rightHandFingerPosesInSensorFramceCache.set(right);
}
MyAvatar::FingerPosesMap MyAvatar::getLeftHandFingerControllerPosesInSensorFrame() const {
return _leftHandFingerPosesInSensorFramceCache.get();
}
MyAvatar::FingerPosesMap MyAvatar::getRightHandFingerControllerPosesInSensorFrame() const {
return _rightHandFingerPosesInSensorFramceCache.get();
}
void MyAvatar::setFootControllerPosesInSensorFrame(const controller::Pose& left, const controller::Pose& right) { void MyAvatar::setFootControllerPosesInSensorFrame(const controller::Pose& left, const controller::Pose& right) {
_leftFootControllerPoseInSensorFrameCache.set(left); _leftFootControllerPoseInSensorFrameCache.set(left);
_rightFootControllerPoseInSensorFrameCache.set(right); _rightFootControllerPoseInSensorFrameCache.set(right);
@ -1620,7 +1634,8 @@ void MyAvatar::prepareForPhysicsSimulation() {
_characterController.setParentVelocity(parentVelocity); _characterController.setParentVelocity(parentVelocity);
_characterController.setPositionAndOrientation(getPosition(), getOrientation()); _characterController.setPositionAndOrientation(getPosition(), getOrientation());
if (qApp->isHMDMode()) { auto headPose = getHeadControllerPoseInAvatarFrame();
if (headPose.isValid()) {
_follow.prePhysicsUpdate(*this, deriveBodyFromHMDSensor(), _bodySensorMatrix, hasDriveInput()); _follow.prePhysicsUpdate(*this, deriveBodyFromHMDSensor(), _bodySensorMatrix, hasDriveInput());
} else { } else {
_follow.deactivate(); _follow.deactivate();
@ -2358,7 +2373,7 @@ bool MyAvatar::safeLanding(const glm::vec3& position) {
if (QThread::currentThread() != thread()) { if (QThread::currentThread() != thread()) {
bool result; bool result;
QMetaObject::invokeMethod(this, "safeLanding", Qt::BlockingQueuedConnection, Q_RETURN_ARG(bool, result), Q_ARG(const glm::vec3&, position)); BLOCKING_INVOKE_METHOD(this, "safeLanding", Q_RETURN_ARG(bool, result), Q_ARG(const glm::vec3&, position));
return result; return result;
} }
glm::vec3 better; glm::vec3 better;
@ -2524,6 +2539,21 @@ bool MyAvatar::getFlyingEnabled() {
return _enableFlying; return _enableFlying;
} }
// Public interface for targetscale
float MyAvatar::getAvatarScale() {
return getTargetScale();
}
void MyAvatar::setAvatarScale(float val) {
if (QThread::currentThread() != thread()) {
QMetaObject::invokeMethod(this, "setAvatarScale", Q_ARG(float, val));
return;
}
setTargetScale(val);
}
void MyAvatar::setCollisionsEnabled(bool enabled) { void MyAvatar::setCollisionsEnabled(bool enabled) {
if (QThread::currentThread() != thread()) { if (QThread::currentThread() != thread()) {

View file

@ -366,7 +366,7 @@ public:
float getDriveKey(DriveKeys key) const; float getDriveKey(DriveKeys key) const;
Q_INVOKABLE float getRawDriveKey(DriveKeys key) const; Q_INVOKABLE float getRawDriveKey(DriveKeys key) const;
void relayDriveKeysToCharacterController(); void relayDriveKeysToCharacterController();
Q_INVOKABLE void disableDriveKey(DriveKeys key); Q_INVOKABLE void disableDriveKey(DriveKeys key);
Q_INVOKABLE void enableDriveKey(DriveKeys key); Q_INVOKABLE void enableDriveKey(DriveKeys key);
Q_INVOKABLE bool isDriveKeyDisabled(DriveKeys key) const; Q_INVOKABLE bool isDriveKeyDisabled(DriveKeys key) const;
@ -474,6 +474,11 @@ public:
controller::Pose getLeftHandControllerPoseInAvatarFrame() const; controller::Pose getLeftHandControllerPoseInAvatarFrame() const;
controller::Pose getRightHandControllerPoseInAvatarFrame() const; controller::Pose getRightHandControllerPoseInAvatarFrame() const;
typedef std::map<int, std::pair<controller::Pose, QString>> FingerPosesMap;
void setFingerControllerPosesInSensorFrame(const FingerPosesMap& left, const FingerPosesMap& right);
FingerPosesMap getLeftHandFingerControllerPosesInSensorFrame() const;
FingerPosesMap getRightHandFingerControllerPosesInSensorFrame() const;
void setFootControllerPosesInSensorFrame(const controller::Pose& left, const controller::Pose& right); void setFootControllerPosesInSensorFrame(const controller::Pose& left, const controller::Pose& right);
controller::Pose getLeftFootControllerPoseInSensorFrame() const; controller::Pose getLeftFootControllerPoseInSensorFrame() const;
controller::Pose getRightFootControllerPoseInSensorFrame() const; controller::Pose getRightFootControllerPoseInSensorFrame() const;
@ -512,6 +517,9 @@ public:
Q_INVOKABLE void setFlyingEnabled(bool enabled); Q_INVOKABLE void setFlyingEnabled(bool enabled);
Q_INVOKABLE bool getFlyingEnabled(); Q_INVOKABLE bool getFlyingEnabled();
Q_INVOKABLE float getAvatarScale();
Q_INVOKABLE void setAvatarScale(float scale);
Q_INVOKABLE void setCollisionsEnabled(bool enabled); Q_INVOKABLE void setCollisionsEnabled(bool enabled);
Q_INVOKABLE bool getCollisionsEnabled(); Q_INVOKABLE bool getCollisionsEnabled();
Q_INVOKABLE void setCharacterControllerEnabled(bool enabled); // deprecated Q_INVOKABLE void setCharacterControllerEnabled(bool enabled); // deprecated
@ -788,13 +796,15 @@ private:
// These are stored in SENSOR frame // These are stored in SENSOR frame
ThreadSafeValueCache<controller::Pose> _leftHandControllerPoseInSensorFrameCache { controller::Pose() }; ThreadSafeValueCache<controller::Pose> _leftHandControllerPoseInSensorFrameCache { controller::Pose() };
ThreadSafeValueCache<controller::Pose> _rightHandControllerPoseInSensorFrameCache { controller::Pose() }; ThreadSafeValueCache<controller::Pose> _rightHandControllerPoseInSensorFrameCache { controller::Pose() };
ThreadSafeValueCache<controller::Pose> _leftFootControllerPoseInSensorFrameCache{ controller::Pose() }; ThreadSafeValueCache<FingerPosesMap> _leftHandFingerPosesInSensorFramceCache { };
ThreadSafeValueCache<controller::Pose> _rightFootControllerPoseInSensorFrameCache{ controller::Pose() }; ThreadSafeValueCache<FingerPosesMap> _rightHandFingerPosesInSensorFramceCache { };
ThreadSafeValueCache<controller::Pose> _hipsControllerPoseInSensorFrameCache{ controller::Pose() }; ThreadSafeValueCache<controller::Pose> _leftFootControllerPoseInSensorFrameCache { controller::Pose() };
ThreadSafeValueCache<controller::Pose> _spine2ControllerPoseInSensorFrameCache{ controller::Pose() }; ThreadSafeValueCache<controller::Pose> _rightFootControllerPoseInSensorFrameCache { controller::Pose() };
ThreadSafeValueCache<controller::Pose> _headControllerPoseInSensorFrameCache{ controller::Pose() }; ThreadSafeValueCache<controller::Pose> _hipsControllerPoseInSensorFrameCache { controller::Pose() };
ThreadSafeValueCache<controller::Pose> _leftArmControllerPoseInSensorFrameCache{ controller::Pose() }; ThreadSafeValueCache<controller::Pose> _spine2ControllerPoseInSensorFrameCache { controller::Pose() };
ThreadSafeValueCache<controller::Pose> _rightArmControllerPoseInSensorFrameCache{ controller::Pose() }; ThreadSafeValueCache<controller::Pose> _headControllerPoseInSensorFrameCache { controller::Pose() };
ThreadSafeValueCache<controller::Pose> _leftArmControllerPoseInSensorFrameCache { controller::Pose() };
ThreadSafeValueCache<controller::Pose> _rightArmControllerPoseInSensorFrameCache { controller::Pose() };
bool _hmdLeanRecenterEnabled = true; bool _hmdLeanRecenterEnabled = true;
AnimPose _prePhysicsRoomPose; AnimPose _prePhysicsRoomPose;

View file

@ -96,7 +96,7 @@ void MySkeletonModel::updateRig(float deltaTime, glm::mat4 parentTransform) {
params.controllerPoses[Rig::ControllerType_RightArm] = AnimPose::identity; params.controllerPoses[Rig::ControllerType_RightArm] = AnimPose::identity;
params.controllerActiveFlags[Rig::ControllerType_RightArm] = false; params.controllerActiveFlags[Rig::ControllerType_RightArm] = false;
} }
auto avatarLeftArmPose = myAvatar->getLeftArmControllerPoseInAvatarFrame(); auto avatarLeftArmPose = myAvatar->getLeftArmControllerPoseInAvatarFrame();
if (avatarLeftArmPose.isValid()) { if (avatarLeftArmPose.isValid()) {
AnimPose pose(avatarLeftArmPose.getRotation(), avatarLeftArmPose.getTranslation()); AnimPose pose(avatarLeftArmPose.getRotation(), avatarLeftArmPose.getTranslation());
@ -174,5 +174,50 @@ void MySkeletonModel::updateRig(float deltaTime, glm::mat4 parentTransform) {
eyeParams.rightEyeJointIndex = geometry.rightEyeJointIndex; eyeParams.rightEyeJointIndex = geometry.rightEyeJointIndex;
_rig.updateFromEyeParameters(eyeParams); _rig.updateFromEyeParameters(eyeParams);
updateFingers(myAvatar->getLeftHandFingerControllerPosesInSensorFrame());
updateFingers(myAvatar->getRightHandFingerControllerPosesInSensorFrame());
} }
void MySkeletonModel::updateFingers(const MyAvatar::FingerPosesMap& fingerPoses) {
// Assumes that finger poses are kept in order in the poses map.
if (fingerPoses.size() == 0) {
return;
}
auto posesMapItr = fingerPoses.begin();
bool isLeftHand = posesMapItr->first < (int)controller::Action::RIGHT_HAND_THUMB1;
MyAvatar* myAvatar = static_cast<MyAvatar*>(_owningAvatar);
auto handPose = isLeftHand
? myAvatar->getLeftHandControllerPoseInSensorFrame()
: myAvatar->getRightHandControllerPoseInSensorFrame();
auto handJointRotation = handPose.getRotation();
bool isHandValid = handPose.isValid();
bool isFingerValid = false;
glm::quat previousJointRotation;
while (posesMapItr != fingerPoses.end()) {
auto jointName = posesMapItr->second.second;
if (isHandValid && jointName.right(1) == "1") {
isFingerValid = posesMapItr->second.first.isValid();
previousJointRotation = handJointRotation;
}
if (isHandValid && isFingerValid) {
auto thisJointRotation = posesMapItr->second.first.getRotation();
const float CONTROLLER_PRIORITY = 2.0f;
_rig.setJointRotation(_rig.indexOfJoint(jointName), true, glm::inverse(previousJointRotation) * thisJointRotation,
CONTROLLER_PRIORITY);
previousJointRotation = thisJointRotation;
} else {
_rig.clearJointAnimationPriority(_rig.indexOfJoint(jointName));
}
posesMapItr++;
}
}

View file

@ -10,6 +10,7 @@
#define hifi_MySkeletonModel_h #define hifi_MySkeletonModel_h
#include <avatars-renderer/SkeletonModel.h> #include <avatars-renderer/SkeletonModel.h>
#include "MyAvatar.h"
/// A skeleton loaded from a model. /// A skeleton loaded from a model.
class MySkeletonModel : public SkeletonModel { class MySkeletonModel : public SkeletonModel {
@ -21,6 +22,9 @@ private:
public: public:
MySkeletonModel(Avatar* owningAvatar, QObject* parent = nullptr); MySkeletonModel(Avatar* owningAvatar, QObject* parent = nullptr);
void updateRig(float deltaTime, glm::mat4 parentTransform) override; void updateRig(float deltaTime, glm::mat4 parentTransform) override;
private:
void updateFingers(const MyAvatar::FingerPosesMap& fingerPoses);
}; };
#endif // hifi_MySkeletonModel_h #endif // hifi_MySkeletonModel_h

View file

@ -1,246 +0,0 @@
//
// Created by Sam Cake on 6/2/2014
// Copyright 2014 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
//
#include "Leapmotion.h"
#include <NumericalConstants.h>
#include "Menu.h"
const int PALMROOT_NUM_JOINTS = 3;
const int FINGER_NUM_JOINTS = 4;
const int HAND_NUM_JOINTS = FINGER_NUM_JOINTS*5+PALMROOT_NUM_JOINTS;
const DeviceTracker::Name Leapmotion::NAME = "Leapmotion";
// find the index of a joint from
// the side: true = right
// the finger & the bone:
// finger in [0..4] : bone in [0..3] a finger phalange
// [-1] up the hand branch : bone in [0..2] <=> [ hand, forearm, arm]
MotionTracker::Index evalJointIndex(bool isRightSide, int finger, int bone) {
MotionTracker::Index offset = 1 // start after root
+ (int(isRightSide) * HAND_NUM_JOINTS) // then offset for side
+ PALMROOT_NUM_JOINTS; // then add the arm/forearm/hand chain
if (finger >= 0) {
// from there go down in the correct finger and bone
return offset + (finger * FINGER_NUM_JOINTS) + bone;
} else {
// or go back up for the correct root bone
return offset - 1 - bone;
}
}
// static
void Leapmotion::init() {
DeviceTracker* device = DeviceTracker::getDevice(NAME);
if (!device) {
// create a new Leapmotion and register it
Leapmotion* leap = new Leapmotion();
DeviceTracker::registerDevice(NAME, leap);
}
}
// static
void Leapmotion::destroy() {
DeviceTracker::destroyDevice(NAME);
}
// static
Leapmotion* Leapmotion::getInstance() {
DeviceTracker* device = DeviceTracker::getDevice(NAME);
if (!device) {
// create a new Leapmotion and register it
device = new Leapmotion();
DeviceTracker::registerDevice(NAME, device);
}
return dynamic_cast< Leapmotion* > (device);
}
Leapmotion::Leapmotion() :
MotionTracker(),
_active(false)
{
// Create the Leapmotion joint hierarchy
std::vector< Semantic > sides;
sides.push_back("joint_L_");
sides.push_back("joint_R_");
std::vector< Semantic > rootBones;
rootBones.push_back("elbow");
rootBones.push_back("wrist");
rootBones.push_back("hand");
std::vector< Semantic > fingers;
fingers.push_back("thumb");
fingers.push_back("index");
fingers.push_back("middle");
fingers.push_back("ring");
fingers.push_back("pinky");
std::vector< Semantic > fingerBones;
fingerBones.push_back("1");
fingerBones.push_back("2");
fingerBones.push_back("3");
fingerBones.push_back("4");
std::vector< Index > palms;
for (unsigned int s = 0; s < sides.size(); s++) {
Index rootJoint = 0;
for (unsigned int rb = 0; rb < rootBones.size(); rb++) {
rootJoint = addJoint(sides[s] + rootBones[rb], rootJoint);
}
// capture the hand index for debug
palms.push_back(rootJoint);
for (unsigned int f = 0; f < fingers.size(); f++) {
for (unsigned int b = 0; b < fingerBones.size(); b++) {
rootJoint = addJoint(sides[s] + fingers[f] + fingerBones[b], rootJoint);
}
}
}
#ifdef HAVE_LEAPMOTION
if (Menu::getInstance()->isOptionChecked(MenuOption::LeapMotionOnHMD)) {
_controller.setPolicyFlags(Leap::Controller::POLICY_OPTIMIZE_HMD);
}
#endif
}
Leapmotion::~Leapmotion() {
}
#ifdef HAVE_LEAPMOTION
glm::quat quatFromLeapBase(float sideSign, const Leap::Matrix& basis) {
// fix the handness to right and always...
glm::vec3 xAxis = glm::normalize(sideSign * glm::vec3(basis.xBasis.x, basis.xBasis.y, basis.xBasis.z));
glm::vec3 yAxis = glm::normalize(glm::vec3(basis.yBasis.x, basis.yBasis.y, basis.yBasis.z));
glm::vec3 zAxis = glm::normalize(glm::vec3(basis.zBasis.x, basis.zBasis.y, basis.zBasis.z));
xAxis = glm::normalize(glm::cross(yAxis, zAxis));
glm::quat orientation = (glm::quat_cast(glm::mat3(xAxis, yAxis, zAxis)));
return orientation;
}
glm::vec3 vec3FromLeapVector(const Leap::Vector& vec) {
return glm::vec3(vec.x * METERS_PER_MILLIMETER, vec.y * METERS_PER_MILLIMETER, vec.z * METERS_PER_MILLIMETER);
}
#endif
void Leapmotion::update() {
#ifdef HAVE_LEAPMOTION
bool wasActive = _active;
_active = _controller.isConnected();
if (_active || wasActive) {
// Go through all the joints and increment their counter since last update.
// Increment all counters once after controller first becomes inactive so that each joint reports itself as inactive.
// TODO C++11 for (auto jointIt = _jointsArray.begin(); jointIt != _jointsArray.end(); jointIt++) {
for (JointTracker::Vector::iterator jointIt = _jointsArray.begin(); jointIt != _jointsArray.end(); jointIt++) {
(*jointIt).tickNewFrame();
}
}
if (!_active) {
return;
}
// Get the most recent frame and report some basic information
const Leap::Frame frame = _controller.frame();
static int64_t lastFrameID = -1;
int64_t newFrameID = frame.id();
// If too soon then exit
if (lastFrameID >= newFrameID)
return;
glm::vec3 delta(0.0f);
glm::quat handOri;
if (!frame.hands().isEmpty()) {
for (int handNum = 0; handNum < frame.hands().count(); handNum++) {
const Leap::Hand hand = frame.hands()[handNum];
int side = (hand.isRight() ? 1 : -1);
JointTracker* parentJointTracker = _jointsArray.data();
int rootBranchIndex = -1;
Leap::Arm arm = hand.arm();
if (arm.isValid()) {
glm::quat ori = quatFromLeapBase(float(side), arm.basis());
glm::vec3 pos = vec3FromLeapVector(arm.elbowPosition());
JointTracker* elbow = editJointTracker(evalJointIndex((side > 0), rootBranchIndex, 2)); // 2 is the index of the elbow joint
elbow->editAbsFrame().setTranslation(pos);
elbow->editAbsFrame().setRotation(ori);
elbow->updateLocFromAbsTransform(parentJointTracker);
elbow->activeFrame();
parentJointTracker = elbow;
pos = vec3FromLeapVector(arm.wristPosition());
JointTracker* wrist = editJointTracker(evalJointIndex((side > 0), rootBranchIndex, 1)); // 1 is the index of the wrist joint
wrist->editAbsFrame().setTranslation(pos);
wrist->editAbsFrame().setRotation(ori);
wrist->updateLocFromAbsTransform(parentJointTracker);
wrist->activeFrame();
parentJointTracker = wrist;
}
JointTracker* palmJoint = NULL;
{
glm::vec3 pos = vec3FromLeapVector(hand.palmPosition());
glm::quat ori = quatFromLeapBase(float(side), hand.basis());
palmJoint = editJointTracker(evalJointIndex((side > 0), rootBranchIndex, 0)); // 0 is the index of the palm joint
palmJoint->editAbsFrame().setTranslation(pos);
palmJoint->editAbsFrame().setRotation(ori);
palmJoint->updateLocFromAbsTransform(parentJointTracker);
palmJoint->activeFrame();
}
// Check if the hand has any fingers
const Leap::FingerList fingers = hand.fingers();
if (!fingers.isEmpty()) {
// For every fingers in the list
for (int i = 0; i < fingers.count(); ++i) {
// Reset the parent joint to the palmJoint for every finger traversal
parentJointTracker = palmJoint;
// surprisingly, Leap::Finger::Type start at 0 for thumb a until 4 for the pinky
Index fingerIndex = evalJointIndex((side > 0), int(fingers[i].type()), 0);
// let's update the finger's joints
for (int b = 0; b < FINGER_NUM_JOINTS; b++) {
Leap::Bone::Type type = Leap::Bone::Type(b + Leap::Bone::TYPE_METACARPAL);
Leap::Bone bone = fingers[i].bone(type);
JointTracker* ljointTracker = editJointTracker(fingerIndex + b);
if (bone.isValid()) {
Leap::Vector bp = bone.nextJoint();
ljointTracker->editAbsFrame().setTranslation(vec3FromLeapVector(bp));
ljointTracker->editAbsFrame().setRotation(quatFromLeapBase(float(side), bone.basis()));
ljointTracker->updateLocFromAbsTransform(parentJointTracker);
ljointTracker->activeFrame();
}
parentJointTracker = ljointTracker;
}
}
}
}
}
lastFrameID = newFrameID;
#endif
}

View file

@ -1,48 +0,0 @@
//
// Created by Sam Cake on 6/2/2014
// Copyright 2014 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#ifndef hifi_Leapmotion_h
#define hifi_Leapmotion_h
#include <QDateTime>
#include <trackers/MotionTracker.h>
#ifdef HAVE_LEAPMOTION
#include <Leap.h>
#endif
/// Handles interaction with the Leapmotion skeleton tracking suit.
class Leapmotion : public MotionTracker {
public:
static const Name NAME;
static void init();
static void destroy();
/// Leapmotion MotionTracker factory
static Leapmotion* getInstance();
bool isActive() const { return _active; }
virtual void update() override;
protected:
Leapmotion();
virtual ~Leapmotion();
private:
#ifdef HAVE_LEAPMOTION
Leap::Listener _listener;
Leap::Controller _controller;
#endif
bool _active;
};
#endif // hifi_Leapmotion_h

View file

@ -101,7 +101,7 @@ int main(int argc, const char* argv[]) {
if (allowMultipleInstances) { if (allowMultipleInstances) {
instanceMightBeRunning = false; instanceMightBeRunning = false;
} }
// this needs to be done here in main, as the mechanism for setting the // this needs to be done here in main, as the mechanism for setting the
// scripts directory appears not to work. See the bug report // scripts directory appears not to work. See the bug report
// https://highfidelity.fogbugz.com/f/cases/5759/Issues-changing-scripts-directory-in-ScriptsEngine // https://highfidelity.fogbugz.com/f/cases/5759/Issues-changing-scripts-directory-in-ScriptsEngine
if (parser.isSet(overrideScriptsPathOption)) { if (parser.isSet(overrideScriptsPathOption)) {
@ -111,20 +111,6 @@ int main(int argc, const char* argv[]) {
} }
} }
if (parser.isSet(overrideAppLocalDataPathOption)) {
// get dir to use for cache
QString cacheDir = parser.value(overrideAppLocalDataPathOption);
if (!cacheDir.isEmpty()) {
// tell everyone to use the right cache location
//
// this handles data8 and prepared
DependencyManager::get<ResourceManager>()->setCacheDir(cacheDir);
// this does the ktx_cache
PathUtils::getAppLocalDataPath(cacheDir);
}
}
if (instanceMightBeRunning) { if (instanceMightBeRunning) {
// Try to connect and send message to existing interface instance // Try to connect and send message to existing interface instance
QLocalSocket socket; QLocalSocket socket;

View file

@ -11,6 +11,8 @@
#include "Audio.h" #include "Audio.h"
#include <shared/QtHelpers.h>
#include "Application.h" #include "Application.h"
#include "AudioClient.h" #include "AudioClient.h"
#include "ui/AvatarInputs.h" #include "ui/AvatarInputs.h"
@ -49,27 +51,22 @@ float Audio::loudnessToLevel(float loudness) {
Audio::Audio() : _devices(_contextIsHMD) { Audio::Audio() : _devices(_contextIsHMD) {
auto client = DependencyManager::get<AudioClient>().data(); auto client = DependencyManager::get<AudioClient>().data();
connect(client, &AudioClient::muteToggled, this, &Audio::onMutedChanged); connect(client, &AudioClient::muteToggled, this, &Audio::onMutedChanged);
connect(client, &AudioClient::noiseReductionChanged, this, &Audio::onNoiseReductionChanged);
connect(client, &AudioClient::inputLoudnessChanged, this, &Audio::onInputLoudnessChanged); connect(client, &AudioClient::inputLoudnessChanged, this, &Audio::onInputLoudnessChanged);
connect(client, &AudioClient::inputVolumeChanged, this, &Audio::onInputVolumeChanged);
connect(this, &Audio::contextChanged, &_devices, &AudioDevices::onContextChanged); connect(this, &Audio::contextChanged, &_devices, &AudioDevices::onContextChanged);
connect(&_devices._inputs, &AudioDeviceList::deviceChanged, this, &Audio::onInputChanged);
enableNoiseReduction(enableNoiseReductionSetting.get()); enableNoiseReduction(enableNoiseReductionSetting.get());
} }
void Audio::setMuted(bool isMuted) { void Audio::setMuted(bool isMuted) {
if (_isMuted != isMuted) { if (_isMuted != isMuted) {
auto client = DependencyManager::get<AudioClient>().data(); auto client = DependencyManager::get<AudioClient>().data();
QMetaObject::invokeMethod(client, "toggleMute", Qt::BlockingQueuedConnection); QMetaObject::invokeMethod(client, "toggleMute");
_isMuted = isMuted;
emit mutedChanged(_isMuted);
} }
} }
void Audio::onMutedChanged() { void Audio::onMutedChanged() {
auto client = DependencyManager::get<AudioClient>().data(); bool isMuted = DependencyManager::get<AudioClient>()->isMuted();
bool isMuted;
QMetaObject::invokeMethod(client, "isMuted", Qt::BlockingQueuedConnection, Q_RETURN_ARG(bool, isMuted));
if (_isMuted != isMuted) { if (_isMuted != isMuted) {
_isMuted = isMuted; _isMuted = isMuted;
emit mutedChanged(_isMuted); emit mutedChanged(_isMuted);
@ -79,11 +76,16 @@ void Audio::onMutedChanged() {
void Audio::enableNoiseReduction(bool enable) { void Audio::enableNoiseReduction(bool enable) {
if (_enableNoiseReduction != enable) { if (_enableNoiseReduction != enable) {
auto client = DependencyManager::get<AudioClient>().data(); auto client = DependencyManager::get<AudioClient>().data();
QMetaObject::invokeMethod(client, "setNoiseReduction", Qt::BlockingQueuedConnection, Q_ARG(bool, enable)); QMetaObject::invokeMethod(client, "setNoiseReduction", Q_ARG(bool, enable));
enableNoiseReductionSetting.set(enable); enableNoiseReductionSetting.set(enable);
_enableNoiseReduction = enable; }
emit noiseReductionChanged(enable); }
void Audio::onNoiseReductionChanged() {
bool noiseReductionEnabled = DependencyManager::get<AudioClient>()->isNoiseReductionEnabled();
if (_enableNoiseReduction != noiseReductionEnabled) {
_enableNoiseReduction = noiseReductionEnabled;
emit noiseReductionChanged(_enableNoiseReduction);
} }
} }
@ -93,19 +95,11 @@ void Audio::setInputVolume(float volume) {
if (_inputVolume != volume) { if (_inputVolume != volume) {
auto client = DependencyManager::get<AudioClient>().data(); auto client = DependencyManager::get<AudioClient>().data();
QMetaObject::invokeMethod(client, "setInputVolume", Qt::BlockingQueuedConnection, Q_ARG(float, volume)); QMetaObject::invokeMethod(client, "setInputVolume", Q_ARG(float, volume));
_inputVolume = volume;
emit inputVolumeChanged(_inputVolume);
} }
} }
// different audio input devices may have different volumes void Audio::onInputVolumeChanged(float volume) {
void Audio::onInputChanged() {
auto client = DependencyManager::get<AudioClient>().data();
float volume;
QMetaObject::invokeMethod(client, "getInputVolume", Qt::BlockingQueuedConnection, Q_RETURN_ARG(float, volume));
if (_inputVolume != volume) { if (_inputVolume != volume) {
_inputVolume = volume; _inputVolume = volume;
emit inputVolumeChanged(_inputVolume); emit inputVolumeChanged(_inputVolume);

View file

@ -62,9 +62,12 @@ signals:
void contextChanged(const QString& context); void contextChanged(const QString& context);
public slots: public slots:
void onMutedChanged();
void onContextChanged(); void onContextChanged();
void onInputChanged();
private slots:
void onMutedChanged();
void onNoiseReductionChanged();
void onInputVolumeChanged(float volume);
void onInputLoudnessChanged(float loudness); void onInputLoudnessChanged(float loudness);
protected: protected:

View file

@ -11,6 +11,8 @@
#include <map> #include <map>
#include <shared/QtHelpers.h>
#include "AudioDevices.h" #include "AudioDevices.h"
#include "Application.h" #include "Application.h"
@ -71,22 +73,14 @@ bool AudioDeviceList::setData(const QModelIndex& index, const QVariant& value, i
bool AudioDeviceList::setDevice(int row, bool fromUser) { bool AudioDeviceList::setDevice(int row, bool fromUser) {
bool success = false; bool success = false;
auto& device = _devices[row]; auto& device = _devices[row];
_userSelection = fromUser;
// skip if already selected // skip if already selected
if (!device.selected) { if (!device.selected) {
auto client = DependencyManager::get<AudioClient>(); auto client = DependencyManager::get<AudioClient>();
QMetaObject::invokeMethod(client.data(), "switchAudioDevice", Qt::BlockingQueuedConnection, QMetaObject::invokeMethod(client.data(), "switchAudioDevice",
Q_RETURN_ARG(bool, success),
Q_ARG(QAudio::Mode, _mode), Q_ARG(QAudio::Mode, _mode),
Q_ARG(const QAudioDeviceInfo&, device.info)); Q_ARG(const QAudioDeviceInfo&, device.info));
if (success) {
device.selected = true;
if (fromUser) {
emit deviceSelected(device.info, _selectedDevice);
}
emit deviceChanged(device.info);
}
} }
emit dataChanged(createIndex(0, 0), createIndex(rowCount() - 1, 0)); emit dataChanged(createIndex(0, 0), createIndex(rowCount() - 1, 0));
@ -135,12 +129,12 @@ void AudioDeviceList::resetDevice(bool contextIsHMD, const QString& device) {
} }
void AudioDeviceList::onDeviceChanged(const QAudioDeviceInfo& device) { void AudioDeviceList::onDeviceChanged(const QAudioDeviceInfo& device) {
auto oldDevice = _selectedDevice;
_selectedDevice = device; _selectedDevice = device;
QModelIndex index; QModelIndex index;
for (auto i = 0; i < _devices.size(); ++i) { for (auto i = 0; i < _devices.size(); ++i) {
AudioDevice& device = _devices[i]; AudioDevice& device = _devices[i];
if (device.selected && device.info != _selectedDevice) { if (device.selected && device.info != _selectedDevice) {
device.selected = false; device.selected = false;
} else if (device.info == _selectedDevice) { } else if (device.info == _selectedDevice) {
@ -149,6 +143,11 @@ void AudioDeviceList::onDeviceChanged(const QAudioDeviceInfo& device) {
} }
} }
if (_userSelection) {
_userSelection = false;
emit deviceSelected(_selectedDevice, oldDevice);
}
emit deviceChanged(_selectedDevice); emit deviceChanged(_selectedDevice);
emit dataChanged(createIndex(0, 0), createIndex(rowCount() - 1, 0)); emit dataChanged(createIndex(0, 0), createIndex(rowCount() - 1, 0));
} }

View file

@ -58,7 +58,7 @@ private:
static QHash<int, QByteArray> _roles; static QHash<int, QByteArray> _roles;
static Qt::ItemFlags _flags; static Qt::ItemFlags _flags;
bool _userSelection { false };
QAudio::Mode _mode; QAudio::Mode _mode;
QAudioDeviceInfo _selectedDevice; QAudioDeviceInfo _selectedDevice;
QList<AudioDevice> _devices; QList<AudioDevice> _devices;

View file

@ -8,9 +8,12 @@
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
// //
#include "Application.h"
#include "ClipboardScriptingInterface.h" #include "ClipboardScriptingInterface.h"
#include <shared/QtHelpers.h>
#include "Application.h"
ClipboardScriptingInterface::ClipboardScriptingInterface() { ClipboardScriptingInterface::ClipboardScriptingInterface() {
} }
@ -24,7 +27,7 @@ float ClipboardScriptingInterface::getClipboardContentsLargestDimension() {
bool ClipboardScriptingInterface::exportEntities(const QString& filename, const QVector<EntityItemID>& entityIDs) { bool ClipboardScriptingInterface::exportEntities(const QString& filename, const QVector<EntityItemID>& entityIDs) {
bool retVal; bool retVal;
QMetaObject::invokeMethod(qApp, "exportEntities", Qt::BlockingQueuedConnection, BLOCKING_INVOKE_METHOD(qApp, "exportEntities",
Q_RETURN_ARG(bool, retVal), Q_RETURN_ARG(bool, retVal),
Q_ARG(const QString&, filename), Q_ARG(const QString&, filename),
Q_ARG(const QVector<EntityItemID>&, entityIDs)); Q_ARG(const QVector<EntityItemID>&, entityIDs));
@ -33,7 +36,7 @@ bool ClipboardScriptingInterface::exportEntities(const QString& filename, const
bool ClipboardScriptingInterface::exportEntities(const QString& filename, float x, float y, float z, float s) { bool ClipboardScriptingInterface::exportEntities(const QString& filename, float x, float y, float z, float s) {
bool retVal; bool retVal;
QMetaObject::invokeMethod(qApp, "exportEntities", Qt::BlockingQueuedConnection, BLOCKING_INVOKE_METHOD(qApp, "exportEntities",
Q_RETURN_ARG(bool, retVal), Q_RETURN_ARG(bool, retVal),
Q_ARG(const QString&, filename), Q_ARG(const QString&, filename),
Q_ARG(float, x), Q_ARG(float, x),
@ -45,7 +48,7 @@ bool ClipboardScriptingInterface::exportEntities(const QString& filename, float
bool ClipboardScriptingInterface::importEntities(const QString& filename) { bool ClipboardScriptingInterface::importEntities(const QString& filename) {
bool retVal; bool retVal;
QMetaObject::invokeMethod(qApp, "importEntities", Qt::BlockingQueuedConnection, BLOCKING_INVOKE_METHOD(qApp, "importEntities",
Q_RETURN_ARG(bool, retVal), Q_RETURN_ARG(bool, retVal),
Q_ARG(const QString&, filename)); Q_ARG(const QString&, filename));
return retVal; return retVal;
@ -53,7 +56,7 @@ bool ClipboardScriptingInterface::importEntities(const QString& filename) {
QVector<EntityItemID> ClipboardScriptingInterface::pasteEntities(glm::vec3 position) { QVector<EntityItemID> ClipboardScriptingInterface::pasteEntities(glm::vec3 position) {
QVector<EntityItemID> retVal; QVector<EntityItemID> retVal;
QMetaObject::invokeMethod(qApp, "pasteEntities", Qt::BlockingQueuedConnection, BLOCKING_INVOKE_METHOD(qApp, "pasteEntities",
Q_RETURN_ARG(QVector<EntityItemID>, retVal), Q_RETURN_ARG(QVector<EntityItemID>, retVal),
Q_ARG(float, position.x), Q_ARG(float, position.x),
Q_ARG(float, position.y), Q_ARG(float, position.y),

View file

@ -13,6 +13,10 @@
#include <QObject> #include <QObject>
#include <glm/glm.hpp>
#include <EntityItemID.h>
/**jsdoc /**jsdoc
* @namespace Clipboard * @namespace Clipboard
*/ */

View file

@ -17,7 +17,6 @@
#include <plugins/PluginManager.h> #include <plugins/PluginManager.h>
#include "Application.h" #include "Application.h"
#include <trackers/MotionTracker.h>
void ControllerScriptingInterface::handleMetaEvent(HFMetaEvent* event) { void ControllerScriptingInterface::handleMetaEvent(HFMetaEvent* event) {
if (event->type() == HFActionEvent::startType()) { if (event->type() == HFActionEvent::startType()) {
@ -97,86 +96,6 @@ QVariant ControllerScriptingInterface::getRecommendedOverlayRect() const {
return qRectToVariant(rect); return qRectToVariant(rect);
} }
controller::InputController* ControllerScriptingInterface::createInputController(const QString& deviceName, const QString& tracker) {
// This is where we retrieve the Device Tracker category and then the sub tracker within it
auto icIt = _inputControllers.find(0);
if (icIt != _inputControllers.end()) {
return (*icIt).second.get();
}
// Look for device
DeviceTracker::ID deviceID = DeviceTracker::getDeviceID(deviceName.toStdString());
if (deviceID < 0) {
deviceID = 0;
}
// TODO in this current implementation, we just pick the device assuming there is one (normally the Leapmotion)
// in the near future we need to change that to a real mapping between the devices and the deviceName
// ALso we need to expand the spec so we can fall back on the "default" controller per categories
if (deviceID >= 0) {
// TODO here again the assumption it's the LeapMotion and so it's a MOtionTracker, this would need to be changed to support different types of devices
MotionTracker* motionTracker = dynamic_cast< MotionTracker* > (DeviceTracker::getDevice(deviceID));
if (motionTracker) {
MotionTracker::Index trackerID = motionTracker->findJointIndex(tracker.toStdString());
if (trackerID >= 0) {
controller::InputController::Pointer inputController = std::make_shared<InputController>(deviceID, trackerID, this);
controller::InputController::Key key = inputController->getKey();
_inputControllers.insert(InputControllerMap::value_type(key, inputController));
return inputController.get();
}
}
}
return nullptr;
}
void ControllerScriptingInterface::releaseInputController(controller::InputController* input) {
_inputControllers.erase(input->getKey());
}
void ControllerScriptingInterface::updateInputControllers() {
for (auto it = _inputControllers.begin(); it != _inputControllers.end(); it++) {
(*it).second->update();
}
}
InputController::InputController(int deviceTrackerId, int subTrackerId, QObject* parent) :
_deviceTrackerId(deviceTrackerId),
_subTrackerId(subTrackerId),
_isActive(false)
{
}
void InputController::update() {
_isActive = false;
// TODO for now the InputController is only supporting a JointTracker from a MotionTracker
MotionTracker* motionTracker = dynamic_cast< MotionTracker*> (DeviceTracker::getDevice(_deviceTrackerId));
if (motionTracker) {
if ((int)_subTrackerId < motionTracker->numJointTrackers()) {
const MotionTracker::JointTracker* joint = motionTracker->getJointTracker(_subTrackerId);
if (joint->isActive()) {
joint->getAbsFrame().getTranslation(_eventCache.absTranslation);
joint->getAbsFrame().getRotation(_eventCache.absRotation);
joint->getLocFrame().getTranslation(_eventCache.locTranslation);
joint->getLocFrame().getRotation(_eventCache.locRotation);
_isActive = true;
//emit spatialEvent(_eventCache);
}
}
}
}
const unsigned int INPUTCONTROLLER_KEY_DEVICE_OFFSET = 16;
const unsigned int INPUTCONTROLLER_KEY_DEVICE_MASK = 16;
InputController::Key InputController::getKey() const {
return (((_deviceTrackerId & INPUTCONTROLLER_KEY_DEVICE_MASK) << INPUTCONTROLLER_KEY_DEVICE_OFFSET) | _subTrackerId);
}
void ControllerScriptingInterface::emitKeyPressEvent(QKeyEvent* event) { emit keyPressEvent(KeyEvent(*event)); } void ControllerScriptingInterface::emitKeyPressEvent(QKeyEvent* event) { emit keyPressEvent(KeyEvent(*event)); }
void ControllerScriptingInterface::emitKeyReleaseEvent(QKeyEvent* event) { emit keyReleaseEvent(KeyEvent(*event)); } void ControllerScriptingInterface::emitKeyReleaseEvent(QKeyEvent* event) { emit keyReleaseEvent(KeyEvent(*event)); }

View file

@ -25,38 +25,6 @@
#include <WheelEvent.h> #include <WheelEvent.h>
class ScriptEngine; class ScriptEngine;
class PalmData;
class InputController : public controller::InputController {
Q_OBJECT
public:
InputController(int deviceTrackerId, int subTrackerId, QObject* parent = NULL);
virtual void update() override;
virtual Key getKey() const override;
public slots:
virtual bool isActive() const override { return _isActive; }
virtual glm::vec3 getAbsTranslation() const override { return _eventCache.absTranslation; }
virtual glm::quat getAbsRotation() const override { return _eventCache.absRotation; }
virtual glm::vec3 getLocTranslation() const override { return _eventCache.locTranslation; }
virtual glm::quat getLocRotation() const override { return _eventCache.locRotation; }
private:
int _deviceTrackerId;
uint _subTrackerId;
// cache for the spatial
SpatialEvent _eventCache;
bool _isActive;
signals:
};
/// handles scripting of input controller commands from JS /// handles scripting of input controller commands from JS
class ControllerScriptingInterface : public controller::ScriptingInterface { class ControllerScriptingInterface : public controller::ScriptingInterface {
Q_OBJECT Q_OBJECT
@ -86,8 +54,6 @@ public:
bool isJoystickCaptured(int joystickIndex) const; bool isJoystickCaptured(int joystickIndex) const;
bool areEntityClicksCaptured() const; bool areEntityClicksCaptured() const;
void updateInputControllers();
public slots: public slots:
virtual void captureKeyEvents(const KeyEvent& event); virtual void captureKeyEvents(const KeyEvent& event);
@ -102,10 +68,6 @@ public slots:
virtual glm::vec2 getViewportDimensions() const; virtual glm::vec2 getViewportDimensions() const;
virtual QVariant getRecommendedOverlayRect() const; virtual QVariant getRecommendedOverlayRect() const;
/// Factory to create an InputController
virtual controller::InputController* createInputController(const QString& deviceName, const QString& tracker);
virtual void releaseInputController(controller::InputController* input);
signals: signals:
void keyPressEvent(const KeyEvent& event); void keyPressEvent(const KeyEvent& event);
void keyReleaseEvent(const KeyEvent& event); void keyReleaseEvent(const KeyEvent& event);
@ -135,8 +97,6 @@ private:
bool _captureEntityClicks; bool _captureEntityClicks;
using InputKey = controller::InputController::Key; using InputKey = controller::InputController::Key;
using InputControllerMap = std::map<InputKey, controller::InputController::Pointer>;
InputControllerMap _inputControllers;
}; };
const int NUMBER_OF_SPATIALCONTROLS_PER_PALM = 2; // the hand and the tip const int NUMBER_OF_SPATIALCONTROLS_PER_PALM = 2; // the hand and the tip

View file

@ -13,6 +13,7 @@
#include <QtScript/QScriptContext> #include <QtScript/QScriptContext>
#include <shared/QtHelpers.h>
#include <avatar/AvatarManager.h> #include <avatar/AvatarManager.h>
#include <display-plugins/DisplayPlugin.h> #include <display-plugins/DisplayPlugin.h>
#include <display-plugins/CompositorHelper.h> #include <display-plugins/CompositorHelper.h>
@ -152,22 +153,31 @@ QString HMDScriptingInterface::preferredAudioOutput() const {
return qApp->getActiveDisplayPlugin()->getPreferredAudioOutDevice(); return qApp->getActiveDisplayPlugin()->getPreferredAudioOutDevice();
} }
bool HMDScriptingInterface::setHandLasers(int hands, bool enabled, const glm::vec4& color, const glm::vec3& direction) const { bool HMDScriptingInterface::setHandLasers(int hands, bool enabled, const glm::vec4& color, const glm::vec3& direction) {
if (QThread::currentThread() != thread()) {
bool result;
BLOCKING_INVOKE_METHOD(this, "setHandLasers", Q_RETURN_ARG(bool, result),
Q_ARG(int, hands), Q_ARG(bool, enabled), Q_ARG(glm::vec4, color), Q_ARG(glm::vec3, direction));
return result;
}
auto offscreenUi = DependencyManager::get<OffscreenUi>(); auto offscreenUi = DependencyManager::get<OffscreenUi>();
offscreenUi->executeOnUiThread([offscreenUi, enabled] { offscreenUi->getDesktop()->setProperty("hmdHandMouseActive", enabled);
offscreenUi->getDesktop()->setProperty("hmdHandMouseActive", enabled);
});
return qApp->getActiveDisplayPlugin()->setHandLaser(hands, return qApp->getActiveDisplayPlugin()->setHandLaser(hands,
enabled ? DisplayPlugin::HandLaserMode::Overlay : DisplayPlugin::HandLaserMode::None, enabled ? DisplayPlugin::HandLaserMode::Overlay : DisplayPlugin::HandLaserMode::None,
color, direction); color, direction);
} }
bool HMDScriptingInterface::setExtraLaser(const glm::vec3& worldStart, bool enabled, const glm::vec4& color, const glm::vec3& direction) const { bool HMDScriptingInterface::setExtraLaser(const glm::vec3& worldStart, bool enabled, const glm::vec4& color, const glm::vec3& direction) {
auto offscreenUi = DependencyManager::get<OffscreenUi>(); if (QThread::currentThread() != thread()) {
offscreenUi->executeOnUiThread([offscreenUi, enabled] { bool result;
offscreenUi->getDesktop()->setProperty("hmdHandMouseActive", enabled); BLOCKING_INVOKE_METHOD(this, "setExtraLaser", Q_RETURN_ARG(bool, result),
}); Q_ARG(glm::vec3, worldStart), Q_ARG(bool, enabled), Q_ARG(glm::vec4, color), Q_ARG(glm::vec3, direction));
return result;
}
auto offscreenUi = DependencyManager::get<OffscreenUi>();
offscreenUi->getDesktop()->setProperty("hmdHandMouseActive", enabled);
auto myAvatar = DependencyManager::get<AvatarManager>()->getMyAvatar(); auto myAvatar = DependencyManager::get<AvatarManager>()->getMyAvatar();
auto sensorToWorld = myAvatar->getSensorToWorldMatrix(); auto sensorToWorld = myAvatar->getSensorToWorldMatrix();
@ -179,11 +189,11 @@ bool HMDScriptingInterface::setExtraLaser(const glm::vec3& worldStart, bool enab
color, sensorStart, sensorDirection); color, sensorStart, sensorDirection);
} }
void HMDScriptingInterface::disableExtraLaser() const { void HMDScriptingInterface::disableExtraLaser() {
setExtraLaser(vec3(0), false, vec4(0), vec3(0)); setExtraLaser(vec3(0), false, vec4(0), vec3(0));
} }
void HMDScriptingInterface::disableHandLasers(int hands) const { void HMDScriptingInterface::disableHandLasers(int hands) {
setHandLasers(hands, false, vec4(0), vec3(0)); setHandLasers(hands, false, vec4(0), vec3(0));
} }

View file

@ -51,11 +51,11 @@ public:
Q_INVOKABLE void requestHideHandControllers(); Q_INVOKABLE void requestHideHandControllers();
Q_INVOKABLE bool shouldShowHandControllers() const; Q_INVOKABLE bool shouldShowHandControllers() const;
Q_INVOKABLE bool setHandLasers(int hands, bool enabled, const glm::vec4& color, const glm::vec3& direction) const; Q_INVOKABLE bool setHandLasers(int hands, bool enabled, const glm::vec4& color, const glm::vec3& direction);
Q_INVOKABLE void disableHandLasers(int hands) const; Q_INVOKABLE void disableHandLasers(int hands);
Q_INVOKABLE bool setExtraLaser(const glm::vec3& worldStart, bool enabled, const glm::vec4& color, const glm::vec3& direction) const; Q_INVOKABLE bool setExtraLaser(const glm::vec3& worldStart, bool enabled, const glm::vec4& color, const glm::vec3& direction);
Q_INVOKABLE void disableExtraLaser() const; Q_INVOKABLE void disableExtraLaser();
/// Suppress the activation of any on-screen keyboard so that a script operation will /// Suppress the activation of any on-screen keyboard so that a script operation will

View file

@ -14,6 +14,7 @@
#include <QtCore/QCoreApplication> #include <QtCore/QCoreApplication>
#include <QtCore/QThread> #include <QtCore/QThread>
#include <shared/QtHelpers.h>
#include <MenuItemProperties.h> #include <MenuItemProperties.h>
#include "Menu.h" #include "Menu.h"
@ -43,7 +44,7 @@ bool MenuScriptingInterface::menuExists(const QString& menu) {
return Menu::getInstance()->menuExists(menu); return Menu::getInstance()->menuExists(menu);
} }
bool result; bool result;
QMetaObject::invokeMethod(Menu::getInstance(), "menuExists", Qt::BlockingQueuedConnection, BLOCKING_INVOKE_METHOD(Menu::getInstance(), "menuExists",
Q_RETURN_ARG(bool, result), Q_RETURN_ARG(bool, result),
Q_ARG(const QString&, menu)); Q_ARG(const QString&, menu));
return result; return result;
@ -86,7 +87,7 @@ bool MenuScriptingInterface::menuItemExists(const QString& menu, const QString&
return Menu::getInstance()->menuItemExists(menu, menuitem); return Menu::getInstance()->menuItemExists(menu, menuitem);
} }
bool result; bool result;
QMetaObject::invokeMethod(Menu::getInstance(), "menuItemExists", Qt::BlockingQueuedConnection, BLOCKING_INVOKE_METHOD(Menu::getInstance(), "menuItemExists",
Q_RETURN_ARG(bool, result), Q_RETURN_ARG(bool, result),
Q_ARG(const QString&, menu), Q_ARG(const QString&, menu),
Q_ARG(const QString&, menuitem)); Q_ARG(const QString&, menuitem));
@ -114,7 +115,7 @@ bool MenuScriptingInterface::isOptionChecked(const QString& menuOption) {
return Menu::getInstance()->isOptionChecked(menuOption); return Menu::getInstance()->isOptionChecked(menuOption);
} }
bool result; bool result;
QMetaObject::invokeMethod(Menu::getInstance(), "isOptionChecked", Qt::BlockingQueuedConnection, BLOCKING_INVOKE_METHOD(Menu::getInstance(), "isOptionChecked",
Q_RETURN_ARG(bool, result), Q_RETURN_ARG(bool, result),
Q_ARG(const QString&, menuOption)); Q_ARG(const QString&, menuOption));
return result; return result;
@ -131,7 +132,7 @@ bool MenuScriptingInterface::isMenuEnabled(const QString& menuOption) {
return Menu::getInstance()->isOptionChecked(menuOption); return Menu::getInstance()->isOptionChecked(menuOption);
} }
bool result; bool result;
QMetaObject::invokeMethod(Menu::getInstance(), "isMenuEnabled", Qt::BlockingQueuedConnection, BLOCKING_INVOKE_METHOD(Menu::getInstance(), "isMenuEnabled",
Q_RETURN_ARG(bool, result), Q_RETURN_ARG(bool, result),
Q_ARG(const QString&, menuOption)); Q_ARG(const QString&, menuOption));
return result; return result;
@ -157,7 +158,7 @@ bool MenuScriptingInterface::isInfoViewVisible(const QString& path) {
} }
bool result; bool result;
QMetaObject::invokeMethod(Menu::getInstance(), "isInfoViewVisible", Qt::BlockingQueuedConnection, BLOCKING_INVOKE_METHOD(Menu::getInstance(), "isInfoViewVisible",
Q_RETURN_ARG(bool, result), Q_ARG(const QString&, path)); Q_RETURN_ARG(bool, result), Q_ARG(const QString&, path));
return result; return result;
} }

View file

@ -11,6 +11,7 @@
#include <QtCore/QLoggingCategory> #include <QtCore/QLoggingCategory>
#include <QtCore/QThread> #include <QtCore/QThread>
#include <shared/QtHelpers.h>
#include <DependencyManager.h> #include <DependencyManager.h>
#include <Trace.h> #include <Trace.h>
#include <StatTracker.h> #include <StatTracker.h>
@ -57,20 +58,25 @@ void TestScriptingInterface::waitIdle() {
} }
bool TestScriptingInterface::loadTestScene(QString scene) { bool TestScriptingInterface::loadTestScene(QString scene) {
if (QThread::currentThread() != thread()) {
bool result;
BLOCKING_INVOKE_METHOD(this, "loadTestScene", Q_RETURN_ARG(bool, result), Q_ARG(QString, scene));
return result;
}
static const QString TEST_ROOT = "https://raw.githubusercontent.com/highfidelity/hifi_tests/master/"; static const QString TEST_ROOT = "https://raw.githubusercontent.com/highfidelity/hifi_tests/master/";
static const QString TEST_BINARY_ROOT = "https://hifi-public.s3.amazonaws.com/test_scene_data/"; static const QString TEST_BINARY_ROOT = "https://hifi-public.s3.amazonaws.com/test_scene_data/";
static const QString TEST_SCRIPTS_ROOT = TEST_ROOT + "scripts/"; static const QString TEST_SCRIPTS_ROOT = TEST_ROOT + "scripts/";
static const QString TEST_SCENES_ROOT = TEST_ROOT + "scenes/"; static const QString TEST_SCENES_ROOT = TEST_ROOT + "scenes/";
return DependencyManager::get<OffscreenUi>()->returnFromUiThread([scene]()->QVariant {
DependencyManager::get<ResourceManager>()->setUrlPrefixOverride("atp:/", TEST_BINARY_ROOT + scene + ".atp/"); DependencyManager::get<ResourceManager>()->setUrlPrefixOverride("atp:/", TEST_BINARY_ROOT + scene + ".atp/");
auto tree = qApp->getEntities()->getTree(); auto tree = qApp->getEntities()->getTree();
auto treeIsClient = tree->getIsClient(); auto treeIsClient = tree->getIsClient();
// Force the tree to accept the load regardless of permissions // Force the tree to accept the load regardless of permissions
tree->setIsClient(false); tree->setIsClient(false);
auto result = tree->readFromURL(TEST_SCENES_ROOT + scene + ".json"); auto result = tree->readFromURL(TEST_SCENES_ROOT + scene + ".json");
tree->setIsClient(treeIsClient); tree->setIsClient(treeIsClient);
return result; return result;
}).toBool();
} }
bool TestScriptingInterface::startTracing(QString logrules) { bool TestScriptingInterface::startTracing(QString logrules) {

View file

@ -9,11 +9,14 @@
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
// //
#include "WindowScriptingInterface.h"
#include <QClipboard> #include <QClipboard>
#include <QtCore/QDir> #include <QtCore/QDir>
#include <QMessageBox> #include <QMessageBox>
#include <QScriptValue> #include <QScriptValue>
#include <shared/QtHelpers.h>
#include <SettingHandle.h> #include <SettingHandle.h>
#include <display-plugins/CompositorHelper.h> #include <display-plugins/CompositorHelper.h>
@ -24,8 +27,6 @@
#include "Menu.h" #include "Menu.h"
#include "OffscreenUi.h" #include "OffscreenUi.h"
#include "WindowScriptingInterface.h"
static const QString DESKTOP_LOCATION = QStandardPaths::writableLocation(QStandardPaths::DesktopLocation); static const QString DESKTOP_LOCATION = QStandardPaths::writableLocation(QStandardPaths::DesktopLocation);
static const QString LAST_BROWSE_LOCATION_SETTING = "LastBrowseLocation"; static const QString LAST_BROWSE_LOCATION_SETTING = "LastBrowseLocation";
static const QString LAST_BROWSE_ASSETS_LOCATION_SETTING = "LastBrowseAssetsLocation"; static const QString LAST_BROWSE_ASSETS_LOCATION_SETTING = "LastBrowseAssetsLocation";
@ -316,7 +317,7 @@ bool WindowScriptingInterface::isPhysicsEnabled() {
int WindowScriptingInterface::openMessageBox(QString title, QString text, int buttons, int defaultButton) { int WindowScriptingInterface::openMessageBox(QString title, QString text, int buttons, int defaultButton) {
if (QThread::currentThread() != thread()) { if (QThread::currentThread() != thread()) {
int result; int result;
QMetaObject::invokeMethod(this, "openMessageBox", Qt::BlockingQueuedConnection, BLOCKING_INVOKE_METHOD(this, "openMessageBox",
Q_RETURN_ARG(int, result), Q_RETURN_ARG(int, result),
Q_ARG(QString, title), Q_ARG(QString, title),
Q_ARG(QString, text), Q_ARG(QString, text),

View file

@ -18,6 +18,8 @@
#include <QtScript/QScriptValue> #include <QtScript/QScriptValue>
#include <QtWidgets/QMessageBox> #include <QtWidgets/QMessageBox>
#include <DependencyManager.h>
class CustomPromptResult { class CustomPromptResult {
public: public:
QVariant value; QVariant value;

View file

@ -15,6 +15,7 @@
#include <QScrollBar> #include <QScrollBar>
#include <QtConcurrent/QtConcurrentRun> #include <QtConcurrent/QtConcurrentRun>
#include <shared/QtHelpers.h>
#include <ScriptEngines.h> #include <ScriptEngines.h>
#include <PathUtils.h> #include <PathUtils.h>
@ -115,7 +116,7 @@ void JSConsole::executeCommand(const QString& command) {
QScriptValue JSConsole::executeCommandInWatcher(const QString& command) { QScriptValue JSConsole::executeCommandInWatcher(const QString& command) {
QScriptValue result; QScriptValue result;
QMetaObject::invokeMethod(_scriptEngine, "evaluate", Qt::ConnectionType::BlockingQueuedConnection, BLOCKING_INVOKE_METHOD(_scriptEngine, "evaluate",
Q_RETURN_ARG(QScriptValue, result), Q_RETURN_ARG(QScriptValue, result),
Q_ARG(const QString&, command), Q_ARG(const QString&, command),
Q_ARG(const QString&, _consoleFileName)); Q_ARG(const QString&, _consoleFileName));

View file

@ -45,11 +45,13 @@ Image3DOverlay::~Image3DOverlay() {
} }
void Image3DOverlay::update(float deltatime) { void Image3DOverlay::update(float deltatime) {
#if OVERLAY_PANELS
if (usecTimestampNow() > _transformExpiry) { if (usecTimestampNow() > _transformExpiry) {
Transform transform = getTransform(); Transform transform = getTransform();
applyTransformTo(transform); applyTransformTo(transform);
setTransform(transform); setTransform(transform);
} }
#endif
} }
void Image3DOverlay::render(RenderArgs* args) { void Image3DOverlay::render(RenderArgs* args) {

View file

@ -84,9 +84,9 @@ public:
void setColorPulse(float value) { _colorPulse = value; } void setColorPulse(float value) { _colorPulse = value; }
void setAlphaPulse(float value) { _alphaPulse = value; } void setAlphaPulse(float value) { _alphaPulse = value; }
virtual void setProperties(const QVariantMap& properties); Q_INVOKABLE virtual void setProperties(const QVariantMap& properties);
virtual Overlay* createClone() const = 0; Q_INVOKABLE virtual Overlay* createClone() const = 0;
virtual QVariant getProperty(const QString& property); Q_INVOKABLE virtual QVariant getProperty(const QString& property);
render::ItemID getRenderItemID() const { return _renderItemID; } render::ItemID getRenderItemID() const { return _renderItemID; }
void setRenderItemID(render::ItemID renderItemID) { _renderItemID = renderItemID; } void setRenderItemID(render::ItemID renderItemID) { _renderItemID = renderItemID; }

View file

@ -11,6 +11,8 @@
#include "OverlayPanel.h" #include "OverlayPanel.h"
#if OVERLAY_PANELS
#include <QVariant> #include <QVariant>
#include <RegisteredMetaTypes.h> #include <RegisteredMetaTypes.h>
#include <DependencyManager.h> #include <DependencyManager.h>
@ -185,3 +187,4 @@ void OverlayPanel::applyTransformTo(Transform& transform, bool force) {
pointTransformAtCamera(transform, getOffsetRotation()); pointTransformAtCamera(transform, getOffsetRotation());
} }
} }
#endif

View file

@ -22,6 +22,7 @@
#include "Billboardable.h" #include "Billboardable.h"
#include "Overlay.h" #include "Overlay.h"
#if OVERLAY_PANELS
class PropertyBinding { class PropertyBinding {
public: public:
PropertyBinding() {} PropertyBinding() {}
@ -80,4 +81,6 @@ private:
QScriptEngine* _scriptEngine; QScriptEngine* _scriptEngine;
}; };
#endif
#endif // hifi_OverlayPanel_h #endif // hifi_OverlayPanel_h

View file

@ -14,6 +14,7 @@
#include <QtScript/QScriptValueIterator> #include <QtScript/QScriptValueIterator>
#include <shared/QtHelpers.h>
#include <OffscreenUi.h> #include <OffscreenUi.h>
#include <render/Scene.h> #include <render/Scene.h>
#include <RegisteredMetaTypes.h> #include <RegisteredMetaTypes.h>
@ -39,34 +40,39 @@
Q_LOGGING_CATEGORY(trace_render_overlays, "trace.render.overlays") Q_LOGGING_CATEGORY(trace_render_overlays, "trace.render.overlays")
void Overlays::cleanupAllOverlays() { void Overlays::cleanupAllOverlays() {
QMap<OverlayID, Overlay::Pointer> overlaysHUD;
QMap<OverlayID, Overlay::Pointer> overlaysWorld;
{ {
QWriteLocker lock(&_lock); QMutexLocker locker(&_mutex);
QWriteLocker deleteLock(&_deleteLock); overlaysHUD.swap(_overlaysHUD);
foreach(Overlay::Pointer overlay, _overlaysHUD) { overlaysWorld.swap(_overlaysWorld);
_overlaysToDelete.push_back(overlay);
}
foreach(Overlay::Pointer overlay, _overlaysWorld) {
_overlaysToDelete.push_back(overlay);
}
_overlaysHUD.clear();
_overlaysWorld.clear();
_panels.clear();
} }
foreach(Overlay::Pointer overlay, overlaysHUD) {
_overlaysToDelete.push_back(overlay);
}
foreach(Overlay::Pointer overlay, overlaysWorld) {
_overlaysToDelete.push_back(overlay);
}
#if OVERLAY_PANELS
_panels.clear();
#endif
cleanupOverlaysToDelete(); cleanupOverlaysToDelete();
} }
void Overlays::init() { void Overlays::init() {
#if OVERLAY_PANELS
_scriptEngine = new QScriptEngine(); _scriptEngine = new QScriptEngine();
#endif
} }
void Overlays::update(float deltatime) { void Overlays::update(float deltatime) {
{ {
QWriteLocker lock(&_lock); QMutexLocker locker(&_mutex);
foreach(Overlay::Pointer thisOverlay, _overlaysHUD) { foreach(const auto& thisOverlay, _overlaysHUD) {
thisOverlay->update(deltatime); thisOverlay->update(deltatime);
} }
foreach(Overlay::Pointer thisOverlay, _overlaysWorld) { foreach(const auto& thisOverlay, _overlaysWorld) {
thisOverlay->update(deltatime); thisOverlay->update(deltatime);
} }
} }
@ -80,8 +86,6 @@ void Overlays::cleanupOverlaysToDelete() {
render::Transaction transaction; render::Transaction transaction;
{ {
QWriteLocker lock(&_deleteLock);
do { do {
Overlay::Pointer overlay = _overlaysToDelete.takeLast(); Overlay::Pointer overlay = _overlaysToDelete.takeLast();
@ -100,7 +104,6 @@ void Overlays::cleanupOverlaysToDelete() {
void Overlays::renderHUD(RenderArgs* renderArgs) { void Overlays::renderHUD(RenderArgs* renderArgs) {
PROFILE_RANGE(render_overlays, __FUNCTION__); PROFILE_RANGE(render_overlays, __FUNCTION__);
QReadLocker lock(&_lock);
gpu::Batch& batch = *renderArgs->_batch; gpu::Batch& batch = *renderArgs->_batch;
auto geometryCache = DependencyManager::get<GeometryCache>(); auto geometryCache = DependencyManager::get<GeometryCache>();
@ -111,7 +114,7 @@ void Overlays::renderHUD(RenderArgs* renderArgs) {
int height = size.y; int height = size.y;
mat4 legacyProjection = glm::ortho<float>(0, width, height, 0, -1000, 1000); mat4 legacyProjection = glm::ortho<float>(0, width, height, 0, -1000, 1000);
QMutexLocker locker(&_mutex);
foreach(Overlay::Pointer thisOverlay, _overlaysHUD) { foreach(Overlay::Pointer thisOverlay, _overlaysHUD) {
// Reset all batch pipeline settings between overlay // Reset all batch pipeline settings between overlay
@ -126,16 +129,17 @@ void Overlays::renderHUD(RenderArgs* renderArgs) {
} }
void Overlays::disable() { void Overlays::disable() {
QWriteLocker lock(&_lock);
_enabled = false; _enabled = false;
} }
void Overlays::enable() { void Overlays::enable() {
QWriteLocker lock(&_lock);
_enabled = true; _enabled = true;
} }
// Note, can't be invoked by scripts, but can be called by the InterfaceParentFinder
// class on packet processing threads
Overlay::Pointer Overlays::getOverlay(OverlayID id) const { Overlay::Pointer Overlays::getOverlay(OverlayID id) const {
QMutexLocker locker(&_mutex);
if (_overlaysHUD.contains(id)) { if (_overlaysHUD.contains(id)) {
return _overlaysHUD[id]; return _overlaysHUD[id];
} }
@ -146,6 +150,12 @@ Overlay::Pointer Overlays::getOverlay(OverlayID id) const {
} }
OverlayID Overlays::addOverlay(const QString& type, const QVariant& properties) { OverlayID Overlays::addOverlay(const QString& type, const QVariant& properties) {
if (QThread::currentThread() != thread()) {
OverlayID result;
BLOCKING_INVOKE_METHOD(this, "addOverlay", Q_RETURN_ARG(OverlayID, result), Q_ARG(QString, type), Q_ARG(QVariant, properties));
return result;
}
Overlay::Pointer thisOverlay = nullptr; Overlay::Pointer thisOverlay = nullptr;
if (type == ImageOverlay::TYPE) { if (type == ImageOverlay::TYPE) {
@ -185,19 +195,22 @@ OverlayID Overlays::addOverlay(const QString& type, const QVariant& properties)
return UNKNOWN_OVERLAY_ID; return UNKNOWN_OVERLAY_ID;
} }
OverlayID Overlays::addOverlay(Overlay::Pointer overlay) { OverlayID Overlays::addOverlay(const Overlay::Pointer& overlay) {
QWriteLocker lock(&_lock);
OverlayID thisID = OverlayID(QUuid::createUuid()); OverlayID thisID = OverlayID(QUuid::createUuid());
overlay->setOverlayID(thisID); overlay->setOverlayID(thisID);
overlay->setStackOrder(_stackOrder++); overlay->setStackOrder(_stackOrder++);
if (overlay->is3D()) { if (overlay->is3D()) {
_overlaysWorld[thisID] = overlay; {
QMutexLocker locker(&_mutex);
_overlaysWorld[thisID] = overlay;
}
render::ScenePointer scene = qApp->getMain3DScene(); render::ScenePointer scene = qApp->getMain3DScene();
render::Transaction transaction; render::Transaction transaction;
overlay->addToScene(overlay, scene, transaction); overlay->addToScene(overlay, scene, transaction);
scene->enqueueTransaction(transaction); scene->enqueueTransaction(transaction);
} else { } else {
QMutexLocker locker(&_mutex);
_overlaysHUD[thisID] = overlay; _overlaysHUD[thisID] = overlay;
} }
@ -205,14 +218,22 @@ OverlayID Overlays::addOverlay(Overlay::Pointer overlay) {
} }
OverlayID Overlays::cloneOverlay(OverlayID id) { OverlayID Overlays::cloneOverlay(OverlayID id) {
if (QThread::currentThread() != thread()) {
OverlayID result;
BLOCKING_INVOKE_METHOD(this, "cloneOverlay", Q_RETURN_ARG(OverlayID, result), Q_ARG(OverlayID, id));
return result;
}
Overlay::Pointer thisOverlay = getOverlay(id); Overlay::Pointer thisOverlay = getOverlay(id);
if (thisOverlay) { if (thisOverlay) {
OverlayID cloneId = addOverlay(Overlay::Pointer(thisOverlay->createClone())); OverlayID cloneId = addOverlay(Overlay::Pointer(thisOverlay->createClone()));
#if OVERLAY_PANELS
auto attachable = std::dynamic_pointer_cast<PanelAttachable>(thisOverlay); auto attachable = std::dynamic_pointer_cast<PanelAttachable>(thisOverlay);
if (attachable && attachable->getParentPanel()) { if (attachable && attachable->getParentPanel()) {
attachable->getParentPanel()->addChild(cloneId); attachable->getParentPanel()->addChild(cloneId);
} }
#endif
return cloneId; return cloneId;
} }
@ -220,21 +241,32 @@ OverlayID Overlays::cloneOverlay(OverlayID id) {
} }
bool Overlays::editOverlay(OverlayID id, const QVariant& properties) { bool Overlays::editOverlay(OverlayID id, const QVariant& properties) {
QWriteLocker lock(&_lock); if (QThread::currentThread() != thread()) {
// NOTE editOverlay can be called very frequently in scripts and can't afford to
// block waiting on the main thread. Additionally, no script actually
// examines the return value and does something useful with it, so use a non-blocking
// invoke and just always return true
QMetaObject::invokeMethod(this, "editOverlay", Q_ARG(OverlayID, id), Q_ARG(QVariant, properties));
return true;
}
Overlay::Pointer thisOverlay = getOverlay(id); Overlay::Pointer thisOverlay = getOverlay(id);
if (thisOverlay) { if (thisOverlay) {
thisOverlay->setProperties(properties.toMap()); thisOverlay->setProperties(properties.toMap());
return true; return true;
} }
return false; return false;
} }
bool Overlays::editOverlays(const QVariant& propertiesById) { bool Overlays::editOverlays(const QVariant& propertiesById) {
if (QThread::currentThread() != thread()) {
// NOTE see comment on editOverlay for why this is not a blocking call
QMetaObject::invokeMethod(this, "editOverlays", Q_ARG(QVariant, propertiesById));
return true;
}
QVariantMap map = propertiesById.toMap(); QVariantMap map = propertiesById.toMap();
bool success = true; bool success = true;
QWriteLocker lock(&_lock);
for (const auto& key : map.keys()) { for (const auto& key : map.keys()) {
OverlayID id = OverlayID(key); OverlayID id = OverlayID(key);
Overlay::Pointer thisOverlay = getOverlay(id); Overlay::Pointer thisOverlay = getOverlay(id);
@ -249,10 +281,15 @@ bool Overlays::editOverlays(const QVariant& propertiesById) {
} }
void Overlays::deleteOverlay(OverlayID id) { void Overlays::deleteOverlay(OverlayID id) {
if (QThread::currentThread() != thread()) {
QMetaObject::invokeMethod(this, "deleteOverlay", Q_ARG(OverlayID, id));
return;
}
Overlay::Pointer overlayToDelete; Overlay::Pointer overlayToDelete;
{ {
QWriteLocker lock(&_lock); QMutexLocker locker(&_mutex);
if (_overlaysHUD.contains(id)) { if (_overlaysHUD.contains(id)) {
overlayToDelete = _overlaysHUD.take(id); overlayToDelete = _overlaysHUD.take(id);
} else if (_overlaysWorld.contains(id)) { } else if (_overlaysWorld.contains(id)) {
@ -262,19 +299,25 @@ void Overlays::deleteOverlay(OverlayID id) {
} }
} }
#if OVERLAY_PANELS
auto attachable = std::dynamic_pointer_cast<PanelAttachable>(overlayToDelete); auto attachable = std::dynamic_pointer_cast<PanelAttachable>(overlayToDelete);
if (attachable && attachable->getParentPanel()) { if (attachable && attachable->getParentPanel()) {
attachable->getParentPanel()->removeChild(id); attachable->getParentPanel()->removeChild(id);
attachable->setParentPanel(nullptr); attachable->setParentPanel(nullptr);
} }
#endif
QWriteLocker lock(&_deleteLock);
_overlaysToDelete.push_back(overlayToDelete); _overlaysToDelete.push_back(overlayToDelete);
emit overlayDeleted(id); emit overlayDeleted(id);
} }
QString Overlays::getOverlayType(OverlayID overlayId) const { QString Overlays::getOverlayType(OverlayID overlayId) {
if (QThread::currentThread() != thread()) {
QString result;
BLOCKING_INVOKE_METHOD(this, "getOverlayType", Q_RETURN_ARG(QString, result), Q_ARG(OverlayID, overlayId));
return result;
}
Overlay::Pointer overlay = getOverlay(overlayId); Overlay::Pointer overlay = getOverlay(overlayId);
if (overlay) { if (overlay) {
return overlay->getType(); return overlay->getType();
@ -283,6 +326,12 @@ QString Overlays::getOverlayType(OverlayID overlayId) const {
} }
QObject* Overlays::getOverlayObject(OverlayID id) { QObject* Overlays::getOverlayObject(OverlayID id) {
if (QThread::currentThread() != thread()) {
QObject* result;
BLOCKING_INVOKE_METHOD(this, "getOverlayObject", Q_RETURN_ARG(QObject*, result), Q_ARG(OverlayID, id));
return result;
}
Overlay::Pointer thisOverlay = getOverlay(id); Overlay::Pointer thisOverlay = getOverlay(id);
if (thisOverlay) { if (thisOverlay) {
return qobject_cast<QObject*>(&(*thisOverlay)); return qobject_cast<QObject*>(&(*thisOverlay));
@ -290,6 +339,7 @@ QObject* Overlays::getOverlayObject(OverlayID id) {
return nullptr; return nullptr;
} }
#if OVERLAY_PANELS
OverlayID Overlays::getParentPanel(OverlayID childId) const { OverlayID Overlays::getParentPanel(OverlayID childId) const {
Overlay::Pointer overlay = getOverlay(childId); Overlay::Pointer overlay = getOverlay(childId);
auto attachable = std::dynamic_pointer_cast<PanelAttachable>(overlay); auto attachable = std::dynamic_pointer_cast<PanelAttachable>(overlay);
@ -330,33 +380,31 @@ void Overlays::setParentPanel(OverlayID childId, OverlayID panelId) {
} }
} }
} }
#endif
OverlayID Overlays::getOverlayAtPoint(const glm::vec2& point) { OverlayID Overlays::getOverlayAtPoint(const glm::vec2& point) {
glm::vec2 pointCopy = point; if (QThread::currentThread() != thread()) {
QReadLocker lock(&_lock); OverlayID result;
BLOCKING_INVOKE_METHOD(this, "getOverlayAtPoint", Q_RETURN_ARG(OverlayID, result), Q_ARG(glm::vec2, point));
return result;
}
if (!_enabled) { if (!_enabled) {
return UNKNOWN_OVERLAY_ID; return UNKNOWN_OVERLAY_ID;
} }
QMapIterator<OverlayID, Overlay::Pointer> i(_overlaysHUD);
const float LARGE_NEGATIVE_FLOAT = -9999999; QMutexLocker locker(&_mutex);
glm::vec3 origin(pointCopy.x, pointCopy.y, LARGE_NEGATIVE_FLOAT); QMapIterator<OverlayID, Overlay::Pointer> i(_overlaysHUD);
glm::vec3 direction(0, 0, 1);
glm::vec3 thisSurfaceNormal;
unsigned int bestStackOrder = 0; unsigned int bestStackOrder = 0;
OverlayID bestOverlayID = UNKNOWN_OVERLAY_ID; OverlayID bestOverlayID = UNKNOWN_OVERLAY_ID;
while (i.hasNext()) { while (i.hasNext()) {
i.next(); i.next();
OverlayID thisID = i.key(); auto thisOverlay = std::dynamic_pointer_cast<Overlay2D>(i.value());
if (!i.value()->is3D()) { if (thisOverlay && thisOverlay->getVisible() && thisOverlay->isLoaded() &&
auto thisOverlay = std::dynamic_pointer_cast<Overlay2D>(i.value()); thisOverlay->getBoundingRect().contains(point.x, point.y, false)) {
if (thisOverlay && thisOverlay->getVisible() && thisOverlay->isLoaded() && if (thisOverlay->getStackOrder() > bestStackOrder) {
thisOverlay->getBoundingRect().contains(pointCopy.x, pointCopy.y, false)) { bestOverlayID = i.key();
if (thisOverlay->getStackOrder() > bestStackOrder) { bestStackOrder = thisOverlay->getStackOrder();
bestOverlayID = thisID;
bestStackOrder = thisOverlay->getStackOrder();
}
} }
} }
} }
@ -365,9 +413,14 @@ OverlayID Overlays::getOverlayAtPoint(const glm::vec2& point) {
} }
OverlayPropertyResult Overlays::getProperty(OverlayID id, const QString& property) { OverlayPropertyResult Overlays::getProperty(OverlayID id, const QString& property) {
if (QThread::currentThread() != thread()) {
OverlayPropertyResult result;
BLOCKING_INVOKE_METHOD(this, "getProperty", Q_RETURN_ARG(OverlayPropertyResult, result), Q_ARG(OverlayID, id), Q_ARG(QString, property));
return result;
}
OverlayPropertyResult result; OverlayPropertyResult result;
Overlay::Pointer thisOverlay = getOverlay(id); Overlay::Pointer thisOverlay = getOverlay(id);
QReadLocker lock(&_lock);
if (thisOverlay && thisOverlay->supportsGetProperty()) { if (thisOverlay && thisOverlay->supportsGetProperty()) {
result.value = thisOverlay->getProperty(property); result.value = thisOverlay->getProperty(property);
} }
@ -405,10 +458,22 @@ RayToOverlayIntersectionResult Overlays::findRayIntersectionInternal(const PickR
const QVector<OverlayID>& overlaysToInclude, const QVector<OverlayID>& overlaysToInclude,
const QVector<OverlayID>& overlaysToDiscard, const QVector<OverlayID>& overlaysToDiscard,
bool visibleOnly, bool collidableOnly) { bool visibleOnly, bool collidableOnly) {
QReadLocker lock(&_lock); if (QThread::currentThread() != thread()) {
RayToOverlayIntersectionResult result;
BLOCKING_INVOKE_METHOD(this, "findRayIntersectionInternal", Q_RETURN_ARG(RayToOverlayIntersectionResult, result),
Q_ARG(PickRay, ray),
Q_ARG(bool, precisionPicking),
Q_ARG(QVector<OverlayID>, overlaysToInclude),
Q_ARG(QVector<OverlayID>, overlaysToDiscard),
Q_ARG(bool, visibleOnly),
Q_ARG(bool, collidableOnly));
return result;
}
float bestDistance = std::numeric_limits<float>::max(); float bestDistance = std::numeric_limits<float>::max();
bool bestIsFront = false; bool bestIsFront = false;
QMutexLocker locker(&_mutex);
RayToOverlayIntersectionResult result; RayToOverlayIntersectionResult result;
QMapIterator<OverlayID, Overlay::Pointer> i(_overlaysWorld); QMapIterator<OverlayID, Overlay::Pointer> i(_overlaysWorld);
while (i.hasNext()) { while (i.hasNext()) {
@ -448,16 +513,6 @@ RayToOverlayIntersectionResult Overlays::findRayIntersectionInternal(const PickR
return result; return result;
} }
RayToOverlayIntersectionResult::RayToOverlayIntersectionResult() :
intersects(false),
overlayID(UNKNOWN_OVERLAY_ID),
distance(0),
face(),
intersection(),
extraInfo()
{
}
QScriptValue RayToOverlayIntersectionResultToScriptValue(QScriptEngine* engine, const RayToOverlayIntersectionResult& value) { QScriptValue RayToOverlayIntersectionResultToScriptValue(QScriptEngine* engine, const RayToOverlayIntersectionResult& value) {
auto obj = engine->newObject(); auto obj = engine->newObject();
obj.setProperty("intersects", value.intersects); obj.setProperty("intersects", value.intersects);
@ -531,7 +586,12 @@ void RayToOverlayIntersectionResultFromScriptValue(const QScriptValue& objectVar
} }
bool Overlays::isLoaded(OverlayID id) { bool Overlays::isLoaded(OverlayID id) {
QReadLocker lock(&_lock); if (QThread::currentThread() != thread()) {
bool result;
BLOCKING_INVOKE_METHOD(this, "isLoaded", Q_RETURN_ARG(bool, result), Q_ARG(OverlayID, id));
return result;
}
Overlay::Pointer thisOverlay = getOverlay(id); Overlay::Pointer thisOverlay = getOverlay(id);
if (!thisOverlay) { if (!thisOverlay) {
return false; // not found return false; // not found
@ -539,14 +599,27 @@ bool Overlays::isLoaded(OverlayID id) {
return thisOverlay->isLoaded(); return thisOverlay->isLoaded();
} }
QSizeF Overlays::textSize(OverlayID id, const QString& text) const { QSizeF Overlays::textSize(OverlayID id, const QString& text) {
Overlay::Pointer thisOverlay = _overlaysHUD[id]; if (QThread::currentThread() != thread()) {
QSizeF result;
BLOCKING_INVOKE_METHOD(this, "textSize", Q_RETURN_ARG(QSizeF, result), Q_ARG(OverlayID, id), Q_ARG(QString, text));
return result;
}
Overlay::Pointer thisOverlay;
{
QMutexLocker locker(&_mutex);
thisOverlay = _overlaysHUD[id];
}
if (thisOverlay) { if (thisOverlay) {
if (auto textOverlay = std::dynamic_pointer_cast<TextOverlay>(thisOverlay)) { if (auto textOverlay = std::dynamic_pointer_cast<TextOverlay>(thisOverlay)) {
return textOverlay->textSize(text); return textOverlay->textSize(text);
} }
} else { } else {
thisOverlay = _overlaysWorld[id]; {
QMutexLocker locker(&_mutex);
thisOverlay = _overlaysWorld[id];
}
if (auto text3dOverlay = std::dynamic_pointer_cast<Text3DOverlay>(thisOverlay)) { if (auto text3dOverlay = std::dynamic_pointer_cast<Text3DOverlay>(thisOverlay)) {
return text3dOverlay->textSize(text); return text3dOverlay->textSize(text);
} }
@ -554,6 +627,7 @@ QSizeF Overlays::textSize(OverlayID id, const QString& text) const {
return QSizeF(0.0f, 0.0f); return QSizeF(0.0f, 0.0f);
} }
#if OVERLAY_PANELS
OverlayID Overlays::addPanel(OverlayPanel::Pointer panel) { OverlayID Overlays::addPanel(OverlayPanel::Pointer panel) {
QWriteLocker lock(&_lock); QWriteLocker lock(&_lock);
@ -607,8 +681,16 @@ void Overlays::deletePanel(OverlayID panelId) {
emit panelDeleted(panelId); emit panelDeleted(panelId);
} }
#endif
bool Overlays::isAddedOverlay(OverlayID id) { bool Overlays::isAddedOverlay(OverlayID id) {
if (QThread::currentThread() != thread()) {
bool result;
BLOCKING_INVOKE_METHOD(this, "isAddedOverlay", Q_RETURN_ARG(bool, result), Q_ARG(OverlayID, id));
return result;
}
QMutexLocker locker(&_mutex);
return _overlaysHUD.contains(id) || _overlaysWorld.contains(id); return _overlaysHUD.contains(id) || _overlaysWorld.contains(id);
} }
@ -636,20 +718,43 @@ void Overlays::sendHoverLeaveOverlay(OverlayID id, PointerEvent event) {
emit hoverLeaveOverlay(id, event); emit hoverLeaveOverlay(id, event);
} }
OverlayID Overlays::getKeyboardFocusOverlay() const { OverlayID Overlays::getKeyboardFocusOverlay() {
if (QThread::currentThread() != thread()) {
OverlayID result;
BLOCKING_INVOKE_METHOD(this, "getKeyboardFocusOverlay", Q_RETURN_ARG(OverlayID, result));
return result;
}
return qApp->getKeyboardFocusOverlay(); return qApp->getKeyboardFocusOverlay();
} }
void Overlays::setKeyboardFocusOverlay(OverlayID id) { void Overlays::setKeyboardFocusOverlay(OverlayID id) {
if (QThread::currentThread() != thread()) {
QMetaObject::invokeMethod(this, "setKeyboardFocusOverlay", Q_ARG(OverlayID, id));
return;
}
qApp->setKeyboardFocusOverlay(id); qApp->setKeyboardFocusOverlay(id);
} }
float Overlays::width() const { float Overlays::width() {
if (QThread::currentThread() != thread()) {
float result;
BLOCKING_INVOKE_METHOD(this, "width", Q_RETURN_ARG(float, result));
return result;
}
auto offscreenUi = DependencyManager::get<OffscreenUi>(); auto offscreenUi = DependencyManager::get<OffscreenUi>();
return offscreenUi->getWindow()->size().width(); return offscreenUi->getWindow()->size().width();
} }
float Overlays::height() const { float Overlays::height() {
if (QThread::currentThread() != thread()) {
float result;
BLOCKING_INVOKE_METHOD(this, "height", Q_RETURN_ARG(float, result));
return result;
}
auto offscreenUi = DependencyManager::get<OffscreenUi>(); auto offscreenUi = DependencyManager::get<OffscreenUi>();
return offscreenUi->getWindow()->size().height(); return offscreenUi->getWindow()->size().height();
} }
@ -705,7 +810,6 @@ PointerEvent Overlays::calculatePointerEvent(Overlay::Pointer overlay, PickRay r
auto thisOverlay = std::dynamic_pointer_cast<Web3DOverlay>(overlay); auto thisOverlay = std::dynamic_pointer_cast<Web3DOverlay>(overlay);
QReadLocker lock(&_lock);
auto position = thisOverlay->getPosition(); auto position = thisOverlay->getPosition();
auto rotation = thisOverlay->getRotation(); auto rotation = thisOverlay->getRotation();
auto dimensions = thisOverlay->getSize(); auto dimensions = thisOverlay->getSize();
@ -854,9 +958,14 @@ bool Overlays::mouseMoveEvent(QMouseEvent* event) {
return false; return false;
} }
QVector<QUuid> Overlays::findOverlays(const glm::vec3& center, float radius) const { QVector<QUuid> Overlays::findOverlays(const glm::vec3& center, float radius) {
QVector<QUuid> result; QVector<QUuid> result;
if (QThread::currentThread() != thread()) {
BLOCKING_INVOKE_METHOD(this, "findOverlays", Q_RETURN_ARG(QVector<QUuid>, result), Q_ARG(glm::vec3, center), Q_ARG(float, radius));
return result;
}
QMutexLocker locker(&_mutex);
QMapIterator<OverlayID, Overlay::Pointer> i(_overlaysWorld); QMapIterator<OverlayID, Overlay::Pointer> i(_overlaysWorld);
int checked = 0; int checked = 0;
while (i.hasNext()) { while (i.hasNext()) {

View file

@ -25,8 +25,9 @@
#include <PointerEvent.h> #include <PointerEvent.h>
#include "Overlay.h" #include "Overlay.h"
#include "OverlayPanel.h"
#include "PanelAttachable.h" #include "PanelAttachable.h"
#include "OverlayPanel.h"
class PickRay; class PickRay;
@ -41,6 +42,8 @@ Q_DECLARE_METATYPE(OverlayPropertyResult);
QScriptValue OverlayPropertyResultToScriptValue(QScriptEngine* engine, const OverlayPropertyResult& value); QScriptValue OverlayPropertyResultToScriptValue(QScriptEngine* engine, const OverlayPropertyResult& value);
void OverlayPropertyResultFromScriptValue(const QScriptValue& object, OverlayPropertyResult& value); void OverlayPropertyResultFromScriptValue(const QScriptValue& object, OverlayPropertyResult& value);
const OverlayID UNKNOWN_OVERLAY_ID = OverlayID();
/**jsdoc /**jsdoc
* @typedef Overlays.RayToOverlayIntersectionResult * @typedef Overlays.RayToOverlayIntersectionResult
* @property {bool} intersects True if the PickRay intersected with a 3D overlay. * @property {bool} intersects True if the PickRay intersected with a 3D overlay.
@ -51,10 +54,9 @@ void OverlayPropertyResultFromScriptValue(const QScriptValue& object, OverlayPro
*/ */
class RayToOverlayIntersectionResult { class RayToOverlayIntersectionResult {
public: public:
RayToOverlayIntersectionResult(); bool intersects { false };
bool intersects; OverlayID overlayID { UNKNOWN_OVERLAY_ID };
OverlayID overlayID; float distance { 0 };
float distance;
BoxFace face; BoxFace face;
glm::vec3 surfaceNormal; glm::vec3 surfaceNormal;
glm::vec3 intersection; glm::vec3 intersection;
@ -77,8 +79,6 @@ void RayToOverlayIntersectionResultFromScriptValue(const QScriptValue& object, R
* @namespace Overlays * @namespace Overlays
*/ */
const OverlayID UNKNOWN_OVERLAY_ID = OverlayID();
class Overlays : public QObject { class Overlays : public QObject {
Q_OBJECT Q_OBJECT
@ -94,11 +94,13 @@ public:
void enable(); void enable();
Overlay::Pointer getOverlay(OverlayID id) const; Overlay::Pointer getOverlay(OverlayID id) const;
#if OVERLAY_PANELS
OverlayPanel::Pointer getPanel(OverlayID id) const { return _panels[id]; } OverlayPanel::Pointer getPanel(OverlayID id) const { return _panels[id]; }
#endif
/// adds an overlay that's already been created /// adds an overlay that's already been created
OverlayID addOverlay(Overlay* overlay) { return addOverlay(Overlay::Pointer(overlay)); } OverlayID addOverlay(Overlay* overlay) { return addOverlay(Overlay::Pointer(overlay)); }
OverlayID addOverlay(Overlay::Pointer overlay); OverlayID addOverlay(const Overlay::Pointer& overlay);
bool mousePressEvent(QMouseEvent* event); bool mousePressEvent(QMouseEvent* event);
bool mouseDoublePressEvent(QMouseEvent* event); bool mouseDoublePressEvent(QMouseEvent* event);
@ -156,7 +158,7 @@ public slots:
* @param {Overlays.OverlayID} overlayID The ID of the overlay to get the type of. * @param {Overlays.OverlayID} overlayID The ID of the overlay to get the type of.
* @return {string} The type of the overlay if found, otherwise the empty string. * @return {string} The type of the overlay if found, otherwise the empty string.
*/ */
QString getOverlayType(OverlayID overlayId) const; QString getOverlayType(OverlayID overlayId);
/**jsdoc /**jsdoc
* Get the overlay Script object. * Get the overlay Script object.
@ -215,7 +217,7 @@ public slots:
* @param {float} radius search radius * @param {float} radius search radius
* @return {Overlays.OverlayID[]} list of overlays withing the radius * @return {Overlays.OverlayID[]} list of overlays withing the radius
*/ */
QVector<QUuid> findOverlays(const glm::vec3& center, float radius) const; QVector<QUuid> findOverlays(const glm::vec3& center, float radius);
/**jsdoc /**jsdoc
* Check whether an overlay's assets have been loaded. For example, if the * Check whether an overlay's assets have been loaded. For example, if the
@ -237,7 +239,7 @@ public slots:
* @param {string} The string to measure. * @param {string} The string to measure.
* @return {Vec2} The size of the text. * @return {Vec2} The size of the text.
*/ */
QSizeF textSize(OverlayID id, const QString& text) const; QSizeF textSize(OverlayID id, const QString& text);
/**jsdoc /**jsdoc
* Get the width of the virtual 2D HUD. * Get the width of the virtual 2D HUD.
@ -245,7 +247,7 @@ public slots:
* @function Overlays.width * @function Overlays.width
* @return {float} The width of the 2D HUD. * @return {float} The width of the 2D HUD.
*/ */
float width() const; float width();
/**jsdoc /**jsdoc
* Get the height of the virtual 2D HUD. * Get the height of the virtual 2D HUD.
@ -253,11 +255,12 @@ public slots:
* @function Overlays.height * @function Overlays.height
* @return {float} The height of the 2D HUD. * @return {float} The height of the 2D HUD.
*/ */
float height() const; float height();
/// return true if there is an overlay with that id else false /// return true if there is an overlay with that id else false
bool isAddedOverlay(OverlayID id); bool isAddedOverlay(OverlayID id);
#if OVERLAY_PANELS
OverlayID getParentPanel(OverlayID childId) const; OverlayID getParentPanel(OverlayID childId) const;
void setParentPanel(OverlayID childId, OverlayID panelId); void setParentPanel(OverlayID childId, OverlayID panelId);
@ -279,6 +282,8 @@ public slots:
/// return true if there is a panel with that id else false /// return true if there is a panel with that id else false
bool isAddedPanel(OverlayID id) { return _panels.contains(id); } bool isAddedPanel(OverlayID id) { return _panels.contains(id); }
#endif
void sendMousePressOnOverlay(OverlayID overlayID, const PointerEvent& event); void sendMousePressOnOverlay(OverlayID overlayID, const PointerEvent& event);
void sendMouseReleaseOnOverlay(OverlayID overlayID, const PointerEvent& event); void sendMouseReleaseOnOverlay(OverlayID overlayID, const PointerEvent& event);
void sendMouseMoveOnOverlay(OverlayID overlayID, const PointerEvent& event); void sendMouseMoveOnOverlay(OverlayID overlayID, const PointerEvent& event);
@ -287,7 +292,7 @@ public slots:
void sendHoverOverOverlay(OverlayID id, PointerEvent event); void sendHoverOverOverlay(OverlayID id, PointerEvent event);
void sendHoverLeaveOverlay(OverlayID id, PointerEvent event); void sendHoverLeaveOverlay(OverlayID id, PointerEvent event);
OverlayID getKeyboardFocusOverlay() const; OverlayID getKeyboardFocusOverlay();
void setKeyboardFocusOverlay(OverlayID id); void setKeyboardFocusOverlay(OverlayID id);
signals: signals:
@ -314,15 +319,18 @@ signals:
private: private:
void cleanupOverlaysToDelete(); void cleanupOverlaysToDelete();
mutable QMutex _mutex;
QMap<OverlayID, Overlay::Pointer> _overlaysHUD; QMap<OverlayID, Overlay::Pointer> _overlaysHUD;
QMap<OverlayID, Overlay::Pointer> _overlaysWorld; QMap<OverlayID, Overlay::Pointer> _overlaysWorld;
#if OVERLAY_PANELS
QMap<OverlayID, OverlayPanel::Pointer> _panels; QMap<OverlayID, OverlayPanel::Pointer> _panels;
#endif
QList<Overlay::Pointer> _overlaysToDelete; QList<Overlay::Pointer> _overlaysToDelete;
unsigned int _stackOrder { 1 }; unsigned int _stackOrder { 1 };
QReadWriteLock _lock; #if OVERLAY_PANELS
QReadWriteLock _deleteLock;
QScriptEngine* _scriptEngine; QScriptEngine* _scriptEngine;
#endif
bool _enabled = true; bool _enabled = true;
PointerEvent calculatePointerEvent(Overlay::Pointer overlay, PickRay ray, RayToOverlayIntersectionResult rayPickResult, PointerEvent calculatePointerEvent(Overlay::Pointer overlay, PickRay ray, RayToOverlayIntersectionResult rayPickResult,
@ -331,7 +339,7 @@ private:
OverlayID _currentClickingOnOverlayID { UNKNOWN_OVERLAY_ID }; OverlayID _currentClickingOnOverlayID { UNKNOWN_OVERLAY_ID };
OverlayID _currentHoverOverOverlayID { UNKNOWN_OVERLAY_ID }; OverlayID _currentHoverOverOverlayID { UNKNOWN_OVERLAY_ID };
RayToOverlayIntersectionResult findRayIntersectionInternal(const PickRay& ray, bool precisionPicking, Q_INVOKABLE RayToOverlayIntersectionResult findRayIntersectionInternal(const PickRay& ray, bool precisionPicking,
const QVector<OverlayID>& overlaysToInclude, const QVector<OverlayID>& overlaysToInclude,
const QVector<OverlayID>& overlaysToDiscard, const QVector<OverlayID>& overlaysToDiscard,
bool visibleOnly = false, bool collidableOnly = false); bool visibleOnly = false, bool collidableOnly = false);

View file

@ -16,11 +16,15 @@
#include "OverlayPanel.h" #include "OverlayPanel.h"
bool PanelAttachable::getParentVisible() const { bool PanelAttachable::getParentVisible() const {
#if OVERLAY_PANELS
if (getParentPanel()) { if (getParentPanel()) {
return getParentPanel()->getVisible() && getParentPanel()->getParentVisible(); return getParentPanel()->getVisible() && getParentPanel()->getParentVisible();
} else { } else {
return true; return true;
} }
#else
return true;
#endif
} }
QVariant PanelAttachable::getProperty(const QString& property) { QVariant PanelAttachable::getProperty(const QString& property) {
@ -61,11 +65,13 @@ void PanelAttachable::applyTransformTo(Transform& transform, bool force) {
if (force || usecTimestampNow() > _transformExpiry) { if (force || usecTimestampNow() > _transformExpiry) {
const quint64 TRANSFORM_UPDATE_PERIOD = 100000; // frequency is 10 Hz const quint64 TRANSFORM_UPDATE_PERIOD = 100000; // frequency is 10 Hz
_transformExpiry = usecTimestampNow() + TRANSFORM_UPDATE_PERIOD; _transformExpiry = usecTimestampNow() + TRANSFORM_UPDATE_PERIOD;
#if OVERLAY_PANELS
if (getParentPanel()) { if (getParentPanel()) {
getParentPanel()->applyTransformTo(transform, true); getParentPanel()->applyTransformTo(transform, true);
transform.postTranslate(getOffsetPosition()); transform.postTranslate(getOffsetPosition());
transform.postRotate(getOffsetRotation()); transform.postRotate(getOffsetRotation());
transform.postScale(getOffsetScale()); transform.postScale(getOffsetScale());
} }
#endif
} }
} }

View file

@ -30,6 +30,8 @@
#ifndef hifi_PanelAttachable_h #ifndef hifi_PanelAttachable_h
#define hifi_PanelAttachable_h #define hifi_PanelAttachable_h
#define OVERLAY_PANELS 0
#include <memory> #include <memory>
#include <glm/glm.hpp> #include <glm/glm.hpp>
@ -39,18 +41,21 @@
#include <QUuid> #include <QUuid>
class OverlayPanel; class OverlayPanel;
class PanelAttachable { class PanelAttachable {
public: public:
// getters // getters
#if OVERLAY_PANELS
std::shared_ptr<OverlayPanel> getParentPanel() const { return _parentPanel; } std::shared_ptr<OverlayPanel> getParentPanel() const { return _parentPanel; }
#endif
glm::vec3 getOffsetPosition() const { return _offset.getTranslation(); } glm::vec3 getOffsetPosition() const { return _offset.getTranslation(); }
glm::quat getOffsetRotation() const { return _offset.getRotation(); } glm::quat getOffsetRotation() const { return _offset.getRotation(); }
glm::vec3 getOffsetScale() const { return _offset.getScale(); } glm::vec3 getOffsetScale() const { return _offset.getScale(); }
bool getParentVisible() const; bool getParentVisible() const;
// setters // setters
#if OVERLAY_PANELS
void setParentPanel(std::shared_ptr<OverlayPanel> panel) { _parentPanel = panel; } void setParentPanel(std::shared_ptr<OverlayPanel> panel) { _parentPanel = panel; }
#endif
void setOffsetPosition(const glm::vec3& position) { _offset.setTranslation(position); } void setOffsetPosition(const glm::vec3& position) { _offset.setTranslation(position); }
void setOffsetRotation(const glm::quat& rotation) { _offset.setRotation(rotation); } void setOffsetRotation(const glm::quat& rotation) { _offset.setRotation(rotation); }
void setOffsetScale(float scale) { _offset.setScale(scale); } void setOffsetScale(float scale) { _offset.setScale(scale); }
@ -66,7 +71,9 @@ protected:
quint64 _transformExpiry = 0; quint64 _transformExpiry = 0;
private: private:
#if OVERLAY_PANELS
std::shared_ptr<OverlayPanel> _parentPanel = nullptr; std::shared_ptr<OverlayPanel> _parentPanel = nullptr;
#endif
Transform _offset; Transform _offset;
}; };

View file

@ -32,21 +32,20 @@ QmlOverlay::QmlOverlay(const QUrl& url, const QmlOverlay* textOverlay)
} }
void QmlOverlay::buildQmlElement(const QUrl& url) { void QmlOverlay::buildQmlElement(const QUrl& url) {
if (QThread::currentThread() != thread()) {
QMetaObject::invokeMethod(this, "buildQmlElement", Q_ARG(QUrl, url));
return;
}
auto offscreenUi = DependencyManager::get<OffscreenUi>(); auto offscreenUi = DependencyManager::get<OffscreenUi>();
offscreenUi->returnFromUiThread([=] { offscreenUi->load(url, [=](QQmlContext* context, QObject* object) {
offscreenUi->load(url, [=](QQmlContext* context, QObject* object) { QQuickItem* rawPtr = dynamic_cast<QQuickItem*>(object);
QQuickItem* rawPtr = dynamic_cast<QQuickItem*>(object); // Create a shared ptr with a custom deleter lambda, that calls deleteLater
// Create a shared ptr with a custom deleter lambda, that calls deleteLater _qmlElement = std::shared_ptr<QQuickItem>(rawPtr, [](QQuickItem* ptr) {
_qmlElement = std::shared_ptr<QQuickItem>(rawPtr, [](QQuickItem* ptr) { if (ptr) {
if (ptr) { ptr->deleteLater();
ptr->deleteLater(); }
}
});
}); });
while (!_qmlElement) {
qApp->processEvents();
}
return QVariant();
}); });
} }
@ -55,20 +54,23 @@ QmlOverlay::~QmlOverlay() {
} }
void QmlOverlay::setProperties(const QVariantMap& properties) { void QmlOverlay::setProperties(const QVariantMap& properties) {
if (QThread::currentThread() != thread()) {
QMetaObject::invokeMethod(this, "setProperties", Q_ARG(QVariantMap, properties));
return;
}
Overlay2D::setProperties(properties); Overlay2D::setProperties(properties);
auto bounds = _bounds; auto bounds = _bounds;
std::weak_ptr<QQuickItem> weakQmlElement = _qmlElement; std::weak_ptr<QQuickItem> weakQmlElement = _qmlElement;
DependencyManager::get<OffscreenUi>()->executeOnUiThread([weakQmlElement, bounds, properties] { // check to see if qmlElement still exists
// check to see if qmlElement still exists auto qmlElement = weakQmlElement.lock();
auto qmlElement = weakQmlElement.lock(); if (qmlElement) {
if (qmlElement) { qmlElement->setX(bounds.left());
qmlElement->setX(bounds.left()); qmlElement->setY(bounds.top());
qmlElement->setY(bounds.top()); qmlElement->setWidth(bounds.width());
qmlElement->setWidth(bounds.width()); qmlElement->setHeight(bounds.height());
qmlElement->setHeight(bounds.height()); QMetaObject::invokeMethod(qmlElement.get(), "updatePropertiesFromScript", Qt::DirectConnection, Q_ARG(QVariant, properties));
QMetaObject::invokeMethod(qmlElement.get(), "updatePropertiesFromScript", Qt::DirectConnection, Q_ARG(QVariant, properties)); }
}
});
} }
void QmlOverlay::render(RenderArgs* args) { void QmlOverlay::render(RenderArgs* args) {

View file

@ -32,7 +32,7 @@ public:
void render(RenderArgs* args) override; void render(RenderArgs* args) override;
private: private:
void buildQmlElement(const QUrl& url); Q_INVOKABLE void buildQmlElement(const QUrl& url);
protected: protected:
std::shared_ptr<QQuickItem> _qmlElement; std::shared_ptr<QQuickItem> _qmlElement;

View file

@ -9,15 +9,18 @@
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
// //
#include "AnimationCache.h"
#include <QRunnable> #include <QRunnable>
#include <QThreadPool> #include <QThreadPool>
#include "AnimationCache.h" #include <shared/QtHelpers.h>
#include "AnimationLogging.h"
#include <Trace.h> #include <Trace.h>
#include <StatTracker.h> #include <StatTracker.h>
#include <Profile.h> #include <Profile.h>
#include "AnimationLogging.h"
int animationPointerMetaTypeId = qRegisterMetaType<AnimationPointer>(); int animationPointerMetaTypeId = qRegisterMetaType<AnimationPointer>();
AnimationCache::AnimationCache(QObject* parent) : AnimationCache::AnimationCache(QObject* parent) :
@ -31,7 +34,7 @@ AnimationCache::AnimationCache(QObject* parent) :
AnimationPointer AnimationCache::getAnimation(const QUrl& url) { AnimationPointer AnimationCache::getAnimation(const QUrl& url) {
if (QThread::currentThread() != thread()) { if (QThread::currentThread() != thread()) {
AnimationPointer result; AnimationPointer result;
QMetaObject::invokeMethod(this, "getAnimation", Qt::BlockingQueuedConnection, BLOCKING_INVOKE_METHOD(this, "getAnimation",
Q_RETURN_ARG(AnimationPointer, result), Q_ARG(const QUrl&, url)); Q_RETURN_ARG(AnimationPointer, result), Q_ARG(const QUrl&, url));
return result; return result;
} }
@ -97,7 +100,7 @@ bool Animation::isLoaded() const {
QStringList Animation::getJointNames() const { QStringList Animation::getJointNames() const {
if (QThread::currentThread() != thread()) { if (QThread::currentThread() != thread()) {
QStringList result; QStringList result;
QMetaObject::invokeMethod(const_cast<Animation*>(this), "getJointNames", Qt::BlockingQueuedConnection, BLOCKING_INVOKE_METHOD(const_cast<Animation*>(this), "getJointNames",
Q_RETURN_ARG(QStringList, result)); Q_RETURN_ARG(QStringList, result));
return result; return result;
} }
@ -111,7 +114,7 @@ QStringList Animation::getJointNames() const {
QVector<FBXAnimationFrame> Animation::getFrames() const { QVector<FBXAnimationFrame> Animation::getFrames() const {
if (QThread::currentThread() != thread()) { if (QThread::currentThread() != thread()) {
QVector<FBXAnimationFrame> result; QVector<FBXAnimationFrame> result;
QMetaObject::invokeMethod(const_cast<Animation*>(this), "getFrames", Qt::BlockingQueuedConnection, BLOCKING_INVOKE_METHOD(const_cast<Animation*>(this), "getFrames",
Q_RETURN_ARG(QVector<FBXAnimationFrame>, result)); Q_RETURN_ARG(QVector<FBXAnimationFrame>, result));
return result; return result;
} }

View file

@ -259,10 +259,21 @@ void AudioClient::customDeleter() {
void AudioClient::cleanupBeforeQuit() { void AudioClient::cleanupBeforeQuit() {
// FIXME: this should be put in customDeleter, but there is still a reference to this when it is called, // FIXME: this should be put in customDeleter, but there is still a reference to this when it is called,
// so this must be explicitly, synchronously stopped // so this must be explicitly, synchronously stopped
static ConditionalGuard guard;
if (QThread::currentThread() != thread()) {
// This will likely be called from the main thread, but we don't want to do blocking queued calls
// from the main thread, so we use a normal auto-connection invoke, and then use a conditional to wait
// for completion
// The effect is the same, yes, but we actually want to avoid the use of Qt::BlockingQueuedConnection
// in the code
QMetaObject::invokeMethod(this, "cleanupBeforeQuit");
guard.wait();
return;
}
stop(); stop();
_checkDevicesTimer->stop(); _checkDevicesTimer->stop();
guard.trigger();
} }
void AudioClient::handleMismatchAudioFormat(SharedNodePointer node, const QString& currentCodec, const QString& recievedCodec) { void AudioClient::handleMismatchAudioFormat(SharedNodePointer node, const QString& currentCodec, const QString& recievedCodec) {
@ -1335,6 +1346,14 @@ void AudioClient::toggleMute() {
emit muteToggled(); emit muteToggled();
} }
void AudioClient::setNoiseReduction(bool enable) {
if (_isNoiseGateEnabled != enable) {
_isNoiseGateEnabled = enable;
emit noiseReductionChanged();
}
}
void AudioClient::setIsStereoInput(bool isStereoInput) { void AudioClient::setIsStereoInput(bool isStereoInput) {
if (isStereoInput != _isStereoInput) { if (isStereoInput != _isStereoInput) {
_isStereoInput = isStereoInput; _isStereoInput = isStereoInput;
@ -1446,6 +1465,8 @@ bool AudioClient::switchInputToAudioDevice(const QAudioDeviceInfo& inputDeviceIn
_audioInput = new QAudioInput(inputDeviceInfo, _inputFormat, this); _audioInput = new QAudioInput(inputDeviceInfo, _inputFormat, this);
_numInputCallbackBytes = calculateNumberOfInputCallbackBytes(_inputFormat); _numInputCallbackBytes = calculateNumberOfInputCallbackBytes(_inputFormat);
_audioInput->setBufferSize(_numInputCallbackBytes); _audioInput->setBufferSize(_numInputCallbackBytes);
// different audio input devices may have different volumes
emit inputVolumeChanged(_audioInput->volume());
// how do we want to handle input working, but output not working? // how do we want to handle input working, but output not working?
int numFrameSamples = calculateNumberOfFrameSamples(_numInputCallbackBytes); int numFrameSamples = calculateNumberOfFrameSamples(_numInputCallbackBytes);
@ -1703,7 +1724,7 @@ float AudioClient::azimuthForSource(const glm::vec3& relativePosition) {
// produce an oriented angle about the y-axis // produce an oriented angle about the y-axis
glm::vec3 direction = rotatedSourcePosition * (1.0f / fastSqrtf(rotatedSourcePositionLength2)); glm::vec3 direction = rotatedSourcePosition * (1.0f / fastSqrtf(rotatedSourcePositionLength2));
float angle = fastAcosf(glm::clamp(-direction.z, -1.0f, 1.0f)); // UNIT_NEG_Z is "forward" float angle = fastAcosf(glm::clamp(-direction.z, -1.0f, 1.0f)); // UNIT_NEG_Z is "forward"
return (direction.x < 0.0f) ? -angle : angle; return (direction.x < 0.0f) ? -angle : angle;
} else { } else {
@ -1847,3 +1868,10 @@ void AudioClient::setAvatarBoundingBoxParameters(glm::vec3 corner, glm::vec3 sca
void AudioClient::startThread() { void AudioClient::startThread() {
moveToNewNamedThread(this, "Audio Thread", [this] { start(); }); moveToNewNamedThread(this, "Audio Thread", [this] { start(); });
} }
void AudioClient::setInputVolume(float volume) {
if (_audioInput && volume != (float)_audioInput->volume()) {
_audioInput->setVolume(volume);
emit inputVolumeChanged(_audioInput->volume());
}
}

View file

@ -180,7 +180,8 @@ public slots:
virtual void setIsStereoInput(bool stereo) override; virtual void setIsStereoInput(bool stereo) override;
void setNoiseReduction(bool isNoiseGateEnabled) { _isNoiseGateEnabled = isNoiseGateEnabled; } void setNoiseReduction(bool isNoiseGateEnabled);
bool isNoiseReductionEnabled() const { return _isNoiseGateEnabled; }
void toggleLocalEcho() { _shouldEchoLocally = !_shouldEchoLocally; } void toggleLocalEcho() { _shouldEchoLocally = !_shouldEchoLocally; }
void toggleServerEcho() { _shouldEchoToServer = !_shouldEchoToServer; } void toggleServerEcho() { _shouldEchoToServer = !_shouldEchoToServer; }
@ -197,7 +198,7 @@ public slots:
bool switchAudioDevice(QAudio::Mode mode, const QString& deviceName); bool switchAudioDevice(QAudio::Mode mode, const QString& deviceName);
float getInputVolume() const { return (_audioInput) ? (float)_audioInput->volume() : 0.0f; } float getInputVolume() const { return (_audioInput) ? (float)_audioInput->volume() : 0.0f; }
void setInputVolume(float volume) { if (_audioInput) _audioInput->setVolume(volume); } void setInputVolume(float volume);
void setReverb(bool reverb); void setReverb(bool reverb);
void setReverbOptions(const AudioEffectOptions* options); void setReverbOptions(const AudioEffectOptions* options);
@ -207,7 +208,9 @@ public slots:
void saveSettings(); void saveSettings();
signals: signals:
bool muteToggled(); void inputVolumeChanged(float volume);
void muteToggled();
void noiseReductionChanged();
void mutedByMixer(); void mutedByMixer();
void inputReceived(const QByteArray& inputSamples); void inputReceived(const QByteArray& inputSamples);
void inputLoudnessChanged(float loudness); void inputLoudnessChanged(float loudness);

View file

@ -9,10 +9,13 @@
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
// //
#include <qthread.h> #include "SoundCache.h"
#include <QtCore/QThread>
#include <shared/QtHelpers.h>
#include "AudioLogging.h" #include "AudioLogging.h"
#include "SoundCache.h"
static const int SOUNDS_LOADING_PRIORITY { -7 }; // Make sure sounds load after the low rez texture mips static const int SOUNDS_LOADING_PRIORITY { -7 }; // Make sure sounds load after the low rez texture mips
@ -29,7 +32,7 @@ SoundCache::SoundCache(QObject* parent) :
SharedSoundPointer SoundCache::getSound(const QUrl& url) { SharedSoundPointer SoundCache::getSound(const QUrl& url) {
if (QThread::currentThread() != thread()) { if (QThread::currentThread() != thread()) {
SharedSoundPointer result; SharedSoundPointer result;
QMetaObject::invokeMethod(this, "getSound", Qt::BlockingQueuedConnection, BLOCKING_INVOKE_METHOD(this, "getSound",
Q_RETURN_ARG(SharedSoundPointer, result), Q_ARG(const QUrl&, url)); Q_RETURN_ARG(SharedSoundPointer, result), Q_ARG(const QUrl&, url));
return result; return result;
} }

View file

@ -15,6 +15,7 @@
#include <glm/gtx/transform.hpp> #include <glm/gtx/transform.hpp>
#include <glm/gtx/vector_query.hpp> #include <glm/gtx/vector_query.hpp>
#include <shared/QtHelpers.h>
#include <DeferredLightingEffect.h> #include <DeferredLightingEffect.h>
#include <EntityTreeRenderer.h> #include <EntityTreeRenderer.h>
#include <NodeList.h> #include <NodeList.h>
@ -1010,7 +1011,7 @@ glm::vec3 Avatar::getAbsoluteJointTranslationInObjectFrame(int index) const {
int Avatar::getJointIndex(const QString& name) const { int Avatar::getJointIndex(const QString& name) const {
if (QThread::currentThread() != thread()) { if (QThread::currentThread() != thread()) {
int result; int result;
QMetaObject::invokeMethod(const_cast<Avatar*>(this), "getJointIndex", Qt::BlockingQueuedConnection, BLOCKING_INVOKE_METHOD(const_cast<Avatar*>(this), "getJointIndex",
Q_RETURN_ARG(int, result), Q_ARG(const QString&, name)); Q_RETURN_ARG(int, result), Q_ARG(const QString&, name));
return result; return result;
} }
@ -1024,7 +1025,7 @@ int Avatar::getJointIndex(const QString& name) const {
QStringList Avatar::getJointNames() const { QStringList Avatar::getJointNames() const {
if (QThread::currentThread() != thread()) { if (QThread::currentThread() != thread()) {
QStringList result; QStringList result;
QMetaObject::invokeMethod(const_cast<Avatar*>(this), "getJointNames", Qt::BlockingQueuedConnection, BLOCKING_INVOKE_METHOD(const_cast<Avatar*>(this), "getJointNames",
Q_RETURN_ARG(QStringList, result)); Q_RETURN_ARG(QStringList, result));
return result; return result;
} }
@ -1034,7 +1035,7 @@ QStringList Avatar::getJointNames() const {
glm::vec3 Avatar::getJointPosition(int index) const { glm::vec3 Avatar::getJointPosition(int index) const {
if (QThread::currentThread() != thread()) { if (QThread::currentThread() != thread()) {
glm::vec3 position; glm::vec3 position;
QMetaObject::invokeMethod(const_cast<Avatar*>(this), "getJointPosition", Qt::BlockingQueuedConnection, BLOCKING_INVOKE_METHOD(const_cast<Avatar*>(this), "getJointPosition",
Q_RETURN_ARG(glm::vec3, position), Q_ARG(const int, index)); Q_RETURN_ARG(glm::vec3, position), Q_ARG(const int, index));
return position; return position;
} }
@ -1046,7 +1047,7 @@ glm::vec3 Avatar::getJointPosition(int index) const {
glm::vec3 Avatar::getJointPosition(const QString& name) const { glm::vec3 Avatar::getJointPosition(const QString& name) const {
if (QThread::currentThread() != thread()) { if (QThread::currentThread() != thread()) {
glm::vec3 position; glm::vec3 position;
QMetaObject::invokeMethod(const_cast<Avatar*>(this), "getJointPosition", Qt::BlockingQueuedConnection, BLOCKING_INVOKE_METHOD(const_cast<Avatar*>(this), "getJointPosition",
Q_RETURN_ARG(glm::vec3, position), Q_ARG(const QString&, name)); Q_RETURN_ARG(glm::vec3, position), Q_ARG(const QString&, name));
return position; return position;
} }
@ -1105,7 +1106,7 @@ static std::shared_ptr<Model> allocateAttachmentModel(bool isSoft, const Rig& ri
void Avatar::setAttachmentData(const QVector<AttachmentData>& attachmentData) { void Avatar::setAttachmentData(const QVector<AttachmentData>& attachmentData) {
if (QThread::currentThread() != thread()) { if (QThread::currentThread() != thread()) {
QMetaObject::invokeMethod(this, "setAttachmentData", Qt::BlockingQueuedConnection, BLOCKING_INVOKE_METHOD(this, "setAttachmentData",
Q_ARG(const QVector<AttachmentData>, attachmentData)); Q_ARG(const QVector<AttachmentData>, attachmentData));
return; return;
} }

View file

@ -25,6 +25,7 @@
#include <QtNetwork/QNetworkReply> #include <QtNetwork/QNetworkReply>
#include <QtNetwork/QNetworkRequest> #include <QtNetwork/QNetworkRequest>
#include <shared/QtHelpers.h>
#include <QVariantGLM.h> #include <QVariantGLM.h>
#include <Transform.h> #include <Transform.h>
#include <NetworkAccessManager.h> #include <NetworkAccessManager.h>
@ -1227,7 +1228,7 @@ bool AvatarData::isJointDataValid(int index) const {
} }
if (QThread::currentThread() != thread()) { if (QThread::currentThread() != thread()) {
bool result; bool result;
QMetaObject::invokeMethod(const_cast<AvatarData*>(this), "isJointDataValid", Qt::BlockingQueuedConnection, BLOCKING_INVOKE_METHOD(const_cast<AvatarData*>(this), "isJointDataValid",
Q_RETURN_ARG(bool, result), Q_ARG(int, index)); Q_RETURN_ARG(bool, result), Q_ARG(int, index));
return result; return result;
} }
@ -1240,7 +1241,7 @@ glm::quat AvatarData::getJointRotation(int index) const {
} }
if (QThread::currentThread() != thread()) { if (QThread::currentThread() != thread()) {
glm::quat result; glm::quat result;
QMetaObject::invokeMethod(const_cast<AvatarData*>(this), "getJointRotation", Qt::BlockingQueuedConnection, BLOCKING_INVOKE_METHOD(const_cast<AvatarData*>(this), "getJointRotation",
Q_RETURN_ARG(glm::quat, result), Q_ARG(int, index)); Q_RETURN_ARG(glm::quat, result), Q_ARG(int, index));
return result; return result;
} }
@ -1255,7 +1256,7 @@ glm::vec3 AvatarData::getJointTranslation(int index) const {
} }
if (QThread::currentThread() != thread()) { if (QThread::currentThread() != thread()) {
glm::vec3 result; glm::vec3 result;
QMetaObject::invokeMethod(const_cast<AvatarData*>(this), "getJointTranslation", Qt::BlockingQueuedConnection, BLOCKING_INVOKE_METHOD(const_cast<AvatarData*>(this), "getJointTranslation",
Q_RETURN_ARG(glm::vec3, result), Q_ARG(int, index)); Q_RETURN_ARG(glm::vec3, result), Q_ARG(int, index));
return result; return result;
} }
@ -1266,7 +1267,7 @@ glm::vec3 AvatarData::getJointTranslation(int index) const {
glm::vec3 AvatarData::getJointTranslation(const QString& name) const { glm::vec3 AvatarData::getJointTranslation(const QString& name) const {
if (QThread::currentThread() != thread()) { if (QThread::currentThread() != thread()) {
glm::vec3 result; glm::vec3 result;
QMetaObject::invokeMethod(const_cast<AvatarData*>(this), "getJointTranslation", Qt::BlockingQueuedConnection, BLOCKING_INVOKE_METHOD(const_cast<AvatarData*>(this), "getJointTranslation",
Q_RETURN_ARG(glm::vec3, result), Q_ARG(const QString&, name)); Q_RETURN_ARG(glm::vec3, result), Q_ARG(const QString&, name));
return result; return result;
} }
@ -1344,7 +1345,7 @@ void AvatarData::clearJointData(const QString& name) {
bool AvatarData::isJointDataValid(const QString& name) const { bool AvatarData::isJointDataValid(const QString& name) const {
if (QThread::currentThread() != thread()) { if (QThread::currentThread() != thread()) {
bool result; bool result;
QMetaObject::invokeMethod(const_cast<AvatarData*>(this), "isJointDataValid", Qt::BlockingQueuedConnection, BLOCKING_INVOKE_METHOD(const_cast<AvatarData*>(this), "isJointDataValid",
Q_RETURN_ARG(bool, result), Q_ARG(const QString&, name)); Q_RETURN_ARG(bool, result), Q_ARG(const QString&, name));
return result; return result;
} }
@ -1354,7 +1355,7 @@ bool AvatarData::isJointDataValid(const QString& name) const {
glm::quat AvatarData::getJointRotation(const QString& name) const { glm::quat AvatarData::getJointRotation(const QString& name) const {
if (QThread::currentThread() != thread()) { if (QThread::currentThread() != thread()) {
glm::quat result; glm::quat result;
QMetaObject::invokeMethod(const_cast<AvatarData*>(this), "getJointRotation", Qt::BlockingQueuedConnection, BLOCKING_INVOKE_METHOD(const_cast<AvatarData*>(this), "getJointRotation",
Q_RETURN_ARG(glm::quat, result), Q_ARG(const QString&, name)); Q_RETURN_ARG(glm::quat, result), Q_ARG(const QString&, name));
return result; return result;
} }
@ -1364,8 +1365,7 @@ glm::quat AvatarData::getJointRotation(const QString& name) const {
QVector<glm::quat> AvatarData::getJointRotations() const { QVector<glm::quat> AvatarData::getJointRotations() const {
if (QThread::currentThread() != thread()) { if (QThread::currentThread() != thread()) {
QVector<glm::quat> result; QVector<glm::quat> result;
QMetaObject::invokeMethod(const_cast<AvatarData*>(this), BLOCKING_INVOKE_METHOD(const_cast<AvatarData*>(this), "getJointRotations",
"getJointRotations", Qt::BlockingQueuedConnection,
Q_RETURN_ARG(QVector<glm::quat>, result)); Q_RETURN_ARG(QVector<glm::quat>, result));
return result; return result;
} }
@ -1380,8 +1380,7 @@ QVector<glm::quat> AvatarData::getJointRotations() const {
void AvatarData::setJointRotations(QVector<glm::quat> jointRotations) { void AvatarData::setJointRotations(QVector<glm::quat> jointRotations) {
if (QThread::currentThread() != thread()) { if (QThread::currentThread() != thread()) {
QVector<glm::quat> result; QVector<glm::quat> result;
QMetaObject::invokeMethod(const_cast<AvatarData*>(this), BLOCKING_INVOKE_METHOD(const_cast<AvatarData*>(this), "setJointRotations",
"setJointRotations", Qt::BlockingQueuedConnection,
Q_ARG(QVector<glm::quat>, jointRotations)); Q_ARG(QVector<glm::quat>, jointRotations));
} }
QWriteLocker writeLock(&_jointDataLock); QWriteLocker writeLock(&_jointDataLock);
@ -1398,8 +1397,7 @@ void AvatarData::setJointRotations(QVector<glm::quat> jointRotations) {
QVector<glm::vec3> AvatarData::getJointTranslations() const { QVector<glm::vec3> AvatarData::getJointTranslations() const {
if (QThread::currentThread() != thread()) { if (QThread::currentThread() != thread()) {
QVector<glm::vec3> result; QVector<glm::vec3> result;
QMetaObject::invokeMethod(const_cast<AvatarData*>(this), BLOCKING_INVOKE_METHOD(const_cast<AvatarData*>(this), "getJointTranslations",
"getJointTranslations", Qt::BlockingQueuedConnection,
Q_RETURN_ARG(QVector<glm::vec3>, result)); Q_RETURN_ARG(QVector<glm::vec3>, result));
return result; return result;
} }
@ -1414,8 +1412,7 @@ QVector<glm::vec3> AvatarData::getJointTranslations() const {
void AvatarData::setJointTranslations(QVector<glm::vec3> jointTranslations) { void AvatarData::setJointTranslations(QVector<glm::vec3> jointTranslations) {
if (QThread::currentThread() != thread()) { if (QThread::currentThread() != thread()) {
QVector<glm::quat> result; QVector<glm::quat> result;
QMetaObject::invokeMethod(const_cast<AvatarData*>(this), BLOCKING_INVOKE_METHOD(const_cast<AvatarData*>(this), "setJointTranslations",
"setJointTranslations", Qt::BlockingQueuedConnection,
Q_ARG(QVector<glm::vec3>, jointTranslations)); Q_ARG(QVector<glm::vec3>, jointTranslations));
} }
QWriteLocker writeLock(&_jointDataLock); QWriteLocker writeLock(&_jointDataLock);
@ -1616,7 +1613,7 @@ void AvatarData::setDisplayName(const QString& displayName) {
QVector<AttachmentData> AvatarData::getAttachmentData() const { QVector<AttachmentData> AvatarData::getAttachmentData() const {
if (QThread::currentThread() != thread()) { if (QThread::currentThread() != thread()) {
QVector<AttachmentData> result; QVector<AttachmentData> result;
QMetaObject::invokeMethod(const_cast<AvatarData*>(this), "getAttachmentData", Qt::BlockingQueuedConnection, BLOCKING_INVOKE_METHOD(const_cast<AvatarData*>(this), "getAttachmentData",
Q_RETURN_ARG(QVector<AttachmentData>, result)); Q_RETURN_ARG(QVector<AttachmentData>, result));
return result; return result;
} }
@ -1978,7 +1975,7 @@ JointData jointDataFromJsonValue(const QJsonValue& json) {
result.rotation = quatFromJsonValue(array[0]); result.rotation = quatFromJsonValue(array[0]);
result.rotationSet = true; result.rotationSet = true;
result.translation = vec3FromJsonValue(array[1]); result.translation = vec3FromJsonValue(array[1]);
result.translationSet = false; result.translationSet = true;
} }
return result; return result;
} }
@ -2146,12 +2143,9 @@ void AvatarData::fromJson(const QJsonObject& json, bool useFrameSkeleton) {
QVector<JointData> jointArray; QVector<JointData> jointArray;
QJsonArray jointArrayJson = json[JSON_AVATAR_JOINT_ARRAY].toArray(); QJsonArray jointArrayJson = json[JSON_AVATAR_JOINT_ARRAY].toArray();
jointArray.reserve(jointArrayJson.size()); jointArray.reserve(jointArrayJson.size());
int i = 0;
for (const auto& jointJson : jointArrayJson) { for (const auto& jointJson : jointArrayJson) {
auto joint = jointDataFromJsonValue(jointJson); auto joint = jointDataFromJsonValue(jointJson);
jointArray.push_back(joint); jointArray.push_back(joint);
setJointData(i, joint.rotation, joint.translation);
i++;
} }
setRawJointData(jointArray); setRawJointData(jointArray);
} }
@ -2342,7 +2336,7 @@ void AvatarData::clearAvatarEntity(const QUuid& entityID) {
AvatarEntityMap AvatarData::getAvatarEntityData() const { AvatarEntityMap AvatarData::getAvatarEntityData() const {
AvatarEntityMap result; AvatarEntityMap result;
if (QThread::currentThread() != thread()) { if (QThread::currentThread() != thread()) {
QMetaObject::invokeMethod(const_cast<AvatarData*>(this), "getAvatarEntityData", Qt::BlockingQueuedConnection, BLOCKING_INVOKE_METHOD(const_cast<AvatarData*>(this), "getAvatarEntityData",
Q_RETURN_ARG(AvatarEntityMap, result)); Q_RETURN_ARG(AvatarEntityMap, result));
return result; return result;
} }
@ -2383,7 +2377,7 @@ void AvatarData::setAvatarEntityData(const AvatarEntityMap& avatarEntityData) {
AvatarEntityIDs AvatarData::getAndClearRecentlyDetachedIDs() { AvatarEntityIDs AvatarData::getAndClearRecentlyDetachedIDs() {
AvatarEntityIDs result; AvatarEntityIDs result;
if (QThread::currentThread() != thread()) { if (QThread::currentThread() != thread()) {
QMetaObject::invokeMethod(const_cast<AvatarData*>(this), "getAndClearRecentlyDetachedIDs", Qt::BlockingQueuedConnection, BLOCKING_INVOKE_METHOD(const_cast<AvatarData*>(this), "getAndClearRecentlyDetachedIDs",
Q_RETURN_ARG(AvatarEntityIDs, result)); Q_RETURN_ARG(AvatarEntityIDs, result));
return result; return result;
} }

View file

@ -627,6 +627,7 @@ public:
void markIdentityDataChanged() { _identityDataChanged = true; } void markIdentityDataChanged() { _identityDataChanged = true; }
void pushIdentitySequenceNumber() { ++_identitySequenceNumber; }; void pushIdentitySequenceNumber() { ++_identitySequenceNumber; };
bool hasProcessedFirstIdentity() const { return _hasProcessedFirstIdentity; }
float getDensity() const { return _density; } float getDensity() const { return _density; }

View file

@ -59,6 +59,48 @@ namespace controller {
makePosePair(Action::SPINE2, "Spine2"), makePosePair(Action::SPINE2, "Spine2"),
makePosePair(Action::HEAD, "Head"), makePosePair(Action::HEAD, "Head"),
makePosePair(Action::LEFT_HAND_THUMB1, "LeftHandThumb1"),
makePosePair(Action::LEFT_HAND_THUMB2, "LeftHandThumb2"),
makePosePair(Action::LEFT_HAND_THUMB3, "LeftHandThumb3"),
makePosePair(Action::LEFT_HAND_THUMB4, "LeftHandThumb4"),
makePosePair(Action::LEFT_HAND_INDEX1, "LeftHandIndex1"),
makePosePair(Action::LEFT_HAND_INDEX2, "LeftHandIndex2"),
makePosePair(Action::LEFT_HAND_INDEX3, "LeftHandIndex3"),
makePosePair(Action::LEFT_HAND_INDEX4, "LeftHandIndex4"),
makePosePair(Action::LEFT_HAND_MIDDLE1, "LeftHandMiddle1"),
makePosePair(Action::LEFT_HAND_MIDDLE2, "LeftHandMiddle2"),
makePosePair(Action::LEFT_HAND_MIDDLE3, "LeftHandMiddle3"),
makePosePair(Action::LEFT_HAND_MIDDLE4, "LeftHandMiddle4"),
makePosePair(Action::LEFT_HAND_RING1, "LeftHandRing1"),
makePosePair(Action::LEFT_HAND_RING2, "LeftHandRing2"),
makePosePair(Action::LEFT_HAND_RING3, "LeftHandRing3"),
makePosePair(Action::LEFT_HAND_RING4, "LeftHandRing4"),
makePosePair(Action::LEFT_HAND_PINKY1, "LeftHandPinky1"),
makePosePair(Action::LEFT_HAND_PINKY2, "LeftHandPinky2"),
makePosePair(Action::LEFT_HAND_PINKY3, "LeftHandPinky3"),
makePosePair(Action::LEFT_HAND_PINKY4, "LeftHandPinky4"),
makePosePair(Action::RIGHT_HAND_THUMB1, "RightHandThumb1"),
makePosePair(Action::RIGHT_HAND_THUMB2, "RightHandThumb2"),
makePosePair(Action::RIGHT_HAND_THUMB3, "RightHandThumb3"),
makePosePair(Action::RIGHT_HAND_THUMB4, "RightHandThumb4"),
makePosePair(Action::RIGHT_HAND_INDEX1, "RightHandIndex1"),
makePosePair(Action::RIGHT_HAND_INDEX2, "RightHandIndex2"),
makePosePair(Action::RIGHT_HAND_INDEX3, "RightHandIndex3"),
makePosePair(Action::RIGHT_HAND_INDEX4, "RightHandIndex4"),
makePosePair(Action::RIGHT_HAND_MIDDLE1, "RightHandMiddle1"),
makePosePair(Action::RIGHT_HAND_MIDDLE2, "RightHandMiddle2"),
makePosePair(Action::RIGHT_HAND_MIDDLE3, "RightHandMiddle3"),
makePosePair(Action::RIGHT_HAND_MIDDLE4, "RightHandMiddle4"),
makePosePair(Action::RIGHT_HAND_RING1, "RightHandRing1"),
makePosePair(Action::RIGHT_HAND_RING2, "RightHandRing2"),
makePosePair(Action::RIGHT_HAND_RING3, "RightHandRing3"),
makePosePair(Action::RIGHT_HAND_RING4, "RightHandRing4"),
makePosePair(Action::RIGHT_HAND_PINKY1, "RightHandPinky1"),
makePosePair(Action::RIGHT_HAND_PINKY2, "RightHandPinky2"),
makePosePair(Action::RIGHT_HAND_PINKY3, "RightHandPinky3"),
makePosePair(Action::RIGHT_HAND_PINKY4, "RightHandPinky4"),
makeButtonPair(Action::LEFT_HAND_CLICK, "LeftHandClick"), makeButtonPair(Action::LEFT_HAND_CLICK, "LeftHandClick"),
makeButtonPair(Action::RIGHT_HAND_CLICK, "RightHandClick"), makeButtonPair(Action::RIGHT_HAND_CLICK, "RightHandClick"),

View file

@ -104,6 +104,47 @@ enum class Action {
LEFT_ARM, LEFT_ARM,
RIGHT_ARM, RIGHT_ARM,
LEFT_HAND_THUMB1,
LEFT_HAND_THUMB2,
LEFT_HAND_THUMB3,
LEFT_HAND_THUMB4,
LEFT_HAND_INDEX1,
LEFT_HAND_INDEX2,
LEFT_HAND_INDEX3,
LEFT_HAND_INDEX4,
LEFT_HAND_MIDDLE1,
LEFT_HAND_MIDDLE2,
LEFT_HAND_MIDDLE3,
LEFT_HAND_MIDDLE4,
LEFT_HAND_RING1,
LEFT_HAND_RING2,
LEFT_HAND_RING3,
LEFT_HAND_RING4,
LEFT_HAND_PINKY1,
LEFT_HAND_PINKY2,
LEFT_HAND_PINKY3,
LEFT_HAND_PINKY4,
RIGHT_HAND_THUMB1,
RIGHT_HAND_THUMB2,
RIGHT_HAND_THUMB3,
RIGHT_HAND_THUMB4,
RIGHT_HAND_INDEX1,
RIGHT_HAND_INDEX2,
RIGHT_HAND_INDEX3,
RIGHT_HAND_INDEX4,
RIGHT_HAND_MIDDLE1,
RIGHT_HAND_MIDDLE2,
RIGHT_HAND_MIDDLE3,
RIGHT_HAND_MIDDLE4,
RIGHT_HAND_RING1,
RIGHT_HAND_RING2,
RIGHT_HAND_RING3,
RIGHT_HAND_RING4,
RIGHT_HAND_PINKY1,
RIGHT_HAND_PINKY2,
RIGHT_HAND_PINKY3,
RIGHT_HAND_PINKY4,
NUM_ACTIONS, NUM_ACTIONS,
}; };

View file

@ -101,7 +101,47 @@ Input::NamedVector StandardController::getAvailableInputs() const {
// Poses // Poses
makePair(LEFT_HAND, "LeftHand"), makePair(LEFT_HAND, "LeftHand"),
makePair(LEFT_HAND_THUMB1, "LeftHandThumb1"),
makePair(LEFT_HAND_THUMB2, "LeftHandThumb2"),
makePair(LEFT_HAND_THUMB3, "LeftHandThumb3"),
makePair(LEFT_HAND_THUMB4, "LeftHandThumb4"),
makePair(LEFT_HAND_INDEX1, "LeftHandIndex1"),
makePair(LEFT_HAND_INDEX2, "LeftHandIndex2"),
makePair(LEFT_HAND_INDEX3, "LeftHandIndex3"),
makePair(LEFT_HAND_INDEX4, "LeftHandIndex4"),
makePair(LEFT_HAND_MIDDLE1, "LeftHandMiddle1"),
makePair(LEFT_HAND_MIDDLE2, "LeftHandMiddle2"),
makePair(LEFT_HAND_MIDDLE3, "LeftHandMiddle3"),
makePair(LEFT_HAND_MIDDLE4, "LeftHandMiddle4"),
makePair(LEFT_HAND_RING1, "LeftHandRing1"),
makePair(LEFT_HAND_RING2, "LeftHandRing2"),
makePair(LEFT_HAND_RING3, "LeftHandRing3"),
makePair(LEFT_HAND_RING4, "LeftHandRing4"),
makePair(LEFT_HAND_PINKY1, "LeftHandPinky1"),
makePair(LEFT_HAND_PINKY2, "LeftHandPinky2"),
makePair(LEFT_HAND_PINKY3, "LeftHandPinky3"),
makePair(LEFT_HAND_PINKY4, "LeftHandPinky4"),
makePair(RIGHT_HAND, "RightHand"), makePair(RIGHT_HAND, "RightHand"),
makePair(RIGHT_HAND_THUMB1, "RightHandThumb1"),
makePair(RIGHT_HAND_THUMB2, "RightHandThumb2"),
makePair(RIGHT_HAND_THUMB3, "RightHandThumb3"),
makePair(RIGHT_HAND_THUMB4, "RightHandThumb4"),
makePair(RIGHT_HAND_INDEX1, "RightHandIndex1"),
makePair(RIGHT_HAND_INDEX2, "RightHandIndex2"),
makePair(RIGHT_HAND_INDEX3, "RightHandIndex3"),
makePair(RIGHT_HAND_INDEX4, "RightHandIndex4"),
makePair(RIGHT_HAND_MIDDLE1, "RightHandMiddle1"),
makePair(RIGHT_HAND_MIDDLE2, "RightHandMiddle2"),
makePair(RIGHT_HAND_MIDDLE3, "RightHandMiddle3"),
makePair(RIGHT_HAND_MIDDLE4, "RightHandMiddle4"),
makePair(RIGHT_HAND_RING1, "RightHandRing1"),
makePair(RIGHT_HAND_RING2, "RightHandRing2"),
makePair(RIGHT_HAND_RING3, "RightHandRing3"),
makePair(RIGHT_HAND_RING4, "RightHandRing4"),
makePair(RIGHT_HAND_PINKY1, "RightHandPinky1"),
makePair(RIGHT_HAND_PINKY2, "RightHandPinky2"),
makePair(RIGHT_HAND_PINKY3, "RightHandPinky3"),
makePair(RIGHT_HAND_PINKY4, "RightHandPinky4"),
makePair(LEFT_FOOT, "LeftFoot"), makePair(LEFT_FOOT, "LeftFoot"),
makePair(RIGHT_FOOT, "RightFoot"), makePair(RIGHT_FOOT, "RightFoot"),
makePair(RIGHT_ARM, "RightArm"), makePair(RIGHT_ARM, "RightArm"),

View file

@ -11,14 +11,16 @@
#include <memory> #include <memory>
#include <math.h> #include <math.h>
#include <glm/gtc/type_ptr.hpp>
#include <QtCore/QTimer> #include <QtCore/QTimer>
#include <QtCore/QThread> #include <QtCore/QThread>
#include <QtWidgets/QApplication> #include <QtWidgets/QApplication>
#include <QtWidgets/QDesktopWidget> #include <QtWidgets/QDesktopWidget>
#include <glm/gtc/type_ptr.hpp>
#include <QtGui/QWindow> #include <QtGui/QWindow>
#include <QQuickWindow> #include <QQuickWindow>
#include <shared/QtHelpers.h>
#include <ui/Menu.h> #include <ui/Menu.h>
#include <NumericalConstants.h> #include <NumericalConstants.h>
#include <DependencyManager.h> #include <DependencyManager.h>
@ -289,7 +291,7 @@ glm::vec2 CompositorHelper::getReticleMaximumPosition() const {
void CompositorHelper::sendFakeMouseEvent() { void CompositorHelper::sendFakeMouseEvent() {
if (qApp->thread() != QThread::currentThread()) { if (qApp->thread() != QThread::currentThread()) {
QMetaObject::invokeMethod(this, "sendFakeMouseEvent", Qt::BlockingQueuedConnection); BLOCKING_INVOKE_METHOD(this, "sendFakeMouseEvent");
return; return;
} }

View file

@ -17,6 +17,7 @@
#include <QScriptSyntaxCheckResult> #include <QScriptSyntaxCheckResult>
#include <QThreadPool> #include <QThreadPool>
#include <shared/QtHelpers.h>
#include <ColorUtils.h> #include <ColorUtils.h>
#include <AbstractScriptingServicesInterface.h> #include <AbstractScriptingServicesInterface.h>
#include <AbstractViewStateInterface.h> #include <AbstractViewStateInterface.h>
@ -380,7 +381,7 @@ ModelPointer EntityTreeRenderer::allocateModel(const QString& url, float loading
// Only create and delete models on the thread that owns the EntityTreeRenderer // Only create and delete models on the thread that owns the EntityTreeRenderer
if (QThread::currentThread() != thread()) { if (QThread::currentThread() != thread()) {
QMetaObject::invokeMethod(this, "allocateModel", Qt::BlockingQueuedConnection, BLOCKING_INVOKE_METHOD(this, "allocateModel",
Q_RETURN_ARG(ModelPointer, model), Q_RETURN_ARG(ModelPointer, model),
Q_ARG(const QString&, url)); Q_ARG(const QString&, url));
@ -397,7 +398,7 @@ ModelPointer EntityTreeRenderer::allocateModel(const QString& url, float loading
ModelPointer EntityTreeRenderer::updateModel(ModelPointer model, const QString& newUrl) { ModelPointer EntityTreeRenderer::updateModel(ModelPointer model, const QString& newUrl) {
// Only create and delete models on the thread that owns the EntityTreeRenderer // Only create and delete models on the thread that owns the EntityTreeRenderer
if (QThread::currentThread() != thread()) { if (QThread::currentThread() != thread()) {
QMetaObject::invokeMethod(this, "updateModel", Qt::BlockingQueuedConnection, BLOCKING_INVOKE_METHOD(this, "updateModel",
Q_RETURN_ARG(ModelPointer, model), Q_RETURN_ARG(ModelPointer, model),
Q_ARG(ModelPointer, model), Q_ARG(ModelPointer, model),
Q_ARG(const QString&, newUrl)); Q_ARG(const QString&, newUrl));

View file

@ -9,19 +9,20 @@
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
// //
#include "EntityScriptingInterface.h"
#include <glm/gtc/matrix_transform.hpp> #include <glm/gtc/matrix_transform.hpp>
#include <glm/gtx/transform.hpp> #include <glm/gtx/transform.hpp>
#include "EntityScriptingInterface.h"
#include <QFutureWatcher> #include <QFutureWatcher>
#include <QtConcurrent/QtConcurrentRun> #include <QtConcurrent/QtConcurrentRun>
#include "EntityItemID.h" #include <shared/QtHelpers.h>
#include <VariantMapToScriptValue.h> #include <VariantMapToScriptValue.h>
#include <SharedUtil.h> #include <SharedUtil.h>
#include <SpatialParentFinder.h> #include <SpatialParentFinder.h>
#include "EntityItemID.h"
#include "EntitiesLogging.h" #include "EntitiesLogging.h"
#include "EntityDynamicFactoryInterface.h" #include "EntityDynamicFactoryInterface.h"
#include "EntityDynamicInterface.h" #include "EntityDynamicInterface.h"
@ -1488,7 +1489,7 @@ int EntityScriptingInterface::getJointIndex(const QUuid& entityID, const QString
return -1; return -1;
} }
int result; int result;
QMetaObject::invokeMethod(_entityTree.get(), "getJointIndex", Qt::BlockingQueuedConnection, BLOCKING_INVOKE_METHOD(_entityTree.get(), "getJointIndex",
Q_RETURN_ARG(int, result), Q_ARG(QUuid, entityID), Q_ARG(QString, name)); Q_RETURN_ARG(int, result), Q_ARG(QUuid, entityID), Q_ARG(QString, name));
return result; return result;
} }
@ -1498,7 +1499,7 @@ QStringList EntityScriptingInterface::getJointNames(const QUuid& entityID) {
return QStringList(); return QStringList();
} }
QStringList result; QStringList result;
QMetaObject::invokeMethod(_entityTree.get(), "getJointNames", Qt::BlockingQueuedConnection, BLOCKING_INVOKE_METHOD(_entityTree.get(), "getJointNames",
Q_RETURN_ARG(QStringList, result), Q_ARG(QUuid, entityID)); Q_RETURN_ARG(QStringList, result), Q_ARG(QUuid, entityID));
return result; return result;
} }

View file

@ -114,7 +114,9 @@ GLBackend::CommandCall GLBackend::_commandCalls[Batch::NUM_COMMANDS] =
(&::gpu::gl::GLBackend::do_getQuery), (&::gpu::gl::GLBackend::do_getQuery),
(&::gpu::gl::GLBackend::do_resetStages), (&::gpu::gl::GLBackend::do_resetStages),
(&::gpu::gl::GLBackend::do_disableContextViewCorrection),
(&::gpu::gl::GLBackend::do_restoreContextViewCorrection),
(&::gpu::gl::GLBackend::do_disableContextStereo), (&::gpu::gl::GLBackend::do_disableContextStereo),
(&::gpu::gl::GLBackend::do_restoreContextStereo), (&::gpu::gl::GLBackend::do_restoreContextStereo),
@ -374,6 +376,13 @@ void GLBackend::do_resetStages(const Batch& batch, size_t paramOffset) {
resetStages(); resetStages();
} }
void GLBackend::do_disableContextViewCorrection(const Batch& batch, size_t paramOffset) {
_transform._viewCorrectionEnabled = false;
}
void GLBackend::do_restoreContextViewCorrection(const Batch& batch, size_t paramOffset) {
_transform._viewCorrectionEnabled = true;
}
void GLBackend::do_disableContextStereo(const Batch& batch, size_t paramOffset) { void GLBackend::do_disableContextStereo(const Batch& batch, size_t paramOffset) {

View file

@ -143,6 +143,10 @@ public:
// Reset stages // Reset stages
virtual void do_resetStages(const Batch& batch, size_t paramOffset) final; virtual void do_resetStages(const Batch& batch, size_t paramOffset) final;
virtual void do_disableContextViewCorrection(const Batch& batch, size_t paramOffset) final;
virtual void do_restoreContextViewCorrection(const Batch& batch, size_t paramOffset) final;
virtual void do_disableContextStereo(const Batch& batch, size_t paramOffset) final; virtual void do_disableContextStereo(const Batch& batch, size_t paramOffset) final;
virtual void do_restoreContextStereo(const Batch& batch, size_t paramOffset) final; virtual void do_restoreContextStereo(const Batch& batch, size_t paramOffset) final;
@ -333,6 +337,8 @@ protected:
bool _skybox { false }; bool _skybox { false };
Transform _view; Transform _view;
CameraCorrection _correction; CameraCorrection _correction;
bool _viewCorrectionEnabled{ true };
Mat4 _projection; Mat4 _projection;
Vec4i _viewport { 0, 0, 1, 1 }; Vec4i _viewport { 0, 0, 1, 1 };
@ -400,6 +406,7 @@ protected:
bool _invalidProgram { false }; bool _invalidProgram { false };
BufferView _cameraCorrectionBuffer { gpu::BufferView(std::make_shared<gpu::Buffer>(sizeof(CameraCorrection), nullptr )) }; BufferView _cameraCorrectionBuffer { gpu::BufferView(std::make_shared<gpu::Buffer>(sizeof(CameraCorrection), nullptr )) };
BufferView _cameraCorrectionBufferIdentity { gpu::BufferView(std::make_shared<gpu::Buffer>(sizeof(CameraCorrection), nullptr )) };
State::Data _stateCache{ State::DEFAULT }; State::Data _stateCache{ State::DEFAULT };
State::Signature _stateSignatureCache { 0 }; State::Signature _stateSignatureCache { 0 };
@ -409,6 +416,8 @@ protected:
PipelineStageState() { PipelineStageState() {
_cameraCorrectionBuffer.edit<CameraCorrection>() = CameraCorrection(); _cameraCorrectionBuffer.edit<CameraCorrection>() = CameraCorrection();
_cameraCorrectionBufferIdentity.edit<CameraCorrection>() = CameraCorrection();
_cameraCorrectionBufferIdentity._buffer->flush();
} }
} _pipeline; } _pipeline;

View file

@ -77,8 +77,14 @@ void GLBackend::do_setPipeline(const Batch& batch, size_t paramOffset) {
if (_pipeline._invalidProgram) { if (_pipeline._invalidProgram) {
glUseProgram(_pipeline._program); glUseProgram(_pipeline._program);
if (_pipeline._cameraCorrectionLocation != -1) { if (_pipeline._cameraCorrectionLocation != -1) {
auto cameraCorrectionBuffer = syncGPUObject(*_pipeline._cameraCorrectionBuffer._buffer); gl::GLBuffer* cameraCorrectionBuffer = nullptr;
if (_transform._viewCorrectionEnabled) {
cameraCorrectionBuffer = syncGPUObject(*_pipeline._cameraCorrectionBuffer._buffer);
} else {
cameraCorrectionBuffer = syncGPUObject(*_pipeline._cameraCorrectionBufferIdentity._buffer);
}
glBindBufferRange(GL_UNIFORM_BUFFER, _pipeline._cameraCorrectionLocation, cameraCorrectionBuffer->_id, 0, sizeof(CameraCorrection)); glBindBufferRange(GL_UNIFORM_BUFFER, _pipeline._cameraCorrectionLocation, cameraCorrectionBuffer->_id, 0, sizeof(CameraCorrection));
} }
(void) CHECK_GL_ERROR(); (void) CHECK_GL_ERROR();
_pipeline._invalidProgram = false; _pipeline._invalidProgram = false;

View file

@ -102,7 +102,7 @@ void GLBackend::TransformStageState::preUpdate(size_t commandIndex, const Stereo
if (_invalidView) { if (_invalidView) {
// Apply the correction // Apply the correction
if (_viewIsCamera && _correction.correction != glm::mat4()) { if (_viewIsCamera && (_viewCorrectionEnabled && _correction.correction != glm::mat4())) {
// FIXME should I switch to using the camera correction buffer in Transform.slf and leave this out? // FIXME should I switch to using the camera correction buffer in Transform.slf and leave this out?
Transform result; Transform result;
_view.mult(result, _view, _correction.correction); _view.mult(result, _view, _correction.correction);

View file

@ -390,6 +390,13 @@ void Batch::resetStages() {
ADD_COMMAND(resetStages); ADD_COMMAND(resetStages);
} }
void Batch::disableContextViewCorrection() {
ADD_COMMAND(disableContextViewCorrection);
}
void Batch::restoreContextViewCorrection() {
ADD_COMMAND(restoreContextViewCorrection);
}
void Batch::disableContextStereo() { void Batch::disableContextStereo() {
ADD_COMMAND(disableContextStereo); ADD_COMMAND(disableContextStereo);

View file

@ -217,6 +217,9 @@ public:
// Reset the stage caches and states // Reset the stage caches and states
void resetStages(); void resetStages();
void disableContextViewCorrection();
void restoreContextViewCorrection();
void disableContextStereo(); void disableContextStereo();
void restoreContextStereo(); void restoreContextStereo();
@ -304,6 +307,9 @@ public:
COMMAND_resetStages, COMMAND_resetStages,
COMMAND_disableContextViewCorrection,
COMMAND_restoreContextViewCorrection,
COMMAND_disableContextStereo, COMMAND_disableContextStereo,
COMMAND_restoreContextStereo, COMMAND_restoreContextStereo,

View file

@ -198,11 +198,7 @@ gpu::TexturePointer TextureCache::getTextureByHash(const std::string& hash) {
std::unique_lock<std::mutex> lock(_texturesByHashesMutex); std::unique_lock<std::mutex> lock(_texturesByHashesMutex);
weakPointer = _texturesByHashes[hash]; weakPointer = _texturesByHashes[hash];
} }
auto result = weakPointer.lock(); return weakPointer.lock();
if (result) {
qCWarning(modelnetworking) << "QQQ Returning live texture for hash " << hash.c_str();
}
return result;
} }
gpu::TexturePointer TextureCache::cacheTextureByHash(const std::string& hash, const gpu::TexturePointer& texture) { gpu::TexturePointer TextureCache::cacheTextureByHash(const std::string& hash, const gpu::TexturePointer& texture) {

View file

@ -19,6 +19,8 @@
#include <QtScript/QScriptEngine> #include <QtScript/QScriptEngine>
#include <QtNetwork/QNetworkDiskCache> #include <QtNetwork/QNetworkDiskCache>
#include <shared/GlobalAppProperties.h>
#include "AssetRequest.h" #include "AssetRequest.h"
#include "AssetUpload.h" #include "AssetUpload.h"
#include "AssetUtils.h" #include "AssetUtils.h"
@ -31,11 +33,12 @@
MessageID AssetClient::_currentID = 0; MessageID AssetClient::_currentID = 0;
AssetClient::AssetClient(const QString& cacheDir) : _cacheDir(cacheDir) { AssetClient::AssetClient() {
_cacheDir = qApp->property(hifi::properties::APP_LOCAL_DATA_PATH).toString();
setCustomDeleter([](Dependency* dependency){ setCustomDeleter([](Dependency* dependency){
static_cast<AssetClient*>(dependency)->deleteLater(); static_cast<AssetClient*>(dependency)->deleteLater();
}); });
auto nodeList = DependencyManager::get<NodeList>(); auto nodeList = DependencyManager::get<NodeList>();
auto& packetReceiver = nodeList->getPacketReceiver(); auto& packetReceiver = nodeList->getPacketReceiver();
@ -105,7 +108,7 @@ void AssetClient::handleAssetMappingOperationReply(QSharedPointer<ReceivedMessag
MessageID messageID; MessageID messageID;
message->readPrimitive(&messageID); message->readPrimitive(&messageID);
AssetServerError error; AssetServerError error;
message->readPrimitive(&error); message->readPrimitive(&error);
@ -132,13 +135,13 @@ void AssetClient::handleAssetMappingOperationReply(QSharedPointer<ReceivedMessag
bool haveAssetServer() { bool haveAssetServer() {
auto nodeList = DependencyManager::get<NodeList>(); auto nodeList = DependencyManager::get<NodeList>();
SharedNodePointer assetServer = nodeList->soloNodeOfType(NodeType::AssetServer); SharedNodePointer assetServer = nodeList->soloNodeOfType(NodeType::AssetServer);
if (!assetServer) { if (!assetServer) {
qCWarning(asset_client) << "Could not complete AssetClient operation " qCWarning(asset_client) << "Could not complete AssetClient operation "
<< "since you are not currently connected to an asset-server."; << "since you are not currently connected to an asset-server.";
return false; return false;
} }
return true; return true;
} }
@ -220,14 +223,14 @@ MessageID AssetClient::getAsset(const QString& hash, DataOffset start, DataOffse
SharedNodePointer assetServer = nodeList->soloNodeOfType(NodeType::AssetServer); SharedNodePointer assetServer = nodeList->soloNodeOfType(NodeType::AssetServer);
if (assetServer) { if (assetServer) {
auto messageID = ++_currentID; auto messageID = ++_currentID;
auto payloadSize = sizeof(messageID) + SHA256_HASH_LENGTH + sizeof(start) + sizeof(end); auto payloadSize = sizeof(messageID) + SHA256_HASH_LENGTH + sizeof(start) + sizeof(end);
auto packet = NLPacket::create(PacketType::AssetGet, payloadSize, true); auto packet = NLPacket::create(PacketType::AssetGet, payloadSize, true);
qCDebug(asset_client) << "Requesting data from" << start << "to" << end << "of" << hash << "from asset-server."; qCDebug(asset_client) << "Requesting data from" << start << "to" << end << "of" << hash << "from asset-server.";
packet->writePrimitive(messageID); packet->writePrimitive(messageID);
packet->write(QByteArray::fromHex(hash.toLatin1())); packet->write(QByteArray::fromHex(hash.toLatin1()));
@ -254,10 +257,10 @@ MessageID AssetClient::getAssetInfo(const QString& hash, GetInfoCallback callbac
if (assetServer) { if (assetServer) {
auto messageID = ++_currentID; auto messageID = ++_currentID;
auto payloadSize = sizeof(messageID) + SHA256_HASH_LENGTH; auto payloadSize = sizeof(messageID) + SHA256_HASH_LENGTH;
auto packet = NLPacket::create(PacketType::AssetGetInfo, payloadSize, true); auto packet = NLPacket::create(PacketType::AssetGetInfo, payloadSize, true);
packet->writePrimitive(messageID); packet->writePrimitive(messageID);
packet->write(QByteArray::fromHex(hash.toLatin1())); packet->write(QByteArray::fromHex(hash.toLatin1()));
@ -278,7 +281,7 @@ void AssetClient::handleAssetGetInfoReply(QSharedPointer<ReceivedMessage> messag
MessageID messageID; MessageID messageID;
message->readPrimitive(&messageID); message->readPrimitive(&messageID);
auto assetHash = message->read(SHA256_HASH_LENGTH); auto assetHash = message->read(SHA256_HASH_LENGTH);
AssetServerError error; AssetServerError error;
message->readPrimitive(&error); message->readPrimitive(&error);
@ -367,7 +370,7 @@ void AssetClient::handleAssetGetReply(QSharedPointer<ReceivedMessage> message, S
callbacks.completeCallback(true, error, message->readAll()); callbacks.completeCallback(true, error, message->readAll());
} }
messageCallbackMap.erase(requestIt); messageCallbackMap.erase(requestIt);
} }
} }
@ -478,7 +481,7 @@ MessageID AssetClient::getAllAssetMappings(MappingOperationCallback callback) {
auto nodeList = DependencyManager::get<NodeList>(); auto nodeList = DependencyManager::get<NodeList>();
SharedNodePointer assetServer = nodeList->soloNodeOfType(NodeType::AssetServer); SharedNodePointer assetServer = nodeList->soloNodeOfType(NodeType::AssetServer);
if (assetServer) { if (assetServer) {
auto packetList = NLPacketList::create(PacketType::AssetMappingOperation, QByteArray(), true, true); auto packetList = NLPacketList::create(PacketType::AssetMappingOperation, QByteArray(), true, true);
@ -501,7 +504,7 @@ MessageID AssetClient::getAllAssetMappings(MappingOperationCallback callback) {
MessageID AssetClient::deleteAssetMappings(const AssetPathList& paths, MappingOperationCallback callback) { MessageID AssetClient::deleteAssetMappings(const AssetPathList& paths, MappingOperationCallback callback) {
auto nodeList = DependencyManager::get<NodeList>(); auto nodeList = DependencyManager::get<NodeList>();
SharedNodePointer assetServer = nodeList->soloNodeOfType(NodeType::AssetServer); SharedNodePointer assetServer = nodeList->soloNodeOfType(NodeType::AssetServer);
if (assetServer) { if (assetServer) {
auto packetList = NLPacketList::create(PacketType::AssetMappingOperation, QByteArray(), true, true); auto packetList = NLPacketList::create(PacketType::AssetMappingOperation, QByteArray(), true, true);
@ -532,7 +535,7 @@ MessageID AssetClient::setAssetMapping(const QString& path, const AssetHash& has
auto nodeList = DependencyManager::get<NodeList>(); auto nodeList = DependencyManager::get<NodeList>();
SharedNodePointer assetServer = nodeList->soloNodeOfType(NodeType::AssetServer); SharedNodePointer assetServer = nodeList->soloNodeOfType(NodeType::AssetServer);
if (assetServer) { if (assetServer) {
auto packetList = NLPacketList::create(PacketType::AssetMappingOperation, QByteArray(), true, true); auto packetList = NLPacketList::create(PacketType::AssetMappingOperation, QByteArray(), true, true);
@ -644,7 +647,7 @@ MessageID AssetClient::uploadAsset(const QByteArray& data, UploadResultCallback
auto nodeList = DependencyManager::get<NodeList>(); auto nodeList = DependencyManager::get<NodeList>();
SharedNodePointer assetServer = nodeList->soloNodeOfType(NodeType::AssetServer); SharedNodePointer assetServer = nodeList->soloNodeOfType(NodeType::AssetServer);
if (assetServer) { if (assetServer) {
auto packetList = NLPacketList::create(PacketType::AssetUpload, QByteArray(), true, true); auto packetList = NLPacketList::create(PacketType::AssetUpload, QByteArray(), true, true);
@ -682,7 +685,7 @@ void AssetClient::handleAssetUploadReply(QSharedPointer<ReceivedMessage> message
} else { } else {
auto hash = message->read(SHA256_HASH_LENGTH); auto hash = message->read(SHA256_HASH_LENGTH);
hashString = hash.toHex(); hashString = hash.toHex();
qCDebug(asset_client) << "Successfully uploaded asset to asset-server - SHA256 hash is " << hashString; qCDebug(asset_client) << "Successfully uploaded asset to asset-server - SHA256 hash is " << hashString;
} }

View file

@ -49,7 +49,7 @@ using ProgressCallback = std::function<void(qint64 totalReceived, qint64 total)>
class AssetClient : public QObject, public Dependency { class AssetClient : public QObject, public Dependency {
Q_OBJECT Q_OBJECT
public: public:
AssetClient(const QString& cacheDir=""); AssetClient();
Q_INVOKABLE GetMappingRequest* createGetMappingRequest(const AssetPath& path); Q_INVOKABLE GetMappingRequest* createGetMappingRequest(const AssetPath& path);
Q_INVOKABLE GetAllMappingsRequest* createGetAllMappingsRequest(); Q_INVOKABLE GetAllMappingsRequest* createGetAllMappingsRequest();

View file

@ -20,6 +20,7 @@
#include <QtNetwork/QHostInfo> #include <QtNetwork/QHostInfo>
#include <QtNetwork/QNetworkInterface> #include <QtNetwork/QNetworkInterface>
#include <shared/QtHelpers.h>
#include <ThreadHelpers.h> #include <ThreadHelpers.h>
#include <LogHandler.h> #include <LogHandler.h>
#include <UUID.h> #include <UUID.h>
@ -232,7 +233,7 @@ void NodeList::processICEPingPacket(QSharedPointer<ReceivedMessage> message) {
void NodeList::reset() { void NodeList::reset() {
if (thread() != QThread::currentThread()) { if (thread() != QThread::currentThread()) {
QMetaObject::invokeMethod(this, "reset", Qt::BlockingQueuedConnection); QMetaObject::invokeMethod(this, "reset");
return; return;
} }

View file

@ -9,22 +9,24 @@
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
// //
#include "ResourceCache.h"
#include <cfloat> #include <cfloat>
#include <cmath> #include <cmath>
#include <assert.h>
#include <QThread> #include <QThread>
#include <QTimer> #include <QTimer>
#include <SharedUtil.h> #include <SharedUtil.h>
#include <assert.h> #include <shared/QtHelpers.h>
#include <Trace.h>
#include <Profile.h>
#include "NetworkAccessManager.h" #include "NetworkAccessManager.h"
#include "NetworkLogging.h" #include "NetworkLogging.h"
#include "NodeList.h" #include "NodeList.h"
#include "ResourceCache.h"
#include <Trace.h>
#include <Profile.h>
#define clamp(x, min, max) (((x) < (min)) ? (min) :\ #define clamp(x, min, max) (((x) < (min)) ? (min) :\
(((x) > (max)) ? (max) :\ (((x) > (max)) ? (max) :\
@ -178,7 +180,7 @@ ScriptableResource* ResourceCache::prefetch(const QUrl& url, void* extra) {
if (QThread::currentThread() != thread()) { if (QThread::currentThread() != thread()) {
// Must be called in thread to ensure getResource returns a valid pointer // Must be called in thread to ensure getResource returns a valid pointer
QMetaObject::invokeMethod(this, "prefetch", Qt::BlockingQueuedConnection, BLOCKING_INVOKE_METHOD(this, "prefetch",
Q_RETURN_ARG(ScriptableResource*, result), Q_RETURN_ARG(ScriptableResource*, result),
Q_ARG(QUrl, url), Q_ARG(void*, extra)); Q_ARG(QUrl, url), Q_ARG(void*, extra));
return result; return result;
@ -301,7 +303,7 @@ QVariantList ResourceCache::getResourceList() {
QVariantList list; QVariantList list;
if (QThread::currentThread() != thread()) { if (QThread::currentThread() != thread()) {
// NOTE: invokeMethod does not allow a const QObject* // NOTE: invokeMethod does not allow a const QObject*
QMetaObject::invokeMethod(this, "getResourceList", Qt::BlockingQueuedConnection, BLOCKING_INVOKE_METHOD(this, "getResourceList",
Q_RETURN_ARG(QVariantList, list)); Q_RETURN_ARG(QVariantList, list));
} else { } else {
auto resources = _resources.uniqueKeys(); auto resources = _resources.uniqueKeys();

View file

@ -28,7 +28,7 @@
ResourceManager::ResourceManager() { ResourceManager::ResourceManager() {
_thread.setObjectName("Resource Manager Thread"); _thread.setObjectName("Resource Manager Thread");
auto assetClient = DependencyManager::set<AssetClient>(_cacheDir); auto assetClient = DependencyManager::set<AssetClient>();
assetClient->moveToThread(&_thread); assetClient->moveToThread(&_thread);
QObject::connect(&_thread, &QThread::started, assetClient.data(), &AssetClient::init); QObject::connect(&_thread, &QThread::started, assetClient.data(), &AssetClient::init);
@ -160,7 +160,3 @@ bool ResourceManager::resourceExists(const QUrl& url) {
return false; return false;
} }
void ResourceManager::setCacheDir(const QString& cacheDir) {
// TODO: check for existence?
_cacheDir = cacheDir;
}

View file

@ -59,7 +59,6 @@ private:
PrefixMap _prefixMap; PrefixMap _prefixMap;
QMutex _prefixMapLock; QMutex _prefixMapLock;
QString _cacheDir;
}; };
#endif #endif

View file

@ -17,6 +17,7 @@
#include <QtCore/QThread> #include <QtCore/QThread>
#include <shared/QtHelpers.h>
#include <LogHandler.h> #include <LogHandler.h>
#include "../NetworkLogging.h" #include "../NetworkLogging.h"
@ -276,7 +277,7 @@ Connection* Socket::findOrCreateConnection(const HifiSockAddr& sockAddr) {
void Socket::clearConnections() { void Socket::clearConnections() {
if (QThread::currentThread() != thread()) { if (QThread::currentThread() != thread()) {
QMetaObject::invokeMethod(this, "clearConnections", Qt::BlockingQueuedConnection); BLOCKING_INVOKE_METHOD(this, "clearConnections");
return; return;
} }

View file

@ -11,6 +11,8 @@
#include <QThread> #include <QThread>
#include <shared/QtHelpers.h>
#include "DisplayPlugin.h" #include "DisplayPlugin.h"
#include "InputPlugin.h" #include "InputPlugin.h"
#include "PluginManager.h" #include "PluginManager.h"
@ -21,7 +23,7 @@ InputConfiguration::InputConfiguration() {
QStringList InputConfiguration::inputPlugins() { QStringList InputConfiguration::inputPlugins() {
if (QThread::currentThread() != thread()) { if (QThread::currentThread() != thread()) {
QStringList result; QStringList result;
QMetaObject::invokeMethod(this, "inputPlugins", Qt::BlockingQueuedConnection, BLOCKING_INVOKE_METHOD(this, "inputPlugins",
Q_RETURN_ARG(QStringList, result)); Q_RETURN_ARG(QStringList, result));
return result; return result;
} }
@ -42,7 +44,7 @@ QStringList InputConfiguration::inputPlugins() {
QStringList InputConfiguration::activeInputPlugins() { QStringList InputConfiguration::activeInputPlugins() {
if (QThread::currentThread() != thread()) { if (QThread::currentThread() != thread()) {
QStringList result; QStringList result;
QMetaObject::invokeMethod(this, "activeInputPlugins", Qt::BlockingQueuedConnection, BLOCKING_INVOKE_METHOD(this, "activeInputPlugins",
Q_RETURN_ARG(QStringList, result)); Q_RETURN_ARG(QStringList, result));
return result; return result;
} }
@ -64,7 +66,7 @@ QStringList InputConfiguration::activeInputPlugins() {
QString InputConfiguration::configurationLayout(QString pluginName) { QString InputConfiguration::configurationLayout(QString pluginName) {
if (QThread::currentThread() != thread()) { if (QThread::currentThread() != thread()) {
QString result; QString result;
QMetaObject::invokeMethod(this, "configurationLayout", Qt::BlockingQueuedConnection, BLOCKING_INVOKE_METHOD(this, "configurationLayout",
Q_RETURN_ARG(QString, result), Q_RETURN_ARG(QString, result),
Q_ARG(QString, pluginName)); Q_ARG(QString, pluginName));
return result; return result;
@ -81,7 +83,7 @@ QString InputConfiguration::configurationLayout(QString pluginName) {
void InputConfiguration::setConfigurationSettings(QJsonObject configurationSettings, QString pluginName) { void InputConfiguration::setConfigurationSettings(QJsonObject configurationSettings, QString pluginName) {
if (QThread::currentThread() != thread()) { if (QThread::currentThread() != thread()) {
QMetaObject::invokeMethod(this, "setConfigurationSettings", Qt::BlockingQueuedConnection, BLOCKING_INVOKE_METHOD(this, "setConfigurationSettings",
Q_ARG(QJsonObject, configurationSettings), Q_ARG(QJsonObject, configurationSettings),
Q_ARG(QString, pluginName)); Q_ARG(QString, pluginName));
return; return;
@ -97,7 +99,7 @@ void InputConfiguration::setConfigurationSettings(QJsonObject configurationSetti
QJsonObject InputConfiguration::configurationSettings(QString pluginName) { QJsonObject InputConfiguration::configurationSettings(QString pluginName) {
if (QThread::currentThread() != thread()) { if (QThread::currentThread() != thread()) {
QJsonObject result; QJsonObject result;
QMetaObject::invokeMethod(this, "configurationSettings", Qt::BlockingQueuedConnection, BLOCKING_INVOKE_METHOD(this, "configurationSettings",
Q_RETURN_ARG(QJsonObject, result), Q_RETURN_ARG(QJsonObject, result),
Q_ARG(QString, pluginName)); Q_ARG(QString, pluginName));
return result; return result;
@ -113,7 +115,7 @@ QJsonObject InputConfiguration::configurationSettings(QString pluginName) {
void InputConfiguration::calibratePlugin(QString pluginName) { void InputConfiguration::calibratePlugin(QString pluginName) {
if (QThread::currentThread() != thread()) { if (QThread::currentThread() != thread()) {
QMetaObject::invokeMethod(this, "calibratePlugin", Qt::BlockingQueuedConnection); BLOCKING_INVOKE_METHOD(this, "calibratePlugin");
return; return;
} }
@ -128,7 +130,7 @@ void InputConfiguration::calibratePlugin(QString pluginName) {
bool InputConfiguration::uncalibratePlugin(QString pluginName) { bool InputConfiguration::uncalibratePlugin(QString pluginName) {
if (QThread::currentThread() != thread()) { if (QThread::currentThread() != thread()) {
bool result; bool result;
QMetaObject::invokeMethod(this, "uncalibratePlugin", Qt::BlockingQueuedConnection, BLOCKING_INVOKE_METHOD(this, "uncalibratePlugin",
Q_ARG(bool, result)); Q_ARG(bool, result));
return result; return result;
} }

View file

@ -8,6 +8,8 @@
#include <QThread> #include <QThread>
#include <shared/QtHelpers.h>
#include "ClipCache.h" #include "ClipCache.h"
#include "impl/PointerClip.h" #include "impl/PointerClip.h"
#include "Logging.h" #include "Logging.h"
@ -37,7 +39,7 @@ ClipCache::ClipCache(QObject* parent) :
NetworkClipLoaderPointer ClipCache::getClipLoader(const QUrl& url) { NetworkClipLoaderPointer ClipCache::getClipLoader(const QUrl& url) {
if (QThread::currentThread() != thread()) { if (QThread::currentThread() != thread()) {
NetworkClipLoaderPointer result; NetworkClipLoaderPointer result;
QMetaObject::invokeMethod(this, "getClipLoader", Qt::BlockingQueuedConnection, BLOCKING_INVOKE_METHOD(this, "getClipLoader",
Q_RETURN_ARG(NetworkClipLoaderPointer, result), Q_ARG(const QUrl&, url)); Q_RETURN_ARG(NetworkClipLoaderPointer, result), Q_ARG(const QUrl&, url));
return result; return result;
} }

View file

@ -39,7 +39,7 @@ void DeferredFrameTransform::update(RenderArgs* args) {
args->getViewFrustum().evalProjectionMatrix(frameTransformBuffer.projectionMono); args->getViewFrustum().evalProjectionMatrix(frameTransformBuffer.projectionMono);
// Running in stero ? // Running in stero ?
bool isStereo = args->_context->isStereo(); bool isStereo = args->isStereo();
if (!isStereo) { if (!isStereo) {
frameTransformBuffer.projection[0] = frameTransformBuffer.projectionMono; frameTransformBuffer.projection[0] = frameTransformBuffer.projectionMono;
frameTransformBuffer.stereoInfo = glm::vec4(0.0f, (float)args->_viewport.z, 0.0f, 0.0f); frameTransformBuffer.stereoInfo = glm::vec4(0.0f, (float)args->_viewport.z, 0.0f, 0.0f);

View file

@ -18,6 +18,7 @@
#include <glm/gtx/transform.hpp> #include <glm/gtx/transform.hpp>
#include <glm/gtx/norm.hpp> #include <glm/gtx/norm.hpp>
#include <shared/QtHelpers.h>
#include <GeometryUtil.h> #include <GeometryUtil.h>
#include <PathUtils.h> #include <PathUtils.h>
#include <PerfStat.h> #include <PerfStat.h>
@ -870,7 +871,7 @@ bool Model::getRelativeDefaultJointTranslation(int jointIndex, glm::vec3& transl
QStringList Model::getJointNames() const { QStringList Model::getJointNames() const {
if (QThread::currentThread() != thread()) { if (QThread::currentThread() != thread()) {
QStringList result; QStringList result;
QMetaObject::invokeMethod(const_cast<Model*>(this), "getJointNames", Qt::BlockingQueuedConnection, BLOCKING_INVOKE_METHOD(const_cast<Model*>(this), "getJointNames",
Q_RETURN_ARG(QStringList, result)); Q_RETURN_ARG(QStringList, result));
return result; return result;
} }

View file

@ -406,7 +406,7 @@ void Blit::run(const RenderContextPointer& renderContext, const gpu::Framebuffer
batch.setFramebuffer(blitFbo); batch.setFramebuffer(blitFbo);
if (renderArgs->_renderMode == RenderArgs::MIRROR_RENDER_MODE) { if (renderArgs->_renderMode == RenderArgs::MIRROR_RENDER_MODE) {
if (renderArgs->_context->isStereo()) { if (renderArgs->isStereo()) {
gpu::Vec4i srcRectLeft; gpu::Vec4i srcRectLeft;
srcRectLeft.z = width / 2; srcRectLeft.z = width / 2;
srcRectLeft.w = height; srcRectLeft.w = height;

View file

@ -459,7 +459,7 @@ void SurfaceGeometryPass::run(const render::RenderContextPointer& renderContext,
auto diffuseVPipeline = _diffusePass.getBlurVPipeline(); auto diffuseVPipeline = _diffusePass.getBlurVPipeline();
auto diffuseHPipeline = _diffusePass.getBlurHPipeline(); auto diffuseHPipeline = _diffusePass.getBlurHPipeline();
_diffusePass.getParameters()->setWidthHeight(curvatureViewport.z, curvatureViewport.w, args->_context->isStereo()); _diffusePass.getParameters()->setWidthHeight(curvatureViewport.z, curvatureViewport.w, args->isStereo());
glm::ivec2 textureSize(curvatureTexture->getDimensions()); glm::ivec2 textureSize(curvatureTexture->getDimensions());
_diffusePass.getParameters()->setTexcoordTransform(gpu::Framebuffer::evalSubregionTexcoordTransformCoefficients(textureSize, curvatureViewport)); _diffusePass.getParameters()->setTexcoordTransform(gpu::Framebuffer::evalSubregionTexcoordTransformCoefficients(textureSize, curvatureViewport));
_diffusePass.getParameters()->setDepthPerspective(args->getViewFrustum().getProjection()[1][1]); _diffusePass.getParameters()->setDepthPerspective(args->getViewFrustum().getProjection()[1][1]);

View file

@ -34,6 +34,8 @@ in vec2 _texCoord0;
out vec4 _fragColor; out vec4 _fragColor;
void main(void) { void main(void) {
_fragColor = vec4(0.0);
// Grab the fragment data from the uv // Grab the fragment data from the uv
vec2 texCoord = _texCoord0.st; vec2 texCoord = _texCoord0.st;

View file

@ -99,6 +99,8 @@ namespace render {
void pushViewFrustum(const ViewFrustum& viewFrustum) { _viewFrustums.push(viewFrustum); } void pushViewFrustum(const ViewFrustum& viewFrustum) { _viewFrustums.push(viewFrustum); }
void popViewFrustum() { _viewFrustums.pop(); } void popViewFrustum() { _viewFrustums.pop(); }
bool isStereo() const { return _displayMode != MONO; }
std::shared_ptr<gpu::Context> _context; std::shared_ptr<gpu::Context> _context;
std::shared_ptr<gpu::Framebuffer> _blitFramebuffer; std::shared_ptr<gpu::Framebuffer> _blitFramebuffer;
std::shared_ptr<render::ShapePipeline> _pipeline; std::shared_ptr<render::ShapePipeline> _pipeline;

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