mirror of
https://github.com/overte-org/overte.git
synced 2025-08-06 19:59:28 +02:00
Merge branch 'master' into infoview
This commit is contained in:
commit
fb2ea3185e
20 changed files with 300 additions and 130 deletions
40
cmake/macros/AddResourcesToOSXBundle.cmake
Normal file
40
cmake/macros/AddResourcesToOSXBundle.cmake
Normal file
|
@ -0,0 +1,40 @@
|
||||||
|
#
|
||||||
|
# AddResourcesToOSXBundle.cmake
|
||||||
|
# cmake/macros
|
||||||
|
#
|
||||||
|
# Created by Stephen Birarda on 04/27/15.
|
||||||
|
# Copyright 2015 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(_RECURSIVELY_SET_PACKAGE_LOCATION _PATH)
|
||||||
|
# enumerate the items
|
||||||
|
foreach(_ITEM ${ARGN})
|
||||||
|
|
||||||
|
if (IS_DIRECTORY "${_ITEM}")
|
||||||
|
# recurse into the directory and check for more resources
|
||||||
|
file(GLOB _DIR_CONTENTS "${_ITEM}/*")
|
||||||
|
|
||||||
|
# figure out the path for this directory and then call ourselves to recurse into it
|
||||||
|
get_filename_component(_ITEM_PATH ${_ITEM} NAME)
|
||||||
|
_recursively_set_package_location("${_PATH}/${_ITEM_PATH}" ${_DIR_CONTENTS})
|
||||||
|
else ()
|
||||||
|
# add any files in the root to the resources folder directly
|
||||||
|
SET_SOURCE_FILES_PROPERTIES(${_ITEM} PROPERTIES MACOSX_PACKAGE_LOCATION "Resources${_PATH}")
|
||||||
|
list(APPEND DISCOVERED_RESOURCES ${_ITEM})
|
||||||
|
endif ()
|
||||||
|
|
||||||
|
endforeach()
|
||||||
|
endmacro(_RECURSIVELY_SET_PACKAGE_LOCATION _PATH)
|
||||||
|
|
||||||
|
macro(ADD_RESOURCES_TO_OS_X_BUNDLE _RSRC_FOLDER)
|
||||||
|
|
||||||
|
# GLOB the resource directory
|
||||||
|
file(GLOB _ROOT_ITEMS "${_RSRC_FOLDER}/*")
|
||||||
|
|
||||||
|
# recursively enumerate from the root items
|
||||||
|
_recursively_set_package_location("" ${_ROOT_ITEMS})
|
||||||
|
|
||||||
|
endmacro(ADD_RESOURCES_TO_OS_X_BUNDLE _RSRC_FOLDER)
|
|
@ -504,7 +504,7 @@ void DomainServer::populateStaticScriptedAssignmentsFromSettings() {
|
||||||
Assignment::AgentType,
|
Assignment::AgentType,
|
||||||
scriptPool);
|
scriptPool);
|
||||||
scriptAssignment->setPayload(scriptURL.toUtf8());
|
scriptAssignment->setPayload(scriptURL.toUtf8());
|
||||||
|
|
||||||
// add it to static hash so we know we have to keep giving it back out
|
// add it to static hash so we know we have to keep giving it back out
|
||||||
addStaticAssignmentToAssignmentHash(scriptAssignment);
|
addStaticAssignmentToAssignmentHash(scriptAssignment);
|
||||||
}
|
}
|
||||||
|
@ -675,6 +675,10 @@ void DomainServer::handleConnectRequest(const QByteArray& packet, const HifiSock
|
||||||
nodeData->setAssignmentUUID(matchingQueuedAssignment->getUUID());
|
nodeData->setAssignmentUUID(matchingQueuedAssignment->getUUID());
|
||||||
nodeData->setWalletUUID(pendingAssigneeData->getWalletUUID());
|
nodeData->setWalletUUID(pendingAssigneeData->getWalletUUID());
|
||||||
|
|
||||||
|
// always allow assignment clients to create and destroy entities
|
||||||
|
newNode->setCanAdjustLocks(true);
|
||||||
|
newNode->setCanRez(true);
|
||||||
|
|
||||||
// now that we've pulled the wallet UUID and added the node to our list, delete the pending assignee data
|
// now that we've pulled the wallet UUID and added the node to our list, delete the pending assignee data
|
||||||
delete pendingAssigneeData;
|
delete pendingAssigneeData;
|
||||||
}
|
}
|
||||||
|
@ -2119,10 +2123,10 @@ SharedAssignmentPointer DomainServer::deployableAssignmentForRequest(const Assig
|
||||||
Assignment* assignment = sharedAssignment->data();
|
Assignment* assignment = sharedAssignment->data();
|
||||||
bool requestIsAllTypes = requestAssignment.getType() == Assignment::AllTypes;
|
bool requestIsAllTypes = requestAssignment.getType() == Assignment::AllTypes;
|
||||||
bool assignmentTypesMatch = assignment->getType() == requestAssignment.getType();
|
bool assignmentTypesMatch = assignment->getType() == requestAssignment.getType();
|
||||||
bool nietherHasPool = assignment->getPool().isEmpty() && requestAssignment.getPool().isEmpty();
|
bool neitherHasPool = assignment->getPool().isEmpty() && requestAssignment.getPool().isEmpty();
|
||||||
bool assignmentPoolsMatch = assignment->getPool() == requestAssignment.getPool();
|
bool assignmentPoolsMatch = assignment->getPool() == requestAssignment.getPool();
|
||||||
|
|
||||||
if ((requestIsAllTypes || assignmentTypesMatch) && (nietherHasPool || assignmentPoolsMatch)) {
|
if ((requestIsAllTypes || assignmentTypesMatch) && (neitherHasPool || assignmentPoolsMatch)) {
|
||||||
|
|
||||||
// remove the assignment from the queue
|
// remove the assignment from the queue
|
||||||
SharedAssignmentPointer deployableAssignment = _unfulfilledAssignments.takeAt(sharedAssignment
|
SharedAssignmentPointer deployableAssignment = _unfulfilledAssignments.takeAt(sharedAssignment
|
||||||
|
|
|
@ -88,18 +88,15 @@ if (APPLE)
|
||||||
# set where in the bundle to put the resources file
|
# set where in the bundle to put the resources file
|
||||||
SET_SOURCE_FILES_PROPERTIES(${CMAKE_CURRENT_SOURCE_DIR}/icon/${ICON_FILENAME} PROPERTIES MACOSX_PACKAGE_LOCATION Resources)
|
SET_SOURCE_FILES_PROPERTIES(${CMAKE_CURRENT_SOURCE_DIR}/icon/${ICON_FILENAME} PROPERTIES MACOSX_PACKAGE_LOCATION Resources)
|
||||||
|
|
||||||
# grab the directories in resources and put them in the right spot in Resources
|
set(DISCOVERED_RESOURCES "")
|
||||||
file(GLOB RESOURCE_SUBDIRS RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}/resources" "${CMAKE_CURRENT_SOURCE_DIR}/resources/*")
|
|
||||||
foreach(DIR ${RESOURCE_SUBDIRS})
|
|
||||||
if(IS_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/resources/${DIR}")
|
|
||||||
FILE(GLOB DIR_CONTENTS "resources/${DIR}/*")
|
|
||||||
SET_SOURCE_FILES_PROPERTIES(${DIR_CONTENTS} PROPERTIES MACOSX_PACKAGE_LOCATION "Resources/${DIR}")
|
|
||||||
|
|
||||||
SET(INTERFACE_SRCS ${INTERFACE_SRCS} "${DIR_CONTENTS}")
|
# use the add_resources_to_os_x_bundle macro to recurse into resources
|
||||||
endif()
|
add_resources_to_os_x_bundle("${CMAKE_CURRENT_SOURCE_DIR}/resources")
|
||||||
endforeach()
|
|
||||||
|
|
||||||
SET(INTERFACE_SRCS ${INTERFACE_SRCS} "${CMAKE_CURRENT_SOURCE_DIR}/icon/${ICON_FILENAME}")
|
# append the discovered resources to our list of interface sources
|
||||||
|
list(APPEND INTERFACE_SRCS ${DISCOVERED_RESOURCES})
|
||||||
|
|
||||||
|
set(INTERFACE_SRCS ${INTERFACE_SRCS} "${CMAKE_CURRENT_SOURCE_DIR}/icon/${ICON_FILENAME}")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
# create the executable, make it a bundle on OS X
|
# create the executable, make it a bundle on OS X
|
||||||
|
|
|
@ -119,9 +119,9 @@ static const QString INFO_EDIT_ENTITIES_PATH = "html/edit-commands.html";
|
||||||
|
|
||||||
#ifdef Q_OS_WIN
|
#ifdef Q_OS_WIN
|
||||||
static const UINT UWM_IDENTIFY_INSTANCES =
|
static const UINT UWM_IDENTIFY_INSTANCES =
|
||||||
RegisterWindowMessage("UWM_IDENTIFY_INSTANCES_{8AB82783-B74A-4258-955B-8188C22AA0D6}");
|
RegisterWindowMessage("UWM_IDENTIFY_INSTANCES_{8AB82783-B74A-4258-955B-8188C22AA0D6}_" + qgetenv("USERNAME"));
|
||||||
static const UINT UWM_SHOW_APPLICATION =
|
static const UINT UWM_SHOW_APPLICATION =
|
||||||
RegisterWindowMessage("UWM_SHOW_APPLICATION_{71123FD6-3DA8-4DC1-9C27-8A12A6250CBA}");
|
RegisterWindowMessage("UWM_SHOW_APPLICATION_{71123FD6-3DA8-4DC1-9C27-8A12A6250CBA}_" + qgetenv("USERNAME"));
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
class Application;
|
class Application;
|
||||||
|
|
|
@ -73,20 +73,20 @@ void Head::reset() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void Head::simulate(float deltaTime, bool isMine, bool billboard) {
|
void Head::simulate(float deltaTime, bool isMine, bool billboard) {
|
||||||
|
// Update audio trailing average for rendering facial animations
|
||||||
|
const float AUDIO_AVERAGING_SECS = 0.05f;
|
||||||
|
const float AUDIO_LONG_TERM_AVERAGING_SECS = 30.0f;
|
||||||
|
_averageLoudness = glm::mix(_averageLoudness, _audioLoudness, glm::min(deltaTime / AUDIO_AVERAGING_SECS, 1.0f));
|
||||||
|
|
||||||
|
if (_longTermAverageLoudness == -1.0) {
|
||||||
|
_longTermAverageLoudness = _averageLoudness;
|
||||||
|
} else {
|
||||||
|
_longTermAverageLoudness = glm::mix(_longTermAverageLoudness, _averageLoudness, glm::min(deltaTime / AUDIO_LONG_TERM_AVERAGING_SECS, 1.0f));
|
||||||
|
}
|
||||||
|
|
||||||
if (isMine) {
|
if (isMine) {
|
||||||
MyAvatar* myAvatar = static_cast<MyAvatar*>(_owningAvatar);
|
MyAvatar* myAvatar = static_cast<MyAvatar*>(_owningAvatar);
|
||||||
|
|
||||||
// Update audio trailing average for rendering facial animations
|
|
||||||
const float AUDIO_AVERAGING_SECS = 0.05f;
|
|
||||||
const float AUDIO_LONG_TERM_AVERAGING_SECS = 30.0f;
|
|
||||||
_averageLoudness = glm::mix(_averageLoudness, _audioLoudness, glm::min(deltaTime / AUDIO_AVERAGING_SECS, 1.0f));
|
|
||||||
|
|
||||||
if (_longTermAverageLoudness == -1.0) {
|
|
||||||
_longTermAverageLoudness = _averageLoudness;
|
|
||||||
} else {
|
|
||||||
_longTermAverageLoudness = glm::mix(_longTermAverageLoudness, _averageLoudness, glm::min(deltaTime / AUDIO_LONG_TERM_AVERAGING_SECS, 1.0f));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Only use face trackers when not playing back a recording.
|
// Only use face trackers when not playing back a recording.
|
||||||
if (!myAvatar->isPlaying()) {
|
if (!myAvatar->isPlaying()) {
|
||||||
FaceTracker* faceTracker = Application::getInstance()->getActiveFaceTracker();
|
FaceTracker* faceTracker = Application::getInstance()->getActiveFaceTracker();
|
||||||
|
|
|
@ -136,9 +136,6 @@ struct Packet {
|
||||||
|
|
||||||
const float STARTING_DDE_MESSAGE_TIME = 0.033f;
|
const float STARTING_DDE_MESSAGE_TIME = 0.033f;
|
||||||
|
|
||||||
const int FPS_TIMER_DELAY = 2000; // ms
|
|
||||||
const int FPS_TIMER_DURATION = 2000; // ms
|
|
||||||
|
|
||||||
DdeFaceTracker::DdeFaceTracker() :
|
DdeFaceTracker::DdeFaceTracker() :
|
||||||
DdeFaceTracker(QHostAddress::Any, DDE_SERVER_PORT, DDE_CONTROL_PORT)
|
DdeFaceTracker(QHostAddress::Any, DDE_SERVER_PORT, DDE_CONTROL_PORT)
|
||||||
{
|
{
|
||||||
|
@ -147,6 +144,7 @@ DdeFaceTracker::DdeFaceTracker() :
|
||||||
|
|
||||||
DdeFaceTracker::DdeFaceTracker(const QHostAddress& host, quint16 serverPort, quint16 controlPort) :
|
DdeFaceTracker::DdeFaceTracker(const QHostAddress& host, quint16 serverPort, quint16 controlPort) :
|
||||||
_ddeProcess(NULL),
|
_ddeProcess(NULL),
|
||||||
|
_ddeStopping(false),
|
||||||
_host(host),
|
_host(host),
|
||||||
_serverPort(serverPort),
|
_serverPort(serverPort),
|
||||||
_controlPort(controlPort),
|
_controlPort(controlPort),
|
||||||
|
@ -171,9 +169,7 @@ DdeFaceTracker::DdeFaceTracker(const QHostAddress& host, quint16 serverPort, qui
|
||||||
_lastLeftEyeBlink(0.0f),
|
_lastLeftEyeBlink(0.0f),
|
||||||
_filteredLeftEyeBlink(0.0f),
|
_filteredLeftEyeBlink(0.0f),
|
||||||
_lastRightEyeBlink(0.0f),
|
_lastRightEyeBlink(0.0f),
|
||||||
_filteredRightEyeBlink(0.0f),
|
_filteredRightEyeBlink(0.0f)
|
||||||
_isCalculatingFPS(false),
|
|
||||||
_frameCount(0)
|
|
||||||
{
|
{
|
||||||
_coefficients.resize(NUM_FACESHIFT_BLENDSHAPES);
|
_coefficients.resize(NUM_FACESHIFT_BLENDSHAPES);
|
||||||
|
|
||||||
|
@ -201,46 +197,50 @@ void DdeFaceTracker::setEnabled(bool enabled) {
|
||||||
if (enabled && !_ddeProcess) {
|
if (enabled && !_ddeProcess) {
|
||||||
// Terminate any existing DDE process, perhaps left running after an Interface crash
|
// Terminate any existing DDE process, perhaps left running after an Interface crash
|
||||||
_udpSocket.writeDatagram(DDE_EXIT_COMMAND, DDE_SERVER_ADDR, _controlPort);
|
_udpSocket.writeDatagram(DDE_EXIT_COMMAND, DDE_SERVER_ADDR, _controlPort);
|
||||||
|
_ddeStopping = false;
|
||||||
|
|
||||||
qDebug() << "[Info] DDE Face Tracker Starting";
|
qCDebug(interfaceapp) << "DDE Face Tracker: Starting";
|
||||||
_ddeProcess = new QProcess(qApp);
|
_ddeProcess = new QProcess(qApp);
|
||||||
connect(_ddeProcess, SIGNAL(finished(int, QProcess::ExitStatus)), SLOT(processFinished(int, QProcess::ExitStatus)));
|
connect(_ddeProcess, SIGNAL(finished(int, QProcess::ExitStatus)), SLOT(processFinished(int, QProcess::ExitStatus)));
|
||||||
_ddeProcess->start(QCoreApplication::applicationDirPath() + DDE_PROGRAM_PATH, DDE_ARGUMENTS);
|
_ddeProcess->start(QCoreApplication::applicationDirPath() + DDE_PROGRAM_PATH, DDE_ARGUMENTS);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!enabled && _ddeProcess) {
|
if (!enabled && _ddeProcess) {
|
||||||
|
_ddeStopping = true;
|
||||||
_udpSocket.writeDatagram(DDE_EXIT_COMMAND, DDE_SERVER_ADDR, _controlPort);
|
_udpSocket.writeDatagram(DDE_EXIT_COMMAND, DDE_SERVER_ADDR, _controlPort);
|
||||||
delete _ddeProcess;
|
qCDebug(interfaceapp) << "DDE Face Tracker: Stopping";
|
||||||
_ddeProcess = NULL;
|
|
||||||
qDebug() << "[Info] DDE Face Tracker Stopped";
|
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void DdeFaceTracker::processFinished(int exitCode, QProcess::ExitStatus exitStatus) {
|
void DdeFaceTracker::processFinished(int exitCode, QProcess::ExitStatus exitStatus) {
|
||||||
if (_ddeProcess) {
|
if (_ddeProcess) {
|
||||||
// DDE crashed or was manually terminated
|
if (_ddeStopping) {
|
||||||
qDebug() << "[Info] DDE Face Tracker Stopped Unexpectedly";
|
qCDebug(interfaceapp) << "DDE Face Tracker: Stopped";
|
||||||
|
|
||||||
|
} else {
|
||||||
|
qCWarning(interfaceapp) << "DDE Face Tracker: Stopped unexpectedly";
|
||||||
|
Menu::getInstance()->setIsOptionChecked(MenuOption::NoFaceTracking, true);
|
||||||
|
}
|
||||||
_udpSocket.close();
|
_udpSocket.close();
|
||||||
|
delete _ddeProcess;
|
||||||
_ddeProcess = NULL;
|
_ddeProcess = NULL;
|
||||||
Menu::getInstance()->setIsOptionChecked(MenuOption::NoFaceTracking, true);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void DdeFaceTracker::reset() {
|
void DdeFaceTracker::reset() {
|
||||||
_reset = true;
|
if (_udpSocket.state() == QAbstractSocket::BoundState) {
|
||||||
|
_reset = true;
|
||||||
|
|
||||||
qDebug() << "[Info] Reset DDE Tracking";
|
qCDebug(interfaceapp) << "DDE Face Tracker: Reset";
|
||||||
const char* DDE_RESET_COMMAND = "reset";
|
|
||||||
_udpSocket.writeDatagram(DDE_RESET_COMMAND, DDE_SERVER_ADDR, _controlPort);
|
|
||||||
|
|
||||||
// Log camera FPS after a reset
|
const char* DDE_RESET_COMMAND = "reset";
|
||||||
if (!_isCalculatingFPS) {
|
_udpSocket.writeDatagram(DDE_RESET_COMMAND, DDE_SERVER_ADDR, _controlPort);
|
||||||
QTimer::singleShot(FPS_TIMER_DELAY, this, SLOT(startFPSTimer()));
|
|
||||||
_isCalculatingFPS = true;
|
FaceTracker::reset();
|
||||||
|
|
||||||
|
_reset = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
_reset = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool DdeFaceTracker::isActive() const {
|
bool DdeFaceTracker::isActive() const {
|
||||||
|
@ -250,7 +250,7 @@ bool DdeFaceTracker::isActive() const {
|
||||||
|
|
||||||
//private slots and methods
|
//private slots and methods
|
||||||
void DdeFaceTracker::socketErrorOccurred(QAbstractSocket::SocketError socketError) {
|
void DdeFaceTracker::socketErrorOccurred(QAbstractSocket::SocketError socketError) {
|
||||||
qCDebug(interfaceapp) << "[Error] DDE Face Tracker Socket Error: " << _udpSocket.errorString();
|
qCWarning(interfaceapp) << "DDE Face Tracker: Socket error: " << _udpSocket.errorString();
|
||||||
}
|
}
|
||||||
|
|
||||||
void DdeFaceTracker::socketStateChanged(QAbstractSocket::SocketState socketState) {
|
void DdeFaceTracker::socketStateChanged(QAbstractSocket::SocketState socketState) {
|
||||||
|
@ -278,7 +278,7 @@ void DdeFaceTracker::socketStateChanged(QAbstractSocket::SocketState socketState
|
||||||
state = "Unconnected";
|
state = "Unconnected";
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
qCDebug(interfaceapp) << "[Info] DDE Face Tracker Socket: " << state;
|
qCDebug(interfaceapp) << "DDE Face Tracker: Socket: " << state;
|
||||||
}
|
}
|
||||||
|
|
||||||
void DdeFaceTracker::readPendingDatagrams() {
|
void DdeFaceTracker::readPendingDatagrams() {
|
||||||
|
@ -419,23 +419,10 @@ void DdeFaceTracker::decodePacket(const QByteArray& buffer) {
|
||||||
}
|
}
|
||||||
_lastMessageReceived = usecsNow;
|
_lastMessageReceived = usecsNow;
|
||||||
|
|
||||||
// Count frames if timing
|
FaceTracker::countFrame();
|
||||||
if (_isCalculatingFPS) {
|
|
||||||
_frameCount++;
|
|
||||||
}
|
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
qCDebug(interfaceapp) << "[Error] DDE Face Tracker Decode Error";
|
qCWarning(interfaceapp) << "DDE Face Tracker: Decode error";
|
||||||
}
|
}
|
||||||
_lastReceiveTimestamp = usecTimestampNow();
|
_lastReceiveTimestamp = usecTimestampNow();
|
||||||
}
|
}
|
||||||
|
|
||||||
void DdeFaceTracker::startFPSTimer() {
|
|
||||||
_frameCount = 0;
|
|
||||||
QTimer::singleShot(FPS_TIMER_DURATION, this, SLOT(finishFPSTimer()));
|
|
||||||
}
|
|
||||||
|
|
||||||
void DdeFaceTracker::finishFPSTimer() {
|
|
||||||
qDebug() << "[Info] DDE FPS =" << (float)_frameCount / ((float)FPS_TIMER_DURATION / 1000.0f);
|
|
||||||
_isCalculatingFPS = false;
|
|
||||||
}
|
|
||||||
|
|
|
@ -59,15 +59,13 @@ private slots:
|
||||||
void readPendingDatagrams();
|
void readPendingDatagrams();
|
||||||
void socketStateChanged(QAbstractSocket::SocketState socketState);
|
void socketStateChanged(QAbstractSocket::SocketState socketState);
|
||||||
|
|
||||||
void startFPSTimer();
|
|
||||||
void finishFPSTimer();
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
DdeFaceTracker();
|
DdeFaceTracker();
|
||||||
DdeFaceTracker(const QHostAddress& host, quint16 serverPort, quint16 controlPort);
|
DdeFaceTracker(const QHostAddress& host, quint16 serverPort, quint16 controlPort);
|
||||||
~DdeFaceTracker();
|
virtual ~DdeFaceTracker();
|
||||||
|
|
||||||
QProcess* _ddeProcess;
|
QProcess* _ddeProcess;
|
||||||
|
bool _ddeStopping;
|
||||||
|
|
||||||
QHostAddress _host;
|
QHostAddress _host;
|
||||||
quint16 _serverPort;
|
quint16 _serverPort;
|
||||||
|
@ -111,9 +109,6 @@ private:
|
||||||
float _filteredLeftEyeBlink;
|
float _filteredLeftEyeBlink;
|
||||||
float _lastRightEyeBlink;
|
float _lastRightEyeBlink;
|
||||||
float _filteredRightEyeBlink;
|
float _filteredRightEyeBlink;
|
||||||
|
|
||||||
bool _isCalculatingFPS;
|
|
||||||
int _frameCount;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // hifi_DdeFaceTracker_h
|
#endif // hifi_DdeFaceTracker_h
|
|
@ -9,9 +9,21 @@
|
||||||
// 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 <QTimer>
|
||||||
|
|
||||||
#include <GLMHelpers.h>
|
#include <GLMHelpers.h>
|
||||||
|
|
||||||
#include "FaceTracker.h"
|
#include "FaceTracker.h"
|
||||||
|
#include "InterfaceLogging.h"
|
||||||
|
|
||||||
|
const int FPS_TIMER_DELAY = 2000; // ms
|
||||||
|
const int FPS_TIMER_DURATION = 2000; // ms
|
||||||
|
|
||||||
|
FaceTracker::FaceTracker() :
|
||||||
|
_isCalculatingFPS(false),
|
||||||
|
_frameCount(0)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
inline float FaceTracker::getBlendshapeCoefficient(int index) const {
|
inline float FaceTracker::getBlendshapeCoefficient(int index) const {
|
||||||
return isValidBlendshapeIndex(index) ? glm::mix(0.0f, _blendshapeCoefficients[index], getFadeCoefficient())
|
return isValidBlendshapeIndex(index) ? glm::mix(0.0f, _blendshapeCoefficients[index], getFadeCoefficient())
|
||||||
|
@ -65,4 +77,27 @@ void FaceTracker::update(float deltaTime) {
|
||||||
_relaxationStatus = glm::clamp(_relaxationStatus - deltaTime / RELAXATION_TIME, 0.0f, 1.0f);
|
_relaxationStatus = glm::clamp(_relaxationStatus - deltaTime / RELAXATION_TIME, 0.0f, 1.0f);
|
||||||
_fadeCoefficient = std::exp(-(1.0f - _relaxationStatus) * INVERSE_AT_EPSILON);
|
_fadeCoefficient = std::exp(-(1.0f - _relaxationStatus) * INVERSE_AT_EPSILON);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void FaceTracker::reset() {
|
||||||
|
if (isActive() && !_isCalculatingFPS) {
|
||||||
|
QTimer::singleShot(FPS_TIMER_DELAY, this, SLOT(startFPSTimer()));
|
||||||
|
_isCalculatingFPS = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void FaceTracker::startFPSTimer() {
|
||||||
|
_frameCount = 0;
|
||||||
|
QTimer::singleShot(FPS_TIMER_DURATION, this, SLOT(finishFPSTimer()));
|
||||||
|
}
|
||||||
|
|
||||||
|
void FaceTracker::countFrame() {
|
||||||
|
if (_isCalculatingFPS) {
|
||||||
|
_frameCount++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void FaceTracker::finishFPSTimer() {
|
||||||
|
qCDebug(interfaceapp) << "Face tracker FPS =" << (float)_frameCount / ((float)FPS_TIMER_DURATION / 1000.0f);
|
||||||
|
_isCalculatingFPS = false;
|
||||||
|
}
|
||||||
|
|
|
@ -28,7 +28,7 @@ public:
|
||||||
|
|
||||||
virtual void init() {}
|
virtual void init() {}
|
||||||
virtual void update(float deltaTime);
|
virtual void update(float deltaTime);
|
||||||
virtual void reset() {}
|
virtual void reset();
|
||||||
|
|
||||||
float getFadeCoefficient() const;
|
float getFadeCoefficient() const;
|
||||||
|
|
||||||
|
@ -44,6 +44,9 @@ public:
|
||||||
float getBlendshapeCoefficient(int index) const;
|
float getBlendshapeCoefficient(int index) const;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
FaceTracker();
|
||||||
|
virtual ~FaceTracker() {};
|
||||||
|
|
||||||
glm::vec3 _headTranslation = glm::vec3(0.0f);
|
glm::vec3 _headTranslation = glm::vec3(0.0f);
|
||||||
glm::quat _headRotation = glm::quat();
|
glm::quat _headRotation = glm::quat();
|
||||||
float _estimatedEyePitch = 0.0f;
|
float _estimatedEyePitch = 0.0f;
|
||||||
|
@ -52,6 +55,16 @@ protected:
|
||||||
|
|
||||||
float _relaxationStatus = 0.0f; // Between 0.0f and 1.0f
|
float _relaxationStatus = 0.0f; // Between 0.0f and 1.0f
|
||||||
float _fadeCoefficient = 0.0f; // Between 0.0f and 1.0f
|
float _fadeCoefficient = 0.0f; // Between 0.0f and 1.0f
|
||||||
|
|
||||||
|
void countFrame();
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void startFPSTimer();
|
||||||
|
void finishFPSTimer();
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool _isCalculatingFPS;
|
||||||
|
int _frameCount;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // hifi_FaceTracker_h
|
#endif // hifi_FaceTracker_h
|
||||||
|
|
|
@ -30,20 +30,16 @@ const QString DEFAULT_FACESHIFT_HOSTNAME = "localhost";
|
||||||
const quint16 FACESHIFT_PORT = 33433;
|
const quint16 FACESHIFT_PORT = 33433;
|
||||||
const float DEFAULT_FACESHIFT_EYE_DEFLECTION = 0.25f;
|
const float DEFAULT_FACESHIFT_EYE_DEFLECTION = 0.25f;
|
||||||
|
|
||||||
const int FPS_TIMER_DELAY = 2000; // ms
|
|
||||||
const int FPS_TIMER_DURATION = 2000; // ms
|
|
||||||
|
|
||||||
Faceshift::Faceshift() :
|
Faceshift::Faceshift() :
|
||||||
_eyeDeflection("faceshiftEyeDeflection", DEFAULT_FACESHIFT_EYE_DEFLECTION),
|
_eyeDeflection("faceshiftEyeDeflection", DEFAULT_FACESHIFT_EYE_DEFLECTION),
|
||||||
_hostname("faceshiftHostname", DEFAULT_FACESHIFT_HOSTNAME),
|
_hostname("faceshiftHostname", DEFAULT_FACESHIFT_HOSTNAME)
|
||||||
_isCalculatingFPS(false),
|
|
||||||
_frameCount(0)
|
|
||||||
{
|
{
|
||||||
#ifdef HAVE_FACESHIFT
|
#ifdef HAVE_FACESHIFT
|
||||||
connect(&_tcpSocket, SIGNAL(connected()), SLOT(noteConnected()));
|
connect(&_tcpSocket, SIGNAL(connected()), SLOT(noteConnected()));
|
||||||
connect(&_tcpSocket, SIGNAL(error(QAbstractSocket::SocketError)), SLOT(noteError(QAbstractSocket::SocketError)));
|
connect(&_tcpSocket, SIGNAL(error(QAbstractSocket::SocketError)), SLOT(noteError(QAbstractSocket::SocketError)));
|
||||||
connect(&_tcpSocket, SIGNAL(readyRead()), SLOT(readFromSocket()));
|
connect(&_tcpSocket, SIGNAL(readyRead()), SLOT(readFromSocket()));
|
||||||
connect(&_tcpSocket, SIGNAL(stateChanged(QAbstractSocket::SocketState)), SIGNAL(connectionStateChanged()));
|
connect(&_tcpSocket, SIGNAL(stateChanged(QAbstractSocket::SocketState)), SIGNAL(connectionStateChanged()));
|
||||||
|
connect(&_tcpSocket, SIGNAL(disconnected()), SLOT(noteDisconnected()));
|
||||||
|
|
||||||
connect(&_udpSocket, SIGNAL(readyRead()), SLOT(readPendingDatagrams()));
|
connect(&_udpSocket, SIGNAL(readyRead()), SLOT(readPendingDatagrams()));
|
||||||
|
|
||||||
|
@ -83,15 +79,13 @@ void Faceshift::update(float deltaTime) {
|
||||||
|
|
||||||
void Faceshift::reset() {
|
void Faceshift::reset() {
|
||||||
if (_tcpSocket.state() == QAbstractSocket::ConnectedState) {
|
if (_tcpSocket.state() == QAbstractSocket::ConnectedState) {
|
||||||
|
qCDebug(interfaceapp, "Faceshift: Reset");
|
||||||
|
|
||||||
|
FaceTracker::reset();
|
||||||
|
|
||||||
string message;
|
string message;
|
||||||
fsBinaryStream::encode_message(message, fsMsgCalibrateNeutral());
|
fsBinaryStream::encode_message(message, fsMsgCalibrateNeutral());
|
||||||
send(message);
|
send(message);
|
||||||
|
|
||||||
// Log camera FPS after a reset
|
|
||||||
if (!_isCalculatingFPS) {
|
|
||||||
QTimer::singleShot(FPS_TIMER_DELAY, this, SLOT(startFPSTimer()));
|
|
||||||
_isCalculatingFPS = true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
_longTermAverageInitialized = false;
|
_longTermAverageInitialized = false;
|
||||||
}
|
}
|
||||||
|
@ -138,6 +132,7 @@ void Faceshift::setTCPEnabled(bool enabled) {
|
||||||
if ((_tcpEnabled = enabled)) {
|
if ((_tcpEnabled = enabled)) {
|
||||||
connectSocket();
|
connectSocket();
|
||||||
} else {
|
} else {
|
||||||
|
qCDebug(interfaceapp, "Faceshift: Disconnecting...");
|
||||||
_tcpSocket.disconnectFromHost();
|
_tcpSocket.disconnectFromHost();
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -156,7 +151,7 @@ void Faceshift::connectSocket() {
|
||||||
|
|
||||||
void Faceshift::noteConnected() {
|
void Faceshift::noteConnected() {
|
||||||
#ifdef HAVE_FACESHIFT
|
#ifdef HAVE_FACESHIFT
|
||||||
qCDebug(interfaceapp, "Faceshift: Connected.");
|
qCDebug(interfaceapp, "Faceshift: Connected");
|
||||||
// request the list of blendshape names
|
// request the list of blendshape names
|
||||||
string message;
|
string message;
|
||||||
fsBinaryStream::encode_message(message, fsMsgSendBlendshapeNames());
|
fsBinaryStream::encode_message(message, fsMsgSendBlendshapeNames());
|
||||||
|
@ -164,10 +159,16 @@ void Faceshift::noteConnected() {
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Faceshift::noteDisconnected() {
|
||||||
|
#ifdef HAVE_FACESHIFT
|
||||||
|
qCDebug(interfaceapp, "Faceshift: Disconnected");
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
void Faceshift::noteError(QAbstractSocket::SocketError error) {
|
void Faceshift::noteError(QAbstractSocket::SocketError error) {
|
||||||
if (!_tcpRetryCount) {
|
if (!_tcpRetryCount) {
|
||||||
// Only spam log with fail to connect the first time, so that we can keep waiting for server
|
// Only spam log with fail to connect the first time, so that we can keep waiting for server
|
||||||
qCDebug(interfaceapp) << "Faceshift: " << _tcpSocket.errorString();
|
qCWarning(interfaceapp) << "Faceshift: " << _tcpSocket.errorString();
|
||||||
}
|
}
|
||||||
// retry connection after a 2 second delay
|
// retry connection after a 2 second delay
|
||||||
if (_tcpEnabled) {
|
if (_tcpEnabled) {
|
||||||
|
@ -294,10 +295,8 @@ void Faceshift::receive(const QByteArray& buffer) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
// Count frames if timing
|
|
||||||
if (_isCalculatingFPS) {
|
FaceTracker::countFrame();
|
||||||
_frameCount++;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Faceshift::setEyeDeflection(float faceshiftEyeDeflection) {
|
void Faceshift::setEyeDeflection(float faceshiftEyeDeflection) {
|
||||||
|
@ -308,12 +307,3 @@ void Faceshift::setHostname(const QString& hostname) {
|
||||||
_hostname.set(hostname);
|
_hostname.set(hostname);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Faceshift::startFPSTimer() {
|
|
||||||
_frameCount = 0;
|
|
||||||
QTimer::singleShot(FPS_TIMER_DURATION, this, SLOT(finishFPSTimer()));
|
|
||||||
}
|
|
||||||
|
|
||||||
void Faceshift::finishFPSTimer() {
|
|
||||||
qCDebug(interfaceapp) << "Faceshift: FPS =" << (float)_frameCount / ((float)FPS_TIMER_DURATION / 1000.0f);
|
|
||||||
_isCalculatingFPS = false;
|
|
||||||
}
|
|
||||||
|
|
|
@ -95,8 +95,7 @@ private slots:
|
||||||
void noteError(QAbstractSocket::SocketError error);
|
void noteError(QAbstractSocket::SocketError error);
|
||||||
void readPendingDatagrams();
|
void readPendingDatagrams();
|
||||||
void readFromSocket();
|
void readFromSocket();
|
||||||
void startFPSTimer();
|
void noteDisconnected();
|
||||||
void finishFPSTimer();
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Faceshift();
|
Faceshift();
|
||||||
|
@ -154,9 +153,6 @@ private:
|
||||||
int _mouthSmileRightIndex = 29;
|
int _mouthSmileRightIndex = 29;
|
||||||
|
|
||||||
int _jawOpenIndex = 21;
|
int _jawOpenIndex = 21;
|
||||||
|
|
||||||
bool _isCalculatingFPS;
|
|
||||||
int _frameCount;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // hifi_Faceshift_h
|
#endif // hifi_Faceshift_h
|
||||||
|
|
|
@ -42,7 +42,7 @@ static BOOL CALLBACK enumWindowsCallback(HWND hWnd, LPARAM lParam) {
|
||||||
int main(int argc, const char* argv[]) {
|
int main(int argc, const char* argv[]) {
|
||||||
#ifdef Q_OS_WIN
|
#ifdef Q_OS_WIN
|
||||||
// Run only one instance of Interface at a time.
|
// Run only one instance of Interface at a time.
|
||||||
HANDLE mutex = CreateMutex(NULL, FALSE, "High Fidelity Interface");
|
HANDLE mutex = CreateMutex(NULL, FALSE, "High Fidelity Interface - " + qgetenv("USERNAME"));
|
||||||
DWORD result = GetLastError();
|
DWORD result = GetLastError();
|
||||||
if (result == ERROR_ALREADY_EXISTS || result == ERROR_ACCESS_DENIED) {
|
if (result == ERROR_ALREADY_EXISTS || result == ERROR_ACCESS_DENIED) {
|
||||||
// Interface is already running.
|
// Interface is already running.
|
||||||
|
|
|
@ -18,39 +18,77 @@ EntityItem* RenderableZoneEntityItem::factory(const EntityItemID& entityID, cons
|
||||||
return new RenderableZoneEntityItem(entityID, properties);
|
return new RenderableZoneEntityItem(entityID, properties);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool RenderableZoneEntityItem::setProperties(const EntityItemProperties& properties) {
|
template<typename Lambda>
|
||||||
|
void RenderableZoneEntityItem::changeProperties(Lambda setNewProperties) {
|
||||||
QString oldShapeURL = getCompoundShapeURL();
|
QString oldShapeURL = getCompoundShapeURL();
|
||||||
bool somethingChanged = ZoneEntityItem::setProperties(properties);
|
glm::vec3 oldPosition = getPosition(), oldDimensions = getDimensions();
|
||||||
if (somethingChanged && oldShapeURL != getCompoundShapeURL()) {
|
glm::quat oldRotation = getRotation();
|
||||||
_compoundShapeModel = DependencyManager::get<GeometryCache>()->getGeometry(getCompoundShapeURL(), QUrl(), true);
|
|
||||||
|
setNewProperties();
|
||||||
|
|
||||||
|
if (oldShapeURL != getCompoundShapeURL()) {
|
||||||
|
if (!_model) {
|
||||||
|
_model = getModel();
|
||||||
|
_needsInitialSimulation = true;
|
||||||
|
}
|
||||||
|
_model->setURL(getCompoundShapeURL(), QUrl(), true, true);
|
||||||
}
|
}
|
||||||
|
if (oldPosition != getPosition() ||
|
||||||
|
oldRotation != getRotation() ||
|
||||||
|
oldDimensions != getDimensions()) {
|
||||||
|
_needsInitialSimulation = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool RenderableZoneEntityItem::setProperties(const EntityItemProperties& properties) {
|
||||||
|
bool somethingChanged = false;
|
||||||
|
changeProperties([&]() {
|
||||||
|
somethingChanged = this->ZoneEntityItem::setProperties(properties);
|
||||||
|
});
|
||||||
return somethingChanged;
|
return somethingChanged;
|
||||||
}
|
}
|
||||||
|
|
||||||
int RenderableZoneEntityItem::readEntitySubclassDataFromBuffer(const unsigned char* data, int bytesLeftToRead,
|
int RenderableZoneEntityItem::readEntitySubclassDataFromBuffer(const unsigned char* data, int bytesLeftToRead,
|
||||||
ReadBitstreamToTreeParams& args,
|
ReadBitstreamToTreeParams& args,
|
||||||
EntityPropertyFlags& propertyFlags, bool overwriteLocalData) {
|
EntityPropertyFlags& propertyFlags, bool overwriteLocalData) {
|
||||||
QString oldShapeURL = getCompoundShapeURL();
|
int bytesRead = 0;
|
||||||
int bytesRead = ZoneEntityItem::readEntitySubclassDataFromBuffer(data, bytesLeftToRead,
|
changeProperties([&]() {
|
||||||
args, propertyFlags, overwriteLocalData);
|
bytesRead = ZoneEntityItem::readEntitySubclassDataFromBuffer(data, bytesLeftToRead,
|
||||||
if (oldShapeURL != getCompoundShapeURL()) {
|
args, propertyFlags, overwriteLocalData);
|
||||||
_compoundShapeModel = DependencyManager::get<GeometryCache>()->getGeometry(getCompoundShapeURL(), QUrl(), true);
|
});
|
||||||
}
|
|
||||||
return bytesRead;
|
return bytesRead;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Model* RenderableZoneEntityItem::getModel() {
|
||||||
|
Model* model = new Model();
|
||||||
|
model->init();
|
||||||
|
return model;
|
||||||
|
}
|
||||||
|
|
||||||
|
void RenderableZoneEntityItem::initialSimulation() {
|
||||||
|
_model->setScaleToFit(true, getDimensions());
|
||||||
|
_model->setSnapModelToRegistrationPoint(true, getRegistrationPoint());
|
||||||
|
_model->setRotation(getRotation());
|
||||||
|
_model->setTranslation(getPosition());
|
||||||
|
_model->simulate(0.0f);
|
||||||
|
_needsInitialSimulation = false;
|
||||||
|
}
|
||||||
|
|
||||||
bool RenderableZoneEntityItem::contains(const glm::vec3& point) const {
|
bool RenderableZoneEntityItem::contains(const glm::vec3& point) const {
|
||||||
if (getShapeType() != SHAPE_TYPE_COMPOUND) {
|
if (getShapeType() != SHAPE_TYPE_COMPOUND) {
|
||||||
return EntityItem::contains(point);
|
return EntityItem::contains(point);
|
||||||
}
|
}
|
||||||
if (!_compoundShapeModel && hasCompoundShapeURL()) {
|
|
||||||
const_cast<RenderableZoneEntityItem*>(this)->_compoundShapeModel = DependencyManager::get<GeometryCache>()->getGeometry(getCompoundShapeURL(), QUrl(), true);
|
if (_model && !_model->isActive() && hasCompoundShapeURL()) {
|
||||||
|
// Since we have a delayload, we need to update the geometry if it has been downloaded
|
||||||
|
_model->setURL(getCompoundShapeURL(), QUrl(), true);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (EntityItem::contains(point) && _compoundShapeModel && _compoundShapeModel->isLoaded()) {
|
if (_model && _model->isActive() && EntityItem::contains(point)) {
|
||||||
const FBXGeometry& geometry = _compoundShapeModel->getFBXGeometry();
|
if (_needsInitialSimulation) {
|
||||||
glm::vec3 meshDimensions = geometry.getUnscaledMeshExtents().maximum - geometry.getUnscaledMeshExtents().minimum;
|
const_cast<RenderableZoneEntityItem*>(this)->initialSimulation();
|
||||||
return geometry.convexHullContains(worldToEntity(point) * meshDimensions);
|
}
|
||||||
|
return _model->convexHullContains(point);
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
|
|
|
@ -12,6 +12,7 @@
|
||||||
#ifndef hifi_RenderableZoneEntityItem_h
|
#ifndef hifi_RenderableZoneEntityItem_h
|
||||||
#define hifi_RenderableZoneEntityItem_h
|
#define hifi_RenderableZoneEntityItem_h
|
||||||
|
|
||||||
|
#include <Model.h>
|
||||||
#include <ZoneEntityItem.h>
|
#include <ZoneEntityItem.h>
|
||||||
|
|
||||||
class NetworkGeometry;
|
class NetworkGeometry;
|
||||||
|
@ -21,7 +22,9 @@ public:
|
||||||
static EntityItem* factory(const EntityItemID& entityID, const EntityItemProperties& properties);
|
static EntityItem* factory(const EntityItemID& entityID, const EntityItemProperties& properties);
|
||||||
|
|
||||||
RenderableZoneEntityItem(const EntityItemID& entityItemID, const EntityItemProperties& properties) :
|
RenderableZoneEntityItem(const EntityItemID& entityItemID, const EntityItemProperties& properties) :
|
||||||
ZoneEntityItem(entityItemID, properties)
|
ZoneEntityItem(entityItemID, properties),
|
||||||
|
_model(NULL),
|
||||||
|
_needsInitialSimulation(true)
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
virtual bool setProperties(const EntityItemProperties& properties);
|
virtual bool setProperties(const EntityItemProperties& properties);
|
||||||
|
@ -32,8 +35,14 @@ public:
|
||||||
virtual bool contains(const glm::vec3& point) const;
|
virtual bool contains(const glm::vec3& point) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
Model* getModel();
|
||||||
|
void initialSimulation();
|
||||||
|
|
||||||
QSharedPointer<NetworkGeometry> _compoundShapeModel;
|
template<typename Lambda>
|
||||||
|
void changeProperties(Lambda functor);
|
||||||
|
|
||||||
|
Model* _model;
|
||||||
|
bool _needsInitialSimulation;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // hifi_RenderableZoneEntityItem_h
|
#endif // hifi_RenderableZoneEntityItem_h
|
|
@ -58,6 +58,9 @@ NodeList::NodeList(char newOwnerType, unsigned short socketListenPort, unsigned
|
||||||
|
|
||||||
// handle ICE signal from DS so connection is attempted immediately
|
// handle ICE signal from DS so connection is attempted immediately
|
||||||
connect(&_domainHandler, &DomainHandler::requestICEConnectionAttempt, this, &NodeList::handleICEConnectionToDomainServer);
|
connect(&_domainHandler, &DomainHandler::requestICEConnectionAttempt, this, &NodeList::handleICEConnectionToDomainServer);
|
||||||
|
|
||||||
|
// clear out NodeList when login is finished
|
||||||
|
connect(&AccountManager::getInstance(), &AccountManager::loginComplete , this, &NodeList::reset);
|
||||||
|
|
||||||
// clear our NodeList when logout is requested
|
// clear our NodeList when logout is requested
|
||||||
connect(&AccountManager::getInstance(), &AccountManager::logoutComplete , this, &NodeList::reset);
|
connect(&AccountManager::getInstance(), &AccountManager::logoutComplete , this, &NodeList::reset);
|
||||||
|
|
|
@ -285,6 +285,7 @@ void OctreePersistThread::restoreFromMostRecentBackup() {
|
||||||
qCDebug(octree) << "DONE restoring backup file " << mostRecentBackupFileName << "to" << _filename << "...";
|
qCDebug(octree) << "DONE restoring backup file " << mostRecentBackupFileName << "to" << _filename << "...";
|
||||||
} else {
|
} else {
|
||||||
qCDebug(octree) << "ERROR while restoring backup file " << mostRecentBackupFileName << "to" << _filename << "...";
|
qCDebug(octree) << "ERROR while restoring backup file " << mostRecentBackupFileName << "to" << _filename << "...";
|
||||||
|
perror("ERROR while restoring backup file");
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
qCDebug(octree) << "NO BEST backup file found.";
|
qCDebug(octree) << "NO BEST backup file found.";
|
||||||
|
@ -366,6 +367,7 @@ void OctreePersistThread::rollOldBackupVersions(const BackupRule& rule) {
|
||||||
qCDebug(octree) << "DONE rolling backup file " << backupFilenameN << "to" << backupFilenameNplusOne << "...";
|
qCDebug(octree) << "DONE rolling backup file " << backupFilenameN << "to" << backupFilenameNplusOne << "...";
|
||||||
} else {
|
} else {
|
||||||
qCDebug(octree) << "ERROR in rolling backup file " << backupFilenameN << "to" << backupFilenameNplusOne << "...";
|
qCDebug(octree) << "ERROR in rolling backup file " << backupFilenameN << "to" << backupFilenameNplusOne << "...";
|
||||||
|
perror("ERROR in rolling backup file");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -425,6 +427,7 @@ void OctreePersistThread::backup() {
|
||||||
rule.lastBackup = now; // only record successful backup in this case.
|
rule.lastBackup = now; // only record successful backup in this case.
|
||||||
} else {
|
} else {
|
||||||
qCDebug(octree) << "ERROR in backing up persist file...";
|
qCDebug(octree) << "ERROR in backing up persist file...";
|
||||||
|
perror("ERROR in backing up persist file");
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
qCDebug(octree) << "persist file " << _filename << " does not exist. " <<
|
qCDebug(octree) << "persist file " << _filename << " does not exist. " <<
|
||||||
|
|
|
@ -324,7 +324,7 @@ public:
|
||||||
|
|
||||||
const FBXGeometry& getFBXGeometry() const { return _geometry; }
|
const FBXGeometry& getFBXGeometry() const { return _geometry; }
|
||||||
const QVector<NetworkMesh>& getMeshes() const { return _meshes; }
|
const QVector<NetworkMesh>& getMeshes() const { return _meshes; }
|
||||||
//
|
|
||||||
QVector<int> getJointMappings(const AnimationPointer& animation);
|
QVector<int> getJointMappings(const AnimationPointer& animation);
|
||||||
|
|
||||||
virtual void setLoadPriority(const QPointer<QObject>& owner, float priority);
|
virtual void setLoadPriority(const QPointer<QObject>& owner, float priority);
|
||||||
|
|
|
@ -573,6 +573,61 @@ bool Model::findRayIntersectionAgainstSubMeshes(const glm::vec3& origin, const g
|
||||||
return intersectedSomething;
|
return intersectedSomething;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Model::convexHullContains(glm::vec3 point) {
|
||||||
|
// if we aren't active, we can't compute that yet...
|
||||||
|
if (!isActive()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// extents is the entity relative, scaled, centered extents of the entity
|
||||||
|
glm::vec3 position = _translation;
|
||||||
|
glm::mat4 rotation = glm::mat4_cast(_rotation);
|
||||||
|
glm::mat4 translation = glm::translate(position);
|
||||||
|
glm::mat4 modelToWorldMatrix = translation * rotation;
|
||||||
|
glm::mat4 worldToModelMatrix = glm::inverse(modelToWorldMatrix);
|
||||||
|
|
||||||
|
Extents modelExtents = getMeshExtents(); // NOTE: unrotated
|
||||||
|
|
||||||
|
glm::vec3 dimensions = modelExtents.maximum - modelExtents.minimum;
|
||||||
|
glm::vec3 corner = -(dimensions * _registrationPoint);
|
||||||
|
AABox modelFrameBox(corner, dimensions);
|
||||||
|
|
||||||
|
glm::vec3 modelFramePoint = glm::vec3(worldToModelMatrix * glm::vec4(point, 1.0f));
|
||||||
|
|
||||||
|
// we can use the AABox's contains() by mapping our point into the model frame
|
||||||
|
// and testing there.
|
||||||
|
if (modelFrameBox.contains(modelFramePoint)){
|
||||||
|
if (!_calculatedMeshTrianglesValid) {
|
||||||
|
recalculateMeshBoxes(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we are inside the models box, then consider the submeshes...
|
||||||
|
int subMeshIndex = 0;
|
||||||
|
foreach(const AABox& subMeshBox, _calculatedMeshBoxes) {
|
||||||
|
if (subMeshBox.contains(point)) {
|
||||||
|
bool insideMesh = true;
|
||||||
|
// To be inside the sub mesh, we need to be behind every triangles' planes
|
||||||
|
const QVector<Triangle>& meshTriangles = _calculatedMeshTriangles[subMeshIndex];
|
||||||
|
foreach (const Triangle& triangle, meshTriangles) {
|
||||||
|
if (!isPointBehindTrianglesPlane(point, triangle.v0, triangle.v1, triangle.v2)) {
|
||||||
|
// it's not behind at least one so we bail
|
||||||
|
insideMesh = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
if (insideMesh) {
|
||||||
|
// It's inside this mesh, return true.
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
subMeshIndex++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// It wasn't in any mesh, return false.
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
// TODO: we seem to call this too often when things haven't actually changed... look into optimizing this
|
// TODO: we seem to call this too often when things haven't actually changed... look into optimizing this
|
||||||
void Model::recalculateMeshBoxes(bool pickAgainstTriangles) {
|
void Model::recalculateMeshBoxes(bool pickAgainstTriangles) {
|
||||||
bool calculatedMeshTrianglesNeeded = pickAgainstTriangles && !_calculatedMeshTrianglesValid;
|
bool calculatedMeshTrianglesNeeded = pickAgainstTriangles && !_calculatedMeshTrianglesValid;
|
||||||
|
@ -1047,7 +1102,7 @@ int Model::getLastFreeJointIndex(int jointIndex) const {
|
||||||
|
|
||||||
void Model::setURL(const QUrl& url, const QUrl& fallback, bool retainCurrent, bool delayLoad) {
|
void Model::setURL(const QUrl& url, const QUrl& fallback, bool retainCurrent, bool delayLoad) {
|
||||||
// don't recreate the geometry if it's the same URL
|
// don't recreate the geometry if it's the same URL
|
||||||
if (_url == url) {
|
if (_url == url && _geometry && _geometry->getURL() == url) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
_url = url;
|
_url = url;
|
||||||
|
|
|
@ -213,6 +213,7 @@ public:
|
||||||
|
|
||||||
bool findRayIntersectionAgainstSubMeshes(const glm::vec3& origin, const glm::vec3& direction, float& distance,
|
bool findRayIntersectionAgainstSubMeshes(const glm::vec3& origin, const glm::vec3& direction, float& distance,
|
||||||
BoxFace& face, QString& extraInfo, bool pickAgainstTriangles = false);
|
BoxFace& face, QString& extraInfo, bool pickAgainstTriangles = false);
|
||||||
|
bool convexHullContains(glm::vec3 point);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
QSharedPointer<NetworkGeometry> _geometry;
|
QSharedPointer<NetworkGeometry> _geometry;
|
||||||
|
|
|
@ -13,8 +13,12 @@
|
||||||
#include "ScriptAudioInjector.h"
|
#include "ScriptAudioInjector.h"
|
||||||
|
|
||||||
QScriptValue injectorToScriptValue(QScriptEngine* engine, ScriptAudioInjector* const& in) {
|
QScriptValue injectorToScriptValue(QScriptEngine* engine, ScriptAudioInjector* const& in) {
|
||||||
|
// The AudioScriptingInterface::playSound method can return null, so we need to account for that.
|
||||||
|
if (!in) {
|
||||||
|
return QScriptValue(QScriptValue::NullValue);
|
||||||
|
}
|
||||||
|
|
||||||
// when the script goes down we want to cleanup the injector
|
// when the script goes down we want to cleanup the injector
|
||||||
|
|
||||||
QObject::connect(engine, &QScriptEngine::destroyed, in, &ScriptAudioInjector::stopInjectorImmediately,
|
QObject::connect(engine, &QScriptEngine::destroyed, in, &ScriptAudioInjector::stopInjectorImmediately,
|
||||||
Qt::DirectConnection);
|
Qt::DirectConnection);
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue