merge upstream/master into andrew/isentropic

Conflicts:
	libraries/networking/src/PacketHeaders.cpp
	libraries/networking/src/PacketHeaders.h
This commit is contained in:
Andrew Meadows 2015-03-05 08:22:02 -08:00
commit 49eee89c19
246 changed files with 3089 additions and 27921 deletions

View file

@ -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.

View file

@ -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.

View file

@ -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")

View file

@ -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
)

View file

@ -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();

View file

@ -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);

View file

@ -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

View 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();
}
}

View 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

View file

@ -0,0 +1,8 @@
#include "AssignmentClientChildData.h"
AssignmentClientChildData::AssignmentClientChildData(QString childType) :
_childType(childType)
{
}

View 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

View file

@ -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);
}
}
}
}

View file

@ -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

View file

@ -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:

View file

@ -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;
}

View file

@ -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.";
}

View file

@ -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

View file

@ -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 ()

View file

@ -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.")

View file

@ -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

View file

@ -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)

View file

@ -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")

View file

@ -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)

View file

@ -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 ()

View 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)

View file

@ -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();

View file

@ -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") {

View file

@ -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);

View 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);
*/

View file

@ -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);

View file

@ -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>

View file

@ -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>

View file

@ -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;
}

View file

@ -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;

View file

@ -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);

View file

@ -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")

View file

@ -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.

View file

@ -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();
}

View file

@ -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

View file

@ -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());
}

View file

@ -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:

View file

@ -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

View file

@ -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

View file

@ -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);

View file

@ -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

View file

@ -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

View file

@ -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;

View file

@ -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);
}

View file

@ -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

View file

@ -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);
}

View file

@ -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;
};

View file

@ -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);
}
}

View file

@ -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

View file

@ -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);

View file

@ -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);
}
}

View file

@ -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;

View file

@ -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);
}
}
}

View file

@ -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;

View file

@ -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

View file

@ -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";
}

View file

@ -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

View file

@ -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);
}
}

View file

@ -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

View file

@ -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());
}

View file

@ -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

View file

@ -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);

View file

@ -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), &timestamp);
// 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
}

View file

@ -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

View file

@ -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;

View file

@ -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;

View file

@ -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) &&

View file

@ -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;
};

View file

@ -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());
}

View file

@ -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)

View file

@ -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:

View file

@ -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() {

View file

@ -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;

View file

@ -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);

View file

@ -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];

View file

@ -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);
}

View file

@ -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);
}

View file

@ -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

View file

@ -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();
}

View file

@ -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

View file

@ -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

View file

@ -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));
}

View file

@ -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

View file

@ -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());

View file

@ -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();

View file

@ -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;
}

View file

@ -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

View file

@ -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"

View file

@ -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>

View file

@ -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>

View file

@ -17,8 +17,6 @@
#include <glm/glm.hpp>
#include <QGLWidget>
#include <ProgramObject.h>
#include <SharedUtil.h>

View file

@ -11,7 +11,6 @@
// include this before QGLWidget, which includes an earlier version of OpenGL
#include "InterfaceConfig.h"
#include <QGLWidget>
#include <QPainter>
#include <QSvgRenderer>

View file

@ -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>

View file

@ -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