mirror of
https://github.com/lubosz/overte.git
synced 2025-04-14 06:46:19 +02:00
merge upstream/master into andrew/isentropic
Conflicts: libraries/networking/src/PacketHeaders.cpp libraries/networking/src/PacketHeaders.h
This commit is contained in:
commit
49eee89c19
246 changed files with 3089 additions and 27921 deletions
7
BUILD.md
7
BUILD.md
|
@ -4,6 +4,7 @@
|
|||
* [Qt](http://qt-project.org/downloads) ~> 5.3.2
|
||||
* [OpenSSL](https://www.openssl.org/related/binaries.html) ~> 1.0.1g
|
||||
* IMPORTANT: OpenSSL 1.0.1g is critical to avoid a security vulnerability.
|
||||
* [VHACD](https://github.com/virneo/v-hacd)(clone this repository)(Optional)
|
||||
|
||||
####CMake External Project Dependencies
|
||||
|
||||
|
@ -13,12 +14,10 @@
|
|||
* [gverb](https://github.com/highfidelity/gverb)
|
||||
* [Soxr](http://sourceforge.net/projects/soxr/) ~> 0.1.1
|
||||
|
||||
The following external projects are optional dependencies. You can indicate to CMake that you would like to include them by passing -DGET_$NAME=1 when running a clean CMake build. For example, to get CMake to download and compile QXmpp you would pass -DGET_QXMPP=1.
|
||||
The following external projects are optional dependencies. You can indicate to CMake that you would like to include them by passing -DGET_$NAME=1 when running a clean CMake build. For example, to get CMake to download and compile SDL2 you would pass -DGET_SDL2=1.
|
||||
|
||||
* [SDL2](https://www.libsdl.org/download-2.0.php) ~> 2.0.3
|
||||
* Enables game controller support in Interface
|
||||
* [QXmpp](https://github.com/qxmpp-project/qxmpp) ~> 0.7.6
|
||||
* Enables text chat support in Interface
|
||||
|
||||
The above dependencies will be downloaded, built, linked and included automatically by CMake where we require them. The CMakeLists files that handle grabbing each of the following external dependencies can be found in the [cmake/externals folder](cmake/externals). The resulting downloads, source files and binaries will be placed in the `build-ext` directory in each of the subfolders for each external project.
|
||||
|
||||
|
@ -76,5 +75,5 @@ In the examples below the variable $NAME would be replaced by the name of the de
|
|||
|
||||
####Devices
|
||||
|
||||
You can support external input/output devices such as Oculus Rift, Leap Motion, Faceshift, PrioVR, MIDI, Razr Hydra and more by adding each individual SDK in the visible building path. Refer to the readme file available in each device folder in [interface/external/](interface/external) for the detailed explanation of the requirements to use the device.
|
||||
You can support external input/output devices such as Oculus Rift, Leap Motion, Faceshift, MIDI, Razr Hydra and more by adding each individual SDK in the visible building path. Refer to the readme file available in each device folder in [interface/external/](interface/external) for the detailed explanation of the requirements to use the device.
|
||||
|
||||
|
|
23
BUILD_WIN.md
23
BUILD_WIN.md
|
@ -14,18 +14,14 @@ Or you can start a regular command prompt and then run:
|
|||
|
||||
If using Visual Studio 2013 and building as a Visual Studio 2013 project you need the Windows 8 SDK which you should already have as part of installing Visual Studio 2013. You should be able to see it at `C:\Program Files (x86)\Windows Kits\8.1\Lib\winv6.3\um\x86`.
|
||||
|
||||
####nmake & msbuild
|
||||
####nmake
|
||||
|
||||
Some of the external projects may require nmake and msbuild to compile and install. If they are not installed at the locations listed below, please ensure that both are in your PATH so CMake can find them when required.
|
||||
Some of the external projects may require nmake to compile and install. If it is not installed at the location listed below, please ensure that it is in your PATH so CMake can find it when required.
|
||||
|
||||
We expect nmake.exe to be located at the following path.
|
||||
|
||||
C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\bin
|
||||
|
||||
We expect msbuild.exe to be located at the following path.
|
||||
|
||||
C:\Program Files (x86)\MSBUILD\12.0\Bin
|
||||
|
||||
###Qt
|
||||
You can use the online installer or the offline installer. If you use the offline installer, be sure to select the "OpenGL" version.
|
||||
|
||||
|
@ -79,6 +75,21 @@ To prevent these problems, install OpenSSL yourself. Download the following bina
|
|||
|
||||
Install OpenSSL into the Windows system directory, to make sure that Qt uses the version that you've just installed, and not some other version.
|
||||
|
||||
###vhacd
|
||||
Download it directly from https://github.com/virneo/v-hacd
|
||||
|
||||
To build it run the following commands
|
||||
1. cd src\
|
||||
2. mkdir build
|
||||
3. cd build
|
||||
4. cmake ..
|
||||
|
||||
Build using visual studio 2013. Build ALL_BUILD and INSTALL targets both in Release and Debug.
|
||||
|
||||
This will create an output folder with include and lib directory inside it.
|
||||
|
||||
Either copy the contents of output folder to ENV %HIFI_LIB_DIR%/vhacd or create an environment variable VHACD_ROOT_DIR to this output directory.
|
||||
|
||||
###Build High Fidelity using Visual Studio
|
||||
Follow the same build steps from the CMake section of [BUILD.md](BUILD.md), but pass a different generator to CMake.
|
||||
|
||||
|
|
|
@ -164,7 +164,6 @@ if (WIN32)
|
|||
endif ()
|
||||
|
||||
option(GET_SDL2 "Get SDL2 library automatically as external project" 0)
|
||||
option(GET_QXMPP "GET Qxmpp library automatically as external project" 0)
|
||||
|
||||
if (WIN32)
|
||||
add_paths_to_fixup_libs("${QT_DIR}/bin")
|
||||
|
|
|
@ -8,7 +8,7 @@ target_include_directories(${TARGET_NAME} PRIVATE ${GLM_INCLUDE_DIRS})
|
|||
|
||||
# link in the shared libraries
|
||||
link_hifi_libraries(
|
||||
audio avatars octree environment gpu model fbx entities metavoxels
|
||||
audio avatars octree environment gpu model fbx entities
|
||||
networking animation shared script-engine embedded-webserver
|
||||
physics
|
||||
)
|
||||
|
|
|
@ -44,7 +44,7 @@ Agent::Agent(const QByteArray& packet) :
|
|||
// be the parent of the script engine so it gets moved when we do
|
||||
_scriptEngine.setParent(this);
|
||||
|
||||
_scriptEngine.getEntityScriptingInterface()->setPacketSender(&_entityEditSender);
|
||||
DependencyManager::get<EntityScriptingInterface>()->setPacketSender(&_entityEditSender);
|
||||
|
||||
DependencyManager::set<ResouceCacheSharedItems>();
|
||||
DependencyManager::set<SoundCache>();
|
||||
|
@ -68,8 +68,8 @@ void Agent::readPendingDatagrams() {
|
|||
// PacketType_JURISDICTION, first byte is the node type...
|
||||
switch (receivedPacket[headerBytes]) {
|
||||
case NodeType::EntityServer:
|
||||
_scriptEngine.getEntityScriptingInterface()->getJurisdictionListener()->
|
||||
queueReceivedPacket(matchedNode, receivedPacket);
|
||||
DependencyManager::get<EntityScriptingInterface>()->getJurisdictionListener()->
|
||||
queueReceivedPacket(matchedNode, receivedPacket);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -211,10 +211,12 @@ void Agent::run() {
|
|||
|
||||
_scriptEngine.registerGlobalObject("SoundCache", DependencyManager::get<SoundCache>().data());
|
||||
|
||||
auto entityScriptingInterface = DependencyManager::get<EntityScriptingInterface>();
|
||||
|
||||
_scriptEngine.registerGlobalObject("EntityViewer", &_entityViewer);
|
||||
_entityViewer.setJurisdictionListener(_scriptEngine.getEntityScriptingInterface()->getJurisdictionListener());
|
||||
_entityViewer.setJurisdictionListener(entityScriptingInterface->getJurisdictionListener());
|
||||
_entityViewer.init();
|
||||
_scriptEngine.getEntityScriptingInterface()->setEntityTree(_entityViewer.getTree());
|
||||
entityScriptingInterface->setEntityTree(_entityViewer.getTree());
|
||||
|
||||
_scriptEngine.setScriptContents(scriptContents);
|
||||
_scriptEngine.run();
|
||||
|
|
|
@ -18,10 +18,10 @@
|
|||
#include <AccountManager.h>
|
||||
#include <AddressManager.h>
|
||||
#include <Assignment.h>
|
||||
#include <AvatarHashMap.h>
|
||||
#include <HifiConfigVariantMap.h>
|
||||
#include <EntityScriptingInterface.h>
|
||||
#include <LogHandler.h>
|
||||
#include <LogUtils.h>
|
||||
#include <LimitedNodeList.h>
|
||||
#include <NodeList.h>
|
||||
#include <PacketHeaders.h>
|
||||
#include <SharedUtil.h>
|
||||
|
@ -40,79 +40,44 @@ SharedAssignmentPointer AssignmentClient::_currentAssignment;
|
|||
|
||||
int hifiSockAddrMeta = qRegisterMetaType<HifiSockAddr>("HifiSockAddr");
|
||||
|
||||
AssignmentClient::AssignmentClient(int &argc, char **argv) :
|
||||
QCoreApplication(argc, argv),
|
||||
AssignmentClient::AssignmentClient(Assignment::Type requestAssignmentType, QString assignmentPool, QUuid walletUUID,
|
||||
QString assignmentServerHostname, quint16 assignmentServerPort) :
|
||||
_assignmentServerHostname(DEFAULT_ASSIGNMENT_SERVER_HOSTNAME),
|
||||
_localASPortSharedMem(NULL)
|
||||
_localASPortSharedMem(NULL),
|
||||
_localACMPortSharedMem(NULL)
|
||||
{
|
||||
LogUtils::init();
|
||||
|
||||
setOrganizationName("High Fidelity");
|
||||
setOrganizationDomain("highfidelity.io");
|
||||
setApplicationName("assignment-client");
|
||||
QSettings::setDefaultFormat(QSettings::IniFormat);
|
||||
|
||||
// create a NodeList as an unassigned client
|
||||
DependencyManager::registerInheritance<LimitedNodeList, NodeList>();
|
||||
auto addressManager = DependencyManager::set<AddressManager>();
|
||||
auto nodeList = DependencyManager::set<NodeList>(NodeType::Unassigned);
|
||||
auto avatarHashMap = DependencyManager::set<AvatarHashMap>();
|
||||
|
||||
// setup a shutdown event listener to handle SIGTERM or WM_CLOSE for us
|
||||
#ifdef _WIN32
|
||||
installNativeEventFilter(&ShutdownEventListener::getInstance());
|
||||
#else
|
||||
ShutdownEventListener::getInstance();
|
||||
#endif
|
||||
auto entityScriptingInterface = DependencyManager::set<EntityScriptingInterface>();
|
||||
|
||||
// make up a uuid for this child so the parent can tell us apart. This id will be changed
|
||||
// when the domain server hands over an assignment.
|
||||
QUuid nodeUUID = QUuid::createUuid();
|
||||
nodeList->setSessionUUID(nodeUUID);
|
||||
|
||||
// set the logging target to the the CHILD_TARGET_NAME
|
||||
LogHandler::getInstance().setTargetName(ASSIGNMENT_CLIENT_TARGET_NAME);
|
||||
|
||||
const QVariantMap argumentVariantMap = HifiConfigVariantMap::mergeCLParametersWithJSONConfig(arguments());
|
||||
|
||||
const QString ASSIGNMENT_TYPE_OVERRIDE_OPTION = "t";
|
||||
const QString ASSIGNMENT_POOL_OPTION = "pool";
|
||||
const QString ASSIGNMENT_WALLET_DESTINATION_ID_OPTION = "wallet";
|
||||
const QString CUSTOM_ASSIGNMENT_SERVER_HOSTNAME_OPTION = "a";
|
||||
const QString CUSTOM_ASSIGNMENT_SERVER_PORT_OPTION = "p";
|
||||
|
||||
Assignment::Type requestAssignmentType = Assignment::AllTypes;
|
||||
|
||||
// check for an assignment type passed on the command line or in the config
|
||||
if (argumentVariantMap.contains(ASSIGNMENT_TYPE_OVERRIDE_OPTION)) {
|
||||
requestAssignmentType = (Assignment::Type) argumentVariantMap.value(ASSIGNMENT_TYPE_OVERRIDE_OPTION).toInt();
|
||||
}
|
||||
|
||||
QString assignmentPool;
|
||||
|
||||
// check for an assignment pool passed on the command line or in the config
|
||||
if (argumentVariantMap.contains(ASSIGNMENT_POOL_OPTION)) {
|
||||
assignmentPool = argumentVariantMap.value(ASSIGNMENT_POOL_OPTION).toString();
|
||||
}
|
||||
|
||||
// setup our _requestAssignment member variable from the passed arguments
|
||||
_requestAssignment = Assignment(Assignment::RequestCommand, requestAssignmentType, assignmentPool);
|
||||
|
||||
// check for a wallet UUID on the command line or in the config
|
||||
// this would represent where the user running AC wants funds sent to
|
||||
if (argumentVariantMap.contains(ASSIGNMENT_WALLET_DESTINATION_ID_OPTION)) {
|
||||
QUuid walletUUID = argumentVariantMap.value(ASSIGNMENT_WALLET_DESTINATION_ID_OPTION).toString();
|
||||
if (!walletUUID.isNull()) {
|
||||
qDebug() << "The destination wallet UUID for credits is" << uuidStringWithoutCurlyBraces(walletUUID);
|
||||
_requestAssignment.setWalletUUID(walletUUID);
|
||||
}
|
||||
|
||||
quint16 assignmentServerPort = DEFAULT_DOMAIN_SERVER_PORT;
|
||||
|
||||
// check for an overriden assignment server hostname
|
||||
if (argumentVariantMap.contains(CUSTOM_ASSIGNMENT_SERVER_HOSTNAME_OPTION)) {
|
||||
if (assignmentServerHostname != "") {
|
||||
// change the hostname for our assignment server
|
||||
_assignmentServerHostname = argumentVariantMap.value(CUSTOM_ASSIGNMENT_SERVER_HOSTNAME_OPTION).toString();
|
||||
}
|
||||
|
||||
// check for an overriden assignment server port
|
||||
if (argumentVariantMap.contains(CUSTOM_ASSIGNMENT_SERVER_PORT_OPTION)) {
|
||||
assignmentServerPort =
|
||||
argumentVariantMap.value(CUSTOM_ASSIGNMENT_SERVER_PORT_OPTION).toString().toUInt();
|
||||
_assignmentServerHostname = assignmentServerHostname;
|
||||
}
|
||||
|
||||
_assignmentServerSocket = HifiSockAddr(_assignmentServerHostname, assignmentServerPort, true);
|
||||
|
@ -123,9 +88,12 @@ AssignmentClient::AssignmentClient(int &argc, char **argv) :
|
|||
// call a timer function every ASSIGNMENT_REQUEST_INTERVAL_MSECS to ask for assignment, if required
|
||||
qDebug() << "Waiting for assignment -" << _requestAssignment;
|
||||
|
||||
QTimer* timer = new QTimer(this);
|
||||
connect(timer, SIGNAL(timeout()), SLOT(sendAssignmentRequest()));
|
||||
timer->start(ASSIGNMENT_REQUEST_INTERVAL_MSECS);
|
||||
if (_assignmentServerHostname != "localhost") {
|
||||
qDebug () << "- will attempt to connect to domain-server on" << _assignmentServerSocket.getPort();
|
||||
}
|
||||
|
||||
connect(&_requestTimer, SIGNAL(timeout()), SLOT(sendAssignmentRequest()));
|
||||
_requestTimer.start(ASSIGNMENT_REQUEST_INTERVAL_MSECS);
|
||||
|
||||
// connect our readPendingDatagrams method to the readyRead() signal of the socket
|
||||
connect(&nodeList->getNodeSocket(), &QUdpSocket::readyRead, this, &AssignmentClient::readPendingDatagrams);
|
||||
|
@ -136,6 +104,45 @@ AssignmentClient::AssignmentClient(int &argc, char **argv) :
|
|||
|
||||
// Create Singleton objects on main thread
|
||||
NetworkAccessManager::getInstance();
|
||||
|
||||
// Hook up a timer to send this child's status to the Monitor once per second
|
||||
setUpStatsToMonitor();
|
||||
}
|
||||
|
||||
|
||||
void AssignmentClient::stopAssignmentClient() {
|
||||
qDebug() << "Exiting.";
|
||||
_requestTimer.stop();
|
||||
_statsTimerACM.stop();
|
||||
QCoreApplication::quit();
|
||||
}
|
||||
|
||||
|
||||
void AssignmentClient::setUpStatsToMonitor() {
|
||||
// Figure out the address to send out stats to
|
||||
quint16 localMonitorServerPort = DEFAULT_ASSIGNMENT_CLIENT_MONITOR_PORT;
|
||||
auto nodeList = DependencyManager::get<NodeList>();
|
||||
|
||||
nodeList->getLocalServerPortFromSharedMemory(ASSIGNMENT_CLIENT_MONITOR_LOCAL_PORT_SMEM_KEY,
|
||||
_localACMPortSharedMem, localMonitorServerPort);
|
||||
_assignmentClientMonitorSocket = HifiSockAddr(DEFAULT_ASSIGNMENT_CLIENT_MONITOR_HOSTNAME, localMonitorServerPort, true);
|
||||
|
||||
// send a stats packet every 1 seconds
|
||||
connect(&_statsTimerACM, &QTimer::timeout, this, &AssignmentClient::sendStatsPacketToACM);
|
||||
_statsTimerACM.start(1000);
|
||||
}
|
||||
|
||||
void AssignmentClient::sendStatsPacketToACM() {
|
||||
// tell the assignment client monitor what this assignment client is doing (if anything)
|
||||
QJsonObject statsObject;
|
||||
auto nodeList = DependencyManager::get<NodeList>();
|
||||
|
||||
if (_currentAssignment) {
|
||||
statsObject["assignment_type"] = _currentAssignment->getTypeName();
|
||||
} else {
|
||||
statsObject["assignment_type"] = "none";
|
||||
}
|
||||
nodeList->sendStats(statsObject, _assignmentClientMonitorSocket);
|
||||
}
|
||||
|
||||
void AssignmentClient::sendAssignmentRequest() {
|
||||
|
@ -145,23 +152,9 @@ void AssignmentClient::sendAssignmentRequest() {
|
|||
|
||||
if (_assignmentServerHostname == "localhost") {
|
||||
// we want to check again for the local domain-server port in case the DS has restarted
|
||||
if (!_localASPortSharedMem) {
|
||||
_localASPortSharedMem = new QSharedMemory(DOMAIN_SERVER_LOCAL_PORT_SMEM_KEY, this);
|
||||
|
||||
if (!_localASPortSharedMem->attach(QSharedMemory::ReadOnly)) {
|
||||
qWarning() << "Could not attach to shared memory at key" << DOMAIN_SERVER_LOCAL_PORT_SMEM_KEY
|
||||
<< "- will attempt to connect to domain-server on" << _assignmentServerSocket.getPort();
|
||||
}
|
||||
}
|
||||
|
||||
if (_localASPortSharedMem->isAttached()) {
|
||||
_localASPortSharedMem->lock();
|
||||
|
||||
quint16 localAssignmentServerPort;
|
||||
memcpy(&localAssignmentServerPort, _localASPortSharedMem->data(), sizeof(localAssignmentServerPort));
|
||||
|
||||
_localASPortSharedMem->unlock();
|
||||
|
||||
quint16 localAssignmentServerPort;
|
||||
if (nodeList->getLocalServerPortFromSharedMemory(DOMAIN_SERVER_LOCAL_PORT_SMEM_KEY, _localASPortSharedMem,
|
||||
localAssignmentServerPort)) {
|
||||
if (localAssignmentServerPort != _assignmentServerSocket.getPort()) {
|
||||
qDebug() << "Port for local assignment server read from shared memory is"
|
||||
<< localAssignmentServerPort;
|
||||
|
@ -170,7 +163,6 @@ void AssignmentClient::sendAssignmentRequest() {
|
|||
nodeList->setAssignmentServerSocket(_assignmentServerSocket);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
nodeList->sendAssignment(_requestAssignment);
|
||||
|
@ -227,6 +219,14 @@ void AssignmentClient::readPendingDatagrams() {
|
|||
} else {
|
||||
qDebug() << "Received an assignment that could not be unpacked. Re-requesting.";
|
||||
}
|
||||
} else if (packetTypeForPacket(receivedPacket) == PacketTypeStopNode) {
|
||||
if (senderSockAddr.getAddress() == QHostAddress::LocalHost ||
|
||||
senderSockAddr.getAddress() == QHostAddress::LocalHostIPv6) {
|
||||
qDebug() << "Network told me to exit.";
|
||||
emit stopAssignmentClient();
|
||||
} else {
|
||||
qDebug() << "Got a stop packet from other than localhost.";
|
||||
}
|
||||
} else {
|
||||
// have the NodeList attempt to handle it
|
||||
nodeList->processNodeData(senderSockAddr, receivedPacket);
|
||||
|
|
|
@ -18,10 +18,12 @@
|
|||
|
||||
class QSharedMemory;
|
||||
|
||||
class AssignmentClient : public QCoreApplication {
|
||||
class AssignmentClient : public QObject {
|
||||
Q_OBJECT
|
||||
public:
|
||||
AssignmentClient(int &argc, char **argv);
|
||||
|
||||
AssignmentClient(Assignment::Type requestAssignmentType, QString assignmentPool,
|
||||
QUuid walletUUID, QString assignmentServerHostname, quint16 assignmentServerPort);
|
||||
static const SharedAssignmentPointer& getCurrentAssignment() { return _currentAssignment; }
|
||||
|
||||
private slots:
|
||||
|
@ -29,13 +31,22 @@ private slots:
|
|||
void readPendingDatagrams();
|
||||
void assignmentCompleted();
|
||||
void handleAuthenticationRequest();
|
||||
void sendStatsPacketToACM();
|
||||
void stopAssignmentClient();
|
||||
|
||||
private:
|
||||
void setUpStatsToMonitor();
|
||||
Assignment _requestAssignment;
|
||||
static SharedAssignmentPointer _currentAssignment;
|
||||
QString _assignmentServerHostname;
|
||||
HifiSockAddr _assignmentServerSocket;
|
||||
QSharedMemory* _localASPortSharedMem;
|
||||
QSharedMemory* _localASPortSharedMem; // memory shared with domain server
|
||||
QSharedMemory* _localACMPortSharedMem; // memory shared with assignment client monitor
|
||||
QTimer _requestTimer; // timer for requesting and assignment
|
||||
QTimer _statsTimerACM; // timer for sending stats to assignment client monitor
|
||||
|
||||
protected:
|
||||
HifiSockAddr _assignmentClientMonitorSocket;
|
||||
};
|
||||
|
||||
#endif // hifi_AssignmentClient_h
|
||||
|
|
185
assignment-client/src/AssignmentClientApp.cpp
Normal file
185
assignment-client/src/AssignmentClientApp.cpp
Normal file
|
@ -0,0 +1,185 @@
|
|||
//
|
||||
// AssignmentClientapp.cpp
|
||||
// assignment-client/src
|
||||
//
|
||||
// Created by Seth Alves on 2/19/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
|
||||
//
|
||||
|
||||
#include <QCommandLineParser>
|
||||
|
||||
#include <LogHandler.h>
|
||||
#include <SharedUtil.h>
|
||||
#include <HifiConfigVariantMap.h>
|
||||
#include <ShutdownEventListener.h>
|
||||
|
||||
#include "Assignment.h"
|
||||
#include "AssignmentClient.h"
|
||||
#include "AssignmentClientMonitor.h"
|
||||
#include "AssignmentClientApp.h"
|
||||
|
||||
|
||||
AssignmentClientApp::AssignmentClientApp(int argc, char* argv[]) :
|
||||
QCoreApplication(argc, argv)
|
||||
{
|
||||
# ifndef WIN32
|
||||
setvbuf(stdout, NULL, _IOLBF, 0);
|
||||
# endif
|
||||
|
||||
// setup a shutdown event listener to handle SIGTERM or WM_CLOSE for us
|
||||
# ifdef _WIN32
|
||||
installNativeEventFilter(&ShutdownEventListener::getInstance());
|
||||
# else
|
||||
ShutdownEventListener::getInstance();
|
||||
# endif
|
||||
|
||||
setOrganizationName("High Fidelity");
|
||||
setOrganizationDomain("highfidelity.io");
|
||||
setApplicationName("assignment-client");
|
||||
|
||||
// use the verbose message handler in Logging
|
||||
qInstallMessageHandler(LogHandler::verboseMessageHandler);
|
||||
|
||||
// parse command-line
|
||||
QCommandLineParser parser;
|
||||
parser.setApplicationDescription("High Fidelity Assignment Client");
|
||||
parser.addHelpOption();
|
||||
|
||||
const QCommandLineOption helpOption = parser.addHelpOption();
|
||||
|
||||
const QCommandLineOption clientTypeOption(ASSIGNMENT_TYPE_OVERRIDE_OPTION,
|
||||
"run single assignment client of given type", "type");
|
||||
parser.addOption(clientTypeOption);
|
||||
|
||||
const QCommandLineOption poolOption(ASSIGNMENT_POOL_OPTION, "set assignment pool", "pool-name");
|
||||
parser.addOption(poolOption);
|
||||
|
||||
const QCommandLineOption walletDestinationOption(ASSIGNMENT_WALLET_DESTINATION_ID_OPTION,
|
||||
"set wallet destination", "wallet-uuid");
|
||||
parser.addOption(walletDestinationOption);
|
||||
|
||||
const QCommandLineOption assignmentServerHostnameOption(CUSTOM_ASSIGNMENT_SERVER_HOSTNAME_OPTION,
|
||||
"set assignment-server hostname", "hostname");
|
||||
parser.addOption(assignmentServerHostnameOption);
|
||||
|
||||
const QCommandLineOption assignmentServerPortOption(CUSTOM_ASSIGNMENT_SERVER_PORT_OPTION,
|
||||
"set assignment-server port", "port");
|
||||
parser.addOption(assignmentServerPortOption);
|
||||
|
||||
const QCommandLineOption numChildsOption(ASSIGNMENT_NUM_FORKS_OPTION, "number of children to fork", "child-count");
|
||||
parser.addOption(numChildsOption);
|
||||
|
||||
const QCommandLineOption minChildsOption(ASSIGNMENT_MIN_FORKS_OPTION, "minimum number of children", "child-count");
|
||||
parser.addOption(minChildsOption);
|
||||
|
||||
const QCommandLineOption maxChildsOption(ASSIGNMENT_MAX_FORKS_OPTION, "maximum number of children", "child-count");
|
||||
parser.addOption(maxChildsOption);
|
||||
|
||||
|
||||
if (!parser.parse(QCoreApplication::arguments())) {
|
||||
qCritical() << parser.errorText() << endl;
|
||||
parser.showHelp();
|
||||
Q_UNREACHABLE();
|
||||
}
|
||||
|
||||
if (parser.isSet(helpOption)) {
|
||||
parser.showHelp();
|
||||
Q_UNREACHABLE();
|
||||
}
|
||||
|
||||
|
||||
const QVariantMap argumentVariantMap = HifiConfigVariantMap::mergeCLParametersWithJSONConfig(arguments());
|
||||
|
||||
|
||||
unsigned int numForks = 0;
|
||||
if (parser.isSet(numChildsOption)) {
|
||||
numForks = parser.value(numChildsOption).toInt();
|
||||
}
|
||||
|
||||
unsigned int minForks = 0;
|
||||
if (parser.isSet(minChildsOption)) {
|
||||
minForks = parser.value(minChildsOption).toInt();
|
||||
}
|
||||
|
||||
unsigned int maxForks = 0;
|
||||
if (parser.isSet(maxChildsOption)) {
|
||||
maxForks = parser.value(maxChildsOption).toInt();
|
||||
}
|
||||
|
||||
if (!numForks && minForks) {
|
||||
// if the user specified --min but not -n, set -n to --min
|
||||
numForks = minForks;
|
||||
}
|
||||
|
||||
Assignment::Type requestAssignmentType = Assignment::AllTypes;
|
||||
if (argumentVariantMap.contains(ASSIGNMENT_TYPE_OVERRIDE_OPTION)) {
|
||||
requestAssignmentType = (Assignment::Type) argumentVariantMap.value(ASSIGNMENT_TYPE_OVERRIDE_OPTION).toInt();
|
||||
}
|
||||
if (parser.isSet(clientTypeOption)) {
|
||||
requestAssignmentType = (Assignment::Type) parser.value(clientTypeOption).toInt();
|
||||
}
|
||||
|
||||
QString assignmentPool;
|
||||
// check for an assignment pool passed on the command line or in the config
|
||||
if (argumentVariantMap.contains(ASSIGNMENT_POOL_OPTION)) {
|
||||
assignmentPool = argumentVariantMap.value(ASSIGNMENT_POOL_OPTION).toString();
|
||||
}
|
||||
if (parser.isSet(poolOption)) {
|
||||
assignmentPool = parser.value(poolOption);
|
||||
}
|
||||
|
||||
|
||||
QUuid walletUUID;
|
||||
if (argumentVariantMap.contains(ASSIGNMENT_WALLET_DESTINATION_ID_OPTION)) {
|
||||
walletUUID = argumentVariantMap.value(ASSIGNMENT_WALLET_DESTINATION_ID_OPTION).toString();
|
||||
}
|
||||
if (parser.isSet(walletDestinationOption)) {
|
||||
walletUUID = parser.value(walletDestinationOption);
|
||||
}
|
||||
|
||||
QString assignmentServerHostname;
|
||||
if (argumentVariantMap.contains(ASSIGNMENT_WALLET_DESTINATION_ID_OPTION)) {
|
||||
assignmentServerHostname = argumentVariantMap.value(CUSTOM_ASSIGNMENT_SERVER_HOSTNAME_OPTION).toString();
|
||||
}
|
||||
if (parser.isSet(assignmentServerHostnameOption)) {
|
||||
assignmentServerHostname = parser.value(assignmentServerHostnameOption);
|
||||
}
|
||||
|
||||
// check for an overriden assignment server port
|
||||
quint16 assignmentServerPort = DEFAULT_DOMAIN_SERVER_PORT;
|
||||
if (argumentVariantMap.contains(ASSIGNMENT_WALLET_DESTINATION_ID_OPTION)) {
|
||||
assignmentServerPort = argumentVariantMap.value(CUSTOM_ASSIGNMENT_SERVER_PORT_OPTION).toString().toUInt();
|
||||
}
|
||||
if (parser.isSet(assignmentServerPortOption)) {
|
||||
assignmentServerPort = parser.value(assignmentServerPortOption).toInt();
|
||||
}
|
||||
|
||||
|
||||
|
||||
if (parser.isSet(numChildsOption)) {
|
||||
if (minForks && minForks > numForks) {
|
||||
qCritical() << "--min can't be more than -n";
|
||||
parser.showHelp();
|
||||
Q_UNREACHABLE();
|
||||
}
|
||||
if (maxForks && maxForks < numForks) {
|
||||
qCritical() << "--max can't be less than -n";
|
||||
parser.showHelp();
|
||||
Q_UNREACHABLE();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (numForks || minForks || maxForks) {
|
||||
AssignmentClientMonitor monitor(numForks, minForks, maxForks, assignmentPool,
|
||||
walletUUID, assignmentServerHostname, assignmentServerPort);
|
||||
exec();
|
||||
} else {
|
||||
AssignmentClient client(requestAssignmentType, assignmentPool,
|
||||
walletUUID, assignmentServerHostname, assignmentServerPort);
|
||||
exec();
|
||||
}
|
||||
}
|
34
assignment-client/src/AssignmentClientApp.h
Normal file
34
assignment-client/src/AssignmentClientApp.h
Normal file
|
@ -0,0 +1,34 @@
|
|||
//
|
||||
// AssignmentClientapp.h
|
||||
// assignment-client/src
|
||||
//
|
||||
// Created by Seth Alves on 2/19/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
|
||||
//
|
||||
|
||||
#ifndef hifi_AssignmentClientApp_h
|
||||
#define hifi_AssignmentClientApp_h
|
||||
|
||||
|
||||
#include <QApplication>
|
||||
|
||||
const QString ASSIGNMENT_TYPE_OVERRIDE_OPTION = "t";
|
||||
const QString ASSIGNMENT_POOL_OPTION = "pool";
|
||||
const QString ASSIGNMENT_WALLET_DESTINATION_ID_OPTION = "wallet";
|
||||
const QString CUSTOM_ASSIGNMENT_SERVER_HOSTNAME_OPTION = "a";
|
||||
const QString CUSTOM_ASSIGNMENT_SERVER_PORT_OPTION = "p";
|
||||
const QString ASSIGNMENT_NUM_FORKS_OPTION = "n";
|
||||
const QString ASSIGNMENT_MIN_FORKS_OPTION = "min";
|
||||
const QString ASSIGNMENT_MAX_FORKS_OPTION = "max";
|
||||
|
||||
|
||||
class AssignmentClientApp : public QCoreApplication {
|
||||
Q_OBJECT
|
||||
public:
|
||||
AssignmentClientApp(int argc, char* argv[]);
|
||||
};
|
||||
|
||||
#endif // hifi_AssignmentClientApp_h
|
8
assignment-client/src/AssignmentClientChildData.cpp
Normal file
8
assignment-client/src/AssignmentClientChildData.cpp
Normal file
|
@ -0,0 +1,8 @@
|
|||
|
||||
#include "AssignmentClientChildData.h"
|
||||
|
||||
|
||||
AssignmentClientChildData::AssignmentClientChildData(QString childType) :
|
||||
_childType(childType)
|
||||
{
|
||||
}
|
32
assignment-client/src/AssignmentClientChildData.h
Normal file
32
assignment-client/src/AssignmentClientChildData.h
Normal file
|
@ -0,0 +1,32 @@
|
|||
//
|
||||
// AssignmentClientChildData.h
|
||||
// assignment-client/src
|
||||
//
|
||||
// Created by Seth Alves on 2/23/2015.
|
||||
// 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
|
||||
//
|
||||
|
||||
#ifndef hifi_AssignmentClientChildData_h
|
||||
#define hifi_AssignmentClientChildData_h
|
||||
|
||||
#include <Assignment.h>
|
||||
|
||||
|
||||
class AssignmentClientChildData : public NodeData {
|
||||
public:
|
||||
AssignmentClientChildData(QString childType);
|
||||
|
||||
QString getChildType() { return _childType; }
|
||||
void setChildType(QString childType) { _childType = childType; }
|
||||
|
||||
// implement parseData to return 0 so we can be a subclass of NodeData
|
||||
int parseData(const QByteArray& packet) { return 0; }
|
||||
|
||||
private:
|
||||
QString _childType;
|
||||
};
|
||||
|
||||
#endif // hifi_AssignmentClientChildData_h
|
|
@ -12,40 +12,52 @@
|
|||
#include <signal.h>
|
||||
|
||||
#include <LogHandler.h>
|
||||
#include <ShutdownEventListener.h>
|
||||
#include <AddressManager.h>
|
||||
|
||||
#include "AssignmentClientMonitor.h"
|
||||
#include "AssignmentClientApp.h"
|
||||
#include "AssignmentClientChildData.h"
|
||||
#include "PacketHeaders.h"
|
||||
#include "SharedUtil.h"
|
||||
|
||||
const char* NUM_FORKS_PARAMETER = "-n";
|
||||
|
||||
const QString ASSIGNMENT_CLIENT_MONITOR_TARGET_NAME = "assignment-client-monitor";
|
||||
|
||||
AssignmentClientMonitor::AssignmentClientMonitor(int &argc, char **argv, int numAssignmentClientForks) :
|
||||
QCoreApplication(argc, argv)
|
||||
AssignmentClientMonitor::AssignmentClientMonitor(const unsigned int numAssignmentClientForks,
|
||||
const unsigned int minAssignmentClientForks,
|
||||
const unsigned int maxAssignmentClientForks,
|
||||
QString assignmentPool, QUuid walletUUID, QString assignmentServerHostname,
|
||||
quint16 assignmentServerPort) :
|
||||
_numAssignmentClientForks(numAssignmentClientForks),
|
||||
_minAssignmentClientForks(minAssignmentClientForks),
|
||||
_maxAssignmentClientForks(maxAssignmentClientForks),
|
||||
_assignmentPool(assignmentPool),
|
||||
_walletUUID(walletUUID),
|
||||
_assignmentServerHostname(assignmentServerHostname),
|
||||
_assignmentServerPort(assignmentServerPort)
|
||||
{
|
||||
// start the Logging class with the parent's target name
|
||||
LogHandler::getInstance().setTargetName(ASSIGNMENT_CLIENT_MONITOR_TARGET_NAME);
|
||||
|
||||
// setup a shutdown event listener to handle SIGTERM or WM_CLOSE for us
|
||||
#ifdef _WIN32
|
||||
installNativeEventFilter(&ShutdownEventListener::getInstance());
|
||||
#else
|
||||
ShutdownEventListener::getInstance();
|
||||
#endif
|
||||
|
||||
_childArguments = arguments();
|
||||
|
||||
// remove the parameter for the number of forks so it isn't passed to the child forked processes
|
||||
int forksParameterIndex = _childArguments.indexOf(NUM_FORKS_PARAMETER);
|
||||
|
||||
// this removes both the "-n" parameter and the number of forks passed
|
||||
_childArguments.removeAt(forksParameterIndex);
|
||||
_childArguments.removeAt(forksParameterIndex);
|
||||
|
||||
// create a NodeList so we can receive stats from children
|
||||
DependencyManager::registerInheritance<LimitedNodeList, NodeList>();
|
||||
auto addressManager = DependencyManager::set<AddressManager>();
|
||||
auto nodeList = DependencyManager::set<LimitedNodeList>(DEFAULT_ASSIGNMENT_CLIENT_MONITOR_PORT);
|
||||
|
||||
connect(&nodeList->getNodeSocket(), &QUdpSocket::readyRead, this, &AssignmentClientMonitor::readPendingDatagrams);
|
||||
|
||||
nodeList->putLocalPortIntoSharedMemory(ASSIGNMENT_CLIENT_MONITOR_LOCAL_PORT_SMEM_KEY, this,
|
||||
nodeList->getNodeSocket().localPort());
|
||||
|
||||
// use QProcess to fork off a process for each of the child assignment clients
|
||||
for (int i = 0; i < numAssignmentClientForks; i++) {
|
||||
for (unsigned int i = 0; i < _numAssignmentClientForks; i++) {
|
||||
spawnChildClient();
|
||||
}
|
||||
|
||||
connect(&_checkSparesTimer, &QTimer::timeout, this, &AssignmentClientMonitor::checkSpares);
|
||||
|
||||
_checkSparesTimer.start(NODE_SILENCE_THRESHOLD_MSECS * 3);
|
||||
}
|
||||
|
||||
AssignmentClientMonitor::~AssignmentClientMonitor() {
|
||||
|
@ -53,46 +65,145 @@ AssignmentClientMonitor::~AssignmentClientMonitor() {
|
|||
}
|
||||
|
||||
void AssignmentClientMonitor::stopChildProcesses() {
|
||||
|
||||
QList<QPointer<QProcess> >::Iterator it = _childProcesses.begin();
|
||||
while (it != _childProcesses.end()) {
|
||||
if (!it->isNull()) {
|
||||
qDebug() << "Monitor is terminating child process" << it->data();
|
||||
|
||||
// don't re-spawn this child when it goes down
|
||||
disconnect(it->data(), 0, this, 0);
|
||||
|
||||
it->data()->terminate();
|
||||
it->data()->waitForFinished();
|
||||
}
|
||||
|
||||
it = _childProcesses.erase(it);
|
||||
}
|
||||
auto nodeList = DependencyManager::get<NodeList>();
|
||||
|
||||
nodeList->eachNode([&](const SharedNodePointer& node) {
|
||||
qDebug() << "asking child" << node->getUUID() << "to exit.";
|
||||
node->activateLocalSocket();
|
||||
QByteArray diePacket = byteArrayWithPopulatedHeader(PacketTypeStopNode);
|
||||
nodeList->writeUnverifiedDatagram(diePacket, *node->getActiveSocket());
|
||||
});
|
||||
}
|
||||
|
||||
void AssignmentClientMonitor::spawnChildClient() {
|
||||
QProcess *assignmentClient = new QProcess(this);
|
||||
|
||||
_childProcesses.append(QPointer<QProcess>(assignmentClient));
|
||||
|
||||
|
||||
// unparse the parts of the command-line that the child cares about
|
||||
QStringList _childArguments;
|
||||
if (_assignmentPool != "") {
|
||||
_childArguments.append("--" + ASSIGNMENT_POOL_OPTION);
|
||||
_childArguments.append(_assignmentPool);
|
||||
}
|
||||
if (!_walletUUID.isNull()) {
|
||||
_childArguments.append("--" + ASSIGNMENT_WALLET_DESTINATION_ID_OPTION);
|
||||
_childArguments.append(_walletUUID.toString());
|
||||
}
|
||||
if (_assignmentServerHostname != "") {
|
||||
_childArguments.append("--" + CUSTOM_ASSIGNMENT_SERVER_HOSTNAME_OPTION);
|
||||
_childArguments.append(_assignmentServerHostname);
|
||||
}
|
||||
if (_assignmentServerPort != DEFAULT_DOMAIN_SERVER_PORT) {
|
||||
_childArguments.append("--" + CUSTOM_ASSIGNMENT_SERVER_PORT_OPTION);
|
||||
_childArguments.append(QString::number(_assignmentServerPort));
|
||||
}
|
||||
|
||||
// make sure that the output from the child process appears in our output
|
||||
assignmentClient->setProcessChannelMode(QProcess::ForwardedChannels);
|
||||
|
||||
assignmentClient->start(applicationFilePath(), _childArguments);
|
||||
|
||||
// link the child processes' finished slot to our childProcessFinished slot
|
||||
connect(assignmentClient, SIGNAL(finished(int, QProcess::ExitStatus)), this,
|
||||
SLOT(childProcessFinished(int, QProcess::ExitStatus)));
|
||||
|
||||
assignmentClient->start(QCoreApplication::applicationFilePath(), _childArguments);
|
||||
|
||||
qDebug() << "Spawned a child client with PID" << assignmentClient->pid();
|
||||
}
|
||||
|
||||
void AssignmentClientMonitor::childProcessFinished(int exitCode, QProcess::ExitStatus exitStatus) {
|
||||
qDebug("Replacing dead child assignment client with a new one");
|
||||
|
||||
// remove the old process from our list of child processes
|
||||
qDebug() << "need to remove" << QPointer<QProcess>(qobject_cast<QProcess*>(sender()));
|
||||
_childProcesses.removeOne(QPointer<QProcess>(qobject_cast<QProcess*>(sender())));
|
||||
|
||||
spawnChildClient();
|
||||
|
||||
|
||||
void AssignmentClientMonitor::checkSpares() {
|
||||
auto nodeList = DependencyManager::get<NodeList>();
|
||||
QUuid aSpareId = "";
|
||||
unsigned int spareCount = 0;
|
||||
unsigned int totalCount = 0;
|
||||
|
||||
nodeList->removeSilentNodes();
|
||||
|
||||
nodeList->eachNode([&](const SharedNodePointer& node) {
|
||||
AssignmentClientChildData *childData = static_cast<AssignmentClientChildData*>(node->getLinkedData());
|
||||
totalCount ++;
|
||||
if (childData->getChildType() == "none") {
|
||||
spareCount ++;
|
||||
aSpareId = node->getUUID();
|
||||
}
|
||||
});
|
||||
|
||||
// Spawn or kill children, as needed. If --min or --max weren't specified, allow the child count
|
||||
// to drift up or down as far as needed.
|
||||
if (spareCount < 1 || totalCount < _minAssignmentClientForks) {
|
||||
if (!_maxAssignmentClientForks || totalCount < _maxAssignmentClientForks) {
|
||||
spawnChildClient();
|
||||
}
|
||||
}
|
||||
|
||||
if (spareCount > 1) {
|
||||
if (!_minAssignmentClientForks || totalCount > _minAssignmentClientForks) {
|
||||
// kill aSpareId
|
||||
qDebug() << "asking child" << aSpareId << "to exit.";
|
||||
SharedNodePointer childNode = nodeList->nodeWithUUID(aSpareId);
|
||||
childNode->activateLocalSocket();
|
||||
QByteArray diePacket = byteArrayWithPopulatedHeader(PacketTypeStopNode);
|
||||
nodeList->writeUnverifiedDatagram(diePacket, childNode);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void AssignmentClientMonitor::readPendingDatagrams() {
|
||||
auto nodeList = DependencyManager::get<NodeList>();
|
||||
|
||||
QByteArray receivedPacket;
|
||||
HifiSockAddr senderSockAddr;
|
||||
|
||||
while (nodeList->getNodeSocket().hasPendingDatagrams()) {
|
||||
receivedPacket.resize(nodeList->getNodeSocket().pendingDatagramSize());
|
||||
nodeList->getNodeSocket().readDatagram(receivedPacket.data(), receivedPacket.size(),
|
||||
senderSockAddr.getAddressPointer(), senderSockAddr.getPortPointer());
|
||||
|
||||
if (nodeList->packetVersionAndHashMatch(receivedPacket)) {
|
||||
if (packetTypeForPacket(receivedPacket) == PacketTypeNodeJsonStats) {
|
||||
QUuid packetUUID = uuidFromPacketHeader(receivedPacket);
|
||||
SharedNodePointer matchingNode = nodeList->sendingNodeForPacket(receivedPacket);
|
||||
if (!matchingNode) {
|
||||
// The parent only expects to be talking with prorams running on this same machine.
|
||||
if (senderSockAddr.getAddress() == QHostAddress::LocalHost ||
|
||||
senderSockAddr.getAddress() == QHostAddress::LocalHostIPv6) {
|
||||
if (!packetUUID.isNull()) {
|
||||
matchingNode = DependencyManager::get<LimitedNodeList>()->addOrUpdateNode
|
||||
(packetUUID, NodeType::Unassigned, senderSockAddr, senderSockAddr, false);
|
||||
AssignmentClientChildData *childData = new AssignmentClientChildData("unknown");
|
||||
matchingNode->setLinkedData(childData);
|
||||
} else {
|
||||
// tell unknown assignment-client child to exit.
|
||||
qDebug() << "asking unknown child to exit.";
|
||||
QByteArray diePacket = byteArrayWithPopulatedHeader(PacketTypeStopNode);
|
||||
nodeList->writeUnverifiedDatagram(diePacket, senderSockAddr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (matchingNode) {
|
||||
// update our records about how to reach this child
|
||||
matchingNode->setLocalSocket(senderSockAddr);
|
||||
|
||||
// push past the packet header
|
||||
QDataStream packetStream(receivedPacket);
|
||||
packetStream.skipRawData(numBytesForPacketHeader(receivedPacket));
|
||||
// decode json
|
||||
QVariantMap unpackedVariantMap;
|
||||
packetStream >> unpackedVariantMap;
|
||||
QJsonObject unpackedStatsJSON = QJsonObject::fromVariantMap(unpackedVariantMap);
|
||||
|
||||
// get child's assignment type out of the decoded json
|
||||
QString childType = unpackedStatsJSON["assignment_type"].toString();
|
||||
AssignmentClientChildData *childData =
|
||||
static_cast<AssignmentClientChildData*>(matchingNode->getLinkedData());
|
||||
childData->setChildType(childType);
|
||||
// note when this child talked
|
||||
matchingNode->setLastHeardMicrostamp(usecTimestampNow());
|
||||
}
|
||||
} else {
|
||||
// have the NodeList attempt to handle it
|
||||
nodeList->processNodeData(senderSockAddr, receivedPacket);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -15,25 +15,40 @@
|
|||
#include <QtCore/QCoreApplication>
|
||||
#include <QtCore/qpointer.h>
|
||||
#include <QtCore/QProcess>
|
||||
#include <QtCore/QDateTime>
|
||||
|
||||
#include <Assignment.h>
|
||||
|
||||
#include "AssignmentClientChildData.h"
|
||||
|
||||
extern const char* NUM_FORKS_PARAMETER;
|
||||
|
||||
class AssignmentClientMonitor : public QCoreApplication {
|
||||
|
||||
class AssignmentClientMonitor : public QObject {
|
||||
Q_OBJECT
|
||||
public:
|
||||
AssignmentClientMonitor(int &argc, char **argv, int numAssignmentClientForks);
|
||||
AssignmentClientMonitor(const unsigned int numAssignmentClientForks, const unsigned int minAssignmentClientForks,
|
||||
const unsigned int maxAssignmentClientForks, QString assignmentPool, QUuid walletUUID,
|
||||
QString assignmentServerHostname, quint16 assignmentServerPort);
|
||||
~AssignmentClientMonitor();
|
||||
|
||||
void stopChildProcesses();
|
||||
private slots:
|
||||
void childProcessFinished(int exitCode, QProcess::ExitStatus exitStatus);
|
||||
void readPendingDatagrams();
|
||||
void checkSpares();
|
||||
|
||||
private:
|
||||
void spawnChildClient();
|
||||
QList<QPointer<QProcess> > _childProcesses;
|
||||
|
||||
QStringList _childArguments;
|
||||
QTimer _checkSparesTimer; // every few seconds see if it need fewer or more spare children
|
||||
|
||||
const unsigned int _numAssignmentClientForks;
|
||||
const unsigned int _minAssignmentClientForks;
|
||||
const unsigned int _maxAssignmentClientForks;
|
||||
|
||||
QString _assignmentPool;
|
||||
QUuid _walletUUID;
|
||||
QString _assignmentServerHostname;
|
||||
quint16 _assignmentServerPort;
|
||||
};
|
||||
|
||||
#endif // hifi_AssignmentClientMonitor_h
|
||||
|
|
|
@ -15,7 +15,6 @@
|
|||
#include "AssignmentFactory.h"
|
||||
#include "audio/AudioMixer.h"
|
||||
#include "avatars/AvatarMixer.h"
|
||||
#include "metavoxels/MetavoxelServer.h"
|
||||
#include "entities/EntityServer.h"
|
||||
|
||||
ThreadedAssignment* AssignmentFactory::unpackAssignment(const QByteArray& packet) {
|
||||
|
@ -34,8 +33,6 @@ ThreadedAssignment* AssignmentFactory::unpackAssignment(const QByteArray& packet
|
|||
return new AvatarMixer(packet);
|
||||
case Assignment::AgentType:
|
||||
return new Agent(packet);
|
||||
case Assignment::MetavoxelServerType:
|
||||
return new MetavoxelServer(packet);
|
||||
case Assignment::EntityServerType:
|
||||
return new EntityServer(packet);
|
||||
default:
|
||||
|
|
|
@ -9,34 +9,10 @@
|
|||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#include <LogHandler.h>
|
||||
#include <SharedUtil.h>
|
||||
|
||||
#include "Assignment.h"
|
||||
#include "AssignmentClient.h"
|
||||
#include "AssignmentClientMonitor.h"
|
||||
#include "AssignmentClientApp.h"
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
#ifndef WIN32
|
||||
setvbuf(stdout, NULL, _IOLBF, 0);
|
||||
#endif
|
||||
|
||||
// use the verbose message handler in Logging
|
||||
qInstallMessageHandler(LogHandler::verboseMessageHandler);
|
||||
|
||||
const char* numForksString = getCmdOption(argc, (const char**)argv, NUM_FORKS_PARAMETER);
|
||||
|
||||
int numForks = 0;
|
||||
|
||||
if (numForksString) {
|
||||
numForks = atoi(numForksString);
|
||||
}
|
||||
|
||||
if (numForks) {
|
||||
AssignmentClientMonitor monitor(argc, argv, numForks);
|
||||
return monitor.exec();
|
||||
} else {
|
||||
AssignmentClient client(argc, argv);
|
||||
return client.exec();
|
||||
}
|
||||
AssignmentClientApp app(argc, argv);
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -1,367 +0,0 @@
|
|||
//
|
||||
// MetavoxelServer.cpp
|
||||
// assignment-client/src/metavoxels
|
||||
//
|
||||
// Created by Andrzej Kapolka on 12/18/13.
|
||||
// Copyright 2013 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 <QCoreApplication>
|
||||
#include <QDateTime>
|
||||
#include <QDir>
|
||||
#include <QFile>
|
||||
#include <QSaveFile>
|
||||
#include <QThread>
|
||||
|
||||
#include <PacketHeaders.h>
|
||||
|
||||
#include <MetavoxelMessages.h>
|
||||
#include <MetavoxelUtil.h>
|
||||
|
||||
#include "MetavoxelServer.h"
|
||||
|
||||
MetavoxelServer::MetavoxelServer(const QByteArray& packet) :
|
||||
ThreadedAssignment(packet),
|
||||
_nextSender(0),
|
||||
_savedDataInitialized(false) {
|
||||
}
|
||||
|
||||
void MetavoxelServer::applyEdit(const MetavoxelEditMessage& edit) {
|
||||
MetavoxelData data = _data;
|
||||
edit.apply(data, SharedObject::getWeakHash());
|
||||
setData(data);
|
||||
}
|
||||
|
||||
void MetavoxelServer::setData(const MetavoxelData& data, bool loaded) {
|
||||
if (_data == data) {
|
||||
return;
|
||||
}
|
||||
emit dataChanged(_data = data);
|
||||
|
||||
if (loaded) {
|
||||
_savedData = data;
|
||||
|
||||
} else if (!_savedDataInitialized) {
|
||||
_savedDataInitialized = true;
|
||||
|
||||
// start the save timer
|
||||
QTimer* saveTimer = new QTimer(this);
|
||||
connect(saveTimer, &QTimer::timeout, this, &MetavoxelServer::maybeSaveData);
|
||||
const int SAVE_INTERVAL = 1000 * 30;
|
||||
saveTimer->start(SAVE_INTERVAL);
|
||||
}
|
||||
}
|
||||
|
||||
const QString METAVOXEL_SERVER_LOGGING_NAME = "metavoxel-server";
|
||||
|
||||
void MetavoxelServer::run() {
|
||||
commonInit(METAVOXEL_SERVER_LOGGING_NAME, NodeType::MetavoxelServer);
|
||||
|
||||
auto nodeList = DependencyManager::get<NodeList>();
|
||||
nodeList->addNodeTypeToInterestSet(NodeType::Agent);
|
||||
|
||||
connect(nodeList.data(), &NodeList::nodeAdded, this, &MetavoxelServer::maybeAttachSession);
|
||||
connect(nodeList.data(), &NodeList::nodeKilled, this, &MetavoxelServer::maybeDeleteSession);
|
||||
|
||||
// initialize Bitstream before using it in multiple threads
|
||||
Bitstream::preThreadingInit();
|
||||
|
||||
// create the senders, each with its own thread
|
||||
int threadCount = QThread::idealThreadCount();
|
||||
if (threadCount == -1) {
|
||||
const int DEFAULT_THREAD_COUNT = 4;
|
||||
threadCount = DEFAULT_THREAD_COUNT;
|
||||
}
|
||||
qDebug() << "Creating" << threadCount << "sender threads";
|
||||
for (int i = 0; i < threadCount; i++) {
|
||||
QThread* thread = new QThread(this);
|
||||
MetavoxelSender* sender = new MetavoxelSender(this);
|
||||
sender->moveToThread(thread);
|
||||
connect(thread, &QThread::finished, sender, &QObject::deleteLater);
|
||||
thread->start();
|
||||
QMetaObject::invokeMethod(sender, "start");
|
||||
_senders.append(sender);
|
||||
}
|
||||
|
||||
// create the persister and start it in its own thread
|
||||
_persister = new MetavoxelPersister(this);
|
||||
QThread* persistenceThread = new QThread(this);
|
||||
_persister->moveToThread(persistenceThread);
|
||||
connect(persistenceThread, &QThread::finished, _persister, &QObject::deleteLater);
|
||||
persistenceThread->start();
|
||||
|
||||
// queue up the load
|
||||
QMetaObject::invokeMethod(_persister, "load");
|
||||
}
|
||||
|
||||
void MetavoxelServer::readPendingDatagrams() {
|
||||
QByteArray receivedPacket;
|
||||
HifiSockAddr senderSockAddr;
|
||||
|
||||
auto nodeList = DependencyManager::get<NodeList>();
|
||||
|
||||
while (readAvailableDatagram(receivedPacket, senderSockAddr)) {
|
||||
if (nodeList->packetVersionAndHashMatch(receivedPacket)) {
|
||||
switch (packetTypeForPacket(receivedPacket)) {
|
||||
case PacketTypeMetavoxelData:
|
||||
nodeList->findNodeAndUpdateWithDataFromPacket(receivedPacket);
|
||||
break;
|
||||
|
||||
default:
|
||||
nodeList->processNodeData(senderSockAddr, receivedPacket);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void MetavoxelServer::aboutToFinish() {
|
||||
QMetaObject::invokeMethod(_persister, "save", Q_ARG(const MetavoxelData&, _data));
|
||||
|
||||
foreach (MetavoxelSender* sender, _senders) {
|
||||
sender->thread()->quit();
|
||||
sender->thread()->wait();
|
||||
}
|
||||
_persister->thread()->quit();
|
||||
_persister->thread()->wait();
|
||||
}
|
||||
|
||||
void MetavoxelServer::maybeAttachSession(const SharedNodePointer& node) {
|
||||
if (node->getType() == NodeType::Agent) {
|
||||
QMutexLocker locker(&node->getMutex());
|
||||
MetavoxelSender* sender = _senders.at(_nextSender);
|
||||
_nextSender = (_nextSender + 1) % _senders.size();
|
||||
MetavoxelSession* session = new MetavoxelSession(node, sender);
|
||||
session->moveToThread(sender->thread());
|
||||
QMetaObject::invokeMethod(sender, "addSession", Q_ARG(QObject*, session));
|
||||
node->setLinkedData(session);
|
||||
}
|
||||
}
|
||||
|
||||
void MetavoxelServer::maybeDeleteSession(const SharedNodePointer& node) {
|
||||
if (node->getType() == NodeType::Agent) {
|
||||
// we assume the node is already locked
|
||||
MetavoxelSession* session = static_cast<MetavoxelSession*>(node->getLinkedData());
|
||||
if (session) {
|
||||
node->setLinkedData(NULL);
|
||||
session->deleteLater();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void MetavoxelServer::maybeSaveData() {
|
||||
if (_savedData != _data) {
|
||||
QMetaObject::invokeMethod(_persister, "save", Q_ARG(const MetavoxelData&, _savedData = _data));
|
||||
}
|
||||
}
|
||||
|
||||
MetavoxelSender::MetavoxelSender(MetavoxelServer* server) :
|
||||
_server(server),
|
||||
_sendTimer(this) {
|
||||
|
||||
_sendTimer.setSingleShot(true);
|
||||
connect(&_sendTimer, &QTimer::timeout, this, &MetavoxelSender::sendDeltas);
|
||||
|
||||
connect(_server, &MetavoxelServer::dataChanged, this, &MetavoxelSender::setData);
|
||||
}
|
||||
|
||||
const int SEND_INTERVAL = 50;
|
||||
|
||||
void MetavoxelSender::start() {
|
||||
_lastSend = QDateTime::currentMSecsSinceEpoch();
|
||||
_sendTimer.start(SEND_INTERVAL);
|
||||
}
|
||||
|
||||
void MetavoxelSender::addSession(QObject* session) {
|
||||
_sessions.insert(static_cast<MetavoxelSession*>(session));
|
||||
connect(session, &QObject::destroyed, this, &MetavoxelSender::removeSession);
|
||||
}
|
||||
|
||||
void MetavoxelSender::sendDeltas() {
|
||||
// send deltas for all sessions associated with our thread
|
||||
foreach (MetavoxelSession* session, _sessions) {
|
||||
session->update();
|
||||
}
|
||||
|
||||
// restart the send timer
|
||||
qint64 now = QDateTime::currentMSecsSinceEpoch();
|
||||
int elapsed = now - _lastSend;
|
||||
_lastSend = now;
|
||||
|
||||
_sendTimer.start(qMax(0, 2 * SEND_INTERVAL - qMax(elapsed, SEND_INTERVAL)));
|
||||
}
|
||||
|
||||
void MetavoxelSender::removeSession(QObject* session) {
|
||||
_sessions.remove(static_cast<MetavoxelSession*>(session));
|
||||
}
|
||||
|
||||
MetavoxelSession::MetavoxelSession(const SharedNodePointer& node, MetavoxelSender* sender) :
|
||||
Endpoint(node, new PacketRecord(), NULL),
|
||||
_sender(sender),
|
||||
_reliableDeltaChannel(NULL),
|
||||
_reliableDeltaID(0) {
|
||||
|
||||
connect(&_sequencer, SIGNAL(receivedHighPriorityMessage(const QVariant&)), SLOT(handleMessage(const QVariant&)));
|
||||
connect(&_sequencer, SIGNAL(sendAcknowledged(int)), SLOT(checkReliableDeltaReceived()));
|
||||
connect(_sequencer.getReliableInputChannel(), SIGNAL(receivedMessage(const QVariant&, Bitstream&)),
|
||||
SLOT(handleMessage(const QVariant&, Bitstream&)));
|
||||
}
|
||||
|
||||
void MetavoxelSession::update() {
|
||||
// wait until we have a valid lod before sending
|
||||
if (!_lod.isValid()) {
|
||||
return;
|
||||
}
|
||||
// if we're sending a reliable delta, wait until it's acknowledged
|
||||
if (_reliableDeltaChannel) {
|
||||
sendPacketGroup();
|
||||
return;
|
||||
}
|
||||
Bitstream& out = _sequencer.startPacket();
|
||||
int start = _sequencer.getOutputStream().getUnderlying().device()->pos();
|
||||
out << QVariant::fromValue(MetavoxelDeltaMessage());
|
||||
PacketRecord* sendRecord = getLastAcknowledgedSendRecord();
|
||||
_sender->getData().writeDelta(sendRecord->getData(), sendRecord->getLOD(), out, _lod);
|
||||
out.flush();
|
||||
int end = _sequencer.getOutputStream().getUnderlying().device()->pos();
|
||||
if (end > _sequencer.getMaxPacketSize()) {
|
||||
// we need to send the delta on the reliable channel
|
||||
_reliableDeltaChannel = _sequencer.getReliableOutputChannel(RELIABLE_DELTA_CHANNEL_INDEX);
|
||||
_reliableDeltaChannel->startMessage();
|
||||
_reliableDeltaChannel->getBuffer().write(_sequencer.getOutgoingPacketData().constData() + start, end - start);
|
||||
_reliableDeltaChannel->endMessage();
|
||||
|
||||
_reliableDeltaWriteMappings = out.getAndResetWriteMappings();
|
||||
_reliableDeltaReceivedOffset = _reliableDeltaChannel->getBytesWritten();
|
||||
_reliableDeltaData = _sender->getData();
|
||||
_reliableDeltaLOD = _lod;
|
||||
|
||||
// go back to the beginning with the current packet and note that there's a delta pending
|
||||
_sequencer.getOutputStream().getUnderlying().device()->seek(start);
|
||||
MetavoxelDeltaPendingMessage msg = { ++_reliableDeltaID, sendRecord->getPacketNumber(), _lodPacketNumber };
|
||||
out << (_reliableDeltaMessage = QVariant::fromValue(msg));
|
||||
_sequencer.endPacket();
|
||||
|
||||
} else {
|
||||
_sequencer.endPacket();
|
||||
}
|
||||
|
||||
// perhaps send additional packets to fill out the group
|
||||
sendPacketGroup(1);
|
||||
}
|
||||
|
||||
void MetavoxelSession::handleMessage(const QVariant& message, Bitstream& in) {
|
||||
handleMessage(message);
|
||||
}
|
||||
|
||||
PacketRecord* MetavoxelSession::maybeCreateSendRecord() const {
|
||||
return _reliableDeltaChannel ? new PacketRecord(_sequencer.getOutgoingPacketNumber(),
|
||||
_reliableDeltaLOD, _reliableDeltaData) : new PacketRecord(_sequencer.getOutgoingPacketNumber(),
|
||||
_lod, _sender->getData());
|
||||
}
|
||||
|
||||
void MetavoxelSession::handleMessage(const QVariant& message) {
|
||||
int userType = message.userType();
|
||||
if (userType == ClientStateMessage::Type) {
|
||||
ClientStateMessage state = message.value<ClientStateMessage>();
|
||||
_lod = state.lod;
|
||||
_lodPacketNumber = _sequencer.getIncomingPacketNumber();
|
||||
|
||||
} else if (userType == MetavoxelEditMessage::Type) {
|
||||
if (_node->getCanAdjustLocks()) {
|
||||
QMetaObject::invokeMethod(_sender->getServer(), "applyEdit",
|
||||
Q_ARG(const MetavoxelEditMessage&, message.value<MetavoxelEditMessage>()));
|
||||
}
|
||||
} else if (userType == QMetaType::QVariantList) {
|
||||
foreach (const QVariant& element, message.toList()) {
|
||||
handleMessage(element);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void MetavoxelSession::checkReliableDeltaReceived() {
|
||||
if (!_reliableDeltaChannel || _reliableDeltaChannel->getOffset() < _reliableDeltaReceivedOffset) {
|
||||
return;
|
||||
}
|
||||
_sequencer.getOutputStream().persistWriteMappings(_reliableDeltaWriteMappings);
|
||||
_reliableDeltaWriteMappings = Bitstream::WriteMappings();
|
||||
_reliableDeltaData = MetavoxelData();
|
||||
_reliableDeltaChannel = NULL;
|
||||
}
|
||||
|
||||
void MetavoxelSession::sendPacketGroup(int alreadySent) {
|
||||
int additionalPackets = _sequencer.notePacketGroup() - alreadySent;
|
||||
for (int i = 0; i < additionalPackets; i++) {
|
||||
Bitstream& out = _sequencer.startPacket();
|
||||
if (_reliableDeltaChannel) {
|
||||
out << _reliableDeltaMessage;
|
||||
} else {
|
||||
out << QVariant();
|
||||
}
|
||||
_sequencer.endPacket();
|
||||
}
|
||||
}
|
||||
|
||||
MetavoxelPersister::MetavoxelPersister(MetavoxelServer* server) :
|
||||
_server(server) {
|
||||
}
|
||||
|
||||
const char* SAVE_FILE = "/resources/metavoxels.dat";
|
||||
|
||||
const int FILE_MAGIC = 0xDADAFACE;
|
||||
const int FILE_VERSION = 4;
|
||||
|
||||
void MetavoxelPersister::load() {
|
||||
QString path = QCoreApplication::applicationDirPath() + SAVE_FILE;
|
||||
QFile file(path);
|
||||
if (!file.exists()) {
|
||||
return;
|
||||
}
|
||||
MetavoxelData data;
|
||||
{
|
||||
QDebug debug = qDebug() << "Reading from" << path << "...";
|
||||
file.open(QIODevice::ReadOnly);
|
||||
QDataStream inStream(&file);
|
||||
Bitstream in(inStream);
|
||||
int magic, version;
|
||||
in >> magic;
|
||||
if (magic != FILE_MAGIC) {
|
||||
debug << "wrong file magic: " << magic;
|
||||
return;
|
||||
}
|
||||
in >> version;
|
||||
if (version != FILE_VERSION) {
|
||||
debug << "wrong file version: " << version;
|
||||
return;
|
||||
}
|
||||
try {
|
||||
in >> data;
|
||||
} catch (const BitstreamException& e) {
|
||||
debug << "failed, " << e.getDescription();
|
||||
return;
|
||||
}
|
||||
QMetaObject::invokeMethod(_server, "setData", Q_ARG(const MetavoxelData&, data), Q_ARG(bool, true));
|
||||
debug << "done.";
|
||||
}
|
||||
data.dumpStats();
|
||||
}
|
||||
|
||||
void MetavoxelPersister::save(const MetavoxelData& data) {
|
||||
QString path = QCoreApplication::applicationDirPath() + SAVE_FILE;
|
||||
QDir directory = QFileInfo(path).dir();
|
||||
if (!directory.exists()) {
|
||||
directory.mkpath(".");
|
||||
}
|
||||
QDebug debug = qDebug() << "Writing to" << path << "...";
|
||||
QSaveFile file(path);
|
||||
file.open(QIODevice::WriteOnly);
|
||||
QDataStream outStream(&file);
|
||||
Bitstream out(outStream);
|
||||
out << FILE_MAGIC << FILE_VERSION << data;
|
||||
out.flush();
|
||||
file.commit();
|
||||
debug << "done.";
|
||||
}
|
|
@ -1,157 +0,0 @@
|
|||
//
|
||||
// MetavoxelServer.h
|
||||
// assignment-client/src/metavoxels
|
||||
//
|
||||
// Created by Andrzej Kapolka on 12/18/13.
|
||||
// Copyright 2013 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_MetavoxelServer_h
|
||||
#define hifi_MetavoxelServer_h
|
||||
|
||||
#include <QList>
|
||||
#include <QTimer>
|
||||
|
||||
#include <ThreadedAssignment.h>
|
||||
|
||||
#include <Endpoint.h>
|
||||
|
||||
class MetavoxelEditMessage;
|
||||
class MetavoxelPersister;
|
||||
class MetavoxelSender;
|
||||
class MetavoxelSession;
|
||||
|
||||
/// Maintains a shared metavoxel system, accepting change requests and broadcasting updates.
|
||||
class MetavoxelServer : public ThreadedAssignment {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
||||
MetavoxelServer(const QByteArray& packet);
|
||||
|
||||
Q_INVOKABLE void applyEdit(const MetavoxelEditMessage& edit);
|
||||
|
||||
const MetavoxelData& getData() const { return _data; }
|
||||
|
||||
Q_INVOKABLE void setData(const MetavoxelData& data, bool loaded = false);
|
||||
|
||||
virtual void run();
|
||||
|
||||
virtual void readPendingDatagrams();
|
||||
|
||||
virtual void aboutToFinish();
|
||||
|
||||
signals:
|
||||
|
||||
void dataChanged(const MetavoxelData& data);
|
||||
|
||||
private slots:
|
||||
|
||||
void maybeAttachSession(const SharedNodePointer& node);
|
||||
void maybeDeleteSession(const SharedNodePointer& node);
|
||||
void maybeSaveData();
|
||||
|
||||
private:
|
||||
|
||||
QVector<MetavoxelSender*> _senders;
|
||||
int _nextSender;
|
||||
|
||||
MetavoxelPersister* _persister;
|
||||
|
||||
MetavoxelData _data;
|
||||
MetavoxelData _savedData;
|
||||
bool _savedDataInitialized;
|
||||
};
|
||||
|
||||
/// Handles update sending for one thread.
|
||||
class MetavoxelSender : public QObject {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
||||
MetavoxelSender(MetavoxelServer* server);
|
||||
|
||||
MetavoxelServer* getServer() const { return _server; }
|
||||
|
||||
const MetavoxelData& getData() const { return _data; }
|
||||
|
||||
Q_INVOKABLE void start();
|
||||
|
||||
Q_INVOKABLE void addSession(QObject* session);
|
||||
|
||||
private slots:
|
||||
|
||||
void setData(const MetavoxelData& data) { _data = data; }
|
||||
void sendDeltas();
|
||||
void removeSession(QObject* session);
|
||||
|
||||
private:
|
||||
|
||||
MetavoxelServer* _server;
|
||||
QSet<MetavoxelSession*> _sessions;
|
||||
|
||||
QTimer _sendTimer;
|
||||
qint64 _lastSend;
|
||||
|
||||
MetavoxelData _data;
|
||||
};
|
||||
|
||||
/// Contains the state of a single client session.
|
||||
class MetavoxelSession : public Endpoint {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
||||
MetavoxelSession(const SharedNodePointer& node, MetavoxelSender* sender);
|
||||
|
||||
virtual void update();
|
||||
|
||||
protected:
|
||||
|
||||
virtual void handleMessage(const QVariant& message, Bitstream& in);
|
||||
|
||||
virtual PacketRecord* maybeCreateSendRecord() const;
|
||||
|
||||
private slots:
|
||||
|
||||
void handleMessage(const QVariant& message);
|
||||
void checkReliableDeltaReceived();
|
||||
|
||||
private:
|
||||
|
||||
void sendPacketGroup(int alreadySent = 0);
|
||||
|
||||
MetavoxelSender* _sender;
|
||||
|
||||
MetavoxelLOD _lod;
|
||||
int _lodPacketNumber;
|
||||
|
||||
ReliableChannel* _reliableDeltaChannel;
|
||||
int _reliableDeltaReceivedOffset;
|
||||
MetavoxelData _reliableDeltaData;
|
||||
MetavoxelLOD _reliableDeltaLOD;
|
||||
Bitstream::WriteMappings _reliableDeltaWriteMappings;
|
||||
int _reliableDeltaID;
|
||||
QVariant _reliableDeltaMessage;
|
||||
};
|
||||
|
||||
/// Handles persistence in a separate thread.
|
||||
class MetavoxelPersister : public QObject {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
||||
MetavoxelPersister(MetavoxelServer* server);
|
||||
|
||||
Q_INVOKABLE void load();
|
||||
Q_INVOKABLE void save(const MetavoxelData& data);
|
||||
|
||||
private:
|
||||
|
||||
MetavoxelServer* _server;
|
||||
};
|
||||
|
||||
#endif // hifi_MetavoxelServer_h
|
47
cmake/externals/bullet/CMakeLists.txt
vendored
47
cmake/externals/bullet/CMakeLists.txt
vendored
|
@ -14,21 +14,12 @@ endif ()
|
|||
|
||||
include(ExternalProject)
|
||||
|
||||
if (WIN32)
|
||||
if (UPPER_CMAKE_BUILD_TYPE MATCHES DEBUG)
|
||||
set(MSBUILD_CONFIGURATION Debug)
|
||||
else ()
|
||||
set(MSBUILD_CONFIGURATION Release)
|
||||
endif ()
|
||||
|
||||
find_program(MSBUILD_COMMAND msbuild PATHS "C:/Program Files (x86)/MSBUILD/12.0/Bin")
|
||||
|
||||
if (WIN32)
|
||||
ExternalProject_Add(
|
||||
${EXTERNAL_NAME}
|
||||
URL https://bullet.googlecode.com/files/bullet-2.82-r2704.zip
|
||||
URL_MD5 f5e8914fc9064ad32e0d62d19d33d977
|
||||
CMAKE_ARGS ${PLATFORM_CMAKE_ARGS} -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE} -DCMAKE_INSTALL_PREFIX:PATH=<INSTALL_DIR> -DBUILD_EXTRAS=0 -DINSTALL_LIBS=1 -DBUILD_DEMOS=0 -DUSE_GLUT=0
|
||||
BUILD_COMMAND ${MSBUILD_COMMAND} ALL_BUILD.vcxproj /p:Configuration=${MSBUILD_CONFIGURATION}
|
||||
CMAKE_ARGS ${PLATFORM_CMAKE_ARGS} -DCMAKE_INSTALL_PREFIX:PATH=<INSTALL_DIR> -DBUILD_EXTRAS=0 -DINSTALL_LIBS=1 -DBUILD_DEMOS=0 -DUSE_GLUT=0
|
||||
LOG_DOWNLOAD 1
|
||||
LOG_CONFIGURE 1
|
||||
LOG_BUILD 1
|
||||
|
@ -66,28 +57,22 @@ elseif (WIN32)
|
|||
endif ()
|
||||
|
||||
if (DEFINED BULLET_LIB_EXT)
|
||||
if (NOT WIN32 OR UPPER_CMAKE_BUILD_TYPE MATCHES RELEASE)
|
||||
set(_PRESENT_LIB_TYPE RELEASE)
|
||||
set(_MISSING_LIB_TYPE DEBUG)
|
||||
else ()
|
||||
set(_PRESENT_LIB_TYPE DEBUG)
|
||||
set(_MISSING_LIB_TYPE RELEASE)
|
||||
set(_LIB_NAME_SUFFIX _Debug)
|
||||
endif ()
|
||||
set(_BULLET_LIB_PAIRS "DYNAMICS_LIBRARY\;BulletDynamics" "COLLISION_LIBRARY\;BulletCollision" "MATH_LIBRARY\;LinearMath" "SOFTBODY_LIBRARY\;BulletSoftBody")
|
||||
|
||||
set(${EXTERNAL_NAME_UPPER}_DYNAMICS_LIBRARY_${_PRESENT_LIB_TYPE} ${BULLET_LIB_DIR}/${LIB_PREFIX}BulletDynamics${_LIB_NAME_SUFFIX}.${BULLET_LIB_EXT} CACHE FILEPATH "Bullet dynamics ${_PRESENT_LIB_TYPE} library location")
|
||||
set(${EXTERNAL_NAME_UPPER}_DYNAMICS_LIBRARY_${_MISSING_LIB_TYPE} "" CACHE FILEPATH "Bullet dynamics ${_MISSING_LIB_TYPE} library location")
|
||||
|
||||
set(${EXTERNAL_NAME_UPPER}_COLLISION_LIBRARY_${_PRESENT_LIB_TYPE} ${BULLET_LIB_DIR}/${LIB_PREFIX}BulletCollision${_LIB_NAME_SUFFIX}.${BULLET_LIB_EXT} CACHE FILEPATH "Bullet collision ${_PRESENT_LIB_TYPE} library location")
|
||||
set(${EXTERNAL_NAME_UPPER}_COLLISION_LIBRARY_${_MISSING_LIB_TYPE} "" CACHE FILEPATH "Bullet collision ${_MISSING_LIB_TYPE} library location")
|
||||
|
||||
set(${EXTERNAL_NAME_UPPER}_MATH_LIBRARY_${_PRESENT_LIB_TYPE} ${BULLET_LIB_DIR}/${LIB_PREFIX}LinearMath${_LIB_NAME_SUFFIX}.${BULLET_LIB_EXT} CACHE FILEPATH "Bullet math ${_PRESENT_LIB_TYPE} library location")
|
||||
set(${EXTERNAL_NAME_UPPER}_MATH_LIBRARY_${_MISSING_LIB_TYPE} "" CACHE FILEPATH "Bullet math ${_MISSING_LIB_TYPE} library location")
|
||||
|
||||
set(${EXTERNAL_NAME_UPPER}_SOFTBODY_LIBRARY_${_PRESENT_LIB_TYPE} ${BULLET_LIB_DIR}/${LIB_PREFIX}BulletSoftBody${_LIB_NAME_SUFFIX}.${BULLET_LIB_EXT} CACHE FILEPATH "Bullet softbody ${_PRESENT_LIB_TYPE} library location")
|
||||
set(${EXTERNAL_NAME_UPPER}_SOFTBODY_LIBRARY_${_MISSING_LIB_TYPE} "" CACHE FILEPATH "Bullet softbody ${_MISSING_LIB_TYPE} library location")
|
||||
foreach(_LIB_PAIR ${_BULLET_LIB_PAIRS})
|
||||
list(GET _LIB_PAIR 0 _LIB_VAR_NAME)
|
||||
list(GET _LIB_PAIR 1 _LIB_NAME)
|
||||
|
||||
set(${EXTERNAL_NAME_UPPER}_${_LIB_VAR_NAME}_RELEASE ${BULLET_LIB_DIR}/${LIB_PREFIX}${_LIB_NAME}.${BULLET_LIB_EXT} CACHE FILEPATH "${_LIB_NAME} release library location")
|
||||
|
||||
if (WIN32)
|
||||
set(${EXTERNAL_NAME_UPPER}_${_LIB_VAR_NAME}_DEBUG ${BULLET_LIB_DIR}/${LIB_PREFIX}${_LIB_NAME}_Debug.${BULLET_LIB_EXT} CACHE FILEPATH "${_LIB_NAME} debug library location")
|
||||
else ()
|
||||
set(${EXTERNAL_NAME_UPPER}_${_LIB_VAR_NAME}_DEBUG "" CACHE FILEPATH "${_LIB_NAME} debug library location")
|
||||
endif ()
|
||||
endforeach()
|
||||
endif ()
|
||||
|
||||
if (DEFINED ${EXTERNAL_NAME_UPPER}_DYNAMICS_LIBRARY_${_PRESENT_LIB_TYPE})
|
||||
if (DEFINED ${EXTERNAL_NAME_UPPER}_DYNAMICS_LIBRARY_RELEASE)
|
||||
set(${EXTERNAL_NAME_UPPER}_INCLUDE_DIR ${INSTALL_DIR}/include/bullet CACHE PATH "Path to bullet include directory")
|
||||
endif ()
|
2
cmake/externals/qxmpp/CMakeLists.txt
vendored
2
cmake/externals/qxmpp/CMakeLists.txt
vendored
|
@ -1,7 +1,7 @@
|
|||
set(EXTERNAL_NAME qxmpp)
|
||||
|
||||
# we need to find qmake inside QT_DIR
|
||||
find_program(QMAKE_COMMAND NAME qmake PATHS ${QT_DIR}/bin NO_DEFAULT_PATH)
|
||||
find_program(QMAKE_COMMAND NAME qmake PATHS ${QT_DIR}/bin $ENV{QTTOOLDIR} NO_DEFAULT_PATH)
|
||||
|
||||
if (NOT QMAKE_COMMAND)
|
||||
message(FATAL_ERROR "Could not find qmake. Qxmpp cannot be compiled without qmake.")
|
||||
|
|
13
cmake/externals/qxmpp/qxmpp.patch
vendored
13
cmake/externals/qxmpp/qxmpp.patch
vendored
|
@ -1,13 +0,0 @@
|
|||
diff --git a/qxmpp-0.7.6/src/src.pro b/qxmpp-0.7.6-patch/src/src.pro
|
||||
index 954738c..8404c8c 100644
|
||||
--- a/qxmpp-0.7.6/src/src.pro
|
||||
+++ b/qxmpp-0.7.6-patch/src/src.pro
|
||||
@@ -4,7 +4,7 @@ QT -= gui
|
||||
|
||||
TEMPLATE = lib
|
||||
|
||||
-CONFIG += $$QXMPP_LIBRARY_TYPE
|
||||
+CONFIG += $$QXMPP_LIBRARY_TYPE c++11
|
||||
DEFINES += QXMPP_BUILD
|
||||
DEFINES += $$QXMPP_INTERNAL_DEFINES
|
||||
INCLUDEPATH += $$QXMPP_INCLUDEPATH $$QXMPP_INTERNAL_INCLUDES
|
|
@ -15,12 +15,21 @@ function(AUTOSCRIBE_SHADER SHADER_FILE)
|
|||
list(APPEND SHADER_INCLUDE_FILES ${includeFile})
|
||||
endforeach()
|
||||
|
||||
#Extract the unique include shader paths
|
||||
foreach(SHADER_INCLUDE ${SHADER_INCLUDE_FILES})
|
||||
get_filename_component(INCLUDE_DIR ${SHADER_INCLUDE} PATH)
|
||||
list(APPEND SHADER_INCLUDES_PATHS ${INCLUDE_DIR})
|
||||
endforeach()
|
||||
|
||||
|
||||
#Extract the unique include shader paths
|
||||
set(INCLUDES ${HIFI_LIBRARIES_SHADER_INCLUDE_FILES})
|
||||
#message(Hifi for includes ${INCLUDES})
|
||||
foreach(EXTRA_SHADER_INCLUDE ${INCLUDES})
|
||||
list(APPEND SHADER_INCLUDES_PATHS ${EXTRA_SHADER_INCLUDE})
|
||||
endforeach()
|
||||
|
||||
list(REMOVE_DUPLICATES SHADER_INCLUDES_PATHS)
|
||||
#message(ready for includes ${SHADER_INCLUDES_PATHS})
|
||||
|
||||
# make the scribe include arguments
|
||||
set(SCRIBE_INCLUDES)
|
||||
|
@ -64,6 +73,17 @@ endfunction()
|
|||
|
||||
|
||||
macro(AUTOSCRIBE_SHADER_LIB)
|
||||
|
||||
file(RELATIVE_PATH RELATIVE_LIBRARY_DIR_PATH ${CMAKE_CURRENT_SOURCE_DIR} "${HIFI_LIBRARY_DIR}")
|
||||
foreach(HIFI_LIBRARY ${ARGN})
|
||||
#if (NOT TARGET ${HIFI_LIBRARY})
|
||||
# file(GLOB_RECURSE HIFI_LIBRARIES_SHADER_INCLUDE_FILES ${RELATIVE_LIBRARY_DIR_PATH}/${HIFI_LIBRARY}/src/)
|
||||
#endif ()
|
||||
|
||||
#file(GLOB_RECURSE HIFI_LIBRARIES_SHADER_INCLUDE_FILES ${HIFI_LIBRARY_DIR}/${HIFI_LIBRARY}/src/*.slh)
|
||||
list(APPEND HIFI_LIBRARIES_SHADER_INCLUDE_FILES ${HIFI_LIBRARY_DIR}/${HIFI_LIBRARY}/src)
|
||||
endforeach()
|
||||
#message(${HIFI_LIBRARIES_SHADER_INCLUDE_FILES})
|
||||
|
||||
file(GLOB_RECURSE SHADER_INCLUDE_FILES src/*.slh)
|
||||
file(GLOB_RECURSE SHADER_SOURCE_FILES src/*.slv src/*.slf)
|
||||
|
|
|
@ -14,10 +14,12 @@ macro(SETUP_EXTERNALS_BINARY_DIR)
|
|||
# get a short name for the generator to use in the path
|
||||
STRING(REGEX REPLACE " " "-" CMAKE_GENERATOR_FOLDER_NAME ${CMAKE_GENERATOR})
|
||||
|
||||
if (CMAKE_GENERATOR_FOLDER_NAME STREQUAL "Unix-Makefiles")
|
||||
set(CMAKE_GENERATOR_FOLDER_NAME "makefiles")
|
||||
elseif (CMAKE_GENERATOR_FOLDER_NAME STREQUAL "Visual-Studio-12")
|
||||
set(CMAKE_GENERATOR_FOLDER_NAME "vs12")
|
||||
if (MSVC12)
|
||||
set(CMAKE_GENERATOR_FOLDER_NAME "vc12")
|
||||
else ()
|
||||
if (CMAKE_GENERATOR_FOLDER_NAME STREQUAL "Unix-Makefiles")
|
||||
set(CMAKE_GENERATOR_FOLDER_NAME "makefiles")
|
||||
endif ()
|
||||
endif ()
|
||||
|
||||
set(EXTERNALS_BINARY_ROOT_DIR "${CMAKE_CURRENT_SOURCE_DIR}/build-ext")
|
||||
|
|
|
@ -1,24 +0,0 @@
|
|||
# Try to find the PrioVR library
|
||||
#
|
||||
# You must provide a PRIOVR_ROOT_DIR which contains lib and include directories
|
||||
#
|
||||
# Once done this will define
|
||||
#
|
||||
# PRIOVR_FOUND - system found PrioVR
|
||||
# PRIOVR_INCLUDE_DIRS - the PrioVR include directory
|
||||
# PRIOVR_LIBRARIES - Link this to use PrioVR
|
||||
#
|
||||
# Created on 5/12/2014 by Andrzej Kapolka
|
||||
# Copyright (c) 2014 High Fidelity
|
||||
#
|
||||
|
||||
find_path(PRIOVR_INCLUDE_DIRS yei_skeletal_api.h ${PRIOVR_ROOT_DIR}/include)
|
||||
|
||||
if (WIN32)
|
||||
find_library(PRIOVR_LIBRARIES Skeletal_API.lib ${PRIOVR_ROOT_DIR}/lib)
|
||||
endif (WIN32)
|
||||
|
||||
include(FindPackageHandleStandardArgs)
|
||||
find_package_handle_standard_args(PrioVR DEFAULT_MSG PRIOVR_INCLUDE_DIRS PRIOVR_LIBRARIES)
|
||||
|
||||
mark_as_advanced(PRIOVR_INCLUDE_DIRS PRIOVR_LIBRARIES)
|
|
@ -1,45 +0,0 @@
|
|||
#
|
||||
# FindQxmpp.cmake
|
||||
#
|
||||
# Try to find the qxmpp library
|
||||
#
|
||||
# You can provide a QXMPP_ROOT_DIR which contains lib and include directories
|
||||
#
|
||||
# Once done this will define
|
||||
#
|
||||
# QXMPP_FOUND - system found qxmpp
|
||||
# QXMPP_INCLUDE_DIRS - the qxmpp include directory
|
||||
# QXMPP_LIBRARIES - Link this to use qxmpp
|
||||
#
|
||||
# Created on 3/10/2014 by Stephen Birarda
|
||||
# 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("${MACRO_DIR}/HifiLibrarySearchHints.cmake")
|
||||
hifi_library_search_hints("qxmpp")
|
||||
|
||||
find_path(QXMPP_INCLUDE_DIRS qxmpp/QXmppClient.h PATH_SUFFIXES include HINTS ${QXMPP_SEARCH_DIRS})
|
||||
|
||||
find_library(QXMPP_LIBRARY_RELEASE NAMES qxmpp PATH_SUFFIXES lib HINTS ${QXMPP_SEARCH_DIRS})
|
||||
find_library(QXMPP_LIBRARY_DEBUG NAMES qxmpp_d PATH_SUFFIXES lib HINTS ${QXMPP_SEARCH_DIRS})
|
||||
|
||||
if (WIN32)
|
||||
find_path(QXMPP_DLL_PATH NAMES qxmpp.dll PATH_SUFFIXES lib HINTS ${QXMPP_SEARCH_DIRS})
|
||||
endif ()
|
||||
|
||||
find_package(Qt5 COMPONENTS Xml REQUIRED)
|
||||
|
||||
include(SelectLibraryConfigurations)
|
||||
select_library_configurations(QXMPP)
|
||||
|
||||
set(QXMPP_LIBRARIES "${QXMPP_LIBRARY}" Qt5::Xml)
|
||||
|
||||
include(FindPackageHandleStandardArgs)
|
||||
find_package_handle_standard_args(QXmpp DEFAULT_MSG QXMPP_INCLUDE_DIRS QXMPP_LIBRARIES QXMPP_LIBRARY)
|
||||
|
||||
if (QXMPP_DLL_PATH)
|
||||
add_paths_to_fixup_libs(${QXMPP_DLL_PATH})
|
||||
endif ()
|
59
cmake/modules/FindVHACD.cmake
Normal file
59
cmake/modules/FindVHACD.cmake
Normal file
|
@ -0,0 +1,59 @@
|
|||
#
|
||||
# FindVHACD.cmake
|
||||
#
|
||||
# Try to find the V-HACD library that decomposes a 3D surface into a set of "near" convex parts.
|
||||
#
|
||||
# Once done this will define
|
||||
#
|
||||
# VHACD_FOUND - system found V-HACD
|
||||
# VHACD_INCLUDE_DIRS - the V-HACD include directory
|
||||
# VHACD_LIBRARIES - link to this to use V-HACD
|
||||
#
|
||||
# Created on 2/20/2015 by Virendra Singh
|
||||
# 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
|
||||
#
|
||||
|
||||
include("${MACRO_DIR}/HifiLibrarySearchHints.cmake")
|
||||
hifi_library_search_hints("vhacd")
|
||||
|
||||
macro(_FIND_VHACD_LIBRARY _var)
|
||||
set(_${_var}_NAMES ${ARGN})
|
||||
find_library(${_var}_LIBRARY_RELEASE
|
||||
NAMES ${_${_var}_NAMES}
|
||||
HINTS
|
||||
${VHACD_SEARCH_DIRS}
|
||||
$ENV{VHACD_ROOT_DIR}
|
||||
PATH_SUFFIXES lib lib/Release
|
||||
)
|
||||
|
||||
find_library(${_var}_LIBRARY_DEBUG
|
||||
NAMES ${_${_var}_NAMES}
|
||||
HINTS
|
||||
${VHACD_SEARCH_DIRS}
|
||||
$ENV{VHACD_ROOT_DIR}
|
||||
PATH_SUFFIXES lib lib/Debug
|
||||
)
|
||||
|
||||
select_library_configurations(${_var})
|
||||
|
||||
mark_as_advanced(${_var}_LIBRARY)
|
||||
mark_as_advanced(${_var}_LIBRARY)
|
||||
endmacro()
|
||||
|
||||
|
||||
find_path(VHACD_INCLUDE_DIRS VHACD.h PATH_SUFFIXES include HINTS ${VHACD_SEARCH_DIRS} $ENV{VHACD_ROOT_DIR})
|
||||
if(NOT WIN32)
|
||||
_FIND_VHACD_LIBRARY(VHACD libVHACD.a)
|
||||
else()
|
||||
_FIND_VHACD_LIBRARY(VHACD VHACD_LIB)
|
||||
endif()
|
||||
set(VHACD_LIBRARIES ${VHACD_LIBRARY})
|
||||
|
||||
include(FindPackageHandleStandardArgs)
|
||||
find_package_handle_standard_args(VHACD "Could NOT find VHACD, try to set the path to VHACD root folder in the system variable VHACD_ROOT_DIR or create a directory vhacd in HIFI_LIB_DIR and paste the necessary files there"
|
||||
VHACD_INCLUDE_DIRS VHACD_LIBRARIES)
|
||||
|
||||
mark_as_advanced(VHACD_INCLUDE_DIRS VHACD_LIBRARIES VHACD_SEARCH_DIRS)
|
|
@ -32,6 +32,7 @@
|
|||
#include <SharedUtil.h>
|
||||
#include <ShutdownEventListener.h>
|
||||
#include <UUID.h>
|
||||
#include <LogHandler.h>
|
||||
|
||||
#include "DomainServerNodeData.h"
|
||||
|
||||
|
@ -246,19 +247,14 @@ void DomainServer::setupNodeListAndAssignments(const QUuid& sessionUUID) {
|
|||
auto nodeList = DependencyManager::set<LimitedNodeList>(domainServerPort, domainServerDTLSPort);
|
||||
|
||||
// no matter the local port, save it to shared mem so that local assignment clients can ask what it is
|
||||
QSharedMemory* sharedPortMem = new QSharedMemory(DOMAIN_SERVER_LOCAL_PORT_SMEM_KEY, this);
|
||||
quint16 localPort = nodeList->getNodeSocket().localPort();
|
||||
|
||||
// attempt to create the shared memory segment
|
||||
if (sharedPortMem->create(sizeof(localPort)) || sharedPortMem->attach()) {
|
||||
sharedPortMem->lock();
|
||||
memcpy(sharedPortMem->data(), &localPort, sizeof(localPort));
|
||||
sharedPortMem->unlock();
|
||||
|
||||
qDebug() << "Wrote local listening port" << localPort << "to shared memory at key" << DOMAIN_SERVER_LOCAL_PORT_SMEM_KEY;
|
||||
} else {
|
||||
qWarning() << "Failed to create and attach to shared memory to share local port with assignment-client children.";
|
||||
}
|
||||
nodeList->putLocalPortIntoSharedMemory(DOMAIN_SERVER_LOCAL_PORT_SMEM_KEY, this, nodeList->getNodeSocket().localPort());
|
||||
|
||||
// store our local http ports in shared memory
|
||||
quint16 localHttpPort = DOMAIN_SERVER_HTTP_PORT;
|
||||
nodeList->putLocalPortIntoSharedMemory(DOMAIN_SERVER_LOCAL_HTTP_PORT_SMEM_KEY, this, localHttpPort);
|
||||
quint16 localHttpsPort = DOMAIN_SERVER_HTTPS_PORT;
|
||||
nodeList->putLocalPortIntoSharedMemory(DOMAIN_SERVER_LOCAL_HTTPS_PORT_SMEM_KEY, this, localHttpsPort);
|
||||
|
||||
|
||||
// set our LimitedNodeList UUID to match the UUID from our config
|
||||
// nodes will currently use this to add resources to data-web that relate to our domain
|
||||
|
@ -560,6 +556,7 @@ void DomainServer::populateDefaultStaticAssignmentsExcludingTypes(const QSet<Ass
|
|||
if (!excludedTypes.contains(defaultedType)
|
||||
&& defaultedType != Assignment::UNUSED_0
|
||||
&& defaultedType != Assignment::UNUSED_1
|
||||
&& defaultedType != Assignment::UNUSED_2
|
||||
&& defaultedType != Assignment::AgentType) {
|
||||
// type has not been set from a command line or config file config, use the default
|
||||
// by clearing whatever exists and writing a single default assignment with no payload
|
||||
|
@ -570,8 +567,7 @@ void DomainServer::populateDefaultStaticAssignmentsExcludingTypes(const QSet<Ass
|
|||
}
|
||||
|
||||
const NodeSet STATICALLY_ASSIGNED_NODES = NodeSet() << NodeType::AudioMixer
|
||||
<< NodeType::AvatarMixer << NodeType::EntityServer
|
||||
<< NodeType::MetavoxelServer;
|
||||
<< NodeType::AvatarMixer << NodeType::EntityServer;
|
||||
|
||||
void DomainServer::handleConnectRequest(const QByteArray& packet, const HifiSockAddr& senderSockAddr) {
|
||||
|
||||
|
@ -955,8 +951,10 @@ void DomainServer::readAvailableDatagrams() {
|
|||
|
||||
if (requestAssignment.getType() != Assignment::AgentType
|
||||
|| noisyMessageTimer.elapsed() > NOISY_MESSAGE_INTERVAL_MSECS) {
|
||||
static QString repeatedMessage = LogHandler::getInstance().addOnlyOnceMessageRegex
|
||||
("Received a request for assignment type [^ ]+ from [^ ]+");
|
||||
qDebug() << "Received a request for assignment type" << requestAssignment.getType()
|
||||
<< "from" << senderSockAddr;
|
||||
<< "from" << senderSockAddr;
|
||||
noisyMessageTimer.restart();
|
||||
}
|
||||
|
||||
|
@ -986,6 +984,8 @@ void DomainServer::readAvailableDatagrams() {
|
|||
} else {
|
||||
if (requestAssignment.getType() != Assignment::AgentType
|
||||
|| noisyMessageTimer.elapsed() > NOISY_MESSAGE_INTERVAL_MSECS) {
|
||||
static QString repeatedMessage = LogHandler::getInstance().addOnlyOnceMessageRegex
|
||||
("Unable to fulfill assignment request of type [^ ]+ from [^ ]+");
|
||||
qDebug() << "Unable to fulfill assignment request of type" << requestAssignment.getType()
|
||||
<< "from" << senderSockAddr;
|
||||
noisyMessageTimer.restart();
|
||||
|
|
|
@ -81,6 +81,8 @@ var SETTING_INSPECT_TOOL_ENABLED = "inspectToolEnabled";
|
|||
var SETTING_AUTO_FOCUS_ON_SELECT = "autoFocusOnSelect";
|
||||
var SETTING_EASE_ON_FOCUS = "cameraEaseOnFocus";
|
||||
|
||||
var INSUFFICIENT_PERMISSIONS_ERROR_MSG = "You do not have the necessary permissions to edit on this domain."
|
||||
|
||||
var modelURLs = [
|
||||
HIFI_PUBLIC_BUCKET + "models/entities/2-Terrain:%20Alder.fbx",
|
||||
HIFI_PUBLIC_BUCKET + "models/entities/2-Terrain:%20Bush1.fbx",
|
||||
|
@ -177,25 +179,29 @@ var toolBar = (function () {
|
|||
|
||||
that.setActive = function(active) {
|
||||
if (active != isActive) {
|
||||
isActive = active;
|
||||
if (!isActive) {
|
||||
entityListTool.setVisible(false);
|
||||
gridTool.setVisible(false);
|
||||
grid.setEnabled(false);
|
||||
propertiesTool.setVisible(false);
|
||||
selectionManager.clearSelections();
|
||||
cameraManager.disable();
|
||||
if (active && !Entities.canAdjustLocks()) {
|
||||
Window.alert(INSUFFICIENT_PERMISSIONS_ERROR_MSG);
|
||||
} else {
|
||||
hasShownPropertiesTool = false;
|
||||
cameraManager.enable();
|
||||
entityListTool.setVisible(true);
|
||||
gridTool.setVisible(true);
|
||||
grid.setEnabled(true);
|
||||
propertiesTool.setVisible(true);
|
||||
Window.setFocus();
|
||||
isActive = active;
|
||||
if (!isActive) {
|
||||
entityListTool.setVisible(false);
|
||||
gridTool.setVisible(false);
|
||||
grid.setEnabled(false);
|
||||
propertiesTool.setVisible(false);
|
||||
selectionManager.clearSelections();
|
||||
cameraManager.disable();
|
||||
} else {
|
||||
hasShownPropertiesTool = false;
|
||||
cameraManager.enable();
|
||||
entityListTool.setVisible(true);
|
||||
gridTool.setVisible(true);
|
||||
grid.setEnabled(true);
|
||||
propertiesTool.setVisible(true);
|
||||
Window.setFocus();
|
||||
}
|
||||
}
|
||||
}
|
||||
toolBar.selectTool(activeButton, active);
|
||||
toolBar.selectTool(activeButton, isActive);
|
||||
};
|
||||
|
||||
var RESIZE_INTERVAL = 50;
|
||||
|
@ -400,6 +406,12 @@ var toolBar = (function () {
|
|||
that.setActive(false);
|
||||
});
|
||||
|
||||
Entities.canAdjustLocksChanged.connect(function(canAdjustLocks) {
|
||||
if (isActive && !canAdjustLocks) {
|
||||
that.setActive(false);
|
||||
}
|
||||
});
|
||||
|
||||
that.cleanup = function () {
|
||||
toolBar.cleanup();
|
||||
};
|
||||
|
@ -934,24 +946,37 @@ PropertiesTool = function(opts) {
|
|||
data = {
|
||||
type: 'update',
|
||||
};
|
||||
if (selectionManager.hasSelection()) {
|
||||
data.id = selectionManager.selections[0].id;
|
||||
data.properties = Entities.getEntityProperties(selectionManager.selections[0]);
|
||||
data.properties.rotation = Quat.safeEulerAngles(data.properties.rotation);
|
||||
var selections = [];
|
||||
for (var i = 0; i < selectionManager.selections.length; i++) {
|
||||
var entity = {};
|
||||
entity.id = selectionManager.selections[i].id;
|
||||
entity.properties = Entities.getEntityProperties(selectionManager.selections[i]);
|
||||
entity.properties.rotation = Quat.safeEulerAngles(entity.properties.rotation);
|
||||
selections.push(entity);
|
||||
}
|
||||
data.selections = selections;
|
||||
webView.eventBridge.emitScriptEvent(JSON.stringify(data));
|
||||
});
|
||||
|
||||
webView.eventBridge.webEventReceived.connect(function(data) {
|
||||
print(data);
|
||||
data = JSON.parse(data);
|
||||
if (data.type == "update") {
|
||||
selectionManager.saveProperties();
|
||||
if (data.properties.rotation !== undefined) {
|
||||
var rotation = data.properties.rotation;
|
||||
data.properties.rotation = Quat.fromPitchYawRollDegrees(rotation.x, rotation.y, rotation.z);
|
||||
if (selectionManager.selections.length > 1) {
|
||||
properties = {
|
||||
locked: data.properties.locked,
|
||||
visible: data.properties.visible,
|
||||
};
|
||||
for (var i = 0; i < selectionManager.selections.length; i++) {
|
||||
Entities.editEntity(selectionManager.selections[i], properties);
|
||||
}
|
||||
} else {
|
||||
if (data.properties.rotation !== undefined) {
|
||||
var rotation = data.properties.rotation;
|
||||
data.properties.rotation = Quat.fromPitchYawRollDegrees(rotation.x, rotation.y, rotation.z);
|
||||
}
|
||||
Entities.editEntity(selectionManager.selections[0], data.properties);
|
||||
}
|
||||
Entities.editEntity(selectionManager.selections[0], data.properties);
|
||||
pushCommandForSelections();
|
||||
selectionManager._update();
|
||||
} else if (data.type == "action") {
|
||||
|
|
|
@ -1,57 +0,0 @@
|
|||
//
|
||||
// globalServicesExample.js
|
||||
// examples
|
||||
//
|
||||
// Created by Thijs Wenker on 9/12/14.
|
||||
// Copyright 2014 High Fidelity, Inc.
|
||||
//
|
||||
// Example usage of the GlobalServices object. You could use it to make your own chatbox.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
function onConnected() {
|
||||
if (GlobalServices.onlineUsers.length > 0) {
|
||||
sendMessageForm()
|
||||
return;
|
||||
}
|
||||
Script.setTimeout(function() { sendMessageForm(); }, 5000);
|
||||
}
|
||||
|
||||
function onDisconnected(reason) {
|
||||
switch(reason) {
|
||||
case "logout":
|
||||
Window.alert("logged out!");
|
||||
break;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
function onOnlineUsersChanged(users) {
|
||||
print(users);
|
||||
}
|
||||
|
||||
function onIncommingMessage(user, message) {
|
||||
print(user + ": " + message);
|
||||
if (message === "hello") {
|
||||
GlobalServices.chat("hello, @" + user + "!");
|
||||
}
|
||||
}
|
||||
|
||||
function sendMessageForm() {
|
||||
var form =
|
||||
[
|
||||
{ label: "To:", options: ["(noone)"].concat(GlobalServices.onlineUsers) },
|
||||
{ label: "Message:", value: "Enter message here" }
|
||||
];
|
||||
if (Window.form("Send message on public chat", form)) {
|
||||
GlobalServices.chat(form[0].value == "(noone)" ? form[1].value : "@" + form[0].value + ", " + form[1].value);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
GlobalServices.connected.connect(onConnected);
|
||||
GlobalServices.disconnected.connect(onDisconnected);
|
||||
GlobalServices.onlineUsersChanged.connect(onOnlineUsersChanged);
|
||||
GlobalServices.incomingMessage.connect(onIncommingMessage);
|
34
examples/example/misc/sunLightExample.js
Normal file
34
examples/example/misc/sunLightExample.js
Normal file
|
@ -0,0 +1,34 @@
|
|||
//
|
||||
// SunLightExample.js
|
||||
// examples
|
||||
// Sam Gateau
|
||||
// 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
|
||||
//
|
||||
|
||||
var intensity = 1.0;
|
||||
var day = 0.0;
|
||||
var hour = 12.0;
|
||||
var longitude = 115.0;
|
||||
var latitude = 31.0;
|
||||
var stageOrientation = Quat.fromPitchYawRollDegrees(0.0, 180.0, 0.0);
|
||||
|
||||
Scene.setStageDayTime(hour);
|
||||
Scene.setStageOrientation(stageOrientation);
|
||||
Scene.setStageLocation(longitude, latitude, 0.0);
|
||||
/*
|
||||
function ticktack() {
|
||||
hour += 0.1;
|
||||
//Scene.setSunIntensity(Math.cos(time));
|
||||
if (hour > 24.0) {
|
||||
hour = 0.0;
|
||||
day++;
|
||||
Scene.setStageYearTime(day);
|
||||
}
|
||||
Scene.setStageDayTime(hour);
|
||||
}
|
||||
|
||||
Script.setInterval(ticktack, 41);
|
||||
*/
|
|
@ -1,27 +0,0 @@
|
|||
//
|
||||
// loadScriptFromMessage.js
|
||||
// examples
|
||||
//
|
||||
// Created by Thijs Wenker on 9/15/14.
|
||||
// Copyright 2014 High Fidelity, Inc.
|
||||
//
|
||||
// Filters script links out of incomming messages and prompts you to run the script.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
//Javascript link RegEX
|
||||
const JS_LINK_REGEX = /https?:\/\/[^ ]+\.js/i;
|
||||
|
||||
function onIncomingMessage(user, message) {
|
||||
var script_link = JS_LINK_REGEX.exec(message);
|
||||
if (script_link == null) {
|
||||
return;
|
||||
}
|
||||
if (Window.confirm("@" + user + " sent the following script:\n" + script_link + "\nwould you like to run it?")) {
|
||||
Script.load(script_link);
|
||||
}
|
||||
}
|
||||
|
||||
GlobalServices.incomingMessage.connect(onIncomingMessage);
|
|
@ -20,6 +20,7 @@
|
|||
elRefresh = document.getElementById("refresh");
|
||||
elDelete = document.getElementById("delete");
|
||||
elTeleport = document.getElementById("teleport");
|
||||
elNoEntitiesMessage = document.getElementById("no-entities");
|
||||
|
||||
document.getElementById("entity-type").onclick = function() {
|
||||
setSortColumn('type');
|
||||
|
@ -155,11 +156,18 @@
|
|||
}
|
||||
} else if (data.type == "update") {
|
||||
var newEntities = data.entities;
|
||||
for (var i = 0; i < newEntities.length; i++) {
|
||||
var id = newEntities[i].id;
|
||||
addEntity(id, newEntities[i].type, newEntities[i].url);
|
||||
if (newEntities.length == 0) {
|
||||
elEntityTable.style.display = "none";
|
||||
elNoEntitiesMessage.style.display = "block";
|
||||
} else {
|
||||
elEntityTable.style.display = "table";
|
||||
elNoEntitiesMessage.style.display = "none";
|
||||
for (var i = 0; i < newEntities.length; i++) {
|
||||
var id = newEntities[i].id;
|
||||
addEntity(id, newEntities[i].type, newEntities[i].url);
|
||||
}
|
||||
updateSelectedEntities(data.selectedIDs);
|
||||
}
|
||||
updateSelectedEntities(data.selectedIDs);
|
||||
}
|
||||
});
|
||||
setTimeout(refreshEntities, 1000);
|
||||
|
@ -194,6 +202,8 @@
|
|||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<div id="no-entities">
|
||||
No entities found within 50 meter radius. Try moving to a different location and refreshing.
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
@ -128,21 +128,11 @@
|
|||
|
||||
var elLightSections = document.querySelectorAll(".light-section");
|
||||
var elLightSpotLight = document.getElementById("property-light-spot-light");
|
||||
var elLightDiffuseRed = document.getElementById("property-light-diffuse-red");
|
||||
var elLightDiffuseGreen = document.getElementById("property-light-diffuse-green");
|
||||
var elLightDiffuseBlue = document.getElementById("property-light-diffuse-blue");
|
||||
var elLightColorRed = document.getElementById("property-light-color-red");
|
||||
var elLightColorGreen = document.getElementById("property-light-color-green");
|
||||
var elLightColorBlue = document.getElementById("property-light-color-blue");
|
||||
|
||||
var elLightAmbientRed = document.getElementById("property-light-ambient-red");
|
||||
var elLightAmbientGreen = document.getElementById("property-light-ambient-green");
|
||||
var elLightAmbientBlue = document.getElementById("property-light-ambient-blue");
|
||||
|
||||
var elLightSpecularRed = document.getElementById("property-light-specular-red");
|
||||
var elLightSpecularGreen = document.getElementById("property-light-specular-green");
|
||||
var elLightSpecularBlue = document.getElementById("property-light-specular-blue");
|
||||
|
||||
var elLightConstantAttenuation = document.getElementById("property-light-constant-attenuation");
|
||||
var elLightLinearAttenuation = document.getElementById("property-light-linear-attenuation");
|
||||
var elLightQuadraticAttenuation = document.getElementById("property-light-quadratic-attenuation");
|
||||
var elLightIntensity = document.getElementById("property-light-intensity");
|
||||
var elLightExponent = document.getElementById("property-light-exponent");
|
||||
var elLightCutoff = document.getElementById("property-light-cutoff");
|
||||
|
||||
|
@ -171,12 +161,37 @@
|
|||
EventBridge.scriptEventReceived.connect(function(data) {
|
||||
data = JSON.parse(data);
|
||||
if (data.type == "update") {
|
||||
if (data.properties === undefined) {
|
||||
disableChildren(document.getElementById("properties"), 'input');
|
||||
} else {
|
||||
var properties = data.properties;
|
||||
if (data.selections.length == 0) {
|
||||
elType.innerHTML = "<i>No Selection</i>";
|
||||
elID.innerHTML = "";
|
||||
disableChildren(document.getElementById("properties-list"), 'input');
|
||||
} else if (data.selections.length > 1) {
|
||||
var selections = data.selections;
|
||||
|
||||
elID.innerHTML = data.id;
|
||||
var ids = [];
|
||||
var types = {};
|
||||
|
||||
for (var i = 0; i < selections.length; i++) {
|
||||
ids.push(selections[i].id);
|
||||
var type = selections[i].properties.type;
|
||||
if (types[type] === undefined) {
|
||||
types[type] = 0;
|
||||
}
|
||||
types[type]++;
|
||||
}
|
||||
elID.innerHTML = ids.join("<br>");
|
||||
|
||||
var typeStrs = [];
|
||||
for (type in types) {
|
||||
typeStrs.push(type + " (" + types[type] + ")");
|
||||
}
|
||||
elType.innerHTML = typeStrs.join(", ");
|
||||
|
||||
disableChildren(document.getElementById("properties-list"), 'input');
|
||||
} else {
|
||||
var properties = data.selections[0].properties;
|
||||
|
||||
elID.innerHTML = properties.id;
|
||||
|
||||
elType.innerHTML = properties.type;
|
||||
|
||||
|
@ -290,21 +305,11 @@
|
|||
elLightSections[i].style.display = 'block';
|
||||
}
|
||||
|
||||
elLightDiffuseRed.value = properties.diffuseColor.red;
|
||||
elLightDiffuseGreen.value = properties.diffuseColor.green;
|
||||
elLightDiffuseBlue.value = properties.diffuseColor.blue;
|
||||
elLightColorRed.value = properties.color.red;
|
||||
elLightColorGreen.value = properties.color.green;
|
||||
elLightColorBlue.value = properties.color.blue;
|
||||
|
||||
elLightAmbientRed.value = properties.ambientColor.red;
|
||||
elLightAmbientGreen.value = properties.ambientColor.green;
|
||||
elLightAmbientBlue.value = properties.ambientColor.blue;
|
||||
|
||||
elLightSpecularRed.value = properties.specularColor.red;
|
||||
elLightSpecularGreen.value = properties.specularColor.green;
|
||||
elLightSpecularBlue.value = properties.specularColor.blue;
|
||||
|
||||
elLightConstantAttenuation.value = properties.constantAttenuation;
|
||||
elLightLinearAttenuation.value = properties.linearAttenuation;
|
||||
elLightQuadraticAttenuation.value = properties.quadraticAttenuation;
|
||||
elLightIntensity.value = properties.intensity;
|
||||
elLightExponent.value = properties.exponent;
|
||||
elLightCutoff.value = properties.cutoff;
|
||||
}
|
||||
|
@ -375,27 +380,13 @@
|
|||
|
||||
elLightSpotLight.addEventListener('change', createEmitCheckedPropertyUpdateFunction('isSpotlight'));
|
||||
|
||||
var lightDiffuseChangeFunction = createEmitColorPropertyUpdateFunction(
|
||||
'diffuseColor', elLightDiffuseRed, elLightDiffuseGreen, elLightDiffuseBlue);
|
||||
elLightDiffuseRed.addEventListener('change', lightDiffuseChangeFunction);
|
||||
elLightDiffuseGreen.addEventListener('change', lightDiffuseChangeFunction);
|
||||
elLightDiffuseBlue.addEventListener('change', lightDiffuseChangeFunction);
|
||||
var lightColorChangeFunction = createEmitColorPropertyUpdateFunction(
|
||||
'color', elLightColorRed, elLightColorGreen, elLightColorBlue);
|
||||
elLightColorRed.addEventListener('change', lightColorChangeFunction);
|
||||
elLightColorGreen.addEventListener('change', lightColorChangeFunction);
|
||||
elLightColorBlue.addEventListener('change', lightColorChangeFunction);
|
||||
|
||||
var lightAmbientChangeFunction = createEmitColorPropertyUpdateFunction(
|
||||
'ambientColor', elLightAmbientRed, elLightAmbientGreen, elLightAmbientBlue);
|
||||
elLightAmbientRed.addEventListener('change', lightAmbientChangeFunction);
|
||||
elLightAmbientGreen.addEventListener('change', lightAmbientChangeFunction);
|
||||
elLightAmbientBlue.addEventListener('change', lightAmbientChangeFunction);
|
||||
|
||||
var lightSpecularChangeFunction = createEmitColorPropertyUpdateFunction(
|
||||
'specularColor', elLightSpecularRed, elLightSpecularGreen, elLightSpecularBlue);
|
||||
elLightSpecularRed.addEventListener('change', lightSpecularChangeFunction);
|
||||
elLightSpecularGreen.addEventListener('change', lightSpecularChangeFunction);
|
||||
elLightSpecularBlue.addEventListener('change', lightSpecularChangeFunction);
|
||||
|
||||
elLightConstantAttenuation.addEventListener('change', createEmitNumberPropertyUpdateFunction('constantAttenuation'));
|
||||
elLightLinearAttenuation.addEventListener('change', createEmitNumberPropertyUpdateFunction('linearAttenuation'));
|
||||
elLightQuadraticAttenuation.addEventListener('change', createEmitNumberPropertyUpdateFunction('quadraticAttenuation'));
|
||||
elLightIntensity.addEventListener('change', createEmitNumberPropertyUpdateFunction('intensity'));
|
||||
elLightExponent.addEventListener('change', createEmitNumberPropertyUpdateFunction('exponent'));
|
||||
elLightCutoff.addEventListener('change', createEmitNumberPropertyUpdateFunction('cutoff'));
|
||||
|
||||
|
@ -448,6 +439,13 @@
|
|||
percentage: parseInt(elRescaleDimensionsPct.value),
|
||||
}));
|
||||
});
|
||||
|
||||
window.onblur = function() {
|
||||
// Fake a change event
|
||||
var ev = document.createEvent("HTMLEvents");
|
||||
ev.initEvent("change", true, true);
|
||||
document.activeElement.dispatchEvent(ev);
|
||||
}
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
|
@ -715,55 +713,27 @@
|
|||
</div>
|
||||
</div>
|
||||
<div class="light-section property">
|
||||
<div class="label">Diffuse</div>
|
||||
<div class="label">Color</div>
|
||||
<div class="value">
|
||||
<div class="input-area">R <input class="coord" type='number' id="property-light-diffuse-red"></input></div>
|
||||
<div class="input-area">G <input class="coord" type='number' id="property-light-diffuse-green"></input></div>
|
||||
<div class="input-area">B <input class="coord" type='number' id="property-light-diffuse-blue"></input></div>
|
||||
<div class="input-area">R <input class="coord" type='number' id="property-light-color-red"></input></div>
|
||||
<div class="input-area">G <input class="coord" type='number' id="property-light-color-green"></input></div>
|
||||
<div class="input-area">B <input class="coord" type='number' id="property-light-color-blue"></input></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="light-section property">
|
||||
<div class="label">Ambient</div>
|
||||
<div class="label">Intensity</div>
|
||||
<div class="value">
|
||||
<div class="input-area">R <input class="coord" type='number' id="property-light-ambient-red"></input></div>
|
||||
<div class="input-area">G <input class="coord" type='number' id="property-light-ambient-green"></input></div>
|
||||
<div class="input-area">B <input class="coord" type='number' id="property-light-ambient-blue"></input></div>
|
||||
<input class="coord" type='number' id="property-light-intensity"></input>
|
||||
</div>
|
||||
</div>
|
||||
<div class="light-section property">
|
||||
<div class="label">Specular</div>
|
||||
<div class="value">
|
||||
<div class="input-area">R <input class="coord" type='number' id="property-light-specular-red"></input></div>
|
||||
<div class="input-area">G <input class="coord" type='number' id="property-light-specular-green"></input></div>
|
||||
<div class="input-area">B <input class="coord" type='number' id="property-light-specular-blue"></input></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="light-section property">
|
||||
<div class="label">Constant Attenuation</div>
|
||||
<div class="value">
|
||||
<input class="coord" type='number' id="property-light-constant-attenuation"></input>
|
||||
</div>
|
||||
</div>
|
||||
<div class="light-section property">
|
||||
<div class="label">Linear Attenuation</div>
|
||||
<div class="value">
|
||||
<input class="coord" type='number' id="property-light-linear-attenuation"></input>
|
||||
</div>
|
||||
</div>
|
||||
<div class="light-section property">
|
||||
<div class="label">Quadratic Attenuation</div>
|
||||
<div class="value">
|
||||
<input class="coord" type='number' id="property-light-quadratic-attenuation"></input>
|
||||
</div>
|
||||
</div>
|
||||
<div class="light-section property">
|
||||
<div class="label">Exponent</div>
|
||||
<div class="label">Spot Light Exponent</div>
|
||||
<div class="value">
|
||||
<input class="coord" type='number' id="property-light-exponent"></input>
|
||||
</div>
|
||||
</div>
|
||||
<div class="light-section property">
|
||||
<div class="label">Cutoff (degrees)</div>
|
||||
<div class="label">Spot Light Cutoff (degrees)</div>
|
||||
<div class="value">
|
||||
<input class="coord" type='number' id="property-light-cutoff"></input>
|
||||
</div>
|
||||
|
|
|
@ -189,6 +189,11 @@ input, textarea {
|
|||
font-size: 7.5pt;
|
||||
}
|
||||
|
||||
input:disabled, textarea:disabled {
|
||||
background-color: rgb(102, 102, 102);
|
||||
color: rgb(160, 160, 160);
|
||||
}
|
||||
|
||||
#properties-list input[type=button] {
|
||||
cursor: pointer;
|
||||
background-color: rgb(51, 102, 102);
|
||||
|
@ -199,6 +204,11 @@ input, textarea {
|
|||
color: rgb(204, 204, 204);
|
||||
}
|
||||
|
||||
#properties-list input[type=button]:disabled {
|
||||
background-color: rgb(41, 82, 82);
|
||||
color: rgb(160, 160, 160);
|
||||
}
|
||||
|
||||
#properties-list .property {
|
||||
padding: 6pt 6pt;
|
||||
border-top: 0.75pt solid rgb(63, 63, 63);
|
||||
|
@ -257,3 +267,11 @@ td {
|
|||
|
||||
vertical-align: top;
|
||||
}
|
||||
|
||||
#no-entities {
|
||||
display: none;
|
||||
font-size: 120%;
|
||||
padding: 10pt;
|
||||
font-weight: bold;
|
||||
font-style: italic;
|
||||
}
|
||||
|
|
|
@ -238,12 +238,12 @@ SelectionDisplay = (function () {
|
|||
|
||||
// These are multipliers for sizing the rotation degrees display while rotating an entity
|
||||
var ROTATION_DISPLAY_DISTANCE_MULTIPLIER = 1.2;
|
||||
var ROTATION_DISPLAY_SIZE_X_MULTIPLIER = 0.5;
|
||||
var ROTATION_DISPLAY_SIZE_X_MULTIPLIER = 0.6;
|
||||
var ROTATION_DISPLAY_SIZE_Y_MULTIPLIER = 0.18;
|
||||
var ROTATION_DISPLAY_LINE_HEIGHT_MULTIPLIER = 0.17;
|
||||
var ROTATION_DISPLAY_LINE_HEIGHT_MULTIPLIER = 0.14;
|
||||
|
||||
var ROTATE_ARROW_WEST_NORTH_URL = HIFI_PUBLIC_BUCKET + "images/rotate-arrow-west-north.png";
|
||||
var ROTATE_ARROW_WEST_SOUTH_URL = HIFI_PUBLIC_BUCKET + "images/rotate-arrow-west-south.png";
|
||||
var ROTATE_ARROW_WEST_NORTH_URL = HIFI_PUBLIC_BUCKET + "images/rotate-arrow-west-north.svg";
|
||||
var ROTATE_ARROW_WEST_SOUTH_URL = HIFI_PUBLIC_BUCKET + "images/rotate-arrow-west-south.svg";
|
||||
|
||||
var showExtendedStretchHandles = false;
|
||||
|
||||
|
@ -280,11 +280,11 @@ SelectionDisplay = (function () {
|
|||
var originalRoll;
|
||||
|
||||
|
||||
var rotateHandleColor = { red: 0, green: 0, blue: 0 };
|
||||
var rotateHandleAlpha = 0.7;
|
||||
var handleColor = { red: 255, green: 255, blue: 255 };
|
||||
var handleAlpha = 0.7;
|
||||
|
||||
var highlightedHandleColor = { red: 255, green: 0, blue: 0 };
|
||||
var highlightedHandleAlpha = 0.7;
|
||||
var highlightedHandleColor = { red: 183, green: 64, blue: 44 };
|
||||
var highlightedHandleAlpha = 0.9;
|
||||
|
||||
var previousHandle = false;
|
||||
var previousHandleColor;
|
||||
|
@ -385,10 +385,10 @@ SelectionDisplay = (function () {
|
|||
});
|
||||
|
||||
var grabberMoveUp = Overlays.addOverlay("billboard", {
|
||||
url: HIFI_PUBLIC_BUCKET + "images/up-arrow.png",
|
||||
url: HIFI_PUBLIC_BUCKET + "images/up-arrow.svg",
|
||||
position: { x:0, y: 0, z: 0},
|
||||
color: { red: 0, green: 0, blue: 0 },
|
||||
alpha: 1.0,
|
||||
color: handleColor,
|
||||
alpha: handleAlpha,
|
||||
visible: false,
|
||||
size: 0.1,
|
||||
scale: 0.1,
|
||||
|
@ -533,7 +533,7 @@ SelectionDisplay = (function () {
|
|||
|
||||
var rotateOverlayTarget = Overlays.addOverlay("circle3d", {
|
||||
position: { x:0, y: 0, z: 0},
|
||||
size: rotateOverlayTargetSize,
|
||||
size: rotateOverlayTargetSize * 2,
|
||||
color: { red: 0, green: 0, blue: 0 },
|
||||
alpha: 0.0,
|
||||
solid: true,
|
||||
|
@ -595,8 +595,8 @@ SelectionDisplay = (function () {
|
|||
var yawHandle = Overlays.addOverlay("billboard", {
|
||||
url: ROTATE_ARROW_WEST_NORTH_URL,
|
||||
position: { x:0, y: 0, z: 0},
|
||||
color: rotateHandleColor,
|
||||
alpha: rotateHandleAlpha,
|
||||
color: handleColor,
|
||||
alpha: handleAlpha,
|
||||
visible: false,
|
||||
size: 0.1,
|
||||
scale: 0.1,
|
||||
|
@ -608,8 +608,8 @@ SelectionDisplay = (function () {
|
|||
var pitchHandle = Overlays.addOverlay("billboard", {
|
||||
url: ROTATE_ARROW_WEST_NORTH_URL,
|
||||
position: { x:0, y: 0, z: 0},
|
||||
color: rotateHandleColor,
|
||||
alpha: rotateHandleAlpha,
|
||||
color: handleColor,
|
||||
alpha: handleAlpha,
|
||||
visible: false,
|
||||
size: 0.1,
|
||||
scale: 0.1,
|
||||
|
@ -621,8 +621,8 @@ SelectionDisplay = (function () {
|
|||
var rollHandle = Overlays.addOverlay("billboard", {
|
||||
url: ROTATE_ARROW_WEST_NORTH_URL,
|
||||
position: { x:0, y: 0, z: 0},
|
||||
color: rotateHandleColor,
|
||||
alpha: rotateHandleAlpha,
|
||||
color: handleColor,
|
||||
alpha: handleAlpha,
|
||||
visible: false,
|
||||
size: 0.1,
|
||||
scale: 0.1,
|
||||
|
@ -1692,7 +1692,7 @@ SelectionDisplay = (function () {
|
|||
y: innerRadius * ROTATION_DISPLAY_SIZE_Y_MULTIPLIER
|
||||
},
|
||||
lineHeight: innerRadius * ROTATION_DISPLAY_LINE_HEIGHT_MULTIPLIER,
|
||||
text: normalizeDegrees(angleFromZero),
|
||||
text: normalizeDegrees(angleFromZero) + "°",
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -1713,15 +1713,17 @@ SelectionDisplay = (function () {
|
|||
Overlays.editOverlay(rotateOverlayInner,
|
||||
{
|
||||
visible: true,
|
||||
size: innerRadius,
|
||||
size: innerRadius * 2,
|
||||
innerRadius: 0.9,
|
||||
startAt: 0,
|
||||
endAt: 360,
|
||||
alpha: innerAlpha
|
||||
});
|
||||
|
||||
Overlays.editOverlay(rotateOverlayOuter,
|
||||
{
|
||||
visible: true,
|
||||
size: outerRadius,
|
||||
size: outerRadius * 2,
|
||||
innerRadius: 0.9,
|
||||
startAt: 0,
|
||||
endAt: 360,
|
||||
|
@ -1731,7 +1733,7 @@ SelectionDisplay = (function () {
|
|||
Overlays.editOverlay(rotateOverlayCurrent,
|
||||
{
|
||||
visible: true,
|
||||
size: outerRadius,
|
||||
size: outerRadius * 2,
|
||||
startAt: 0,
|
||||
endAt: 0,
|
||||
innerRadius: 0.9,
|
||||
|
@ -1809,13 +1811,13 @@ SelectionDisplay = (function () {
|
|||
if (snapToInner) {
|
||||
Overlays.editOverlay(rotateOverlayOuter, { startAt: 0, endAt: 360 });
|
||||
Overlays.editOverlay(rotateOverlayInner, { startAt: startAtRemainder, endAt: endAtRemainder });
|
||||
Overlays.editOverlay(rotateOverlayCurrent, { startAt: startAtCurrent, endAt: endAtCurrent, size: innerRadius,
|
||||
Overlays.editOverlay(rotateOverlayCurrent, { startAt: startAtCurrent, endAt: endAtCurrent, size: innerRadius * 2,
|
||||
majorTickMarksAngle: innerSnapAngle, minorTickMarksAngle: 0,
|
||||
majorTickMarksLength: -0.25, minorTickMarksLength: 0, });
|
||||
} else {
|
||||
Overlays.editOverlay(rotateOverlayInner, { startAt: 0, endAt: 360 });
|
||||
Overlays.editOverlay(rotateOverlayOuter, { startAt: startAtRemainder, endAt: endAtRemainder });
|
||||
Overlays.editOverlay(rotateOverlayCurrent, { startAt: startAtCurrent, endAt: endAtCurrent, size: outerRadius,
|
||||
Overlays.editOverlay(rotateOverlayCurrent, { startAt: startAtCurrent, endAt: endAtCurrent, size: outerRadius * 2,
|
||||
majorTickMarksAngle: 45.0, minorTickMarksAngle: 5,
|
||||
majorTickMarksLength: 0.25, minorTickMarksLength: 0.1, });
|
||||
}
|
||||
|
@ -1840,15 +1842,17 @@ SelectionDisplay = (function () {
|
|||
Overlays.editOverlay(rotateOverlayInner,
|
||||
{
|
||||
visible: true,
|
||||
size: innerRadius,
|
||||
size: innerRadius * 2,
|
||||
innerRadius: 0.9,
|
||||
startAt: 0,
|
||||
endAt: 360,
|
||||
alpha: innerAlpha
|
||||
});
|
||||
|
||||
Overlays.editOverlay(rotateOverlayOuter,
|
||||
{
|
||||
visible: true,
|
||||
size: outerRadius,
|
||||
size: outerRadius * 2,
|
||||
innerRadius: 0.9,
|
||||
startAt: 0,
|
||||
endAt: 360,
|
||||
|
@ -1858,7 +1862,7 @@ SelectionDisplay = (function () {
|
|||
Overlays.editOverlay(rotateOverlayCurrent,
|
||||
{
|
||||
visible: true,
|
||||
size: outerRadius,
|
||||
size: outerRadius * 2,
|
||||
startAt: 0,
|
||||
endAt: 0,
|
||||
innerRadius: 0.9,
|
||||
|
@ -1929,13 +1933,13 @@ SelectionDisplay = (function () {
|
|||
if (snapToInner) {
|
||||
Overlays.editOverlay(rotateOverlayOuter, { startAt: 0, endAt: 360 });
|
||||
Overlays.editOverlay(rotateOverlayInner, { startAt: startAtRemainder, endAt: endAtRemainder });
|
||||
Overlays.editOverlay(rotateOverlayCurrent, { startAt: startAtCurrent, endAt: endAtCurrent, size: innerRadius,
|
||||
Overlays.editOverlay(rotateOverlayCurrent, { startAt: startAtCurrent, endAt: endAtCurrent, size: innerRadius * 2,
|
||||
majorTickMarksAngle: innerSnapAngle, minorTickMarksAngle: 0,
|
||||
majorTickMarksLength: -0.25, minorTickMarksLength: 0, });
|
||||
} else {
|
||||
Overlays.editOverlay(rotateOverlayInner, { startAt: 0, endAt: 360 });
|
||||
Overlays.editOverlay(rotateOverlayOuter, { startAt: startAtRemainder, endAt: endAtRemainder });
|
||||
Overlays.editOverlay(rotateOverlayCurrent, { startAt: startAtCurrent, endAt: endAtCurrent, size: outerRadius,
|
||||
Overlays.editOverlay(rotateOverlayCurrent, { startAt: startAtCurrent, endAt: endAtCurrent, size: outerRadius * 2,
|
||||
majorTickMarksAngle: 45.0, minorTickMarksAngle: 5,
|
||||
majorTickMarksLength: 0.25, minorTickMarksLength: 0.1, });
|
||||
}
|
||||
|
@ -1959,15 +1963,17 @@ SelectionDisplay = (function () {
|
|||
Overlays.editOverlay(rotateOverlayInner,
|
||||
{
|
||||
visible: true,
|
||||
size: innerRadius,
|
||||
size: innerRadius * 2,
|
||||
innerRadius: 0.9,
|
||||
startAt: 0,
|
||||
endAt: 360,
|
||||
alpha: innerAlpha
|
||||
});
|
||||
|
||||
Overlays.editOverlay(rotateOverlayOuter,
|
||||
{
|
||||
visible: true,
|
||||
size: outerRadius,
|
||||
size: outerRadius * 2,
|
||||
innerRadius: 0.9,
|
||||
startAt: 0,
|
||||
endAt: 360,
|
||||
|
@ -1977,7 +1983,7 @@ SelectionDisplay = (function () {
|
|||
Overlays.editOverlay(rotateOverlayCurrent,
|
||||
{
|
||||
visible: true,
|
||||
size: outerRadius,
|
||||
size: outerRadius * 2,
|
||||
startAt: 0,
|
||||
endAt: 0,
|
||||
innerRadius: 0.9,
|
||||
|
@ -2047,13 +2053,13 @@ SelectionDisplay = (function () {
|
|||
if (snapToInner) {
|
||||
Overlays.editOverlay(rotateOverlayOuter, { startAt: 0, endAt: 360 });
|
||||
Overlays.editOverlay(rotateOverlayInner, { startAt: startAtRemainder, endAt: endAtRemainder });
|
||||
Overlays.editOverlay(rotateOverlayCurrent, { startAt: startAtCurrent, endAt: endAtCurrent, size: innerRadius,
|
||||
Overlays.editOverlay(rotateOverlayCurrent, { startAt: startAtCurrent, endAt: endAtCurrent, size: innerRadius * 2,
|
||||
majorTickMarksAngle: innerSnapAngle, minorTickMarksAngle: 0,
|
||||
majorTickMarksLength: -0.25, minorTickMarksLength: 0, });
|
||||
} else {
|
||||
Overlays.editOverlay(rotateOverlayInner, { startAt: 0, endAt: 360 });
|
||||
Overlays.editOverlay(rotateOverlayOuter, { startAt: startAtRemainder, endAt: endAtRemainder });
|
||||
Overlays.editOverlay(rotateOverlayCurrent, { startAt: startAtCurrent, endAt: endAtCurrent, size: outerRadius,
|
||||
Overlays.editOverlay(rotateOverlayCurrent, { startAt: startAtCurrent, endAt: endAtCurrent, size: outerRadius * 2,
|
||||
majorTickMarksAngle: 45.0, minorTickMarksAngle: 5,
|
||||
majorTickMarksLength: 0.25, minorTickMarksLength: 0.1, });
|
||||
}
|
||||
|
@ -2342,14 +2348,14 @@ SelectionDisplay = (function () {
|
|||
case yawHandle:
|
||||
case pitchHandle:
|
||||
case rollHandle:
|
||||
pickedColor = rotateHandleColor;
|
||||
pickedAlpha = rotateHandleAlpha;
|
||||
pickedColor = handleColor;
|
||||
pickedAlpha = handleAlpha;
|
||||
highlightNeeded = true;
|
||||
break;
|
||||
|
||||
case grabberMoveUp:
|
||||
pickedColor = rotateHandleColor;
|
||||
pickedAlpha = rotateHandleAlpha;
|
||||
pickedColor = handleColor;
|
||||
pickedAlpha = handleAlpha;
|
||||
highlightNeeded = true;
|
||||
break;
|
||||
|
||||
|
|
|
@ -14,32 +14,28 @@
|
|||
// This script generates notifications created via a number of ways, such as:
|
||||
// keystroke:
|
||||
//
|
||||
// "q" returns number of users currently online (for debug purposes)
|
||||
|
||||
// CTRL/s for snapshot.
|
||||
// CTRL/m for mic mute and unmute.
|
||||
|
||||
// System generated notifications:
|
||||
// Displays users online at startup.
|
||||
// If Screen is resized.
|
||||
// Triggers notification if @MyUserName is mentioned in chat.
|
||||
// Announces existing user logging out.
|
||||
// Announces new user logging in.
|
||||
// If mic is muted for any reason.
|
||||
//
|
||||
// To add a new System notification type:
|
||||
//
|
||||
// 1. Set the Event Connector at the bottom of the script.
|
||||
// example:
|
||||
// GlobalServices.incomingMessage.connect(onIncomingMessage);
|
||||
// AudioDevice.muteToggled.connect(onMuteStateChanged);
|
||||
//
|
||||
// 2. Create a new function to produce a text string, do not include new line returns.
|
||||
// example:
|
||||
// function onIncomingMessage(user, message) {
|
||||
// //do stuff here;
|
||||
// var text = "This is a notification";
|
||||
// var wrappedText = wordWrap(text);
|
||||
// createNotification(wrappedText, NotificationType.SNAPSHOT);
|
||||
// function onMuteStateChanged() {
|
||||
// var muteState,
|
||||
// muteString;
|
||||
//
|
||||
// muteState = AudioDevice.getMuted() ? "muted" : "unmuted";
|
||||
// muteString = "Microphone is now " + muteState;
|
||||
// createNotification(muteString, NotificationType.MUTE_TOGGLE);
|
||||
// }
|
||||
//
|
||||
// This new function must call wordWrap(text) if the length of message is longer than 42 chars or unknown.
|
||||
|
@ -54,11 +50,12 @@
|
|||
// 2. Declare a text string.
|
||||
// 3. Call createNotifications(text, NotificationType) parsing the text.
|
||||
// example:
|
||||
// var welcome;
|
||||
// if (key.text == "q") { //queries number of users online
|
||||
// var welcome = "There are " + GlobalServices.onlineUsers.length + " users online now.";
|
||||
// createNotification(welcome, NotificationType.USERS_ONLINE);
|
||||
// }
|
||||
// if (key.text === "s") {
|
||||
// if (ctrlIsPressed === true) {
|
||||
// noteString = "Snapshot taken.";
|
||||
// createNotification(noteString, NotificationType.SNAPSHOT);
|
||||
// }
|
||||
// }
|
||||
Script.include("./libraries/globals.js");
|
||||
Script.include("./libraries/soundArray.js");
|
||||
|
||||
|
@ -81,8 +78,6 @@ var frame = 0;
|
|||
var ourWidth = Window.innerWidth;
|
||||
var ourHeight = Window.innerHeight;
|
||||
var text = "placeholder";
|
||||
var last_users = GlobalServices.onlineUsers;
|
||||
var users = [];
|
||||
var ctrlIsPressed = false;
|
||||
var ready = true;
|
||||
var MENU_NAME = 'Tools > Notifications';
|
||||
|
@ -93,19 +88,11 @@ var PLAY_NOTIFICATION_SOUNDS_TYPE_SETTING_PRE = "play_notification_sounds_type_"
|
|||
|
||||
var NotificationType = {
|
||||
UNKNOWN: 0,
|
||||
USER_JOINS: 1,
|
||||
USER_LEAVES: 2,
|
||||
MUTE_TOGGLE: 3,
|
||||
CHAT_MENTION: 4,
|
||||
USERS_ONLINE: 5,
|
||||
SNAPSHOT: 6,
|
||||
WINDOW_RESIZE: 7,
|
||||
MUTE_TOGGLE: 1,
|
||||
SNAPSHOT: 2,
|
||||
WINDOW_RESIZE: 3,
|
||||
properties: [
|
||||
{ text: "User Join" },
|
||||
{ text: "User Leave" },
|
||||
{ text: "Mute Toggle" },
|
||||
{ text: "Chat Mention" },
|
||||
{ text: "Users Online" },
|
||||
{ text: "Snapshot" },
|
||||
{ text: "Window Resize" }
|
||||
],
|
||||
|
@ -476,15 +463,9 @@ var STARTUP_TIMEOUT = 500, // ms
|
|||
startingUp = true,
|
||||
startupTimer = null;
|
||||
|
||||
// This reports the number of users online at startup
|
||||
function reportUsers() {
|
||||
createNotification("Welcome! There are " + GlobalServices.onlineUsers.length + " users online now.", NotificationType.USERS_ONLINE);
|
||||
}
|
||||
|
||||
function finishStartup() {
|
||||
startingUp = false;
|
||||
Script.clearTimeout(startupTimer);
|
||||
reportUsers();
|
||||
}
|
||||
|
||||
function isStartingUp() {
|
||||
|
@ -498,42 +479,6 @@ function isStartingUp() {
|
|||
return startingUp;
|
||||
}
|
||||
|
||||
// Triggers notification if a user logs on or off
|
||||
function onOnlineUsersChanged(users) {
|
||||
var i;
|
||||
|
||||
if (!isStartingUp()) { // Skip user notifications at startup.
|
||||
for (i = 0; i < users.length; i += 1) {
|
||||
if (last_users.indexOf(users[i]) === -1.0) {
|
||||
createNotification(users[i] + " has joined", NotificationType.USER_JOINS);
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < last_users.length; i += 1) {
|
||||
if (users.indexOf(last_users[i]) === -1.0) {
|
||||
createNotification(last_users[i] + " has left", NotificationType.USER_LEAVES);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
last_users = users;
|
||||
}
|
||||
|
||||
// Triggers notification if @MyUserName is mentioned in chat and returns the message to the notification.
|
||||
function onIncomingMessage(user, message) {
|
||||
var myMessage,
|
||||
alertMe,
|
||||
thisAlert;
|
||||
|
||||
myMessage = message;
|
||||
alertMe = "@" + GlobalServices.myUsername;
|
||||
thisAlert = user + ": " + myMessage;
|
||||
|
||||
if (myMessage.indexOf(alertMe) > -1.0) {
|
||||
CreateNotification(wordWrap(thisAlert), NotificationType.CHAT_MENTION);
|
||||
}
|
||||
}
|
||||
|
||||
// Triggers mic mute notification
|
||||
function onMuteStateChanged() {
|
||||
var muteState,
|
||||
|
@ -573,20 +518,12 @@ function keyReleaseEvent(key) {
|
|||
|
||||
// Triggers notification on specific key driven events
|
||||
function keyPressEvent(key) {
|
||||
var numUsers,
|
||||
welcome,
|
||||
noteString;
|
||||
var noteString;
|
||||
|
||||
if (key.key === 16777249) {
|
||||
ctrlIsPressed = true;
|
||||
}
|
||||
|
||||
if (key.text === "q") { //queries number of users online
|
||||
numUsers = GlobalServices.onlineUsers.length;
|
||||
welcome = "There are " + numUsers + " users online now.";
|
||||
createNotification(welcome, NotificationType.USERS_ONLINE);
|
||||
}
|
||||
|
||||
if (key.text === "s") {
|
||||
if (ctrlIsPressed === true) {
|
||||
noteString = "Snapshot taken.";
|
||||
|
@ -641,8 +578,6 @@ function menuItemEvent(menuItem) {
|
|||
AudioDevice.muteToggled.connect(onMuteStateChanged);
|
||||
Controller.keyPressEvent.connect(keyPressEvent);
|
||||
Controller.mousePressEvent.connect(mousePressEvent);
|
||||
GlobalServices.onlineUsersChanged.connect(onOnlineUsersChanged);
|
||||
GlobalServices.incomingMessage.connect(onIncomingMessage);
|
||||
Controller.keyReleaseEvent.connect(keyReleaseEvent);
|
||||
Script.update.connect(update);
|
||||
Script.scriptEnding.connect(scriptEnding);
|
||||
|
|
|
@ -2,7 +2,7 @@ set(TARGET_NAME interface)
|
|||
project(${TARGET_NAME})
|
||||
|
||||
# set a default root dir for each of our optional externals if it was not passed
|
||||
set(OPTIONAL_EXTERNALS "Faceshift" "LibOVR" "PrioVR" "Sixense" "LeapMotion" "RtMidi" "Qxmpp" "SDL2" "RSSDK")
|
||||
set(OPTIONAL_EXTERNALS "Faceshift" "LibOVR" "Sixense" "LeapMotion" "RtMidi" "SDL2" "RSSDK")
|
||||
foreach(EXTERNAL ${OPTIONAL_EXTERNALS})
|
||||
string(TOUPPER ${EXTERNAL} ${EXTERNAL}_UPPERCASE)
|
||||
if (NOT ${${EXTERNAL}_UPPERCASE}_ROOT_DIR)
|
||||
|
@ -115,11 +115,11 @@ target_include_directories(${TARGET_NAME} SYSTEM PRIVATE ${BULLET_INCLUDE_DIRS})
|
|||
target_link_libraries(${TARGET_NAME} ${BULLET_LIBRARIES})
|
||||
|
||||
# link required hifi libraries
|
||||
link_hifi_libraries(shared octree environment gpu model fbx metavoxels networking entities avatars
|
||||
link_hifi_libraries(shared octree environment gpu model fbx networking entities avatars
|
||||
audio audio-client animation script-engine physics
|
||||
render-utils entities-renderer)
|
||||
|
||||
add_dependency_external_projects(sdl2 qxmpp)
|
||||
add_dependency_external_projects(sdl2)
|
||||
|
||||
# perform standard include and linking for found externals
|
||||
foreach(EXTERNAL ${OPTIONAL_EXTERNALS})
|
||||
|
@ -175,16 +175,6 @@ if (RTMIDI_FOUND AND NOT DISABLE_RTMIDI AND APPLE)
|
|||
target_link_libraries(${TARGET_NAME} ${CoreMIDI})
|
||||
endif ()
|
||||
|
||||
if (QXMPP_FOUND AND NOT DISABLE_QXMPP AND WIN32)
|
||||
if (NOT QXMPP_DLL_PATH)
|
||||
# if we have no QXmpp DLL path, assume we're linking a static QXmpp on windows
|
||||
add_definitions(-DQXMPP_STATIC)
|
||||
else ()
|
||||
# otherwise assume we are linking a dynamic QXmpp
|
||||
add_definitions(-DQXMPP_SHARED)
|
||||
endif ()
|
||||
endif ()
|
||||
|
||||
# include headers for interface and InterfaceConfig.
|
||||
include_directories("${PROJECT_SOURCE_DIR}/src" "${PROJECT_BINARY_DIR}/includes")
|
||||
|
||||
|
|
16
interface/external/priovr/readme.txt
vendored
16
interface/external/priovr/readme.txt
vendored
|
@ -1,16 +0,0 @@
|
|||
|
||||
Instructions for adding the PrioVR driver to Interface
|
||||
Andrzej Kapolka, May 12, 2014
|
||||
|
||||
1. Download and install the YEI drivers from https://www.yeitechnology.com/yei-3-space-sensor-software-suite. If using
|
||||
Window 8+, follow the workaround instructions at http://forum.yeitechnology.com/viewtopic.php?f=3&t=24.
|
||||
|
||||
2. Get the PrioVR skeleton API, open ts_c_api2_priovr2/visual_studio/ThreeSpace_API_2/ThreeSpace_API_2.sln
|
||||
in Visual Studio, and build it.
|
||||
|
||||
3. Copy ts_c_api2_priovr2/visual_studio/ThreeSpace_API_2/Skeletal_API/yei_skeletal_api.h to interface/external/priovr/include,
|
||||
ts_c_api2_priovr2/visual_studio/ThreeSpace_API_2/Debug/Skeletal_API.lib to interface/external/priovr/lib, and
|
||||
ts_c_api2_priovr2/visual_studio/ThreeSpace_API_2/Debug/*.dll to your path.
|
||||
|
||||
4. Delete your build directory, run cmake and build, and you should be all set.
|
||||
|
|
@ -52,6 +52,7 @@
|
|||
#include <QMediaPlayer>
|
||||
#include <QMimeData>
|
||||
#include <QMessageBox>
|
||||
#include <QJsonDocument>
|
||||
|
||||
#include <AddressManager.h>
|
||||
#include <AccountManager.h>
|
||||
|
@ -75,13 +76,15 @@
|
|||
#include <PhysicsEngine.h>
|
||||
#include <ProgramObject.h>
|
||||
#include <ResourceCache.h>
|
||||
#include <ScriptCache.h>
|
||||
//#include <ScriptCache.h>
|
||||
#include <SettingHandle.h>
|
||||
#include <SoundCache.h>
|
||||
#include <TextRenderer.h>
|
||||
#include <UserActivityLogger.h>
|
||||
#include <UUID.h>
|
||||
|
||||
#include <SceneScriptingInterface.h>
|
||||
|
||||
#include "Application.h"
|
||||
#include "AudioClient.h"
|
||||
#include "InterfaceVersion.h"
|
||||
|
@ -215,11 +218,10 @@ bool setupEssentials(int& argc, char** argv) {
|
|||
DependencyManager::registerInheritance<AvatarHashMap, AvatarManager>();
|
||||
|
||||
// Set dependencies
|
||||
auto glCanvas = DependencyManager::set<GLCanvas>();
|
||||
auto addressManager = DependencyManager::set<AddressManager>();
|
||||
auto nodeList = DependencyManager::set<NodeList>(NodeType::Agent, listenPort);
|
||||
auto geometryCache = DependencyManager::set<GeometryCache>();
|
||||
auto scriptCache = DependencyManager::set<ScriptCache>();
|
||||
//auto scriptCache = DependencyManager::set<ScriptCache>();
|
||||
auto soundCache = DependencyManager::set<SoundCache>();
|
||||
auto glowEffect = DependencyManager::set<GlowEffect>();
|
||||
auto faceshift = DependencyManager::set<Faceshift>();
|
||||
|
@ -240,6 +242,7 @@ bool setupEssentials(int& argc, char** argv) {
|
|||
auto dialogsManager = DependencyManager::set<DialogsManager>();
|
||||
auto bandwidthRecorder = DependencyManager::set<BandwidthRecorder>();
|
||||
auto resouceCacheSharedItems = DependencyManager::set<ResouceCacheSharedItems>();
|
||||
auto entityScriptingInterface = DependencyManager::set<EntityScriptingInterface>();
|
||||
#if defined(Q_OS_MAC) || defined(Q_OS_WIN)
|
||||
auto speechRecognizer = DependencyManager::set<SpeechRecognizer>();
|
||||
#endif
|
||||
|
@ -307,7 +310,6 @@ Application::Application(int& argc, char** argv, QElapsedTimer &startup_time) :
|
|||
|
||||
Model::setAbstractViewStateInterface(this); // The model class will sometimes need to know view state details from us
|
||||
|
||||
auto glCanvas = DependencyManager::get<GLCanvas>();
|
||||
auto nodeList = DependencyManager::get<NodeList>();
|
||||
|
||||
_myAvatar = DependencyManager::get<AvatarManager>()->getMyAvatar();
|
||||
|
@ -416,8 +418,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer &startup_time) :
|
|||
|
||||
// tell the NodeList instance who to tell the domain server we care about
|
||||
nodeList->addSetOfNodeTypesToNodeInterestSet(NodeSet() << NodeType::AudioMixer << NodeType::AvatarMixer
|
||||
<< NodeType::EntityServer
|
||||
<< NodeType::MetavoxelServer);
|
||||
<< NodeType::EntityServer);
|
||||
|
||||
// connect to the packet sent signal of the _entityEditSender
|
||||
connect(&_entityEditSender, &EntityEditPacketSender::packetSent, this, &Application::packetSent);
|
||||
|
@ -447,16 +448,16 @@ Application::Application(int& argc, char** argv, QElapsedTimer &startup_time) :
|
|||
|
||||
ResourceCache::setRequestLimit(3);
|
||||
|
||||
_window->setCentralWidget(glCanvas.data());
|
||||
_window->setCentralWidget(_glWidget);
|
||||
|
||||
_window->restoreGeometry();
|
||||
|
||||
_window->setVisible(true);
|
||||
glCanvas->setFocusPolicy(Qt::StrongFocus);
|
||||
glCanvas->setFocus();
|
||||
_glWidget->setFocusPolicy(Qt::StrongFocus);
|
||||
_glWidget->setFocus();
|
||||
|
||||
// enable mouse tracking; otherwise, we only get drag events
|
||||
glCanvas->setMouseTracking(true);
|
||||
_glWidget->setMouseTracking(true);
|
||||
|
||||
_toolWindow = new ToolWindow();
|
||||
_toolWindow->setWindowFlags(_toolWindow->windowFlags() | Qt::WindowStaysOnTopHint);
|
||||
|
@ -474,7 +475,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer &startup_time) :
|
|||
|
||||
checkVersion();
|
||||
|
||||
_overlays.init(glCanvas.data()); // do this before scripts load
|
||||
_overlays.init(); // do this before scripts load
|
||||
|
||||
_runningScriptsWidget->setRunningScripts(getRunningScripts());
|
||||
connect(_runningScriptsWidget, &RunningScriptsWidget::stopScriptName, this, &Application::stopScript);
|
||||
|
@ -533,7 +534,7 @@ void Application::aboutToQuit() {
|
|||
}
|
||||
|
||||
void Application::cleanupBeforeQuit() {
|
||||
|
||||
_datagramProcessor.shutdown(); // tell the datagram processor we're shutting down, so it can short circuit
|
||||
_entities.shutdown(); // tell the entities system we're shutting down, so it will stop running scripts
|
||||
ScriptEngine::stopAllScripts(this); // stop all currently running global scripts
|
||||
|
||||
|
@ -584,8 +585,6 @@ Application::~Application() {
|
|||
_entities.getTree()->setSimulation(NULL);
|
||||
tree->unlock();
|
||||
|
||||
qInstallMessageHandler(NULL);
|
||||
|
||||
// ask the datagram processing thread to quit and wait until it is done
|
||||
_nodeThread->quit();
|
||||
_nodeThread->wait();
|
||||
|
@ -599,13 +598,13 @@ Application::~Application() {
|
|||
|
||||
ModelEntityItem::cleanupLoadedAnimations() ;
|
||||
|
||||
DependencyManager::destroy<GLCanvas>();
|
||||
|
||||
DependencyManager::destroy<AnimationCache>();
|
||||
DependencyManager::destroy<TextureCache>();
|
||||
DependencyManager::destroy<GeometryCache>();
|
||||
DependencyManager::destroy<ScriptCache>();
|
||||
//DependencyManager::destroy<ScriptCache>();
|
||||
DependencyManager::destroy<SoundCache>();
|
||||
|
||||
qInstallMessageHandler(NULL); // NOTE: Do this as late as possible so we continue to get our log messages
|
||||
}
|
||||
|
||||
void Application::initializeGL() {
|
||||
|
@ -690,7 +689,7 @@ void Application::paintGL() {
|
|||
if (OculusManager::isConnected()) {
|
||||
DependencyManager::get<TextureCache>()->setFrameBufferSize(OculusManager::getRenderTargetSize());
|
||||
} else {
|
||||
QSize fbSize = DependencyManager::get<GLCanvas>()->getDeviceSize() * getRenderResolutionScale();
|
||||
QSize fbSize = _glWidget->getDeviceSize() * getRenderResolutionScale();
|
||||
DependencyManager::get<TextureCache>()->setFrameBufferSize(fbSize);
|
||||
}
|
||||
|
||||
|
@ -1057,8 +1056,7 @@ void Application::keyPressEvent(QKeyEvent* event) {
|
|||
if (isShifted) {
|
||||
_viewFrustum.setFocalLength(_viewFrustum.getFocalLength() - 0.1f);
|
||||
if (TV3DManager::isConnected()) {
|
||||
auto glCanvas = DependencyManager::get<GLCanvas>();
|
||||
TV3DManager::configureCamera(_myCamera, glCanvas->getDeviceWidth(), glCanvas->getDeviceHeight());
|
||||
TV3DManager::configureCamera(_myCamera, _glWidget->getDeviceWidth(), _glWidget->getDeviceHeight());
|
||||
}
|
||||
} else {
|
||||
_myCamera.setEyeOffsetPosition(_myCamera.getEyeOffsetPosition() + glm::vec3(-0.001, 0, 0));
|
||||
|
@ -1070,8 +1068,7 @@ void Application::keyPressEvent(QKeyEvent* event) {
|
|||
if (isShifted) {
|
||||
_viewFrustum.setFocalLength(_viewFrustum.getFocalLength() + 0.1f);
|
||||
if (TV3DManager::isConnected()) {
|
||||
auto glCanvas = DependencyManager::get<GLCanvas>();
|
||||
TV3DManager::configureCamera(_myCamera, glCanvas->getDeviceWidth(), glCanvas->getDeviceHeight());
|
||||
TV3DManager::configureCamera(_myCamera, _glWidget->getDeviceWidth(), _glWidget->getDeviceHeight());
|
||||
}
|
||||
|
||||
} else {
|
||||
|
@ -1448,8 +1445,7 @@ void Application::sendPingPackets() {
|
|||
QByteArray pingPacket = DependencyManager::get<NodeList>()->constructPingPacket();
|
||||
controlledBroadcastToNodes(pingPacket, NodeSet()
|
||||
<< NodeType::EntityServer
|
||||
<< NodeType::AudioMixer << NodeType::AvatarMixer
|
||||
<< NodeType::MetavoxelServer);
|
||||
<< NodeType::AudioMixer << NodeType::AvatarMixer);
|
||||
}
|
||||
|
||||
// Every second, check the frame rates and other stuff
|
||||
|
@ -1500,7 +1496,7 @@ void Application::idle() {
|
|||
{
|
||||
PerformanceTimer perfTimer("updateGL");
|
||||
PerformanceWarning warn(showWarnings, "Application::idle()... updateGL()");
|
||||
DependencyManager::get<GLCanvas>()->updateGL();
|
||||
_glWidget->updateGL();
|
||||
}
|
||||
{
|
||||
PerformanceTimer perfTimer("rest");
|
||||
|
@ -1541,8 +1537,7 @@ void Application::setFullscreen(bool fullscreen) {
|
|||
}
|
||||
|
||||
void Application::setEnable3DTVMode(bool enable3DTVMode) {
|
||||
auto glCanvas = DependencyManager::get<GLCanvas>();
|
||||
resizeGL(glCanvas->getDeviceWidth(), glCanvas->getDeviceHeight());
|
||||
resizeGL(_glWidget->getDeviceWidth(), _glWidget->getDeviceHeight());
|
||||
}
|
||||
|
||||
void Application::setEnableVRMode(bool enableVRMode) {
|
||||
|
@ -1567,8 +1562,7 @@ void Application::setEnableVRMode(bool enableVRMode) {
|
|||
_myCamera.setHmdRotation(glm::quat());
|
||||
}
|
||||
|
||||
auto glCanvas = DependencyManager::get<GLCanvas>();
|
||||
resizeGL(glCanvas->getDeviceWidth(), glCanvas->getDeviceHeight());
|
||||
resizeGL(_glWidget->getDeviceWidth(), _glWidget->getDeviceHeight());
|
||||
|
||||
updateCursorVisibility();
|
||||
}
|
||||
|
@ -1579,9 +1573,8 @@ void Application::setLowVelocityFilter(bool lowVelocityFilter) {
|
|||
|
||||
bool Application::mouseOnScreen() const {
|
||||
if (OculusManager::isConnected()) {
|
||||
auto glCanvas = DependencyManager::get<GLCanvas>();
|
||||
return getMouseX() >= 0 && getMouseX() <= glCanvas->getDeviceWidth() &&
|
||||
getMouseY() >= 0 && getMouseY() <= glCanvas->getDeviceHeight();
|
||||
return getMouseX() >= 0 && getMouseX() <= _glWidget->getDeviceWidth() &&
|
||||
getMouseY() >= 0 && getMouseY() <= _glWidget->getDeviceHeight();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
@ -1773,8 +1766,10 @@ void Application::init() {
|
|||
tree->setSimulation(&_physicsEngine);
|
||||
_physicsEngine.init(&_entityEditSender);
|
||||
|
||||
auto entityScriptingInterface = DependencyManager::get<EntityScriptingInterface>();
|
||||
|
||||
connect(&_physicsEngine, &EntitySimulation::entityCollisionWithEntity,
|
||||
ScriptEngine::getEntityScriptingInterface(), &EntityScriptingInterface::entityCollisionWithEntity);
|
||||
entityScriptingInterface.data(), &EntityScriptingInterface::entityCollisionWithEntity);
|
||||
|
||||
// connect the _entityCollisionSystem to our EntityTreeRenderer since that's what handles running entity scripts
|
||||
connect(&_physicsEngine, &EntitySimulation::entityCollisionWithEntity,
|
||||
|
@ -1782,16 +1777,13 @@ void Application::init() {
|
|||
|
||||
// connect the _entities (EntityTreeRenderer) to our script engine's EntityScriptingInterface for firing
|
||||
// of events related clicking, hovering over, and entering entities
|
||||
_entities.connectSignalsToSlots(ScriptEngine::getEntityScriptingInterface());
|
||||
_entities.connectSignalsToSlots(entityScriptingInterface.data());
|
||||
|
||||
_entityClipboardRenderer.init();
|
||||
_entityClipboardRenderer.setViewFrustum(getViewFrustum());
|
||||
_entityClipboardRenderer.setTree(&_entityClipboard);
|
||||
|
||||
_metavoxels.init();
|
||||
|
||||
auto glCanvas = DependencyManager::get<GLCanvas>();
|
||||
_rearMirrorTools = new RearMirrorTools(glCanvas.data(), _mirrorViewRect);
|
||||
_rearMirrorTools = new RearMirrorTools(_glWidget, _mirrorViewRect);
|
||||
|
||||
connect(_rearMirrorTools, SIGNAL(closeView()), SLOT(closeMirrorView()));
|
||||
connect(_rearMirrorTools, SIGNAL(restoreView()), SLOT(restoreMirrorView()));
|
||||
|
@ -1799,10 +1791,10 @@ void Application::init() {
|
|||
connect(_rearMirrorTools, SIGNAL(resetView()), SLOT(resetSensors()));
|
||||
|
||||
// make sure our texture cache knows about window size changes
|
||||
DependencyManager::get<TextureCache>()->associateWithWidget(glCanvas.data());
|
||||
DependencyManager::get<TextureCache>()->associateWithWidget(_glWidget);
|
||||
|
||||
// initialize the GlowEffect with our widget
|
||||
DependencyManager::get<GlowEffect>()->init(glCanvas.data(),
|
||||
DependencyManager::get<GlowEffect>()->init(_glWidget,
|
||||
Menu::getInstance()->isOptionChecked(MenuOption::EnableGlowEffect));
|
||||
}
|
||||
|
||||
|
@ -1868,35 +1860,6 @@ void Application::updateMouseRay() {
|
|||
}
|
||||
}
|
||||
|
||||
void Application::updateFaceshift() {
|
||||
bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings);
|
||||
PerformanceWarning warn(showWarnings, "Application::updateFaceshift()");
|
||||
auto faceshift = DependencyManager::get<Faceshift>();
|
||||
// Update faceshift
|
||||
faceshift->update();
|
||||
|
||||
// Copy angular velocity if measured by faceshift, to the head
|
||||
if (faceshift->isActive()) {
|
||||
_myAvatar->getHead()->setAngularVelocity(faceshift->getHeadAngularVelocity());
|
||||
}
|
||||
}
|
||||
|
||||
void Application::updateVisage() {
|
||||
bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings);
|
||||
PerformanceWarning warn(showWarnings, "Application::updateVisage()");
|
||||
|
||||
// Update Visage
|
||||
DependencyManager::get<Visage>()->update();
|
||||
}
|
||||
|
||||
void Application::updateDDE() {
|
||||
bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings);
|
||||
PerformanceWarning warn(showWarnings, "Application::updateDDE()");
|
||||
|
||||
// Update Cara
|
||||
DependencyManager::get<DdeFaceTracker>()->update();
|
||||
}
|
||||
|
||||
void Application::updateMyAvatarLookAtPosition() {
|
||||
PerformanceTimer perfTimer("lookAt");
|
||||
bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings);
|
||||
|
@ -1982,16 +1945,6 @@ void Application::updateThreads(float deltaTime) {
|
|||
}
|
||||
}
|
||||
|
||||
void Application::updateMetavoxels(float deltaTime) {
|
||||
PerformanceTimer perfTimer("updateMetavoxels");
|
||||
bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings);
|
||||
PerformanceWarning warn(showWarnings, "Application::updateMetavoxels()");
|
||||
|
||||
if (Menu::getInstance()->isOptionChecked(MenuOption::Metavoxels)) {
|
||||
_metavoxels.simulate(deltaTime);
|
||||
}
|
||||
}
|
||||
|
||||
void Application::cameraMenuChanged() {
|
||||
if (Menu::getInstance()->isOptionChecked(MenuOption::FullscreenMirror)) {
|
||||
if (_myCamera.getMode() != CAMERA_MODE_MIRROR) {
|
||||
|
@ -2056,9 +2009,9 @@ void Application::updateCursor(float deltaTime) {
|
|||
|
||||
void Application::updateCursorVisibility() {
|
||||
if (!_cursorVisible || Menu::getInstance()->isOptionChecked(MenuOption::EnableVRMode)) {
|
||||
DependencyManager::get<GLCanvas>()->setCursor(Qt::BlankCursor);
|
||||
_glWidget->setCursor(Qt::BlankCursor);
|
||||
} else {
|
||||
DependencyManager::get<GLCanvas>()->unsetCursor();
|
||||
_glWidget->unsetCursor();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2076,12 +2029,12 @@ void Application::update(float deltaTime) {
|
|||
{
|
||||
PerformanceTimer perfTimer("devices");
|
||||
DeviceTracker::updateAll();
|
||||
updateFaceshift();
|
||||
updateVisage();
|
||||
FaceTracker* tracker = getActiveFaceTracker();
|
||||
if (tracker) {
|
||||
tracker->update(deltaTime);
|
||||
}
|
||||
SixenseManager::getInstance().update(deltaTime);
|
||||
JoystickScriptingInterface::getInstance().update();
|
||||
_prioVR.update(deltaTime);
|
||||
|
||||
}
|
||||
|
||||
// Dispatch input events
|
||||
|
@ -2091,7 +2044,6 @@ void Application::update(float deltaTime) {
|
|||
|
||||
DependencyManager::get<AvatarManager>()->updateOtherAvatars(deltaTime); //loop through all the other avatars and simulate them...
|
||||
|
||||
updateMetavoxels(deltaTime); // update metavoxels
|
||||
updateCamera(deltaTime); // handle various camera tweaks like off axis projection
|
||||
updateDialogs(deltaTime); // update various stats dialogs if present
|
||||
updateCursor(deltaTime); // Handle cursor updates
|
||||
|
@ -2500,7 +2452,8 @@ void Application::loadViewFrustum(Camera& camera, ViewFrustum& viewFrustum) {
|
|||
|
||||
glm::vec3 Application::getSunDirection() {
|
||||
// Sun direction is in fact just the location of the sun relative to the origin
|
||||
return glm::normalize(_environment.getClosestData(_myCamera.getPosition()).getSunLocation(_myCamera.getPosition()));
|
||||
auto skyStage = DependencyManager::get<SceneScriptingInterface>()->getSkyStage();
|
||||
return skyStage->getSunLight()->getDirection();
|
||||
}
|
||||
|
||||
void Application::updateShadowMap() {
|
||||
|
@ -2510,7 +2463,7 @@ void Application::updateShadowMap() {
|
|||
glEnable(GL_DEPTH_TEST);
|
||||
glClear(GL_DEPTH_BUFFER_BIT);
|
||||
|
||||
glm::vec3 lightDirection = -getSunDirection();
|
||||
glm::vec3 lightDirection = getSunDirection();
|
||||
glm::quat rotation = rotationBetween(IDENTITY_FRONT, lightDirection);
|
||||
glm::quat inverseRotation = glm::inverse(rotation);
|
||||
|
||||
|
@ -2580,7 +2533,9 @@ void Application::updateShadowMap() {
|
|||
glm::ortho(minima.x, maxima.x, minima.y, maxima.y, -maxima.z, -minima.z) * glm::mat4_cast(inverseRotation));
|
||||
|
||||
// update the shadow view frustum
|
||||
_shadowViewFrustum.setPosition(rotation * ((minima + maxima) * 0.5f));
|
||||
// glm::vec3 shadowFrustumCenter = glm::vec3((minima.x + maxima.x) * 0.5f, (minima.y + maxima.y) * 0.5f, (minima.z + maxima.z) * 0.5f);
|
||||
glm::vec3 shadowFrustumCenter = rotation * ((minima + maxima) * 0.5f);
|
||||
_shadowViewFrustum.setPosition(shadowFrustumCenter);
|
||||
_shadowViewFrustum.setOrientation(rotation);
|
||||
_shadowViewFrustum.setOrthographic(true);
|
||||
_shadowViewFrustum.setWidth(maxima.x - minima.x);
|
||||
|
@ -2610,8 +2565,10 @@ void Application::updateShadowMap() {
|
|||
// this is what is used for rendering the Entities and avatars
|
||||
Transform viewTransform;
|
||||
viewTransform.setRotation(rotation);
|
||||
// viewTransform.postTranslate(shadowFrustumCenter);
|
||||
setViewTransform(viewTransform);
|
||||
|
||||
|
||||
glEnable(GL_POLYGON_OFFSET_FILL);
|
||||
glPolygonOffset(1.1f, 4.0f); // magic numbers courtesy http://www.eecs.berkeley.edu/~ravir/6160/papers/shadowmaps.ppt
|
||||
|
||||
|
@ -2648,8 +2605,7 @@ void Application::updateShadowMap() {
|
|||
|
||||
fbo->release();
|
||||
|
||||
auto glCanvas = DependencyManager::get<GLCanvas>();
|
||||
glViewport(0, 0, glCanvas->getDeviceWidth(), glCanvas->getDeviceHeight());
|
||||
glViewport(0, 0, _glWidget->getDeviceWidth(), _glWidget->getDeviceHeight());
|
||||
}
|
||||
|
||||
const GLfloat WORLD_AMBIENT_COLOR[] = { 0.525f, 0.525f, 0.6f };
|
||||
|
@ -2699,7 +2655,7 @@ QImage Application::renderAvatarBillboard() {
|
|||
Glower glower;
|
||||
|
||||
const int BILLBOARD_SIZE = 64;
|
||||
renderRearViewMirror(QRect(0, DependencyManager::get<GLCanvas>()->getDeviceHeight() - BILLBOARD_SIZE,
|
||||
renderRearViewMirror(QRect(0, _glWidget->getDeviceHeight() - BILLBOARD_SIZE,
|
||||
BILLBOARD_SIZE, BILLBOARD_SIZE),
|
||||
true);
|
||||
|
||||
|
@ -2837,14 +2793,6 @@ void Application::displaySide(Camera& theCamera, bool selfAvatarOnly, RenderArgs
|
|||
float originSphereRadius = 0.05f;
|
||||
DependencyManager::get<GeometryCache>()->renderSphere(originSphereRadius, 15, 15, glm::vec4(1.0f, 0.0f, 0.0f, 1.0f));
|
||||
|
||||
// also, metavoxels
|
||||
if (Menu::getInstance()->isOptionChecked(MenuOption::Metavoxels)) {
|
||||
PerformanceTimer perfTimer("metavoxels");
|
||||
PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings),
|
||||
"Application::displaySide() ... metavoxels...");
|
||||
_metavoxels.render();
|
||||
}
|
||||
|
||||
// render models...
|
||||
if (Menu::getInstance()->isOptionChecked(MenuOption::Entities)) {
|
||||
PerformanceTimer perfTimer("entities");
|
||||
|
@ -2880,7 +2828,9 @@ void Application::displaySide(Camera& theCamera, bool selfAvatarOnly, RenderArgs
|
|||
|
||||
{
|
||||
DependencyManager::get<DeferredLightingEffect>()->setAmbientLightMode(getRenderAmbientLight());
|
||||
DependencyManager::get<DeferredLightingEffect>()->setGlobalLight(-getSunDirection(), GLOBAL_LIGHT_COLOR, GLOBAL_LIGHT_INTENSITY);
|
||||
auto skyStage = DependencyManager::get<SceneScriptingInterface>()->getSkyStage();
|
||||
DependencyManager::get<DeferredLightingEffect>()->setGlobalLight(skyStage->getSunLight()->getDirection(), skyStage->getSunLight()->getColor(), skyStage->getSunLight()->getIntensity());
|
||||
|
||||
PROFILE_RANGE("DeferredLighting");
|
||||
PerformanceTimer perfTimer("lighting");
|
||||
DependencyManager::get<DeferredLightingEffect>()->render();
|
||||
|
@ -2991,9 +2941,8 @@ bool Application::getCascadeShadowsEnabled() {
|
|||
}
|
||||
|
||||
glm::vec2 Application::getScaledScreenPoint(glm::vec2 projectedPoint) {
|
||||
auto glCanvas = DependencyManager::get<GLCanvas>();
|
||||
float horizontalScale = glCanvas->getDeviceWidth() / 2.0f;
|
||||
float verticalScale = glCanvas->getDeviceHeight() / 2.0f;
|
||||
float horizontalScale = _glWidget->getDeviceWidth() / 2.0f;
|
||||
float verticalScale = _glWidget->getDeviceHeight() / 2.0f;
|
||||
|
||||
// -1,-1 is 0,windowHeight
|
||||
// 1,1 is windowWidth,0
|
||||
|
@ -3012,7 +2961,7 @@ glm::vec2 Application::getScaledScreenPoint(glm::vec2 projectedPoint) {
|
|||
// -1,-1 1,-1
|
||||
|
||||
glm::vec2 screenPoint((projectedPoint.x + 1.0) * horizontalScale,
|
||||
((projectedPoint.y + 1.0) * -verticalScale) + glCanvas->getDeviceHeight());
|
||||
((projectedPoint.y + 1.0) * -verticalScale) + _glWidget->getDeviceHeight());
|
||||
|
||||
return screenPoint;
|
||||
}
|
||||
|
@ -3142,13 +3091,12 @@ void Application::resetSensors() {
|
|||
|
||||
OculusManager::reset();
|
||||
|
||||
_prioVR.reset();
|
||||
//_leapmotion.reset();
|
||||
|
||||
QScreen* currentScreen = _window->windowHandle()->screen();
|
||||
QWindow* mainWindow = _window->windowHandle();
|
||||
QPoint windowCenter = mainWindow->geometry().center();
|
||||
DependencyManager::get<GLCanvas>()->cursor().setPos(currentScreen, windowCenter);
|
||||
_glWidget->cursor().setPos(currentScreen, windowCenter);
|
||||
|
||||
_myAvatar->reset();
|
||||
|
||||
|
@ -3476,8 +3424,9 @@ void joystickFromScriptValue(const QScriptValue &object, Joystick* &out) {
|
|||
void Application::registerScriptEngineWithApplicationServices(ScriptEngine* scriptEngine) {
|
||||
// setup the packet senders and jurisdiction listeners of the script engine's scripting interfaces so
|
||||
// we can use the same ones from the application.
|
||||
scriptEngine->getEntityScriptingInterface()->setPacketSender(&_entityEditSender);
|
||||
scriptEngine->getEntityScriptingInterface()->setEntityTree(_entities.getTree());
|
||||
auto entityScriptingInterface = DependencyManager::get<EntityScriptingInterface>();
|
||||
entityScriptingInterface->setPacketSender(&_entityEditSender);
|
||||
entityScriptingInterface->setEntityTree(_entities.getTree());
|
||||
|
||||
// AvatarManager has some custom types
|
||||
AvatarManager::registerMetaTypes(scriptEngine);
|
||||
|
@ -3520,7 +3469,6 @@ void Application::registerScriptEngineWithApplicationServices(ScriptEngine* scri
|
|||
scriptEngine->registerGlobalObject("AnimationCache", DependencyManager::get<AnimationCache>().data());
|
||||
scriptEngine->registerGlobalObject("SoundCache", DependencyManager::get<SoundCache>().data());
|
||||
scriptEngine->registerGlobalObject("Account", AccountScriptingInterface::getInstance());
|
||||
scriptEngine->registerGlobalObject("Metavoxels", &_metavoxels);
|
||||
|
||||
scriptEngine->registerGlobalObject("GlobalServices", GlobalServicesScriptingInterface::getInstance());
|
||||
qScriptRegisterMetaType(scriptEngine, DownloadInfoResultToScriptValue, DownloadInfoResultFromScriptValue);
|
||||
|
@ -3784,7 +3732,7 @@ void Application::setPreviousScriptLocation(const QString& previousScriptLocatio
|
|||
|
||||
void Application::loadDialog() {
|
||||
|
||||
QString fileNameString = QFileDialog::getOpenFileName(DependencyManager::get<GLCanvas>().data(),
|
||||
QString fileNameString = QFileDialog::getOpenFileName(_glWidget,
|
||||
tr("Open Script"),
|
||||
getPreviousScriptLocation(),
|
||||
tr("JavaScript Files (*.js)"));
|
||||
|
@ -3825,7 +3773,7 @@ void Application::setScriptsLocation(const QString& scriptsLocation) {
|
|||
|
||||
void Application::toggleLogDialog() {
|
||||
if (! _logDialog) {
|
||||
_logDialog = new LogDialog(DependencyManager::get<GLCanvas>().data(), getLogger());
|
||||
_logDialog = new LogDialog(_glWidget, getLogger());
|
||||
}
|
||||
|
||||
if (_logDialog->isVisible()) {
|
||||
|
@ -3882,7 +3830,7 @@ void Application::parseVersionXml() {
|
|||
}
|
||||
|
||||
if (!shouldSkipVersion(latestVersion) && applicationVersion() != latestVersion) {
|
||||
new UpdateDialog(DependencyManager::get<GLCanvas>().data(), releaseNotes, latestVersion, downloadUrl);
|
||||
new UpdateDialog(_glWidget, releaseNotes, latestVersion, downloadUrl);
|
||||
}
|
||||
sender->deleteLater();
|
||||
}
|
||||
|
@ -3915,7 +3863,7 @@ void Application::takeSnapshot() {
|
|||
}
|
||||
|
||||
if (!_snapshotShareDialog) {
|
||||
_snapshotShareDialog = new SnapshotShareDialog(fileName, DependencyManager::get<GLCanvas>().data());
|
||||
_snapshotShareDialog = new SnapshotShareDialog(fileName, _glWidget);
|
||||
}
|
||||
_snapshotShareDialog->show();
|
||||
}
|
||||
|
|
|
@ -45,13 +45,11 @@
|
|||
#include "FileLogger.h"
|
||||
#include "GLCanvas.h"
|
||||
#include "Menu.h"
|
||||
#include "MetavoxelSystem.h"
|
||||
#include "PacketHeaders.h"
|
||||
#include "Physics.h"
|
||||
#include "Stars.h"
|
||||
#include "avatar/Avatar.h"
|
||||
#include "avatar/MyAvatar.h"
|
||||
#include "devices/PrioVR.h"
|
||||
#include "devices/SixenseManager.h"
|
||||
#include "scripting/ControllerScriptingInterface.h"
|
||||
#include "ui/BandwidthDialog.h"
|
||||
|
@ -171,17 +169,16 @@ public:
|
|||
bool event(QEvent* event);
|
||||
bool eventFilter(QObject* object, QEvent* event);
|
||||
|
||||
bool isThrottleRendering() const { return DependencyManager::get<GLCanvas>()->isThrottleRendering(); }
|
||||
GLCanvas* getGLWidget() { return _glWidget; }
|
||||
bool isThrottleRendering() const { return _glWidget->isThrottleRendering(); }
|
||||
|
||||
Camera* getCamera() { return &_myCamera; }
|
||||
ViewFrustum* getViewFrustum() { return &_viewFrustum; }
|
||||
ViewFrustum* getDisplayViewFrustum() { return &_displayViewFrustum; }
|
||||
ViewFrustum* getShadowViewFrustum() { return &_shadowViewFrustum; }
|
||||
const OctreePacketProcessor& getOctreePacketProcessor() const { return _octreeProcessor; }
|
||||
MetavoxelSystem* getMetavoxels() { return &_metavoxels; }
|
||||
EntityTreeRenderer* getEntities() { return &_entities; }
|
||||
Environment* getEnvironment() { return &_environment; }
|
||||
PrioVR* getPrioVR() { return &_prioVR; }
|
||||
QUndoStack* getUndoStack() { return &_undoStack; }
|
||||
MainWindow* getWindow() { return _window; }
|
||||
OctreeQuery& getOctreeQuery() { return _octreeQuery; }
|
||||
|
@ -195,8 +192,8 @@ public:
|
|||
bool mouseOnScreen() const;
|
||||
int getMouseX() const;
|
||||
int getMouseY() const;
|
||||
int getTrueMouseX() const { return DependencyManager::get<GLCanvas>()->mapFromGlobal(QCursor::pos()).x(); }
|
||||
int getTrueMouseY() const { return DependencyManager::get<GLCanvas>()->mapFromGlobal(QCursor::pos()).y(); }
|
||||
int getTrueMouseX() const { return _glWidget->mapFromGlobal(QCursor::pos()).x(); }
|
||||
int getTrueMouseY() const { return _glWidget->mapFromGlobal(QCursor::pos()).y(); }
|
||||
int getMouseDragStartedX() const;
|
||||
int getMouseDragStartedY() const;
|
||||
int getTrueMouseDragStartedX() const { return _mouseDragStartedX; }
|
||||
|
@ -270,8 +267,8 @@ public:
|
|||
|
||||
FileLogger* getLogger() { return _logger; }
|
||||
|
||||
glm::vec2 getViewportDimensions() const { return glm::vec2(DependencyManager::get<GLCanvas>()->getDeviceWidth(),
|
||||
DependencyManager::get<GLCanvas>()->getDeviceHeight()); }
|
||||
glm::vec2 getViewportDimensions() const { return glm::vec2(_glWidget->getDeviceWidth(),
|
||||
_glWidget->getDeviceHeight()); }
|
||||
NodeToJurisdictionMap& getEntityServerJurisdictions() { return _entityServerJurisdictions; }
|
||||
|
||||
void skipVersion(QString latestVersion);
|
||||
|
@ -420,12 +417,8 @@ private:
|
|||
// Various helper functions called during update()
|
||||
void updateLOD();
|
||||
void updateMouseRay();
|
||||
void updateFaceshift();
|
||||
void updateVisage();
|
||||
void updateDDE();
|
||||
void updateMyAvatarLookAtPosition();
|
||||
void updateThreads(float deltaTime);
|
||||
void updateMetavoxels(float deltaTime);
|
||||
void updateCamera(float deltaTime);
|
||||
void updateDialogs(float deltaTime);
|
||||
void updateCursor(float deltaTime);
|
||||
|
@ -478,8 +471,6 @@ private:
|
|||
EntityTreeRenderer _entityClipboardRenderer;
|
||||
EntityTree _entityClipboard;
|
||||
|
||||
MetavoxelSystem _metavoxels;
|
||||
|
||||
ViewFrustum _viewFrustum; // current state of view frustum, perspective, orientation, etc.
|
||||
ViewFrustum _lastQueriedViewFrustum; /// last view frustum used to query octree servers (voxels)
|
||||
ViewFrustum _displayViewFrustum;
|
||||
|
@ -492,8 +483,6 @@ private:
|
|||
|
||||
MyAvatar* _myAvatar; // TODO: move this and relevant code to AvatarManager (or MyAvatar as the case may be)
|
||||
|
||||
PrioVR _prioVR;
|
||||
|
||||
Camera _myCamera; // My view onto the world
|
||||
Camera _mirrorCamera; // Cammera for mirror view
|
||||
QRect _mirrorViewRect;
|
||||
|
@ -593,6 +582,8 @@ private:
|
|||
|
||||
QThread _settingsThread;
|
||||
QTimer _settingsTimer;
|
||||
|
||||
GLCanvas* _glWidget = new GLCanvas(); // our GLCanvas has a couple extra features
|
||||
};
|
||||
|
||||
#endif // hifi_Application_h
|
||||
|
|
|
@ -122,7 +122,7 @@ void Camera::setFarClip(float f) {
|
|||
}
|
||||
|
||||
PickRay Camera::computePickRay(float x, float y) {
|
||||
auto glCanvas = DependencyManager::get<GLCanvas>();
|
||||
auto glCanvas = Application::getInstance()->getGLWidget();
|
||||
return computeViewPickRay(x / glCanvas->width(), y / glCanvas->height());
|
||||
}
|
||||
|
||||
|
|
|
@ -30,6 +30,10 @@ DatagramProcessor::DatagramProcessor(QObject* parent) :
|
|||
void DatagramProcessor::processDatagrams() {
|
||||
PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings),
|
||||
"DatagramProcessor::processDatagrams()");
|
||||
|
||||
if (_isShuttingDown) {
|
||||
return; // bail early... we're shutting down.
|
||||
}
|
||||
|
||||
HifiSockAddr senderSockAddr;
|
||||
|
||||
|
@ -96,9 +100,6 @@ void DatagramProcessor::processDatagrams() {
|
|||
}
|
||||
break;
|
||||
}
|
||||
case PacketTypeMetavoxelData:
|
||||
nodeList->findNodeAndUpdateWithDataFromPacket(incomingPacket);
|
||||
break;
|
||||
case PacketTypeBulkAvatarData:
|
||||
case PacketTypeKillAvatar:
|
||||
case PacketTypeAvatarIdentity:
|
||||
|
|
|
@ -25,14 +25,17 @@ public:
|
|||
int getOutByteCount() const { return _outByteCount; }
|
||||
|
||||
void resetCounters() { _inPacketCount = 0; _outPacketCount = 0; _inByteCount = 0; _outByteCount = 0; }
|
||||
|
||||
void shutdown() { _isShuttingDown = true; }
|
||||
public slots:
|
||||
void processDatagrams();
|
||||
|
||||
private:
|
||||
int _inPacketCount;
|
||||
int _outPacketCount;
|
||||
int _inByteCount;
|
||||
int _outByteCount;
|
||||
int _inPacketCount = 0;
|
||||
int _outPacketCount = 0;
|
||||
int _inByteCount = 0;
|
||||
int _outByteCount = 0;
|
||||
bool _isShuttingDown = false;
|
||||
};
|
||||
|
||||
#endif // hifi_DatagramProcessor_h
|
||||
|
|
|
@ -16,14 +16,13 @@
|
|||
#include <QGLWidget>
|
||||
#include <QTimer>
|
||||
|
||||
#include <DependencyManager.h>
|
||||
|
||||
/// customized canvas that simply forwards requests/events to the singleton application
|
||||
class GLCanvas : public QGLWidget, public Dependency {
|
||||
class GLCanvas : public QGLWidget {
|
||||
Q_OBJECT
|
||||
SINGLETON_DEPENDENCY
|
||||
|
||||
public:
|
||||
GLCanvas();
|
||||
|
||||
bool isThrottleRendering() const;
|
||||
|
||||
int getDeviceWidth() const;
|
||||
|
@ -60,12 +59,8 @@ private slots:
|
|||
void activeChanged(Qt::ApplicationState state);
|
||||
void throttleRender();
|
||||
bool eventFilter(QObject*, QEvent* event);
|
||||
|
||||
private:
|
||||
GLCanvas();
|
||||
~GLCanvas() {
|
||||
qDebug() << "Deleting GLCanvas";
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
#endif // hifi_GLCanvas_h
|
||||
|
|
|
@ -20,7 +20,6 @@
|
|||
#include <PathUtils.h>
|
||||
#include <SettingHandle.h>
|
||||
#include <UserActivityLogger.h>
|
||||
#include <XmppClient.h>
|
||||
|
||||
#include "Application.h"
|
||||
#include "AccountManager.h"
|
||||
|
@ -148,8 +147,6 @@ Menu::Menu() {
|
|||
dialogsManager.data(), SLOT(editAnimations()));
|
||||
|
||||
QMenu* toolsMenu = addMenu("Tools");
|
||||
addActionToQMenuAndActionHash(toolsMenu, MenuOption::MetavoxelEditor, 0,
|
||||
dialogsManager.data(), SLOT(showMetavoxelEditor()));
|
||||
addActionToQMenuAndActionHash(toolsMenu, MenuOption::ScriptEditor, Qt::ALT | Qt::Key_S,
|
||||
dialogsManager.data(), SLOT(showScriptEditor()));
|
||||
|
||||
|
@ -162,12 +159,9 @@ Menu::Menu() {
|
|||
SLOT(setEnabled(bool)));
|
||||
connect(speechRecognizer.data(), SIGNAL(enabledUpdated(bool)), speechRecognizerAction, SLOT(setChecked(bool)));
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_QXMPP
|
||||
|
||||
addActionToQMenuAndActionHash(toolsMenu, MenuOption::Chat, Qt::Key_Backslash,
|
||||
dialogsManager.data(), SLOT(showChat()));
|
||||
dialogsManager->setupChat();
|
||||
#endif
|
||||
dialogsManager.data(), SLOT(showIRCLink()));
|
||||
|
||||
addActionToQMenuAndActionHash(toolsMenu,
|
||||
MenuOption::ToolWindow,
|
||||
|
@ -295,7 +289,6 @@ Menu::Menu() {
|
|||
QMenu* renderOptionsMenu = developerMenu->addMenu("Render");
|
||||
addCheckableActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::Atmosphere, Qt::SHIFT | Qt::Key_A, true);
|
||||
addCheckableActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::Avatars, 0, true);
|
||||
addCheckableActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::Metavoxels, 0, true);
|
||||
addCheckableActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::Entities, 0, true);
|
||||
addCheckableActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::AmbientOcclusion);
|
||||
addCheckableActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::DontFadeOnOctreeServerChanges);
|
||||
|
@ -394,13 +387,6 @@ Menu::Menu() {
|
|||
addCheckableActionToQMenuAndActionHash(avatarDebugMenu, MenuOption::RenderLookAtVectors, 0, false);
|
||||
addCheckableActionToQMenuAndActionHash(avatarDebugMenu, MenuOption::RenderFocusIndicator, 0, false);
|
||||
|
||||
QMenu* metavoxelOptionsMenu = developerMenu->addMenu("Metavoxels");
|
||||
addCheckableActionToQMenuAndActionHash(metavoxelOptionsMenu, MenuOption::DisplayHermiteData, 0, false);
|
||||
addCheckableActionToQMenuAndActionHash(metavoxelOptionsMenu, MenuOption::RenderHeightfields, 0, true);
|
||||
addCheckableActionToQMenuAndActionHash(metavoxelOptionsMenu, MenuOption::RenderDualContourSurfaces, 0, true);
|
||||
addActionToQMenuAndActionHash(metavoxelOptionsMenu, MenuOption::NetworkSimulator, 0,
|
||||
dialogsManager.data(), SLOT(showMetavoxelNetworkSimulator()));
|
||||
|
||||
QMenu* handOptionsMenu = developerMenu->addMenu("Hands");
|
||||
addCheckableActionToQMenuAndActionHash(handOptionsMenu, MenuOption::AlignForearmsWithWrists, 0, false);
|
||||
addCheckableActionToQMenuAndActionHash(handOptionsMenu, MenuOption::AlternateIK, 0, false);
|
||||
|
@ -453,7 +439,8 @@ Menu::Menu() {
|
|||
|
||||
QMenu* timingMenu = developerMenu->addMenu("Timing and Stats");
|
||||
QMenu* perfTimerMenu = timingMenu->addMenu("Performance Timer");
|
||||
addCheckableActionToQMenuAndActionHash(perfTimerMenu, MenuOption::DisplayTimingDetails, 0, true);
|
||||
addCheckableActionToQMenuAndActionHash(perfTimerMenu, MenuOption::DisplayDebugTimingDetails, 0, false);
|
||||
addCheckableActionToQMenuAndActionHash(perfTimerMenu, MenuOption::OnlyDisplayTopTen, 0, true);
|
||||
addCheckableActionToQMenuAndActionHash(perfTimerMenu, MenuOption::ExpandUpdateTiming, 0, false);
|
||||
addCheckableActionToQMenuAndActionHash(perfTimerMenu, MenuOption::ExpandMyAvatarTiming, 0, false);
|
||||
addCheckableActionToQMenuAndActionHash(perfTimerMenu, MenuOption::ExpandMyAvatarSimulateTiming, 0, false);
|
||||
|
|
|
@ -145,12 +145,11 @@ namespace MenuOption {
|
|||
const QString DisableNackPackets = "Disable NACK Packets";
|
||||
const QString DisplayHands = "Show Hand Info";
|
||||
const QString DisplayHandTargets = "Show Hand Targets";
|
||||
const QString DisplayHermiteData = "Display Hermite Data";
|
||||
const QString DisplayModelBounds = "Display Model Bounds";
|
||||
const QString DisplayModelTriangles = "Display Model Triangles";
|
||||
const QString DisplayModelElementChildProxies = "Display Model Element Children";
|
||||
const QString DisplayModelElementProxy = "Display Model Element Bounds";
|
||||
const QString DisplayTimingDetails = "Display Timing Details";
|
||||
const QString DisplayDebugTimingDetails = "Display Timing Details";
|
||||
const QString DontDoPrecisionPicking = "Don't Do Precision Picking";
|
||||
const QString DontFadeOnOctreeServerChanges = "Don't Fade In/Out on Octree Server Changes";
|
||||
const QString DontRenderEntitiesAsScene = "Don't Render Entities as Scene";
|
||||
|
@ -186,28 +185,24 @@ namespace MenuOption {
|
|||
const QString Login = "Login";
|
||||
const QString Log = "Log";
|
||||
const QString LowVelocityFilter = "Low Velocity Filter";
|
||||
const QString MetavoxelEditor = "Metavoxel Editor...";
|
||||
const QString Metavoxels = "Metavoxels";
|
||||
const QString Mirror = "Mirror";
|
||||
const QString MuteAudio = "Mute Microphone";
|
||||
const QString MuteEnvironment = "Mute Environment";
|
||||
const QString NetworkSimulator = "Network Simulator...";
|
||||
const QString NewVoxelCullingMode = "New Voxel Culling Mode";
|
||||
const QString NoFaceTracking = "None";
|
||||
const QString ObeyEnvironmentalGravity = "Obey Environmental Gravity";
|
||||
const QString OctreeStats = "Voxel and Entity Statistics";
|
||||
const QString OffAxisProjection = "Off-Axis Projection";
|
||||
const QString OldVoxelCullingMode = "Old Voxel Culling Mode";
|
||||
const QString OnlyDisplayTopTen = "Only Display Top Ten";
|
||||
const QString Pair = "Pair";
|
||||
const QString PipelineWarnings = "Log Render Pipeline Warnings";
|
||||
const QString Preferences = "Preferences...";
|
||||
const QString Quit = "Quit";
|
||||
const QString ReloadAllScripts = "Reload All Scripts";
|
||||
const QString RenderBoundingCollisionShapes = "Show Bounding Collision Shapes";
|
||||
const QString RenderDualContourSurfaces = "Render Dual Contour Surfaces";
|
||||
const QString RenderFocusIndicator = "Show Eye Focus";
|
||||
const QString RenderHeadCollisionShapes = "Show Head Collision Shapes";
|
||||
const QString RenderHeightfields = "Render Heightfields";
|
||||
const QString RenderLookAtVectors = "Show Look-at Vectors";
|
||||
const QString RenderSkeletonCollisionShapes = "Show Skeleton Collision Shapes";
|
||||
const QString RenderTargetFramerate = "Framerate";
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -1,445 +0,0 @@
|
|||
//
|
||||
// MetavoxelSystem.h
|
||||
// interface/src
|
||||
//
|
||||
// Created by Andrzej Kapolka on 12/10/13.
|
||||
// Copyright 2013 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_MetavoxelSystem_h
|
||||
#define hifi_MetavoxelSystem_h
|
||||
|
||||
#include <QList>
|
||||
#include <QOpenGLBuffer>
|
||||
#include <QReadWriteLock>
|
||||
#include <QVector>
|
||||
|
||||
#include <glm/glm.hpp>
|
||||
|
||||
#include <MetavoxelClientManager.h>
|
||||
#include <ProgramObject.h>
|
||||
#include <TextureCache.h>
|
||||
|
||||
class HeightfieldBaseLayerBatch;
|
||||
class HeightfieldSplatBatch;
|
||||
class HermiteBatch;
|
||||
class MetavoxelBatch;
|
||||
class Model;
|
||||
class VoxelSplatBatch;
|
||||
|
||||
/// Renders a metavoxel tree.
|
||||
class MetavoxelSystem : public MetavoxelClientManager {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
||||
class NetworkSimulation {
|
||||
public:
|
||||
float dropRate;
|
||||
float repeatRate;
|
||||
int minimumDelay;
|
||||
int maximumDelay;
|
||||
int bandwidthLimit;
|
||||
|
||||
NetworkSimulation(float dropRate = 0.0f, float repeatRate = 0.0f, int minimumDelay = 0,
|
||||
int maximumDelay = 0, int bandwidthLimit = 0);
|
||||
};
|
||||
|
||||
virtual ~MetavoxelSystem();
|
||||
|
||||
virtual void init();
|
||||
|
||||
virtual MetavoxelLOD getLOD();
|
||||
|
||||
const Frustum& getFrustum() const { return _frustum; }
|
||||
|
||||
void setNetworkSimulation(const NetworkSimulation& simulation);
|
||||
NetworkSimulation getNetworkSimulation();
|
||||
|
||||
void simulate(float deltaTime);
|
||||
void render();
|
||||
|
||||
void renderHeightfieldCursor(const glm::vec3& position, float radius);
|
||||
|
||||
Q_INVOKABLE void paintHeightfieldColor(const glm::vec3& position, float radius, const QColor& color);
|
||||
|
||||
Q_INVOKABLE void paintHeightfieldMaterial(const glm::vec3& position, float radius, const SharedObjectPointer& material);
|
||||
|
||||
Q_INVOKABLE void setHeightfieldColor(const SharedObjectPointer& spanner, const QColor& color, bool paint = false);
|
||||
|
||||
Q_INVOKABLE void setHeightfieldMaterial(const SharedObjectPointer& spanner,
|
||||
const SharedObjectPointer& material, bool paint = false);
|
||||
|
||||
void addHeightfieldBaseBatch(const HeightfieldBaseLayerBatch& batch) { _heightfieldBaseBatches.append(batch); }
|
||||
void addHeightfieldSplatBatch(const HeightfieldSplatBatch& batch) { _heightfieldSplatBatches.append(batch); }
|
||||
|
||||
void addVoxelBaseBatch(const MetavoxelBatch& batch) { _voxelBaseBatches.append(batch); }
|
||||
void addVoxelSplatBatch(const VoxelSplatBatch& batch) { _voxelSplatBatches.append(batch); }
|
||||
|
||||
void addHermiteBatch(const HermiteBatch& batch) { _hermiteBatches.append(batch); }
|
||||
|
||||
Q_INVOKABLE void deleteTextures(int heightTextureID, int colorTextureID, int materialTextureID) const;
|
||||
Q_INVOKABLE void deleteBuffers(int vertexBufferID, int indexBufferID, int hermiteBufferID) const;
|
||||
|
||||
signals:
|
||||
|
||||
void rendering();
|
||||
|
||||
protected:
|
||||
|
||||
Q_INVOKABLE void applyMaterialEdit(const MetavoxelEditMessage& message, bool reliable = false);
|
||||
|
||||
virtual MetavoxelClient* createClient(const SharedNodePointer& node);
|
||||
|
||||
private:
|
||||
|
||||
void guideToAugmented(MetavoxelVisitor& visitor, bool render = false);
|
||||
|
||||
MetavoxelLOD _lod;
|
||||
QReadWriteLock _lodLock;
|
||||
Frustum _frustum;
|
||||
|
||||
NetworkSimulation _networkSimulation;
|
||||
QReadWriteLock _networkSimulationLock;
|
||||
|
||||
QVector<HeightfieldBaseLayerBatch> _heightfieldBaseBatches;
|
||||
QVector<HeightfieldSplatBatch> _heightfieldSplatBatches;
|
||||
QVector<MetavoxelBatch> _voxelBaseBatches;
|
||||
QVector<VoxelSplatBatch> _voxelSplatBatches;
|
||||
QVector<HermiteBatch> _hermiteBatches;
|
||||
|
||||
ProgramObject _baseHeightfieldProgram;
|
||||
int _baseHeightScaleLocation;
|
||||
int _baseColorScaleLocation;
|
||||
|
||||
class SplatLocations {
|
||||
public:
|
||||
int heightScale;
|
||||
int textureScale;
|
||||
int splatTextureOffset;
|
||||
int splatTextureScalesS;
|
||||
int splatTextureScalesT;
|
||||
int textureValueMinima;
|
||||
int textureValueMaxima;
|
||||
int materials;
|
||||
int materialWeights;
|
||||
};
|
||||
|
||||
ProgramObject _splatHeightfieldProgram;
|
||||
SplatLocations _splatHeightfieldLocations;
|
||||
|
||||
int _splatHeightScaleLocation;
|
||||
int _splatTextureScaleLocation;
|
||||
int _splatTextureOffsetLocation;
|
||||
int _splatTextureScalesSLocation;
|
||||
int _splatTextureScalesTLocation;
|
||||
int _splatTextureValueMinimaLocation;
|
||||
int _splatTextureValueMaximaLocation;
|
||||
|
||||
ProgramObject _heightfieldCursorProgram;
|
||||
|
||||
ProgramObject _baseVoxelProgram;
|
||||
ProgramObject _splatVoxelProgram;
|
||||
SplatLocations _splatVoxelLocations;
|
||||
|
||||
ProgramObject _voxelCursorProgram;
|
||||
|
||||
static void loadSplatProgram(const char* type, ProgramObject& program, SplatLocations& locations);
|
||||
};
|
||||
|
||||
/// Base class for all batches.
|
||||
class MetavoxelBatch {
|
||||
public:
|
||||
GLuint vertexBufferID;
|
||||
GLuint indexBufferID;
|
||||
glm::vec3 translation;
|
||||
glm::quat rotation;
|
||||
glm::vec3 scale;
|
||||
int vertexCount;
|
||||
int indexCount;
|
||||
};
|
||||
|
||||
/// Base class for heightfield batches.
|
||||
class HeightfieldBatch : public MetavoxelBatch {
|
||||
public:
|
||||
GLuint heightTextureID;
|
||||
glm::vec4 heightScale;
|
||||
};
|
||||
|
||||
/// A batch containing a heightfield base layer.
|
||||
class HeightfieldBaseLayerBatch : public HeightfieldBatch {
|
||||
public:
|
||||
GLuint colorTextureID;
|
||||
glm::vec2 colorScale;
|
||||
};
|
||||
|
||||
/// A batch containing a heightfield splat.
|
||||
class HeightfieldSplatBatch : public HeightfieldBatch {
|
||||
public:
|
||||
GLuint materialTextureID;
|
||||
glm::vec2 textureScale;
|
||||
glm::vec2 splatTextureOffset;
|
||||
int splatTextureIDs[4];
|
||||
glm::vec4 splatTextureScalesS;
|
||||
glm::vec4 splatTextureScalesT;
|
||||
int materialIndex;
|
||||
};
|
||||
|
||||
/// A batch containing a voxel splat.
|
||||
class VoxelSplatBatch : public MetavoxelBatch {
|
||||
public:
|
||||
glm::vec3 splatTextureOffset;
|
||||
int splatTextureIDs[4];
|
||||
glm::vec4 splatTextureScalesS;
|
||||
glm::vec4 splatTextureScalesT;
|
||||
int materialIndex;
|
||||
};
|
||||
|
||||
/// A batch containing Hermite data for debugging.
|
||||
class HermiteBatch {
|
||||
public:
|
||||
GLuint vertexBufferID;
|
||||
glm::vec3 translation;
|
||||
glm::quat rotation;
|
||||
glm::vec3 scale;
|
||||
int vertexCount;
|
||||
};
|
||||
|
||||
/// Generic abstract base class for objects that handle a signal.
|
||||
class SignalHandler : public QObject {
|
||||
Q_OBJECT
|
||||
|
||||
public slots:
|
||||
|
||||
virtual void handle() = 0;
|
||||
};
|
||||
|
||||
/// Simple throttle for limiting bandwidth on a per-second basis.
|
||||
class Throttle {
|
||||
public:
|
||||
|
||||
Throttle();
|
||||
|
||||
/// Sets the per-second limit.
|
||||
void setLimit(int limit) { _limit = limit; }
|
||||
|
||||
/// Determines whether the message with the given size should be throttled (discarded). If not, registers the message
|
||||
/// as having been processed (i.e., contributing to later throttling).
|
||||
bool shouldThrottle(int bytes);
|
||||
|
||||
private:
|
||||
|
||||
int _limit;
|
||||
int _total;
|
||||
|
||||
typedef QPair<qint64, int> Bucket;
|
||||
QList<Bucket> _buckets;
|
||||
};
|
||||
|
||||
/// A client session associated with a single server.
|
||||
class MetavoxelSystemClient : public MetavoxelClient {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
||||
MetavoxelSystemClient(const SharedNodePointer& node, MetavoxelUpdater* updater);
|
||||
|
||||
Q_INVOKABLE void setAugmentedData(const MetavoxelData& data);
|
||||
|
||||
/// Returns a copy of the augmented data. This function is thread-safe.
|
||||
MetavoxelData getAugmentedData();
|
||||
|
||||
void setRenderedAugmentedData(const MetavoxelData& data) { _renderedAugmentedData = data; }
|
||||
|
||||
virtual int parseData(const QByteArray& packet);
|
||||
|
||||
protected:
|
||||
|
||||
virtual void dataChanged(const MetavoxelData& oldData);
|
||||
virtual void sendDatagram(const QByteArray& data);
|
||||
|
||||
private:
|
||||
|
||||
MetavoxelData _augmentedData;
|
||||
MetavoxelData _renderedAugmentedData;
|
||||
QReadWriteLock _augmentedDataLock;
|
||||
|
||||
Throttle _sendThrottle;
|
||||
Throttle _receiveThrottle;
|
||||
};
|
||||
|
||||
/// Base class for cached static buffers.
|
||||
class BufferData : public QSharedData {
|
||||
public:
|
||||
|
||||
virtual ~BufferData();
|
||||
|
||||
virtual void render(const glm::vec3& translation, const glm::quat& rotation,
|
||||
const glm::vec3& scale, bool cursor = false) = 0;
|
||||
};
|
||||
|
||||
typedef QExplicitlySharedDataPointer<BufferData> BufferDataPointer;
|
||||
|
||||
/// Describes contents of a vertex in a voxel buffer.
|
||||
class VoxelPoint {
|
||||
public:
|
||||
glm::vec3 vertex;
|
||||
quint8 color[3];
|
||||
char normal[3];
|
||||
quint8 materials[4];
|
||||
quint8 materialWeights[4];
|
||||
|
||||
void setNormal(const glm::vec3& normal);
|
||||
};
|
||||
|
||||
/// A container for a coordinate within a voxel block.
|
||||
class VoxelCoord {
|
||||
public:
|
||||
QRgb encoded;
|
||||
|
||||
VoxelCoord(QRgb encoded) : encoded(encoded) { }
|
||||
|
||||
bool operator==(const VoxelCoord& other) const { return encoded == other.encoded; }
|
||||
};
|
||||
|
||||
inline uint qHash(const VoxelCoord& coord, uint seed) {
|
||||
// multiply by prime numbers greater than the possible size
|
||||
return qHash(qRed(coord.encoded) + 257 * (qGreen(coord.encoded) + 263 * qBlue(coord.encoded)), seed);
|
||||
}
|
||||
|
||||
/// Contains the information necessary to render a voxel block.
|
||||
class VoxelBuffer : public BufferData {
|
||||
public:
|
||||
|
||||
VoxelBuffer(const QVector<VoxelPoint>& vertices, const QVector<int>& indices, const QVector<glm::vec3>& hermite,
|
||||
const QMultiHash<VoxelCoord, int>& quadIndices, int size, const QVector<SharedObjectPointer>& materials =
|
||||
QVector<SharedObjectPointer>());
|
||||
virtual ~VoxelBuffer();
|
||||
|
||||
bool isHermiteEnabled() const { return _hermiteEnabled; }
|
||||
|
||||
/// Finds the first intersection between the described ray and the voxel data.
|
||||
bool findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, float boundsDistance, float& distance) const;
|
||||
|
||||
virtual void render(const glm::vec3& translation, const glm::quat& rotation,
|
||||
const glm::vec3& scale, bool cursor = false);
|
||||
|
||||
private:
|
||||
|
||||
QVector<VoxelPoint> _vertices;
|
||||
QVector<int> _indices;
|
||||
QVector<glm::vec3> _hermite;
|
||||
bool _hermiteEnabled;
|
||||
QMultiHash<VoxelCoord, int> _quadIndices;
|
||||
int _size;
|
||||
int _vertexCount;
|
||||
int _indexCount;
|
||||
int _hermiteCount;
|
||||
GLuint _vertexBufferID;
|
||||
GLuint _indexBufferID;
|
||||
GLuint _hermiteBufferID;
|
||||
QVector<SharedObjectPointer> _materials;
|
||||
QVector<NetworkTexturePointer> _networkTextures;
|
||||
};
|
||||
|
||||
/// Renders metavoxels as points.
|
||||
class DefaultMetavoxelRendererImplementation : public MetavoxelRendererImplementation {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
||||
Q_INVOKABLE DefaultMetavoxelRendererImplementation();
|
||||
|
||||
virtual void simulate(MetavoxelData& data, float deltaTime, MetavoxelInfo& info, const MetavoxelLOD& lod);
|
||||
virtual void render(MetavoxelData& data, MetavoxelInfo& info, const MetavoxelLOD& lod);
|
||||
};
|
||||
|
||||
/// Renders spheres.
|
||||
class SphereRenderer : public SpannerRenderer {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
||||
Q_INVOKABLE SphereRenderer();
|
||||
|
||||
virtual void render(const MetavoxelLOD& lod = MetavoxelLOD(), bool contained = false, bool cursor = false);
|
||||
};
|
||||
|
||||
/// Renders cuboids.
|
||||
class CuboidRenderer : public SpannerRenderer {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
||||
Q_INVOKABLE CuboidRenderer();
|
||||
|
||||
virtual void render(const MetavoxelLOD& lod = MetavoxelLOD(), bool contained = false, bool cursor = false);
|
||||
};
|
||||
|
||||
/// Renders static models.
|
||||
class StaticModelRenderer : public SpannerRenderer {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
||||
Q_INVOKABLE StaticModelRenderer();
|
||||
|
||||
virtual void init(Spanner* spanner);
|
||||
virtual void simulate(float deltaTime);
|
||||
virtual void render(const MetavoxelLOD& lod = MetavoxelLOD(), bool contained = false, bool cursor = false);
|
||||
virtual bool findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, float& distance) const;
|
||||
|
||||
private slots:
|
||||
|
||||
void applyTranslation(const glm::vec3& translation);
|
||||
void applyRotation(const glm::quat& rotation);
|
||||
void applyScale(float scale);
|
||||
void applyURL(const QUrl& url);
|
||||
|
||||
private:
|
||||
|
||||
Model* _model;
|
||||
};
|
||||
|
||||
/// Renders heightfields.
|
||||
class HeightfieldRenderer : public SpannerRenderer {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
||||
Q_INVOKABLE HeightfieldRenderer();
|
||||
|
||||
virtual void render(const MetavoxelLOD& lod = MetavoxelLOD(), bool contained = false, bool cursor = false);
|
||||
};
|
||||
|
||||
/// Renders a single quadtree node.
|
||||
class HeightfieldNodeRenderer : public AbstractHeightfieldNodeRenderer {
|
||||
public:
|
||||
|
||||
HeightfieldNodeRenderer();
|
||||
virtual ~HeightfieldNodeRenderer();
|
||||
|
||||
virtual bool findRayIntersection(const glm::vec3& translation, const glm::quat& rotation, const glm::vec3& scale,
|
||||
const glm::vec3& origin, const glm::vec3& direction, float boundsDistance, float& distance) const;
|
||||
|
||||
void render(const HeightfieldNodePointer& node, const glm::vec3& translation,
|
||||
const glm::quat& rotation, const glm::vec3& scale, bool cursor);
|
||||
|
||||
private:
|
||||
|
||||
GLuint _heightTextureID;
|
||||
GLuint _colorTextureID;
|
||||
GLuint _materialTextureID;
|
||||
QVector<NetworkTexturePointer> _networkTextures;
|
||||
|
||||
BufferDataPointer _voxels;
|
||||
|
||||
typedef QPair<int, int> IntPair;
|
||||
typedef QPair<QOpenGLBuffer, QOpenGLBuffer> BufferPair;
|
||||
static QHash<IntPair, BufferPair> _bufferPairs;
|
||||
};
|
||||
|
||||
#endif // hifi_MetavoxelSystem_h
|
|
@ -12,7 +12,6 @@
|
|||
#include <QStyle>
|
||||
#include <QStyleOptionTitleBar>
|
||||
|
||||
#include "DependencyManager.h"
|
||||
#include "GLCanvas.h"
|
||||
|
||||
#include "UIUtil.h"
|
||||
|
@ -44,8 +43,6 @@ int UIUtil::getWindowTitleBarHeight(const QWidget* window) {
|
|||
// this function at all. If you mix both you will end up with inconsistent results
|
||||
// across platforms.
|
||||
void UIUtil::scaleWidgetFontSizes(QWidget* widget) {
|
||||
auto glCanvas = DependencyManager::get<GLCanvas>();
|
||||
|
||||
// This is the base dpi that we are targetting. This is based on Mac OSXs default DPI,
|
||||
// and is the basis for all font sizes.
|
||||
const float BASE_DPI = 72.0f;
|
||||
|
|
|
@ -1,85 +0,0 @@
|
|||
//
|
||||
// XmppClient.cpp
|
||||
// interface/src
|
||||
//
|
||||
// Created by Dimitar Dobrev on 10/3/14.
|
||||
// Copyright 2013 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 <AccountManager.h>
|
||||
|
||||
#include "XmppClient.h"
|
||||
|
||||
const QString DEFAULT_XMPP_SERVER = "chat.highfidelity.io";
|
||||
const QString DEFAULT_CHAT_ROOM = "public@public-chat.highfidelity.io";
|
||||
|
||||
#ifdef HAVE_QXMPP
|
||||
XmppClient::XmppClient() :
|
||||
_xmppClient(),
|
||||
_xmppMUCManager()
|
||||
{
|
||||
AccountManager& accountManager = AccountManager::getInstance();
|
||||
connect(&accountManager, SIGNAL(profileChanged()), this, SLOT(connectToServer()));
|
||||
connect(&accountManager, SIGNAL(logoutComplete()), this, SLOT(disconnectFromServer()));
|
||||
}
|
||||
#else
|
||||
XmppClient::XmppClient() {
|
||||
|
||||
}
|
||||
#endif
|
||||
|
||||
XmppClient& XmppClient::getInstance() {
|
||||
static XmppClient sharedInstance;
|
||||
return sharedInstance;
|
||||
}
|
||||
|
||||
void XmppClient::xmppConnected() {
|
||||
#ifdef HAVE_QXMPP
|
||||
_publicChatRoom = _xmppMUCManager.addRoom(DEFAULT_CHAT_ROOM);
|
||||
_publicChatRoom->setNickName(AccountManager::getInstance().getAccountInfo().getUsername());
|
||||
_publicChatRoom->join();
|
||||
emit joinedPublicChatRoom();
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef HAVE_QXMPP
|
||||
void XmppClient::xmppError(QXmppClient::Error error) {
|
||||
qDebug() << "Error connnecting to XMPP for user "
|
||||
<< AccountManager::getInstance().getAccountInfo().getUsername() << ": " << error;
|
||||
}
|
||||
#endif
|
||||
|
||||
void XmppClient::connectToServer() {
|
||||
#ifdef HAVE_QXMPP
|
||||
disconnectFromServer();
|
||||
|
||||
if (_xmppClient.addExtension(&_xmppMUCManager)) {
|
||||
connect(&_xmppClient, SIGNAL(connected()), this, SLOT(xmppConnected()));
|
||||
connect(&_xmppClient, SIGNAL(error(QXmppClient::Error)), this, SLOT(xmppError(QXmppClient::Error)));
|
||||
}
|
||||
AccountManager& accountManager = AccountManager::getInstance();
|
||||
QString user = accountManager.getAccountInfo().getUsername();
|
||||
const QString& password = accountManager.getAccountInfo().getXMPPPassword();
|
||||
_xmppClient.connectToServer(user + "@" + DEFAULT_XMPP_SERVER, password);
|
||||
#endif
|
||||
}
|
||||
|
||||
void XmppClient::disconnectFromServer() {
|
||||
#ifdef HAVE_QXMPP
|
||||
if (_xmppClient.isConnected()) {
|
||||
_xmppClient.disconnectFromServer();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
XmppClient::XmppClient(const XmppClient& other) {
|
||||
Q_UNUSED(other);
|
||||
}
|
||||
|
||||
void XmppClient::operator =(XmppClient const& other) {
|
||||
Q_UNUSED(other);
|
||||
}
|
|
@ -1,57 +0,0 @@
|
|||
//
|
||||
// XmppClient.h
|
||||
// interface/src
|
||||
//
|
||||
// Created by Dimitar Dobrev on 10/3/14.
|
||||
// Copyright 2013 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_XmppClient_h
|
||||
#define hifi_XmppClient_h
|
||||
|
||||
#include <QObject>
|
||||
|
||||
#ifdef HAVE_QXMPP
|
||||
#include <qxmpp/QXmppClient.h>
|
||||
#include <qxmpp/QXmppMucManager.h>
|
||||
#endif
|
||||
|
||||
/// Generalized threaded processor for handling received inbound packets.
|
||||
class XmppClient : public QObject {
|
||||
Q_OBJECT
|
||||
public:
|
||||
static XmppClient& getInstance();
|
||||
|
||||
#ifdef HAVE_QXMPP
|
||||
QXmppClient& getXMPPClient() { return _xmppClient; }
|
||||
const QXmppMucRoom* getPublicChatRoom() const { return _publicChatRoom; }
|
||||
#endif
|
||||
|
||||
signals:
|
||||
void joinedPublicChatRoom();
|
||||
|
||||
private slots:
|
||||
void xmppConnected();
|
||||
#ifdef HAVE_QXMPP
|
||||
void xmppError(QXmppClient::Error error);
|
||||
#endif
|
||||
|
||||
void connectToServer();
|
||||
void disconnectFromServer();
|
||||
|
||||
private:
|
||||
XmppClient();
|
||||
XmppClient(XmppClient const& other); // not implemented
|
||||
void operator=(XmppClient const& other); // not implemented
|
||||
|
||||
#ifdef HAVE_QXMPP
|
||||
QXmppClient _xmppClient;
|
||||
QXmppMucManager _xmppMUCManager;
|
||||
QXmppMucRoom* _publicChatRoom;
|
||||
#endif
|
||||
};
|
||||
|
||||
#endif // hifi_XmppClient_h
|
|
@ -16,6 +16,7 @@
|
|||
#include <PathUtils.h>
|
||||
#include <GeometryCache.h>
|
||||
|
||||
#include "Application.h"
|
||||
#include "AudioToolBox.h"
|
||||
|
||||
// Mute icon configration
|
||||
|
@ -37,7 +38,7 @@ bool AudioToolBox::mousePressEvent(int x, int y) {
|
|||
void AudioToolBox::render(int x, int y, bool boxed) {
|
||||
glEnable(GL_TEXTURE_2D);
|
||||
|
||||
auto glCanvas = DependencyManager::get<GLCanvas>();
|
||||
auto glCanvas = Application::getInstance()->getGLWidget();
|
||||
if (_micTextureId == 0) {
|
||||
_micTextureId = glCanvas->bindTexture(QImage(PathUtils::resourcesPath() + "images/mic.svg"));
|
||||
}
|
||||
|
@ -105,8 +106,12 @@ void AudioToolBox::render(int x, int y, bool boxed) {
|
|||
glm::vec2 bottomRight(_iconBounds.right(), _iconBounds.bottom());
|
||||
glm::vec2 texCoordTopLeft(1,1);
|
||||
glm::vec2 texCoordBottomRight(0,0);
|
||||
|
||||
if (_boxQuadID == GeometryCache::UNKNOWN_ID) {
|
||||
_boxQuadID = DependencyManager::get<GeometryCache>()->allocateID();
|
||||
}
|
||||
|
||||
DependencyManager::get<GeometryCache>()->renderQuad(topLeft, bottomRight, texCoordTopLeft, texCoordBottomRight, quadColor);
|
||||
DependencyManager::get<GeometryCache>()->renderQuad(topLeft, bottomRight, texCoordTopLeft, texCoordBottomRight, quadColor, _boxQuadID);
|
||||
|
||||
glDisable(GL_TEXTURE_2D);
|
||||
}
|
|
@ -13,6 +13,7 @@
|
|||
#define hifi_AudioToolBox_h
|
||||
|
||||
#include <DependencyManager.h>
|
||||
#include <GeometryCache.h>
|
||||
|
||||
class AudioToolBox : public Dependency {
|
||||
SINGLETON_DEPENDENCY
|
||||
|
@ -26,6 +27,7 @@ private:
|
|||
GLuint _micTextureId = 0;
|
||||
GLuint _muteTextureId = 0;
|
||||
GLuint _boxTextureId = 0;
|
||||
int _boxQuadID = GeometryCache::UNKNOWN_ID;
|
||||
QRect _iconBounds;
|
||||
qint64 _iconPulseTimeReference = 0;
|
||||
};
|
||||
|
|
|
@ -77,7 +77,8 @@ Avatar::Avatar() :
|
|||
_moving(false),
|
||||
_collisionGroups(0),
|
||||
_initialized(false),
|
||||
_shouldRenderBillboard(true)
|
||||
_shouldRenderBillboard(true),
|
||||
_voiceSphereID(GeometryCache::UNKNOWN_ID)
|
||||
{
|
||||
// we may have been created in the network thread, but we live in the main thread
|
||||
moveToThread(Application::getInstance()->thread());
|
||||
|
@ -366,7 +367,7 @@ void Avatar::render(const glm::vec3& cameraPosition, RenderMode renderMode, bool
|
|||
|
||||
// render body
|
||||
if (Menu::getInstance()->isOptionChecked(MenuOption::Avatars)) {
|
||||
renderBody(renderMode, postLighting, glowLevel);
|
||||
renderBody(frustum, renderMode, postLighting, glowLevel);
|
||||
}
|
||||
|
||||
if (!postLighting && renderMode != SHADOW_RENDER_MODE) {
|
||||
|
@ -380,8 +381,7 @@ void Avatar::render(const glm::vec3& cameraPosition, RenderMode renderMode, bool
|
|||
foreach (const AvatarManager::LocalLight& light, DependencyManager::get<AvatarManager>()->getLocalLights()) {
|
||||
glm::vec3 direction = orientation * light.direction;
|
||||
DependencyManager::get<DeferredLightingEffect>()->addSpotLight(position - direction * distance,
|
||||
distance * 2.0f, glm::vec3(), light.color, light.color, 1.0f, 0.5f, 0.0f, direction,
|
||||
LIGHT_EXPONENT, LIGHT_CUTOFF);
|
||||
distance * 2.0f, light.color, 0.5f, orientation, LIGHT_EXPONENT, LIGHT_CUTOFF);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -439,8 +439,13 @@ void Avatar::render(const glm::vec3& cameraPosition, RenderMode renderMode, bool
|
|||
glPushMatrix();
|
||||
glTranslatef(_position.x, _position.y, _position.z);
|
||||
glScalef(height, height, height);
|
||||
|
||||
if (_voiceSphereID == GeometryCache::UNKNOWN_ID) {
|
||||
_voiceSphereID = DependencyManager::get<GeometryCache>()->allocateID();
|
||||
}
|
||||
DependencyManager::get<GeometryCache>()->renderSphere(sphereRadius, 15, 15,
|
||||
glm::vec4(SPHERE_COLOR[0], SPHERE_COLOR[1], SPHERE_COLOR[2], 1.0f - angle / MAX_SPHERE_ANGLE));
|
||||
glm::vec4(SPHERE_COLOR[0], SPHERE_COLOR[1], SPHERE_COLOR[2], 1.0f - angle / MAX_SPHERE_ANGLE), true,
|
||||
_voiceSphereID);
|
||||
|
||||
glPopMatrix();
|
||||
}
|
||||
|
@ -472,7 +477,7 @@ glm::quat Avatar::computeRotationFromBodyToWorldUp(float proportion) const {
|
|||
return glm::angleAxis(angle * proportion, axis);
|
||||
}
|
||||
|
||||
void Avatar::renderBody(RenderMode renderMode, bool postLighting, float glowLevel) {
|
||||
void Avatar::renderBody(ViewFrustum* renderFrustum, RenderMode renderMode, bool postLighting, float glowLevel) {
|
||||
Model::RenderMode modelRenderMode = (renderMode == SHADOW_RENDER_MODE) ?
|
||||
Model::SHADOW_RENDER_MODE : Model::DEFAULT_RENDER_MODE;
|
||||
{
|
||||
|
@ -489,11 +494,13 @@ void Avatar::renderBody(RenderMode renderMode, bool postLighting, float glowLeve
|
|||
if (postLighting) {
|
||||
getHand()->render(false, modelRenderMode);
|
||||
} else {
|
||||
_skeletonModel.render(1.0f, modelRenderMode);
|
||||
renderAttachments(renderMode);
|
||||
RenderArgs args;
|
||||
args._viewFrustum = renderFrustum;
|
||||
_skeletonModel.render(1.0f, modelRenderMode, &args);
|
||||
renderAttachments(renderMode, &args);
|
||||
}
|
||||
}
|
||||
getHead()->render(1.0f, modelRenderMode, postLighting);
|
||||
getHead()->render(1.0f, renderFrustum, modelRenderMode, postLighting);
|
||||
}
|
||||
|
||||
bool Avatar::shouldRenderHead(const glm::vec3& cameraPosition, RenderMode renderMode) const {
|
||||
|
@ -520,11 +527,11 @@ void Avatar::simulateAttachments(float deltaTime) {
|
|||
}
|
||||
}
|
||||
|
||||
void Avatar::renderAttachments(RenderMode renderMode) {
|
||||
void Avatar::renderAttachments(RenderMode renderMode, RenderArgs* args) {
|
||||
Model::RenderMode modelRenderMode = (renderMode == SHADOW_RENDER_MODE) ?
|
||||
Model::SHADOW_RENDER_MODE : Model::DEFAULT_RENDER_MODE;
|
||||
foreach (Model* model, _attachmentModels) {
|
||||
model->render(1.0f, modelRenderMode);
|
||||
model->render(1.0f, modelRenderMode, args);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -223,11 +223,11 @@ protected:
|
|||
|
||||
float calculateDisplayNameScaleFactor(const glm::vec3& textPosition, bool inHMD);
|
||||
void renderDisplayName();
|
||||
virtual void renderBody(RenderMode renderMode, bool postLighting, float glowLevel = 0.0f);
|
||||
virtual void renderBody(ViewFrustum* renderFrustum, RenderMode renderMode, bool postLighting, float glowLevel = 0.0f);
|
||||
virtual bool shouldRenderHead(const glm::vec3& cameraPosition, RenderMode renderMode) const;
|
||||
|
||||
void simulateAttachments(float deltaTime);
|
||||
virtual void renderAttachments(RenderMode renderMode);
|
||||
virtual void renderAttachments(RenderMode renderMode, RenderArgs* args);
|
||||
|
||||
virtual void updateJointMappings();
|
||||
|
||||
|
@ -243,6 +243,8 @@ private:
|
|||
float getBillboardSize() const;
|
||||
|
||||
static int _jointConesID;
|
||||
|
||||
int _voiceSphereID;
|
||||
};
|
||||
|
||||
#endif // hifi_Avatar_h
|
||||
|
|
|
@ -39,6 +39,8 @@ void FaceModel::simulate(float deltaTime, bool fullUpdate) {
|
|||
setPupilDilation(_owningHead->getPupilDilation());
|
||||
setBlendshapeCoefficients(_owningHead->getBlendshapeCoefficients());
|
||||
|
||||
invalidCalculatedMeshBoxes();
|
||||
|
||||
if (isActive()) {
|
||||
setOffset(-_geometry->getFBXGeometry().neckPivot);
|
||||
Model::simulateInternal(deltaTime);
|
||||
|
|
|
@ -42,7 +42,6 @@ Head::Head(Avatar* owningAvatar) :
|
|||
_mouth2(0.0f),
|
||||
_mouth3(0.0f),
|
||||
_mouth4(0.0f),
|
||||
_angularVelocity(0,0,0),
|
||||
_renderLookatVectors(false),
|
||||
_saccade(0.0f, 0.0f, 0.0f),
|
||||
_saccadeTarget(0.0f, 0.0f, 0.0f),
|
||||
|
@ -244,13 +243,15 @@ void Head::relaxLean(float deltaTime) {
|
|||
_deltaLeanForward *= relaxationFactor;
|
||||
}
|
||||
|
||||
void Head::render(float alpha, Model::RenderMode mode, bool postLighting) {
|
||||
void Head::render(float alpha, ViewFrustum* renderFrustum, Model::RenderMode mode, bool postLighting) {
|
||||
if (postLighting) {
|
||||
if (_renderLookatVectors) {
|
||||
renderLookatVectors(_leftEyePosition, _rightEyePosition, getCorrectedLookAtPosition());
|
||||
}
|
||||
} else {
|
||||
_faceModel.render(alpha, mode);
|
||||
RenderArgs args;
|
||||
args._viewFrustum = renderFrustum;
|
||||
_faceModel.render(alpha, mode, &args);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -40,7 +40,7 @@ public:
|
|||
void init();
|
||||
void reset();
|
||||
void simulate(float deltaTime, bool isMine, bool billboard = false);
|
||||
void render(float alpha, Model::RenderMode mode, bool postLighting);
|
||||
void render(float alpha, ViewFrustum* renderFrustum, Model::RenderMode mode, bool postLighting);
|
||||
void setScale(float scale);
|
||||
void setPosition(glm::vec3 position) { _position = position; }
|
||||
void setAverageLoudness(float averageLoudness) { _averageLoudness = averageLoudness; }
|
||||
|
@ -55,9 +55,6 @@ public:
|
|||
|
||||
/// \return orientationBody * orientationBasePitch
|
||||
glm::quat getCameraOrientation () const;
|
||||
|
||||
const glm::vec3& getAngularVelocity() const { return _angularVelocity; }
|
||||
void setAngularVelocity(glm::vec3 angularVelocity) { _angularVelocity = angularVelocity; }
|
||||
|
||||
void setCorrectedLookAtPosition(glm::vec3 correctedLookAtPosition);
|
||||
glm::vec3 getCorrectedLookAtPosition();
|
||||
|
@ -130,7 +127,6 @@ private:
|
|||
float _mouth2;
|
||||
float _mouth3;
|
||||
float _mouth4;
|
||||
glm::vec3 _angularVelocity;
|
||||
bool _renderLookatVectors;
|
||||
glm::vec3 _saccade;
|
||||
glm::vec3 _saccadeTarget;
|
||||
|
|
|
@ -294,12 +294,7 @@ void MyAvatar::updateFromTrackers(float deltaTime) {
|
|||
return;
|
||||
}
|
||||
|
||||
if (Application::getInstance()->getPrioVR()->hasHeadRotation()) {
|
||||
estimatedRotation = glm::degrees(safeEulerAngles(Application::getInstance()->getPrioVR()->getHeadRotation()));
|
||||
estimatedRotation.x *= -1.0f;
|
||||
estimatedRotation.z *= -1.0f;
|
||||
|
||||
} else if (OculusManager::isConnected()) {
|
||||
if (OculusManager::isConnected()) {
|
||||
estimatedPosition = OculusManager::getRelativePosition();
|
||||
estimatedPosition.x *= -1.0f;
|
||||
_trackedHeadPosition = estimatedPosition;
|
||||
|
@ -349,13 +344,6 @@ void MyAvatar::updateFromTrackers(float deltaTime) {
|
|||
}
|
||||
head->setDeltaRoll(estimatedRotation.z);
|
||||
|
||||
// the priovr can give us exact lean
|
||||
if (Application::getInstance()->getPrioVR()->isActive()) {
|
||||
glm::vec3 eulers = glm::degrees(safeEulerAngles(Application::getInstance()->getPrioVR()->getTorsoRotation()));
|
||||
head->setLeanSideways(eulers.z);
|
||||
head->setLeanForward(eulers.x);
|
||||
return;
|
||||
}
|
||||
// Update torso lean distance based on accelerometer data
|
||||
const float TORSO_LENGTH = 0.5f;
|
||||
glm::vec3 relativePosition = estimatedPosition - glm::vec3(0.0f, -TORSO_LENGTH, 0.0f);
|
||||
|
@ -892,13 +880,7 @@ void MyAvatar::updateLookAtTargetAvatar() {
|
|||
_lookAtTargetAvatar.clear();
|
||||
_targetAvatarPosition = glm::vec3(0.0f);
|
||||
|
||||
glm::quat faceRotation = Application::getInstance()->getViewFrustum()->getOrientation();
|
||||
FaceTracker* tracker = Application::getInstance()->getActiveFaceTracker();
|
||||
if (tracker) {
|
||||
// If faceshift or other face tracker in use, add on the actual angle of the head
|
||||
faceRotation *= tracker->getHeadRotation();
|
||||
}
|
||||
glm::vec3 lookForward = faceRotation * IDENTITY_FRONT;
|
||||
glm::vec3 lookForward = getHead()->getFinalOrientationInWorldFrame() * IDENTITY_FRONT;
|
||||
glm::vec3 cameraPosition = Application::getInstance()->getCamera()->getPosition();
|
||||
|
||||
float smallestAngleTo = glm::radians(Application::getInstance()->getCamera()->getFieldOfView()) / 2.0f;
|
||||
|
@ -1085,7 +1067,7 @@ void MyAvatar::attach(const QString& modelURL, const QString& jointName, const g
|
|||
Avatar::attach(modelURL, jointName, translation, rotation, scale, allowDuplicates, useSaved);
|
||||
}
|
||||
|
||||
void MyAvatar::renderBody(RenderMode renderMode, bool postLighting, float glowLevel) {
|
||||
void MyAvatar::renderBody(ViewFrustum* renderFrustum, RenderMode renderMode, bool postLighting, float glowLevel) {
|
||||
if (!(_skeletonModel.isRenderable() && getHead()->getFaceModel().isRenderable())) {
|
||||
return; // wait until both models are loaded
|
||||
}
|
||||
|
@ -1094,15 +1076,17 @@ void MyAvatar::renderBody(RenderMode renderMode, bool postLighting, float glowLe
|
|||
Model::RenderMode modelRenderMode = (renderMode == SHADOW_RENDER_MODE) ?
|
||||
Model::SHADOW_RENDER_MODE : Model::DEFAULT_RENDER_MODE;
|
||||
if (!postLighting) {
|
||||
_skeletonModel.render(1.0f, modelRenderMode);
|
||||
renderAttachments(renderMode);
|
||||
RenderArgs args;
|
||||
args._viewFrustum = renderFrustum;
|
||||
_skeletonModel.render(1.0f, modelRenderMode, &args);
|
||||
renderAttachments(renderMode, &args);
|
||||
}
|
||||
|
||||
// Render head so long as the camera isn't inside it
|
||||
const Camera *camera = Application::getInstance()->getCamera();
|
||||
const glm::vec3 cameraPos = camera->getPosition();
|
||||
if (shouldRenderHead(cameraPos, renderMode)) {
|
||||
getHead()->render(1.0f, modelRenderMode, postLighting);
|
||||
getHead()->render(1.0f, renderFrustum, modelRenderMode, postLighting);
|
||||
}
|
||||
if (postLighting) {
|
||||
getHand()->render(true, modelRenderMode);
|
||||
|
@ -1164,15 +1148,8 @@ void MyAvatar::updateOrientation(float deltaTime) {
|
|||
pitch *= DEGREES_PER_RADIAN;
|
||||
roll *= DEGREES_PER_RADIAN;
|
||||
|
||||
// Record the angular velocity
|
||||
Head* head = getHead();
|
||||
if (deltaTime > 0.0f) {
|
||||
glm::vec3 angularVelocity(pitch - head->getBasePitch(), yaw - head->getBaseYaw(), roll - head->getBaseRoll());
|
||||
angularVelocity *= 1.0f / deltaTime;
|
||||
head->setAngularVelocity(angularVelocity);
|
||||
}
|
||||
|
||||
//Invert yaw and roll when in mirror mode
|
||||
Head* head = getHead();
|
||||
if (Application::getInstance()->getCamera()->getMode() == CAMERA_MODE_MIRROR) {
|
||||
head->setBaseYaw(-yaw);
|
||||
head->setBasePitch(pitch);
|
||||
|
@ -1900,9 +1877,9 @@ void MyAvatar::onToggleRagdoll() {
|
|||
}
|
||||
}
|
||||
|
||||
void MyAvatar::renderAttachments(RenderMode renderMode) {
|
||||
void MyAvatar::renderAttachments(RenderMode renderMode, RenderArgs* args) {
|
||||
if (Application::getInstance()->getCamera()->getMode() != CAMERA_MODE_FIRST_PERSON || renderMode == MIRROR_RENDER_MODE) {
|
||||
Avatar::renderAttachments(renderMode);
|
||||
Avatar::renderAttachments(renderMode, args);
|
||||
return;
|
||||
}
|
||||
const FBXGeometry& geometry = _skeletonModel.getGeometry()->getFBXGeometry();
|
||||
|
@ -1912,7 +1889,7 @@ void MyAvatar::renderAttachments(RenderMode renderMode) {
|
|||
for (int i = 0; i < _attachmentData.size(); i++) {
|
||||
const QString& jointName = _attachmentData.at(i).jointName;
|
||||
if (jointName != headJointName && jointName != "Head") {
|
||||
_attachmentModels.at(i)->render(1.0f, modelRenderMode);
|
||||
_attachmentModels.at(i)->render(1.0f, modelRenderMode, args);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -38,7 +38,7 @@ public:
|
|||
void updateFromTrackers(float deltaTime);
|
||||
|
||||
void render(const glm::vec3& cameraPosition, RenderMode renderMode = NORMAL_RENDER_MODE, bool postLighting = false);
|
||||
void renderBody(RenderMode renderMode, bool postLighting, float glowLevel = 0.0f);
|
||||
void renderBody(ViewFrustum* renderFrustum, RenderMode renderMode, bool postLighting, float glowLevel = 0.0f);
|
||||
bool shouldRenderHead(const glm::vec3& cameraPosition, RenderMode renderMode) const;
|
||||
void renderDebugBodyPoints();
|
||||
|
||||
|
@ -187,7 +187,7 @@ signals:
|
|||
void transformChanged();
|
||||
|
||||
protected:
|
||||
virtual void renderAttachments(RenderMode renderMode);
|
||||
virtual void renderAttachments(RenderMode renderMode, RenderArgs* args);
|
||||
|
||||
private:
|
||||
float _turningKeyPressTime;
|
||||
|
|
|
@ -106,21 +106,6 @@ void SkeletonModel::simulate(float deltaTime, bool fullUpdate) {
|
|||
}
|
||||
|
||||
const FBXGeometry& geometry = _geometry->getFBXGeometry();
|
||||
PrioVR* prioVR = Application::getInstance()->getPrioVR();
|
||||
if (prioVR->isActive()) {
|
||||
for (int i = 0; i < prioVR->getJointRotations().size(); i++) {
|
||||
int humanIKJointIndex = prioVR->getHumanIKJointIndices().at(i);
|
||||
if (humanIKJointIndex == -1) {
|
||||
continue;
|
||||
}
|
||||
int jointIndex = geometry.humanIKJointIndices.at(humanIKJointIndex);
|
||||
if (jointIndex != -1) {
|
||||
JointState& state = _jointStates[jointIndex];
|
||||
state.setRotationInBindFrame(prioVR->getJointRotations().at(i), PALM_PRIORITY);
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// find the left and rightmost active palms
|
||||
int leftPalmIndex, rightPalmIndex;
|
||||
|
@ -294,7 +279,7 @@ void SkeletonModel::updateJointState(int index) {
|
|||
}
|
||||
|
||||
void SkeletonModel::maybeUpdateLeanRotation(const JointState& parentState, JointState& state) {
|
||||
if (!_owningAvatar->isMyAvatar() || Application::getInstance()->getPrioVR()->isActive()) {
|
||||
if (!_owningAvatar->isMyAvatar()) {
|
||||
return;
|
||||
}
|
||||
// get the rotation axes in joint space and use them to adjust the rotation
|
||||
|
|
|
@ -17,15 +17,89 @@
|
|||
#include <QElapsedTimer>
|
||||
|
||||
#include "DdeFaceTracker.h"
|
||||
#include "FaceshiftConstants.h"
|
||||
|
||||
static const QHostAddress DDE_FEATURE_POINT_SERVER_ADDR("127.0.0.1");
|
||||
static const quint16 DDE_FEATURE_POINT_SERVER_PORT = 5555;
|
||||
|
||||
static const int NUM_EXPRESSION = 46;
|
||||
static const int MIN_PACKET_SIZE = (8 + NUM_EXPRESSION) * sizeof(float) + sizeof(int);
|
||||
static const int NUM_EXPRESSIONS = 46;
|
||||
static const int MIN_PACKET_SIZE = (8 + NUM_EXPRESSIONS) * sizeof(float) + sizeof(int);
|
||||
static const int MAX_NAME_SIZE = 31;
|
||||
|
||||
struct Packet{
|
||||
// There's almost but not quite a 1-1 correspondence between DDE's 46 and Faceshift 1.3's 48 packets.
|
||||
// The best guess at mapping is to:
|
||||
// - Swap L and R values
|
||||
// - Skip two Faceshift values: JawChew (22) and LipsLowerDown (37)
|
||||
static const int DDE_TO_FACESHIFT_MAPPING[] = {
|
||||
1, 0, 3, 2, 5, 4, 7, 6, 9, 8, 11, 10, 13, 12, 15, 14,
|
||||
16,
|
||||
18, 17,
|
||||
19,
|
||||
23,
|
||||
21,
|
||||
// Skip JawChew
|
||||
20,
|
||||
25, 24, 27, 26, 29, 28, 31, 30, 33, 32,
|
||||
34, 35, 36,
|
||||
// Skip LipsLowerDown
|
||||
38, 39, 40, 41, 42, 43, 44, 45,
|
||||
47, 46
|
||||
};
|
||||
|
||||
// The DDE coefficients, overall, range from -0.2 to 1.5 or so. However, individual coefficients typically vary much
|
||||
// less than this.
|
||||
static const float DDE_COEFFICIENT_SCALES[] = {
|
||||
4.0f, // EyeBlink_L
|
||||
4.0f, // EyeBlink_R
|
||||
1.0f, // EyeSquint_L
|
||||
1.0f, // EyeSquint_R
|
||||
1.0f, // EyeDown_L
|
||||
1.0f, // EyeDown_R
|
||||
1.0f, // EyeIn_L
|
||||
1.0f, // EyeIn_R
|
||||
4.0f, // EyeOpen_L
|
||||
4.0f, // EyeOpen_R
|
||||
1.0f, // EyeOut_L
|
||||
1.0f, // EyeOut_R
|
||||
1.0f, // EyeUp_L
|
||||
1.0f, // EyeUp_R
|
||||
3.0f, // BrowsD_L
|
||||
3.0f, // BrowsD_R
|
||||
3.0f, // BrowsU_C
|
||||
3.0f, // BrowsU_L
|
||||
3.0f, // BrowsU_R
|
||||
1.0f, // JawFwd
|
||||
1.5f, // JawLeft
|
||||
1.8f, // JawOpen
|
||||
1.0f, // JawChew
|
||||
1.5f, // JawRight
|
||||
1.5f, // MouthLeft
|
||||
1.5f, // MouthRight
|
||||
1.5f, // MouthFrown_L
|
||||
1.5f, // MouthFrown_R
|
||||
1.5f, // MouthSmile_L
|
||||
1.5f, // MouthSmile_R
|
||||
1.0f, // MouthDimple_L
|
||||
1.0f, // MouthDimple_R
|
||||
1.0f, // LipsStretch_L
|
||||
1.0f, // LipsStretch_R
|
||||
1.0f, // LipsUpperClose
|
||||
1.0f, // LipsLowerClose
|
||||
1.0f, // LipsUpperUp
|
||||
1.0f, // LipsLowerDown
|
||||
1.0f, // LipsUpperOpen
|
||||
1.0f, // LipsLowerOpen
|
||||
2.5f, // LipsFunnel
|
||||
2.0f, // LipsPucker
|
||||
1.5f, // ChinLowerRaise
|
||||
1.5f, // ChinUpperRaise
|
||||
1.0f, // Sneer
|
||||
3.0f, // Puff
|
||||
1.0f, // CheekSquint_L
|
||||
1.0f // CheekSquint_R
|
||||
};
|
||||
|
||||
struct Packet {
|
||||
//roughly in mm
|
||||
float focal_length[1];
|
||||
float translation[3];
|
||||
|
@ -33,8 +107,9 @@ struct Packet{
|
|||
//quaternion
|
||||
float rotation[4];
|
||||
|
||||
//blendshape coefficients ranging between -0.2 and 1.5
|
||||
float expressions[NUM_EXPRESSION];
|
||||
// The DDE coefficients, overall, range from -0.2 to 1.5 or so. However, individual coefficients typically vary much
|
||||
// less than this.
|
||||
float expressions[NUM_EXPRESSIONS];
|
||||
|
||||
//avatar id selected on the UI
|
||||
int avatar_id;
|
||||
|
@ -50,6 +125,8 @@ DdeFaceTracker::DdeFaceTracker() :
|
|||
}
|
||||
|
||||
DdeFaceTracker::DdeFaceTracker(const QHostAddress& host, quint16 port) :
|
||||
_host(host),
|
||||
_port(port),
|
||||
_lastReceiveTimestamp(0),
|
||||
_reset(false),
|
||||
_leftBlinkIndex(0), // see http://support.faceshift.com/support/articles/35129-export-of-blendshapes
|
||||
|
@ -64,10 +141,13 @@ DdeFaceTracker::DdeFaceTracker(const QHostAddress& host, quint16 port) :
|
|||
_mouthSmileLeftIndex(28),
|
||||
_mouthSmileRightIndex(29),
|
||||
_jawOpenIndex(21),
|
||||
_host(host),
|
||||
_port(port)
|
||||
_previousTranslation(glm::vec3()),
|
||||
_previousRotation(glm::quat())
|
||||
{
|
||||
_blendshapeCoefficients.resize(NUM_EXPRESSION);
|
||||
_coefficients.resize(NUM_FACESHIFT_BLENDSHAPES);
|
||||
_previousCoefficients.resize(NUM_FACESHIFT_BLENDSHAPES);
|
||||
|
||||
_blendshapeCoefficients.resize(NUM_FACESHIFT_BLENDSHAPES);
|
||||
|
||||
connect(&_udpSocket, SIGNAL(readyRead()), SLOT(readPendingDatagrams()));
|
||||
connect(&_udpSocket, SIGNAL(error(QAbstractSocket::SocketError)), SLOT(socketErrorOccurred(QAbstractSocket::SocketError)));
|
||||
|
@ -80,18 +160,6 @@ DdeFaceTracker::~DdeFaceTracker() {
|
|||
}
|
||||
}
|
||||
|
||||
void DdeFaceTracker::init() {
|
||||
|
||||
}
|
||||
|
||||
void DdeFaceTracker::reset() {
|
||||
_reset = true;
|
||||
}
|
||||
|
||||
void DdeFaceTracker::update() {
|
||||
|
||||
}
|
||||
|
||||
void DdeFaceTracker::setEnabled(bool enabled) {
|
||||
// isOpen() does not work as one might expect on QUdpSocket; don't test isOpen() before closing socket.
|
||||
_udpSocket.close();
|
||||
|
@ -151,37 +219,6 @@ float DdeFaceTracker::getBlendshapeCoefficient(int index) const {
|
|||
return (index >= 0 && index < (int)_blendshapeCoefficients.size()) ? _blendshapeCoefficients[index] : 0.0f;
|
||||
}
|
||||
|
||||
static const float DDE_MIN_RANGE = -0.2f;
|
||||
static const float DDE_MAX_RANGE = 1.5f;
|
||||
float rescaleCoef(float ddeCoef) {
|
||||
return (ddeCoef - DDE_MIN_RANGE) / (DDE_MAX_RANGE - DDE_MIN_RANGE);
|
||||
}
|
||||
|
||||
const int MIN = 0;
|
||||
const int AVG = 1;
|
||||
const int MAX = 2;
|
||||
const float LONG_TERM_AVERAGE = 0.999f;
|
||||
|
||||
|
||||
void resetCoefficient(float * coefficient, float currentValue) {
|
||||
coefficient[MIN] = coefficient[MAX] = coefficient[AVG] = currentValue;
|
||||
}
|
||||
|
||||
float updateAndGetCoefficient(float * coefficient, float currentValue, bool scaleToRange = false) {
|
||||
coefficient[MIN] = (currentValue < coefficient[MIN]) ? currentValue : coefficient[MIN];
|
||||
coefficient[MAX] = (currentValue > coefficient[MAX]) ? currentValue : coefficient[MAX];
|
||||
coefficient[AVG] = LONG_TERM_AVERAGE * coefficient[AVG] + (1.0f - LONG_TERM_AVERAGE) * currentValue;
|
||||
if (coefficient[MAX] > coefficient[MIN]) {
|
||||
if (scaleToRange) {
|
||||
return glm::clamp((currentValue - coefficient[AVG]) / (coefficient[MAX] - coefficient[MIN]), 0.0f, 1.0f);
|
||||
} else {
|
||||
return glm::clamp(currentValue - coefficient[AVG], 0.0f, 1.0f);
|
||||
}
|
||||
} else {
|
||||
return 0.0f;
|
||||
}
|
||||
}
|
||||
|
||||
void DdeFaceTracker::decodePacket(const QByteArray& buffer) {
|
||||
if(buffer.size() > MIN_PACKET_SIZE) {
|
||||
Packet packet;
|
||||
|
@ -196,9 +233,6 @@ void DdeFaceTracker::decodePacket(const QByteArray& buffer) {
|
|||
if (_reset || (_lastReceiveTimestamp == 0)) {
|
||||
memcpy(&_referenceTranslation, &translation, sizeof(glm::vec3));
|
||||
memcpy(&_referenceRotation, &rotation, sizeof(glm::quat));
|
||||
|
||||
resetCoefficient(_rightEye, packet.expressions[0]);
|
||||
resetCoefficient(_leftEye, packet.expressions[1]);
|
||||
_reset = false;
|
||||
}
|
||||
|
||||
|
@ -207,51 +241,61 @@ void DdeFaceTracker::decodePacket(const QByteArray& buffer) {
|
|||
translation -= _referenceTranslation;
|
||||
translation /= LEAN_DAMPING_FACTOR;
|
||||
translation.x *= -1;
|
||||
|
||||
_headTranslation = (translation + _previousTranslation) / 2.0f;
|
||||
_previousTranslation = translation;
|
||||
|
||||
// Compute relative rotation
|
||||
rotation = glm::inverse(_referenceRotation) * rotation;
|
||||
|
||||
// copy values
|
||||
_headTranslation = translation;
|
||||
_headRotation = rotation;
|
||||
|
||||
if (_lastReceiveTimestamp == 0) {
|
||||
// On first packet, reset coefficients
|
||||
}
|
||||
|
||||
// Set blendshapes
|
||||
float EYE_MAGNIFIER = 4.0f;
|
||||
float rightEye = glm::clamp((updateAndGetCoefficient(_rightEye, packet.expressions[0])) * EYE_MAGNIFIER, 0.0f, 1.0f);
|
||||
_blendshapeCoefficients[_rightBlinkIndex] = rightEye;
|
||||
float leftEye = glm::clamp((updateAndGetCoefficient(_leftEye, packet.expressions[1])) * EYE_MAGNIFIER, 0.0f, 1.0f);
|
||||
_blendshapeCoefficients[_leftBlinkIndex] = leftEye;
|
||||
_headRotation = (rotation + _previousRotation) / 2.0f;
|
||||
_previousRotation = rotation;
|
||||
|
||||
|
||||
float leftBrow = 1.0f - rescaleCoef(packet.expressions[14]);
|
||||
if (leftBrow < 0.5f) {
|
||||
_blendshapeCoefficients[_browDownLeftIndex] = 1.0f - 2.0f * leftBrow;
|
||||
_blendshapeCoefficients[_browUpLeftIndex] = 0.0f;
|
||||
} else {
|
||||
_blendshapeCoefficients[_browDownLeftIndex] = 0.0f;
|
||||
_blendshapeCoefficients[_browUpLeftIndex] = 2.0f * (leftBrow - 0.5f);
|
||||
// Translate DDE coefficients to Faceshift compatible coefficients
|
||||
for (int i = 0; i < NUM_EXPRESSIONS; i += 1) {
|
||||
_coefficients[DDE_TO_FACESHIFT_MAPPING[i]] = packet.expressions[i];
|
||||
}
|
||||
float rightBrow = 1.0f - rescaleCoef(packet.expressions[15]);
|
||||
if (rightBrow < 0.5f) {
|
||||
_blendshapeCoefficients[_browDownRightIndex] = 1.0f - 2.0f * rightBrow;
|
||||
_blendshapeCoefficients[_browUpRightIndex] = 0.0f;
|
||||
|
||||
// Use EyeBlink values to control both EyeBlink and EyeOpen
|
||||
static const float RELAXED_EYE_VALUE = 0.1f;
|
||||
float leftEye = (_coefficients[_leftBlinkIndex] + _previousCoefficients[_leftBlinkIndex]) / 2.0f;
|
||||
float rightEye = (_coefficients[_rightBlinkIndex] + _previousCoefficients[_rightBlinkIndex]) / 2.0f;
|
||||
if (leftEye > RELAXED_EYE_VALUE) {
|
||||
_coefficients[_leftBlinkIndex] = leftEye - RELAXED_EYE_VALUE;
|
||||
_coefficients[_leftEyeOpenIndex] = 0.0f;
|
||||
} else {
|
||||
_blendshapeCoefficients[_browDownRightIndex] = 0.0f;
|
||||
_blendshapeCoefficients[_browUpRightIndex] = 2.0f * (rightBrow - 0.5f);
|
||||
_coefficients[_leftBlinkIndex] = 0.0f;
|
||||
_coefficients[_leftEyeOpenIndex] = RELAXED_EYE_VALUE - leftEye;
|
||||
}
|
||||
|
||||
float JAW_OPEN_MAGNIFIER = 1.4f;
|
||||
_blendshapeCoefficients[_jawOpenIndex] = rescaleCoef(packet.expressions[21]) * JAW_OPEN_MAGNIFIER;
|
||||
|
||||
float SMILE_MULTIPLIER = 2.0f;
|
||||
_blendshapeCoefficients[_mouthSmileLeftIndex] = glm::clamp(packet.expressions[24] * SMILE_MULTIPLIER, 0.0f, 1.0f);
|
||||
_blendshapeCoefficients[_mouthSmileRightIndex] = glm::clamp(packet.expressions[23] * SMILE_MULTIPLIER, 0.0f, 1.0f);
|
||||
|
||||
|
||||
if (rightEye > RELAXED_EYE_VALUE) {
|
||||
_coefficients[_rightBlinkIndex] = rightEye - RELAXED_EYE_VALUE;
|
||||
_coefficients[_rightEyeOpenIndex] = 0.0f;
|
||||
} else {
|
||||
_coefficients[_rightBlinkIndex] = 0.0f;
|
||||
_coefficients[_rightEyeOpenIndex] = RELAXED_EYE_VALUE - rightEye;
|
||||
}
|
||||
|
||||
// Use BrowsU_C to control both brows' up and down
|
||||
_coefficients[_browDownLeftIndex] = -_coefficients[_browUpCenterIndex];
|
||||
_coefficients[_browDownRightIndex] = -_coefficients[_browUpCenterIndex];
|
||||
_coefficients[_browUpLeftIndex] = _coefficients[_browUpCenterIndex];
|
||||
_coefficients[_browUpRightIndex] = _coefficients[_browUpCenterIndex];
|
||||
|
||||
// Offset jaw open coefficient
|
||||
static const float JAW_OPEN_THRESHOLD = 0.16f;
|
||||
_coefficients[_jawOpenIndex] = _coefficients[_jawOpenIndex] - JAW_OPEN_THRESHOLD;
|
||||
|
||||
// Offset smile coefficients
|
||||
static const float SMILE_THRESHOLD = 0.18f;
|
||||
_coefficients[_mouthSmileLeftIndex] = _coefficients[_mouthSmileLeftIndex] - SMILE_THRESHOLD;
|
||||
_coefficients[_mouthSmileRightIndex] = _coefficients[_mouthSmileRightIndex] - SMILE_THRESHOLD;
|
||||
|
||||
|
||||
// Scale all coefficients
|
||||
for (int i = 0; i < NUM_EXPRESSIONS; i += 1) {
|
||||
_blendshapeCoefficients[i]
|
||||
= glm::clamp(DDE_COEFFICIENT_SCALES[i] * (_coefficients[i] + _previousCoefficients[i]) / 2.0f, 0.0f, 1.0f);
|
||||
_previousCoefficients[i] = _coefficients[i];
|
||||
}
|
||||
|
||||
} else {
|
||||
qDebug() << "[Error] DDE Face Tracker Decode Error";
|
||||
}
|
||||
|
|
|
@ -23,12 +23,10 @@ class DdeFaceTracker : public FaceTracker, public Dependency {
|
|||
SINGLETON_DEPENDENCY
|
||||
|
||||
public:
|
||||
//initialization
|
||||
void init();
|
||||
void reset();
|
||||
void update();
|
||||
|
||||
bool isActive() const;
|
||||
virtual void reset() { _reset = true; }
|
||||
|
||||
virtual bool isActive() const;
|
||||
virtual bool isTracking() const { return isActive(); }
|
||||
|
||||
float getLeftBlink() const { return getBlendshapeCoefficient(_leftBlinkIndex); }
|
||||
float getRightBlink() const { return getBlendshapeCoefficient(_rightBlinkIndex); }
|
||||
|
@ -90,10 +88,13 @@ private:
|
|||
int _mouthSmileRightIndex;
|
||||
|
||||
int _jawOpenIndex;
|
||||
|
||||
float _leftEye[3];
|
||||
float _rightEye[3];
|
||||
|
||||
|
||||
QVector<float> _coefficients;
|
||||
|
||||
// Previous values for simple smoothing
|
||||
glm::vec3 _previousTranslation;
|
||||
glm::quat _previousRotation;
|
||||
QVector<float> _previousCoefficients;
|
||||
};
|
||||
|
||||
#endif // hifi_DdeFaceTracker_h
|
|
@ -9,9 +9,60 @@
|
|||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#include <GLMHelpers.h>
|
||||
|
||||
#include "FaceTracker.h"
|
||||
|
||||
FaceTracker::FaceTracker() :
|
||||
_estimatedEyePitch(0.0f),
|
||||
_estimatedEyeYaw(0.0f) {
|
||||
inline float FaceTracker::getBlendshapeCoefficient(int index) const {
|
||||
return isValidBlendshapeIndex(index) ? glm::mix(0.0f, _blendshapeCoefficients[index], getFadeCoefficient())
|
||||
: 0.0f;
|
||||
}
|
||||
|
||||
const QVector<float>& FaceTracker::getBlendshapeCoefficients() const {
|
||||
static QVector<float> blendshapes;
|
||||
float fadeCoefficient = getFadeCoefficient();
|
||||
if (fadeCoefficient == 1.0f) {
|
||||
return _blendshapeCoefficients;
|
||||
} else {
|
||||
blendshapes.resize(_blendshapeCoefficients.size());
|
||||
for (int i = 0; i < _blendshapeCoefficients.size(); i++) {
|
||||
blendshapes[i] = glm::mix(0.0f, _blendshapeCoefficients[i], fadeCoefficient);
|
||||
}
|
||||
return blendshapes;
|
||||
}
|
||||
}
|
||||
|
||||
float FaceTracker::getFadeCoefficient() const {
|
||||
return _fadeCoefficient;
|
||||
}
|
||||
|
||||
const glm::vec3 FaceTracker::getHeadTranslation() const {
|
||||
return glm::mix(glm::vec3(0.0f), _headTranslation, getFadeCoefficient());
|
||||
}
|
||||
|
||||
const glm::quat FaceTracker::getHeadRotation() const {
|
||||
return safeMix(glm::quat(), _headRotation, getFadeCoefficient());
|
||||
}
|
||||
|
||||
void FaceTracker::update(float deltaTime) {
|
||||
// Based on exponential distributions: http://en.wikipedia.org/wiki/Exponential_distribution
|
||||
static const float EPSILON = 0.02f; // MUST BE < 1.0f
|
||||
static const float INVERSE_AT_EPSILON = -std::log(EPSILON); // So that f(1.0f) = EPSILON ~ 0.0f
|
||||
static const float RELAXATION_TIME = 0.8f; // sec
|
||||
|
||||
if (isTracking()) {
|
||||
if (_relaxationStatus == 1.0f) {
|
||||
_fadeCoefficient = 1.0f;
|
||||
return;
|
||||
}
|
||||
_relaxationStatus = glm::clamp(_relaxationStatus + deltaTime / RELAXATION_TIME, 0.0f, 1.0f);
|
||||
_fadeCoefficient = 1.0f - std::exp(-_relaxationStatus * INVERSE_AT_EPSILON);
|
||||
} else {
|
||||
if (_relaxationStatus == 0.0f) {
|
||||
_fadeCoefficient = 0.0f;
|
||||
return;
|
||||
}
|
||||
_relaxationStatus = glm::clamp(_relaxationStatus - deltaTime / RELAXATION_TIME, 0.0f, 1.0f);
|
||||
_fadeCoefficient = std::exp(-(1.0f - _relaxationStatus) * INVERSE_AT_EPSILON);
|
||||
}
|
||||
}
|
|
@ -18,29 +18,40 @@
|
|||
#include <glm/glm.hpp>
|
||||
#include <glm/gtc/quaternion.hpp>
|
||||
|
||||
/// Base class for face trackers (Faceshift, Visage).
|
||||
/// Base class for face trackers (Faceshift, Visage, DDE).
|
||||
class FaceTracker : public QObject {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
FaceTracker();
|
||||
virtual ~FaceTracker() {}
|
||||
virtual bool isActive() const { return false; }
|
||||
virtual bool isTracking() const { return false; }
|
||||
|
||||
const glm::vec3& getHeadTranslation() const { return _headTranslation; }
|
||||
const glm::quat& getHeadRotation() const { return _headRotation; }
|
||||
virtual void init() {}
|
||||
virtual void update(float deltaTime);
|
||||
virtual void reset() {}
|
||||
|
||||
float getFadeCoefficient() const;
|
||||
|
||||
const glm::vec3 getHeadTranslation() const;
|
||||
const glm::quat getHeadRotation() const;
|
||||
|
||||
float getEstimatedEyePitch() const { return _estimatedEyePitch; }
|
||||
float getEstimatedEyeYaw() const { return _estimatedEyeYaw; }
|
||||
|
||||
const QVector<float>& getBlendshapeCoefficients() const { return _blendshapeCoefficients; }
|
||||
int getNumBlendshapes() const { return _blendshapeCoefficients.size(); }
|
||||
bool isValidBlendshapeIndex(int index) const { return index >= 0 && index < getNumBlendshapes(); }
|
||||
const QVector<float>& getBlendshapeCoefficients() const;
|
||||
float getBlendshapeCoefficient(int index) const;
|
||||
|
||||
protected:
|
||||
|
||||
glm::vec3 _headTranslation;
|
||||
glm::quat _headRotation;
|
||||
float _estimatedEyePitch;
|
||||
float _estimatedEyeYaw;
|
||||
glm::vec3 _headTranslation = glm::vec3(0.0f);
|
||||
glm::quat _headRotation = glm::quat();
|
||||
float _estimatedEyePitch = 0.0f;
|
||||
float _estimatedEyeYaw = 0.0f;
|
||||
QVector<float> _blendshapeCoefficients;
|
||||
|
||||
float _relaxationStatus = 0.0f; // Between 0.0f and 1.0f
|
||||
float _fadeCoefficient = 0.0f; // Between 0.0f and 1.0f
|
||||
};
|
||||
|
||||
#endif // hifi_FaceTracker_h
|
||||
|
|
|
@ -25,37 +25,11 @@ using namespace fs;
|
|||
|
||||
using namespace std;
|
||||
|
||||
const QString DEFAULT_FACESHIFT_HOSTNAME = "localhost";
|
||||
const quint16 FACESHIFT_PORT = 33433;
|
||||
float STARTING_FACESHIFT_FRAME_TIME = 0.033f;
|
||||
const float DEFAULT_FACESHIFT_EYE_DEFLECTION = 0.25f;
|
||||
|
||||
Faceshift::Faceshift() :
|
||||
_tcpEnabled(true),
|
||||
_tcpRetryCount(0),
|
||||
_lastTrackingStateReceived(0),
|
||||
_averageFrameTime(STARTING_FACESHIFT_FRAME_TIME),
|
||||
_headAngularVelocity(0),
|
||||
_headLinearVelocity(0),
|
||||
_lastHeadTranslation(0),
|
||||
_filteredHeadTranslation(0),
|
||||
_eyeGazeLeftPitch(0.0f),
|
||||
_eyeGazeLeftYaw(0.0f),
|
||||
_eyeGazeRightPitch(0.0f),
|
||||
_eyeGazeRightYaw(0.0f),
|
||||
_leftBlinkIndex(0), // see http://support.faceshift.com/support/articles/35129-export-of-blendshapes
|
||||
_rightBlinkIndex(1),
|
||||
_leftEyeOpenIndex(8),
|
||||
_rightEyeOpenIndex(9),
|
||||
_browDownLeftIndex(14),
|
||||
_browDownRightIndex(15),
|
||||
_browUpCenterIndex(16),
|
||||
_browUpLeftIndex(17),
|
||||
_browUpRightIndex(18),
|
||||
_mouthSmileLeftIndex(28),
|
||||
_mouthSmileRightIndex(29),
|
||||
_jawOpenIndex(21),
|
||||
_longTermAverageEyePitch(0.0f),
|
||||
_longTermAverageEyeYaw(0.0f),
|
||||
_longTermAverageInitialized(false),
|
||||
_eyeDeflection("faceshiftEyeDeflection", DEFAULT_FACESHIFT_EYE_DEFLECTION),
|
||||
_hostname("faceshiftHostname", DEFAULT_FACESHIFT_HOSTNAME)
|
||||
{
|
||||
|
@ -71,31 +45,17 @@ Faceshift::Faceshift() :
|
|||
#endif
|
||||
}
|
||||
|
||||
#ifdef HAVE_FACESHIFT
|
||||
void Faceshift::init() {
|
||||
#ifdef HAVE_FACESHIFT
|
||||
setTCPEnabled(Menu::getInstance()->isOptionChecked(MenuOption::Faceshift));
|
||||
#endif
|
||||
}
|
||||
|
||||
bool Faceshift::isConnectedOrConnecting() const {
|
||||
return _tcpSocket.state() == QAbstractSocket::ConnectedState ||
|
||||
(_tcpRetryCount == 0 && _tcpSocket.state() != QAbstractSocket::UnconnectedState);
|
||||
}
|
||||
|
||||
bool Faceshift::isActive() const {
|
||||
#ifdef HAVE_FACESHIFT
|
||||
const quint64 ACTIVE_TIMEOUT_USECS = 1000000;
|
||||
return (usecTimestampNow() - _lastTrackingStateReceived) < ACTIVE_TIMEOUT_USECS;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
void Faceshift::update() {
|
||||
void Faceshift::update(float deltaTime) {
|
||||
if (!isActive()) {
|
||||
return;
|
||||
}
|
||||
PerformanceTimer perfTimer("faceshift");
|
||||
FaceTracker::update(deltaTime);
|
||||
|
||||
// get the euler angles relative to the window
|
||||
glm::vec3 eulers = glm::degrees(safeEulerAngles(_headRotation * glm::quat(glm::radians(glm::vec3(
|
||||
(_eyeGazeLeftPitch + _eyeGazeRightPitch) / 2.0f, (_eyeGazeLeftYaw + _eyeGazeRightYaw) / 2.0f, 0.0f)))));
|
||||
|
@ -116,14 +76,28 @@ void Faceshift::update() {
|
|||
}
|
||||
|
||||
void Faceshift::reset() {
|
||||
#ifdef HAVE_FACESHIFT
|
||||
if (_tcpSocket.state() == QAbstractSocket::ConnectedState) {
|
||||
string message;
|
||||
fsBinaryStream::encode_message(message, fsMsgCalibrateNeutral());
|
||||
send(message);
|
||||
}
|
||||
_longTermAverageInitialized = false;
|
||||
}
|
||||
|
||||
bool Faceshift::isActive() const {
|
||||
const quint64 ACTIVE_TIMEOUT_USECS = 1000000;
|
||||
return (usecTimestampNow() - _lastTrackingStateReceived) < ACTIVE_TIMEOUT_USECS;
|
||||
}
|
||||
|
||||
bool Faceshift::isTracking() const {
|
||||
return isActive() && _tracking;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
bool Faceshift::isConnectedOrConnecting() const {
|
||||
return _tcpSocket.state() == QAbstractSocket::ConnectedState ||
|
||||
(_tcpRetryCount == 0 && _tcpSocket.state() != QAbstractSocket::UnconnectedState);
|
||||
}
|
||||
|
||||
void Faceshift::updateFakeCoefficients(float leftBlink, float rightBlink, float browUp,
|
||||
|
@ -148,12 +122,13 @@ void Faceshift::updateFakeCoefficients(float leftBlink, float rightBlink, float
|
|||
}
|
||||
|
||||
void Faceshift::setTCPEnabled(bool enabled) {
|
||||
#ifdef HAVE_FACESHIFT
|
||||
if ((_tcpEnabled = enabled)) {
|
||||
connectSocket();
|
||||
|
||||
} else {
|
||||
_tcpSocket.disconnectFromHost();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void Faceshift::connectSocket() {
|
||||
|
@ -202,10 +177,6 @@ void Faceshift::readFromSocket() {
|
|||
receive(_tcpSocket.readAll());
|
||||
}
|
||||
|
||||
float Faceshift::getBlendshapeCoefficient(int index) const {
|
||||
return (index >= 0 && index < (int)_blendshapeCoefficients.size()) ? _blendshapeCoefficients[index] : 0.0f;
|
||||
}
|
||||
|
||||
void Faceshift::send(const std::string& message) {
|
||||
_tcpSocket.write(message.data(), message.size());
|
||||
}
|
||||
|
|
|
@ -24,8 +24,7 @@
|
|||
|
||||
#include "FaceTracker.h"
|
||||
|
||||
const float DEFAULT_FACESHIFT_EYE_DEFLECTION = 0.25f;
|
||||
const QString DEFAULT_FACESHIFT_HOSTNAME = "localhost";
|
||||
const float STARTING_FACESHIFT_FRAME_TIME = 0.033f;
|
||||
|
||||
/// Handles interaction with the Faceshift software, which provides head position/orientation and facial features.
|
||||
class Faceshift : public FaceTracker, public Dependency {
|
||||
|
@ -33,11 +32,17 @@ class Faceshift : public FaceTracker, public Dependency {
|
|||
SINGLETON_DEPENDENCY
|
||||
|
||||
public:
|
||||
void init();
|
||||
#ifdef HAVE_FACESHIFT
|
||||
// If we don't have faceshift, use the base class' methods
|
||||
virtual void init();
|
||||
virtual void update(float deltaTime);
|
||||
virtual void reset();
|
||||
|
||||
bool isConnectedOrConnecting() const;
|
||||
virtual bool isActive() const;
|
||||
virtual bool isTracking() const;
|
||||
#endif
|
||||
|
||||
bool isActive() const;
|
||||
bool isConnectedOrConnecting() const;
|
||||
|
||||
const glm::vec3& getHeadAngularVelocity() const { return _headAngularVelocity; }
|
||||
|
||||
|
@ -68,9 +73,6 @@ public:
|
|||
|
||||
QString getHostname() { return _hostname.get(); }
|
||||
void setHostname(const QString& hostname);
|
||||
|
||||
void update();
|
||||
void reset();
|
||||
|
||||
void updateFakeCoefficients(float leftBlink,
|
||||
float rightBlink,
|
||||
|
@ -82,15 +84,12 @@ public:
|
|||
QVector<float>& coefficients) const;
|
||||
|
||||
signals:
|
||||
|
||||
void connectionStateChanged();
|
||||
|
||||
public slots:
|
||||
|
||||
void setTCPEnabled(bool enabled);
|
||||
|
||||
private slots:
|
||||
|
||||
void connectSocket();
|
||||
void noteConnected();
|
||||
void noteError(QAbstractSocket::SocketError error);
|
||||
|
@ -101,8 +100,6 @@ private:
|
|||
Faceshift();
|
||||
virtual ~Faceshift() {}
|
||||
|
||||
float getBlendshapeCoefficient(int index) const;
|
||||
|
||||
void send(const std::string& message);
|
||||
void receive(const QByteArray& buffer);
|
||||
|
||||
|
@ -113,48 +110,48 @@ private:
|
|||
fs::fsBinaryStream _stream;
|
||||
#endif
|
||||
|
||||
bool _tcpEnabled;
|
||||
int _tcpRetryCount;
|
||||
bool _tracking;
|
||||
quint64 _lastTrackingStateReceived;
|
||||
float _averageFrameTime;
|
||||
bool _tcpEnabled = true;
|
||||
int _tcpRetryCount = 0;
|
||||
bool _tracking = false;
|
||||
quint64 _lastTrackingStateReceived = 0;
|
||||
float _averageFrameTime = STARTING_FACESHIFT_FRAME_TIME;
|
||||
|
||||
glm::vec3 _headAngularVelocity;
|
||||
glm::vec3 _headLinearVelocity;
|
||||
glm::vec3 _lastHeadTranslation;
|
||||
glm::vec3 _filteredHeadTranslation;
|
||||
glm::vec3 _headAngularVelocity = glm::vec3(0.0f);
|
||||
glm::vec3 _headLinearVelocity = glm::vec3(0.0f);
|
||||
glm::vec3 _lastHeadTranslation = glm::vec3(0.0f);
|
||||
glm::vec3 _filteredHeadTranslation = glm::vec3(0.0f);
|
||||
|
||||
// degrees
|
||||
float _eyeGazeLeftPitch;
|
||||
float _eyeGazeLeftYaw;
|
||||
float _eyeGazeRightPitch;
|
||||
float _eyeGazeRightYaw;
|
||||
|
||||
int _leftBlinkIndex;
|
||||
int _rightBlinkIndex;
|
||||
int _leftEyeOpenIndex;
|
||||
int _rightEyeOpenIndex;
|
||||
|
||||
// Brows
|
||||
int _browDownLeftIndex;
|
||||
int _browDownRightIndex;
|
||||
int _browUpCenterIndex;
|
||||
int _browUpLeftIndex;
|
||||
int _browUpRightIndex;
|
||||
|
||||
int _mouthSmileLeftIndex;
|
||||
int _mouthSmileRightIndex;
|
||||
|
||||
int _jawOpenIndex;
|
||||
float _eyeGazeLeftPitch = 0.0f;
|
||||
float _eyeGazeLeftYaw = 0.0f;
|
||||
float _eyeGazeRightPitch = 0.0f;
|
||||
float _eyeGazeRightYaw = 0.0f;
|
||||
|
||||
// degrees
|
||||
float _longTermAverageEyePitch;
|
||||
float _longTermAverageEyeYaw;
|
||||
bool _longTermAverageInitialized;
|
||||
float _longTermAverageEyePitch = 0.0f;
|
||||
float _longTermAverageEyeYaw = 0.0f;
|
||||
bool _longTermAverageInitialized = false;
|
||||
|
||||
Setting::Handle<float> _eyeDeflection;
|
||||
Setting::Handle<QString> _hostname;
|
||||
|
||||
// see http://support.faceshift.com/support/articles/35129-export-of-blendshapes
|
||||
int _leftBlinkIndex = 0;
|
||||
int _rightBlinkIndex = 1;
|
||||
int _leftEyeOpenIndex = 8;
|
||||
int _rightEyeOpenIndex = 9;
|
||||
|
||||
// Brows
|
||||
int _browDownLeftIndex = 14;
|
||||
int _browDownRightIndex = 15;
|
||||
int _browUpCenterIndex = 16;
|
||||
int _browUpLeftIndex = 17;
|
||||
int _browUpRightIndex = 18;
|
||||
|
||||
int _mouthSmileLeftIndex = 28;
|
||||
int _mouthSmileRightIndex = 29;
|
||||
|
||||
int _jawOpenIndex = 21;
|
||||
};
|
||||
|
||||
#endif // hifi_Faceshift_h
|
||||
|
|
|
@ -566,7 +566,7 @@ void OculusManager::display(const glm::quat &bodyOrientation, const glm::vec3 &p
|
|||
}
|
||||
|
||||
// restore our normal viewport
|
||||
auto glCanvas = DependencyManager::get<GLCanvas>();
|
||||
auto glCanvas = Application::getInstance()->getGLWidget();
|
||||
glViewport(0, 0, glCanvas->getDeviceWidth(), glCanvas->getDeviceHeight());
|
||||
|
||||
glMatrixMode(GL_PROJECTION);
|
||||
|
@ -585,7 +585,7 @@ void OculusManager::display(const glm::quat &bodyOrientation, const glm::vec3 &p
|
|||
void OculusManager::renderDistortionMesh(ovrPosef eyeRenderPose[ovrEye_Count]) {
|
||||
|
||||
glLoadIdentity();
|
||||
auto glCanvas = DependencyManager::get<GLCanvas>();
|
||||
auto glCanvas = Application::getInstance()->getGLWidget();
|
||||
glOrtho(0, glCanvas->getDeviceWidth(), 0, glCanvas->getDeviceHeight(), -1.0, 1.0);
|
||||
|
||||
glDisable(GL_DEPTH_TEST);
|
||||
|
|
|
@ -1,224 +0,0 @@
|
|||
//
|
||||
// PrioVR.cpp
|
||||
// interface/src/devices
|
||||
//
|
||||
// Created by Andrzej Kapolka on 5/12/14.
|
||||
// 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 <QTimer>
|
||||
#include <QtDebug>
|
||||
|
||||
#include <avatar/AvatarManager.h>
|
||||
#include <FBXReader.h>
|
||||
#include <PerfStat.h>
|
||||
#include <TextRenderer.h>
|
||||
|
||||
#include "Application.h"
|
||||
#include "PrioVR.h"
|
||||
#include "scripting/JoystickScriptingInterface.h"
|
||||
|
||||
#ifdef HAVE_PRIOVR
|
||||
const unsigned int SERIAL_LIST[] = { 0x00000001, 0x00000000, 0x00000008, 0x00000009, 0x0000000A,
|
||||
0x0000000C, 0x0000000D, 0x0000000E, 0x00000004, 0x00000005, 0x00000010, 0x00000011 };
|
||||
const unsigned char AXIS_LIST[] = { 9, 43, 37, 37, 37, 13, 13, 13, 52, 52, 28, 28 };
|
||||
const int LIST_LENGTH = sizeof(SERIAL_LIST) / sizeof(SERIAL_LIST[0]);
|
||||
|
||||
const char* JOINT_NAMES[] = { "Neck", "Spine", "LeftArm", "LeftForeArm", "LeftHand", "RightArm",
|
||||
"RightForeArm", "RightHand", "LeftUpLeg", "LeftLeg", "RightUpLeg", "RightLeg" };
|
||||
|
||||
static int indexOfHumanIKJoint(const char* jointName) {
|
||||
for (int i = 0;; i++) {
|
||||
QByteArray humanIKJoint = HUMANIK_JOINTS[i];
|
||||
if (humanIKJoint.isEmpty()) {
|
||||
return -1;
|
||||
}
|
||||
if (humanIKJoint == jointName) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void setPalm(float deltaTime, int index) {
|
||||
MyAvatar* avatar = DependencyManager::get<AvatarManager>()->getMyAvatar();
|
||||
Hand* hand = avatar->getHand();
|
||||
PalmData* palm;
|
||||
bool foundHand = false;
|
||||
for (size_t j = 0; j < hand->getNumPalms(); j++) {
|
||||
if (hand->getPalms()[j].getSixenseID() == index) {
|
||||
palm = &(hand->getPalms()[j]);
|
||||
foundHand = true;
|
||||
}
|
||||
}
|
||||
if (!foundHand) {
|
||||
PalmData newPalm(hand);
|
||||
hand->getPalms().push_back(newPalm);
|
||||
palm = &(hand->getPalms()[hand->getNumPalms() - 1]);
|
||||
palm->setSixenseID(index);
|
||||
}
|
||||
|
||||
palm->setActive(true);
|
||||
|
||||
// Read controller buttons and joystick into the hand
|
||||
const QString PRIO_JOYSTICK_NAME = "PrioVR";
|
||||
Joystick* prioJoystick = JoystickScriptingInterface::getInstance().joystickWithName(PRIO_JOYSTICK_NAME);
|
||||
if (prioJoystick) {
|
||||
const QVector<float> axes = prioJoystick->getAxes();
|
||||
const QVector<bool> buttons = prioJoystick->getButtons();
|
||||
|
||||
if (axes.size() >= 4 && buttons.size() >= 4) {
|
||||
if (index == LEFT_HAND_INDEX) {
|
||||
palm->setControllerButtons(buttons[1] ? BUTTON_FWD : 0);
|
||||
palm->setTrigger(buttons[0] ? 1.0f : 0.0f);
|
||||
palm->setJoystick(axes[0], -axes[1]);
|
||||
|
||||
} else {
|
||||
palm->setControllerButtons(buttons[3] ? BUTTON_FWD : 0);
|
||||
palm->setTrigger(buttons[2] ? 1.0f : 0.0f);
|
||||
palm->setJoystick(axes[2], -axes[3]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// NOTE: this math is done in the worl-frame with unecessary complexity.
|
||||
// TODO: transfom this to stay in the model-frame.
|
||||
glm::vec3 position;
|
||||
glm::quat rotation;
|
||||
SkeletonModel* skeletonModel = &DependencyManager::get<AvatarManager>()->getMyAvatar()->getSkeletonModel();
|
||||
int jointIndex;
|
||||
glm::quat inverseRotation = glm::inverse(DependencyManager::get<AvatarManager>()->getMyAvatar()->getOrientation());
|
||||
if (index == LEFT_HAND_INDEX) {
|
||||
jointIndex = skeletonModel->getLeftHandJointIndex();
|
||||
skeletonModel->getJointRotationInWorldFrame(jointIndex, rotation);
|
||||
rotation = inverseRotation * rotation * glm::quat(glm::vec3(0.0f, PI_OVER_TWO, 0.0f));
|
||||
|
||||
} else {
|
||||
jointIndex = skeletonModel->getRightHandJointIndex();
|
||||
skeletonModel->getJointRotationInWorldFrame(jointIndex, rotation);
|
||||
rotation = inverseRotation * rotation * glm::quat(glm::vec3(0.0f, -PI_OVER_TWO, 0.0f));
|
||||
}
|
||||
skeletonModel->getJointPositionInWorldFrame(jointIndex, position);
|
||||
position = inverseRotation * (position - skeletonModel->getTranslation());
|
||||
|
||||
palm->setRawRotation(rotation);
|
||||
|
||||
// Compute current velocity from position change
|
||||
glm::vec3 rawVelocity;
|
||||
if (deltaTime > 0.0f) {
|
||||
rawVelocity = (position - palm->getRawPosition()) / deltaTime;
|
||||
} else {
|
||||
rawVelocity = glm::vec3(0.0f);
|
||||
}
|
||||
palm->setRawVelocity(rawVelocity);
|
||||
palm->setRawPosition(position);
|
||||
|
||||
// Store the one fingertip in the palm structure so we can track velocity
|
||||
const float FINGER_LENGTH = 0.3f; // meters
|
||||
const glm::vec3 FINGER_VECTOR(0.0f, 0.0f, FINGER_LENGTH);
|
||||
const glm::vec3 newTipPosition = position + rotation * FINGER_VECTOR;
|
||||
glm::vec3 oldTipPosition = palm->getTipRawPosition();
|
||||
if (deltaTime > 0.0f) {
|
||||
palm->setTipVelocity((newTipPosition - oldTipPosition) / deltaTime);
|
||||
} else {
|
||||
palm->setTipVelocity(glm::vec3(0.0f));
|
||||
}
|
||||
palm->setTipPosition(newTipPosition);
|
||||
}
|
||||
#endif
|
||||
|
||||
PrioVR::PrioVR() {
|
||||
#ifdef HAVE_PRIOVR
|
||||
char jointsDiscovered[LIST_LENGTH];
|
||||
_skeletalDevice = yei_setUpPrioVRSensors(0x00000000, const_cast<unsigned int*>(SERIAL_LIST),
|
||||
const_cast<unsigned char*>(AXIS_LIST), jointsDiscovered, LIST_LENGTH, YEI_TIMESTAMP_SYSTEM);
|
||||
if (!_skeletalDevice) {
|
||||
return;
|
||||
}
|
||||
_jointRotations.resize(LIST_LENGTH);
|
||||
_lastJointRotations.resize(LIST_LENGTH);
|
||||
for (int i = 0; i < LIST_LENGTH; i++) {
|
||||
_humanIKJointIndices.append(jointsDiscovered[i] ? indexOfHumanIKJoint(JOINT_NAMES[i]) : -1);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
PrioVR::~PrioVR() {
|
||||
#ifdef HAVE_PRIOVR
|
||||
if (_skeletalDevice) {
|
||||
yei_stopStreaming(_skeletalDevice);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
const int HEAD_ROTATION_INDEX = 0;
|
||||
|
||||
bool PrioVR::hasHeadRotation() const {
|
||||
return _humanIKJointIndices.size() > HEAD_ROTATION_INDEX && _humanIKJointIndices.at(HEAD_ROTATION_INDEX) != -1;
|
||||
}
|
||||
|
||||
glm::quat PrioVR::getHeadRotation() const {
|
||||
return _jointRotations.size() > HEAD_ROTATION_INDEX ? _jointRotations.at(HEAD_ROTATION_INDEX) : glm::quat();
|
||||
}
|
||||
|
||||
glm::quat PrioVR::getTorsoRotation() const {
|
||||
const int TORSO_ROTATION_INDEX = 1;
|
||||
return _jointRotations.size() > TORSO_ROTATION_INDEX ? _jointRotations.at(TORSO_ROTATION_INDEX) : glm::quat();
|
||||
}
|
||||
|
||||
void PrioVR::update(float deltaTime) {
|
||||
#ifdef HAVE_PRIOVR
|
||||
if (!_skeletalDevice) {
|
||||
return;
|
||||
}
|
||||
PerformanceTimer perfTimer("PrioVR");
|
||||
unsigned int timestamp;
|
||||
yei_getLastStreamDataAll(_skeletalDevice, (char*)_jointRotations.data(),
|
||||
_jointRotations.size() * sizeof(glm::quat), ×tamp);
|
||||
|
||||
// convert to our expected coordinate system, average with last rotations to smooth
|
||||
for (int i = 0; i < _jointRotations.size(); i++) {
|
||||
_jointRotations[i].y *= -1.0f;
|
||||
_jointRotations[i].z *= -1.0f;
|
||||
|
||||
glm::quat lastRotation = _lastJointRotations.at(i);
|
||||
_lastJointRotations[i] = _jointRotations.at(i);
|
||||
_jointRotations[i] = safeMix(lastRotation, _jointRotations.at(i), 0.5f);
|
||||
}
|
||||
|
||||
// convert the joysticks into palm data
|
||||
setPalm(deltaTime, LEFT_HAND_INDEX);
|
||||
setPalm(deltaTime, RIGHT_HAND_INDEX);
|
||||
#endif
|
||||
}
|
||||
|
||||
void PrioVR::reset() {
|
||||
#ifdef HAVE_PRIOVR
|
||||
if (!_skeletalDevice) {
|
||||
return;
|
||||
}
|
||||
connect(Application::getInstance(), SIGNAL(renderingOverlay()), SLOT(renderCalibrationCountdown()));
|
||||
_calibrationCountdownStarted = QDateTime::currentDateTime();
|
||||
#endif
|
||||
}
|
||||
|
||||
void PrioVR::renderCalibrationCountdown() {
|
||||
#ifdef HAVE_PRIOVR
|
||||
const int COUNTDOWN_SECONDS = 3;
|
||||
int secondsRemaining = COUNTDOWN_SECONDS - _calibrationCountdownStarted.secsTo(QDateTime::currentDateTime());
|
||||
if (secondsRemaining == 0) {
|
||||
yei_tareSensors(_skeletalDevice);
|
||||
Application::getInstance()->disconnect(this);
|
||||
return;
|
||||
}
|
||||
static TextRenderer* textRenderer = TextRenderer::getInstance(MONO_FONT_FAMILY, 18, QFont::Bold,
|
||||
false, TextRenderer::OUTLINE_EFFECT, 2);
|
||||
QByteArray text = "Assume T-Pose in " + QByteArray::number(secondsRemaining) + "...";
|
||||
auto glCanvas = DependencyManager::get<GLCanvas>();
|
||||
textRenderer->draw((glCanvas->width() - textRenderer->computeExtent(text.constData()).x) / 2,
|
||||
glCanvas->height() / 2,
|
||||
text, glm::vec4(1,1,1,1));
|
||||
#endif
|
||||
}
|
|
@ -1,65 +0,0 @@
|
|||
//
|
||||
// PrioVR.h
|
||||
// interface/src/devices
|
||||
//
|
||||
// Created by Andrzej Kapolka on 5/12/14.
|
||||
// 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_PrioVR_h
|
||||
#define hifi_PrioVR_h
|
||||
|
||||
#include <QDateTime>
|
||||
#include <QObject>
|
||||
#include <QVector>
|
||||
|
||||
#include <glm/gtc/quaternion.hpp>
|
||||
|
||||
#ifdef HAVE_PRIOVR
|
||||
extern "C" {
|
||||
#include <yei_skeletal_api.h>
|
||||
}
|
||||
#endif
|
||||
|
||||
/// Handles interaction with the PrioVR skeleton tracking suit.
|
||||
class PrioVR : public QObject {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
||||
PrioVR();
|
||||
virtual ~PrioVR();
|
||||
|
||||
bool isActive() const { return !_jointRotations.isEmpty(); }
|
||||
|
||||
bool hasHeadRotation() const;
|
||||
|
||||
glm::quat getHeadRotation() const;
|
||||
glm::quat getTorsoRotation() const;
|
||||
|
||||
const QVector<int>& getHumanIKJointIndices() const { return _humanIKJointIndices; }
|
||||
const QVector<glm::quat>& getJointRotations() const { return _jointRotations; }
|
||||
|
||||
void update(float deltaTime);
|
||||
void reset();
|
||||
|
||||
private slots:
|
||||
|
||||
void renderCalibrationCountdown();
|
||||
|
||||
private:
|
||||
#ifdef HAVE_PRIOVR
|
||||
YEI_Device_Id _skeletalDevice;
|
||||
#endif
|
||||
|
||||
QVector<int> _humanIKJointIndices;
|
||||
QVector<glm::quat> _jointRotations;
|
||||
QVector<glm::quat> _lastJointRotations;
|
||||
|
||||
QDateTime _calibrationCountdownStarted;
|
||||
};
|
||||
|
||||
#endif // hifi_PrioVR_h
|
|
@ -472,7 +472,7 @@ void SixenseManager::updateCalibration(const sixenseControllerData* controllers)
|
|||
//Injecting mouse movements and clicks
|
||||
void SixenseManager::emulateMouse(PalmData* palm, int index) {
|
||||
MyAvatar* avatar = DependencyManager::get<AvatarManager>()->getMyAvatar();
|
||||
auto glCanvas = DependencyManager::get<GLCanvas>();
|
||||
auto glCanvas = Application::getInstance()->getGLWidget();
|
||||
QPoint pos;
|
||||
|
||||
Qt::MouseButton bumperButton;
|
||||
|
|
|
@ -35,7 +35,7 @@ bool TV3DManager::isConnected() {
|
|||
}
|
||||
|
||||
void TV3DManager::connect() {
|
||||
auto glCanvas = DependencyManager::get<GLCanvas>();
|
||||
auto glCanvas = Application::getInstance()->getGLWidget();
|
||||
int width = glCanvas->getDeviceWidth();
|
||||
int height = glCanvas->getDeviceHeight();
|
||||
Camera& camera = *Application::getInstance()->getCamera();
|
||||
|
@ -93,7 +93,7 @@ void TV3DManager::display(Camera& whichCamera) {
|
|||
// left eye portal
|
||||
int portalX = 0;
|
||||
int portalY = 0;
|
||||
auto glCanvas = DependencyManager::get<GLCanvas>();
|
||||
auto glCanvas = Application::getInstance()->getGLWidget();
|
||||
QSize deviceSize = glCanvas->getDeviceSize() *
|
||||
Application::getInstance()->getRenderResolutionScale();
|
||||
int portalW = deviceSize.width() / 2;
|
||||
|
|
|
@ -41,7 +41,6 @@ const glm::vec3 DEFAULT_HEAD_ORIGIN(0.0f, 0.0f, 0.7f);
|
|||
|
||||
Visage::Visage() :
|
||||
_enabled(false),
|
||||
_active(false),
|
||||
_headOrigin(DEFAULT_HEAD_ORIGIN) {
|
||||
|
||||
#ifdef HAVE_VISAGE
|
||||
|
@ -119,20 +118,20 @@ static const QMultiHash<QByteArray, QPair<int, float> >& getActionUnitNameMap()
|
|||
}
|
||||
#endif
|
||||
|
||||
const float TRANSLATION_SCALE = 20.0f;
|
||||
|
||||
#ifdef HAVE_VISAGE
|
||||
const float TRANSLATION_SCALE = 20.0f;
|
||||
void Visage::init() {
|
||||
connect(DependencyManager::get<Faceshift>().data(), SIGNAL(connectionStateChanged()), SLOT(updateEnabled()));
|
||||
updateEnabled();
|
||||
}
|
||||
|
||||
void Visage::update() {
|
||||
#ifdef HAVE_VISAGE
|
||||
_active = (_tracker->getTrackingData(_data) == TRACK_STAT_OK);
|
||||
if (!_active) {
|
||||
void Visage::update(float deltaTime) {
|
||||
if (!isActive()) {
|
||||
return;
|
||||
}
|
||||
PerformanceTimer perfTimer("visage");
|
||||
FaceTracker::update(deltaTime);
|
||||
|
||||
_headRotation = glm::quat(glm::vec3(-_data->faceRotation[0], -_data->faceRotation[1], _data->faceRotation[2]));
|
||||
_headTranslation = (glm::vec3(_data->faceTranslation[0], _data->faceTranslation[1], _data->faceTranslation[2]) -
|
||||
_headOrigin) * TRANSLATION_SCALE;
|
||||
|
@ -164,12 +163,12 @@ void Visage::update() {
|
|||
}
|
||||
_blendshapeCoefficients[leftEyeBlinkIndex] = 1.0f - _data->eyeClosure[1];
|
||||
_blendshapeCoefficients[rightEyeBlinkIndex] = 1.0f - _data->eyeClosure[0];
|
||||
#endif
|
||||
}
|
||||
|
||||
void Visage::reset() {
|
||||
_headOrigin += _headTranslation / TRANSLATION_SCALE;
|
||||
}
|
||||
#endif
|
||||
|
||||
void Visage::updateEnabled() {
|
||||
setEnabled(Menu::getInstance()->isOptionChecked(MenuOption::Visage) &&
|
||||
|
|
|
@ -31,15 +31,16 @@ class Visage : public FaceTracker, public Dependency {
|
|||
SINGLETON_DEPENDENCY
|
||||
|
||||
public:
|
||||
void init();
|
||||
#ifdef HAVE_VISAGE
|
||||
virtual void init();
|
||||
virtual void update(float deltaTime);
|
||||
virtual void reset();
|
||||
|
||||
bool isActive() const { return _active; }
|
||||
|
||||
void update();
|
||||
void reset();
|
||||
virtual bool isActive() const { return _tracker->getTrackingData(_data) == TRACK_STAT_OK; }
|
||||
virtual bool isTracking() const { return isActive(); }
|
||||
#endif
|
||||
|
||||
public slots:
|
||||
|
||||
void updateEnabled();
|
||||
|
||||
private:
|
||||
|
@ -55,7 +56,6 @@ private:
|
|||
void setEnabled(bool enabled);
|
||||
|
||||
bool _enabled;
|
||||
bool _active;
|
||||
|
||||
glm::vec3 _headOrigin;
|
||||
};
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
#include <HandData.h>
|
||||
#include <HFBackEvent.h>
|
||||
|
||||
#include "Application.h"
|
||||
#include "devices/MotionTracker.h"
|
||||
#include "devices/SixenseManager.h"
|
||||
#include "ControllerScriptingInterface.h"
|
||||
|
@ -285,7 +286,7 @@ void ControllerScriptingInterface::releaseJoystick(int joystickIndex) {
|
|||
}
|
||||
|
||||
glm::vec2 ControllerScriptingInterface::getViewportDimensions() const {
|
||||
auto glCanvas = DependencyManager::get<GLCanvas>();
|
||||
auto glCanvas = Application::getInstance()->getGLWidget();
|
||||
return glm::vec2(glCanvas->width(), glCanvas->height());
|
||||
}
|
||||
|
||||
|
|
|
@ -12,7 +12,6 @@
|
|||
#include "AccountManager.h"
|
||||
#include "Application.h"
|
||||
#include "ResourceCache.h"
|
||||
#include "XmppClient.h"
|
||||
|
||||
#include "GlobalServicesScriptingInterface.h"
|
||||
|
||||
|
@ -20,13 +19,6 @@ GlobalServicesScriptingInterface::GlobalServicesScriptingInterface() {
|
|||
AccountManager& accountManager = AccountManager::getInstance();
|
||||
connect(&accountManager, &AccountManager::usernameChanged, this, &GlobalServicesScriptingInterface::myUsernameChanged);
|
||||
connect(&accountManager, &AccountManager::logoutComplete, this, &GlobalServicesScriptingInterface::loggedOut);
|
||||
#ifdef HAVE_QXMPP
|
||||
const XmppClient& xmppClient = XmppClient::getInstance();
|
||||
connect(&xmppClient, &XmppClient::joinedPublicChatRoom, this, &GlobalServicesScriptingInterface::connected);
|
||||
connect(&xmppClient, &XmppClient::joinedPublicChatRoom, this, &GlobalServicesScriptingInterface::onConnected);
|
||||
const QXmppClient& qxmppClient = XmppClient::getInstance().getXMPPClient();
|
||||
connect(&qxmppClient, &QXmppClient::messageReceived, this, &GlobalServicesScriptingInterface::messageReceived);
|
||||
#endif // HAVE_QXMPP
|
||||
|
||||
_downloading = false;
|
||||
connect(Application::getInstance(), &Application::renderingInWorldInterface,
|
||||
|
@ -37,30 +29,6 @@ GlobalServicesScriptingInterface::~GlobalServicesScriptingInterface() {
|
|||
AccountManager& accountManager = AccountManager::getInstance();
|
||||
disconnect(&accountManager, &AccountManager::usernameChanged, this, &GlobalServicesScriptingInterface::myUsernameChanged);
|
||||
disconnect(&accountManager, &AccountManager::logoutComplete, this, &GlobalServicesScriptingInterface::loggedOut);
|
||||
#ifdef HAVE_QXMPP
|
||||
const XmppClient& xmppClient = XmppClient::getInstance();
|
||||
disconnect(&xmppClient, &XmppClient::joinedPublicChatRoom, this, &GlobalServicesScriptingInterface::connected);
|
||||
disconnect(&xmppClient, &XmppClient::joinedPublicChatRoom, this, &GlobalServicesScriptingInterface::onConnected);
|
||||
const QXmppClient& qxmppClient = XmppClient::getInstance().getXMPPClient();
|
||||
disconnect(&qxmppClient, &QXmppClient::messageReceived, this, &GlobalServicesScriptingInterface::messageReceived);
|
||||
const QXmppMucRoom* publicChatRoom = XmppClient::getInstance().getPublicChatRoom();
|
||||
disconnect(publicChatRoom, &QXmppMucRoom::participantsChanged,
|
||||
this, &GlobalServicesScriptingInterface::participantsChanged);
|
||||
#endif // HAVE_QXMPP
|
||||
}
|
||||
|
||||
void GlobalServicesScriptingInterface::onConnected() {
|
||||
#ifdef HAVE_QXMPP
|
||||
const QXmppMucRoom* publicChatRoom = XmppClient::getInstance().getPublicChatRoom();
|
||||
connect(publicChatRoom, &QXmppMucRoom::participantsChanged,
|
||||
this, &GlobalServicesScriptingInterface::participantsChanged, Qt::UniqueConnection);
|
||||
#endif // HAVE_QXMPP
|
||||
}
|
||||
|
||||
void GlobalServicesScriptingInterface::participantsChanged() {
|
||||
#ifdef HAVE_QXMPP
|
||||
emit GlobalServicesScriptingInterface::onlineUsersChanged(this->getOnlineUsers());
|
||||
#endif // HAVE_QXMPP
|
||||
}
|
||||
|
||||
GlobalServicesScriptingInterface* GlobalServicesScriptingInterface::getInstance() {
|
||||
|
@ -68,62 +36,14 @@ GlobalServicesScriptingInterface* GlobalServicesScriptingInterface::getInstance(
|
|||
return &sharedInstance;
|
||||
}
|
||||
|
||||
bool GlobalServicesScriptingInterface::isConnected() {
|
||||
#ifdef HAVE_QXMPP
|
||||
return XmppClient::getInstance().getXMPPClient().isConnected();
|
||||
#else
|
||||
return false;
|
||||
#endif // HAVE_QXMPP
|
||||
}
|
||||
|
||||
QScriptValue GlobalServicesScriptingInterface::chat(const QString& message) {
|
||||
#ifdef HAVE_QXMPP
|
||||
if (XmppClient::getInstance().getXMPPClient().isConnected()) {
|
||||
const QXmppMucRoom* publicChatRoom = XmppClient::getInstance().getPublicChatRoom();
|
||||
QXmppMessage messageObject;
|
||||
messageObject.setTo(publicChatRoom->jid());
|
||||
messageObject.setType(QXmppMessage::GroupChat);
|
||||
messageObject.setBody(message);
|
||||
return XmppClient::getInstance().getXMPPClient().sendPacket(messageObject);
|
||||
}
|
||||
#endif // HAVE_QXMPP
|
||||
return false;
|
||||
}
|
||||
|
||||
QString GlobalServicesScriptingInterface::getMyUsername() {
|
||||
return AccountManager::getInstance().getAccountInfo().getUsername();
|
||||
}
|
||||
|
||||
QStringList GlobalServicesScriptingInterface::getOnlineUsers() {
|
||||
#ifdef HAVE_QXMPP
|
||||
if (XmppClient::getInstance().getXMPPClient().isConnected()) {
|
||||
QStringList usernames;
|
||||
const QXmppMucRoom* publicChatRoom = XmppClient::getInstance().getPublicChatRoom();
|
||||
foreach(const QString& participant, XmppClient::getInstance().getPublicChatRoom()->participants()) {
|
||||
usernames.append(participant.right(participant.count() - 1 - publicChatRoom->jid().count()));
|
||||
}
|
||||
return usernames;
|
||||
}
|
||||
#endif // HAVE_QXMPP
|
||||
return QStringList();
|
||||
}
|
||||
|
||||
void GlobalServicesScriptingInterface::loggedOut() {
|
||||
emit GlobalServicesScriptingInterface::disconnected(QString("logout"));
|
||||
}
|
||||
|
||||
#ifdef HAVE_QXMPP
|
||||
void GlobalServicesScriptingInterface::messageReceived(const QXmppMessage& message) {
|
||||
if (message.type() != QXmppMessage::GroupChat) {
|
||||
return;
|
||||
}
|
||||
const QXmppMucRoom* publicChatRoom = XmppClient::getInstance().getPublicChatRoom();
|
||||
QString username = message.from().right(message.from().count() - 1 - publicChatRoom->jid().count());
|
||||
emit GlobalServicesScriptingInterface::incomingMessage(username, message.body());
|
||||
}
|
||||
#endif // HAVE_QXMPP
|
||||
|
||||
|
||||
DownloadInfoResult::DownloadInfoResult() :
|
||||
downloading(QList<float>()),
|
||||
pending(0.0f)
|
||||
|
|
|
@ -19,13 +19,6 @@
|
|||
#include <QString>
|
||||
#include <QStringList>
|
||||
|
||||
#ifdef HAVE_QXMPP
|
||||
|
||||
#include <qxmpp/QXmppClient.h>
|
||||
#include <qxmpp/QXmppMessage.h>
|
||||
|
||||
#endif // HAVE_QXMPP
|
||||
|
||||
class DownloadInfoResult {
|
||||
public:
|
||||
DownloadInfoResult();
|
||||
|
@ -41,30 +34,20 @@ void DownloadInfoResultFromScriptValue(const QScriptValue& object, DownloadInfoR
|
|||
|
||||
class GlobalServicesScriptingInterface : public QObject {
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(bool isConnected READ isConnected)
|
||||
Q_PROPERTY(QString myUsername READ getMyUsername)
|
||||
Q_PROPERTY(QStringList onlineUsers READ getOnlineUsers)
|
||||
GlobalServicesScriptingInterface();
|
||||
~GlobalServicesScriptingInterface();
|
||||
public:
|
||||
static GlobalServicesScriptingInterface* getInstance();
|
||||
|
||||
bool isConnected();
|
||||
QString getMyUsername();
|
||||
QStringList getOnlineUsers();
|
||||
|
||||
|
||||
public slots:
|
||||
QScriptValue chat(const QString& message);
|
||||
DownloadInfoResult getDownloadInfo();
|
||||
void updateDownloadInfo();
|
||||
|
||||
private slots:
|
||||
void loggedOut();
|
||||
void onConnected();
|
||||
void participantsChanged();
|
||||
#ifdef HAVE_QXMPP
|
||||
void messageReceived(const QXmppMessage& message);
|
||||
#endif // HAVE_QXMPP
|
||||
void checkDownloadInfo();
|
||||
|
||||
signals:
|
||||
|
|
|
@ -44,7 +44,7 @@ WebWindowClass* WindowScriptingInterface::doCreateWebWindow(const QString& title
|
|||
}
|
||||
|
||||
QScriptValue WindowScriptingInterface::hasFocus() {
|
||||
return DependencyManager::get<GLCanvas>()->hasFocus();
|
||||
return Application::getInstance()->getGLWidget()->hasFocus();
|
||||
}
|
||||
|
||||
void WindowScriptingInterface::setFocus() {
|
||||
|
|
|
@ -170,7 +170,7 @@ ApplicationOverlay::~ApplicationOverlay() {
|
|||
void ApplicationOverlay::renderOverlay(bool renderToTexture) {
|
||||
PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), "ApplicationOverlay::displayOverlay()");
|
||||
Overlays& overlays = qApp->getOverlays();
|
||||
auto glCanvas = DependencyManager::get<GLCanvas>();
|
||||
auto glCanvas = Application::getInstance()->getGLWidget();
|
||||
|
||||
_textureFov = glm::radians(_oculusUIAngularSize);
|
||||
_textureAspectRatio = (float)glCanvas->getDeviceWidth() / (float)glCanvas->getDeviceHeight();
|
||||
|
@ -239,7 +239,7 @@ void ApplicationOverlay::displayOverlayTexture() {
|
|||
if (_alpha == 0.0f) {
|
||||
return;
|
||||
}
|
||||
auto glCanvas = DependencyManager::get<GLCanvas>();
|
||||
auto glCanvas = Application::getInstance()->getGLWidget();
|
||||
|
||||
glEnable(GL_TEXTURE_2D);
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
|
@ -401,7 +401,7 @@ void ApplicationOverlay::displayOverlayTexture3DTV(Camera& whichCamera, float as
|
|||
glm::vec2(1.0f, 0.0f), glm::vec2(0.0f, 0.0f),
|
||||
overlayColor);
|
||||
|
||||
auto glCanvas = DependencyManager::get<GLCanvas>();
|
||||
auto glCanvas = Application::getInstance()->getGLWidget();
|
||||
if (_crosshairTexture == 0) {
|
||||
_crosshairTexture = glCanvas->bindTexture(QImage(PathUtils::resourcesPath() + "images/sixense-reticle.png"));
|
||||
}
|
||||
|
@ -451,7 +451,7 @@ void ApplicationOverlay::computeOculusPickRay(float x, float y, glm::vec3& origi
|
|||
|
||||
//Caculate the click location using one of the sixense controllers. Scale is not applied
|
||||
QPoint ApplicationOverlay::getPalmClickLocation(const PalmData *palm) const {
|
||||
auto glCanvas = DependencyManager::get<GLCanvas>();
|
||||
auto glCanvas = Application::getInstance()->getGLWidget();
|
||||
MyAvatar* myAvatar = DependencyManager::get<AvatarManager>()->getMyAvatar();
|
||||
|
||||
glm::vec3 tip = myAvatar->getLaserPointerTipPosition(palm);
|
||||
|
@ -528,7 +528,7 @@ bool ApplicationOverlay::calculateRayUICollisionPoint(const glm::vec3& position,
|
|||
|
||||
//Renders optional pointers
|
||||
void ApplicationOverlay::renderPointers() {
|
||||
auto glCanvas = DependencyManager::get<GLCanvas>();
|
||||
auto glCanvas = Application::getInstance()->getGLWidget();
|
||||
|
||||
//lazily load crosshair texture
|
||||
if (_crosshairTexture == 0) {
|
||||
|
@ -575,7 +575,7 @@ void ApplicationOverlay::renderPointers() {
|
|||
}
|
||||
|
||||
void ApplicationOverlay::renderControllerPointers() {
|
||||
auto glCanvas = DependencyManager::get<GLCanvas>();
|
||||
auto glCanvas = Application::getInstance()->getGLWidget();
|
||||
MyAvatar* myAvatar = DependencyManager::get<AvatarManager>()->getMyAvatar();
|
||||
|
||||
//Static variables used for storing controller state
|
||||
|
@ -722,7 +722,7 @@ void ApplicationOverlay::renderMagnifier(glm::vec2 magPos, float sizeMult, bool
|
|||
if (!_magnifier) {
|
||||
return;
|
||||
}
|
||||
auto glCanvas = DependencyManager::get<GLCanvas>();
|
||||
auto glCanvas = Application::getInstance()->getGLWidget();
|
||||
|
||||
const int widgetWidth = glCanvas->width();
|
||||
const int widgetHeight = glCanvas->height();
|
||||
|
@ -787,7 +787,7 @@ void ApplicationOverlay::renderMagnifier(glm::vec2 magPos, float sizeMult, bool
|
|||
}
|
||||
|
||||
void ApplicationOverlay::renderAudioMeter() {
|
||||
auto glCanvas = DependencyManager::get<GLCanvas>();
|
||||
auto glCanvas = Application::getInstance()->getGLWidget();
|
||||
auto audio = DependencyManager::get<AudioClient>();
|
||||
|
||||
// Audio VU Meter and Mute Icon
|
||||
|
@ -905,7 +905,7 @@ void ApplicationOverlay::renderStatsAndLogs() {
|
|||
Application* application = Application::getInstance();
|
||||
QSharedPointer<BandwidthRecorder> bandwidthRecorder = DependencyManager::get<BandwidthRecorder>();
|
||||
|
||||
auto glCanvas = DependencyManager::get<GLCanvas>();
|
||||
auto glCanvas = Application::getInstance()->getGLWidget();
|
||||
const OctreePacketProcessor& octreePacketProcessor = application->getOctreePacketProcessor();
|
||||
NodeBounds& nodeBoundsDisplay = application->getNodeBoundsDisplay();
|
||||
|
||||
|
@ -943,7 +943,7 @@ void ApplicationOverlay::renderDomainConnectionStatusBorder() {
|
|||
auto nodeList = DependencyManager::get<NodeList>();
|
||||
|
||||
if (nodeList && !nodeList->getDomainHandler().isConnected()) {
|
||||
auto glCanvas = DependencyManager::get<GLCanvas>();
|
||||
auto glCanvas = Application::getInstance()->getGLWidget();
|
||||
auto geometryCache = DependencyManager::get<GeometryCache>();
|
||||
int width = glCanvas->width();
|
||||
int height = glCanvas->height();
|
||||
|
@ -1087,7 +1087,7 @@ void ApplicationOverlay::TexturedHemisphere::cleanupVBO() {
|
|||
}
|
||||
|
||||
void ApplicationOverlay::TexturedHemisphere::buildFramebufferObject() {
|
||||
QSize size = DependencyManager::get<GLCanvas>()->getDeviceSize();
|
||||
QSize size = Application::getInstance()->getGLWidget()->getDeviceSize();
|
||||
if (_framebufferObject != NULL && size == _framebufferObject->size()) {
|
||||
// Already build
|
||||
return;
|
||||
|
@ -1138,7 +1138,7 @@ void ApplicationOverlay::TexturedHemisphere::render() {
|
|||
|
||||
|
||||
glm::vec2 ApplicationOverlay::screenToSpherical(glm::vec2 screenPos) const {
|
||||
QSize screenSize = DependencyManager::get<GLCanvas>()->getDeviceSize();
|
||||
QSize screenSize = Application::getInstance()->getGLWidget()->getDeviceSize();
|
||||
float yaw = -(screenPos.x / screenSize.width() - 0.5f) * MOUSE_YAW_RANGE;
|
||||
float pitch = (screenPos.y / screenSize.height() - 0.5f) * MOUSE_PITCH_RANGE;
|
||||
|
||||
|
@ -1146,7 +1146,7 @@ glm::vec2 ApplicationOverlay::screenToSpherical(glm::vec2 screenPos) const {
|
|||
}
|
||||
|
||||
glm::vec2 ApplicationOverlay::sphericalToScreen(glm::vec2 sphericalPos) const {
|
||||
QSize screenSize = DependencyManager::get<GLCanvas>()->getDeviceSize();
|
||||
QSize screenSize = Application::getInstance()->getGLWidget()->getDeviceSize();
|
||||
float x = (-sphericalPos.x / MOUSE_YAW_RANGE + 0.5f) * screenSize.width();
|
||||
float y = (sphericalPos.y / MOUSE_PITCH_RANGE + 0.5f) * screenSize.height();
|
||||
|
||||
|
@ -1154,7 +1154,7 @@ glm::vec2 ApplicationOverlay::sphericalToScreen(glm::vec2 sphericalPos) const {
|
|||
}
|
||||
|
||||
glm::vec2 ApplicationOverlay::sphericalToOverlay(glm::vec2 sphericalPos) const {
|
||||
QSize screenSize = DependencyManager::get<GLCanvas>()->getDeviceSize();
|
||||
QSize screenSize = Application::getInstance()->getGLWidget()->getDeviceSize();
|
||||
float x = (-sphericalPos.x / (_textureFov * _textureAspectRatio) + 0.5f) * screenSize.width();
|
||||
float y = (sphericalPos.y / _textureFov + 0.5f) * screenSize.height();
|
||||
|
||||
|
@ -1162,7 +1162,7 @@ glm::vec2 ApplicationOverlay::sphericalToOverlay(glm::vec2 sphericalPos) const {
|
|||
}
|
||||
|
||||
glm::vec2 ApplicationOverlay::overlayToSpherical(glm::vec2 overlayPos) const {
|
||||
QSize screenSize = DependencyManager::get<GLCanvas>()->getDeviceSize();
|
||||
QSize screenSize = Application::getInstance()->getGLWidget()->getDeviceSize();
|
||||
float yaw = -(overlayPos.x / screenSize.width() - 0.5f) * _textureFov * _textureAspectRatio;
|
||||
float pitch = (overlayPos.y / screenSize.height() - 0.5f) * _textureFov;
|
||||
|
||||
|
|
|
@ -86,12 +86,10 @@ BandwidthDialog::BandwidthDialog(QWidget* parent) :
|
|||
new BandwidthChannelDisplay({NodeType::EntityServer}, form, "Octree", "Kbps", 1.0, COLOR2);
|
||||
_allChannelDisplays[3] = _octreeChannelDisplay =
|
||||
new BandwidthChannelDisplay({NodeType::DomainServer}, form, "Domain", "Kbps", 1.0, COLOR2);
|
||||
_allChannelDisplays[4] = _metavoxelsChannelDisplay =
|
||||
new BandwidthChannelDisplay({NodeType::MetavoxelServer, NodeType::EnvironmentServer}, form, "Metavoxels", "Kbps", 1.0, COLOR2);
|
||||
_allChannelDisplays[5] = _otherChannelDisplay =
|
||||
_allChannelDisplays[4] = _otherChannelDisplay =
|
||||
new BandwidthChannelDisplay({NodeType::Unassigned}, form, "Other", "Kbps", 1.0, COLOR2);
|
||||
_allChannelDisplays[6] = _totalChannelDisplay =
|
||||
new BandwidthChannelDisplay({NodeType::DomainServer, NodeType::EntityServer, NodeType::MetavoxelServer,
|
||||
_allChannelDisplays[5] = _totalChannelDisplay =
|
||||
new BandwidthChannelDisplay({NodeType::DomainServer, NodeType::EntityServer,
|
||||
NodeType::EnvironmentServer, NodeType::AudioMixer, NodeType::Agent,
|
||||
NodeType::AvatarMixer, NodeType::Unassigned},
|
||||
form, "Total", "Kbps", 1.0, COLOR2);
|
||||
|
|
|
@ -63,11 +63,10 @@ private:
|
|||
BandwidthChannelDisplay* _avatarsChannelDisplay;
|
||||
BandwidthChannelDisplay* _octreeChannelDisplay;
|
||||
BandwidthChannelDisplay* _domainChannelDisplay;
|
||||
BandwidthChannelDisplay* _metavoxelsChannelDisplay;
|
||||
BandwidthChannelDisplay* _otherChannelDisplay;
|
||||
BandwidthChannelDisplay* _totalChannelDisplay; // sums of all the other channels
|
||||
|
||||
static const unsigned int _CHANNELCOUNT = 7;
|
||||
static const unsigned int _CHANNELCOUNT = 6;
|
||||
BandwidthChannelDisplay* _allChannelDisplays[_CHANNELCOUNT];
|
||||
|
||||
|
||||
|
|
|
@ -16,7 +16,6 @@
|
|||
#include <AnimationCache.h>
|
||||
#include <DependencyManager.h>
|
||||
#include <GeometryCache.h>
|
||||
#include <ScriptCache.h>
|
||||
#include <SoundCache.h>
|
||||
#include <TextureCache.h>
|
||||
|
||||
|
@ -42,7 +41,6 @@ CachesSizeDialog::CachesSizeDialog(QWidget* parent) :
|
|||
|
||||
form->addRow("Animations cache size (MB):", _animations = createDoubleSpinBox(this));
|
||||
form->addRow("Geometries cache size (MB):", _geometries = createDoubleSpinBox(this));
|
||||
form->addRow("Scripts cache size (MB):", _scripts = createDoubleSpinBox(this));
|
||||
form->addRow("Sounds cache size (MB):", _sounds = createDoubleSpinBox(this));
|
||||
form->addRow("Textures cache size (MB):", _textures = createDoubleSpinBox(this));
|
||||
|
||||
|
@ -59,7 +57,6 @@ CachesSizeDialog::CachesSizeDialog(QWidget* parent) :
|
|||
void CachesSizeDialog::confirmClicked(bool checked) {
|
||||
DependencyManager::get<AnimationCache>()->setUnusedResourceCacheSize(_animations->value() * BYTES_PER_MEGABYTES);
|
||||
DependencyManager::get<GeometryCache>()->setUnusedResourceCacheSize(_geometries->value() * BYTES_PER_MEGABYTES);
|
||||
DependencyManager::get<ScriptCache>()->setUnusedResourceCacheSize(_scripts->value() * BYTES_PER_MEGABYTES);
|
||||
DependencyManager::get<SoundCache>()->setUnusedResourceCacheSize(_sounds->value() * BYTES_PER_MEGABYTES);
|
||||
DependencyManager::get<TextureCache>()->setUnusedResourceCacheSize(_textures->value() * BYTES_PER_MEGABYTES);
|
||||
|
||||
|
@ -69,7 +66,6 @@ void CachesSizeDialog::confirmClicked(bool checked) {
|
|||
void CachesSizeDialog::resetClicked(bool checked) {
|
||||
_animations->setValue(DependencyManager::get<AnimationCache>()->getUnusedResourceCacheSize() / BYTES_PER_MEGABYTES);
|
||||
_geometries->setValue(DependencyManager::get<GeometryCache>()->getUnusedResourceCacheSize() / BYTES_PER_MEGABYTES);
|
||||
_scripts->setValue(DependencyManager::get<ScriptCache>()->getUnusedResourceCacheSize() / BYTES_PER_MEGABYTES);
|
||||
_sounds->setValue(DependencyManager::get<SoundCache>()->getUnusedResourceCacheSize() / BYTES_PER_MEGABYTES);
|
||||
_textures->setValue(DependencyManager::get<TextureCache>()->getUnusedResourceCacheSize() / BYTES_PER_MEGABYTES);
|
||||
}
|
||||
|
|
|
@ -1,420 +0,0 @@
|
|||
//
|
||||
// ChatWindow.cpp
|
||||
// interface/src/ui
|
||||
//
|
||||
// Created by Dimitar Dobrev on 3/6/14.
|
||||
// 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 <QGridLayout>
|
||||
#include <QFrame>
|
||||
#include <QLayoutItem>
|
||||
#include <QPalette>
|
||||
#include <QScrollBar>
|
||||
#include <QSizePolicy>
|
||||
#include <QTimer>
|
||||
#include "qtimespan.h"
|
||||
|
||||
|
||||
#include <AddressManager.h>
|
||||
#include <AccountManager.h>
|
||||
#include <PathUtils.h>
|
||||
|
||||
#include "Application.h"
|
||||
#include "ChatMessageArea.h"
|
||||
#include "FlowLayout.h"
|
||||
#include "MainWindow.h"
|
||||
#include "UIUtil.h"
|
||||
#include "XmppClient.h"
|
||||
|
||||
#include "ui_chatWindow.h"
|
||||
#include "ChatWindow.h"
|
||||
|
||||
|
||||
const int NUM_MESSAGES_TO_TIME_STAMP = 20;
|
||||
|
||||
const QRegularExpression regexLinks("((?:(?:ftp)|(?:https?)|(?:hifi))://\\S+)");
|
||||
const QRegularExpression regexHifiLinks("([#@]\\S+)");
|
||||
const QString mentionSoundsPath("/mention-sounds/");
|
||||
const QString mentionRegex("@(\\b%1\\b)");
|
||||
|
||||
ChatWindow::ChatWindow(QWidget* parent) :
|
||||
QWidget(parent, Qt::Window | Qt::CustomizeWindowHint | Qt::WindowTitleHint | Qt::WindowMinMaxButtonsHint |
|
||||
Qt::WindowCloseButtonHint),
|
||||
_ui(new Ui::ChatWindow),
|
||||
_numMessagesAfterLastTimeStamp(0),
|
||||
_mousePressed(false),
|
||||
_mouseStartPosition(),
|
||||
_trayIcon(parent),
|
||||
_effectPlayer(),
|
||||
_usernameMentionTimestamp("MentionTimestamp", QDateTime())
|
||||
{
|
||||
setAttribute(Qt::WA_DeleteOnClose, false);
|
||||
|
||||
_ui->setupUi(this);
|
||||
|
||||
FlowLayout* flowLayout = new FlowLayout(0, 4, 4);
|
||||
_ui->usersWidget->setLayout(flowLayout);
|
||||
|
||||
_ui->messagePlainTextEdit->installEventFilter(this);
|
||||
_ui->messagePlainTextEdit->setWordWrapMode(QTextOption::WrapAtWordBoundaryOrAnywhere);
|
||||
|
||||
QTextCursor cursor(_ui->messagePlainTextEdit->textCursor());
|
||||
|
||||
cursor.movePosition(QTextCursor::Start);
|
||||
|
||||
QTextBlockFormat format = cursor.blockFormat();
|
||||
format.setLineHeight(130, QTextBlockFormat::ProportionalHeight);
|
||||
|
||||
cursor.setBlockFormat(format);
|
||||
|
||||
_ui->messagePlainTextEdit->setTextCursor(cursor);
|
||||
|
||||
if (!AccountManager::getInstance().isLoggedIn()) {
|
||||
_ui->connectingToXMPPLabel->setText(tr("You must be logged in to chat with others."));
|
||||
}
|
||||
|
||||
#ifdef HAVE_QXMPP
|
||||
const QXmppClient& xmppClient = XmppClient::getInstance().getXMPPClient();
|
||||
if (xmppClient.isConnected()) {
|
||||
participantsChanged();
|
||||
const QXmppMucRoom* publicChatRoom = XmppClient::getInstance().getPublicChatRoom();
|
||||
connect(publicChatRoom, SIGNAL(participantsChanged()), this, SLOT(participantsChanged()));
|
||||
_ui->connectingToXMPPLabel->hide();
|
||||
startTimerForTimeStamps();
|
||||
} else {
|
||||
_ui->numOnlineLabel->hide();
|
||||
_ui->usersArea->hide();
|
||||
_ui->messagesScrollArea->hide();
|
||||
_ui->messagePlainTextEdit->hide();
|
||||
connect(&XmppClient::getInstance(), SIGNAL(joinedPublicChatRoom()), this, SLOT(connected()));
|
||||
}
|
||||
connect(&xmppClient, SIGNAL(messageReceived(QXmppMessage)), this, SLOT(messageReceived(QXmppMessage)));
|
||||
connect(&_trayIcon, SIGNAL(messageClicked()), this, SLOT(notificationClicked()));
|
||||
#endif // HAVE_QXMPP
|
||||
|
||||
QDir mentionSoundsDir(PathUtils::resourcesPath() + mentionSoundsPath);
|
||||
_mentionSounds = mentionSoundsDir.entryList(QDir::Files);
|
||||
_trayIcon.setIcon(QIcon( PathUtils::resourcesPath() + "/images/hifi-logo.svg"));
|
||||
}
|
||||
|
||||
ChatWindow::~ChatWindow() {
|
||||
#ifdef HAVE_QXMPP
|
||||
const QXmppClient& xmppClient = XmppClient::getInstance().getXMPPClient();
|
||||
disconnect(&xmppClient, SIGNAL(joinedPublicChatRoom()), this, SLOT(connected()));
|
||||
disconnect(&xmppClient, SIGNAL(messageReceived(QXmppMessage)), this, SLOT(messageReceived(QXmppMessage)));
|
||||
|
||||
const QXmppMucRoom* publicChatRoom = XmppClient::getInstance().getPublicChatRoom();
|
||||
disconnect(publicChatRoom, SIGNAL(participantsChanged()), this, SLOT(participantsChanged()));
|
||||
#endif // HAVE_QXMPP
|
||||
delete _ui;
|
||||
}
|
||||
|
||||
void ChatWindow::keyPressEvent(QKeyEvent* event) {
|
||||
if (event->key() == Qt::Key_Escape) {
|
||||
Application::getInstance()->getWindow()->activateWindow();
|
||||
hide();
|
||||
} else {
|
||||
QWidget::keyPressEvent(event);
|
||||
}
|
||||
}
|
||||
|
||||
void ChatWindow::showEvent(QShowEvent* event) {
|
||||
QWidget::showEvent(event);
|
||||
|
||||
if (!event->spontaneous()) {
|
||||
_ui->messagePlainTextEdit->setFocus();
|
||||
}
|
||||
QRect parentGeometry = Application::getInstance()->getDesirableApplicationGeometry();
|
||||
int titleBarHeight = UIUtil::getWindowTitleBarHeight(this);
|
||||
int menuBarHeight = Menu::getInstance()->geometry().height();
|
||||
int topMargin = titleBarHeight + menuBarHeight;
|
||||
|
||||
setGeometry(parentGeometry.topRight().x() - size().width() + 1, parentGeometry.topRight().y() + topMargin,
|
||||
size().width(), parentWidget()->height() - topMargin);
|
||||
|
||||
Application::processEvents();
|
||||
|
||||
scrollToBottom();
|
||||
|
||||
#ifdef HAVE_QXMPP
|
||||
const QXmppClient& xmppClient = XmppClient::getInstance().getXMPPClient();
|
||||
if (xmppClient.isConnected()) {
|
||||
participantsChanged();
|
||||
}
|
||||
#endif // HAVE_QXMPP
|
||||
}
|
||||
|
||||
bool ChatWindow::eventFilter(QObject* sender, QEvent* event) {
|
||||
if (sender == _ui->messagePlainTextEdit) {
|
||||
if (event->type() != QEvent::KeyPress) {
|
||||
return false;
|
||||
}
|
||||
QKeyEvent* keyEvent = static_cast<QKeyEvent*>(event);
|
||||
if ((keyEvent->key() == Qt::Key_Return || keyEvent->key() == Qt::Key_Enter) &&
|
||||
(keyEvent->modifiers() & Qt::ShiftModifier) == 0) {
|
||||
QString messageText = _ui->messagePlainTextEdit->document()->toPlainText().trimmed();
|
||||
if (!messageText.isEmpty()) {
|
||||
#ifdef HAVE_QXMPP
|
||||
const QXmppMucRoom* publicChatRoom = XmppClient::getInstance().getPublicChatRoom();
|
||||
QXmppMessage message;
|
||||
message.setTo(publicChatRoom->jid());
|
||||
message.setType(QXmppMessage::GroupChat);
|
||||
message.setBody(messageText);
|
||||
XmppClient::getInstance().getXMPPClient().sendPacket(message);
|
||||
#endif // HAVE_QXMPP
|
||||
QTextCursor cursor = _ui->messagePlainTextEdit->textCursor();
|
||||
cursor.select(QTextCursor::Document);
|
||||
cursor.removeSelectedText();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
} else if (event->type() == QEvent::MouseButtonRelease) {
|
||||
QVariant userVar = sender->property("user");
|
||||
if (userVar.isValid()) {
|
||||
DependencyManager::get<AddressManager>()->goToUser(userVar.toString());
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return QWidget::eventFilter(sender, event);
|
||||
}
|
||||
|
||||
void ChatWindow::addTimeStamp() {
|
||||
QTimeSpan timePassed = QDateTime::currentDateTime() - _lastMessageStamp;
|
||||
int times[] = { timePassed.daysPart(), timePassed.hoursPart(), timePassed.minutesPart() };
|
||||
QString strings[] = { tr("%n day(s)", 0, times[0]), tr("%n hour(s)", 0, times[1]), tr("%n minute(s)", 0, times[2]) };
|
||||
QString timeString = "";
|
||||
for (int i = 0; i < 3; i++) {
|
||||
if (times[i] > 0) {
|
||||
timeString += strings[i] + " ";
|
||||
}
|
||||
}
|
||||
timeString.chop(1);
|
||||
if (!timeString.isEmpty()) {
|
||||
QLabel* timeLabel = new QLabel(timeString);
|
||||
timeLabel->setStyleSheet("color: #333333;"
|
||||
"background-color: white;"
|
||||
"font-size: 14px;"
|
||||
"padding: 4px;");
|
||||
timeLabel->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred);
|
||||
timeLabel->setAlignment(Qt::AlignLeft);
|
||||
|
||||
bool atBottom = isNearBottom();
|
||||
|
||||
_ui->messagesVBoxLayout->addWidget(timeLabel);
|
||||
_ui->messagesVBoxLayout->parentWidget()->updateGeometry();
|
||||
|
||||
Application::processEvents();
|
||||
_numMessagesAfterLastTimeStamp = 0;
|
||||
|
||||
if (atBottom) {
|
||||
scrollToBottom();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ChatWindow::startTimerForTimeStamps() {
|
||||
QTimer* timer = new QTimer(this);
|
||||
timer->setInterval(10 * 60 * 1000);
|
||||
connect(timer, SIGNAL(timeout()), this, SLOT(timeout()));
|
||||
timer->start();
|
||||
}
|
||||
|
||||
void ChatWindow::connected() {
|
||||
_ui->connectingToXMPPLabel->hide();
|
||||
_ui->numOnlineLabel->show();
|
||||
_ui->usersArea->show();
|
||||
_ui->messagesScrollArea->show();
|
||||
_ui->messagePlainTextEdit->show();
|
||||
_ui->messagePlainTextEdit->setFocus();
|
||||
#ifdef HAVE_QXMPP
|
||||
const QXmppMucRoom* publicChatRoom = XmppClient::getInstance().getPublicChatRoom();
|
||||
connect(publicChatRoom, SIGNAL(participantsChanged()), this, SLOT(participantsChanged()));
|
||||
#endif // HAVE_QXMPP
|
||||
startTimerForTimeStamps();
|
||||
}
|
||||
|
||||
void ChatWindow::timeout() {
|
||||
if (_numMessagesAfterLastTimeStamp >= NUM_MESSAGES_TO_TIME_STAMP) {
|
||||
addTimeStamp();
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef HAVE_QXMPP
|
||||
void ChatWindow::notificationClicked() {
|
||||
if (parentWidget()->isMinimized()) {
|
||||
parentWidget()->showNormal();
|
||||
}
|
||||
if (isHidden()) {
|
||||
show();
|
||||
}
|
||||
|
||||
// find last mention
|
||||
int messageCount = _ui->messagesVBoxLayout->count();
|
||||
for (unsigned int i = messageCount; i > 0; i--) {
|
||||
ChatMessageArea* area = (ChatMessageArea*)_ui->messagesVBoxLayout->itemAt(i - 1)->widget();
|
||||
QRegularExpression usernameMention(mentionRegex.arg(AccountManager::getInstance().getAccountInfo().getUsername()));
|
||||
if (area->toPlainText().contains(usernameMention)) {
|
||||
int top = area->geometry().top();
|
||||
int height = area->geometry().height();
|
||||
|
||||
QScrollBar* verticalScrollBar = _ui->messagesScrollArea->verticalScrollBar();
|
||||
verticalScrollBar->setSliderPosition(top - verticalScrollBar->size().height() + height);
|
||||
return;
|
||||
}
|
||||
}
|
||||
Application::processEvents();
|
||||
|
||||
scrollToBottom();
|
||||
}
|
||||
|
||||
QString ChatWindow::getParticipantName(const QString& participant) {
|
||||
const QXmppMucRoom* publicChatRoom = XmppClient::getInstance().getPublicChatRoom();
|
||||
return participant.right(participant.count() - 1 - publicChatRoom->jid().count());
|
||||
}
|
||||
|
||||
void ChatWindow::error(QXmppClient::Error error) {
|
||||
_ui->connectingToXMPPLabel->setText(QString::number(error));
|
||||
}
|
||||
|
||||
void ChatWindow::participantsChanged() {
|
||||
bool atBottom = isNearBottom();
|
||||
|
||||
QStringList participants = XmppClient::getInstance().getPublicChatRoom()->participants();
|
||||
_ui->numOnlineLabel->setText(tr("%1 online now:").arg(participants.count()));
|
||||
|
||||
while (QLayoutItem* item = _ui->usersWidget->layout()->takeAt(0)) {
|
||||
delete item->widget();
|
||||
delete item;
|
||||
}
|
||||
foreach (const QString& participant, participants) {
|
||||
QString participantName = getParticipantName(participant);
|
||||
QLabel* userLabel = new QLabel();
|
||||
userLabel->setText(participantName);
|
||||
userLabel->setStyleSheet("background-color: palette(light);"
|
||||
"border-radius: 5px;"
|
||||
"color: #267077;"
|
||||
"padding-top: 3px;"
|
||||
"padding-right: 2px;"
|
||||
"padding-bottom: 2px;"
|
||||
"padding-left: 2px;"
|
||||
"border: 1px solid palette(shadow);"
|
||||
"font-size: 14px;"
|
||||
"font-weight: bold");
|
||||
userLabel->setProperty("user", participantName);
|
||||
userLabel->setCursor(Qt::PointingHandCursor);
|
||||
userLabel->installEventFilter(this);
|
||||
_ui->usersWidget->layout()->addWidget(userLabel);
|
||||
}
|
||||
Application::processEvents();
|
||||
|
||||
if (atBottom) {
|
||||
scrollToBottom();
|
||||
}
|
||||
}
|
||||
|
||||
void ChatWindow::messageReceived(const QXmppMessage& message) {
|
||||
if (message.type() != QXmppMessage::GroupChat) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Update background if this is a message from the current user
|
||||
bool fromSelf = getParticipantName(message.from()) == AccountManager::getInstance().getAccountInfo().getUsername();
|
||||
|
||||
// Create message area
|
||||
ChatMessageArea* messageArea = new ChatMessageArea(true);
|
||||
messageArea->setWordWrapMode(QTextOption::WrapAtWordBoundaryOrAnywhere);
|
||||
messageArea->setTextInteractionFlags(Qt::TextBrowserInteraction);
|
||||
messageArea->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
|
||||
messageArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
|
||||
messageArea->setReadOnly(true);
|
||||
|
||||
messageArea->setStyleSheet("QTextBrowser{ padding-bottom: 2px;"
|
||||
"padding-left: 2px;"
|
||||
"padding-top: 2px;"
|
||||
"padding-right: 20px;"
|
||||
"margin: 0px;"
|
||||
"color: #333333;"
|
||||
"font-size: 14px;"
|
||||
"background-color: rgba(0, 0, 0, 0%);"
|
||||
"border: 0; }"
|
||||
"QMenu{ border: 2px outset gray; }");
|
||||
|
||||
QString userLabel = getParticipantName(message.from());
|
||||
if (fromSelf) {
|
||||
userLabel = "<b style=\"color: #4a6f91\">" + userLabel + ": </b>";
|
||||
messageArea->setStyleSheet(messageArea->styleSheet() + "background-color: #e1e8ea");
|
||||
} else {
|
||||
userLabel = "<b>" + userLabel + ": </b>";
|
||||
}
|
||||
|
||||
messageArea->document()->setDefaultStyleSheet("a { text-decoration: none; font-weight: bold; color: #267077;}");
|
||||
QString messageText = message.body().toHtmlEscaped();
|
||||
messageText = messageText.replace(regexLinks, "<a href=\"\\1\">\\1</a>");
|
||||
messageText = messageText.replace(regexHifiLinks, "<a href=\"hifi://\\1\">\\1</a>");
|
||||
messageArea->setHtml(userLabel + messageText);
|
||||
|
||||
bool atBottom = isNearBottom();
|
||||
|
||||
_ui->messagesVBoxLayout->addWidget(messageArea);
|
||||
_ui->messagesVBoxLayout->parentWidget()->updateGeometry();
|
||||
Application::processEvents();
|
||||
|
||||
if (atBottom || fromSelf) {
|
||||
scrollToBottom();
|
||||
}
|
||||
|
||||
++_numMessagesAfterLastTimeStamp;
|
||||
if (message.stamp().isValid()) {
|
||||
_lastMessageStamp = message.stamp().toLocalTime();
|
||||
} else {
|
||||
_lastMessageStamp = QDateTime::currentDateTime();
|
||||
}
|
||||
|
||||
QRegularExpression usernameMention(mentionRegex.arg(AccountManager::getInstance().getAccountInfo().getUsername()));
|
||||
if (message.body().contains(usernameMention)) {
|
||||
|
||||
// Don't show messages already seen in icon tray at start-up.
|
||||
bool showMessage = _usernameMentionTimestamp.get() < _lastMessageStamp;
|
||||
if (showMessage) {
|
||||
_usernameMentionTimestamp.set(_lastMessageStamp);
|
||||
}
|
||||
|
||||
if (isHidden() && showMessage) {
|
||||
|
||||
if (_effectPlayer.state() != QMediaPlayer::PlayingState) {
|
||||
// get random sound
|
||||
QFileInfo inf = QFileInfo(PathUtils::resourcesPath() +
|
||||
mentionSoundsPath +
|
||||
_mentionSounds.at(rand() % _mentionSounds.size()));
|
||||
_effectPlayer.setMedia(QUrl::fromLocalFile(inf.absoluteFilePath()));
|
||||
_effectPlayer.play();
|
||||
}
|
||||
|
||||
_trayIcon.show();
|
||||
_trayIcon.showMessage(windowTitle(), message.body());
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif // HAVE_QXMPP
|
||||
|
||||
bool ChatWindow::isNearBottom() {
|
||||
QScrollBar* verticalScrollBar = _ui->messagesScrollArea->verticalScrollBar();
|
||||
return verticalScrollBar->value() >= verticalScrollBar->maximum() - Ui::AUTO_SCROLL_THRESHOLD;
|
||||
}
|
||||
|
||||
// Scroll chat message area to bottom.
|
||||
void ChatWindow::scrollToBottom() {
|
||||
QScrollBar* verticalScrollBar = _ui->messagesScrollArea->verticalScrollBar();
|
||||
verticalScrollBar->setValue(verticalScrollBar->maximum());
|
||||
}
|
||||
|
||||
bool ChatWindow::event(QEvent* event) {
|
||||
if (event->type() == QEvent::WindowActivate) {
|
||||
_ui->messagePlainTextEdit->setFocus();
|
||||
}
|
||||
return QWidget::event(event);
|
||||
}
|
|
@ -1,88 +0,0 @@
|
|||
//
|
||||
// ChatWindow.h
|
||||
// interface/src/ui
|
||||
//
|
||||
// Created by Dimitar Dobrev on 3/6/14.
|
||||
// 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_ChatWindow_h
|
||||
#define hifi_ChatWindow_h
|
||||
|
||||
#include <QDateTime>
|
||||
#include <QDockWidget>
|
||||
#include <QMediaPlayer>
|
||||
#include <QSystemTrayIcon>
|
||||
#include <QTimer>
|
||||
|
||||
#include <Application.h>
|
||||
#include <SettingHandle.h>
|
||||
|
||||
#include "FramelessDialog.h"
|
||||
|
||||
#ifdef HAVE_QXMPP
|
||||
|
||||
#include <qxmpp/QXmppClient.h>
|
||||
#include <qxmpp/QXmppMessage.h>
|
||||
|
||||
#endif
|
||||
|
||||
namespace Ui {
|
||||
|
||||
|
||||
// Maximum amount the chat can be scrolled up in order to auto scroll.
|
||||
const int AUTO_SCROLL_THRESHOLD = 20;
|
||||
|
||||
|
||||
class ChatWindow;
|
||||
}
|
||||
|
||||
class ChatWindow : public QWidget {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
ChatWindow(QWidget* parent);
|
||||
~ChatWindow();
|
||||
|
||||
protected:
|
||||
bool eventFilter(QObject* sender, QEvent* event);
|
||||
|
||||
virtual void keyPressEvent(QKeyEvent *event);
|
||||
virtual void showEvent(QShowEvent* event);
|
||||
virtual bool event(QEvent* event);
|
||||
|
||||
private:
|
||||
#ifdef HAVE_QXMPP
|
||||
QString getParticipantName(const QString& participant);
|
||||
#endif
|
||||
void startTimerForTimeStamps();
|
||||
void addTimeStamp();
|
||||
bool isNearBottom();
|
||||
void scrollToBottom();
|
||||
|
||||
Ui::ChatWindow* _ui;
|
||||
int _numMessagesAfterLastTimeStamp;
|
||||
QDateTime _lastMessageStamp;
|
||||
bool _mousePressed;
|
||||
QPoint _mouseStartPosition;
|
||||
QSystemTrayIcon _trayIcon;
|
||||
QStringList _mentionSounds;
|
||||
QMediaPlayer _effectPlayer;
|
||||
|
||||
Setting::Handle<QDateTime> _usernameMentionTimestamp;
|
||||
|
||||
private slots:
|
||||
void connected();
|
||||
void timeout();
|
||||
#ifdef HAVE_QXMPP
|
||||
void error(QXmppClient::Error error);
|
||||
void participantsChanged();
|
||||
void messageReceived(const QXmppMessage& message);
|
||||
void notificationClicked();
|
||||
#endif
|
||||
};
|
||||
|
||||
#endif // hifi_ChatWindow_h
|
|
@ -9,22 +9,20 @@
|
|||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#include <QMessageBox>
|
||||
|
||||
#include <AccountManager.h>
|
||||
#include <MainWindow.h>
|
||||
#include <PathUtils.h>
|
||||
#include <XmppClient.h>
|
||||
|
||||
#include "AddressBarDialog.h"
|
||||
#include "AnimationsDialog.h"
|
||||
#include "AttachmentsDialog.h"
|
||||
#include "BandwidthDialog.h"
|
||||
#include "CachesSizeDialog.h"
|
||||
#include "ChatWindow.h"
|
||||
#include "HMDToolsDialog.h"
|
||||
#include "LodToolsDialog.h"
|
||||
#include "LoginDialog.h"
|
||||
#include "MetavoxelEditor.h"
|
||||
#include "MetavoxelNetworkSimulator.h"
|
||||
#include "OctreeStatsDialog.h"
|
||||
#include "PreferencesDialog.h"
|
||||
#include "ScriptEditorWindow.h"
|
||||
|
@ -148,68 +146,21 @@ void DialogsManager::hmdToolsClosed() {
|
|||
_hmdToolsDialog->hide();
|
||||
}
|
||||
|
||||
void DialogsManager::showMetavoxelEditor() {
|
||||
maybeCreateDialog(_metavoxelEditor);
|
||||
_metavoxelEditor->raise();
|
||||
}
|
||||
|
||||
void DialogsManager::showMetavoxelNetworkSimulator() {
|
||||
maybeCreateDialog(_metavoxelNetworkSimulator);
|
||||
_metavoxelNetworkSimulator->raise();
|
||||
}
|
||||
|
||||
void DialogsManager::showScriptEditor() {
|
||||
maybeCreateDialog(_scriptEditor);
|
||||
_scriptEditor->raise();
|
||||
}
|
||||
|
||||
void DialogsManager::setupChat() {
|
||||
#ifdef HAVE_QXMPP
|
||||
const QXmppClient& xmppClient = XmppClient::getInstance().getXMPPClient();
|
||||
connect(&xmppClient, &QXmppClient::connected, this, &DialogsManager::toggleChat);
|
||||
connect(&xmppClient, &QXmppClient::disconnected, this, &DialogsManager::toggleChat);
|
||||
|
||||
QDir::setCurrent(PathUtils::resourcesPath());
|
||||
// init chat window to listen chat
|
||||
maybeCreateDialog(_chatWindow);
|
||||
#endif
|
||||
}
|
||||
|
||||
void DialogsManager::showChat() {
|
||||
if (AccountManager::getInstance().isLoggedIn()) {
|
||||
maybeCreateDialog(_chatWindow);
|
||||
|
||||
if (_chatWindow->isHidden()) {
|
||||
_chatWindow->show();
|
||||
}
|
||||
_chatWindow->raise();
|
||||
_chatWindow->activateWindow();
|
||||
_chatWindow->setFocus();
|
||||
} else {
|
||||
qApp->getTrayIcon()->showMessage("Interface",
|
||||
"You need to login to be able to chat with others on this domain.");
|
||||
void DialogsManager::showIRCLink() {
|
||||
if (!_ircInfoBox) {
|
||||
_ircInfoBox = new QMessageBox(QMessageBox::NoIcon,
|
||||
"High Fidelity IRC",
|
||||
"High Fidelity has an IRC channel on irc.freenode.net at #highfidelity.<br/><br/>Web chat is available <a href='http://webchat.freenode.net/?channels=highfidelity&uio=d4'>here</a>.",
|
||||
QMessageBox::Ok);
|
||||
_ircInfoBox->setTextFormat(Qt::RichText);
|
||||
_ircInfoBox->setAttribute(Qt::WA_DeleteOnClose);
|
||||
_ircInfoBox->show();
|
||||
}
|
||||
}
|
||||
|
||||
void DialogsManager::toggleChat() {
|
||||
#ifdef HAVE_QXMPP
|
||||
QAction* chatAction = Menu::getInstance()->getActionForOption(MenuOption::Login);
|
||||
Q_CHECK_PTR(chatAction);
|
||||
|
||||
chatAction->setEnabled(XmppClient::getInstance().getXMPPClient().isConnected());
|
||||
if (!chatAction->isEnabled() && _chatWindow && AccountManager::getInstance().isLoggedIn()) {
|
||||
if (_chatWindow->isHidden()) {
|
||||
_chatWindow->show();
|
||||
_chatWindow->raise();
|
||||
_chatWindow->activateWindow();
|
||||
_chatWindow->setFocus();
|
||||
} else {
|
||||
_chatWindow->hide();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
_ircInfoBox->raise();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -25,15 +25,13 @@ class AddressBarDialog;
|
|||
class AnimationsDialog;
|
||||
class AttachmentsDialog;
|
||||
class CachesSizeDialog;
|
||||
class ChatWindow;
|
||||
class BandwidthDialog;
|
||||
class LodToolsDialog;
|
||||
class LoginDialog;
|
||||
class MetavoxelEditor;
|
||||
class MetavoxelNetworkSimulator;
|
||||
class OctreeStatsDialog;
|
||||
class PreferencesDialog;
|
||||
class ScriptEditorWindow;
|
||||
class QMessageBox;
|
||||
|
||||
class DialogsManager : public QObject, public Dependency {
|
||||
Q_OBJECT
|
||||
|
@ -45,8 +43,6 @@ public:
|
|||
QPointer<LodToolsDialog> getLodToolsDialog() const { return _lodToolsDialog; }
|
||||
QPointer<OctreeStatsDialog> getOctreeStatsDialog() const { return _octreeStatsDialog; }
|
||||
|
||||
void setupChat();
|
||||
|
||||
public slots:
|
||||
void toggleAddressBar();
|
||||
void toggleLoginDialog();
|
||||
|
@ -59,15 +55,12 @@ public slots:
|
|||
void bandwidthDetails();
|
||||
void lodTools();
|
||||
void hmdTools(bool showTools);
|
||||
void showMetavoxelEditor();
|
||||
void showMetavoxelNetworkSimulator();
|
||||
void showScriptEditor();
|
||||
void showChat();
|
||||
|
||||
void showIRCLink();
|
||||
|
||||
private slots:
|
||||
void toggleToolWindow();
|
||||
void hmdToolsClosed();
|
||||
void toggleChat();
|
||||
|
||||
private:
|
||||
DialogsManager() {}
|
||||
|
@ -91,12 +84,10 @@ private:
|
|||
QPointer<AttachmentsDialog> _attachmentsDialog;
|
||||
QPointer<BandwidthDialog> _bandwidthDialog;
|
||||
QPointer<CachesSizeDialog> _cachesSizeDialog;
|
||||
QPointer<ChatWindow> _chatWindow;
|
||||
QPointer<QMessageBox> _ircInfoBox;
|
||||
QPointer<HMDToolsDialog> _hmdToolsDialog;
|
||||
QPointer<LodToolsDialog> _lodToolsDialog;
|
||||
QPointer<LoginDialog> _loginDialog;
|
||||
QPointer<MetavoxelEditor> _metavoxelEditor;
|
||||
QPointer<MetavoxelNetworkSimulator> _metavoxelNetworkSimulator;
|
||||
QPointer<OctreeStatsDialog> _octreeStatsDialog;
|
||||
QPointer<PreferencesDialog> _preferencesDialog;
|
||||
QPointer<ScriptEditorWindow> _scriptEditor;
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -1,479 +0,0 @@
|
|||
//
|
||||
// MetavoxelEditor.h
|
||||
// interface/src/ui
|
||||
//
|
||||
// Created by Andrzej Kapolka on 1/21/14.
|
||||
// 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_MetavoxelEditor_h
|
||||
#define hifi_MetavoxelEditor_h
|
||||
|
||||
#include <QFormLayout>
|
||||
#include <QList>
|
||||
#include <QWidget>
|
||||
|
||||
#include <ProgramObject.h>
|
||||
|
||||
#include "MetavoxelSystem.h"
|
||||
|
||||
class QColorEditor;
|
||||
class QComboBox;
|
||||
class QDoubleSpinBox;
|
||||
class QGroupBox;
|
||||
class QListWidget;
|
||||
class QPushButton;
|
||||
class QScrollArea;
|
||||
class QSpinBox;
|
||||
|
||||
class MetavoxelTool;
|
||||
class SharedObjectEditor;
|
||||
class Vec3Editor;
|
||||
|
||||
/// Allows editing metavoxels.
|
||||
class MetavoxelEditor : public QWidget {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
||||
MetavoxelEditor(QWidget* parent = nullptr);
|
||||
|
||||
QString getSelectedAttribute() const;
|
||||
|
||||
double getGridSpacing() const;
|
||||
double getGridPosition() const;
|
||||
glm::quat getGridRotation() const;
|
||||
|
||||
QVariant getValue() const;
|
||||
|
||||
virtual bool eventFilter(QObject* watched, QEvent* event);
|
||||
|
||||
private slots:
|
||||
|
||||
void selectedAttributeChanged();
|
||||
void createNewAttribute();
|
||||
void deleteSelectedAttribute();
|
||||
void centerGridPosition();
|
||||
void alignGridPosition();
|
||||
void updateAttributes(const QString& select = QString());
|
||||
void updateTool();
|
||||
|
||||
void simulate(float deltaTime);
|
||||
void render();
|
||||
void renderPreview();
|
||||
|
||||
private:
|
||||
|
||||
void addTool(MetavoxelTool* tool);
|
||||
MetavoxelTool* getActiveTool() const;
|
||||
|
||||
QListWidget* _attributes;
|
||||
QPushButton* _deleteAttribute;
|
||||
QCheckBox* _showAll;
|
||||
|
||||
QComboBox* _gridPlane;
|
||||
QDoubleSpinBox* _gridSpacing;
|
||||
QDoubleSpinBox* _gridPosition;
|
||||
|
||||
QList<MetavoxelTool*> _tools;
|
||||
QComboBox* _toolBox;
|
||||
|
||||
QGroupBox* _value;
|
||||
QScrollArea* _valueArea;
|
||||
|
||||
static ProgramObject _gridProgram;
|
||||
};
|
||||
|
||||
/// Base class for editor tools.
|
||||
class MetavoxelTool : public QWidget {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
||||
MetavoxelTool(MetavoxelEditor* editor, const QString& name, bool usesValue = true,
|
||||
bool userFacing = true, bool usesGrid = true);
|
||||
|
||||
bool getUsesValue() const { return _usesValue; }
|
||||
|
||||
bool isUserFacing() const { return _userFacing; }
|
||||
|
||||
bool getUsesGrid() const { return _usesGrid; }
|
||||
|
||||
virtual bool appliesTo(const AttributePointer& attribute) const;
|
||||
|
||||
virtual void simulate(float deltaTime);
|
||||
|
||||
/// Renders the tool's interface, if any.
|
||||
virtual void render();
|
||||
|
||||
/// Renders the tool's metavoxel preview, if any.
|
||||
virtual void renderPreview();
|
||||
|
||||
protected:
|
||||
|
||||
MetavoxelEditor* _editor;
|
||||
bool _usesValue;
|
||||
bool _userFacing;
|
||||
bool _usesGrid;
|
||||
};
|
||||
|
||||
/// Base class for tools that allow dragging out a 3D box.
|
||||
class BoxTool : public MetavoxelTool {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
||||
BoxTool(MetavoxelEditor* editor, const QString& name, bool usesValue = true, bool userFacing = true);
|
||||
|
||||
virtual void render();
|
||||
|
||||
virtual bool eventFilter(QObject* watched, QEvent* event);
|
||||
|
||||
protected:
|
||||
|
||||
virtual bool shouldSnapToGrid();
|
||||
|
||||
virtual QColor getColor() = 0;
|
||||
|
||||
virtual void applyValue(const glm::vec3& minimum, const glm::vec3& maximum) = 0;
|
||||
|
||||
private:
|
||||
|
||||
void resetState();
|
||||
|
||||
enum State { HOVERING_STATE, DRAGGING_STATE, RAISING_STATE };
|
||||
|
||||
State _state;
|
||||
|
||||
glm::vec2 _mousePosition; ///< the position of the mouse in rotated space
|
||||
glm::vec2 _startPosition; ///< the first corner of the selection base
|
||||
glm::vec2 _endPosition; ///< the second corner of the selection base
|
||||
float _height; ///< the selection height
|
||||
};
|
||||
|
||||
/// Allows setting the value of a region by dragging out a box.
|
||||
class BoxSetTool : public BoxTool {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
||||
BoxSetTool(MetavoxelEditor* editor);
|
||||
|
||||
protected:
|
||||
|
||||
virtual QColor getColor();
|
||||
|
||||
virtual void applyValue(const glm::vec3& minimum, const glm::vec3& maximum);
|
||||
};
|
||||
|
||||
/// Allows setting the value across the entire space.
|
||||
class GlobalSetTool : public MetavoxelTool {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
||||
GlobalSetTool(MetavoxelEditor* editor);
|
||||
|
||||
private slots:
|
||||
|
||||
void apply();
|
||||
};
|
||||
|
||||
/// Base class for insert/set spanner tools.
|
||||
class PlaceSpannerTool : public MetavoxelTool {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
||||
PlaceSpannerTool(MetavoxelEditor* editor, const QString& name,
|
||||
const QString& placeText = QString(), bool usesValue = true);
|
||||
|
||||
virtual void simulate(float deltaTime);
|
||||
|
||||
virtual void renderPreview();
|
||||
|
||||
virtual bool appliesTo(const AttributePointer& attribute) const;
|
||||
|
||||
virtual bool eventFilter(QObject* watched, QEvent* event);
|
||||
|
||||
protected:
|
||||
|
||||
virtual QColor getColor();
|
||||
virtual SharedObjectPointer getSpanner();
|
||||
virtual void applyEdit(const AttributePointer& attribute, const SharedObjectPointer& spanner) = 0;
|
||||
|
||||
protected slots:
|
||||
|
||||
void place();
|
||||
|
||||
private:
|
||||
|
||||
QCheckBox* _followMouse;
|
||||
};
|
||||
|
||||
/// Allows inserting a spanner into the scene.
|
||||
class InsertSpannerTool : public PlaceSpannerTool {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
||||
InsertSpannerTool(MetavoxelEditor* editor);
|
||||
|
||||
protected:
|
||||
|
||||
virtual void applyEdit(const AttributePointer& attribute, const SharedObjectPointer& spanner);
|
||||
};
|
||||
|
||||
/// Allows removing a spanner from the scene.
|
||||
class RemoveSpannerTool : public MetavoxelTool {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
||||
RemoveSpannerTool(MetavoxelEditor* editor);
|
||||
|
||||
virtual bool appliesTo(const AttributePointer& attribute) const;
|
||||
|
||||
virtual bool eventFilter(QObject* watched, QEvent* event);
|
||||
};
|
||||
|
||||
/// Allows removing all spanners from the scene.
|
||||
class ClearSpannersTool : public MetavoxelTool {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
||||
ClearSpannersTool(MetavoxelEditor* editor);
|
||||
|
||||
virtual bool appliesTo(const AttributePointer& attribute) const;
|
||||
|
||||
private slots:
|
||||
|
||||
void clear();
|
||||
};
|
||||
|
||||
/// Base class for heightfield tools.
|
||||
class HeightfieldTool : public MetavoxelTool {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
||||
HeightfieldTool(MetavoxelEditor* editor, const QString& name);
|
||||
|
||||
virtual bool appliesTo(const AttributePointer& attribute) const;
|
||||
|
||||
protected slots:
|
||||
|
||||
virtual void apply() = 0;
|
||||
|
||||
protected:
|
||||
|
||||
QFormLayout* _form;
|
||||
Vec3Editor* _translation;
|
||||
QDoubleSpinBox* _spacing;
|
||||
};
|
||||
|
||||
/// Allows importing a heightfield.
|
||||
class ImportHeightfieldTool : public HeightfieldTool {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
||||
ImportHeightfieldTool(MetavoxelEditor* editor);
|
||||
|
||||
virtual void simulate(float deltaTime);
|
||||
|
||||
virtual void renderPreview();
|
||||
|
||||
protected:
|
||||
|
||||
virtual void apply();
|
||||
|
||||
private slots:
|
||||
|
||||
void updateSpanner();
|
||||
|
||||
private:
|
||||
|
||||
QDoubleSpinBox* _heightScale;
|
||||
QDoubleSpinBox* _heightOffset;
|
||||
|
||||
HeightfieldHeightEditor* _height;
|
||||
HeightfieldColorEditor* _color;
|
||||
|
||||
SharedObjectPointer _spanner;
|
||||
};
|
||||
|
||||
/// Base class for tools that allow painting on heightfields.
|
||||
class HeightfieldBrushTool : public MetavoxelTool {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
||||
HeightfieldBrushTool(MetavoxelEditor* editor, const QString& name);
|
||||
|
||||
virtual bool appliesTo(const AttributePointer& attribute) const;
|
||||
|
||||
virtual void render();
|
||||
|
||||
virtual bool eventFilter(QObject* watched, QEvent* event);
|
||||
|
||||
protected:
|
||||
|
||||
virtual QVariant createEdit(bool alternate) = 0;
|
||||
|
||||
QFormLayout* _form;
|
||||
QDoubleSpinBox* _radius;
|
||||
QDoubleSpinBox* _granularity;
|
||||
|
||||
glm::vec3 _position;
|
||||
bool _positionValid;
|
||||
};
|
||||
|
||||
/// Allows raising or lowering parts of the heightfield.
|
||||
class HeightfieldHeightBrushTool : public HeightfieldBrushTool {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
||||
HeightfieldHeightBrushTool(MetavoxelEditor* editor);
|
||||
|
||||
protected:
|
||||
|
||||
virtual QVariant createEdit(bool alternate);
|
||||
|
||||
private:
|
||||
|
||||
QDoubleSpinBox* _height;
|
||||
QComboBox* _mode;
|
||||
};
|
||||
|
||||
/// Contains widgets for editing materials.
|
||||
class MaterialControl : public QObject {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
||||
MaterialControl(QWidget* widget, QFormLayout* form, bool clearable = false);
|
||||
|
||||
SharedObjectPointer getMaterial();
|
||||
|
||||
const QColor& getColor() const { return _color->getColor(); }
|
||||
|
||||
private slots:
|
||||
|
||||
void clearColor();
|
||||
void clearTexture();
|
||||
void updateTexture();
|
||||
void textureLoaded();
|
||||
|
||||
private:
|
||||
|
||||
QColorEditor* _color;
|
||||
SharedObjectEditor* _materialEditor;
|
||||
QSharedPointer<NetworkTexture> _texture;
|
||||
};
|
||||
|
||||
/// Allows texturing parts of the heightfield.
|
||||
class HeightfieldMaterialBrushTool : public HeightfieldBrushTool {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
||||
HeightfieldMaterialBrushTool(MetavoxelEditor* editor);
|
||||
|
||||
protected:
|
||||
|
||||
virtual QVariant createEdit(bool alternate);
|
||||
|
||||
private:
|
||||
|
||||
MaterialControl* _materialControl;
|
||||
};
|
||||
|
||||
/// Allows sculpting parts of the heightfield.
|
||||
class HeightfieldSculptBrushTool : public HeightfieldBrushTool {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
||||
HeightfieldSculptBrushTool(MetavoxelEditor* editor);
|
||||
|
||||
protected:
|
||||
|
||||
virtual QVariant createEdit(bool alternate);
|
||||
|
||||
private:
|
||||
|
||||
MaterialControl* _materialControl;
|
||||
};
|
||||
|
||||
/// Allows "filling" (removing dual contour stack data) parts of the heightfield.
|
||||
class HeightfieldFillBrushTool : public HeightfieldBrushTool {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
||||
HeightfieldFillBrushTool(MetavoxelEditor* editor);
|
||||
|
||||
protected:
|
||||
|
||||
virtual QVariant createEdit(bool alternate);
|
||||
|
||||
private:
|
||||
|
||||
QComboBox* _mode;
|
||||
};
|
||||
|
||||
/// Allows setting heightfield materials by dragging out a box.
|
||||
class HeightfieldMaterialBoxTool : public BoxTool {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
||||
HeightfieldMaterialBoxTool(MetavoxelEditor* editor);
|
||||
|
||||
virtual bool appliesTo(const AttributePointer& attribute) const;
|
||||
|
||||
protected:
|
||||
|
||||
virtual bool shouldSnapToGrid();
|
||||
|
||||
virtual QColor getColor();
|
||||
|
||||
virtual void applyValue(const glm::vec3& minimum, const glm::vec3& maximum);
|
||||
|
||||
private:
|
||||
|
||||
QCheckBox* _snapToGrid;
|
||||
MaterialControl* _materialControl;
|
||||
QDoubleSpinBox* _granularity;
|
||||
};
|
||||
|
||||
/// Allows setting heightfield materials by placing a spanner.
|
||||
class HeightfieldMaterialSpannerTool : public PlaceSpannerTool {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
||||
HeightfieldMaterialSpannerTool(MetavoxelEditor* editor);
|
||||
|
||||
virtual bool appliesTo(const AttributePointer& attribute) const;
|
||||
|
||||
protected:
|
||||
|
||||
virtual SharedObjectPointer getSpanner();
|
||||
virtual QColor getColor();
|
||||
virtual void applyEdit(const AttributePointer& attribute, const SharedObjectPointer& spanner);
|
||||
|
||||
private:
|
||||
|
||||
SharedObjectEditor* _spannerEditor;
|
||||
MaterialControl* _materialControl;
|
||||
QDoubleSpinBox* _granularity;
|
||||
};
|
||||
|
||||
#endif // hifi_MetavoxelEditor_h
|
|
@ -1,87 +0,0 @@
|
|||
//
|
||||
// MetavoxelNetworkSimulator.cpp
|
||||
// interface/src/ui
|
||||
//
|
||||
// Created by Andrzej Kapolka on 10/20/14.
|
||||
// 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 <QDialogButtonBox>
|
||||
#include <QDoubleSpinBox>
|
||||
#include <QFormLayout>
|
||||
#include <QSpinBox>
|
||||
#include <QVBoxLayout>
|
||||
|
||||
#include "Application.h"
|
||||
#include "MetavoxelNetworkSimulator.h"
|
||||
|
||||
const int BYTES_PER_KILOBYTE = 1024;
|
||||
|
||||
MetavoxelNetworkSimulator::MetavoxelNetworkSimulator(QWidget* parent) :
|
||||
QWidget(parent, Qt::Dialog) {
|
||||
|
||||
setWindowTitle("Metavoxel Network Simulator");
|
||||
setAttribute(Qt::WA_DeleteOnClose);
|
||||
|
||||
QVBoxLayout* topLayout = new QVBoxLayout();
|
||||
setLayout(topLayout);
|
||||
|
||||
QFormLayout* form = new QFormLayout();
|
||||
topLayout->addLayout(form);
|
||||
|
||||
MetavoxelSystem::NetworkSimulation simulation = Application::getInstance()->getMetavoxels()->getNetworkSimulation();
|
||||
|
||||
form->addRow("Drop Rate:", _dropRate = new QDoubleSpinBox());
|
||||
_dropRate->setSuffix("%");
|
||||
_dropRate->setValue(simulation.dropRate * 100.0);
|
||||
connect(_dropRate, static_cast<void (QDoubleSpinBox::*)(double)>(&QDoubleSpinBox::valueChanged), this,
|
||||
&MetavoxelNetworkSimulator::updateMetavoxelSystem);
|
||||
|
||||
form->addRow("Repeat Rate:", _repeatRate = new QDoubleSpinBox());
|
||||
_repeatRate->setSuffix("%");
|
||||
_repeatRate->setValue(simulation.repeatRate * 100.0);
|
||||
connect(_repeatRate, static_cast<void (QDoubleSpinBox::*)(double)>(&QDoubleSpinBox::valueChanged), this,
|
||||
&MetavoxelNetworkSimulator::updateMetavoxelSystem);
|
||||
|
||||
form->addRow("Minimum Delay:", _minimumDelay = new QSpinBox());
|
||||
_minimumDelay->setMaximum(1000);
|
||||
_minimumDelay->setSuffix("ms");
|
||||
_minimumDelay->setValue(simulation.minimumDelay);
|
||||
connect(_minimumDelay, static_cast<void (QSpinBox::*)(int)>(&QSpinBox::valueChanged), this,
|
||||
&MetavoxelNetworkSimulator::updateMetavoxelSystem);
|
||||
|
||||
form->addRow("Maximum Delay:", _maximumDelay = new QSpinBox());
|
||||
_maximumDelay->setMaximum(1000);
|
||||
_maximumDelay->setSuffix("ms");
|
||||
_maximumDelay->setValue(simulation.maximumDelay);
|
||||
connect(_maximumDelay, static_cast<void (QSpinBox::*)(int)>(&QSpinBox::valueChanged), this,
|
||||
&MetavoxelNetworkSimulator::updateMetavoxelSystem);
|
||||
|
||||
form->addRow("Bandwidth Limit:", _bandwidthLimit = new QSpinBox());
|
||||
_bandwidthLimit->setMaximum(1024 * 1024);
|
||||
_bandwidthLimit->setSuffix("KB/s");
|
||||
_bandwidthLimit->setValue(simulation.bandwidthLimit / BYTES_PER_KILOBYTE);
|
||||
connect(_bandwidthLimit, static_cast<void (QSpinBox::*)(int)>(&QSpinBox::valueChanged), this,
|
||||
&MetavoxelNetworkSimulator::updateMetavoxelSystem);
|
||||
|
||||
QDialogButtonBox* buttons = new QDialogButtonBox(QDialogButtonBox::Ok, this);
|
||||
topLayout->addWidget(buttons);
|
||||
connect(buttons, &QDialogButtonBox::accepted, this, &QWidget::close);
|
||||
|
||||
show();
|
||||
}
|
||||
|
||||
void MetavoxelNetworkSimulator::updateMetavoxelSystem() {
|
||||
int bandwidthLimit = _bandwidthLimit->value() * BYTES_PER_KILOBYTE;
|
||||
if (bandwidthLimit > 0) {
|
||||
// make sure the limit is enough to let at least one packet through
|
||||
const int MINIMUM_BANDWIDTH_LIMIT = 2048;
|
||||
bandwidthLimit = qMax(bandwidthLimit, MINIMUM_BANDWIDTH_LIMIT);
|
||||
}
|
||||
Application::getInstance()->getMetavoxels()->setNetworkSimulation(MetavoxelSystem::NetworkSimulation(
|
||||
_dropRate->value() / 100.0, _repeatRate->value() / 100.0, qMin(_minimumDelay->value(), _maximumDelay->value()),
|
||||
qMax(_minimumDelay->value(), _maximumDelay->value()), bandwidthLimit));
|
||||
}
|
|
@ -1,41 +0,0 @@
|
|||
//
|
||||
// MetavoxelNetworkSimulator.h
|
||||
// interface/src/ui
|
||||
//
|
||||
// Created by Andrzej Kapolka on 10/20/14.
|
||||
// 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_MetavoxelNetworkSimulator_h
|
||||
#define hifi_MetavoxelNetworkSimulator_h
|
||||
|
||||
#include <QWidget>
|
||||
|
||||
class QDoubleSpinBox;
|
||||
class QSpinBox;
|
||||
|
||||
/// Allows tweaking network simulation (packet drop percentage, etc.) settings for metavoxels.
|
||||
class MetavoxelNetworkSimulator : public QWidget {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
||||
MetavoxelNetworkSimulator(QWidget* parent = nullptr);
|
||||
|
||||
private slots:
|
||||
|
||||
void updateMetavoxelSystem();
|
||||
|
||||
private:
|
||||
|
||||
QDoubleSpinBox* _dropRate;
|
||||
QDoubleSpinBox* _repeatRate;
|
||||
QSpinBox* _minimumDelay;
|
||||
QSpinBox* _maximumDelay;
|
||||
QSpinBox* _bandwidthLimit;
|
||||
};
|
||||
|
||||
#endif // hifi_MetavoxelNetworkSimulator_h
|
|
@ -235,7 +235,7 @@ void PreferencesDialog::savePreferences() {
|
|||
myAvatar->setLeanScale(ui.leanScaleSpin->value());
|
||||
myAvatar->setClampedTargetScale(ui.avatarScaleSpin->value());
|
||||
|
||||
auto glCanvas = DependencyManager::get<GLCanvas>();
|
||||
auto glCanvas = Application::getInstance()->getGLWidget();
|
||||
Application::getInstance()->resizeGL(glCanvas->width(), glCanvas->height());
|
||||
|
||||
DependencyManager::get<AvatarManager>()->getMyAvatar()->setRealWorldFieldOfView(ui.realWorldFieldOfViewSpin->value());
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
#include <GLCanvas.h>
|
||||
#include <NodeList.h>
|
||||
|
||||
#include "Application.h"
|
||||
#include "Snapshot.h"
|
||||
|
||||
// filename format: hifi-snap-by-%username%-on-%date%_%time%_@-%location%.jpg
|
||||
|
@ -93,7 +94,7 @@ QTemporaryFile* Snapshot::saveTempSnapshot() {
|
|||
}
|
||||
|
||||
QFile* Snapshot::savedFileForSnapshot(bool isTemporary) {
|
||||
auto glCanvas = DependencyManager::get<GLCanvas>();
|
||||
auto glCanvas = Application::getInstance()->getGLWidget();
|
||||
QImage shot = glCanvas->grabFrameBuffer();
|
||||
|
||||
Avatar* avatar = DependencyManager::get<AvatarManager>()->getMyAvatar();
|
||||
|
|
|
@ -34,7 +34,8 @@
|
|||
|
||||
using namespace std;
|
||||
|
||||
const int STATS_PELS_PER_LINE = 20;
|
||||
const int STATS_PELS_PER_LINE = 16;
|
||||
const int STATS_PELS_INITIALOFFSET = 12;
|
||||
|
||||
const int STATS_GENERAL_MIN_WIDTH = 165;
|
||||
const int STATS_PING_MIN_WIDTH = 190;
|
||||
|
@ -54,15 +55,9 @@ Stats::Stats():
|
|||
_pingStatsWidth(STATS_PING_MIN_WIDTH),
|
||||
_geoStatsWidth(STATS_GEO_MIN_WIDTH),
|
||||
_octreeStatsWidth(STATS_OCTREE_MIN_WIDTH),
|
||||
_lastHorizontalOffset(0),
|
||||
_metavoxelInternal(0),
|
||||
_metavoxelLeaves(0),
|
||||
_metavoxelSendProgress(0),
|
||||
_metavoxelSendTotal(0),
|
||||
_metavoxelReceiveProgress(0),
|
||||
_metavoxelReceiveTotal(0)
|
||||
_lastHorizontalOffset(0)
|
||||
{
|
||||
auto glCanvas = DependencyManager::get<GLCanvas>();
|
||||
auto glCanvas = Application::getInstance()->getGLWidget();
|
||||
resetWidth(glCanvas->width(), 0);
|
||||
}
|
||||
|
||||
|
@ -73,7 +68,7 @@ void Stats::toggleExpanded() {
|
|||
// called on mouse click release
|
||||
// check for clicks over stats in order to expand or contract them
|
||||
void Stats::checkClick(int mouseX, int mouseY, int mouseDragStartedX, int mouseDragStartedY, int horizontalOffset) {
|
||||
auto glCanvas = DependencyManager::get<GLCanvas>();
|
||||
auto glCanvas = Application::getInstance()->getGLWidget();
|
||||
|
||||
if (0 != glm::compMax(glm::abs(glm::ivec2(mouseX - mouseDragStartedX, mouseY - mouseDragStartedY)))) {
|
||||
// not worried about dragging on stats
|
||||
|
@ -128,7 +123,7 @@ void Stats::checkClick(int mouseX, int mouseY, int mouseDragStartedX, int mouseD
|
|||
}
|
||||
|
||||
void Stats::resetWidth(int width, int horizontalOffset) {
|
||||
auto glCanvas = DependencyManager::get<GLCanvas>();
|
||||
auto glCanvas = Application::getInstance()->getGLWidget();
|
||||
int extraSpace = glCanvas->width() - horizontalOffset -2
|
||||
- STATS_GENERAL_MIN_WIDTH
|
||||
- (Menu::getInstance()->isOptionChecked(MenuOption::TestPing) ? STATS_PING_MIN_WIDTH -1 : 0)
|
||||
|
@ -170,7 +165,7 @@ void Stats::drawBackground(unsigned int rgba, int x, int y, int width, int heigh
|
|||
}
|
||||
|
||||
bool Stats::includeTimingRecord(const QString& name) {
|
||||
if (Menu::getInstance()->isOptionChecked(MenuOption::DisplayTimingDetails)) {
|
||||
if (Menu::getInstance()->isOptionChecked(MenuOption::DisplayDebugTimingDetails)) {
|
||||
if (name.startsWith("/idle/update/")) {
|
||||
if (name.startsWith("/idle/update/myAvatar/")) {
|
||||
if (name.startsWith("/idle/update/myAvatar/simulate/")) {
|
||||
|
@ -202,7 +197,7 @@ void Stats::display(
|
|||
int outKbitsPerSecond,
|
||||
int voxelPacketsToProcess)
|
||||
{
|
||||
auto glCanvas = DependencyManager::get<GLCanvas>();
|
||||
auto glCanvas = Application::getInstance()->getGLWidget();
|
||||
|
||||
unsigned int backgroundColor = 0x33333399;
|
||||
int verticalOffset = 0, lines = 0;
|
||||
|
@ -231,7 +226,7 @@ void Stats::display(
|
|||
|
||||
PerformanceTimer::tallyAllTimerRecords(); // do this even if we're not displaying them, so they don't stack up
|
||||
|
||||
if (_expanded && Menu::getInstance()->isOptionChecked(MenuOption::DisplayTimingDetails)) {
|
||||
if (_expanded && Menu::getInstance()->isOptionChecked(MenuOption::DisplayDebugTimingDetails)) {
|
||||
|
||||
columnOneWidth = _generalStatsWidth + _pingStatsWidth + _geoStatsWidth; // 3 columns wide...
|
||||
// we will also include room for 1 line per timing record and a header of 4 lines
|
||||
|
@ -239,15 +234,21 @@ void Stats::display(
|
|||
|
||||
const QMap<QString, PerformanceTimerRecord>& allRecords = PerformanceTimer::getAllTimerRecords();
|
||||
QMapIterator<QString, PerformanceTimerRecord> i(allRecords);
|
||||
bool onlyDisplayTopTen = Menu::getInstance()->isOptionChecked(MenuOption::OnlyDisplayTopTen);
|
||||
int statsLines = 0;
|
||||
while (i.hasNext()) {
|
||||
i.next();
|
||||
if (includeTimingRecord(i.key())) {
|
||||
lines++;
|
||||
statsLines++;
|
||||
if (onlyDisplayTopTen && statsLines == 10) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
drawBackground(backgroundColor, horizontalOffset, 0, columnOneWidth, lines * STATS_PELS_PER_LINE + 10);
|
||||
drawBackground(backgroundColor, horizontalOffset, 0, columnOneWidth, (lines + 1) * STATS_PELS_PER_LINE);
|
||||
horizontalOffset += 5;
|
||||
|
||||
int columnOneHorizontalOffset = horizontalOffset;
|
||||
|
@ -256,7 +257,7 @@ void Stats::display(
|
|||
QString avatarNodes = QString("Avatars: %1").arg(totalAvatars);
|
||||
QString framesPerSecond = QString("Framerate: %1 FPS").arg(fps, 3, 'f', 0);
|
||||
|
||||
verticalOffset += STATS_PELS_PER_LINE;
|
||||
verticalOffset = STATS_PELS_INITIALOFFSET; // first one is offset by less than a line
|
||||
drawText(horizontalOffset, verticalOffset, scale, rotation, font, serverNodes.toUtf8().constData(), color);
|
||||
verticalOffset += STATS_PELS_PER_LINE;
|
||||
drawText(horizontalOffset, verticalOffset, scale, rotation, font, avatarNodes.toUtf8().constData(), color);
|
||||
|
@ -275,9 +276,10 @@ void Stats::display(
|
|||
|
||||
|
||||
// TODO: the display of these timing details should all be moved to JavaScript
|
||||
if (_expanded && Menu::getInstance()->isOptionChecked(MenuOption::DisplayTimingDetails)) {
|
||||
if (_expanded && Menu::getInstance()->isOptionChecked(MenuOption::DisplayDebugTimingDetails)) {
|
||||
bool onlyDisplayTopTen = Menu::getInstance()->isOptionChecked(MenuOption::OnlyDisplayTopTen);
|
||||
// Timing details...
|
||||
verticalOffset += STATS_PELS_PER_LINE * 6; // skip 6 lines to be under the other columns
|
||||
verticalOffset += STATS_PELS_PER_LINE * 4; // skip 3 lines to be under the other columns
|
||||
drawText(columnOneHorizontalOffset, verticalOffset, scale, rotation, font,
|
||||
"-------------------------------------------------------- Function "
|
||||
"------------------------------------------------------- --msecs- -calls--", color);
|
||||
|
@ -296,6 +298,7 @@ void Stats::display(
|
|||
}
|
||||
}
|
||||
|
||||
int linesDisplayed = 0;
|
||||
QMapIterator<float, QString> j(sortedRecords);
|
||||
j.toBack();
|
||||
while (j.hasPrevious()) {
|
||||
|
@ -311,11 +314,15 @@ void Stats::display(
|
|||
|
||||
verticalOffset += STATS_PELS_PER_LINE;
|
||||
drawText(columnOneHorizontalOffset, verticalOffset, scale, rotation, font, perfLine.toUtf8().constData(), color);
|
||||
linesDisplayed++;
|
||||
if (onlyDisplayTopTen && linesDisplayed == 10) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
verticalOffset = 0;
|
||||
verticalOffset = STATS_PELS_INITIALOFFSET;
|
||||
horizontalOffset = _lastHorizontalOffset + _generalStatsWidth + 1;
|
||||
|
||||
if (Menu::getInstance()->isOptionChecked(MenuOption::TestPing)) {
|
||||
|
@ -351,7 +358,7 @@ void Stats::display(
|
|||
|
||||
// only draw our background if column one didn't draw a wide background
|
||||
if (columnOneWidth == _generalStatsWidth) {
|
||||
drawBackground(backgroundColor, horizontalOffset, 0, _pingStatsWidth, lines * STATS_PELS_PER_LINE + 10);
|
||||
drawBackground(backgroundColor, horizontalOffset, 0, _pingStatsWidth, (lines + 1) * STATS_PELS_PER_LINE);
|
||||
}
|
||||
horizontalOffset += 5;
|
||||
|
||||
|
@ -377,7 +384,6 @@ void Stats::display(
|
|||
voxelAvgPing = QString("Entities avg ping: --");
|
||||
}
|
||||
|
||||
verticalOffset += STATS_PELS_PER_LINE;
|
||||
drawText(horizontalOffset, verticalOffset, scale, rotation, font, audioPing.toUtf8().constData(), color);
|
||||
verticalOffset += STATS_PELS_PER_LINE;
|
||||
drawText(horizontalOffset, verticalOffset, scale, rotation, font, avatarPing.toUtf8().constData(), color);
|
||||
|
@ -396,17 +402,17 @@ void Stats::display(
|
|||
drawText(horizontalOffset, verticalOffset, scale, rotation, font, voxelMaxPing.toUtf8().constData(), color);
|
||||
}
|
||||
|
||||
verticalOffset = 0;
|
||||
verticalOffset = STATS_PELS_INITIALOFFSET;
|
||||
horizontalOffset = _lastHorizontalOffset + _generalStatsWidth + _pingStatsWidth + 2;
|
||||
}
|
||||
|
||||
MyAvatar* myAvatar = DependencyManager::get<AvatarManager>()->getMyAvatar();
|
||||
glm::vec3 avatarPos = myAvatar->getPosition();
|
||||
|
||||
lines = _expanded ? 8 : 3;
|
||||
lines = _expanded ? 7 : 3;
|
||||
|
||||
if (columnOneWidth == _generalStatsWidth) {
|
||||
drawBackground(backgroundColor, horizontalOffset, 0, _geoStatsWidth, lines * STATS_PELS_PER_LINE + 10);
|
||||
drawBackground(backgroundColor, horizontalOffset, 0, _geoStatsWidth, (lines + 1) * STATS_PELS_PER_LINE);
|
||||
}
|
||||
horizontalOffset += 5;
|
||||
|
||||
|
@ -418,7 +424,6 @@ void Stats::display(
|
|||
QString avatarBodyYaw = QString("Yaw: %1").arg(myAvatar->getBodyYaw(), -1, 'f', 1);
|
||||
QString avatarMixerStats;
|
||||
|
||||
verticalOffset += STATS_PELS_PER_LINE;
|
||||
drawText(horizontalOffset, verticalOffset, scale, rotation, font, avatarPosition.toUtf8().constData(), color);
|
||||
verticalOffset += STATS_PELS_PER_LINE;
|
||||
drawText(horizontalOffset, verticalOffset, scale, rotation, font, avatarVelocity.toUtf8().constData(), color);
|
||||
|
@ -449,40 +454,15 @@ void Stats::display(
|
|||
|
||||
verticalOffset += STATS_PELS_PER_LINE;
|
||||
drawText(horizontalOffset, verticalOffset, scale, rotation, font, downloads.str().c_str(), color);
|
||||
|
||||
QMetaObject::invokeMethod(Application::getInstance()->getMetavoxels()->getUpdater(), "getStats",
|
||||
Q_ARG(QObject*, this), Q_ARG(const QByteArray&, "setMetavoxelStats"));
|
||||
|
||||
stringstream nodes;
|
||||
nodes << "Metavoxels: " << (_metavoxelInternal + _metavoxelLeaves);
|
||||
verticalOffset += STATS_PELS_PER_LINE;
|
||||
drawText(horizontalOffset, verticalOffset, scale, rotation, font, nodes.str().c_str(), color);
|
||||
|
||||
stringstream nodeTypes;
|
||||
nodeTypes << "Internal: " << _metavoxelInternal << " Leaves: " << _metavoxelLeaves;
|
||||
verticalOffset += STATS_PELS_PER_LINE;
|
||||
drawText(horizontalOffset, verticalOffset, scale, rotation, font, nodeTypes.str().c_str(), color);
|
||||
|
||||
if (_metavoxelSendTotal > 0 || _metavoxelReceiveTotal > 0) {
|
||||
stringstream reliableStats;
|
||||
if (_metavoxelSendTotal > 0) {
|
||||
reliableStats << "Upload: " << (_metavoxelSendProgress * 100LL / _metavoxelSendTotal) << "% ";
|
||||
}
|
||||
if (_metavoxelReceiveTotal > 0) {
|
||||
reliableStats << "Download: " << (_metavoxelReceiveProgress * 100LL / _metavoxelReceiveTotal) << "%";
|
||||
}
|
||||
verticalOffset += STATS_PELS_PER_LINE;
|
||||
drawText(horizontalOffset, verticalOffset, scale, rotation, font, reliableStats.str().c_str(), color);
|
||||
}
|
||||
}
|
||||
|
||||
verticalOffset = 0;
|
||||
verticalOffset = STATS_PELS_INITIALOFFSET;
|
||||
horizontalOffset = _lastHorizontalOffset + _generalStatsWidth + _pingStatsWidth + _geoStatsWidth + 3;
|
||||
|
||||
lines = _expanded ? 14 : 3;
|
||||
lines = _expanded ? 10 : 2;
|
||||
|
||||
drawBackground(backgroundColor, horizontalOffset, 0, glCanvas->width() - horizontalOffset,
|
||||
lines * STATS_PELS_PER_LINE + 10);
|
||||
(lines + 1) * STATS_PELS_PER_LINE);
|
||||
horizontalOffset += 5;
|
||||
|
||||
// Model/Entity render details
|
||||
|
@ -491,7 +471,6 @@ void Stats::display(
|
|||
octreeStats << "Entity Items rendered: " << entities->getItemsRendered()
|
||||
<< " / Out of view:" << entities->getItemsOutOfView()
|
||||
<< " / Too small:" << entities->getItemsTooSmall();
|
||||
verticalOffset += STATS_PELS_PER_LINE;
|
||||
drawText(horizontalOffset, verticalOffset, scale, rotation, font, (char*)octreeStats.str().c_str(), color);
|
||||
|
||||
if (_expanded) {
|
||||
|
@ -638,12 +617,3 @@ void Stats::display(
|
|||
}
|
||||
}
|
||||
|
||||
void Stats::setMetavoxelStats(int internal, int leaves, int sendProgress,
|
||||
int sendTotal, int receiveProgress, int receiveTotal) {
|
||||
_metavoxelInternal = internal;
|
||||
_metavoxelLeaves = leaves;
|
||||
_metavoxelSendProgress = sendProgress;
|
||||
_metavoxelSendTotal = sendTotal;
|
||||
_metavoxelReceiveProgress = receiveProgress;
|
||||
_metavoxelReceiveTotal = receiveTotal;
|
||||
}
|
||||
|
|
|
@ -33,9 +33,6 @@ public:
|
|||
int inKbitsPerSecond, int outKbitsPerSecond, int voxelPacketsToProcess);
|
||||
bool includeTimingRecord(const QString& name);
|
||||
|
||||
Q_INVOKABLE void setMetavoxelStats(int internal, int leaves, int sendProgress,
|
||||
int sendTotal, int receiveProgress, int receiveTotal);
|
||||
|
||||
private:
|
||||
static Stats* _sharedInstance;
|
||||
|
||||
|
@ -52,12 +49,6 @@ private:
|
|||
|
||||
int _lastHorizontalOffset;
|
||||
|
||||
int _metavoxelInternal;
|
||||
int _metavoxelLeaves;
|
||||
int _metavoxelSendProgress;
|
||||
int _metavoxelSendTotal;
|
||||
int _metavoxelReceiveProgress;
|
||||
int _metavoxelReceiveTotal;
|
||||
};
|
||||
|
||||
#endif // hifi_Stats_h
|
||||
|
|
|
@ -11,7 +11,6 @@
|
|||
// include this before QGLWidget, which includes an earlier version of OpenGL
|
||||
#include "InterfaceConfig.h"
|
||||
|
||||
#include <QGLWidget>
|
||||
#include <SharedUtil.h>
|
||||
|
||||
#include "Application.h"
|
||||
|
|
|
@ -11,7 +11,6 @@
|
|||
// include this before QGLWidget, which includes an earlier version of OpenGL
|
||||
#include "InterfaceConfig.h"
|
||||
|
||||
#include <QGLWidget>
|
||||
#include <GeometryCache.h>
|
||||
#include <GlowEffect.h>
|
||||
#include <SharedUtil.h>
|
||||
|
|
|
@ -11,8 +11,6 @@
|
|||
// include this before QGLWidget, which includes an earlier version of OpenGL
|
||||
#include "InterfaceConfig.h"
|
||||
|
||||
#include <QGLWidget>
|
||||
|
||||
#include <DeferredLightingEffect.h>
|
||||
#include <GlowEffect.h>
|
||||
#include <SharedUtil.h>
|
||||
|
|
|
@ -17,8 +17,6 @@
|
|||
|
||||
#include <glm/glm.hpp>
|
||||
|
||||
#include <QGLWidget>
|
||||
|
||||
#include <ProgramObject.h>
|
||||
#include <SharedUtil.h>
|
||||
|
||||
|
|
|
@ -11,7 +11,6 @@
|
|||
// include this before QGLWidget, which includes an earlier version of OpenGL
|
||||
#include "InterfaceConfig.h"
|
||||
|
||||
#include <QGLWidget>
|
||||
#include <QPainter>
|
||||
#include <QSvgRenderer>
|
||||
|
||||
|
|
|
@ -14,7 +14,6 @@
|
|||
// include this before QGLWidget, which includes an earlier version of OpenGL
|
||||
#include "InterfaceConfig.h"
|
||||
|
||||
#include <QGLWidget>
|
||||
#include <QImage>
|
||||
#include <QNetworkReply>
|
||||
#include <QRect>
|
||||
|
|
|
@ -11,16 +11,12 @@
|
|||
// include this before QGLWidget, which includes an earlier version of OpenGL
|
||||
#include "InterfaceConfig.h"
|
||||
|
||||
#include <QSvgRenderer>
|
||||
#include <QPainter>
|
||||
#include <QGLWidget>
|
||||
#include <SharedUtil.h>
|
||||
|
||||
#include "Overlay.h"
|
||||
|
||||
|
||||
Overlay::Overlay() :
|
||||
_parent(NULL),
|
||||
_isLoaded(true),
|
||||
_alpha(DEFAULT_ALPHA),
|
||||
_glowLevel(0.0f),
|
||||
|
@ -40,7 +36,6 @@ Overlay::Overlay() :
|
|||
}
|
||||
|
||||
Overlay::Overlay(const Overlay* overlay) :
|
||||
_parent(NULL),
|
||||
_isLoaded(overlay->_isLoaded),
|
||||
_alpha(overlay->_alpha),
|
||||
_glowLevel(overlay->_glowLevel),
|
||||
|
@ -60,8 +55,7 @@ Overlay::Overlay(const Overlay* overlay) :
|
|||
{
|
||||
}
|
||||
|
||||
void Overlay::init(QGLWidget* parent, QScriptEngine* scriptEngine) {
|
||||
_parent = parent;
|
||||
void Overlay::init(QScriptEngine* scriptEngine) {
|
||||
_scriptEngine = scriptEngine;
|
||||
}
|
||||
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue