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

This commit is contained in:
ZappoMan 2017-07-06 09:39:33 -07:00
commit 10341af819
13 changed files with 491 additions and 218 deletions

View file

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

View file

@ -458,7 +458,7 @@ Rectangle {
width: glyphButton.width + calibrationText.width + padding
height: hifi.dimensions.controlLineHeight
anchors.top: bottomSeperator.bottom
anchors.topMargin: 10
anchors.topMargin: 15
anchors.left: parent.left
anchors.leftMargin: leftMargin
@ -590,16 +590,24 @@ Rectangle {
lastConfiguration = composeConfigurationSettings();
}
Component.onDestruction: {
var settings = InputConfiguration.configurationSettings(pluginName);
var data = {
"num_pucks": settings["puckCount"]
}
UserActivityLogger.logAction("mocap_ui_close_dialog", data);
}
HifiControls.SpinBox {
id: timeToCalibrate
width: 70
anchors.top: calibrationButton.bottom
anchors.topMargin: 40
anchors.topMargin: 20
anchors.left: parent.left
anchors.leftMargin: leftMargin
minimumValue: 3
value: 3
minimumValue: 5
value: 5
colorScheme: hifi.colorSchemes.dark
onEditingFinished: {
@ -641,17 +649,39 @@ Rectangle {
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) {
var calibrationScreen = stack.currentItem;
if (!status["UI"]) {
calibratingScreen = screen.createObject();
stack.push(calibratingScreen);
}
if (status["calibrated"]) {
calibrationScreen.success();
if (status["UI"]) {
logAction("mocap_ui_success", status);
}
} else if (!status["calibrated"]) {
var uncalibrated = status["success"];
if (!uncalibrated) {
calibrationScreen.failure();
calibrationScreen.failure();
if (status["UI"]) {
logAction("mocap_ui_failed", status);
}
}
updateCalibrationButton();
}
@ -717,6 +747,12 @@ Rectangle {
initializeButtonState();
updateCalibrationText();
var data = {
"num_pucks": settings["puckCount"]
};
UserActivityLogger.logAction("mocap_ui_open_dialog", data);
}
function displayTrackerConfiguration(type) {

View file

@ -25,6 +25,7 @@
#include <QtCore/QCommandLineParser>
#include <QtCore/QMimeData>
#include <QtCore/QThreadPool>
#include <QtConcurrent/QtConcurrentRun>
#include <QtGui/QScreen>
#include <QtGui/QWindow>
@ -2164,48 +2165,74 @@ void Application::paintGL() {
return;
}
auto displayPlugin = getActiveDisplayPlugin();
// FIXME not needed anymore?
_offscreenContext->makeCurrent();
DisplayPluginPointer displayPlugin;
{
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
if (!displayPlugin->beginFrameRender(_frameCount)) {
_inPaint = false;
updateDisplayMode();
return;
{
PROFILE_RANGE(render, "/offscreenMakeCurrent");
// FIXME not needed anymore?
_offscreenContext->makeCurrent();
}
{
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
getMyAvatar()->updateFromHMDSensorMatrix(getHMDSensorPose());
{
PROFILE_RANGE(render, "/updateAvatar");
getMyAvatar()->updateFromHMDSensorMatrix(getHMDSensorPose());
}
auto lodManager = DependencyManager::get<LODManager>();
RenderArgs renderArgs;
{
QMutexLocker viewLocker(&_viewMutex);
_viewFrustum.calculate();
}
RenderArgs renderArgs(_gpuContext, getEntities(), lodManager->getOctreeSizeScale(),
lodManager->getBoundaryLevelAdjust(), RenderArgs::DEFAULT_RENDER_MODE,
RenderArgs::MONO, RenderArgs::RENDER_DEBUG_NONE);
{
QMutexLocker viewLocker(&_viewMutex);
renderArgs.setViewFrustum(_viewFrustum);
PROFILE_RANGE(render, "/buildFrustrumAndArgs");
{
QMutexLocker viewLocker(&_viewMutex);
_viewFrustum.calculate();
}
renderArgs = RenderArgs(_gpuContext, getEntities(), lodManager->getOctreeSizeScale(),
lodManager->getBoundaryLevelAdjust(), RenderArgs::DEFAULT_RENDER_MODE,
RenderArgs::MONO, RenderArgs::RENDER_DEBUG_NONE);
{
QMutexLocker viewLocker(&_viewMutex);
renderArgs.setViewFrustum(_viewFrustum);
}
}
PerformanceWarning::setSuppressShortTimings(Menu::getInstance()->isOptionChecked(MenuOption::SuppressShortTimings));
bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings);
PerformanceWarning warn(showWarnings, "Application::paintGL()");
resizeGL();
_gpuContext->beginFrame(getHMDSensorPose());
// Reset the gpu::Context Stages
// Back to the default framebuffer;
gpu::doInBatch(_gpuContext, [&](gpu::Batch& batch) {
batch.resetStages();
});
{
PROFILE_RANGE(render, "/resizeGL");
PerformanceWarning::setSuppressShortTimings(Menu::getInstance()->isOptionChecked(MenuOption::SuppressShortTimings));
bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings);
PerformanceWarning warn(showWarnings, "Application::paintGL()");
resizeGL();
}
{
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");
// NOTE: There is no batch associated with this renderArgs
// the ApplicationOverlay class assumes it's viewport is setup to be the device size
@ -2216,114 +2243,127 @@ void Application::paintGL() {
glm::vec3 boomOffset;
{
PerformanceTimer perfTimer("CameraUpdates");
PROFILE_RANGE(render, "/updateCamera");
{
PerformanceTimer perfTimer("CameraUpdates");
auto myAvatar = getMyAvatar();
boomOffset = myAvatar->getScale() * myAvatar->getBoomLength() * -IDENTITY_FORWARD;
auto myAvatar = getMyAvatar();
boomOffset = myAvatar->getScale() * myAvatar->getBoomLength() * -IDENTITY_FORWARD;
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::ThirdPerson, !(myAvatar->getBoomLength() <= MyAvatar::ZOOM_MIN));
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());
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::ThirdPerson, !(myAvatar->getBoomLength() <= MyAvatar::ZOOM_MIN));
cameraMenuChanged();
}
} 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);
// The render mode is default or mirror if the camera is in mirror mode, assigned further below
renderArgs._renderMode = RenderArgs::DEFAULT_RENDER_MODE;
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) {
// 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()) {
glm::quat hmdRotation = extractRotation(myAvatar->getHMDSensorMatrix());
_myCamera.setOrientation(cameraEntity->getRotation() * hmdRotation);
glm::vec3 hmdOffset = extractTranslation(myAvatar->getHMDSensorMatrix());
_myCamera.setPosition(cameraEntity->getPosition() + (hmdRotation * hmdOffset));
mat4 camMat = myAvatar->getSensorToWorldMatrix() * myAvatar->getHMDSensorMatrix();
_myCamera.setPosition(extractTranslation(camMat));
_myCamera.setOrientation(glm::quat_cast(camMat));
} else {
_myCamera.setOrientation(cameraEntity->getRotation());
_myCamera.setPosition(cameraEntity->getPosition());
_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());
// 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
if (!isHMDMode()) {
_myCamera.update(1.0f / _frameCounter.rate());
// Update camera position
if (!isHMDMode()) {
_myCamera.update(1.0f / _frameCounter.rate());
}
}
}
getApplicationCompositor().setFrameInfo(_frameCount, _myCamera.getTransform());
{
PROFILE_RANGE(render, "/updateCompositor");
getApplicationCompositor().setFrameInfo(_frameCount, _myCamera.getTransform());
}
// Primary rendering pass
auto framebufferCache = DependencyManager::get<FramebufferCache>();
const QSize size = framebufferCache->getFrameBufferSize();
// Final framebuffer that will be handled to the display-plugin
auto finalFramebuffer = framebufferCache->getFramebuffer();
gpu::FramebufferPointer finalFramebuffer;
QSize finalFramebufferSize;
{
PROFILE_RANGE(render, "/getOutputFramebuffer");
// 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");
PerformanceTimer perfTimer("mainRender");
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
renderArgs._viewport = ivec4(0, 0, size.width(), size.height());
renderArgs._viewport = ivec4(0, 0, finalFramebufferSize.width(), finalFramebufferSize.height());
if (displayPlugin->isStereo()) {
// Stereo modes will typically have a larger projection matrix overall,
// so we ask for the 'mono' projection matrix, which for stereo and HMD
@ -3623,6 +3663,133 @@ bool Application::shouldPaint(float nsecsElapsed) {
#include <TCHAR.h>
#include <pdh.h>
#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 int numProcessors;
@ -3675,6 +3842,26 @@ void getCpuUsage(vec3& systemAndUser) {
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
@ -3695,15 +3882,17 @@ void Application::idle(float nsecsElapsed) {
}
#ifdef Q_OS_WIN
// If tracing is enabled then monitor the CPU in a separate thread
static std::once_flag once;
std::call_once(once, [] {
initCpuUsage();
std::call_once(once, [&] {
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

View file

@ -40,19 +40,23 @@
Q_LOGGING_CATEGORY(trace_render_overlays, "trace.render.overlays")
void Overlays::cleanupAllOverlays() {
QMap<OverlayID, Overlay::Pointer> overlaysHUD;
QMap<OverlayID, Overlay::Pointer> overlaysWorld;
{
foreach(Overlay::Pointer overlay, _overlaysHUD) {
_overlaysToDelete.push_back(overlay);
}
foreach(Overlay::Pointer overlay, _overlaysWorld) {
_overlaysToDelete.push_back(overlay);
}
_overlaysHUD.clear();
_overlaysWorld.clear();
#if OVERLAY_PANELS
_panels.clear();
#endif
QMutexLocker locker(&_mutex);
overlaysHUD.swap(_overlaysHUD);
overlaysWorld.swap(_overlaysWorld);
}
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();
}
@ -63,12 +67,12 @@ void Overlays::init() {
}
void Overlays::update(float deltatime) {
{
foreach(Overlay::Pointer thisOverlay, _overlaysHUD) {
QMutexLocker locker(&_mutex);
foreach(const auto& thisOverlay, _overlaysHUD) {
thisOverlay->update(deltatime);
}
foreach(Overlay::Pointer thisOverlay, _overlaysWorld) {
foreach(const auto& thisOverlay, _overlaysWorld) {
thisOverlay->update(deltatime);
}
}
@ -110,7 +114,7 @@ void Overlays::renderHUD(RenderArgs* renderArgs) {
int height = size.y;
mat4 legacyProjection = glm::ortho<float>(0, width, height, 0, -1000, 1000);
QMutexLocker locker(&_mutex);
foreach(Overlay::Pointer thisOverlay, _overlaysHUD) {
// Reset all batch pipeline settings between overlay
@ -132,7 +136,10 @@ void Overlays::enable() {
_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 {
QMutexLocker locker(&_mutex);
if (_overlaysHUD.contains(id)) {
return _overlaysHUD[id];
}
@ -193,13 +200,17 @@ OverlayID Overlays::addOverlay(const Overlay::Pointer& overlay) {
overlay->setOverlayID(thisID);
overlay->setStackOrder(_stackOrder++);
if (overlay->is3D()) {
_overlaysWorld[thisID] = overlay;
{
QMutexLocker locker(&_mutex);
_overlaysWorld[thisID] = overlay;
}
render::ScenePointer scene = qApp->getMain3DScene();
render::Transaction transaction;
overlay->addToScene(overlay, scene, transaction);
scene->enqueueTransaction(transaction);
} else {
QMutexLocker locker(&_mutex);
_overlaysHUD[thisID] = overlay;
}
@ -231,9 +242,12 @@ OverlayID Overlays::cloneOverlay(OverlayID id) {
bool Overlays::editOverlay(OverlayID id, const QVariant& properties) {
if (QThread::currentThread() != thread()) {
bool result;
BLOCKING_INVOKE_METHOD(this, "editOverlay", Q_RETURN_ARG(bool, result), Q_ARG(OverlayID, id), Q_ARG(QVariant, properties));
return result;
// 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);
@ -246,9 +260,9 @@ bool Overlays::editOverlay(OverlayID id, const QVariant& properties) {
bool Overlays::editOverlays(const QVariant& propertiesById) {
if (QThread::currentThread() != thread()) {
bool result;
BLOCKING_INVOKE_METHOD(this, "editOverlays", Q_RETURN_ARG(bool, result), Q_ARG(QVariant, propertiesById));
return result;
// 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();
@ -275,6 +289,7 @@ void Overlays::deleteOverlay(OverlayID id) {
Overlay::Pointer overlayToDelete;
{
QMutexLocker locker(&_mutex);
if (_overlaysHUD.contains(id)) {
overlayToDelete = _overlaysHUD.take(id);
} else if (_overlaysWorld.contains(id)) {
@ -374,30 +389,22 @@ OverlayID Overlays::getOverlayAtPoint(const glm::vec2& point) {
return result;
}
glm::vec2 pointCopy = point;
if (!_enabled) {
return UNKNOWN_OVERLAY_ID;
}
QMapIterator<OverlayID, Overlay::Pointer> i(_overlaysHUD);
const float LARGE_NEGATIVE_FLOAT = -9999999;
glm::vec3 origin(pointCopy.x, pointCopy.y, LARGE_NEGATIVE_FLOAT);
glm::vec3 direction(0, 0, 1);
glm::vec3 thisSurfaceNormal;
QMutexLocker locker(&_mutex);
QMapIterator<OverlayID, Overlay::Pointer> i(_overlaysHUD);
unsigned int bestStackOrder = 0;
OverlayID bestOverlayID = UNKNOWN_OVERLAY_ID;
while (i.hasNext()) {
i.next();
OverlayID thisID = i.key();
if (!i.value()->is3D()) {
auto thisOverlay = std::dynamic_pointer_cast<Overlay2D>(i.value());
if (thisOverlay && thisOverlay->getVisible() && thisOverlay->isLoaded() &&
thisOverlay->getBoundingRect().contains(pointCopy.x, pointCopy.y, false)) {
if (thisOverlay->getStackOrder() > bestStackOrder) {
bestOverlayID = thisID;
bestStackOrder = thisOverlay->getStackOrder();
}
auto thisOverlay = std::dynamic_pointer_cast<Overlay2D>(i.value());
if (thisOverlay && thisOverlay->getVisible() && thisOverlay->isLoaded() &&
thisOverlay->getBoundingRect().contains(point.x, point.y, false)) {
if (thisOverlay->getStackOrder() > bestStackOrder) {
bestOverlayID = i.key();
bestStackOrder = thisOverlay->getStackOrder();
}
}
}
@ -466,6 +473,7 @@ RayToOverlayIntersectionResult Overlays::findRayIntersectionInternal(const PickR
float bestDistance = std::numeric_limits<float>::max();
bool bestIsFront = false;
QMutexLocker locker(&_mutex);
RayToOverlayIntersectionResult result;
QMapIterator<OverlayID, Overlay::Pointer> i(_overlaysWorld);
while (i.hasNext()) {
@ -598,13 +606,20 @@ QSizeF Overlays::textSize(OverlayID id, const QString& text) {
return result;
}
Overlay::Pointer thisOverlay = _overlaysHUD[id];
Overlay::Pointer thisOverlay;
{
QMutexLocker locker(&_mutex);
thisOverlay = _overlaysHUD[id];
}
if (thisOverlay) {
if (auto textOverlay = std::dynamic_pointer_cast<TextOverlay>(thisOverlay)) {
return textOverlay->textSize(text);
}
} else {
thisOverlay = _overlaysWorld[id];
{
QMutexLocker locker(&_mutex);
thisOverlay = _overlaysWorld[id];
}
if (auto text3dOverlay = std::dynamic_pointer_cast<Text3DOverlay>(thisOverlay)) {
return text3dOverlay->textSize(text);
}
@ -675,6 +690,7 @@ bool Overlays::isAddedOverlay(OverlayID id) {
return result;
}
QMutexLocker locker(&_mutex);
return _overlaysHUD.contains(id) || _overlaysWorld.contains(id);
}
@ -949,7 +965,7 @@ QVector<QUuid> Overlays::findOverlays(const glm::vec3& center, float radius) {
return result;
}
QMutexLocker locker(&_mutex);
QMapIterator<OverlayID, Overlay::Pointer> i(_overlaysWorld);
int checked = 0;
while (i.hasNext()) {

View file

@ -319,6 +319,7 @@ signals:
private:
void cleanupOverlaysToDelete();
mutable QMutex _mutex;
QMap<OverlayID, Overlay::Pointer> _overlaysHUD;
QMap<OverlayID, Overlay::Pointer> _overlaysWorld;
#if OVERLAY_PANELS

View file

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

View file

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

View file

@ -1821,7 +1821,7 @@ void ScriptEngine::include(const QStringList& includeFiles, QScriptValue callbac
clearExceptions();
}
} else {
scriptWarningMessage("Script.include() skipping evaluation of previously included url:" + url.toString());
scriptPrintedMessage("Script.include() skipping evaluation of previously included url:" + url.toString());
}
}
}

View file

@ -17,10 +17,6 @@ void moveToNewNamedThread(QObject* object, const QString& name, std::function<vo
QThread* thread = new QThread();
thread->setObjectName(name);
if (priority != QThread::InheritPriority) {
thread->setPriority(priority);
}
QString tempName = name;
QObject::connect(thread, &QThread::started, [startCallback] {
startCallback();
@ -32,6 +28,9 @@ void moveToNewNamedThread(QObject* object, const QString& name, std::function<vo
// put the object on the thread
object->moveToThread(thread);
thread->start();
if (priority != QThread::InheritPriority) {
thread->setPriority(priority);
}
}
void moveToNewNamedThread(QObject* object, const QString& name, QThread::Priority priority) {

View file

@ -249,6 +249,7 @@ ViveControllerManager::InputDevice::InputDevice(vr::IVRSystem*& system) : contro
_configStringMap[Config::FeetAndHips] = QString("FeetAndHips");
_configStringMap[Config::FeetHipsAndChest] = QString("FeetHipsAndChest");
_configStringMap[Config::FeetHipsAndShoulders] = QString("FeetHipsAndShoulders");
_configStringMap[Config::FeetHipsChestAndShoulders] = QString("FeetHipsChestAndShoulders");
}
void ViveControllerManager::InputDevice::update(float deltaTime, const controller::InputCalibrationData& inputCalibrationData) {
@ -325,6 +326,7 @@ void ViveControllerManager::InputDevice::calibrateFromUI(const controller::Input
if (_calibrate) {
uncalibrate();
calibrate(inputCalibrationData);
emitCalibrationStatus();
_calibrate = false;
}
}
@ -372,29 +374,23 @@ QJsonObject ViveControllerManager::InputDevice::configurationSettings() {
Locker locker(_lock);
QJsonObject configurationSettings;
configurationSettings["trackerConfiguration"] = configToString(_preferedConfig);
configurationSettings["HMDHead"] = (_headConfig == HeadConfig::HMD) ? true : false;
configurationSettings["handController"] = (_handConfig == HandConfig::HandController) ? true : false;
configurationSettings["HMDHead"] = (_headConfig == HeadConfig::HMD);
configurationSettings["handController"] = (_handConfig == HandConfig::HandController);
configurationSettings["puckCount"] = (int)_validTrackedObjects.size();
return configurationSettings;
}
void ViveControllerManager::InputDevice::emitCalibrationStatus(const bool success) {
void ViveControllerManager::InputDevice::emitCalibrationStatus() {
auto inputConfiguration = DependencyManager::get<InputConfiguration>();
QJsonObject status = QJsonObject();
if (_calibrated && success) {
status["calibrated"] = _calibrated;
status["configuration"] = configToString(_preferedConfig);
} else if (!_calibrated && !success) {
status["calibrated"] = _calibrated;
status["success"] = success;
} else if (!_calibrated && success) {
status["calibrated"] = _calibrated;
status["success"] = success;
status["configuration"] = configToString(_preferedConfig);
status["puckCount"] = (int)_validTrackedObjects.size();
}
status["calibrated"] = _calibrated;
status["configuration"] = configToString(_preferedConfig);
status["head_puck"] = (_headConfig == HeadConfig::Puck);
status["hand_pucks"] = (_handConfig == HandConfig::Pucks);
status["puckCount"] = (int)_validTrackedObjects.size();
status["UI"] = _calibrate;
emit inputConfiguration->calibrationStatus(status); //inputConfiguration->calibrated(status);
emit inputConfiguration->calibrationStatus(status);
}
void ViveControllerManager::InputDevice::handleTrackedObject(uint32_t deviceIndex, const controller::InputCalibrationData& inputCalibrationData) {
@ -437,12 +433,29 @@ void ViveControllerManager::InputDevice::handleTrackedObject(uint32_t deviceInde
}
}
void ViveControllerManager::InputDevice::sendUserActivityData(QString activity) {
QJsonObject jsonData = {
{"num_pucks", (int)_validTrackedObjects.size()},
{"configuration", configToString(_preferedConfig)},
{"head_puck", (_headConfig == HeadConfig::Puck) ? true : false},
{"hand_pucks", (_handConfig == HandConfig::Pucks) ? true : false}
};
UserActivityLogger::getInstance().logAction(activity, jsonData);
}
void ViveControllerManager::InputDevice::calibrateOrUncalibrate(const controller::InputCalibrationData& inputCalibration) {
if (!_calibrated) {
calibrate(inputCalibration);
if (_calibrated) {
sendUserActivityData("mocap_button_success");
} else {
sendUserActivityData("mocap_button_fail");
}
emitCalibrationStatus();
} else {
uncalibrate();
emitCalibrationStatus(true);
sendUserActivityData("mocap_button_uncalibrate");
}
}
@ -454,7 +467,6 @@ void ViveControllerManager::InputDevice::calibrate(const controller::InputCalibr
if (puckCount == 0) {
uncalibrate();
emitCalibrationStatus(false);
return;
}
@ -473,10 +485,8 @@ void ViveControllerManager::InputDevice::calibrate(const controller::InputCalibr
if (!headConfigured || !handsConfigured || !bodyConfigured) {
uncalibrate();
emitCalibrationStatus(false);
} else {
_calibrated = true;
emitCalibrationStatus(true);
qDebug() << "PuckCalibration: " << configToString(_config) << " Configuration Successful";
}
}
@ -566,8 +576,6 @@ bool ViveControllerManager::InputDevice::configureBody(glm::mat4& defaultToRefer
return true;
}
qDebug() << "Puck Calibration: " << configToString(_config) << " Config Failed: Could not meet the minimal # of pucks";
uncalibrate();
emitCalibrationStatus(false);
return false;
}

View file

@ -73,6 +73,7 @@ private:
void calibrateOrUncalibrate(const controller::InputCalibrationData& inputCalibration);
void calibrate(const controller::InputCalibrationData& inputCalibration);
void uncalibrate();
void sendUserActivityData(QString activity);
void configureCalibrationSettings(const QJsonObject configurationSettings);
QJsonObject configurationSettings();
controller::Pose addOffsetToPuckPose(int joint) const;
@ -106,7 +107,7 @@ private:
void calibrateHead(glm::mat4& defaultToReferenceMat, const controller::InputCalibrationData& inputCalibration);
void calibrateFromHandController(const controller::InputCalibrationData& inputCalibrationData);
void calibrateFromUI(const controller::InputCalibrationData& inputCalibrationData);
void emitCalibrationStatus(const bool success);
void emitCalibrationStatus();
void calibrateNextFrame();
@ -139,7 +140,7 @@ private:
FeetAndHips,
FeetHipsAndChest,
FeetHipsAndShoulders,
FeetHipsChestAndShoulders,
FeetHipsChestAndShoulders
};
enum class HeadConfig {

View file

@ -20,7 +20,9 @@ var blastShareText = "Blast to my Connections",
hifiShareText = "Share to Snaps Feed",
hifiAlreadySharedText = "Already Shared to Snaps Feed",
facebookShareText = "Share to Facebook",
twitterShareText = "Share to Twitter";
twitterShareText = "Share to Twitter",
shareButtonLabelTextActive = "SHARE&#58;",
shareButtonLabelTextInactive = "SHARE";
function fileExtensionMatches(filePath, extension) {
return filePath.split('.').pop().toLowerCase() === extension;
@ -138,6 +140,8 @@ function selectImageToShare(selectedID, isSelected) {
var imageContainer = document.getElementById(selectedID),
image = document.getElementById(selectedID + 'img'),
shareBar = document.getElementById(selectedID + "shareBar"),
showShareButtonsDots = document.getElementById(selectedID + "showShareButtonsDots"),
showShareButtonsLabel = document.getElementById(selectedID + "showShareButtonsLabel"),
shareButtonsDiv = document.getElementById(selectedID + "shareButtonsDiv"),
shareBarHelp = document.getElementById(selectedID + "shareBarHelp"),
showShareButtonsButtonDiv = document.getElementById(selectedID + "showShareButtonsButtonDiv"),
@ -156,6 +160,9 @@ function selectImageToShare(selectedID, isSelected) {
shareBar.style.backgroundColor = "rgba(0, 0, 0, 0.45)";
shareBar.style.pointerEvents = "initial";
showShareButtonsDots.style.visibility = "hidden";
showShareButtonsLabel.innerHTML = shareButtonLabelTextActive;
shareButtonsDiv.style.visibility = "visible";
shareBarHelp.style.visibility = "visible";
@ -176,6 +183,9 @@ function selectImageToShare(selectedID, isSelected) {
shareBar.style.backgroundColor = "rgba(0, 0, 0, 0.0)";
shareBar.style.pointerEvents = "none";
showShareButtonsDots.style.visibility = "visible";
showShareButtonsLabel.innerHTML = shareButtonLabelTextInactive;
shareButtonsDiv.style.visibility = "hidden";
shareBarHelp.style.visibility = "hidden";
}
@ -185,6 +195,7 @@ function createShareBar(parentID, isLoggedIn, canShare, isGif, blastButtonDisabl
shareBarHelpID = parentID + "shareBarHelp",
shareButtonsDivID = parentID + "shareButtonsDiv",
showShareButtonsButtonDivID = parentID + "showShareButtonsButtonDiv",
showShareButtonsDotsID = parentID + "showShareButtonsDots",
showShareButtonsLabelID = parentID + "showShareButtonsLabel",
blastToConnectionsButtonID = parentID + "blastToConnectionsButton",
shareWithEveryoneButtonID = parentID + "shareWithEveryoneButton",
@ -199,8 +210,8 @@ function createShareBar(parentID, isLoggedIn, canShare, isGif, blastButtonDisabl
if (canShare) {
shareBarInnerHTML = '<div class="shareControlsHelp" id="' + shareBarHelpID + '" style="visibility:hidden;' + ((canBlast && blastButtonDisabled || !canBlast && hifiButtonDisabled) ? "background-color:#000;opacity:0.5;" : "") + '"></div>' +
'<div class="showShareButtonsButtonDiv inactive" id="' + showShareButtonsButtonDivID + '" onclick="selectImageToShare(' + parentID + ', true)">' +
'<label id="' + showShareButtonsLabelID + '">SHARE</label>' +
'<span class="showShareButtonDots">' +
'<label id="' + showShareButtonsLabelID + '">' + shareButtonLabelTextInactive + '</label>' +
'<span id="' + showShareButtonsDotsID + '" class="showShareButtonDots">' +
'&#xe019;' +
'</div>' +
'</div>' +
@ -217,7 +228,7 @@ function createShareBar(parentID, isLoggedIn, canShare, isGif, blastButtonDisabl
document.getElementById(parentID + 'img').onclick = function () { selectImageToShare(parentID, true); };
} else {
shareBarInnerHTML = '<div class="showShareButtonsButtonDiv inactive" id="' + showShareButtonsButtonDivID + '" onclick="selectImageToShare(' + parentID + ', true)">' +
'<label id="' + showShareButtonsLabelID + '">SHARE</label>' +
'<label id="' + showShareButtonsLabelID + '">' + shareButtonLabelTextInactive + '</label>' +
'<span class="showShareButtonDots">' +
'&#xe019;' +
'</div>' +
@ -230,7 +241,7 @@ function createShareBar(parentID, isLoggedIn, canShare, isGif, blastButtonDisabl
}
} else {
shareBarInnerHTML = '<div class="showShareButtonsButtonDiv inactive" id="' + showShareButtonsButtonDivID + '" onclick="selectImageToShare(' + parentID + ', true)">' +
'<label id="' + showShareButtonsLabelID + '">SHARE</label>' +
'<label id="' + showShareButtonsLabelID + '">' + shareButtonLabelTextInactive + '</label>' +
'<span class="showShareButtonDots">' +
'&#xe019;' +
'</div>' +

View file

@ -90,14 +90,16 @@ ACClientApp::ACClientApp(int argc, char* argv[]) :
auto nodeList = DependencyManager::get<NodeList>();
// start the nodeThread so its event loop is running
nodeList->startThread();
// setup a timer for domain-server check ins
QTimer* domainCheckInTimer = new QTimer(nodeList.data());
connect(domainCheckInTimer, &QTimer::timeout, nodeList.data(), &NodeList::sendDomainServerCheckIn);
domainCheckInTimer->start(DOMAIN_SERVER_CHECK_IN_MSECS);
// start the nodeThread so its event loop is running
// (must happen after the checkin timer is created with the nodelist as it's parent)
nodeList->startThread();
const DomainHandler& domainHandler = nodeList->getDomainHandler();
connect(&domainHandler, SIGNAL(hostnameChanged(const QString&)), SLOT(domainChanged(const QString&)));