mirror of
https://github.com/overte-org/overte.git
synced 2025-08-10 02:52:57 +02:00
Merge with upstream master
This commit is contained in:
commit
ea88cbd75f
47 changed files with 1361 additions and 511 deletions
|
@ -18,10 +18,9 @@
|
||||||
#include <AccountManager.h>
|
#include <AccountManager.h>
|
||||||
#include <AddressManager.h>
|
#include <AddressManager.h>
|
||||||
#include <Assignment.h>
|
#include <Assignment.h>
|
||||||
#include <AvatarHashMap.h>
|
|
||||||
#include <HifiConfigVariantMap.h>
|
|
||||||
#include <LogHandler.h>
|
#include <LogHandler.h>
|
||||||
#include <LogUtils.h>
|
#include <LogUtils.h>
|
||||||
|
#include <LimitedNodeList.h>
|
||||||
#include <NodeList.h>
|
#include <NodeList.h>
|
||||||
#include <PacketHeaders.h>
|
#include <PacketHeaders.h>
|
||||||
#include <SharedUtil.h>
|
#include <SharedUtil.h>
|
||||||
|
@ -40,79 +39,43 @@ SharedAssignmentPointer AssignmentClient::_currentAssignment;
|
||||||
|
|
||||||
int hifiSockAddrMeta = qRegisterMetaType<HifiSockAddr>("HifiSockAddr");
|
int hifiSockAddrMeta = qRegisterMetaType<HifiSockAddr>("HifiSockAddr");
|
||||||
|
|
||||||
AssignmentClient::AssignmentClient(int &argc, char **argv) :
|
AssignmentClient::AssignmentClient(Assignment::Type requestAssignmentType, QString assignmentPool, QUuid walletUUID,
|
||||||
QCoreApplication(argc, argv),
|
QString assignmentServerHostname, quint16 assignmentServerPort) :
|
||||||
_assignmentServerHostname(DEFAULT_ASSIGNMENT_SERVER_HOSTNAME),
|
_assignmentServerHostname(DEFAULT_ASSIGNMENT_SERVER_HOSTNAME),
|
||||||
_localASPortSharedMem(NULL)
|
_localASPortSharedMem(NULL),
|
||||||
|
_localACMPortSharedMem(NULL)
|
||||||
{
|
{
|
||||||
LogUtils::init();
|
LogUtils::init();
|
||||||
|
|
||||||
setOrganizationName("High Fidelity");
|
|
||||||
setOrganizationDomain("highfidelity.io");
|
|
||||||
setApplicationName("assignment-client");
|
|
||||||
QSettings::setDefaultFormat(QSettings::IniFormat);
|
QSettings::setDefaultFormat(QSettings::IniFormat);
|
||||||
|
|
||||||
// create a NodeList as an unassigned client
|
// create a NodeList as an unassigned client
|
||||||
DependencyManager::registerInheritance<LimitedNodeList, NodeList>();
|
DependencyManager::registerInheritance<LimitedNodeList, NodeList>();
|
||||||
auto addressManager = DependencyManager::set<AddressManager>();
|
auto addressManager = DependencyManager::set<AddressManager>();
|
||||||
auto nodeList = DependencyManager::set<NodeList>(NodeType::Unassigned);
|
auto nodeList = DependencyManager::set<NodeList>(NodeType::Unassigned);
|
||||||
auto avatarHashMap = DependencyManager::set<AvatarHashMap>();
|
|
||||||
|
// make up a uuid for this child so the parent can tell us apart. This id will be changed
|
||||||
// setup a shutdown event listener to handle SIGTERM or WM_CLOSE for us
|
// when the domain server hands over an assignment.
|
||||||
#ifdef _WIN32
|
QUuid nodeUUID = QUuid::createUuid();
|
||||||
installNativeEventFilter(&ShutdownEventListener::getInstance());
|
nodeList->setSessionUUID(nodeUUID);
|
||||||
#else
|
|
||||||
ShutdownEventListener::getInstance();
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// set the logging target to the the CHILD_TARGET_NAME
|
// set the logging target to the the CHILD_TARGET_NAME
|
||||||
LogHandler::getInstance().setTargetName(ASSIGNMENT_CLIENT_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
|
// setup our _requestAssignment member variable from the passed arguments
|
||||||
_requestAssignment = Assignment(Assignment::RequestCommand, requestAssignmentType, assignmentPool);
|
_requestAssignment = Assignment(Assignment::RequestCommand, requestAssignmentType, assignmentPool);
|
||||||
|
|
||||||
// check for a wallet UUID on the command line or in the config
|
// 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
|
// this would represent where the user running AC wants funds sent to
|
||||||
if (argumentVariantMap.contains(ASSIGNMENT_WALLET_DESTINATION_ID_OPTION)) {
|
if (!walletUUID.isNull()) {
|
||||||
QUuid walletUUID = argumentVariantMap.value(ASSIGNMENT_WALLET_DESTINATION_ID_OPTION).toString();
|
|
||||||
qDebug() << "The destination wallet UUID for credits is" << uuidStringWithoutCurlyBraces(walletUUID);
|
qDebug() << "The destination wallet UUID for credits is" << uuidStringWithoutCurlyBraces(walletUUID);
|
||||||
_requestAssignment.setWalletUUID(walletUUID);
|
_requestAssignment.setWalletUUID(walletUUID);
|
||||||
}
|
}
|
||||||
|
|
||||||
quint16 assignmentServerPort = DEFAULT_DOMAIN_SERVER_PORT;
|
|
||||||
|
|
||||||
// check for an overriden assignment server hostname
|
// check for an overriden assignment server hostname
|
||||||
if (argumentVariantMap.contains(CUSTOM_ASSIGNMENT_SERVER_HOSTNAME_OPTION)) {
|
if (assignmentServerHostname != "") {
|
||||||
// change the hostname for our assignment server
|
// change the hostname for our assignment server
|
||||||
_assignmentServerHostname = argumentVariantMap.value(CUSTOM_ASSIGNMENT_SERVER_HOSTNAME_OPTION).toString();
|
_assignmentServerHostname = assignmentServerHostname;
|
||||||
}
|
|
||||||
|
|
||||||
// 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();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
_assignmentServerSocket = HifiSockAddr(_assignmentServerHostname, assignmentServerPort, true);
|
_assignmentServerSocket = HifiSockAddr(_assignmentServerHostname, assignmentServerPort, true);
|
||||||
|
@ -123,9 +86,12 @@ AssignmentClient::AssignmentClient(int &argc, char **argv) :
|
||||||
// call a timer function every ASSIGNMENT_REQUEST_INTERVAL_MSECS to ask for assignment, if required
|
// call a timer function every ASSIGNMENT_REQUEST_INTERVAL_MSECS to ask for assignment, if required
|
||||||
qDebug() << "Waiting for assignment -" << _requestAssignment;
|
qDebug() << "Waiting for assignment -" << _requestAssignment;
|
||||||
|
|
||||||
QTimer* timer = new QTimer(this);
|
if (_assignmentServerHostname != "localhost") {
|
||||||
connect(timer, SIGNAL(timeout()), SLOT(sendAssignmentRequest()));
|
qDebug () << "- will attempt to connect to domain-server on" << _assignmentServerSocket.getPort();
|
||||||
timer->start(ASSIGNMENT_REQUEST_INTERVAL_MSECS);
|
}
|
||||||
|
|
||||||
|
connect(&_requestTimer, SIGNAL(timeout()), SLOT(sendAssignmentRequest()));
|
||||||
|
_requestTimer.start(ASSIGNMENT_REQUEST_INTERVAL_MSECS);
|
||||||
|
|
||||||
// connect our readPendingDatagrams method to the readyRead() signal of the socket
|
// connect our readPendingDatagrams method to the readyRead() signal of the socket
|
||||||
connect(&nodeList->getNodeSocket(), &QUdpSocket::readyRead, this, &AssignmentClient::readPendingDatagrams);
|
connect(&nodeList->getNodeSocket(), &QUdpSocket::readyRead, this, &AssignmentClient::readPendingDatagrams);
|
||||||
|
@ -136,6 +102,45 @@ AssignmentClient::AssignmentClient(int &argc, char **argv) :
|
||||||
|
|
||||||
// Create Singleton objects on main thread
|
// Create Singleton objects on main thread
|
||||||
NetworkAccessManager::getInstance();
|
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() {
|
void AssignmentClient::sendAssignmentRequest() {
|
||||||
|
@ -145,23 +150,9 @@ void AssignmentClient::sendAssignmentRequest() {
|
||||||
|
|
||||||
if (_assignmentServerHostname == "localhost") {
|
if (_assignmentServerHostname == "localhost") {
|
||||||
// we want to check again for the local domain-server port in case the DS has restarted
|
// we want to check again for the local domain-server port in case the DS has restarted
|
||||||
if (!_localASPortSharedMem) {
|
quint16 localAssignmentServerPort;
|
||||||
_localASPortSharedMem = new QSharedMemory(DOMAIN_SERVER_LOCAL_PORT_SMEM_KEY, this);
|
if (nodeList->getLocalServerPortFromSharedMemory(DOMAIN_SERVER_LOCAL_PORT_SMEM_KEY, _localASPortSharedMem,
|
||||||
|
localAssignmentServerPort)) {
|
||||||
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();
|
|
||||||
|
|
||||||
if (localAssignmentServerPort != _assignmentServerSocket.getPort()) {
|
if (localAssignmentServerPort != _assignmentServerSocket.getPort()) {
|
||||||
qDebug() << "Port for local assignment server read from shared memory is"
|
qDebug() << "Port for local assignment server read from shared memory is"
|
||||||
<< localAssignmentServerPort;
|
<< localAssignmentServerPort;
|
||||||
|
@ -170,7 +161,6 @@ void AssignmentClient::sendAssignmentRequest() {
|
||||||
nodeList->setAssignmentServerSocket(_assignmentServerSocket);
|
nodeList->setAssignmentServerSocket(_assignmentServerSocket);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
nodeList->sendAssignment(_requestAssignment);
|
nodeList->sendAssignment(_requestAssignment);
|
||||||
|
@ -227,6 +217,14 @@ void AssignmentClient::readPendingDatagrams() {
|
||||||
} else {
|
} else {
|
||||||
qDebug() << "Received an assignment that could not be unpacked. Re-requesting.";
|
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 {
|
} else {
|
||||||
// have the NodeList attempt to handle it
|
// have the NodeList attempt to handle it
|
||||||
nodeList->processNodeData(senderSockAddr, receivedPacket);
|
nodeList->processNodeData(senderSockAddr, receivedPacket);
|
||||||
|
|
|
@ -18,10 +18,12 @@
|
||||||
|
|
||||||
class QSharedMemory;
|
class QSharedMemory;
|
||||||
|
|
||||||
class AssignmentClient : public QCoreApplication {
|
class AssignmentClient : public QObject {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
AssignmentClient(int &argc, char **argv);
|
|
||||||
|
AssignmentClient(Assignment::Type requestAssignmentType, QString assignmentPool,
|
||||||
|
QUuid walletUUID, QString assignmentServerHostname, quint16 assignmentServerPort);
|
||||||
static const SharedAssignmentPointer& getCurrentAssignment() { return _currentAssignment; }
|
static const SharedAssignmentPointer& getCurrentAssignment() { return _currentAssignment; }
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
|
@ -29,13 +31,22 @@ private slots:
|
||||||
void readPendingDatagrams();
|
void readPendingDatagrams();
|
||||||
void assignmentCompleted();
|
void assignmentCompleted();
|
||||||
void handleAuthenticationRequest();
|
void handleAuthenticationRequest();
|
||||||
|
void sendStatsPacketToACM();
|
||||||
|
void stopAssignmentClient();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
void setUpStatsToMonitor();
|
||||||
Assignment _requestAssignment;
|
Assignment _requestAssignment;
|
||||||
static SharedAssignmentPointer _currentAssignment;
|
static SharedAssignmentPointer _currentAssignment;
|
||||||
QString _assignmentServerHostname;
|
QString _assignmentServerHostname;
|
||||||
HifiSockAddr _assignmentServerSocket;
|
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
|
#endif // hifi_AssignmentClient_h
|
||||||
|
|
185
assignment-client/src/AssignmentClientApp.cpp
Normal file
185
assignment-client/src/AssignmentClientApp.cpp
Normal file
|
@ -0,0 +1,185 @@
|
||||||
|
//
|
||||||
|
// AssignmentClientapp.cpp
|
||||||
|
// assignment-client/src
|
||||||
|
//
|
||||||
|
// Created by Seth Alves on 2/19/15.
|
||||||
|
// Copyright 2015 High Fidelity, Inc.
|
||||||
|
//
|
||||||
|
// Distributed under the Apache License, Version 2.0.
|
||||||
|
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||||
|
//
|
||||||
|
|
||||||
|
#include <QCommandLineParser>
|
||||||
|
|
||||||
|
#include <LogHandler.h>
|
||||||
|
#include <SharedUtil.h>
|
||||||
|
#include <HifiConfigVariantMap.h>
|
||||||
|
#include <ShutdownEventListener.h>
|
||||||
|
|
||||||
|
#include "Assignment.h"
|
||||||
|
#include "AssignmentClient.h"
|
||||||
|
#include "AssignmentClientMonitor.h"
|
||||||
|
#include "AssignmentClientApp.h"
|
||||||
|
|
||||||
|
|
||||||
|
AssignmentClientApp::AssignmentClientApp(int argc, char* argv[]) :
|
||||||
|
QCoreApplication(argc, argv)
|
||||||
|
{
|
||||||
|
# ifndef WIN32
|
||||||
|
setvbuf(stdout, NULL, _IOLBF, 0);
|
||||||
|
# endif
|
||||||
|
|
||||||
|
// setup a shutdown event listener to handle SIGTERM or WM_CLOSE for us
|
||||||
|
# ifdef _WIN32
|
||||||
|
installNativeEventFilter(&ShutdownEventListener::getInstance());
|
||||||
|
# else
|
||||||
|
ShutdownEventListener::getInstance();
|
||||||
|
# endif
|
||||||
|
|
||||||
|
setOrganizationName("High Fidelity");
|
||||||
|
setOrganizationDomain("highfidelity.io");
|
||||||
|
setApplicationName("assignment-client");
|
||||||
|
|
||||||
|
// use the verbose message handler in Logging
|
||||||
|
qInstallMessageHandler(LogHandler::verboseMessageHandler);
|
||||||
|
|
||||||
|
// parse command-line
|
||||||
|
QCommandLineParser parser;
|
||||||
|
parser.setApplicationDescription("High Fidelity Assignment Client");
|
||||||
|
parser.addHelpOption();
|
||||||
|
|
||||||
|
const QCommandLineOption helpOption = parser.addHelpOption();
|
||||||
|
|
||||||
|
const QCommandLineOption clientTypeOption(ASSIGNMENT_TYPE_OVERRIDE_OPTION,
|
||||||
|
"run single assignment client of given type", "type");
|
||||||
|
parser.addOption(clientTypeOption);
|
||||||
|
|
||||||
|
const QCommandLineOption poolOption(ASSIGNMENT_POOL_OPTION, "set assignment pool", "pool-name");
|
||||||
|
parser.addOption(poolOption);
|
||||||
|
|
||||||
|
const QCommandLineOption walletDestinationOption(ASSIGNMENT_WALLET_DESTINATION_ID_OPTION,
|
||||||
|
"set wallet destination", "wallet-uuid");
|
||||||
|
parser.addOption(walletDestinationOption);
|
||||||
|
|
||||||
|
const QCommandLineOption assignmentServerHostnameOption(CUSTOM_ASSIGNMENT_SERVER_HOSTNAME_OPTION,
|
||||||
|
"set assignment-server hostname", "hostname");
|
||||||
|
parser.addOption(assignmentServerHostnameOption);
|
||||||
|
|
||||||
|
const QCommandLineOption assignmentServerPortOption(CUSTOM_ASSIGNMENT_SERVER_PORT_OPTION,
|
||||||
|
"set assignment-server port", "port");
|
||||||
|
parser.addOption(assignmentServerPortOption);
|
||||||
|
|
||||||
|
const QCommandLineOption numChildsOption(ASSIGNMENT_NUM_FORKS_OPTION, "number of children to fork", "child-count");
|
||||||
|
parser.addOption(numChildsOption);
|
||||||
|
|
||||||
|
const QCommandLineOption minChildsOption(ASSIGNMENT_MIN_FORKS_OPTION, "minimum number of children", "child-count");
|
||||||
|
parser.addOption(minChildsOption);
|
||||||
|
|
||||||
|
const QCommandLineOption maxChildsOption(ASSIGNMENT_MAX_FORKS_OPTION, "maximum number of children", "child-count");
|
||||||
|
parser.addOption(maxChildsOption);
|
||||||
|
|
||||||
|
|
||||||
|
if (!parser.parse(QCoreApplication::arguments())) {
|
||||||
|
qCritical() << parser.errorText() << endl;
|
||||||
|
parser.showHelp();
|
||||||
|
Q_UNREACHABLE();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (parser.isSet(helpOption)) {
|
||||||
|
parser.showHelp();
|
||||||
|
Q_UNREACHABLE();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const QVariantMap argumentVariantMap = HifiConfigVariantMap::mergeCLParametersWithJSONConfig(arguments());
|
||||||
|
|
||||||
|
|
||||||
|
unsigned int numForks = 0;
|
||||||
|
if (parser.isSet(numChildsOption)) {
|
||||||
|
numForks = parser.value(numChildsOption).toInt();
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int minForks = 0;
|
||||||
|
if (parser.isSet(minChildsOption)) {
|
||||||
|
minForks = parser.value(minChildsOption).toInt();
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int maxForks = 0;
|
||||||
|
if (parser.isSet(maxChildsOption)) {
|
||||||
|
maxForks = parser.value(maxChildsOption).toInt();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!numForks && minForks) {
|
||||||
|
// if the user specified --min but not -n, set -n to --min
|
||||||
|
numForks = minForks;
|
||||||
|
}
|
||||||
|
|
||||||
|
Assignment::Type requestAssignmentType = Assignment::AllTypes;
|
||||||
|
if (argumentVariantMap.contains(ASSIGNMENT_TYPE_OVERRIDE_OPTION)) {
|
||||||
|
requestAssignmentType = (Assignment::Type) argumentVariantMap.value(ASSIGNMENT_TYPE_OVERRIDE_OPTION).toInt();
|
||||||
|
}
|
||||||
|
if (parser.isSet(clientTypeOption)) {
|
||||||
|
requestAssignmentType = (Assignment::Type) parser.value(clientTypeOption).toInt();
|
||||||
|
}
|
||||||
|
|
||||||
|
QString assignmentPool;
|
||||||
|
// check for an assignment pool passed on the command line or in the config
|
||||||
|
if (argumentVariantMap.contains(ASSIGNMENT_POOL_OPTION)) {
|
||||||
|
assignmentPool = argumentVariantMap.value(ASSIGNMENT_POOL_OPTION).toString();
|
||||||
|
}
|
||||||
|
if (parser.isSet(poolOption)) {
|
||||||
|
assignmentPool = parser.value(poolOption);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
QUuid walletUUID;
|
||||||
|
if (argumentVariantMap.contains(ASSIGNMENT_WALLET_DESTINATION_ID_OPTION)) {
|
||||||
|
walletUUID = argumentVariantMap.value(ASSIGNMENT_WALLET_DESTINATION_ID_OPTION).toString();
|
||||||
|
}
|
||||||
|
if (parser.isSet(walletDestinationOption)) {
|
||||||
|
walletUUID = parser.value(walletDestinationOption);
|
||||||
|
}
|
||||||
|
|
||||||
|
QString assignmentServerHostname;
|
||||||
|
if (argumentVariantMap.contains(ASSIGNMENT_WALLET_DESTINATION_ID_OPTION)) {
|
||||||
|
assignmentServerHostname = argumentVariantMap.value(CUSTOM_ASSIGNMENT_SERVER_HOSTNAME_OPTION).toString();
|
||||||
|
}
|
||||||
|
if (parser.isSet(assignmentServerHostnameOption)) {
|
||||||
|
assignmentServerHostname = parser.value(assignmentServerHostnameOption);
|
||||||
|
}
|
||||||
|
|
||||||
|
// check for an overriden assignment server port
|
||||||
|
quint16 assignmentServerPort = DEFAULT_DOMAIN_SERVER_PORT;
|
||||||
|
if (argumentVariantMap.contains(ASSIGNMENT_WALLET_DESTINATION_ID_OPTION)) {
|
||||||
|
assignmentServerPort = argumentVariantMap.value(CUSTOM_ASSIGNMENT_SERVER_PORT_OPTION).toString().toUInt();
|
||||||
|
}
|
||||||
|
if (parser.isSet(assignmentServerPortOption)) {
|
||||||
|
assignmentServerPort = parser.value(assignmentServerPortOption).toInt();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
if (parser.isSet(numChildsOption)) {
|
||||||
|
if (minForks && minForks > numForks) {
|
||||||
|
qCritical() << "--min can't be more than -n";
|
||||||
|
parser.showHelp();
|
||||||
|
Q_UNREACHABLE();
|
||||||
|
}
|
||||||
|
if (maxForks && maxForks < numForks) {
|
||||||
|
qCritical() << "--max can't be less than -n";
|
||||||
|
parser.showHelp();
|
||||||
|
Q_UNREACHABLE();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (numForks || minForks || maxForks) {
|
||||||
|
AssignmentClientMonitor monitor(numForks, minForks, maxForks, assignmentPool,
|
||||||
|
walletUUID, assignmentServerHostname, assignmentServerPort);
|
||||||
|
exec();
|
||||||
|
} else {
|
||||||
|
AssignmentClient client(requestAssignmentType, assignmentPool,
|
||||||
|
walletUUID, assignmentServerHostname, assignmentServerPort);
|
||||||
|
exec();
|
||||||
|
}
|
||||||
|
}
|
34
assignment-client/src/AssignmentClientApp.h
Normal file
34
assignment-client/src/AssignmentClientApp.h
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
//
|
||||||
|
// AssignmentClientapp.h
|
||||||
|
// assignment-client/src
|
||||||
|
//
|
||||||
|
// Created by Seth Alves on 2/19/15.
|
||||||
|
// Copyright 2015 High Fidelity, Inc.
|
||||||
|
//
|
||||||
|
// Distributed under the Apache License, Version 2.0.
|
||||||
|
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef hifi_AssignmentClientApp_h
|
||||||
|
#define hifi_AssignmentClientApp_h
|
||||||
|
|
||||||
|
|
||||||
|
#include <QApplication>
|
||||||
|
|
||||||
|
const QString ASSIGNMENT_TYPE_OVERRIDE_OPTION = "t";
|
||||||
|
const QString ASSIGNMENT_POOL_OPTION = "pool";
|
||||||
|
const QString ASSIGNMENT_WALLET_DESTINATION_ID_OPTION = "wallet";
|
||||||
|
const QString CUSTOM_ASSIGNMENT_SERVER_HOSTNAME_OPTION = "a";
|
||||||
|
const QString CUSTOM_ASSIGNMENT_SERVER_PORT_OPTION = "p";
|
||||||
|
const QString ASSIGNMENT_NUM_FORKS_OPTION = "n";
|
||||||
|
const QString ASSIGNMENT_MIN_FORKS_OPTION = "min";
|
||||||
|
const QString ASSIGNMENT_MAX_FORKS_OPTION = "max";
|
||||||
|
|
||||||
|
|
||||||
|
class AssignmentClientApp : public QCoreApplication {
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
AssignmentClientApp(int argc, char* argv[]);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // hifi_AssignmentClientApp_h
|
8
assignment-client/src/AssignmentClientChildData.cpp
Normal file
8
assignment-client/src/AssignmentClientChildData.cpp
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
|
||||||
|
#include "AssignmentClientChildData.h"
|
||||||
|
|
||||||
|
|
||||||
|
AssignmentClientChildData::AssignmentClientChildData(QString childType) :
|
||||||
|
_childType(childType)
|
||||||
|
{
|
||||||
|
}
|
32
assignment-client/src/AssignmentClientChildData.h
Normal file
32
assignment-client/src/AssignmentClientChildData.h
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
//
|
||||||
|
// AssignmentClientChildData.h
|
||||||
|
// assignment-client/src
|
||||||
|
//
|
||||||
|
// Created by Seth Alves on 2/23/2015.
|
||||||
|
// Copyright 2015 High Fidelity, Inc.
|
||||||
|
//
|
||||||
|
// Distributed under the Apache License, Version 2.0.
|
||||||
|
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef hifi_AssignmentClientChildData_h
|
||||||
|
#define hifi_AssignmentClientChildData_h
|
||||||
|
|
||||||
|
#include <Assignment.h>
|
||||||
|
|
||||||
|
|
||||||
|
class AssignmentClientChildData : public NodeData {
|
||||||
|
public:
|
||||||
|
AssignmentClientChildData(QString childType);
|
||||||
|
|
||||||
|
QString getChildType() { return _childType; }
|
||||||
|
void setChildType(QString childType) { _childType = childType; }
|
||||||
|
|
||||||
|
// implement parseData to return 0 so we can be a subclass of NodeData
|
||||||
|
int parseData(const QByteArray& packet) { return 0; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
QString _childType;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // hifi_AssignmentClientChildData_h
|
|
@ -12,40 +12,51 @@
|
||||||
#include <signal.h>
|
#include <signal.h>
|
||||||
|
|
||||||
#include <LogHandler.h>
|
#include <LogHandler.h>
|
||||||
#include <ShutdownEventListener.h>
|
#include <AddressManager.h>
|
||||||
|
|
||||||
#include "AssignmentClientMonitor.h"
|
#include "AssignmentClientMonitor.h"
|
||||||
|
#include "AssignmentClientApp.h"
|
||||||
|
#include "AssignmentClientChildData.h"
|
||||||
|
#include "PacketHeaders.h"
|
||||||
|
#include "SharedUtil.h"
|
||||||
|
|
||||||
const char* NUM_FORKS_PARAMETER = "-n";
|
const char* NUM_FORKS_PARAMETER = "-n";
|
||||||
|
|
||||||
const QString ASSIGNMENT_CLIENT_MONITOR_TARGET_NAME = "assignment-client-monitor";
|
const QString ASSIGNMENT_CLIENT_MONITOR_TARGET_NAME = "assignment-client-monitor";
|
||||||
|
|
||||||
AssignmentClientMonitor::AssignmentClientMonitor(int &argc, char **argv, int numAssignmentClientForks) :
|
AssignmentClientMonitor::AssignmentClientMonitor(const unsigned int numAssignmentClientForks,
|
||||||
QCoreApplication(argc, argv)
|
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
|
// start the Logging class with the parent's target name
|
||||||
LogHandler::getInstance().setTargetName(ASSIGNMENT_CLIENT_MONITOR_TARGET_NAME);
|
LogHandler::getInstance().setTargetName(ASSIGNMENT_CLIENT_MONITOR_TARGET_NAME);
|
||||||
|
|
||||||
// setup a shutdown event listener to handle SIGTERM or WM_CLOSE for us
|
// create a NodeList so we can receive stats from children
|
||||||
#ifdef _WIN32
|
DependencyManager::registerInheritance<LimitedNodeList, NodeList>();
|
||||||
installNativeEventFilter(&ShutdownEventListener::getInstance());
|
auto addressManager = DependencyManager::set<AddressManager>();
|
||||||
#else
|
auto nodeList = DependencyManager::set<LimitedNodeList>(DEFAULT_ASSIGNMENT_CLIENT_MONITOR_PORT);
|
||||||
ShutdownEventListener::getInstance();
|
|
||||||
#endif
|
connect(&nodeList->getNodeSocket(), &QUdpSocket::readyRead, this, &AssignmentClientMonitor::readPendingDatagrams);
|
||||||
|
|
||||||
_childArguments = arguments();
|
nodeList->putLocalPortIntoSharedMemory(ASSIGNMENT_CLIENT_MONITOR_LOCAL_PORT_SMEM_KEY, this);
|
||||||
|
|
||||||
// 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);
|
|
||||||
|
|
||||||
// use QProcess to fork off a process for each of the child assignment clients
|
// 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();
|
spawnChildClient();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
connect(&_checkSparesTimer, &QTimer::timeout, this, &AssignmentClientMonitor::checkSpares);
|
||||||
|
|
||||||
|
_checkSparesTimer.start(NODE_SILENCE_THRESHOLD_MSECS * 3);
|
||||||
}
|
}
|
||||||
|
|
||||||
AssignmentClientMonitor::~AssignmentClientMonitor() {
|
AssignmentClientMonitor::~AssignmentClientMonitor() {
|
||||||
|
@ -53,46 +64,145 @@ AssignmentClientMonitor::~AssignmentClientMonitor() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void AssignmentClientMonitor::stopChildProcesses() {
|
void AssignmentClientMonitor::stopChildProcesses() {
|
||||||
|
auto nodeList = DependencyManager::get<NodeList>();
|
||||||
QList<QPointer<QProcess> >::Iterator it = _childProcesses.begin();
|
|
||||||
while (it != _childProcesses.end()) {
|
nodeList->eachNode([&](const SharedNodePointer& node) {
|
||||||
if (!it->isNull()) {
|
qDebug() << "asking child" << node->getUUID() << "to exit.";
|
||||||
qDebug() << "Monitor is terminating child process" << it->data();
|
node->activateLocalSocket();
|
||||||
|
QByteArray diePacket = byteArrayWithPopulatedHeader(PacketTypeStopNode);
|
||||||
// don't re-spawn this child when it goes down
|
nodeList->writeUnverifiedDatagram(diePacket, *node->getActiveSocket());
|
||||||
disconnect(it->data(), 0, this, 0);
|
});
|
||||||
|
|
||||||
it->data()->terminate();
|
|
||||||
it->data()->waitForFinished();
|
|
||||||
}
|
|
||||||
|
|
||||||
it = _childProcesses.erase(it);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void AssignmentClientMonitor::spawnChildClient() {
|
void AssignmentClientMonitor::spawnChildClient() {
|
||||||
QProcess *assignmentClient = new QProcess(this);
|
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
|
// make sure that the output from the child process appears in our output
|
||||||
assignmentClient->setProcessChannelMode(QProcess::ForwardedChannels);
|
assignmentClient->setProcessChannelMode(QProcess::ForwardedChannels);
|
||||||
|
|
||||||
assignmentClient->start(applicationFilePath(), _childArguments);
|
assignmentClient->start(QCoreApplication::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)));
|
|
||||||
|
|
||||||
qDebug() << "Spawned a child client with PID" << assignmentClient->pid();
|
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");
|
|
||||||
|
void AssignmentClientMonitor::checkSpares() {
|
||||||
// remove the old process from our list of child processes
|
auto nodeList = DependencyManager::get<NodeList>();
|
||||||
qDebug() << "need to remove" << QPointer<QProcess>(qobject_cast<QProcess*>(sender()));
|
QUuid aSpareId = "";
|
||||||
_childProcesses.removeOne(QPointer<QProcess>(qobject_cast<QProcess*>(sender())));
|
unsigned int spareCount = 0;
|
||||||
|
unsigned int totalCount = 0;
|
||||||
spawnChildClient();
|
|
||||||
|
nodeList->removeSilentNodes();
|
||||||
|
|
||||||
|
nodeList->eachNode([&](const SharedNodePointer& node) {
|
||||||
|
AssignmentClientChildData *childData = static_cast<AssignmentClientChildData*>(node->getLinkedData());
|
||||||
|
totalCount ++;
|
||||||
|
if (childData->getChildType() == "none") {
|
||||||
|
spareCount ++;
|
||||||
|
aSpareId = node->getUUID();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Spawn or kill children, as needed. If --min or --max weren't specified, allow the child count
|
||||||
|
// to drift up or down as far as needed.
|
||||||
|
if (spareCount < 1 || totalCount < _minAssignmentClientForks) {
|
||||||
|
if (!_maxAssignmentClientForks || totalCount < _maxAssignmentClientForks) {
|
||||||
|
spawnChildClient();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (spareCount > 1) {
|
||||||
|
if (!_minAssignmentClientForks || totalCount > _minAssignmentClientForks) {
|
||||||
|
// kill aSpareId
|
||||||
|
qDebug() << "asking child" << aSpareId << "to exit.";
|
||||||
|
SharedNodePointer childNode = nodeList->nodeWithUUID(aSpareId);
|
||||||
|
childNode->activateLocalSocket();
|
||||||
|
QByteArray diePacket = byteArrayWithPopulatedHeader(PacketTypeStopNode);
|
||||||
|
nodeList->writeUnverifiedDatagram(diePacket, childNode);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void AssignmentClientMonitor::readPendingDatagrams() {
|
||||||
|
auto nodeList = DependencyManager::get<NodeList>();
|
||||||
|
|
||||||
|
QByteArray receivedPacket;
|
||||||
|
HifiSockAddr senderSockAddr;
|
||||||
|
|
||||||
|
while (nodeList->getNodeSocket().hasPendingDatagrams()) {
|
||||||
|
receivedPacket.resize(nodeList->getNodeSocket().pendingDatagramSize());
|
||||||
|
nodeList->getNodeSocket().readDatagram(receivedPacket.data(), receivedPacket.size(),
|
||||||
|
senderSockAddr.getAddressPointer(), senderSockAddr.getPortPointer());
|
||||||
|
|
||||||
|
if (nodeList->packetVersionAndHashMatch(receivedPacket)) {
|
||||||
|
if (packetTypeForPacket(receivedPacket) == PacketTypeNodeJsonStats) {
|
||||||
|
QUuid packetUUID = uuidFromPacketHeader(receivedPacket);
|
||||||
|
SharedNodePointer matchingNode = nodeList->sendingNodeForPacket(receivedPacket);
|
||||||
|
if (!matchingNode) {
|
||||||
|
// The parent only expects to be talking with prorams running on this same machine.
|
||||||
|
if (senderSockAddr.getAddress() == QHostAddress::LocalHost ||
|
||||||
|
senderSockAddr.getAddress() == QHostAddress::LocalHostIPv6) {
|
||||||
|
if (!packetUUID.isNull()) {
|
||||||
|
matchingNode = DependencyManager::get<LimitedNodeList>()->addOrUpdateNode
|
||||||
|
(packetUUID, NodeType::Unassigned, senderSockAddr, senderSockAddr, false);
|
||||||
|
AssignmentClientChildData *childData = new AssignmentClientChildData("unknown");
|
||||||
|
matchingNode->setLinkedData(childData);
|
||||||
|
} else {
|
||||||
|
// tell unknown assignment-client child to exit.
|
||||||
|
qDebug() << "asking unknown child to exit.";
|
||||||
|
QByteArray diePacket = byteArrayWithPopulatedHeader(PacketTypeStopNode);
|
||||||
|
nodeList->writeUnverifiedDatagram(diePacket, senderSockAddr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (matchingNode) {
|
||||||
|
// update our records about how to reach this child
|
||||||
|
matchingNode->setLocalSocket(senderSockAddr);
|
||||||
|
|
||||||
|
// push past the packet header
|
||||||
|
QDataStream packetStream(receivedPacket);
|
||||||
|
packetStream.skipRawData(numBytesForPacketHeader(receivedPacket));
|
||||||
|
// decode json
|
||||||
|
QVariantMap unpackedVariantMap;
|
||||||
|
packetStream >> unpackedVariantMap;
|
||||||
|
QJsonObject unpackedStatsJSON = QJsonObject::fromVariantMap(unpackedVariantMap);
|
||||||
|
|
||||||
|
// get child's assignment type out of the decoded json
|
||||||
|
QString childType = unpackedStatsJSON["assignment_type"].toString();
|
||||||
|
AssignmentClientChildData *childData =
|
||||||
|
static_cast<AssignmentClientChildData*>(matchingNode->getLinkedData());
|
||||||
|
childData->setChildType(childType);
|
||||||
|
// note when this child talked
|
||||||
|
matchingNode->setLastHeardMicrostamp(usecTimestampNow());
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// have the NodeList attempt to handle it
|
||||||
|
nodeList->processNodeData(senderSockAddr, receivedPacket);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -15,25 +15,40 @@
|
||||||
#include <QtCore/QCoreApplication>
|
#include <QtCore/QCoreApplication>
|
||||||
#include <QtCore/qpointer.h>
|
#include <QtCore/qpointer.h>
|
||||||
#include <QtCore/QProcess>
|
#include <QtCore/QProcess>
|
||||||
|
#include <QtCore/QDateTime>
|
||||||
|
|
||||||
#include <Assignment.h>
|
#include <Assignment.h>
|
||||||
|
|
||||||
|
#include "AssignmentClientChildData.h"
|
||||||
|
|
||||||
extern const char* NUM_FORKS_PARAMETER;
|
extern const char* NUM_FORKS_PARAMETER;
|
||||||
|
|
||||||
class AssignmentClientMonitor : public QCoreApplication {
|
|
||||||
|
class AssignmentClientMonitor : public QObject {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
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();
|
~AssignmentClientMonitor();
|
||||||
|
|
||||||
void stopChildProcesses();
|
void stopChildProcesses();
|
||||||
private slots:
|
private slots:
|
||||||
void childProcessFinished(int exitCode, QProcess::ExitStatus exitStatus);
|
void readPendingDatagrams();
|
||||||
|
void checkSpares();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void spawnChildClient();
|
void spawnChildClient();
|
||||||
QList<QPointer<QProcess> > _childProcesses;
|
QTimer _checkSparesTimer; // every few seconds see if it need fewer or more spare children
|
||||||
|
|
||||||
QStringList _childArguments;
|
const unsigned int _numAssignmentClientForks;
|
||||||
|
const unsigned int _minAssignmentClientForks;
|
||||||
|
const unsigned int _maxAssignmentClientForks;
|
||||||
|
|
||||||
|
QString _assignmentPool;
|
||||||
|
QUuid _walletUUID;
|
||||||
|
QString _assignmentServerHostname;
|
||||||
|
quint16 _assignmentServerPort;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // hifi_AssignmentClientMonitor_h
|
#endif // hifi_AssignmentClientMonitor_h
|
||||||
|
|
|
@ -9,34 +9,10 @@
|
||||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||||
//
|
//
|
||||||
|
|
||||||
#include <LogHandler.h>
|
|
||||||
#include <SharedUtil.h>
|
|
||||||
|
|
||||||
#include "Assignment.h"
|
#include "AssignmentClientApp.h"
|
||||||
#include "AssignmentClient.h"
|
|
||||||
#include "AssignmentClientMonitor.h"
|
|
||||||
|
|
||||||
int main(int argc, char* argv[]) {
|
int main(int argc, char* argv[]) {
|
||||||
#ifndef WIN32
|
AssignmentClientApp app(argc, argv);
|
||||||
setvbuf(stdout, NULL, _IOLBF, 0);
|
return 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();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -32,6 +32,7 @@
|
||||||
#include <SharedUtil.h>
|
#include <SharedUtil.h>
|
||||||
#include <ShutdownEventListener.h>
|
#include <ShutdownEventListener.h>
|
||||||
#include <UUID.h>
|
#include <UUID.h>
|
||||||
|
#include <LogHandler.h>
|
||||||
|
|
||||||
#include "DomainServerNodeData.h"
|
#include "DomainServerNodeData.h"
|
||||||
|
|
||||||
|
@ -246,19 +247,7 @@ void DomainServer::setupNodeListAndAssignments(const QUuid& sessionUUID) {
|
||||||
auto nodeList = DependencyManager::set<LimitedNodeList>(domainServerPort, domainServerDTLSPort);
|
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
|
// 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);
|
nodeList->putLocalPortIntoSharedMemory(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.";
|
|
||||||
}
|
|
||||||
|
|
||||||
// set our LimitedNodeList UUID to match the UUID from our config
|
// 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
|
// nodes will currently use this to add resources to data-web that relate to our domain
|
||||||
|
@ -955,8 +944,10 @@ void DomainServer::readAvailableDatagrams() {
|
||||||
|
|
||||||
if (requestAssignment.getType() != Assignment::AgentType
|
if (requestAssignment.getType() != Assignment::AgentType
|
||||||
|| noisyMessageTimer.elapsed() > NOISY_MESSAGE_INTERVAL_MSECS) {
|
|| noisyMessageTimer.elapsed() > NOISY_MESSAGE_INTERVAL_MSECS) {
|
||||||
|
static QString repeatedMessage = LogHandler::getInstance().addRepeatedMessageRegex
|
||||||
|
("Received a request for assignment type [^ ]+ from [^ ]+");
|
||||||
qDebug() << "Received a request for assignment type" << requestAssignment.getType()
|
qDebug() << "Received a request for assignment type" << requestAssignment.getType()
|
||||||
<< "from" << senderSockAddr;
|
<< "from" << senderSockAddr;
|
||||||
noisyMessageTimer.restart();
|
noisyMessageTimer.restart();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -986,6 +977,8 @@ void DomainServer::readAvailableDatagrams() {
|
||||||
} else {
|
} else {
|
||||||
if (requestAssignment.getType() != Assignment::AgentType
|
if (requestAssignment.getType() != Assignment::AgentType
|
||||||
|| noisyMessageTimer.elapsed() > NOISY_MESSAGE_INTERVAL_MSECS) {
|
|| noisyMessageTimer.elapsed() > NOISY_MESSAGE_INTERVAL_MSECS) {
|
||||||
|
static QString repeatedMessage = LogHandler::getInstance().addRepeatedMessageRegex
|
||||||
|
("Unable to fulfill assignment request of type [^ ]+ from [^ ]+");
|
||||||
qDebug() << "Unable to fulfill assignment request of type" << requestAssignment.getType()
|
qDebug() << "Unable to fulfill assignment request of type" << requestAssignment.getType()
|
||||||
<< "from" << senderSockAddr;
|
<< "from" << senderSockAddr;
|
||||||
noisyMessageTimer.restart();
|
noisyMessageTimer.restart();
|
||||||
|
|
|
@ -934,24 +934,37 @@ PropertiesTool = function(opts) {
|
||||||
data = {
|
data = {
|
||||||
type: 'update',
|
type: 'update',
|
||||||
};
|
};
|
||||||
if (selectionManager.hasSelection()) {
|
var selections = [];
|
||||||
data.id = selectionManager.selections[0].id;
|
for (var i = 0; i < selectionManager.selections.length; i++) {
|
||||||
data.properties = Entities.getEntityProperties(selectionManager.selections[0]);
|
var entity = {};
|
||||||
data.properties.rotation = Quat.safeEulerAngles(data.properties.rotation);
|
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.emitScriptEvent(JSON.stringify(data));
|
||||||
});
|
});
|
||||||
|
|
||||||
webView.eventBridge.webEventReceived.connect(function(data) {
|
webView.eventBridge.webEventReceived.connect(function(data) {
|
||||||
print(data);
|
|
||||||
data = JSON.parse(data);
|
data = JSON.parse(data);
|
||||||
if (data.type == "update") {
|
if (data.type == "update") {
|
||||||
selectionManager.saveProperties();
|
selectionManager.saveProperties();
|
||||||
if (data.properties.rotation !== undefined) {
|
if (selectionManager.selections.length > 1) {
|
||||||
var rotation = data.properties.rotation;
|
properties = {
|
||||||
data.properties.rotation = Quat.fromPitchYawRollDegrees(rotation.x, rotation.y, rotation.z);
|
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();
|
pushCommandForSelections();
|
||||||
selectionManager._update();
|
selectionManager._update();
|
||||||
} else if (data.type == "action") {
|
} else if (data.type == "action") {
|
||||||
|
|
34
examples/example/misc/sunLightExample.js
Normal file
34
examples/example/misc/sunLightExample.js
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
//
|
||||||
|
// SunLightExample.js
|
||||||
|
// examples
|
||||||
|
// Sam Gateau
|
||||||
|
// Copyright 2015 High Fidelity, Inc.
|
||||||
|
//
|
||||||
|
// Distributed under the Apache License, Version 2.0.
|
||||||
|
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||||
|
//
|
||||||
|
|
||||||
|
var intensity = 1.0;
|
||||||
|
var day = 0.0;
|
||||||
|
var hour = 12.0;
|
||||||
|
var longitude = 115.0;
|
||||||
|
var latitude = 31.0;
|
||||||
|
var stageOrientation = Quat.fromPitchYawRollDegrees(0.0, 180.0, 0.0);
|
||||||
|
|
||||||
|
Scene.setStageDayTime(hour);
|
||||||
|
Scene.setStageOrientation(stageOrientation);
|
||||||
|
Scene.setStageLocation(longitude, latitude, 0.0);
|
||||||
|
/*
|
||||||
|
function ticktack() {
|
||||||
|
hour += 0.1;
|
||||||
|
//Scene.setSunIntensity(Math.cos(time));
|
||||||
|
if (hour > 24.0) {
|
||||||
|
hour = 0.0;
|
||||||
|
day++;
|
||||||
|
Scene.setStageYearTime(day);
|
||||||
|
}
|
||||||
|
Scene.setStageDayTime(hour);
|
||||||
|
}
|
||||||
|
|
||||||
|
Script.setInterval(ticktack, 41);
|
||||||
|
*/
|
|
@ -20,6 +20,7 @@
|
||||||
elRefresh = document.getElementById("refresh");
|
elRefresh = document.getElementById("refresh");
|
||||||
elDelete = document.getElementById("delete");
|
elDelete = document.getElementById("delete");
|
||||||
elTeleport = document.getElementById("teleport");
|
elTeleport = document.getElementById("teleport");
|
||||||
|
elNoEntitiesMessage = document.getElementById("no-entities");
|
||||||
|
|
||||||
document.getElementById("entity-type").onclick = function() {
|
document.getElementById("entity-type").onclick = function() {
|
||||||
setSortColumn('type');
|
setSortColumn('type');
|
||||||
|
@ -155,11 +156,18 @@
|
||||||
}
|
}
|
||||||
} else if (data.type == "update") {
|
} else if (data.type == "update") {
|
||||||
var newEntities = data.entities;
|
var newEntities = data.entities;
|
||||||
for (var i = 0; i < newEntities.length; i++) {
|
if (newEntities.length == 0) {
|
||||||
var id = newEntities[i].id;
|
elEntityTable.style.display = "none";
|
||||||
addEntity(id, newEntities[i].type, newEntities[i].url);
|
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);
|
setTimeout(refreshEntities, 1000);
|
||||||
|
@ -194,6 +202,8 @@
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
|
<div id="no-entities">
|
||||||
|
No entities found within 50 meter radius. Try moving to a different location and refreshing.
|
||||||
|
</div>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
|
@ -132,17 +132,7 @@
|
||||||
var elLightDiffuseGreen = document.getElementById("property-light-diffuse-green");
|
var elLightDiffuseGreen = document.getElementById("property-light-diffuse-green");
|
||||||
var elLightDiffuseBlue = document.getElementById("property-light-diffuse-blue");
|
var elLightDiffuseBlue = document.getElementById("property-light-diffuse-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 elLightConstantAttenuation = document.getElementById("property-light-constant-attenuation");
|
||||||
var elLightLinearAttenuation = document.getElementById("property-light-linear-attenuation");
|
|
||||||
var elLightQuadraticAttenuation = document.getElementById("property-light-quadratic-attenuation");
|
|
||||||
var elLightExponent = document.getElementById("property-light-exponent");
|
var elLightExponent = document.getElementById("property-light-exponent");
|
||||||
var elLightCutoff = document.getElementById("property-light-cutoff");
|
var elLightCutoff = document.getElementById("property-light-cutoff");
|
||||||
|
|
||||||
|
@ -171,12 +161,37 @@
|
||||||
EventBridge.scriptEventReceived.connect(function(data) {
|
EventBridge.scriptEventReceived.connect(function(data) {
|
||||||
data = JSON.parse(data);
|
data = JSON.parse(data);
|
||||||
if (data.type == "update") {
|
if (data.type == "update") {
|
||||||
if (data.properties === undefined) {
|
if (data.selections.length == 0) {
|
||||||
disableChildren(document.getElementById("properties"), 'input');
|
elType.innerHTML = "<i>No Selection</i>";
|
||||||
} else {
|
elID.innerHTML = "";
|
||||||
var properties = data.properties;
|
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;
|
elType.innerHTML = properties.type;
|
||||||
|
|
||||||
|
@ -294,17 +309,7 @@
|
||||||
elLightDiffuseGreen.value = properties.diffuseColor.green;
|
elLightDiffuseGreen.value = properties.diffuseColor.green;
|
||||||
elLightDiffuseBlue.value = properties.diffuseColor.blue;
|
elLightDiffuseBlue.value = properties.diffuseColor.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;
|
elLightConstantAttenuation.value = properties.constantAttenuation;
|
||||||
elLightLinearAttenuation.value = properties.linearAttenuation;
|
|
||||||
elLightQuadraticAttenuation.value = properties.quadraticAttenuation;
|
|
||||||
elLightExponent.value = properties.exponent;
|
elLightExponent.value = properties.exponent;
|
||||||
elLightCutoff.value = properties.cutoff;
|
elLightCutoff.value = properties.cutoff;
|
||||||
}
|
}
|
||||||
|
@ -381,21 +386,7 @@
|
||||||
elLightDiffuseGreen.addEventListener('change', lightDiffuseChangeFunction);
|
elLightDiffuseGreen.addEventListener('change', lightDiffuseChangeFunction);
|
||||||
elLightDiffuseBlue.addEventListener('change', lightDiffuseChangeFunction);
|
elLightDiffuseBlue.addEventListener('change', lightDiffuseChangeFunction);
|
||||||
|
|
||||||
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'));
|
elLightConstantAttenuation.addEventListener('change', createEmitNumberPropertyUpdateFunction('constantAttenuation'));
|
||||||
elLightLinearAttenuation.addEventListener('change', createEmitNumberPropertyUpdateFunction('linearAttenuation'));
|
|
||||||
elLightQuadraticAttenuation.addEventListener('change', createEmitNumberPropertyUpdateFunction('quadraticAttenuation'));
|
|
||||||
elLightExponent.addEventListener('change', createEmitNumberPropertyUpdateFunction('exponent'));
|
elLightExponent.addEventListener('change', createEmitNumberPropertyUpdateFunction('exponent'));
|
||||||
elLightCutoff.addEventListener('change', createEmitNumberPropertyUpdateFunction('cutoff'));
|
elLightCutoff.addEventListener('change', createEmitNumberPropertyUpdateFunction('cutoff'));
|
||||||
|
|
||||||
|
@ -715,7 +706,7 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="light-section property">
|
<div class="light-section property">
|
||||||
<div class="label">Diffuse</div>
|
<div class="label">Color</div>
|
||||||
<div class="value">
|
<div class="value">
|
||||||
<div class="input-area">R <input class="coord" type='number' id="property-light-diffuse-red"></input></div>
|
<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">G <input class="coord" type='number' id="property-light-diffuse-green"></input></div>
|
||||||
|
@ -723,47 +714,19 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="light-section property">
|
<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>
|
|
||||||
</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">
|
<div class="value">
|
||||||
<input class="coord" type='number' id="property-light-constant-attenuation"></input>
|
<input class="coord" type='number' id="property-light-constant-attenuation"></input>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="light-section property">
|
<div class="light-section property">
|
||||||
<div class="label">Linear Attenuation</div>
|
<div class="label">Spot Light Exponent</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="value">
|
<div class="value">
|
||||||
<input class="coord" type='number' id="property-light-exponent"></input>
|
<input class="coord" type='number' id="property-light-exponent"></input>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="light-section property">
|
<div class="light-section property">
|
||||||
<div class="label">Cutoff (degrees)</div>
|
<div class="label">Spot Light Cutoff (degrees)</div>
|
||||||
<div class="value">
|
<div class="value">
|
||||||
<input class="coord" type='number' id="property-light-cutoff"></input>
|
<input class="coord" type='number' id="property-light-cutoff"></input>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -189,6 +189,11 @@ input, textarea {
|
||||||
font-size: 7.5pt;
|
font-size: 7.5pt;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
input:disabled, textarea:disabled {
|
||||||
|
background-color: rgb(102, 102, 102);
|
||||||
|
color: rgb(160, 160, 160);
|
||||||
|
}
|
||||||
|
|
||||||
#properties-list input[type=button] {
|
#properties-list input[type=button] {
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
background-color: rgb(51, 102, 102);
|
background-color: rgb(51, 102, 102);
|
||||||
|
@ -199,6 +204,11 @@ input, textarea {
|
||||||
color: rgb(204, 204, 204);
|
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 {
|
#properties-list .property {
|
||||||
padding: 6pt 6pt;
|
padding: 6pt 6pt;
|
||||||
border-top: 0.75pt solid rgb(63, 63, 63);
|
border-top: 0.75pt solid rgb(63, 63, 63);
|
||||||
|
@ -257,3 +267,11 @@ td {
|
||||||
|
|
||||||
vertical-align: top;
|
vertical-align: top;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#no-entities {
|
||||||
|
display: none;
|
||||||
|
font-size: 120%;
|
||||||
|
padding: 10pt;
|
||||||
|
font-weight: bold;
|
||||||
|
font-style: italic;
|
||||||
|
}
|
||||||
|
|
|
@ -82,6 +82,8 @@
|
||||||
#include <UserActivityLogger.h>
|
#include <UserActivityLogger.h>
|
||||||
#include <UUID.h>
|
#include <UUID.h>
|
||||||
|
|
||||||
|
#include <SceneScriptingInterface.h>
|
||||||
|
|
||||||
#include "Application.h"
|
#include "Application.h"
|
||||||
#include "AudioClient.h"
|
#include "AudioClient.h"
|
||||||
#include "InterfaceVersion.h"
|
#include "InterfaceVersion.h"
|
||||||
|
@ -1859,35 +1861,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() {
|
void Application::updateMyAvatarLookAtPosition() {
|
||||||
PerformanceTimer perfTimer("lookAt");
|
PerformanceTimer perfTimer("lookAt");
|
||||||
bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings);
|
bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings);
|
||||||
|
@ -2067,12 +2040,13 @@ void Application::update(float deltaTime) {
|
||||||
{
|
{
|
||||||
PerformanceTimer perfTimer("devices");
|
PerformanceTimer perfTimer("devices");
|
||||||
DeviceTracker::updateAll();
|
DeviceTracker::updateAll();
|
||||||
updateFaceshift();
|
FaceTracker* tracker = getActiveFaceTracker();
|
||||||
updateVisage();
|
if (tracker) {
|
||||||
|
tracker->update(deltaTime);
|
||||||
|
}
|
||||||
SixenseManager::getInstance().update(deltaTime);
|
SixenseManager::getInstance().update(deltaTime);
|
||||||
JoystickScriptingInterface::getInstance().update();
|
JoystickScriptingInterface::getInstance().update();
|
||||||
_prioVR.update(deltaTime);
|
_prioVR.update(deltaTime);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Dispatch input events
|
// Dispatch input events
|
||||||
|
@ -2491,7 +2465,8 @@ void Application::loadViewFrustum(Camera& camera, ViewFrustum& viewFrustum) {
|
||||||
|
|
||||||
glm::vec3 Application::getSunDirection() {
|
glm::vec3 Application::getSunDirection() {
|
||||||
// Sun direction is in fact just the location of the sun relative to the origin
|
// 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() {
|
void Application::updateShadowMap() {
|
||||||
|
@ -2501,7 +2476,7 @@ void Application::updateShadowMap() {
|
||||||
glEnable(GL_DEPTH_TEST);
|
glEnable(GL_DEPTH_TEST);
|
||||||
glClear(GL_DEPTH_BUFFER_BIT);
|
glClear(GL_DEPTH_BUFFER_BIT);
|
||||||
|
|
||||||
glm::vec3 lightDirection = -getSunDirection();
|
glm::vec3 lightDirection = getSunDirection();
|
||||||
glm::quat rotation = rotationBetween(IDENTITY_FRONT, lightDirection);
|
glm::quat rotation = rotationBetween(IDENTITY_FRONT, lightDirection);
|
||||||
glm::quat inverseRotation = glm::inverse(rotation);
|
glm::quat inverseRotation = glm::inverse(rotation);
|
||||||
|
|
||||||
|
@ -2874,7 +2849,9 @@ void Application::displaySide(Camera& theCamera, bool selfAvatarOnly, RenderArgs
|
||||||
|
|
||||||
{
|
{
|
||||||
DependencyManager::get<DeferredLightingEffect>()->setAmbientLightMode(getRenderAmbientLight());
|
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");
|
PROFILE_RANGE("DeferredLighting");
|
||||||
PerformanceTimer perfTimer("lighting");
|
PerformanceTimer perfTimer("lighting");
|
||||||
DependencyManager::get<DeferredLightingEffect>()->render();
|
DependencyManager::get<DeferredLightingEffect>()->render();
|
||||||
|
|
|
@ -421,9 +421,6 @@ private:
|
||||||
// Various helper functions called during update()
|
// Various helper functions called during update()
|
||||||
void updateLOD();
|
void updateLOD();
|
||||||
void updateMouseRay();
|
void updateMouseRay();
|
||||||
void updateFaceshift();
|
|
||||||
void updateVisage();
|
|
||||||
void updateDDE();
|
|
||||||
void updateMyAvatarLookAtPosition();
|
void updateMyAvatarLookAtPosition();
|
||||||
void updateThreads(float deltaTime);
|
void updateThreads(float deltaTime);
|
||||||
void updateMetavoxels(float deltaTime);
|
void updateMetavoxels(float deltaTime);
|
||||||
|
|
|
@ -380,8 +380,7 @@ void Avatar::render(const glm::vec3& cameraPosition, RenderMode renderMode, bool
|
||||||
foreach (const AvatarManager::LocalLight& light, DependencyManager::get<AvatarManager>()->getLocalLights()) {
|
foreach (const AvatarManager::LocalLight& light, DependencyManager::get<AvatarManager>()->getLocalLights()) {
|
||||||
glm::vec3 direction = orientation * light.direction;
|
glm::vec3 direction = orientation * light.direction;
|
||||||
DependencyManager::get<DeferredLightingEffect>()->addSpotLight(position - direction * distance,
|
DependencyManager::get<DeferredLightingEffect>()->addSpotLight(position - direction * distance,
|
||||||
distance * 2.0f, glm::vec3(), light.color, light.color, 1.0f, 0.5f, 0.0f, direction,
|
distance * 2.0f, light.color, 0.5f, orientation, LIGHT_EXPONENT, LIGHT_CUTOFF);
|
||||||
LIGHT_EXPONENT, LIGHT_CUTOFF);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -42,7 +42,6 @@ Head::Head(Avatar* owningAvatar) :
|
||||||
_mouth2(0.0f),
|
_mouth2(0.0f),
|
||||||
_mouth3(0.0f),
|
_mouth3(0.0f),
|
||||||
_mouth4(0.0f),
|
_mouth4(0.0f),
|
||||||
_angularVelocity(0,0,0),
|
|
||||||
_renderLookatVectors(false),
|
_renderLookatVectors(false),
|
||||||
_saccade(0.0f, 0.0f, 0.0f),
|
_saccade(0.0f, 0.0f, 0.0f),
|
||||||
_saccadeTarget(0.0f, 0.0f, 0.0f),
|
_saccadeTarget(0.0f, 0.0f, 0.0f),
|
||||||
|
|
|
@ -55,9 +55,6 @@ public:
|
||||||
|
|
||||||
/// \return orientationBody * orientationBasePitch
|
/// \return orientationBody * orientationBasePitch
|
||||||
glm::quat getCameraOrientation () const;
|
glm::quat getCameraOrientation () const;
|
||||||
|
|
||||||
const glm::vec3& getAngularVelocity() const { return _angularVelocity; }
|
|
||||||
void setAngularVelocity(glm::vec3 angularVelocity) { _angularVelocity = angularVelocity; }
|
|
||||||
|
|
||||||
void setCorrectedLookAtPosition(glm::vec3 correctedLookAtPosition);
|
void setCorrectedLookAtPosition(glm::vec3 correctedLookAtPosition);
|
||||||
glm::vec3 getCorrectedLookAtPosition();
|
glm::vec3 getCorrectedLookAtPosition();
|
||||||
|
@ -130,7 +127,6 @@ private:
|
||||||
float _mouth2;
|
float _mouth2;
|
||||||
float _mouth3;
|
float _mouth3;
|
||||||
float _mouth4;
|
float _mouth4;
|
||||||
glm::vec3 _angularVelocity;
|
|
||||||
bool _renderLookatVectors;
|
bool _renderLookatVectors;
|
||||||
glm::vec3 _saccade;
|
glm::vec3 _saccade;
|
||||||
glm::vec3 _saccadeTarget;
|
glm::vec3 _saccadeTarget;
|
||||||
|
|
|
@ -892,13 +892,7 @@ void MyAvatar::updateLookAtTargetAvatar() {
|
||||||
_lookAtTargetAvatar.clear();
|
_lookAtTargetAvatar.clear();
|
||||||
_targetAvatarPosition = glm::vec3(0.0f);
|
_targetAvatarPosition = glm::vec3(0.0f);
|
||||||
|
|
||||||
glm::quat faceRotation = Application::getInstance()->getViewFrustum()->getOrientation();
|
glm::vec3 lookForward = getHead()->getFinalOrientationInWorldFrame() * IDENTITY_FRONT;
|
||||||
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 cameraPosition = Application::getInstance()->getCamera()->getPosition();
|
glm::vec3 cameraPosition = Application::getInstance()->getCamera()->getPosition();
|
||||||
|
|
||||||
float smallestAngleTo = glm::radians(Application::getInstance()->getCamera()->getFieldOfView()) / 2.0f;
|
float smallestAngleTo = glm::radians(Application::getInstance()->getCamera()->getFieldOfView()) / 2.0f;
|
||||||
|
@ -1166,15 +1160,8 @@ void MyAvatar::updateOrientation(float deltaTime) {
|
||||||
pitch *= DEGREES_PER_RADIAN;
|
pitch *= DEGREES_PER_RADIAN;
|
||||||
roll *= 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
|
//Invert yaw and roll when in mirror mode
|
||||||
|
Head* head = getHead();
|
||||||
if (Application::getInstance()->getCamera()->getMode() == CAMERA_MODE_MIRROR) {
|
if (Application::getInstance()->getCamera()->getMode() == CAMERA_MODE_MIRROR) {
|
||||||
head->setBaseYaw(-yaw);
|
head->setBaseYaw(-yaw);
|
||||||
head->setBasePitch(pitch);
|
head->setBasePitch(pitch);
|
||||||
|
|
|
@ -50,6 +50,8 @@ DdeFaceTracker::DdeFaceTracker() :
|
||||||
}
|
}
|
||||||
|
|
||||||
DdeFaceTracker::DdeFaceTracker(const QHostAddress& host, quint16 port) :
|
DdeFaceTracker::DdeFaceTracker(const QHostAddress& host, quint16 port) :
|
||||||
|
_host(host),
|
||||||
|
_port(port),
|
||||||
_lastReceiveTimestamp(0),
|
_lastReceiveTimestamp(0),
|
||||||
_reset(false),
|
_reset(false),
|
||||||
_leftBlinkIndex(0), // see http://support.faceshift.com/support/articles/35129-export-of-blendshapes
|
_leftBlinkIndex(0), // see http://support.faceshift.com/support/articles/35129-export-of-blendshapes
|
||||||
|
@ -63,9 +65,7 @@ DdeFaceTracker::DdeFaceTracker(const QHostAddress& host, quint16 port) :
|
||||||
_browUpRightIndex(18),
|
_browUpRightIndex(18),
|
||||||
_mouthSmileLeftIndex(28),
|
_mouthSmileLeftIndex(28),
|
||||||
_mouthSmileRightIndex(29),
|
_mouthSmileRightIndex(29),
|
||||||
_jawOpenIndex(21),
|
_jawOpenIndex(21)
|
||||||
_host(host),
|
|
||||||
_port(port)
|
|
||||||
{
|
{
|
||||||
_blendshapeCoefficients.resize(NUM_EXPRESSION);
|
_blendshapeCoefficients.resize(NUM_EXPRESSION);
|
||||||
|
|
||||||
|
@ -80,18 +80,6 @@ DdeFaceTracker::~DdeFaceTracker() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void DdeFaceTracker::init() {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
void DdeFaceTracker::reset() {
|
|
||||||
_reset = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void DdeFaceTracker::update() {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
void DdeFaceTracker::setEnabled(bool enabled) {
|
void DdeFaceTracker::setEnabled(bool enabled) {
|
||||||
// isOpen() does not work as one might expect on QUdpSocket; don't test isOpen() before closing socket.
|
// isOpen() does not work as one might expect on QUdpSocket; don't test isOpen() before closing socket.
|
||||||
_udpSocket.close();
|
_udpSocket.close();
|
||||||
|
|
|
@ -23,12 +23,10 @@ class DdeFaceTracker : public FaceTracker, public Dependency {
|
||||||
SINGLETON_DEPENDENCY
|
SINGLETON_DEPENDENCY
|
||||||
|
|
||||||
public:
|
public:
|
||||||
//initialization
|
virtual void reset() { _reset = true; }
|
||||||
void init();
|
|
||||||
void reset();
|
virtual bool isActive() const;
|
||||||
void update();
|
virtual bool isTracking() const { return isActive(); }
|
||||||
|
|
||||||
bool isActive() const;
|
|
||||||
|
|
||||||
float getLeftBlink() const { return getBlendshapeCoefficient(_leftBlinkIndex); }
|
float getLeftBlink() const { return getBlendshapeCoefficient(_leftBlinkIndex); }
|
||||||
float getRightBlink() const { return getBlendshapeCoefficient(_rightBlinkIndex); }
|
float getRightBlink() const { return getBlendshapeCoefficient(_rightBlinkIndex); }
|
||||||
|
|
|
@ -11,7 +11,41 @@
|
||||||
|
|
||||||
#include "FaceTracker.h"
|
#include "FaceTracker.h"
|
||||||
|
|
||||||
FaceTracker::FaceTracker() :
|
inline float FaceTracker::getBlendshapeCoefficient(int index) const {
|
||||||
_estimatedEyePitch(0.0f),
|
return isValidBlendshapeIndex(index) ? _blendshapeCoefficients[index] : 0.0f;
|
||||||
_estimatedEyeYaw(0.0f) {
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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 glm::mix(glm::quat(), _headRotation, getFadeCoefficient());
|
||||||
|
}
|
||||||
|
|
||||||
|
void FaceTracker::update(float deltaTime) {
|
||||||
|
// Based on exponential distributions: http://en.wikipedia.org/wiki/Exponential_distribution
|
||||||
|
static const float EPSILON = 0.02f; // MUST BE < 1.0f
|
||||||
|
static const float INVERSE_AT_EPSILON = -std::log(EPSILON); // So that f(1.0f) = EPSILON ~ 0.0f
|
||||||
|
static const float RELAXATION_TIME = 0.8f; // sec
|
||||||
|
|
||||||
|
if (isTracking()) {
|
||||||
|
if (_relaxationStatus == 1.0f) {
|
||||||
|
_fadeCoefficient = 1.0f;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
_relaxationStatus = glm::clamp(_relaxationStatus + deltaTime / RELAXATION_TIME, 0.0f, 1.0f);
|
||||||
|
_fadeCoefficient = 1.0f - std::exp(-_relaxationStatus * INVERSE_AT_EPSILON);
|
||||||
|
} else {
|
||||||
|
if (_relaxationStatus == 0.0f) {
|
||||||
|
_fadeCoefficient = 0.0f;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
_relaxationStatus = glm::clamp(_relaxationStatus - deltaTime / RELAXATION_TIME, 0.0f, 1.0f);
|
||||||
|
_fadeCoefficient = std::exp(-(1.0f - _relaxationStatus) * INVERSE_AT_EPSILON);
|
||||||
|
}
|
||||||
|
}
|
|
@ -18,29 +18,40 @@
|
||||||
#include <glm/glm.hpp>
|
#include <glm/glm.hpp>
|
||||||
#include <glm/gtc/quaternion.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 {
|
class FaceTracker : public QObject {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
FaceTracker();
|
virtual bool isActive() const { return false; }
|
||||||
virtual ~FaceTracker() {}
|
virtual bool isTracking() const { return false; }
|
||||||
|
|
||||||
const glm::vec3& getHeadTranslation() const { return _headTranslation; }
|
virtual void init() {}
|
||||||
const glm::quat& getHeadRotation() const { return _headRotation; }
|
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 getEstimatedEyePitch() const { return _estimatedEyePitch; }
|
||||||
float getEstimatedEyeYaw() const { return _estimatedEyeYaw; }
|
float getEstimatedEyeYaw() const { return _estimatedEyeYaw; }
|
||||||
|
|
||||||
|
int getNumBlendshapes() const { return _blendshapeCoefficients.size(); }
|
||||||
|
bool isValidBlendshapeIndex(int index) const { return index >= 0 && index < getNumBlendshapes(); }
|
||||||
const QVector<float>& getBlendshapeCoefficients() const { return _blendshapeCoefficients; }
|
const QVector<float>& getBlendshapeCoefficients() const { return _blendshapeCoefficients; }
|
||||||
|
float getBlendshapeCoefficient(int index) const;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
glm::vec3 _headTranslation = glm::vec3(0.0f);
|
||||||
glm::vec3 _headTranslation;
|
glm::quat _headRotation = glm::quat();
|
||||||
glm::quat _headRotation;
|
float _estimatedEyePitch = 0.0f;
|
||||||
float _estimatedEyePitch;
|
float _estimatedEyeYaw = 0.0f;
|
||||||
float _estimatedEyeYaw;
|
|
||||||
QVector<float> _blendshapeCoefficients;
|
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
|
#endif // hifi_FaceTracker_h
|
||||||
|
|
|
@ -25,37 +25,11 @@ using namespace fs;
|
||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
|
||||||
|
const QString DEFAULT_FACESHIFT_HOSTNAME = "localhost";
|
||||||
const quint16 FACESHIFT_PORT = 33433;
|
const quint16 FACESHIFT_PORT = 33433;
|
||||||
float STARTING_FACESHIFT_FRAME_TIME = 0.033f;
|
const float DEFAULT_FACESHIFT_EYE_DEFLECTION = 0.25f;
|
||||||
|
|
||||||
Faceshift::Faceshift() :
|
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),
|
_eyeDeflection("faceshiftEyeDeflection", DEFAULT_FACESHIFT_EYE_DEFLECTION),
|
||||||
_hostname("faceshiftHostname", DEFAULT_FACESHIFT_HOSTNAME)
|
_hostname("faceshiftHostname", DEFAULT_FACESHIFT_HOSTNAME)
|
||||||
{
|
{
|
||||||
|
@ -71,31 +45,17 @@ Faceshift::Faceshift() :
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef HAVE_FACESHIFT
|
||||||
void Faceshift::init() {
|
void Faceshift::init() {
|
||||||
#ifdef HAVE_FACESHIFT
|
|
||||||
setTCPEnabled(Menu::getInstance()->isOptionChecked(MenuOption::Faceshift));
|
setTCPEnabled(Menu::getInstance()->isOptionChecked(MenuOption::Faceshift));
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Faceshift::isConnectedOrConnecting() const {
|
void Faceshift::update(float deltaTime) {
|
||||||
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() {
|
|
||||||
if (!isActive()) {
|
if (!isActive()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
PerformanceTimer perfTimer("faceshift");
|
FaceTracker::update(deltaTime);
|
||||||
|
|
||||||
// get the euler angles relative to the window
|
// get the euler angles relative to the window
|
||||||
glm::vec3 eulers = glm::degrees(safeEulerAngles(_headRotation * glm::quat(glm::radians(glm::vec3(
|
glm::vec3 eulers = glm::degrees(safeEulerAngles(_headRotation * glm::quat(glm::radians(glm::vec3(
|
||||||
(_eyeGazeLeftPitch + _eyeGazeRightPitch) / 2.0f, (_eyeGazeLeftYaw + _eyeGazeRightYaw) / 2.0f, 0.0f)))));
|
(_eyeGazeLeftPitch + _eyeGazeRightPitch) / 2.0f, (_eyeGazeLeftYaw + _eyeGazeRightYaw) / 2.0f, 0.0f)))));
|
||||||
|
@ -116,14 +76,28 @@ void Faceshift::update() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void Faceshift::reset() {
|
void Faceshift::reset() {
|
||||||
#ifdef HAVE_FACESHIFT
|
|
||||||
if (_tcpSocket.state() == QAbstractSocket::ConnectedState) {
|
if (_tcpSocket.state() == QAbstractSocket::ConnectedState) {
|
||||||
string message;
|
string message;
|
||||||
fsBinaryStream::encode_message(message, fsMsgCalibrateNeutral());
|
fsBinaryStream::encode_message(message, fsMsgCalibrateNeutral());
|
||||||
send(message);
|
send(message);
|
||||||
}
|
}
|
||||||
_longTermAverageInitialized = false;
|
_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
|
#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,
|
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) {
|
void Faceshift::setTCPEnabled(bool enabled) {
|
||||||
|
#ifdef HAVE_FACESHIFT
|
||||||
if ((_tcpEnabled = enabled)) {
|
if ((_tcpEnabled = enabled)) {
|
||||||
connectSocket();
|
connectSocket();
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
_tcpSocket.disconnectFromHost();
|
_tcpSocket.disconnectFromHost();
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void Faceshift::connectSocket() {
|
void Faceshift::connectSocket() {
|
||||||
|
@ -202,10 +177,6 @@ void Faceshift::readFromSocket() {
|
||||||
receive(_tcpSocket.readAll());
|
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) {
|
void Faceshift::send(const std::string& message) {
|
||||||
_tcpSocket.write(message.data(), message.size());
|
_tcpSocket.write(message.data(), message.size());
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,8 +24,7 @@
|
||||||
|
|
||||||
#include "FaceTracker.h"
|
#include "FaceTracker.h"
|
||||||
|
|
||||||
const float DEFAULT_FACESHIFT_EYE_DEFLECTION = 0.25f;
|
const float STARTING_FACESHIFT_FRAME_TIME = 0.033f;
|
||||||
const QString DEFAULT_FACESHIFT_HOSTNAME = "localhost";
|
|
||||||
|
|
||||||
/// Handles interaction with the Faceshift software, which provides head position/orientation and facial features.
|
/// Handles interaction with the Faceshift software, which provides head position/orientation and facial features.
|
||||||
class Faceshift : public FaceTracker, public Dependency {
|
class Faceshift : public FaceTracker, public Dependency {
|
||||||
|
@ -33,11 +32,17 @@ class Faceshift : public FaceTracker, public Dependency {
|
||||||
SINGLETON_DEPENDENCY
|
SINGLETON_DEPENDENCY
|
||||||
|
|
||||||
public:
|
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; }
|
const glm::vec3& getHeadAngularVelocity() const { return _headAngularVelocity; }
|
||||||
|
|
||||||
|
@ -68,9 +73,6 @@ public:
|
||||||
|
|
||||||
QString getHostname() { return _hostname.get(); }
|
QString getHostname() { return _hostname.get(); }
|
||||||
void setHostname(const QString& hostname);
|
void setHostname(const QString& hostname);
|
||||||
|
|
||||||
void update();
|
|
||||||
void reset();
|
|
||||||
|
|
||||||
void updateFakeCoefficients(float leftBlink,
|
void updateFakeCoefficients(float leftBlink,
|
||||||
float rightBlink,
|
float rightBlink,
|
||||||
|
@ -82,15 +84,12 @@ public:
|
||||||
QVector<float>& coefficients) const;
|
QVector<float>& coefficients) const;
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
|
|
||||||
void connectionStateChanged();
|
void connectionStateChanged();
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
|
|
||||||
void setTCPEnabled(bool enabled);
|
void setTCPEnabled(bool enabled);
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
|
|
||||||
void connectSocket();
|
void connectSocket();
|
||||||
void noteConnected();
|
void noteConnected();
|
||||||
void noteError(QAbstractSocket::SocketError error);
|
void noteError(QAbstractSocket::SocketError error);
|
||||||
|
@ -101,8 +100,6 @@ private:
|
||||||
Faceshift();
|
Faceshift();
|
||||||
virtual ~Faceshift() {}
|
virtual ~Faceshift() {}
|
||||||
|
|
||||||
float getBlendshapeCoefficient(int index) const;
|
|
||||||
|
|
||||||
void send(const std::string& message);
|
void send(const std::string& message);
|
||||||
void receive(const QByteArray& buffer);
|
void receive(const QByteArray& buffer);
|
||||||
|
|
||||||
|
@ -113,48 +110,48 @@ private:
|
||||||
fs::fsBinaryStream _stream;
|
fs::fsBinaryStream _stream;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
bool _tcpEnabled;
|
bool _tcpEnabled = true;
|
||||||
int _tcpRetryCount;
|
int _tcpRetryCount = 0;
|
||||||
bool _tracking;
|
bool _tracking = false;
|
||||||
quint64 _lastTrackingStateReceived;
|
quint64 _lastTrackingStateReceived = 0;
|
||||||
float _averageFrameTime;
|
float _averageFrameTime = STARTING_FACESHIFT_FRAME_TIME;
|
||||||
|
|
||||||
glm::vec3 _headAngularVelocity;
|
glm::vec3 _headAngularVelocity = glm::vec3(0.0f);
|
||||||
glm::vec3 _headLinearVelocity;
|
glm::vec3 _headLinearVelocity = glm::vec3(0.0f);
|
||||||
glm::vec3 _lastHeadTranslation;
|
glm::vec3 _lastHeadTranslation = glm::vec3(0.0f);
|
||||||
glm::vec3 _filteredHeadTranslation;
|
glm::vec3 _filteredHeadTranslation = glm::vec3(0.0f);
|
||||||
|
|
||||||
// degrees
|
// degrees
|
||||||
float _eyeGazeLeftPitch;
|
float _eyeGazeLeftPitch = 0.0f;
|
||||||
float _eyeGazeLeftYaw;
|
float _eyeGazeLeftYaw = 0.0f;
|
||||||
float _eyeGazeRightPitch;
|
float _eyeGazeRightPitch = 0.0f;
|
||||||
float _eyeGazeRightYaw;
|
float _eyeGazeRightYaw = 0.0f;
|
||||||
|
|
||||||
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;
|
|
||||||
|
|
||||||
// degrees
|
// degrees
|
||||||
float _longTermAverageEyePitch;
|
float _longTermAverageEyePitch = 0.0f;
|
||||||
float _longTermAverageEyeYaw;
|
float _longTermAverageEyeYaw = 0.0f;
|
||||||
bool _longTermAverageInitialized;
|
bool _longTermAverageInitialized = false;
|
||||||
|
|
||||||
Setting::Handle<float> _eyeDeflection;
|
Setting::Handle<float> _eyeDeflection;
|
||||||
Setting::Handle<QString> _hostname;
|
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
|
#endif // hifi_Faceshift_h
|
||||||
|
|
|
@ -41,7 +41,6 @@ const glm::vec3 DEFAULT_HEAD_ORIGIN(0.0f, 0.0f, 0.7f);
|
||||||
|
|
||||||
Visage::Visage() :
|
Visage::Visage() :
|
||||||
_enabled(false),
|
_enabled(false),
|
||||||
_active(false),
|
|
||||||
_headOrigin(DEFAULT_HEAD_ORIGIN) {
|
_headOrigin(DEFAULT_HEAD_ORIGIN) {
|
||||||
|
|
||||||
#ifdef HAVE_VISAGE
|
#ifdef HAVE_VISAGE
|
||||||
|
@ -119,20 +118,20 @@ static const QMultiHash<QByteArray, QPair<int, float> >& getActionUnitNameMap()
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
const float TRANSLATION_SCALE = 20.0f;
|
|
||||||
|
|
||||||
|
#ifdef HAVE_VISAGE
|
||||||
|
const float TRANSLATION_SCALE = 20.0f;
|
||||||
void Visage::init() {
|
void Visage::init() {
|
||||||
connect(DependencyManager::get<Faceshift>().data(), SIGNAL(connectionStateChanged()), SLOT(updateEnabled()));
|
connect(DependencyManager::get<Faceshift>().data(), SIGNAL(connectionStateChanged()), SLOT(updateEnabled()));
|
||||||
updateEnabled();
|
updateEnabled();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Visage::update() {
|
void Visage::update(float deltaTime) {
|
||||||
#ifdef HAVE_VISAGE
|
if (!isActive()) {
|
||||||
_active = (_tracker->getTrackingData(_data) == TRACK_STAT_OK);
|
|
||||||
if (!_active) {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
PerformanceTimer perfTimer("visage");
|
FaceTracker::update(deltaTime);
|
||||||
|
|
||||||
_headRotation = glm::quat(glm::vec3(-_data->faceRotation[0], -_data->faceRotation[1], _data->faceRotation[2]));
|
_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]) -
|
_headTranslation = (glm::vec3(_data->faceTranslation[0], _data->faceTranslation[1], _data->faceTranslation[2]) -
|
||||||
_headOrigin) * TRANSLATION_SCALE;
|
_headOrigin) * TRANSLATION_SCALE;
|
||||||
|
@ -164,12 +163,12 @@ void Visage::update() {
|
||||||
}
|
}
|
||||||
_blendshapeCoefficients[leftEyeBlinkIndex] = 1.0f - _data->eyeClosure[1];
|
_blendshapeCoefficients[leftEyeBlinkIndex] = 1.0f - _data->eyeClosure[1];
|
||||||
_blendshapeCoefficients[rightEyeBlinkIndex] = 1.0f - _data->eyeClosure[0];
|
_blendshapeCoefficients[rightEyeBlinkIndex] = 1.0f - _data->eyeClosure[0];
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Visage::reset() {
|
void Visage::reset() {
|
||||||
_headOrigin += _headTranslation / TRANSLATION_SCALE;
|
_headOrigin += _headTranslation / TRANSLATION_SCALE;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
void Visage::updateEnabled() {
|
void Visage::updateEnabled() {
|
||||||
setEnabled(Menu::getInstance()->isOptionChecked(MenuOption::Visage) &&
|
setEnabled(Menu::getInstance()->isOptionChecked(MenuOption::Visage) &&
|
||||||
|
|
|
@ -31,15 +31,16 @@ class Visage : public FaceTracker, public Dependency {
|
||||||
SINGLETON_DEPENDENCY
|
SINGLETON_DEPENDENCY
|
||||||
|
|
||||||
public:
|
public:
|
||||||
void init();
|
#ifdef HAVE_VISAGE
|
||||||
|
virtual void init();
|
||||||
|
virtual void update(float deltaTime);
|
||||||
|
virtual void reset();
|
||||||
|
|
||||||
bool isActive() const { return _active; }
|
virtual bool isActive() const { return _tracker->getTrackingData(_data) == TRACK_STAT_OK; }
|
||||||
|
virtual bool isTracking() const { return isActive(); }
|
||||||
void update();
|
#endif
|
||||||
void reset();
|
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
|
|
||||||
void updateEnabled();
|
void updateEnabled();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -55,7 +56,6 @@ private:
|
||||||
void setEnabled(bool enabled);
|
void setEnabled(bool enabled);
|
||||||
|
|
||||||
bool _enabled;
|
bool _enabled;
|
||||||
bool _active;
|
|
||||||
|
|
||||||
glm::vec3 _headOrigin;
|
glm::vec3 _headOrigin;
|
||||||
};
|
};
|
||||||
|
|
|
@ -36,31 +36,18 @@ void RenderableLightEntityItem::render(RenderArgs* args) {
|
||||||
float diffuseG = getDiffuseColor()[GREEN_INDEX] / MAX_COLOR;
|
float diffuseG = getDiffuseColor()[GREEN_INDEX] / MAX_COLOR;
|
||||||
float diffuseB = getDiffuseColor()[BLUE_INDEX] / MAX_COLOR;
|
float diffuseB = getDiffuseColor()[BLUE_INDEX] / MAX_COLOR;
|
||||||
|
|
||||||
float ambientR = getAmbientColor()[RED_INDEX] / MAX_COLOR;
|
glm::vec3 color = glm::vec3(diffuseR, diffuseG, diffuseB);
|
||||||
float ambientG = getAmbientColor()[GREEN_INDEX] / MAX_COLOR;
|
|
||||||
float ambientB = getAmbientColor()[BLUE_INDEX] / MAX_COLOR;
|
|
||||||
|
|
||||||
float specularR = getSpecularColor()[RED_INDEX] / MAX_COLOR;
|
float intensity = getConstantAttenuation();
|
||||||
float specularG = getSpecularColor()[GREEN_INDEX] / MAX_COLOR;
|
|
||||||
float specularB = getSpecularColor()[BLUE_INDEX] / MAX_COLOR;
|
|
||||||
|
|
||||||
glm::vec3 ambient = glm::vec3(ambientR, ambientG, ambientB);
|
|
||||||
glm::vec3 diffuse = glm::vec3(diffuseR, diffuseG, diffuseB);
|
|
||||||
glm::vec3 specular = glm::vec3(specularR, specularG, specularB);
|
|
||||||
glm::vec3 direction = IDENTITY_FRONT * rotation;
|
|
||||||
float constantAttenuation = getConstantAttenuation();
|
|
||||||
float linearAttenuation = getLinearAttenuation();
|
|
||||||
float quadraticAttenuation = getQuadraticAttenuation();
|
|
||||||
float exponent = getExponent();
|
float exponent = getExponent();
|
||||||
float cutoff = glm::radians(getCutoff());
|
float cutoff = glm::radians(getCutoff());
|
||||||
|
|
||||||
if (_isSpotlight) {
|
if (_isSpotlight) {
|
||||||
DependencyManager::get<DeferredLightingEffect>()->addSpotLight(position, largestDiameter / 2.0f,
|
DependencyManager::get<DeferredLightingEffect>()->addSpotLight(position, largestDiameter / 2.0f,
|
||||||
ambient, diffuse, specular, constantAttenuation, linearAttenuation, quadraticAttenuation,
|
color, intensity, rotation, exponent, cutoff);
|
||||||
direction, exponent, cutoff);
|
|
||||||
} else {
|
} else {
|
||||||
DependencyManager::get<DeferredLightingEffect>()->addPointLight(position, largestDiameter / 2.0f,
|
DependencyManager::get<DeferredLightingEffect>()->addPointLight(position, largestDiameter / 2.0f,
|
||||||
ambient, diffuse, specular, constantAttenuation, linearAttenuation, quadraticAttenuation);
|
color, intensity);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef WANT_DEBUG
|
#ifdef WANT_DEBUG
|
||||||
|
|
|
@ -47,7 +47,7 @@ public:
|
||||||
static void syncGPUObject(const Buffer& buffer);
|
static void syncGPUObject(const Buffer& buffer);
|
||||||
static GLuint getBufferID(const Buffer& buffer);
|
static GLuint getBufferID(const Buffer& buffer);
|
||||||
|
|
||||||
class GLTexture {
|
class GLTexture : public GPUObject {
|
||||||
public:
|
public:
|
||||||
Stamp _storageStamp;
|
Stamp _storageStamp;
|
||||||
Stamp _contentStamp;
|
Stamp _contentStamp;
|
||||||
|
|
209
libraries/model/src/model/Stage.cpp
Normal file
209
libraries/model/src/model/Stage.cpp
Normal file
|
@ -0,0 +1,209 @@
|
||||||
|
//
|
||||||
|
// Stage.cpp
|
||||||
|
// libraries/model/src/model
|
||||||
|
//
|
||||||
|
// Created by Sam Gateau on 2/24/2015.
|
||||||
|
// 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 "Stage.h"
|
||||||
|
|
||||||
|
#include <glm/gtx/transform.hpp>
|
||||||
|
#include <math.h>
|
||||||
|
|
||||||
|
using namespace model;
|
||||||
|
|
||||||
|
|
||||||
|
void EarthSunModel::updateAll() const {
|
||||||
|
updateWorldToSurface();
|
||||||
|
updateSurfaceToEye();
|
||||||
|
updateSun();
|
||||||
|
}
|
||||||
|
|
||||||
|
Mat4d EarthSunModel::evalWorldToGeoLocationMat(double longitude, double latitude, double absAltitude, double scale) {
|
||||||
|
// Longitude is along Z axis but - from east to west
|
||||||
|
Mat4d rotLon = glm::rotate(glm::radians(longitude), Vec3d(0.0, 0.0, 1.0));
|
||||||
|
|
||||||
|
// latitude is along X axis + from south to north
|
||||||
|
Mat4d rotLat = glm::rotate(-glm::radians(latitude), Vec3d(1.0, 0.0, 0.0));
|
||||||
|
|
||||||
|
// translation is movin to the earth surface + altiture at the radius along Y axis
|
||||||
|
Mat4d surfaceT = glm::translate(Vec3d(0.0, -absAltitude, 0.0));
|
||||||
|
|
||||||
|
// Mat4d worldScale = glm::scale(Vec3d(scale));
|
||||||
|
|
||||||
|
Mat4d worldToGeoLocMat = surfaceT * rotLat * rotLon;
|
||||||
|
|
||||||
|
return worldToGeoLocMat;
|
||||||
|
}
|
||||||
|
|
||||||
|
void EarthSunModel::updateWorldToSurface() const {
|
||||||
|
// Check if the final position is too close to the earth center ?
|
||||||
|
double absAltitude = _earthRadius + _altitude;
|
||||||
|
if ( absAltitude < 0.01) {
|
||||||
|
absAltitude = 0.01;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Final world to local Frame
|
||||||
|
_worldToSurfaceMat = evalWorldToGeoLocationMat(_longitude, _latitude, absAltitude, _scale);
|
||||||
|
// and the inverse
|
||||||
|
_surfaceToWorldMat = glm::inverse(_worldToSurfaceMat);
|
||||||
|
|
||||||
|
_surfacePos = Vec3d(_surfaceToWorldMat * Vec4d(0.0, 0.0, 0.0, 1.0));
|
||||||
|
}
|
||||||
|
|
||||||
|
void EarthSunModel::updateSurfaceToEye() const {
|
||||||
|
_surfaceToEyeMat = glm::inverse(_eyeToSurfaceMat);
|
||||||
|
_worldToEyeMat = _surfaceToEyeMat * _worldToSurfaceMat;
|
||||||
|
_eyeToWorldMat = _surfaceToWorldMat * _eyeToSurfaceMat;
|
||||||
|
_eyePos = Vec3d(_eyeToWorldMat * Vec4d(0.0, 0.0, 0.0, 1.0) );
|
||||||
|
_eyeDir = Vec3d(_eyeToWorldMat * Vec4d(0.0, 0.0, -1.0, 0.0) );
|
||||||
|
}
|
||||||
|
|
||||||
|
void EarthSunModel::updateSun() const {
|
||||||
|
// Longitude is along Y axis but - from east to west
|
||||||
|
Mat4d rotSunLon;
|
||||||
|
|
||||||
|
Mat4d rotSun = evalWorldToGeoLocationMat(_sunLongitude, _sunLatitude, _earthRadius, _scale);
|
||||||
|
rotSun = glm::inverse(rotSun);
|
||||||
|
|
||||||
|
_sunDir = Vec3d(rotSun * Vec4d(0.0, 1.0, 0.0, 0.0));
|
||||||
|
|
||||||
|
// sun direction is looking up toward Y axis at the specified sun lat, long
|
||||||
|
Vec3d lssd = Vec3d(_worldToSurfaceMat * Vec4d(_sunDir.x, _sunDir.y, _sunDir.z, 0.0));
|
||||||
|
|
||||||
|
// apply surface rotation offset
|
||||||
|
glm::dquat dSurfOrient(_surfaceOrientation);
|
||||||
|
lssd = glm::rotate(dSurfOrient, lssd);
|
||||||
|
|
||||||
|
_surfaceSunDir = glm::normalize(Vec3(lssd.x, lssd.y, lssd.z));
|
||||||
|
}
|
||||||
|
|
||||||
|
void EarthSunModel::setSurfaceOrientation(const Quat& orientation) {
|
||||||
|
_surfaceOrientation = orientation;
|
||||||
|
invalidate();
|
||||||
|
}
|
||||||
|
|
||||||
|
double moduloRange(double val, double minVal, double maxVal) {
|
||||||
|
double range = maxVal - minVal;
|
||||||
|
double rval = (val - minVal) / range;
|
||||||
|
double intval;
|
||||||
|
return modf(rval, &intval) * range + minVal;
|
||||||
|
}
|
||||||
|
|
||||||
|
const float MAX_LONGITUDE = 180.0f;
|
||||||
|
const float MAX_LATITUDE = 90.0f;
|
||||||
|
|
||||||
|
float validateLongitude(float lon) {
|
||||||
|
return moduloRange(lon, -MAX_LONGITUDE, MAX_LONGITUDE);
|
||||||
|
}
|
||||||
|
|
||||||
|
float validateLatitude(float lat) {
|
||||||
|
return moduloRange(lat, -MAX_LATITUDE, MAX_LATITUDE);
|
||||||
|
}
|
||||||
|
|
||||||
|
float validateAltitude(float altitude) {
|
||||||
|
const float MIN_ALTITUDE = -1000.0f;
|
||||||
|
const float MAX_ALTITUDE = 100000.0f;
|
||||||
|
return std::min(std::max(altitude, MIN_ALTITUDE), MAX_ALTITUDE);
|
||||||
|
}
|
||||||
|
|
||||||
|
void EarthSunModel::setLatitude(float lat) {
|
||||||
|
_latitude = validateLatitude(lat);
|
||||||
|
invalidate();
|
||||||
|
}
|
||||||
|
void EarthSunModel::setLongitude(float lon) {
|
||||||
|
_longitude = validateLongitude(lon);
|
||||||
|
invalidate();
|
||||||
|
}
|
||||||
|
void EarthSunModel::setAltitude(float altitude) {
|
||||||
|
_altitude = validateAltitude(altitude);
|
||||||
|
invalidate();
|
||||||
|
}
|
||||||
|
|
||||||
|
void EarthSunModel::setSunLatitude(float lat) {
|
||||||
|
_sunLatitude = validateLatitude(lat);
|
||||||
|
invalidate();
|
||||||
|
}
|
||||||
|
void EarthSunModel::setSunLongitude(float lon) {
|
||||||
|
_sunLongitude = validateLongitude(lon);
|
||||||
|
invalidate();
|
||||||
|
}
|
||||||
|
|
||||||
|
const int NUM_DAYS_PER_YEAR = 365;
|
||||||
|
const float NUM_HOURS_PER_DAY = 24.0f;
|
||||||
|
const float NUM_HOURS_PER_HALF_DAY = NUM_HOURS_PER_DAY * 0.5f;
|
||||||
|
|
||||||
|
SunSkyStage::SunSkyStage() :
|
||||||
|
_sunLight(new Light())
|
||||||
|
{
|
||||||
|
_sunLight->setType(Light::SUN);
|
||||||
|
|
||||||
|
setSunIntensity(1.0f);
|
||||||
|
setSunColor(Vec3(1.0f, 1.0f, 1.0f));
|
||||||
|
|
||||||
|
// Default origin location is a special place in the world...
|
||||||
|
setOriginLocation(122.407f, 37.777f, 0.03f);
|
||||||
|
// Noun
|
||||||
|
setDayTime(12.0f);
|
||||||
|
// Begining of march
|
||||||
|
setYearTime(60.0f);
|
||||||
|
}
|
||||||
|
|
||||||
|
SunSkyStage::~SunSkyStage() {
|
||||||
|
}
|
||||||
|
|
||||||
|
void SunSkyStage::setDayTime(float hour) {
|
||||||
|
_dayTime = moduloRange(hour, 0.f, NUM_HOURS_PER_DAY);
|
||||||
|
invalidate();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SunSkyStage::setYearTime(unsigned int day) {
|
||||||
|
_yearTime = day % NUM_DAYS_PER_YEAR;
|
||||||
|
invalidate();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SunSkyStage::setOriginOrientation(const Quat& orientation) {
|
||||||
|
_earthSunModel.setSurfaceOrientation(orientation);
|
||||||
|
invalidate();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SunSkyStage::setOriginLocation(float longitude, float latitude, float altitude) {
|
||||||
|
_earthSunModel.setLongitude(longitude);
|
||||||
|
_earthSunModel.setLatitude(latitude);
|
||||||
|
_earthSunModel.setAltitude(altitude);
|
||||||
|
invalidate();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SunSkyStage::setSunColor(const Vec3& color) {
|
||||||
|
_sunLight->setColor(color);
|
||||||
|
}
|
||||||
|
void SunSkyStage::setSunIntensity(float intensity) {
|
||||||
|
_sunLight->setIntensity(intensity);
|
||||||
|
}
|
||||||
|
|
||||||
|
// THe sun declinaison calculus is taken from https://en.wikipedia.org/wiki/Position_of_the_Sun
|
||||||
|
double evalSunDeclinaison(double dayNumber) {
|
||||||
|
return -(23.0 + 44.0/60.0)*cos(glm::radians((360.0/365.0)*(dayNumber + 10.0)));
|
||||||
|
}
|
||||||
|
|
||||||
|
void SunSkyStage::updateGraphicsObject() const {
|
||||||
|
// Always update the sunLongitude based on the current dayTime and the current origin
|
||||||
|
// The day time is supposed to be local at the origin
|
||||||
|
double signedNormalizedDayTime = (_dayTime - NUM_HOURS_PER_HALF_DAY) / NUM_HOURS_PER_HALF_DAY;
|
||||||
|
double sunLongitude = _earthSunModel.getLongitude() + (MAX_LONGITUDE * signedNormalizedDayTime);
|
||||||
|
_earthSunModel.setSunLongitude(sunLongitude);
|
||||||
|
|
||||||
|
// And update the sunLAtitude as the declinaison depending of the time of the year
|
||||||
|
_earthSunModel.setSunLatitude(evalSunDeclinaison(_yearTime));
|
||||||
|
|
||||||
|
Vec3d sunLightDir = -_earthSunModel.getSurfaceSunDir();
|
||||||
|
_sunLight->setDirection(Vec3(sunLightDir.x, sunLightDir.y, sunLightDir.z));
|
||||||
|
|
||||||
|
double originAlt = _earthSunModel.getAltitude();
|
||||||
|
_sunLight->setPosition(Vec3(0.0f, originAlt, 0.0f));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
161
libraries/model/src/model/Stage.h
Normal file
161
libraries/model/src/model/Stage.h
Normal file
|
@ -0,0 +1,161 @@
|
||||||
|
//
|
||||||
|
// Stage.h
|
||||||
|
// libraries/model/src/model
|
||||||
|
//
|
||||||
|
// Created by Sam Gateau on 2/24/2015.
|
||||||
|
// 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_model_Stage_h
|
||||||
|
#define hifi_model_Stage_h
|
||||||
|
|
||||||
|
#include "Light.h"
|
||||||
|
|
||||||
|
namespace model {
|
||||||
|
|
||||||
|
typedef glm::dvec3 Vec3d;
|
||||||
|
typedef glm::dvec4 Vec4d;
|
||||||
|
typedef glm::dmat4 Mat4d;
|
||||||
|
typedef glm::mat4 Mat4;
|
||||||
|
|
||||||
|
class EarthSunModel {
|
||||||
|
public:
|
||||||
|
|
||||||
|
void setScale(float scale);
|
||||||
|
float getScale() const { return _scale; }
|
||||||
|
|
||||||
|
void setLatitude(float lat);
|
||||||
|
float getLatitude() const { return _latitude; }
|
||||||
|
void setLongitude(float lon);
|
||||||
|
float getLongitude() const { return _longitude; }
|
||||||
|
void setAltitude(float altitude);
|
||||||
|
float getAltitude() const { return _altitude; }
|
||||||
|
|
||||||
|
|
||||||
|
void setSurfaceOrientation(const Quat& orientation);
|
||||||
|
const Quat& getSurfaceOrientation() const { valid(); return _surfaceOrientation; }
|
||||||
|
|
||||||
|
const Vec3d& getSurfacePos() const { valid(); return _surfacePos; }
|
||||||
|
|
||||||
|
const Mat4d& getSurfaceToWorldMat() const { valid(); return _surfaceToWorldMat; }
|
||||||
|
const Mat4d& getWoldToSurfaceMat() const { valid(); return _worldToSurfaceMat; }
|
||||||
|
|
||||||
|
const Mat4d& getEyeToSurfaceMat() const { valid(); return _eyeToSurfaceMat; }
|
||||||
|
const Mat4d& getSurfaceToEyeMat() const { valid(); return _surfaceToEyeMat; }
|
||||||
|
|
||||||
|
const Mat4d& getEyeToWorldMat() const { valid(); return _eyeToWorldMat; }
|
||||||
|
const Mat4d& getWorldToEyeMat() const { valid(); return _worldToEyeMat; }
|
||||||
|
|
||||||
|
|
||||||
|
//or set the surfaceToEye mat directly
|
||||||
|
void setEyeToSurfaceMat( const Mat4d& e2s);
|
||||||
|
|
||||||
|
const Vec3d& getEyePos() const { valid(); return _eyePos; }
|
||||||
|
const Vec3d& getEyeDir() const { valid(); return _eyeDir; }
|
||||||
|
|
||||||
|
void setSunLongitude(float lon);
|
||||||
|
float getSunLongitude() const { return _sunLongitude; }
|
||||||
|
|
||||||
|
void setSunLatitude(float lat);
|
||||||
|
float getSunLatitude() const { return _sunLatitude; }
|
||||||
|
|
||||||
|
const Vec3d& getWorldSunDir() const { valid(); return _sunDir; }
|
||||||
|
const Vec3d& getSurfaceSunDir() const { valid(); return _surfaceSunDir; }
|
||||||
|
|
||||||
|
|
||||||
|
EarthSunModel() { valid(); }
|
||||||
|
|
||||||
|
protected:
|
||||||
|
double _scale = 1000.0; //Km
|
||||||
|
double _earthRadius = 6360.0;
|
||||||
|
|
||||||
|
Quat _surfaceOrientation;
|
||||||
|
|
||||||
|
double _longitude = 0.0;
|
||||||
|
double _latitude = 0.0;
|
||||||
|
double _altitude = 0.01;
|
||||||
|
mutable Vec3d _surfacePos;
|
||||||
|
mutable Mat4d _worldToSurfaceMat;
|
||||||
|
mutable Mat4d _surfaceToWorldMat;
|
||||||
|
void updateWorldToSurface() const;
|
||||||
|
|
||||||
|
mutable Mat4d _surfaceToEyeMat;
|
||||||
|
mutable Mat4d _eyeToSurfaceMat;
|
||||||
|
mutable Vec3d _eyeDir;
|
||||||
|
mutable Vec3d _eyePos;
|
||||||
|
void updateSurfaceToEye() const;
|
||||||
|
|
||||||
|
mutable Mat4d _worldToEyeMat;
|
||||||
|
mutable Mat4d _eyeToWorldMat;
|
||||||
|
|
||||||
|
double _sunLongitude = 0.0;
|
||||||
|
double _sunLatitude = 0.0;
|
||||||
|
mutable Vec3d _sunDir;
|
||||||
|
mutable Vec3d _surfaceSunDir;
|
||||||
|
void updateSun() const;
|
||||||
|
|
||||||
|
mutable bool _invalid = true;
|
||||||
|
void invalidate() const { _invalid = true; }
|
||||||
|
void valid() const { if (_invalid) { updateAll(); _invalid = false; } }
|
||||||
|
void updateAll() const;
|
||||||
|
|
||||||
|
static Mat4d evalWorldToGeoLocationMat(double longitude, double latitude, double altitude, double scale);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Sun sky stage generates the rendering primitives to display a scene realistically
|
||||||
|
// at the specified location and time around earth
|
||||||
|
class SunSkyStage {
|
||||||
|
public:
|
||||||
|
|
||||||
|
SunSkyStage();
|
||||||
|
~SunSkyStage();
|
||||||
|
|
||||||
|
// time of the day (local to the position) expressed in decimal hour in the range [0.0, 24.0]
|
||||||
|
void setDayTime(float hour);
|
||||||
|
float getDayTime() const { return _dayTime; }
|
||||||
|
|
||||||
|
// time of the year expressed in day in the range [0, 365]
|
||||||
|
void setYearTime(unsigned int day);
|
||||||
|
unsigned int getYearTime() const { return _yearTime; }
|
||||||
|
|
||||||
|
// Origin orientation used to modify the cardinal axis alignement used.
|
||||||
|
// THe default is north along +Z axis and west along +X axis. this orientation gets added
|
||||||
|
// to the transform stack producing the sun light direction.
|
||||||
|
void setOriginOrientation(const Quat& orientation);
|
||||||
|
const Quat& getOriginOrientation() const { return _earthSunModel.getSurfaceOrientation(); }
|
||||||
|
|
||||||
|
// Location used to define the sun & sky is a longitude and latitude [rad] and a earth surface altitude [km]
|
||||||
|
void setOriginLocation(float longitude, float latitude, float surfaceAltitude);
|
||||||
|
float getOriginLatitude() const { return _earthSunModel.getLatitude(); }
|
||||||
|
float getOriginLongitude() const { return _earthSunModel.getLongitude(); }
|
||||||
|
float getOriginSurfaceAltitude() const { return _earthSunModel.getAltitude(); }
|
||||||
|
|
||||||
|
// Sun properties
|
||||||
|
void setSunColor(const Vec3& color);
|
||||||
|
const Vec3& getSunColor() const { return getSunLight()->getColor(); }
|
||||||
|
void setSunIntensity(float intensity);
|
||||||
|
float getSunIntensity() const { return getSunLight()->getIntensity(); }
|
||||||
|
|
||||||
|
LightPointer getSunLight() const { valid(); return _sunLight; }
|
||||||
|
|
||||||
|
protected:
|
||||||
|
LightPointer _sunLight;
|
||||||
|
|
||||||
|
float _dayTime;
|
||||||
|
int _yearTime;
|
||||||
|
|
||||||
|
mutable EarthSunModel _earthSunModel;
|
||||||
|
|
||||||
|
mutable bool _invalid = true;
|
||||||
|
void invalidate() const { _invalid = true; }
|
||||||
|
void valid() const { if (_invalid) { updateGraphicsObject(); _invalid = false; } }
|
||||||
|
void updateGraphicsObject() const;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef QSharedPointer< SunSkyStage > SunSkyStagePointer;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
|
@ -76,7 +76,7 @@ const QString AddressManager::currentPath(bool withOrientation) const {
|
||||||
pathString += "/" + orientationString;
|
pathString += "/" + orientationString;
|
||||||
} else {
|
} else {
|
||||||
qDebug() << "Cannot add orientation to path without a getter for position."
|
qDebug() << "Cannot add orientation to path without a getter for position."
|
||||||
<< "Call AdressManager::setOrientationGetter to pass a function that will return a glm::quat";
|
<< "Call AddressManager::setOrientationGetter to pass a function that will return a glm::quat";
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -84,7 +84,7 @@ const QString AddressManager::currentPath(bool withOrientation) const {
|
||||||
return pathString;
|
return pathString;
|
||||||
} else {
|
} else {
|
||||||
qDebug() << "Cannot create address path without a getter for position."
|
qDebug() << "Cannot create address path without a getter for position."
|
||||||
<< "Call AdressManager::setPositionGetter to pass a function that will return a const glm::vec3&";
|
<< "Call AddressManager::setPositionGetter to pass a function that will return a const glm::vec3&";
|
||||||
return QString();
|
return QString();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -669,3 +669,41 @@ void LimitedNodeList::sendHeartbeatToIceServer(const HifiSockAddr& iceServerSock
|
||||||
|
|
||||||
writeUnverifiedDatagram(iceRequestByteArray, iceServerSockAddr);
|
writeUnverifiedDatagram(iceRequestByteArray, iceServerSockAddr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void LimitedNodeList::putLocalPortIntoSharedMemory(const QString key, QObject* parent) {
|
||||||
|
// save our local port to shared memory so that assignment client children know how to talk to this parent
|
||||||
|
QSharedMemory* sharedPortMem = new QSharedMemory(key, parent);
|
||||||
|
quint16 localPort = 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" << key;
|
||||||
|
} else {
|
||||||
|
qWarning() << "Failed to create and attach to shared memory to share local port with assignment-client children.";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool LimitedNodeList::getLocalServerPortFromSharedMemory(const QString key, QSharedMemory*& sharedMem,
|
||||||
|
quint16& localPort) {
|
||||||
|
if (!sharedMem) {
|
||||||
|
sharedMem = new QSharedMemory(key, this);
|
||||||
|
|
||||||
|
if (!sharedMem->attach(QSharedMemory::ReadOnly)) {
|
||||||
|
qWarning() << "Could not attach to shared memory at key" << key;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sharedMem->isAttached()) {
|
||||||
|
sharedMem->lock();
|
||||||
|
memcpy(&localPort, sharedMem->data(), sizeof(localPort));
|
||||||
|
sharedMem->unlock();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
|
@ -26,6 +26,7 @@
|
||||||
#include <qsharedpointer.h>
|
#include <qsharedpointer.h>
|
||||||
#include <QtNetwork/qudpsocket.h>
|
#include <QtNetwork/qudpsocket.h>
|
||||||
#include <QtNetwork/qhostaddress.h>
|
#include <QtNetwork/qhostaddress.h>
|
||||||
|
#include <QSharedMemory>
|
||||||
|
|
||||||
#include <tbb/concurrent_unordered_map.h>
|
#include <tbb/concurrent_unordered_map.h>
|
||||||
|
|
||||||
|
@ -49,6 +50,10 @@ const char STUN_SERVER_HOSTNAME[] = "stun.highfidelity.io";
|
||||||
const unsigned short STUN_SERVER_PORT = 3478;
|
const unsigned short STUN_SERVER_PORT = 3478;
|
||||||
|
|
||||||
const QString DOMAIN_SERVER_LOCAL_PORT_SMEM_KEY = "domain-server.local-port";
|
const QString DOMAIN_SERVER_LOCAL_PORT_SMEM_KEY = "domain-server.local-port";
|
||||||
|
const QString ASSIGNMENT_CLIENT_MONITOR_LOCAL_PORT_SMEM_KEY = "assignment-client-monitor.local-port";
|
||||||
|
|
||||||
|
const char DEFAULT_ASSIGNMENT_CLIENT_MONITOR_HOSTNAME[] = "localhost";
|
||||||
|
const unsigned short DEFAULT_ASSIGNMENT_CLIENT_MONITOR_PORT = 40104;
|
||||||
|
|
||||||
class HifiSockAddr;
|
class HifiSockAddr;
|
||||||
|
|
||||||
|
@ -168,6 +173,9 @@ public:
|
||||||
|
|
||||||
return SharedNodePointer();
|
return SharedNodePointer();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void putLocalPortIntoSharedMemory(const QString key, QObject* parent);
|
||||||
|
bool getLocalServerPortFromSharedMemory(const QString key, QSharedMemory*& sharedMem, quint16& localPort);
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void reset();
|
void reset();
|
||||||
|
|
|
@ -149,7 +149,12 @@ QDataStream& operator>>(QDataStream& in, Node& node) {
|
||||||
}
|
}
|
||||||
|
|
||||||
QDebug operator<<(QDebug debug, const Node &node) {
|
QDebug operator<<(QDebug debug, const Node &node) {
|
||||||
debug.nospace() << NodeType::getNodeTypeName(node.getType()) << " (" << node.getType() << ")";
|
debug.nospace() << NodeType::getNodeTypeName(node.getType());
|
||||||
|
if (node.getType() == NodeType::Unassigned) {
|
||||||
|
debug.nospace() << " (1)";
|
||||||
|
} else {
|
||||||
|
debug.nospace() << " (" << node.getType() << ")";
|
||||||
|
}
|
||||||
debug << " " << node.getUUID().toString().toLocal8Bit().constData() << " ";
|
debug << " " << node.getUUID().toString().toLocal8Bit().constData() << " ";
|
||||||
debug.nospace() << node.getPublicSocket() << "/" << node.getLocalSocket();
|
debug.nospace() << node.getPublicSocket() << "/" << node.getLocalSocket();
|
||||||
return debug.nospace();
|
return debug.nospace();
|
||||||
|
|
|
@ -62,13 +62,17 @@ NodeList::NodeList(char newOwnerType, unsigned short socketListenPort, unsigned
|
||||||
connect(&AccountManager::getInstance(), &AccountManager::logoutComplete , this, &NodeList::reset);
|
connect(&AccountManager::getInstance(), &AccountManager::logoutComplete , this, &NodeList::reset);
|
||||||
}
|
}
|
||||||
|
|
||||||
qint64 NodeList::sendStatsToDomainServer(const QJsonObject& statsObject) {
|
qint64 NodeList::sendStats(const QJsonObject& statsObject, HifiSockAddr destination) {
|
||||||
QByteArray statsPacket = byteArrayWithPopulatedHeader(PacketTypeNodeJsonStats);
|
QByteArray statsPacket = byteArrayWithPopulatedHeader(PacketTypeNodeJsonStats);
|
||||||
QDataStream statsPacketStream(&statsPacket, QIODevice::Append);
|
QDataStream statsPacketStream(&statsPacket, QIODevice::Append);
|
||||||
|
|
||||||
statsPacketStream << statsObject.toVariantMap();
|
statsPacketStream << statsObject.toVariantMap();
|
||||||
|
|
||||||
return writeUnverifiedDatagram(statsPacket, _domainHandler.getSockAddr());
|
return writeUnverifiedDatagram(statsPacket, destination);
|
||||||
|
}
|
||||||
|
|
||||||
|
qint64 NodeList::sendStatsToDomainServer(const QJsonObject& statsObject) {
|
||||||
|
return sendStats(statsObject, _domainHandler.getSockAddr());
|
||||||
}
|
}
|
||||||
|
|
||||||
void NodeList::timePingReply(const QByteArray& packet, const SharedNodePointer& sendingNode) {
|
void NodeList::timePingReply(const QByteArray& packet, const SharedNodePointer& sendingNode) {
|
||||||
|
|
|
@ -47,6 +47,7 @@ public:
|
||||||
NodeType_t getOwnerType() const { return _ownerType; }
|
NodeType_t getOwnerType() const { return _ownerType; }
|
||||||
void setOwnerType(NodeType_t ownerType) { _ownerType = ownerType; }
|
void setOwnerType(NodeType_t ownerType) { _ownerType = ownerType; }
|
||||||
|
|
||||||
|
qint64 sendStats(const QJsonObject& statsObject, HifiSockAddr destination);
|
||||||
qint64 sendStatsToDomainServer(const QJsonObject& statsObject);
|
qint64 sendStatsToDomainServer(const QJsonObject& statsObject);
|
||||||
|
|
||||||
int getNumNoReplyDomainCheckIns() const { return _numNoReplyDomainCheckIns; }
|
int getNumNoReplyDomainCheckIns() const { return _numNoReplyDomainCheckIns; }
|
||||||
|
|
|
@ -70,6 +70,8 @@ PacketVersion versionForPacketType(PacketType type) {
|
||||||
return 2;
|
return 2;
|
||||||
case PacketTypeOctreeStats:
|
case PacketTypeOctreeStats:
|
||||||
return 1;
|
return 1;
|
||||||
|
case PacketTypeStopNode:
|
||||||
|
return 1;
|
||||||
case PacketTypeEntityAddOrEdit:
|
case PacketTypeEntityAddOrEdit:
|
||||||
case PacketTypeEntityData:
|
case PacketTypeEntityData:
|
||||||
return VERSION_MODEL_ENTITIES_SUPPORT_SHAPE_TYPE;
|
return VERSION_MODEL_ENTITIES_SUPPORT_SHAPE_TYPE;
|
||||||
|
@ -124,6 +126,7 @@ QString nameForPacketType(PacketType type) {
|
||||||
PACKET_TYPE_NAME_LOOKUP(PacketTypeEntityErase);
|
PACKET_TYPE_NAME_LOOKUP(PacketTypeEntityErase);
|
||||||
PACKET_TYPE_NAME_LOOKUP(PacketTypeEntityAddResponse);
|
PACKET_TYPE_NAME_LOOKUP(PacketTypeEntityAddResponse);
|
||||||
PACKET_TYPE_NAME_LOOKUP(PacketTypeOctreeDataNack);
|
PACKET_TYPE_NAME_LOOKUP(PacketTypeOctreeDataNack);
|
||||||
|
PACKET_TYPE_NAME_LOOKUP(PacketTypeStopNode);
|
||||||
PACKET_TYPE_NAME_LOOKUP(PacketTypeAudioEnvironment);
|
PACKET_TYPE_NAME_LOOKUP(PacketTypeAudioEnvironment);
|
||||||
PACKET_TYPE_NAME_LOOKUP(PacketTypeEntityEditNack);
|
PACKET_TYPE_NAME_LOOKUP(PacketTypeEntityEditNack);
|
||||||
PACKET_TYPE_NAME_LOOKUP(PacketTypeSignedTransactionPayment);
|
PACKET_TYPE_NAME_LOOKUP(PacketTypeSignedTransactionPayment);
|
||||||
|
|
|
@ -67,7 +67,7 @@ enum PacketType {
|
||||||
PacketTypeEntityErase,
|
PacketTypeEntityErase,
|
||||||
PacketTypeEntityAddResponse,
|
PacketTypeEntityAddResponse,
|
||||||
PacketTypeOctreeDataNack, // 45
|
PacketTypeOctreeDataNack, // 45
|
||||||
UNUSED_10,
|
PacketTypeStopNode,
|
||||||
PacketTypeAudioEnvironment,
|
PacketTypeAudioEnvironment,
|
||||||
PacketTypeEntityEditNack,
|
PacketTypeEntityEditNack,
|
||||||
PacketTypeSignedTransactionPayment,
|
PacketTypeSignedTransactionPayment,
|
||||||
|
@ -86,7 +86,7 @@ const QSet<PacketType> NON_VERIFIED_PACKETS = QSet<PacketType>()
|
||||||
<< PacketTypeNodeJsonStats << PacketTypeEntityQuery
|
<< PacketTypeNodeJsonStats << PacketTypeEntityQuery
|
||||||
<< PacketTypeOctreeDataNack << PacketTypeEntityEditNack
|
<< PacketTypeOctreeDataNack << PacketTypeEntityEditNack
|
||||||
<< PacketTypeIceServerHeartbeat << PacketTypeIceServerHeartbeatResponse
|
<< PacketTypeIceServerHeartbeat << PacketTypeIceServerHeartbeatResponse
|
||||||
<< PacketTypeUnverifiedPing << PacketTypeUnverifiedPingReply;
|
<< PacketTypeUnverifiedPing << PacketTypeUnverifiedPingReply << PacketTypeStopNode;
|
||||||
|
|
||||||
const int NUM_BYTES_MD5_HASH = 16;
|
const int NUM_BYTES_MD5_HASH = 16;
|
||||||
const int NUM_STATIC_HEADER_BYTES = sizeof(PacketVersion) + NUM_BYTES_RFC4122_UUID;
|
const int NUM_STATIC_HEADER_BYTES = sizeof(PacketVersion) + NUM_BYTES_RFC4122_UUID;
|
||||||
|
|
|
@ -97,9 +97,7 @@ vec3 evalLightmappedColor(float shadowAttenuation, vec3 normal, vec3 diffuse, ve
|
||||||
Light light = getLight();
|
Light light = getLight();
|
||||||
|
|
||||||
vec3 fragNormal = vec3(invViewMat * vec4(normal, 0.0));
|
vec3 fragNormal = vec3(invViewMat * vec4(normal, 0.0));
|
||||||
|
|
||||||
float diffuseDot = dot(fragNormal, -getLightDirection(light));
|
float diffuseDot = dot(fragNormal, -getLightDirection(light));
|
||||||
// float diffuseDot = dot(normal, getLightDirection(light));
|
|
||||||
|
|
||||||
// need to catch normals perpendicular to the projection plane hence the magic number for the threshold
|
// need to catch normals perpendicular to the projection plane hence the magic number for the threshold
|
||||||
// it should be just 0, but we have innacurracy so we need to overshoot
|
// it should be just 0, but we have innacurracy so we need to overshoot
|
||||||
|
|
|
@ -126,15 +126,13 @@ void DeferredLightingEffect::renderSolidCone(float base, float height, int slice
|
||||||
releaseSimpleProgram();
|
releaseSimpleProgram();
|
||||||
}
|
}
|
||||||
|
|
||||||
void DeferredLightingEffect::addPointLight(const glm::vec3& position, float radius, const glm::vec3& ambient,
|
void DeferredLightingEffect::addPointLight(const glm::vec3& position, float radius, const glm::vec3& color,
|
||||||
const glm::vec3& diffuse, const glm::vec3& specular, float constantAttenuation,
|
float intensity) {
|
||||||
float linearAttenuation, float quadraticAttenuation) {
|
addSpotLight(position, radius, color, intensity);
|
||||||
addSpotLight(position, radius, ambient, diffuse, specular, constantAttenuation, linearAttenuation, quadraticAttenuation);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void DeferredLightingEffect::addSpotLight(const glm::vec3& position, float radius, const glm::vec3& ambient,
|
void DeferredLightingEffect::addSpotLight(const glm::vec3& position, float radius, const glm::vec3& color,
|
||||||
const glm::vec3& diffuse, const glm::vec3& specular, float constantAttenuation, float linearAttenuation,
|
float intensity, const glm::quat& orientation, float exponent, float cutoff) {
|
||||||
float quadraticAttenuation, const glm::vec3& direction, float exponent, float cutoff) {
|
|
||||||
|
|
||||||
int lightID = _pointLights.size() + _spotLights.size() + _globalLights.size();
|
int lightID = _pointLights.size() + _spotLights.size() + _globalLights.size();
|
||||||
if (lightID >= _allocatedLights.size()) {
|
if (lightID >= _allocatedLights.size()) {
|
||||||
|
@ -144,8 +142,8 @@ void DeferredLightingEffect::addSpotLight(const glm::vec3& position, float radiu
|
||||||
|
|
||||||
lp->setPosition(position);
|
lp->setPosition(position);
|
||||||
lp->setMaximumRadius(radius);
|
lp->setMaximumRadius(radius);
|
||||||
lp->setColor(diffuse);
|
lp->setColor(color);
|
||||||
lp->setIntensity(1.0f);
|
lp->setIntensity(intensity);
|
||||||
//lp->setShowContour(quadraticAttenuation);
|
//lp->setShowContour(quadraticAttenuation);
|
||||||
|
|
||||||
if (exponent == 0.0f && cutoff == PI) {
|
if (exponent == 0.0f && cutoff == PI) {
|
||||||
|
@ -153,7 +151,7 @@ void DeferredLightingEffect::addSpotLight(const glm::vec3& position, float radiu
|
||||||
_pointLights.push_back(lightID);
|
_pointLights.push_back(lightID);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
lp->setDirection(direction);
|
lp->setOrientation(orientation);
|
||||||
lp->setSpotAngle(cutoff);
|
lp->setSpotAngle(cutoff);
|
||||||
lp->setSpotExponent(exponent);
|
lp->setSpotExponent(exponent);
|
||||||
lp->setType(model::Light::SPOT);
|
lp->setType(model::Light::SPOT);
|
||||||
|
|
|
@ -57,15 +57,12 @@ public:
|
||||||
void renderSolidCone(float base, float height, int slices, int stacks);
|
void renderSolidCone(float base, float height, int slices, int stacks);
|
||||||
|
|
||||||
/// Adds a point light to render for the current frame.
|
/// Adds a point light to render for the current frame.
|
||||||
void addPointLight(const glm::vec3& position, float radius, const glm::vec3& ambient = glm::vec3(0.0f, 0.0f, 0.0f),
|
void addPointLight(const glm::vec3& position, float radius, const glm::vec3& color = glm::vec3(0.0f, 0.0f, 0.0f),
|
||||||
const glm::vec3& diffuse = glm::vec3(1.0f, 1.0f, 1.0f), const glm::vec3& specular = glm::vec3(1.0f, 1.0f, 1.0f),
|
float intensity = 0.5f);
|
||||||
float constantAttenuation = 1.0f, float linearAttenuation = 0.0f, float quadraticAttenuation = 0.0f);
|
|
||||||
|
|
||||||
/// Adds a spot light to render for the current frame.
|
/// Adds a spot light to render for the current frame.
|
||||||
void addSpotLight(const glm::vec3& position, float radius, const glm::vec3& ambient = glm::vec3(0.0f, 0.0f, 0.0f),
|
void addSpotLight(const glm::vec3& position, float radius, const glm::vec3& color = glm::vec3(1.0f, 1.0f, 1.0f),
|
||||||
const glm::vec3& diffuse = glm::vec3(1.0f, 1.0f, 1.0f), const glm::vec3& specular = glm::vec3(1.0f, 1.0f, 1.0f),
|
float intensity = 0.5f, const glm::quat& orientation = glm::quat(), float exponent = 0.0f, float cutoff = PI);
|
||||||
float constantAttenuation = 1.0f, float linearAttenuation = 0.0f, float quadraticAttenuation = 0.0f,
|
|
||||||
const glm::vec3& direction = glm::vec3(0.0f, 0.0f, -1.0f), float exponent = 0.0f, float cutoff = PI);
|
|
||||||
|
|
||||||
/// Adds an object to render after performing the deferred lighting for the current frame (e.g., a translucent object).
|
/// Adds an object to render after performing the deferred lighting for the current frame (e.g., a translucent object).
|
||||||
void addPostLightingRenderable(PostLightingRenderable* renderable) { _postLightingRenderables.append(renderable); }
|
void addPostLightingRenderable(PostLightingRenderable* renderable) { _postLightingRenderables.append(renderable); }
|
||||||
|
|
40
libraries/script-engine/src/SceneScriptingInterface.cpp
Normal file
40
libraries/script-engine/src/SceneScriptingInterface.cpp
Normal file
|
@ -0,0 +1,40 @@
|
||||||
|
//
|
||||||
|
// SceneScriptingInterface.cpp
|
||||||
|
// interface/src/scripting
|
||||||
|
//
|
||||||
|
// Created by Sam Gateau on 2/24/15.
|
||||||
|
// 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 <AddressManager.h>
|
||||||
|
|
||||||
|
#include "SceneScriptingInterface.h"
|
||||||
|
|
||||||
|
void SceneScriptingInterface::setStageOrientation(const glm::quat& orientation) {
|
||||||
|
_skyStage->setOriginOrientation(orientation);
|
||||||
|
}
|
||||||
|
void SceneScriptingInterface::setStageLocation(float longitude, float latitude, float altitude) {
|
||||||
|
_skyStage->setOriginLocation(longitude, latitude, altitude);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SceneScriptingInterface::setStageDayTime(float hour) {
|
||||||
|
_skyStage->setDayTime(hour);
|
||||||
|
}
|
||||||
|
void SceneScriptingInterface::setStageYearTime(int day) {
|
||||||
|
_skyStage->setYearTime(day);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SceneScriptingInterface::setSunColor(const glm::vec3& color) {
|
||||||
|
_skyStage->setSunColor(color);
|
||||||
|
}
|
||||||
|
void SceneScriptingInterface::setSunIntensity(float intensity) {
|
||||||
|
_skyStage->setSunIntensity(intensity);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
model::SunSkyStagePointer SceneScriptingInterface::getSkyStage() const {
|
||||||
|
return _skyStage;
|
||||||
|
}
|
43
libraries/script-engine/src/SceneScriptingInterface.h
Normal file
43
libraries/script-engine/src/SceneScriptingInterface.h
Normal file
|
@ -0,0 +1,43 @@
|
||||||
|
//
|
||||||
|
// SceneScriptingInterface.h
|
||||||
|
// interface/src/scripting
|
||||||
|
//
|
||||||
|
// Created by Sam Gateau on 2/24/15.
|
||||||
|
// 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_SceneScriptingInterface_h
|
||||||
|
#define hifi_SceneScriptingInterface_h
|
||||||
|
|
||||||
|
#include <qscriptengine.h>
|
||||||
|
|
||||||
|
#include <DependencyManager.h>
|
||||||
|
|
||||||
|
#include "model/Stage.h"
|
||||||
|
|
||||||
|
class SceneScriptingInterface : public QObject, public Dependency {
|
||||||
|
Q_OBJECT
|
||||||
|
SINGLETON_DEPENDENCY
|
||||||
|
|
||||||
|
public:
|
||||||
|
Q_INVOKABLE void setStageOrientation(const glm::quat& orientation);
|
||||||
|
Q_INVOKABLE void setStageLocation(float longitude, float latitude, float altitude);
|
||||||
|
Q_INVOKABLE void setStageDayTime(float hour);
|
||||||
|
Q_INVOKABLE void setStageYearTime(int day);
|
||||||
|
|
||||||
|
Q_INVOKABLE void setSunColor(const glm::vec3& color);
|
||||||
|
Q_INVOKABLE void setSunIntensity(float intensity);
|
||||||
|
|
||||||
|
model::SunSkyStagePointer getSkyStage() const;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
SceneScriptingInterface() {};
|
||||||
|
~SceneScriptingInterface() {};
|
||||||
|
|
||||||
|
model::SunSkyStagePointer _skyStage = model::SunSkyStagePointer(new model::SunSkyStage());
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // hifi_SceneScriptingInterface_h
|
|
@ -39,6 +39,8 @@
|
||||||
#include "TypedArrays.h"
|
#include "TypedArrays.h"
|
||||||
#include "XMLHttpRequestClass.h"
|
#include "XMLHttpRequestClass.h"
|
||||||
|
|
||||||
|
#include "SceneScriptingInterface.h"
|
||||||
|
|
||||||
#include "MIDIEvent.h"
|
#include "MIDIEvent.h"
|
||||||
|
|
||||||
|
|
||||||
|
@ -310,6 +312,8 @@ void ScriptEngine::init() {
|
||||||
|
|
||||||
_isInitialized = true;
|
_isInitialized = true;
|
||||||
|
|
||||||
|
auto sceneScriptingInterface = DependencyManager::set<SceneScriptingInterface>();
|
||||||
|
|
||||||
_entityScriptingInterface.init();
|
_entityScriptingInterface.init();
|
||||||
|
|
||||||
// register various meta-types
|
// register various meta-types
|
||||||
|
@ -353,6 +357,7 @@ void ScriptEngine::init() {
|
||||||
registerGlobalObject("Vec3", &_vec3Library);
|
registerGlobalObject("Vec3", &_vec3Library);
|
||||||
registerGlobalObject("Uuid", &_uuidLibrary);
|
registerGlobalObject("Uuid", &_uuidLibrary);
|
||||||
registerGlobalObject("AnimationCache", DependencyManager::get<AnimationCache>().data());
|
registerGlobalObject("AnimationCache", DependencyManager::get<AnimationCache>().data());
|
||||||
|
registerGlobalObject("Scene", DependencyManager::get<SceneScriptingInterface>().data());
|
||||||
|
|
||||||
// constants
|
// constants
|
||||||
globalObject().setProperty("TREE_SCALE", newVariant(QVariant(TREE_SCALE)));
|
globalObject().setProperty("TREE_SCALE", newVariant(QVariant(TREE_SCALE)));
|
||||||
|
|
Loading…
Reference in a new issue