From c9d6a44c3a5cc399d115738404e1e7acad332415 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Tue, 24 Feb 2015 16:56:13 -0800 Subject: [PATCH 01/36] fix up command-line parsing --- assignment-client/src/AssignmentClient.cpp | 49 ++------ assignment-client/src/AssignmentClient.h | 4 +- assignment-client/src/AssignmentClientApp.cpp | 118 +++++++++++++++++- assignment-client/src/AssignmentClientApp.h | 16 +++ .../src/AssignmentClientMonitor.cpp | 60 ++++++--- .../src/AssignmentClientMonitor.h | 15 ++- 6 files changed, 196 insertions(+), 66 deletions(-) diff --git a/assignment-client/src/AssignmentClient.cpp b/assignment-client/src/AssignmentClient.cpp index 2dfc3787de..cb2da51031 100644 --- a/assignment-client/src/AssignmentClient.cpp +++ b/assignment-client/src/AssignmentClient.cpp @@ -18,7 +18,6 @@ #include #include #include -#include #include #include #include @@ -40,7 +39,9 @@ SharedAssignmentPointer AssignmentClient::_currentAssignment; int hifiSockAddrMeta = qRegisterMetaType("HifiSockAddr"); -AssignmentClient::AssignmentClient(int &argc, char **argv) : +AssignmentClient::AssignmentClient(int &argc, char **argv, + Assignment::Type requestAssignmentType, QString assignmentPool, QUuid walletUUID, + QString assignmentServerHostname, quint16 assignmentServerPort) : QCoreApplication(argc, argv), _assignmentServerHostname(DEFAULT_ASSIGNMENT_SERVER_HOSTNAME), _localASPortSharedMem(NULL), @@ -73,51 +74,20 @@ AssignmentClient::AssignmentClient(int &argc, char **argv) : // set the logging target to the the CHILD_TARGET_NAME LogHandler::getInstance().setTargetName(ASSIGNMENT_CLIENT_TARGET_NAME); - const QVariantMap argumentVariantMap = HifiConfigVariantMap::mergeCLParametersWithJSONConfig(arguments()); - - const QString ASSIGNMENT_TYPE_OVERRIDE_OPTION = "t"; - const QString ASSIGNMENT_POOL_OPTION = "pool"; - const QString ASSIGNMENT_WALLET_DESTINATION_ID_OPTION = "wallet"; - const QString CUSTOM_ASSIGNMENT_SERVER_HOSTNAME_OPTION = "a"; - const QString CUSTOM_ASSIGNMENT_SERVER_PORT_OPTION = "p"; - - Assignment::Type requestAssignmentType = Assignment::AllTypes; - - // check for an assignment type passed on the command line or in the config - if (argumentVariantMap.contains(ASSIGNMENT_TYPE_OVERRIDE_OPTION)) { - requestAssignmentType = (Assignment::Type) argumentVariantMap.value(ASSIGNMENT_TYPE_OVERRIDE_OPTION).toInt(); - } - - QString assignmentPool; - - // check for an assignment pool passed on the command line or in the config - if (argumentVariantMap.contains(ASSIGNMENT_POOL_OPTION)) { - assignmentPool = argumentVariantMap.value(ASSIGNMENT_POOL_OPTION).toString(); - } - // setup our _requestAssignment member variable from the passed arguments _requestAssignment = Assignment(Assignment::RequestCommand, requestAssignmentType, assignmentPool); // check for a wallet UUID on the command line or in the config // this would represent where the user running AC wants funds sent to - if (argumentVariantMap.contains(ASSIGNMENT_WALLET_DESTINATION_ID_OPTION)) { - QUuid walletUUID = argumentVariantMap.value(ASSIGNMENT_WALLET_DESTINATION_ID_OPTION).toString(); + if (!walletUUID.isNull()) { qDebug() << "The destination wallet UUID for credits is" << uuidStringWithoutCurlyBraces(walletUUID); _requestAssignment.setWalletUUID(walletUUID); } - quint16 assignmentServerPort = DEFAULT_DOMAIN_SERVER_PORT; - // check for an overriden assignment server hostname - if (argumentVariantMap.contains(CUSTOM_ASSIGNMENT_SERVER_HOSTNAME_OPTION)) { + if (assignmentServerHostname != "") { // change the hostname for our assignment server - _assignmentServerHostname = argumentVariantMap.value(CUSTOM_ASSIGNMENT_SERVER_HOSTNAME_OPTION).toString(); - } - - // check for an overriden assignment server port - if (argumentVariantMap.contains(CUSTOM_ASSIGNMENT_SERVER_PORT_OPTION)) { - assignmentServerPort = - argumentVariantMap.value(CUSTOM_ASSIGNMENT_SERVER_PORT_OPTION).toString().toUInt(); + _assignmentServerHostname = assignmentServerHostname; } _assignmentServerSocket = HifiSockAddr(_assignmentServerHostname, assignmentServerPort, true); @@ -128,6 +98,10 @@ AssignmentClient::AssignmentClient(int &argc, char **argv) : // call a timer function every ASSIGNMENT_REQUEST_INTERVAL_MSECS to ask for assignment, if required qDebug() << "Waiting for assignment -" << _requestAssignment; + if (_assignmentServerHostname != "localhost") { + qDebug () << "- will attempt to connect to domain-server on" << _assignmentServerSocket.getPort(); + } + connect(&_requestTimer, SIGNAL(timeout()), SLOT(sendAssignmentRequest())); _requestTimer.start(ASSIGNMENT_REQUEST_INTERVAL_MSECS); @@ -199,9 +173,6 @@ void AssignmentClient::sendAssignmentRequest() { nodeList->setAssignmentServerSocket(_assignmentServerSocket); } } - else { - qDebug () << "- will attempt to connect to domain-server on" << _assignmentServerSocket.getPort(); - } } nodeList->sendAssignment(_requestAssignment); diff --git a/assignment-client/src/AssignmentClient.h b/assignment-client/src/AssignmentClient.h index e105309e10..67a5dc89a7 100644 --- a/assignment-client/src/AssignmentClient.h +++ b/assignment-client/src/AssignmentClient.h @@ -21,7 +21,9 @@ class QSharedMemory; class AssignmentClient : public QCoreApplication { Q_OBJECT public: - AssignmentClient(int &argc, char **argv); + + AssignmentClient(int &argc, char **argv, Assignment::Type requestAssignmentType, QString assignmentPool, + QUuid walletUUID, QString assignmentServerHostname, quint16 assignmentServerPort); static const SharedAssignmentPointer& getCurrentAssignment() { return _currentAssignment; } private slots: diff --git a/assignment-client/src/AssignmentClientApp.cpp b/assignment-client/src/AssignmentClientApp.cpp index 477f1a2cf8..7f174f0833 100644 --- a/assignment-client/src/AssignmentClientApp.cpp +++ b/assignment-client/src/AssignmentClientApp.cpp @@ -13,6 +13,7 @@ #include #include +#include #include "Assignment.h" #include "AssignmentClient.h" @@ -37,9 +38,35 @@ AssignmentClientApp::AssignmentClientApp(int argc, char* argv[]) : const QCommandLineOption helpOption = parser.addHelpOption(); - const QCommandLineOption numChildsOption("n", "number of children to fork", "child-count"); + 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(); @@ -51,16 +78,99 @@ AssignmentClientApp::AssignmentClientApp(int argc, char* argv[]) : Q_UNREACHABLE(); } + + const QVariantMap argumentVariantMap = HifiConfigVariantMap::mergeCLParametersWithJSONConfig(arguments()); + + unsigned int numForks = 0; if (parser.isSet(numChildsOption)) { numForks = parser.value(numChildsOption).toInt(); } - if (numForks) { - AssignmentClientMonitor monitor(argc, argv, numForks); + 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(); + } + + + 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)) { + if (numForks || minForks || maxForks) { + qCritical() << "don't use -t with forking mode."; + parser.showHelp(); + Q_UNREACHABLE(); + } + 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(argc, argv, numForks, minForks, maxForks, assignmentPool, + walletUUID, assignmentServerHostname, assignmentServerPort); monitor.exec(); } else { - AssignmentClient client(argc, argv); + AssignmentClient client(argc, argv, requestAssignmentType, assignmentPool, + walletUUID, assignmentServerHostname, assignmentServerPort); client.exec(); } } diff --git a/assignment-client/src/AssignmentClientApp.h b/assignment-client/src/AssignmentClientApp.h index c5099ff25c..531035ef0e 100644 --- a/assignment-client/src/AssignmentClientApp.h +++ b/assignment-client/src/AssignmentClientApp.h @@ -9,10 +9,26 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +#ifndef hifi_AssignmentClientApp_h +#define hifi_AssignmentClientApp_h + + #include +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 diff --git a/assignment-client/src/AssignmentClientMonitor.cpp b/assignment-client/src/AssignmentClientMonitor.cpp index 803c7fd5c7..0f8e7adc17 100644 --- a/assignment-client/src/AssignmentClientMonitor.cpp +++ b/assignment-client/src/AssignmentClientMonitor.cpp @@ -16,6 +16,7 @@ #include #include "AssignmentClientMonitor.h" +#include "AssignmentClientApp.h" #include "AssignmentClientChildData.h" #include "PacketHeaders.h" #include "SharedUtil.h" @@ -24,8 +25,20 @@ const char* NUM_FORKS_PARAMETER = "-n"; const QString ASSIGNMENT_CLIENT_MONITOR_TARGET_NAME = "assignment-client-monitor"; -AssignmentClientMonitor::AssignmentClientMonitor(int &argc, char **argv, const unsigned int numAssignmentClientForks) : - QCoreApplication(argc, argv) +AssignmentClientMonitor::AssignmentClientMonitor(int &argc, char **argv, + const unsigned int numAssignmentClientForks, + const unsigned int minAssignmentClientForks, + const unsigned int maxAssignmentClientForks, + QString assignmentPool, QUuid walletUUID, QString assignmentServerHostname, + quint16 assignmentServerPort) : + QCoreApplication(argc, argv), + _numAssignmentClientForks(numAssignmentClientForks), + _minAssignmentClientForks(minAssignmentClientForks), + _maxAssignmentClientForks(maxAssignmentClientForks), + _assignmentPool(assignmentPool), + _walletUUID(walletUUID), + _assignmentServerHostname(assignmentServerHostname), + _assignmentServerPort(assignmentServerPort) { // start the Logging class with the parent's target name LogHandler::getInstance().setTargetName(ASSIGNMENT_CLIENT_MONITOR_TARGET_NAME); @@ -36,16 +49,6 @@ AssignmentClientMonitor::AssignmentClientMonitor(int &argc, char **argv, const u #else ShutdownEventListener::getInstance(); #endif - - _childArguments = arguments(); - - // remove the parameter for the number of forks so it isn't passed to the child forked processes - int forksParameterIndex = _childArguments.indexOf(NUM_FORKS_PARAMETER); - - // this removes both the "-n" parameter and the number of forks passed - _childArguments.removeAt(forksParameterIndex); - _childArguments.removeAt(forksParameterIndex); - // create a NodeList so we can receive stats from children DependencyManager::registerInheritance(); @@ -58,7 +61,7 @@ AssignmentClientMonitor::AssignmentClientMonitor(int &argc, char **argv, const u nodeList->putLocalPortIntoSharedMemory(ASSIGNMENT_CLIENT_MONITOR_LOCAL_PORT_SMEM_KEY, this); // use QProcess to fork off a process for each of the child assignment clients - for (unsigned int i = 0; i < numAssignmentClientForks; i++) { + for (unsigned int i = 0; i < _numAssignmentClientForks; i++) { spawnChildClient(); } @@ -83,7 +86,26 @@ void AssignmentClientMonitor::stopChildProcesses() { void AssignmentClientMonitor::spawnChildClient() { QProcess *assignmentClient = new QProcess(this); - + + // unparse the parts of the command-line that the child cares about + QStringList _childArguments; + if (_assignmentPool != "") { + _childArguments.append("--" + ASSIGNMENT_POOL_OPTION); + _childArguments.append(_assignmentPool); + } + if (!_walletUUID.isNull()) { + _childArguments.append("--" + ASSIGNMENT_WALLET_DESTINATION_ID_OPTION); + _childArguments.append(_walletUUID.toString()); + } + if (_assignmentServerHostname != "") { + _childArguments.append("--" + CUSTOM_ASSIGNMENT_SERVER_HOSTNAME_OPTION); + _childArguments.append(_assignmentServerHostname); + } + if (_assignmentServerPort != DEFAULT_DOMAIN_SERVER_PORT) { + _childArguments.append("--" + CUSTOM_ASSIGNMENT_SERVER_PORT_OPTION); + _childArguments.append(QString::number(_assignmentServerPort)); + } + // make sure that the output from the child process appears in our output assignmentClient->setProcessChannelMode(QProcess::ForwardedChannels); @@ -98,26 +120,24 @@ void AssignmentClientMonitor::checkSpares() { auto nodeList = DependencyManager::get(); QUuid aSpareId = ""; unsigned int spareCount = 0; + unsigned int totalCount = 0; nodeList->removeSilentNodes(); nodeList->eachNode([&](const SharedNodePointer& node) { AssignmentClientChildData *childData = static_cast(node->getLinkedData()); + totalCount ++; if (childData->getChildType() == "none") { spareCount ++; aSpareId = node->getUUID(); } }); - if (spareCount != 1) { - qDebug() << "spare count is" << spareCount; - } - - if (spareCount < 1) { + if (spareCount < 1 && totalCount < _maxAssignmentClientForks) { spawnChildClient(); } - if (spareCount > 1) { + if (spareCount > 1 && totalCount > _minAssignmentClientForks) { // kill aSpareId qDebug() << "asking child" << aSpareId << "to exit."; SharedNodePointer childNode = nodeList->nodeWithUUID(aSpareId); diff --git a/assignment-client/src/AssignmentClientMonitor.h b/assignment-client/src/AssignmentClientMonitor.h index 71ae34bc8c..e40a10014b 100644 --- a/assignment-client/src/AssignmentClientMonitor.h +++ b/assignment-client/src/AssignmentClientMonitor.h @@ -27,7 +27,10 @@ extern const char* NUM_FORKS_PARAMETER; class AssignmentClientMonitor : public QCoreApplication { Q_OBJECT public: - AssignmentClientMonitor(int &argc, char **argv, const unsigned int numAssignmentClientForks); + AssignmentClientMonitor(int &argc, char **argv, const unsigned int numAssignmentClientForks, + const unsigned int minAssignmentClientForks, const unsigned int maxAssignmentClientForks, + QString assignmentPool, QUuid walletUUID, QString assignmentServerHostname, + quint16 assignmentServerPort); ~AssignmentClientMonitor(); void stopChildProcesses(); @@ -37,8 +40,16 @@ private slots: private: void spawnChildClient(); - QStringList _childArguments; QTimer _checkSparesTimer; // every few seconds see if it need fewer or more spare children + + const unsigned int _numAssignmentClientForks; + const unsigned int _minAssignmentClientForks; + const unsigned int _maxAssignmentClientForks; + + QString _assignmentPool; + QUuid _walletUUID; + QString _assignmentServerHostname; + quint16 _assignmentServerPort; }; #endif // hifi_AssignmentClientMonitor_h From 89ebb45c0390830c84e41c12bf865a84a3792b86 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Tue, 24 Feb 2015 17:09:05 -0800 Subject: [PATCH 02/36] Revert "Merge pull request #4332 from birarda/master" This reverts commit 3230857b0d03c603bacb9016740234e781070d44, reversing changes made to 1b669af79df5335ae0e6565c33e06e30a006ca5e. --- assignment-client/src/AssignmentClient.cpp | 87 +++++++--- assignment-client/src/AssignmentClient.h | 11 +- assignment-client/src/AssignmentClientApp.cpp | 66 ++++++++ assignment-client/src/AssignmentClientApp.h | 18 ++ .../src/AssignmentClientChildData.cpp | 8 + .../src/AssignmentClientChildData.h | 32 ++++ .../src/AssignmentClientMonitor.cpp | 158 ++++++++++++++---- .../src/AssignmentClientMonitor.h | 13 +- assignment-client/src/main.cpp | 30 +--- domain-server/src/DomainServer.cpp | 14 +- libraries/networking/src/AddressManager.cpp | 4 +- libraries/networking/src/LimitedNodeList.cpp | 38 +++++ libraries/networking/src/LimitedNodeList.h | 9 + libraries/networking/src/Node.cpp | 7 +- libraries/networking/src/NodeList.cpp | 8 +- libraries/networking/src/NodeList.h | 1 + libraries/networking/src/PacketHeaders.cpp | 3 + libraries/networking/src/PacketHeaders.h | 4 +- 18 files changed, 403 insertions(+), 108 deletions(-) create mode 100644 assignment-client/src/AssignmentClientApp.cpp create mode 100644 assignment-client/src/AssignmentClientApp.h create mode 100644 assignment-client/src/AssignmentClientChildData.cpp create mode 100644 assignment-client/src/AssignmentClientChildData.h diff --git a/assignment-client/src/AssignmentClient.cpp b/assignment-client/src/AssignmentClient.cpp index bf67d4d597..2dfc3787de 100644 --- a/assignment-client/src/AssignmentClient.cpp +++ b/assignment-client/src/AssignmentClient.cpp @@ -18,10 +18,10 @@ #include #include #include -#include #include #include #include +#include #include #include #include @@ -43,7 +43,8 @@ int hifiSockAddrMeta = qRegisterMetaType("HifiSockAddr"); AssignmentClient::AssignmentClient(int &argc, char **argv) : QCoreApplication(argc, argv), _assignmentServerHostname(DEFAULT_ASSIGNMENT_SERVER_HOSTNAME), - _localASPortSharedMem(NULL) + _localASPortSharedMem(NULL), + _localACMPortSharedMem(NULL) { LogUtils::init(); @@ -56,7 +57,11 @@ AssignmentClient::AssignmentClient(int &argc, char **argv) : DependencyManager::registerInheritance(); auto addressManager = DependencyManager::set(); auto nodeList = DependencyManager::set(NodeType::Unassigned); - auto avatarHashMap = DependencyManager::set(); + + // make up a uuid for this child so the parent can tell us apart. This id will be changed + // when the domain server hands over an assignment. + QUuid nodeUUID = QUuid::createUuid(); + nodeList->setSessionUUID(nodeUUID); // setup a shutdown event listener to handle SIGTERM or WM_CLOSE for us #ifdef _WIN32 @@ -123,9 +128,8 @@ AssignmentClient::AssignmentClient(int &argc, char **argv) : // call a timer function every ASSIGNMENT_REQUEST_INTERVAL_MSECS to ask for assignment, if required qDebug() << "Waiting for assignment -" << _requestAssignment; - QTimer* timer = new QTimer(this); - connect(timer, SIGNAL(timeout()), SLOT(sendAssignmentRequest())); - timer->start(ASSIGNMENT_REQUEST_INTERVAL_MSECS); + connect(&_requestTimer, SIGNAL(timeout()), SLOT(sendAssignmentRequest())); + _requestTimer.start(ASSIGNMENT_REQUEST_INTERVAL_MSECS); // connect our readPendingDatagrams method to the readyRead() signal of the socket connect(&nodeList->getNodeSocket(), &QUdpSocket::readyRead, this, &AssignmentClient::readPendingDatagrams); @@ -136,6 +140,45 @@ AssignmentClient::AssignmentClient(int &argc, char **argv) : // Create Singleton objects on main thread NetworkAccessManager::getInstance(); + + // Hook up a timer to send this child's status to the Monitor once per second + setUpStatsToMonitor(); +} + + +void AssignmentClient::stopAssignmentClient() { + qDebug() << "Exiting."; + _requestTimer.stop(); + _statsTimerACM.stop(); + 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->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(); + + if (_currentAssignment) { + statsObject["assignment_type"] = _currentAssignment->getTypeName(); + } else { + statsObject["assignment_type"] = "none"; + } + nodeList->sendStats(statsObject, _assignmentClientMonitorSocket); } void AssignmentClient::sendAssignmentRequest() { @@ -145,23 +188,9 @@ void AssignmentClient::sendAssignmentRequest() { if (_assignmentServerHostname == "localhost") { // we want to check again for the local domain-server port in case the DS has restarted - if (!_localASPortSharedMem) { - _localASPortSharedMem = new QSharedMemory(DOMAIN_SERVER_LOCAL_PORT_SMEM_KEY, this); - - if (!_localASPortSharedMem->attach(QSharedMemory::ReadOnly)) { - qWarning() << "Could not attach to shared memory at key" << DOMAIN_SERVER_LOCAL_PORT_SMEM_KEY - << "- will attempt to connect to domain-server on" << _assignmentServerSocket.getPort(); - } - } - - if (_localASPortSharedMem->isAttached()) { - _localASPortSharedMem->lock(); - - quint16 localAssignmentServerPort; - memcpy(&localAssignmentServerPort, _localASPortSharedMem->data(), sizeof(localAssignmentServerPort)); - - _localASPortSharedMem->unlock(); - + quint16 localAssignmentServerPort; + if (nodeList->getLocalServerPortFromSharedMemory(DOMAIN_SERVER_LOCAL_PORT_SMEM_KEY, _localASPortSharedMem, + localAssignmentServerPort)) { if (localAssignmentServerPort != _assignmentServerSocket.getPort()) { qDebug() << "Port for local assignment server read from shared memory is" << localAssignmentServerPort; @@ -170,7 +199,9 @@ void AssignmentClient::sendAssignmentRequest() { nodeList->setAssignmentServerSocket(_assignmentServerSocket); } } - + else { + qDebug () << "- will attempt to connect to domain-server on" << _assignmentServerSocket.getPort(); + } } nodeList->sendAssignment(_requestAssignment); @@ -227,6 +258,14 @@ void AssignmentClient::readPendingDatagrams() { } else { qDebug() << "Received an assignment that could not be unpacked. Re-requesting."; } + } else if (packetTypeForPacket(receivedPacket) == PacketTypeStopNode) { + if (senderSockAddr.getAddress() == QHostAddress::LocalHost || + senderSockAddr.getAddress() == QHostAddress::LocalHostIPv6) { + qDebug() << "Network told me to exit."; + emit stopAssignmentClient(); + } else { + qDebug() << "Got a stop packet from other than localhost."; + } } else { // have the NodeList attempt to handle it nodeList->processNodeData(senderSockAddr, receivedPacket); diff --git a/assignment-client/src/AssignmentClient.h b/assignment-client/src/AssignmentClient.h index 053458f136..e105309e10 100644 --- a/assignment-client/src/AssignmentClient.h +++ b/assignment-client/src/AssignmentClient.h @@ -29,13 +29,22 @@ private slots: void readPendingDatagrams(); void assignmentCompleted(); void handleAuthenticationRequest(); + void sendStatsPacketToACM(); + void stopAssignmentClient(); private: + void setUpStatsToMonitor(); Assignment _requestAssignment; static SharedAssignmentPointer _currentAssignment; QString _assignmentServerHostname; HifiSockAddr _assignmentServerSocket; - QSharedMemory* _localASPortSharedMem; + QSharedMemory* _localASPortSharedMem; // memory shared with domain server + QSharedMemory* _localACMPortSharedMem; // memory shared with assignment client monitor + QTimer _requestTimer; // timer for requesting and assignment + QTimer _statsTimerACM; // timer for sending stats to assignment client monitor + + protected: + HifiSockAddr _assignmentClientMonitorSocket; }; #endif // hifi_AssignmentClient_h diff --git a/assignment-client/src/AssignmentClientApp.cpp b/assignment-client/src/AssignmentClientApp.cpp new file mode 100644 index 0000000000..477f1a2cf8 --- /dev/null +++ b/assignment-client/src/AssignmentClientApp.cpp @@ -0,0 +1,66 @@ +// +// 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 + +#include +#include + +#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 + + // 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 numChildsOption("n", "number of children to fork", "child-count"); + parser.addOption(numChildsOption); + + if (!parser.parse(QCoreApplication::arguments())) { + qCritical() << parser.errorText() << endl; + parser.showHelp(); + Q_UNREACHABLE(); + } + + if (parser.isSet(helpOption)) { + parser.showHelp(); + Q_UNREACHABLE(); + } + + unsigned int numForks = 0; + if (parser.isSet(numChildsOption)) { + numForks = parser.value(numChildsOption).toInt(); + } + + if (numForks) { + AssignmentClientMonitor monitor(argc, argv, numForks); + monitor.exec(); + } else { + AssignmentClient client(argc, argv); + client.exec(); + } +} diff --git a/assignment-client/src/AssignmentClientApp.h b/assignment-client/src/AssignmentClientApp.h new file mode 100644 index 0000000000..c5099ff25c --- /dev/null +++ b/assignment-client/src/AssignmentClientApp.h @@ -0,0 +1,18 @@ +// +// 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 +// + +#include + +class AssignmentClientApp : public QCoreApplication { + Q_OBJECT +public: + AssignmentClientApp(int argc, char* argv[]); +}; diff --git a/assignment-client/src/AssignmentClientChildData.cpp b/assignment-client/src/AssignmentClientChildData.cpp new file mode 100644 index 0000000000..de34613ec9 --- /dev/null +++ b/assignment-client/src/AssignmentClientChildData.cpp @@ -0,0 +1,8 @@ + +#include "AssignmentClientChildData.h" + + +AssignmentClientChildData::AssignmentClientChildData(QString childType) : + _childType(childType) +{ +} diff --git a/assignment-client/src/AssignmentClientChildData.h b/assignment-client/src/AssignmentClientChildData.h new file mode 100644 index 0000000000..6fd5f72f7f --- /dev/null +++ b/assignment-client/src/AssignmentClientChildData.h @@ -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 + + +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 diff --git a/assignment-client/src/AssignmentClientMonitor.cpp b/assignment-client/src/AssignmentClientMonitor.cpp index 45e1f56d53..803c7fd5c7 100644 --- a/assignment-client/src/AssignmentClientMonitor.cpp +++ b/assignment-client/src/AssignmentClientMonitor.cpp @@ -13,14 +13,18 @@ #include #include +#include #include "AssignmentClientMonitor.h" +#include "AssignmentClientChildData.h" +#include "PacketHeaders.h" +#include "SharedUtil.h" const char* NUM_FORKS_PARAMETER = "-n"; const QString ASSIGNMENT_CLIENT_MONITOR_TARGET_NAME = "assignment-client-monitor"; -AssignmentClientMonitor::AssignmentClientMonitor(int &argc, char **argv, int numAssignmentClientForks) : +AssignmentClientMonitor::AssignmentClientMonitor(int &argc, char **argv, const unsigned int numAssignmentClientForks) : QCoreApplication(argc, argv) { // start the Logging class with the parent's target name @@ -41,11 +45,25 @@ AssignmentClientMonitor::AssignmentClientMonitor(int &argc, char **argv, int num // this removes both the "-n" parameter and the number of forks passed _childArguments.removeAt(forksParameterIndex); _childArguments.removeAt(forksParameterIndex); + + + // create a NodeList so we can receive stats from children + DependencyManager::registerInheritance(); + auto addressManager = DependencyManager::set(); + auto nodeList = DependencyManager::set(DEFAULT_ASSIGNMENT_CLIENT_MONITOR_PORT, + DEFAULT_ASSIGNMENT_CLIENT_MONITOR_DTLS_PORT); + + connect(&nodeList->getNodeSocket(), &QUdpSocket::readyRead, this, &AssignmentClientMonitor::readPendingDatagrams); + + nodeList->putLocalPortIntoSharedMemory(ASSIGNMENT_CLIENT_MONITOR_LOCAL_PORT_SMEM_KEY, this); // use QProcess to fork off a process for each of the child assignment clients - for (int i = 0; i < numAssignmentClientForks; i++) { + for (unsigned int i = 0; i < numAssignmentClientForks; i++) { spawnChildClient(); } + + connect(&_checkSparesTimer, SIGNAL(timeout()), SLOT(checkSpares())); + _checkSparesTimer.start(NODE_SILENCE_THRESHOLD_MSECS * 3); } AssignmentClientMonitor::~AssignmentClientMonitor() { @@ -53,46 +71,122 @@ AssignmentClientMonitor::~AssignmentClientMonitor() { } void AssignmentClientMonitor::stopChildProcesses() { - - QList >::Iterator it = _childProcesses.begin(); - while (it != _childProcesses.end()) { - if (!it->isNull()) { - qDebug() << "Monitor is terminating child process" << it->data(); - - // don't re-spawn this child when it goes down - disconnect(it->data(), 0, this, 0); - - it->data()->terminate(); - it->data()->waitForFinished(); - } - - it = _childProcesses.erase(it); - } + auto nodeList = DependencyManager::get(); + + nodeList->eachNode([&](const SharedNodePointer& node) { + qDebug() << "asking child" << node->getUUID() << "to exit."; + node->activateLocalSocket(); + QByteArray diePacket = byteArrayWithPopulatedHeader(PacketTypeStopNode); + nodeList->writeUnverifiedDatagram(diePacket, *node->getActiveSocket()); + }); } void AssignmentClientMonitor::spawnChildClient() { QProcess *assignmentClient = new QProcess(this); - _childProcesses.append(QPointer(assignmentClient)); - // make sure that the output from the child process appears in our output assignmentClient->setProcessChannelMode(QProcess::ForwardedChannels); assignmentClient->start(applicationFilePath(), _childArguments); - - // link the child processes' finished slot to our childProcessFinished slot - connect(assignmentClient, SIGNAL(finished(int, QProcess::ExitStatus)), this, - SLOT(childProcessFinished(int, QProcess::ExitStatus))); - + qDebug() << "Spawned a child client with PID" << assignmentClient->pid(); } -void AssignmentClientMonitor::childProcessFinished(int exitCode, QProcess::ExitStatus exitStatus) { - qDebug("Replacing dead child assignment client with a new one"); - - // remove the old process from our list of child processes - qDebug() << "need to remove" << QPointer(qobject_cast(sender())); - _childProcesses.removeOne(QPointer(qobject_cast(sender()))); - - spawnChildClient(); + + +void AssignmentClientMonitor::checkSpares() { + auto nodeList = DependencyManager::get(); + QUuid aSpareId = ""; + unsigned int spareCount = 0; + + nodeList->removeSilentNodes(); + + nodeList->eachNode([&](const SharedNodePointer& node) { + AssignmentClientChildData *childData = static_cast(node->getLinkedData()); + if (childData->getChildType() == "none") { + spareCount ++; + aSpareId = node->getUUID(); + } + }); + + if (spareCount != 1) { + qDebug() << "spare count is" << spareCount; + } + + if (spareCount < 1) { + spawnChildClient(); + } + + if (spareCount > 1) { + // 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(); + + 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()->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(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); + } + } + } +} + + diff --git a/assignment-client/src/AssignmentClientMonitor.h b/assignment-client/src/AssignmentClientMonitor.h index 9a7bca9cb3..71ae34bc8c 100644 --- a/assignment-client/src/AssignmentClientMonitor.h +++ b/assignment-client/src/AssignmentClientMonitor.h @@ -15,25 +15,30 @@ #include #include #include +#include #include +#include "AssignmentClientChildData.h" + extern const char* NUM_FORKS_PARAMETER; + class AssignmentClientMonitor : public QCoreApplication { Q_OBJECT public: - AssignmentClientMonitor(int &argc, char **argv, int numAssignmentClientForks); + AssignmentClientMonitor(int &argc, char **argv, const unsigned int numAssignmentClientForks); ~AssignmentClientMonitor(); void stopChildProcesses(); private slots: - void childProcessFinished(int exitCode, QProcess::ExitStatus exitStatus); + void readPendingDatagrams(); + void checkSpares(); + private: void spawnChildClient(); - QList > _childProcesses; - QStringList _childArguments; + QTimer _checkSparesTimer; // every few seconds see if it need fewer or more spare children }; #endif // hifi_AssignmentClientMonitor_h diff --git a/assignment-client/src/main.cpp b/assignment-client/src/main.cpp index 3bf6990a74..81a12526bf 100644 --- a/assignment-client/src/main.cpp +++ b/assignment-client/src/main.cpp @@ -9,34 +9,10 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -#include -#include -#include "Assignment.h" -#include "AssignmentClient.h" -#include "AssignmentClientMonitor.h" +#include "AssignmentClientApp.h" int main(int argc, char* argv[]) { -#ifndef WIN32 - setvbuf(stdout, NULL, _IOLBF, 0); -#endif - - // use the verbose message handler in Logging - qInstallMessageHandler(LogHandler::verboseMessageHandler); - - const char* numForksString = getCmdOption(argc, (const char**)argv, NUM_FORKS_PARAMETER); - - int numForks = 0; - - if (numForksString) { - numForks = atoi(numForksString); - } - - if (numForks) { - AssignmentClientMonitor monitor(argc, argv, numForks); - return monitor.exec(); - } else { - AssignmentClient client(argc, argv); - return client.exec(); - } + AssignmentClientApp app(argc, argv); + return 0; } diff --git a/domain-server/src/DomainServer.cpp b/domain-server/src/DomainServer.cpp index f84722a438..64e0d335b1 100644 --- a/domain-server/src/DomainServer.cpp +++ b/domain-server/src/DomainServer.cpp @@ -246,19 +246,7 @@ void DomainServer::setupNodeListAndAssignments(const QUuid& sessionUUID) { auto nodeList = DependencyManager::set(domainServerPort, domainServerDTLSPort); // no matter the local port, save it to shared mem so that local assignment clients can ask what it is - QSharedMemory* sharedPortMem = new QSharedMemory(DOMAIN_SERVER_LOCAL_PORT_SMEM_KEY, this); - quint16 localPort = nodeList->getNodeSocket().localPort(); - - // attempt to create the shared memory segment - if (sharedPortMem->create(sizeof(localPort)) || sharedPortMem->attach()) { - sharedPortMem->lock(); - memcpy(sharedPortMem->data(), &localPort, sizeof(localPort)); - sharedPortMem->unlock(); - - qDebug() << "Wrote local listening port" << localPort << "to shared memory at key" << DOMAIN_SERVER_LOCAL_PORT_SMEM_KEY; - } else { - qWarning() << "Failed to create and attach to shared memory to share local port with assignment-client children."; - } + nodeList->putLocalPortIntoSharedMemory(DOMAIN_SERVER_LOCAL_PORT_SMEM_KEY, this); // 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 diff --git a/libraries/networking/src/AddressManager.cpp b/libraries/networking/src/AddressManager.cpp index 9bcdcbe9a4..f67abdca2b 100644 --- a/libraries/networking/src/AddressManager.cpp +++ b/libraries/networking/src/AddressManager.cpp @@ -76,7 +76,7 @@ const QString AddressManager::currentPath(bool withOrientation) const { pathString += "/" + orientationString; } else { 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; } else { 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(); } } diff --git a/libraries/networking/src/LimitedNodeList.cpp b/libraries/networking/src/LimitedNodeList.cpp index c8c454ff14..b240f0df9e 100644 --- a/libraries/networking/src/LimitedNodeList.cpp +++ b/libraries/networking/src/LimitedNodeList.cpp @@ -669,3 +669,41 @@ void LimitedNodeList::sendHeartbeatToIceServer(const HifiSockAddr& iceServerSock 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; +} diff --git a/libraries/networking/src/LimitedNodeList.h b/libraries/networking/src/LimitedNodeList.h index 72aefdb2b3..02234ee4f7 100644 --- a/libraries/networking/src/LimitedNodeList.h +++ b/libraries/networking/src/LimitedNodeList.h @@ -26,6 +26,7 @@ #include #include #include +#include #include @@ -49,6 +50,11 @@ const char STUN_SERVER_HOSTNAME[] = "stun.highfidelity.io"; const unsigned short STUN_SERVER_PORT = 3478; 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; +const unsigned short DEFAULT_ASSIGNMENT_CLIENT_MONITOR_DTLS_PORT = 40105; class HifiSockAddr; @@ -168,6 +174,9 @@ public: return SharedNodePointer(); } + + void putLocalPortIntoSharedMemory(const QString key, QObject* parent); + bool getLocalServerPortFromSharedMemory(const QString key, QSharedMemory*& sharedMem, quint16& localPort); public slots: void reset(); diff --git a/libraries/networking/src/Node.cpp b/libraries/networking/src/Node.cpp index 2bf792c6ee..2a38799707 100644 --- a/libraries/networking/src/Node.cpp +++ b/libraries/networking/src/Node.cpp @@ -149,7 +149,12 @@ QDataStream& operator>>(QDataStream& in, 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.nospace() << node.getPublicSocket() << "/" << node.getLocalSocket(); return debug.nospace(); diff --git a/libraries/networking/src/NodeList.cpp b/libraries/networking/src/NodeList.cpp index f70c2d9b3c..e63f230f6e 100644 --- a/libraries/networking/src/NodeList.cpp +++ b/libraries/networking/src/NodeList.cpp @@ -62,13 +62,17 @@ NodeList::NodeList(char newOwnerType, unsigned short socketListenPort, unsigned 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); QDataStream statsPacketStream(&statsPacket, QIODevice::Append); 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) { diff --git a/libraries/networking/src/NodeList.h b/libraries/networking/src/NodeList.h index 907fccfcac..1c6de4bb6c 100644 --- a/libraries/networking/src/NodeList.h +++ b/libraries/networking/src/NodeList.h @@ -47,6 +47,7 @@ public: NodeType_t getOwnerType() const { return _ownerType; } void setOwnerType(NodeType_t ownerType) { _ownerType = ownerType; } + qint64 sendStats(const QJsonObject& statsObject, HifiSockAddr destination); qint64 sendStatsToDomainServer(const QJsonObject& statsObject); int getNumNoReplyDomainCheckIns() const { return _numNoReplyDomainCheckIns; } diff --git a/libraries/networking/src/PacketHeaders.cpp b/libraries/networking/src/PacketHeaders.cpp index 2eee540fff..db97e216ee 100644 --- a/libraries/networking/src/PacketHeaders.cpp +++ b/libraries/networking/src/PacketHeaders.cpp @@ -70,6 +70,8 @@ PacketVersion versionForPacketType(PacketType type) { return 2; case PacketTypeOctreeStats: return 1; + case PacketTypeStopNode: + return 1; case PacketTypeEntityAddOrEdit: case PacketTypeEntityData: return VERSION_MODEL_ENTITIES_SUPPORT_SHAPE_TYPE; @@ -124,6 +126,7 @@ QString nameForPacketType(PacketType type) { PACKET_TYPE_NAME_LOOKUP(PacketTypeEntityErase); PACKET_TYPE_NAME_LOOKUP(PacketTypeEntityAddResponse); PACKET_TYPE_NAME_LOOKUP(PacketTypeOctreeDataNack); + PACKET_TYPE_NAME_LOOKUP(PacketTypeStopNode); PACKET_TYPE_NAME_LOOKUP(PacketTypeAudioEnvironment); PACKET_TYPE_NAME_LOOKUP(PacketTypeEntityEditNack); PACKET_TYPE_NAME_LOOKUP(PacketTypeSignedTransactionPayment); diff --git a/libraries/networking/src/PacketHeaders.h b/libraries/networking/src/PacketHeaders.h index e593955b51..32f33c01d9 100644 --- a/libraries/networking/src/PacketHeaders.h +++ b/libraries/networking/src/PacketHeaders.h @@ -67,7 +67,7 @@ enum PacketType { PacketTypeEntityErase, PacketTypeEntityAddResponse, PacketTypeOctreeDataNack, // 45 - UNUSED_10, + PacketTypeStopNode, PacketTypeAudioEnvironment, PacketTypeEntityEditNack, PacketTypeSignedTransactionPayment, @@ -86,7 +86,7 @@ const QSet NON_VERIFIED_PACKETS = QSet() << PacketTypeNodeJsonStats << PacketTypeEntityQuery << PacketTypeOctreeDataNack << PacketTypeEntityEditNack << PacketTypeIceServerHeartbeat << PacketTypeIceServerHeartbeatResponse - << PacketTypeUnverifiedPing << PacketTypeUnverifiedPingReply; + << PacketTypeUnverifiedPing << PacketTypeUnverifiedPingReply << PacketTypeStopNode; const int NUM_BYTES_MD5_HASH = 16; const int NUM_STATIC_HEADER_BYTES = sizeof(PacketVersion) + NUM_BYTES_RFC4122_UUID; From 5c5ffc07ab4830518735f159d9388c74412dadeb Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Tue, 24 Feb 2015 17:43:08 -0800 Subject: [PATCH 03/36] allow client count to drift as needed if the user doesn't specify --min or --max --- .../src/AssignmentClientMonitor.cpp | 24 ++++++++++++------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/assignment-client/src/AssignmentClientMonitor.cpp b/assignment-client/src/AssignmentClientMonitor.cpp index 0f8e7adc17..a3eb5170d5 100644 --- a/assignment-client/src/AssignmentClientMonitor.cpp +++ b/assignment-client/src/AssignmentClientMonitor.cpp @@ -133,17 +133,23 @@ void AssignmentClientMonitor::checkSpares() { } }); - if (spareCount < 1 && totalCount < _maxAssignmentClientForks) { - spawnChildClient(); + // 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) { + if (!_maxAssignmentClientForks || totalCount < _maxAssignmentClientForks) { + spawnChildClient(); + } } - if (spareCount > 1 && 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); + 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); + } } } From 0ce49888ff70885e200a50161a5b513713c276f0 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Wed, 25 Feb 2015 09:20:34 -0800 Subject: [PATCH 04/36] AssignmentClientApp is QCoreApplication, other classes aren't. If --min is set and all the assignment clients exit (probably due to domain server restarting), respawn until --min is statisfied. --- assignment-client/src/AssignmentClient.cpp | 9 ++------- assignment-client/src/AssignmentClient.h | 4 ++-- assignment-client/src/AssignmentClientApp.cpp | 16 ++++++++++++---- .../src/AssignmentClientMonitor.cpp | 8 +++----- assignment-client/src/AssignmentClientMonitor.h | 9 ++++----- 5 files changed, 23 insertions(+), 23 deletions(-) diff --git a/assignment-client/src/AssignmentClient.cpp b/assignment-client/src/AssignmentClient.cpp index cb2da51031..38f5c7cc55 100644 --- a/assignment-client/src/AssignmentClient.cpp +++ b/assignment-client/src/AssignmentClient.cpp @@ -39,19 +39,14 @@ SharedAssignmentPointer AssignmentClient::_currentAssignment; int hifiSockAddrMeta = qRegisterMetaType("HifiSockAddr"); -AssignmentClient::AssignmentClient(int &argc, char **argv, - Assignment::Type requestAssignmentType, QString assignmentPool, QUuid walletUUID, +AssignmentClient::AssignmentClient(Assignment::Type requestAssignmentType, QString assignmentPool, QUuid walletUUID, QString assignmentServerHostname, quint16 assignmentServerPort) : - QCoreApplication(argc, argv), _assignmentServerHostname(DEFAULT_ASSIGNMENT_SERVER_HOSTNAME), _localASPortSharedMem(NULL), _localACMPortSharedMem(NULL) { LogUtils::init(); - setOrganizationName("High Fidelity"); - setOrganizationDomain("highfidelity.io"); - setApplicationName("assignment-client"); QSettings::setDefaultFormat(QSettings::IniFormat); // create a NodeList as an unassigned client @@ -124,7 +119,7 @@ void AssignmentClient::stopAssignmentClient() { qDebug() << "Exiting."; _requestTimer.stop(); _statsTimerACM.stop(); - quit(); + QCoreApplication::quit(); } diff --git a/assignment-client/src/AssignmentClient.h b/assignment-client/src/AssignmentClient.h index 67a5dc89a7..d1d93c78dc 100644 --- a/assignment-client/src/AssignmentClient.h +++ b/assignment-client/src/AssignmentClient.h @@ -18,11 +18,11 @@ class QSharedMemory; -class AssignmentClient : public QCoreApplication { +class AssignmentClient : public QObject { Q_OBJECT public: - AssignmentClient(int &argc, char **argv, Assignment::Type requestAssignmentType, QString assignmentPool, + AssignmentClient(Assignment::Type requestAssignmentType, QString assignmentPool, QUuid walletUUID, QString assignmentServerHostname, quint16 assignmentServerPort); static const SharedAssignmentPointer& getCurrentAssignment() { return _currentAssignment; } diff --git a/assignment-client/src/AssignmentClientApp.cpp b/assignment-client/src/AssignmentClientApp.cpp index 7f174f0833..26b6b8675a 100644 --- a/assignment-client/src/AssignmentClientApp.cpp +++ b/assignment-client/src/AssignmentClientApp.cpp @@ -28,6 +28,10 @@ AssignmentClientApp::AssignmentClientApp(int argc, char* argv[]) : setvbuf(stdout, NULL, _IOLBF, 0); # endif + setOrganizationName("High Fidelity"); + setOrganizationDomain("highfidelity.io"); + setApplicationName("assignment-client"); + // use the verbose message handler in Logging qInstallMessageHandler(LogHandler::verboseMessageHandler); @@ -97,6 +101,10 @@ AssignmentClientApp::AssignmentClientApp(int argc, char* argv[]) : 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)) { @@ -165,12 +173,12 @@ AssignmentClientApp::AssignmentClientApp(int argc, char* argv[]) : if (numForks || minForks || maxForks) { - AssignmentClientMonitor monitor(argc, argv, numForks, minForks, maxForks, assignmentPool, + AssignmentClientMonitor monitor(numForks, minForks, maxForks, assignmentPool, walletUUID, assignmentServerHostname, assignmentServerPort); - monitor.exec(); + exec(); } else { - AssignmentClient client(argc, argv, requestAssignmentType, assignmentPool, + AssignmentClient client(requestAssignmentType, assignmentPool, walletUUID, assignmentServerHostname, assignmentServerPort); - client.exec(); + exec(); } } diff --git a/assignment-client/src/AssignmentClientMonitor.cpp b/assignment-client/src/AssignmentClientMonitor.cpp index a3eb5170d5..29fda05ee1 100644 --- a/assignment-client/src/AssignmentClientMonitor.cpp +++ b/assignment-client/src/AssignmentClientMonitor.cpp @@ -25,13 +25,11 @@ const char* NUM_FORKS_PARAMETER = "-n"; const QString ASSIGNMENT_CLIENT_MONITOR_TARGET_NAME = "assignment-client-monitor"; -AssignmentClientMonitor::AssignmentClientMonitor(int &argc, char **argv, - const unsigned int numAssignmentClientForks, +AssignmentClientMonitor::AssignmentClientMonitor(const unsigned int numAssignmentClientForks, const unsigned int minAssignmentClientForks, const unsigned int maxAssignmentClientForks, QString assignmentPool, QUuid walletUUID, QString assignmentServerHostname, quint16 assignmentServerPort) : - QCoreApplication(argc, argv), _numAssignmentClientForks(numAssignmentClientForks), _minAssignmentClientForks(minAssignmentClientForks), _maxAssignmentClientForks(maxAssignmentClientForks), @@ -109,7 +107,7 @@ void AssignmentClientMonitor::spawnChildClient() { // make sure that the output from the child process appears in our output assignmentClient->setProcessChannelMode(QProcess::ForwardedChannels); - assignmentClient->start(applicationFilePath(), _childArguments); + assignmentClient->start(QCoreApplication::applicationFilePath(), _childArguments); qDebug() << "Spawned a child client with PID" << assignmentClient->pid(); } @@ -135,7 +133,7 @@ void AssignmentClientMonitor::checkSpares() { // 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) { + if (spareCount < 1 || totalCount < _minAssignmentClientForks) { if (!_maxAssignmentClientForks || totalCount < _maxAssignmentClientForks) { spawnChildClient(); } diff --git a/assignment-client/src/AssignmentClientMonitor.h b/assignment-client/src/AssignmentClientMonitor.h index e40a10014b..dc88bfcd95 100644 --- a/assignment-client/src/AssignmentClientMonitor.h +++ b/assignment-client/src/AssignmentClientMonitor.h @@ -24,13 +24,12 @@ extern const char* NUM_FORKS_PARAMETER; -class AssignmentClientMonitor : public QCoreApplication { +class AssignmentClientMonitor : public QObject { Q_OBJECT public: - AssignmentClientMonitor(int &argc, char **argv, const unsigned int numAssignmentClientForks, - const unsigned int minAssignmentClientForks, const unsigned int maxAssignmentClientForks, - QString assignmentPool, QUuid walletUUID, QString assignmentServerHostname, - quint16 assignmentServerPort); + AssignmentClientMonitor(const unsigned int numAssignmentClientForks, const unsigned int minAssignmentClientForks, + const unsigned int maxAssignmentClientForks, QString assignmentPool, QUuid walletUUID, + QString assignmentServerHostname, quint16 assignmentServerPort); ~AssignmentClientMonitor(); void stopChildProcesses(); From 6b29e314c20b672cf83a870724f966d2ad250357 Mon Sep 17 00:00:00 2001 From: Sam Gateau Date: Wed, 25 Feb 2015 19:05:27 -0800 Subject: [PATCH 05/36] Adding the Stage of the Scene and exposing control of the sun light from javascript --- interface/src/Application.cpp | 15 +- libraries/gpu/src/gpu/Context.h | 2 +- libraries/gpu/src/gpu/GLBackend.h | 4 +- libraries/model/src/model/Stage.cpp | 442 ++++++++++++++++++ libraries/model/src/model/Stage.h | 200 ++++++++ .../src/SceneScriptingInterface.cpp | 36 ++ .../src/SceneScriptingInterface.h | 43 ++ libraries/script-engine/src/ScriptEngine.cpp | 5 + 8 files changed, 741 insertions(+), 6 deletions(-) create mode 100644 libraries/model/src/model/Stage.cpp create mode 100644 libraries/model/src/model/Stage.h create mode 100644 libraries/script-engine/src/SceneScriptingInterface.cpp create mode 100644 libraries/script-engine/src/SceneScriptingInterface.h diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index a7e73da1bd..9b27c6c570 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -82,6 +82,8 @@ #include #include +#include + #include "Application.h" #include "AudioClient.h" #include "InterfaceVersion.h" @@ -2495,7 +2497,10 @@ void Application::loadViewFrustum(Camera& camera, ViewFrustum& viewFrustum) { glm::vec3 Application::getSunDirection() { // Sun direction is in fact just the location of the sun relative to the origin - return glm::normalize(_environment.getClosestData(_myCamera.getPosition()).getSunLocation(_myCamera.getPosition())); + // return glm::normalize(_environment.getClosestData(_myCamera.getPosition()).getSunLocation(_myCamera.getPosition())); + + auto skyStage = DependencyManager::get()->getSkyStage(); + return skyStage->getSunLight()->getDirection(); } void Application::updateShadowMap() { @@ -2505,7 +2510,7 @@ void Application::updateShadowMap() { glEnable(GL_DEPTH_TEST); glClear(GL_DEPTH_BUFFER_BIT); - glm::vec3 lightDirection = -getSunDirection(); + glm::vec3 lightDirection = getSunDirection(); glm::quat rotation = rotationBetween(IDENTITY_FRONT, lightDirection); glm::quat inverseRotation = glm::inverse(rotation); @@ -2875,7 +2880,11 @@ void Application::displaySide(Camera& theCamera, bool selfAvatarOnly, RenderArgs { DependencyManager::get()->setAmbientLightMode(getRenderAmbientLight()); - DependencyManager::get()->setGlobalLight(-getSunDirection(), GLOBAL_LIGHT_COLOR, GLOBAL_LIGHT_INTENSITY); + // DependencyManager::get()->setGlobalLight(-getSunDirection(), GLOBAL_LIGHT_COLOR, GLOBAL_LIGHT_INTENSITY); + auto skyStage = DependencyManager::get()->getSkyStage(); +// DependencyManager::get()->setGlobalLight(-getSunDirection(), GLOBAL_LIGHT_COLOR, skyStage->_light->getIntensity()); + DependencyManager::get()->setGlobalLight(skyStage->getSunLight()->getDirection(), skyStage->getSunLight()->getColor(), skyStage->getSunLight()->getIntensity()); + PROFILE_RANGE("DeferredLighting"); PerformanceTimer perfTimer("lighting"); DependencyManager::get()->render(); diff --git a/libraries/gpu/src/gpu/Context.h b/libraries/gpu/src/gpu/Context.h index b8cba3ded1..8140c91bf6 100644 --- a/libraries/gpu/src/gpu/Context.h +++ b/libraries/gpu/src/gpu/Context.h @@ -21,7 +21,7 @@ namespace gpu { class GPUObject { public: GPUObject() {} - ~GPUObject() {} + virtual ~GPUObject() {} }; class Batch; diff --git a/libraries/gpu/src/gpu/GLBackend.h b/libraries/gpu/src/gpu/GLBackend.h index e3450ae71a..806ba0b1eb 100644 --- a/libraries/gpu/src/gpu/GLBackend.h +++ b/libraries/gpu/src/gpu/GLBackend.h @@ -32,7 +32,7 @@ public: static void checkGLError(); - class GLBuffer { + class GLBuffer : public GPUObject { public: Stamp _stamp; GLuint _buffer; @@ -44,7 +44,7 @@ public: static void syncGPUObject(const Buffer& buffer); static GLuint getBufferID(const Buffer& buffer); - class GLTexture { + class GLTexture : public GPUObject { public: Stamp _storageStamp; Stamp _contentStamp; diff --git a/libraries/model/src/model/Stage.cpp b/libraries/model/src/model/Stage.cpp new file mode 100644 index 0000000000..64aa504965 --- /dev/null +++ b/libraries/model/src/model/Stage.cpp @@ -0,0 +1,442 @@ +// +// 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 +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)); + _surfaceSunDir = glm::normalize(Vec3(lssd.x, lssd.y, lssd.z)); +} + + +float moduloRange(float val, float minVal, float maxVal) { + float range = maxVal - minVal; + float rval = (val - minVal) / range; + float intval; + return modf(rval, &intval) * range + minVal; +} + +void EarthSunModel::setLatitude(float lat) { + _latitude = moduloRange(lat, -90.0f, 90.0f); + invalidate(); +} +void EarthSunModel::setLongitude(float lon) { + _longitude = moduloRange(lon, -180.0f, 180.0f); + invalidate(); +} +void EarthSunModel::setAltitude(float altitude) { + _altitude = moduloRange(altitude, -1000.f, 100000.f); + invalidate(); +} + +void EarthSunModel::setSunLatitude(float lat) { + _sunLatitude = moduloRange(lat, -90.0f, 90.0f); + invalidate(); +} +void EarthSunModel::setSunLongitude(float lon) { + _sunLongitude = moduloRange(lon, -180.0f, 180.0f); + invalidate(); +} + +const int NUM_DAYS_PER_YEAR = 365; +const float NUM_HOURS_PER_DAY = 24.0f; + +SunSkyStage::SunSkyStage() : + _sunLight(new Light()) +{ + _sunLight->setType(Light::SUN); + + setSunIntensity(1.0f); + setSunColor(Vec3(1.0f, 1.0f, 1.0f)); + + // setOriginLocation(45.0f, 20.0f, 1.0f); + setDayTime(18.0f); + 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::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); +} + +void SunSkyStage::updateGraphicsObject() const { + // Always update the sunLongitude based on the current dayTIme and the current origin + _earthSunModel.setSunLongitude(_earthSunModel.getLongitude() + (-180.0 + 360.0 * _dayTime / NUM_HOURS_PER_DAY)); + + // And update the sunLAtitude as the declinaison depending of the time of the year + _earthSunModel.setSunLatitude(-(23.0 + 44.0/60.0)*cos(glm::radians((360.0/365.0)*(_yearTime + 10)))); + + Vec3d sunLightDir = -_earthSunModel.getSurfaceSunDir(); + + _sunLight->setDirection(Vec3(sunLightDir.x, sunLightDir.y, sunLightDir.z)); +} + + + + + + +// +// Environment.cpp +// interface/src +// +// Created by Andrzej Kapolka on 5/6/13. +// Copyright 2013 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#include "InterfaceConfig.h" + +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "Application.h" +#include "Camera.h" +#include "world.h" + +#include "Environment.h" + +uint qHash(const HifiSockAddr& sockAddr) { + if (sockAddr.getAddress().isNull()) { + return 0; // shouldn't happen, but if it does, zero is a perfectly valid hash + } + quint32 address = sockAddr.getAddress().toIPv4Address(); + return sockAddr.getPort() + qHash(QByteArray::fromRawData((char*) &address, + sizeof(address))); +} + +Environment::Environment() + : _initialized(false) { +} + +Environment::~Environment() { + if (_initialized) { + delete _skyFromAtmosphereProgram; + delete _skyFromSpaceProgram; + } +} + +void Environment::init() { + if (_initialized) { + qDebug("[ERROR] Environment is already initialized."); + return; + } + + _skyFromAtmosphereProgram = createSkyProgram("Atmosphere", _skyFromAtmosphereUniformLocations); + _skyFromSpaceProgram = createSkyProgram("Space", _skyFromSpaceUniformLocations); + + // start off with a default-constructed environment data + _data[HifiSockAddr()][0]; + + _initialized = true; +} + +void Environment::resetToDefault() { + _data.clear(); + _data[HifiSockAddr()][0]; +} + +void Environment::renderAtmospheres(Camera& camera) { + // get the lock for the duration of the call + QMutexLocker locker(&_mutex); + + foreach (const ServerData& serverData, _data) { + // TODO: do something about EnvironmentData + foreach (const EnvironmentData& environmentData, serverData) { + renderAtmosphere(camera, environmentData); + } + } +} + +glm::vec3 Environment::getGravity (const glm::vec3& position) { + // + // 'Default' gravity pulls you downward in Y when you are near the X/Z plane + const glm::vec3 DEFAULT_GRAVITY(0.0f, -1.0f, 0.0f); + glm::vec3 gravity(DEFAULT_GRAVITY); + float DEFAULT_SURFACE_RADIUS = 30.0f; + float gravityStrength; + + // Weaken gravity with height + if (position.y > 0.0f) { + gravityStrength = 1.0f / powf((DEFAULT_SURFACE_RADIUS + position.y) / DEFAULT_SURFACE_RADIUS, 2.0f); + gravity *= gravityStrength; + } + + // get the lock for the duration of the call + QMutexLocker locker(&_mutex); + + foreach (const ServerData& serverData, _data) { + foreach (const EnvironmentData& environmentData, serverData) { + glm::vec3 vector = environmentData.getAtmosphereCenter(position) - position; + float surfaceRadius = environmentData.getAtmosphereInnerRadius(); + if (glm::length(vector) <= surfaceRadius) { + // At or inside a planet, gravity is as set for the planet + gravity += glm::normalize(vector) * environmentData.getGravity(); + } else { + // Outside a planet, the gravity falls off with distance + gravityStrength = 1.0f / powf(glm::length(vector) / surfaceRadius, 2.0f); + gravity += glm::normalize(vector) * environmentData.getGravity() * gravityStrength; + } + } + } + + return gravity; +} + +const EnvironmentData Environment::getClosestData(const glm::vec3& position) { + // get the lock for the duration of the call + QMutexLocker locker(&_mutex); + + EnvironmentData closest; + float closestDistance = FLT_MAX; + foreach (const ServerData& serverData, _data) { + foreach (const EnvironmentData& environmentData, serverData) { + float distance = glm::distance(position, environmentData.getAtmosphereCenter(position)) - + environmentData.getAtmosphereOuterRadius(); + if (distance < closestDistance) { + closest = environmentData; + closestDistance = distance; + } + } + } + return closest; +} + +bool Environment::findCapsulePenetration(const glm::vec3& start, const glm::vec3& end, + float radius, glm::vec3& penetration) { + // collide with the "floor" + bool found = findCapsulePlanePenetration(start, end, radius, glm::vec4(0.0f, 1.0f, 0.0f, 0.0f), penetration); + + glm::vec3 middle = (start + end) * 0.5f; + + // get the lock for the duration of the call + QMutexLocker locker(&_mutex); + + foreach (const ServerData& serverData, _data) { + foreach (const EnvironmentData& environmentData, serverData) { + if (environmentData.getGravity() == 0.0f) { + continue; // don't bother colliding with gravity-less environments + } + glm::vec3 environmentPenetration; + if (findCapsuleSpherePenetration(start, end, radius, environmentData.getAtmosphereCenter(middle), + environmentData.getAtmosphereInnerRadius(), environmentPenetration)) { + penetration = addPenetrations(penetration, environmentPenetration); + found = true; + } + } + } + return found; +} + +int Environment::parseData(const HifiSockAddr& senderAddress, const QByteArray& packet) { + // push past the packet header + int bytesRead = numBytesForPacketHeader(packet); + + // push past flags, sequence, timestamp + bytesRead += sizeof(OCTREE_PACKET_FLAGS); + bytesRead += sizeof(OCTREE_PACKET_SEQUENCE); + bytesRead += sizeof(OCTREE_PACKET_SENT_TIME); + + // get the lock for the duration of the call + QMutexLocker locker(&_mutex); + + EnvironmentData newData; + while (bytesRead < packet.size()) { + int dataLength = newData.parseData(reinterpret_cast(packet.data()) + bytesRead, + packet.size() - bytesRead); + + // update the mapping by address/ID + _data[senderAddress][newData.getID()] = newData; + + bytesRead += dataLength; + } + + // remove the default mapping, if any + _data.remove(HifiSockAddr()); + + return bytesRead; +} + +ProgramObject* Environment::createSkyProgram(const char* from, int* locations) { + ProgramObject* program = new ProgramObject(); + QByteArray prefix = QString(PathUtils::resourcesPath() + "/shaders/SkyFrom" + from).toUtf8(); + program->addShaderFromSourceFile(QGLShader::Vertex, prefix + ".vert"); + program->addShaderFromSourceFile(QGLShader::Fragment, prefix + ".frag"); + program->link(); + + locations[CAMERA_POS_LOCATION] = program->uniformLocation("v3CameraPos"); + locations[LIGHT_POS_LOCATION] = program->uniformLocation("v3LightPos"); + locations[INV_WAVELENGTH_LOCATION] = program->uniformLocation("v3InvWavelength"); + locations[CAMERA_HEIGHT2_LOCATION] = program->uniformLocation("fCameraHeight2"); + locations[OUTER_RADIUS_LOCATION] = program->uniformLocation("fOuterRadius"); + locations[OUTER_RADIUS2_LOCATION] = program->uniformLocation("fOuterRadius2"); + locations[INNER_RADIUS_LOCATION] = program->uniformLocation("fInnerRadius"); + locations[KR_ESUN_LOCATION] = program->uniformLocation("fKrESun"); + locations[KM_ESUN_LOCATION] = program->uniformLocation("fKmESun"); + locations[KR_4PI_LOCATION] = program->uniformLocation("fKr4PI"); + locations[KM_4PI_LOCATION] = program->uniformLocation("fKm4PI"); + locations[SCALE_LOCATION] = program->uniformLocation("fScale"); + locations[SCALE_DEPTH_LOCATION] = program->uniformLocation("fScaleDepth"); + locations[SCALE_OVER_SCALE_DEPTH_LOCATION] = program->uniformLocation("fScaleOverScaleDepth"); + locations[G_LOCATION] = program->uniformLocation("g"); + locations[G2_LOCATION] = program->uniformLocation("g2"); + + return program; +} + +void Environment::renderAtmosphere(Camera& camera, const EnvironmentData& data) { + glm::vec3 center = data.getAtmosphereCenter(camera.getPosition()); + + glPushMatrix(); + glTranslatef(center.x, center.y, center.z); + + glm::vec3 relativeCameraPos = camera.getPosition() - center; + float height = glm::length(relativeCameraPos); + + // use the appropriate shader depending on whether we're inside or outside + ProgramObject* program; + int* locations; + if (height < data.getAtmosphereOuterRadius()) { + program = _skyFromAtmosphereProgram; + locations = _skyFromAtmosphereUniformLocations; + + } else { + program = _skyFromSpaceProgram; + locations = _skyFromSpaceUniformLocations; + } + + // the constants here are from Sean O'Neil's GPU Gems entry + // (http://http.developer.nvidia.com/GPUGems2/gpugems2_chapter16.html), GameEngine.cpp + program->bind(); + program->setUniform(locations[CAMERA_POS_LOCATION], relativeCameraPos); + glm::vec3 lightDirection = glm::normalize(data.getSunLocation()); + program->setUniform(locations[LIGHT_POS_LOCATION], lightDirection); + program->setUniformValue(locations[INV_WAVELENGTH_LOCATION], + 1 / powf(data.getScatteringWavelengths().r, 4.0f), + 1 / powf(data.getScatteringWavelengths().g, 4.0f), + 1 / powf(data.getScatteringWavelengths().b, 4.0f)); + program->setUniformValue(locations[CAMERA_HEIGHT2_LOCATION], height * height); + program->setUniformValue(locations[OUTER_RADIUS_LOCATION], data.getAtmosphereOuterRadius()); + program->setUniformValue(locations[OUTER_RADIUS2_LOCATION], data.getAtmosphereOuterRadius() * data.getAtmosphereOuterRadius()); + program->setUniformValue(locations[INNER_RADIUS_LOCATION], data.getAtmosphereInnerRadius()); + program->setUniformValue(locations[KR_ESUN_LOCATION], data.getRayleighScattering() * data.getSunBrightness()); + program->setUniformValue(locations[KM_ESUN_LOCATION], data.getMieScattering() * data.getSunBrightness()); + program->setUniformValue(locations[KR_4PI_LOCATION], data.getRayleighScattering() * 4.0f * PI); + program->setUniformValue(locations[KM_4PI_LOCATION], data.getMieScattering() * 4.0f * PI); + program->setUniformValue(locations[SCALE_LOCATION], 1.0f / (data.getAtmosphereOuterRadius() - data.getAtmosphereInnerRadius())); + program->setUniformValue(locations[SCALE_DEPTH_LOCATION], 0.25f); + program->setUniformValue(locations[SCALE_OVER_SCALE_DEPTH_LOCATION], + (1.0f / (data.getAtmosphereOuterRadius() - data.getAtmosphereInnerRadius())) / 0.25f); + program->setUniformValue(locations[G_LOCATION], -0.990f); + program->setUniformValue(locations[G2_LOCATION], -0.990f * -0.990f); + + glDepthMask(GL_FALSE); + glDisable(GL_DEPTH_TEST); + DependencyManager::get()->renderSphere(1.0f, 100, 50, glm::vec4(1.0f, 1.0f, 1.0f, 1.0f)); //Draw a unit sphere + glDepthMask(GL_TRUE); + + program->release(); + + glPopMatrix(); +} diff --git a/libraries/model/src/model/Stage.h b/libraries/model/src/model/Stage.h new file mode 100644 index 0000000000..9b2922e163 --- /dev/null +++ b/libraries/model/src/model/Stage.h @@ -0,0 +1,200 @@ +// +// 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: + enum Preset + { + Toulouse = 0, + SanFrancisco, + Sydney, + Num_Presets, + }; + static const std::string PresetNames[Num_Presets]; + //void assignPreset( Preset p); + //Preset preset() const { return mPreset; } + + 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; } + + 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; + + 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); +}; + +namespace gpu { + class Batch; +}; + +class ProgramObject; + +class Skybox { +public: + void recordBatch(gpu::Batch& batch, const Transform& viewTransform, const Mat4& projection); + + Skybox(); + ~Skybox(); +protected: + ProgramObject* createSkyProgram(const char* from, int* locations); + ProgramObject* _skyFromAtmosphereProgram; + ProgramObject* _skyFromSpaceProgram; + enum { + CAMERA_POS_LOCATION, + LIGHT_POS_LOCATION, + INV_WAVELENGTH_LOCATION, + CAMERA_HEIGHT2_LOCATION, + OUTER_RADIUS_LOCATION, + OUTER_RADIUS2_LOCATION, + INNER_RADIUS_LOCATION, + KR_ESUN_LOCATION, + KM_ESUN_LOCATION, + KR_4PI_LOCATION, + KM_4PI_LOCATION, + SCALE_LOCATION, + SCALE_DEPTH_LOCATION, + SCALE_OVER_SCALE_DEPTH_LOCATION, + G_LOCATION, + G2_LOCATION, + LOCATION_COUNT + }; + + int _skyFromAtmosphereUniformLocations[LOCATION_COUNT]; + int _skyFromSpaceUniformLocations[LOCATION_COUNT]; +}; + +// 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; } + + // 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; + + // default day is 1st of january at noun + float _dayTime = 12.0f; + int _yearTime = 0; + + 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 diff --git a/libraries/script-engine/src/SceneScriptingInterface.cpp b/libraries/script-engine/src/SceneScriptingInterface.cpp new file mode 100644 index 0000000000..ff255a3e5e --- /dev/null +++ b/libraries/script-engine/src/SceneScriptingInterface.cpp @@ -0,0 +1,36 @@ +// +// 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 + +#include "SceneScriptingInterface.h" + + Q_INVOKABLE void setOriginGeoLocation(float longitude, float latitude, float altitude); +void SceneScriptingInterface::setOriginLocation(float longitude, float latitude, float altitude) { + _skyStage->setOriginLocation(longitude, latitude, altitude); +} +void SceneScriptingInterface::setSunColor(const glm::vec3& color) { + _skyStage->setSunColor(color); +} +void SceneScriptingInterface::setSunIntensity(float intensity) { + _skyStage->setSunIntensity(intensity); +} + +void SceneScriptingInterface::setDayTime(float hour) { + _skyStage->setDayTime(hour); +} +void SceneScriptingInterface::setYearTime(int day) { + _skyStage->setYearTime(day); +} + +model::SunSkyStagePointer SceneScriptingInterface::getSkyStage() const { + return _skyStage; +} \ No newline at end of file diff --git a/libraries/script-engine/src/SceneScriptingInterface.h b/libraries/script-engine/src/SceneScriptingInterface.h new file mode 100644 index 0000000000..3fc909f9a0 --- /dev/null +++ b/libraries/script-engine/src/SceneScriptingInterface.h @@ -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 + +#include + +#include "model/Stage.h" + +class SceneScriptingInterface : public QObject, public Dependency { + Q_OBJECT + SINGLETON_DEPENDENCY + +public: + Q_INVOKABLE void setOriginLocation(float longitude, float latitude, float altitude); + + Q_INVOKABLE void setSunColor(const glm::vec3& color); + Q_INVOKABLE void setSunIntensity(float intensity); + + Q_INVOKABLE void setDayTime(float hour); + Q_INVOKABLE void setYearTime(int day); + + model::SunSkyStagePointer getSkyStage() const; + +protected: + SceneScriptingInterface() {}; + ~SceneScriptingInterface() {}; + + model::SunSkyStagePointer _skyStage = model::SunSkyStagePointer(new model::SunSkyStage()); +}; + +#endif // hifi_SceneScriptingInterface_h diff --git a/libraries/script-engine/src/ScriptEngine.cpp b/libraries/script-engine/src/ScriptEngine.cpp index 0956374238..aed5d91410 100644 --- a/libraries/script-engine/src/ScriptEngine.cpp +++ b/libraries/script-engine/src/ScriptEngine.cpp @@ -39,6 +39,8 @@ #include "TypedArrays.h" #include "XMLHttpRequestClass.h" +#include "SceneScriptingInterface.h" + #include "MIDIEvent.h" EntityScriptingInterface ScriptEngine::_entityScriptingInterface; @@ -208,6 +210,8 @@ void ScriptEngine::init() { _isInitialized = true; + auto sceneScriptingInterface = DependencyManager::set(); + _entityScriptingInterface.init(); // register various meta-types @@ -251,6 +255,7 @@ void ScriptEngine::init() { registerGlobalObject("Vec3", &_vec3Library); registerGlobalObject("Uuid", &_uuidLibrary); registerGlobalObject("AnimationCache", DependencyManager::get().data()); + registerGlobalObject("Scene", DependencyManager::get().data()); // constants globalObject().setProperty("TREE_SCALE", newVariant(QVariant(TREE_SCALE))); From b4cb5ca9d1e455ec7425a950259bdbc7bb65c9f7 Mon Sep 17 00:00:00 2001 From: Sam Gateau Date: Wed, 25 Feb 2015 19:09:18 -0800 Subject: [PATCH 06/36] add an example script to control the sun light --- examples/example/misc/sunLightExample.js | 32 ++++++++++++++++++++++++ 1 file changed, 32 insertions(+) create mode 100644 examples/example/misc/sunLightExample.js diff --git a/examples/example/misc/sunLightExample.js b/examples/example/misc/sunLightExample.js new file mode 100644 index 0000000000..0bc3b0dfea --- /dev/null +++ b/examples/example/misc/sunLightExample.js @@ -0,0 +1,32 @@ +// +// 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 = 0.0; +var latitude = -45.0; + +Scene.setDayTime(hour); +Scene.setOriginLocation(longitude, latitude, 0.0); + +function ticktack() { + hour += 0.1; + //Scene.setSunIntensity(Math.cos(time)); + if (hour > 24.0) { + hour = 0.0; + day++; + Scene.setYearTime(day); + } + Scene.setDayTime(hour); + +} + +Script.setInterval(ticktack, 41); From 4959e2924e0bd00ab17ed7812763c35cfae5300b Mon Sep 17 00:00:00 2001 From: Sam Gateau Date: Wed, 25 Feb 2015 19:17:38 -0800 Subject: [PATCH 07/36] add an example script to control the sun light --- libraries/model/src/model/Stage.cpp | 277 ---------------------------- 1 file changed, 277 deletions(-) diff --git a/libraries/model/src/model/Stage.cpp b/libraries/model/src/model/Stage.cpp index 64aa504965..dcd633f35c 100644 --- a/libraries/model/src/model/Stage.cpp +++ b/libraries/model/src/model/Stage.cpp @@ -163,280 +163,3 @@ void SunSkyStage::updateGraphicsObject() const { _sunLight->setDirection(Vec3(sunLightDir.x, sunLightDir.y, sunLightDir.z)); } - - - - - -// -// Environment.cpp -// interface/src -// -// Created by Andrzej Kapolka on 5/6/13. -// Copyright 2013 High Fidelity, Inc. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// - -#include "InterfaceConfig.h" - -#include -#include -#include - -#include -#include -#include -#include -#include - -#include "Application.h" -#include "Camera.h" -#include "world.h" - -#include "Environment.h" - -uint qHash(const HifiSockAddr& sockAddr) { - if (sockAddr.getAddress().isNull()) { - return 0; // shouldn't happen, but if it does, zero is a perfectly valid hash - } - quint32 address = sockAddr.getAddress().toIPv4Address(); - return sockAddr.getPort() + qHash(QByteArray::fromRawData((char*) &address, - sizeof(address))); -} - -Environment::Environment() - : _initialized(false) { -} - -Environment::~Environment() { - if (_initialized) { - delete _skyFromAtmosphereProgram; - delete _skyFromSpaceProgram; - } -} - -void Environment::init() { - if (_initialized) { - qDebug("[ERROR] Environment is already initialized."); - return; - } - - _skyFromAtmosphereProgram = createSkyProgram("Atmosphere", _skyFromAtmosphereUniformLocations); - _skyFromSpaceProgram = createSkyProgram("Space", _skyFromSpaceUniformLocations); - - // start off with a default-constructed environment data - _data[HifiSockAddr()][0]; - - _initialized = true; -} - -void Environment::resetToDefault() { - _data.clear(); - _data[HifiSockAddr()][0]; -} - -void Environment::renderAtmospheres(Camera& camera) { - // get the lock for the duration of the call - QMutexLocker locker(&_mutex); - - foreach (const ServerData& serverData, _data) { - // TODO: do something about EnvironmentData - foreach (const EnvironmentData& environmentData, serverData) { - renderAtmosphere(camera, environmentData); - } - } -} - -glm::vec3 Environment::getGravity (const glm::vec3& position) { - // - // 'Default' gravity pulls you downward in Y when you are near the X/Z plane - const glm::vec3 DEFAULT_GRAVITY(0.0f, -1.0f, 0.0f); - glm::vec3 gravity(DEFAULT_GRAVITY); - float DEFAULT_SURFACE_RADIUS = 30.0f; - float gravityStrength; - - // Weaken gravity with height - if (position.y > 0.0f) { - gravityStrength = 1.0f / powf((DEFAULT_SURFACE_RADIUS + position.y) / DEFAULT_SURFACE_RADIUS, 2.0f); - gravity *= gravityStrength; - } - - // get the lock for the duration of the call - QMutexLocker locker(&_mutex); - - foreach (const ServerData& serverData, _data) { - foreach (const EnvironmentData& environmentData, serverData) { - glm::vec3 vector = environmentData.getAtmosphereCenter(position) - position; - float surfaceRadius = environmentData.getAtmosphereInnerRadius(); - if (glm::length(vector) <= surfaceRadius) { - // At or inside a planet, gravity is as set for the planet - gravity += glm::normalize(vector) * environmentData.getGravity(); - } else { - // Outside a planet, the gravity falls off with distance - gravityStrength = 1.0f / powf(glm::length(vector) / surfaceRadius, 2.0f); - gravity += glm::normalize(vector) * environmentData.getGravity() * gravityStrength; - } - } - } - - return gravity; -} - -const EnvironmentData Environment::getClosestData(const glm::vec3& position) { - // get the lock for the duration of the call - QMutexLocker locker(&_mutex); - - EnvironmentData closest; - float closestDistance = FLT_MAX; - foreach (const ServerData& serverData, _data) { - foreach (const EnvironmentData& environmentData, serverData) { - float distance = glm::distance(position, environmentData.getAtmosphereCenter(position)) - - environmentData.getAtmosphereOuterRadius(); - if (distance < closestDistance) { - closest = environmentData; - closestDistance = distance; - } - } - } - return closest; -} - -bool Environment::findCapsulePenetration(const glm::vec3& start, const glm::vec3& end, - float radius, glm::vec3& penetration) { - // collide with the "floor" - bool found = findCapsulePlanePenetration(start, end, radius, glm::vec4(0.0f, 1.0f, 0.0f, 0.0f), penetration); - - glm::vec3 middle = (start + end) * 0.5f; - - // get the lock for the duration of the call - QMutexLocker locker(&_mutex); - - foreach (const ServerData& serverData, _data) { - foreach (const EnvironmentData& environmentData, serverData) { - if (environmentData.getGravity() == 0.0f) { - continue; // don't bother colliding with gravity-less environments - } - glm::vec3 environmentPenetration; - if (findCapsuleSpherePenetration(start, end, radius, environmentData.getAtmosphereCenter(middle), - environmentData.getAtmosphereInnerRadius(), environmentPenetration)) { - penetration = addPenetrations(penetration, environmentPenetration); - found = true; - } - } - } - return found; -} - -int Environment::parseData(const HifiSockAddr& senderAddress, const QByteArray& packet) { - // push past the packet header - int bytesRead = numBytesForPacketHeader(packet); - - // push past flags, sequence, timestamp - bytesRead += sizeof(OCTREE_PACKET_FLAGS); - bytesRead += sizeof(OCTREE_PACKET_SEQUENCE); - bytesRead += sizeof(OCTREE_PACKET_SENT_TIME); - - // get the lock for the duration of the call - QMutexLocker locker(&_mutex); - - EnvironmentData newData; - while (bytesRead < packet.size()) { - int dataLength = newData.parseData(reinterpret_cast(packet.data()) + bytesRead, - packet.size() - bytesRead); - - // update the mapping by address/ID - _data[senderAddress][newData.getID()] = newData; - - bytesRead += dataLength; - } - - // remove the default mapping, if any - _data.remove(HifiSockAddr()); - - return bytesRead; -} - -ProgramObject* Environment::createSkyProgram(const char* from, int* locations) { - ProgramObject* program = new ProgramObject(); - QByteArray prefix = QString(PathUtils::resourcesPath() + "/shaders/SkyFrom" + from).toUtf8(); - program->addShaderFromSourceFile(QGLShader::Vertex, prefix + ".vert"); - program->addShaderFromSourceFile(QGLShader::Fragment, prefix + ".frag"); - program->link(); - - locations[CAMERA_POS_LOCATION] = program->uniformLocation("v3CameraPos"); - locations[LIGHT_POS_LOCATION] = program->uniformLocation("v3LightPos"); - locations[INV_WAVELENGTH_LOCATION] = program->uniformLocation("v3InvWavelength"); - locations[CAMERA_HEIGHT2_LOCATION] = program->uniformLocation("fCameraHeight2"); - locations[OUTER_RADIUS_LOCATION] = program->uniformLocation("fOuterRadius"); - locations[OUTER_RADIUS2_LOCATION] = program->uniformLocation("fOuterRadius2"); - locations[INNER_RADIUS_LOCATION] = program->uniformLocation("fInnerRadius"); - locations[KR_ESUN_LOCATION] = program->uniformLocation("fKrESun"); - locations[KM_ESUN_LOCATION] = program->uniformLocation("fKmESun"); - locations[KR_4PI_LOCATION] = program->uniformLocation("fKr4PI"); - locations[KM_4PI_LOCATION] = program->uniformLocation("fKm4PI"); - locations[SCALE_LOCATION] = program->uniformLocation("fScale"); - locations[SCALE_DEPTH_LOCATION] = program->uniformLocation("fScaleDepth"); - locations[SCALE_OVER_SCALE_DEPTH_LOCATION] = program->uniformLocation("fScaleOverScaleDepth"); - locations[G_LOCATION] = program->uniformLocation("g"); - locations[G2_LOCATION] = program->uniformLocation("g2"); - - return program; -} - -void Environment::renderAtmosphere(Camera& camera, const EnvironmentData& data) { - glm::vec3 center = data.getAtmosphereCenter(camera.getPosition()); - - glPushMatrix(); - glTranslatef(center.x, center.y, center.z); - - glm::vec3 relativeCameraPos = camera.getPosition() - center; - float height = glm::length(relativeCameraPos); - - // use the appropriate shader depending on whether we're inside or outside - ProgramObject* program; - int* locations; - if (height < data.getAtmosphereOuterRadius()) { - program = _skyFromAtmosphereProgram; - locations = _skyFromAtmosphereUniformLocations; - - } else { - program = _skyFromSpaceProgram; - locations = _skyFromSpaceUniformLocations; - } - - // the constants here are from Sean O'Neil's GPU Gems entry - // (http://http.developer.nvidia.com/GPUGems2/gpugems2_chapter16.html), GameEngine.cpp - program->bind(); - program->setUniform(locations[CAMERA_POS_LOCATION], relativeCameraPos); - glm::vec3 lightDirection = glm::normalize(data.getSunLocation()); - program->setUniform(locations[LIGHT_POS_LOCATION], lightDirection); - program->setUniformValue(locations[INV_WAVELENGTH_LOCATION], - 1 / powf(data.getScatteringWavelengths().r, 4.0f), - 1 / powf(data.getScatteringWavelengths().g, 4.0f), - 1 / powf(data.getScatteringWavelengths().b, 4.0f)); - program->setUniformValue(locations[CAMERA_HEIGHT2_LOCATION], height * height); - program->setUniformValue(locations[OUTER_RADIUS_LOCATION], data.getAtmosphereOuterRadius()); - program->setUniformValue(locations[OUTER_RADIUS2_LOCATION], data.getAtmosphereOuterRadius() * data.getAtmosphereOuterRadius()); - program->setUniformValue(locations[INNER_RADIUS_LOCATION], data.getAtmosphereInnerRadius()); - program->setUniformValue(locations[KR_ESUN_LOCATION], data.getRayleighScattering() * data.getSunBrightness()); - program->setUniformValue(locations[KM_ESUN_LOCATION], data.getMieScattering() * data.getSunBrightness()); - program->setUniformValue(locations[KR_4PI_LOCATION], data.getRayleighScattering() * 4.0f * PI); - program->setUniformValue(locations[KM_4PI_LOCATION], data.getMieScattering() * 4.0f * PI); - program->setUniformValue(locations[SCALE_LOCATION], 1.0f / (data.getAtmosphereOuterRadius() - data.getAtmosphereInnerRadius())); - program->setUniformValue(locations[SCALE_DEPTH_LOCATION], 0.25f); - program->setUniformValue(locations[SCALE_OVER_SCALE_DEPTH_LOCATION], - (1.0f / (data.getAtmosphereOuterRadius() - data.getAtmosphereInnerRadius())) / 0.25f); - program->setUniformValue(locations[G_LOCATION], -0.990f); - program->setUniformValue(locations[G2_LOCATION], -0.990f * -0.990f); - - glDepthMask(GL_FALSE); - glDisable(GL_DEPTH_TEST); - DependencyManager::get()->renderSphere(1.0f, 100, 50, glm::vec4(1.0f, 1.0f, 1.0f, 1.0f)); //Draw a unit sphere - glDepthMask(GL_TRUE); - - program->release(); - - glPopMatrix(); -} From 0918d4989b342f9380e77dc6cd2e00cbaa0483df Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Thu, 26 Feb 2015 09:53:23 -0800 Subject: [PATCH 08/36] mv ShutdownEventListener into class which is a child of QCoreApplication --- assignment-client/src/AssignmentClientApp.cpp | 8 ++++++++ assignment-client/src/AssignmentClientMonitor.cpp | 8 -------- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/assignment-client/src/AssignmentClientApp.cpp b/assignment-client/src/AssignmentClientApp.cpp index 26b6b8675a..6e269f35b7 100644 --- a/assignment-client/src/AssignmentClientApp.cpp +++ b/assignment-client/src/AssignmentClientApp.cpp @@ -14,6 +14,7 @@ #include #include #include +#include #include "Assignment.h" #include "AssignmentClient.h" @@ -173,6 +174,13 @@ AssignmentClientApp::AssignmentClientApp(int argc, char* argv[]) : if (numForks || minForks || maxForks) { + // setup a shutdown event listener to handle SIGTERM or WM_CLOSE for us +# ifdef _WIN32 + installNativeEventFilter(&ShutdownEventListener::getInstance()); +# else + ShutdownEventListener::getInstance(); +# endif + AssignmentClientMonitor monitor(numForks, minForks, maxForks, assignmentPool, walletUUID, assignmentServerHostname, assignmentServerPort); exec(); diff --git a/assignment-client/src/AssignmentClientMonitor.cpp b/assignment-client/src/AssignmentClientMonitor.cpp index 29fda05ee1..ffc402c04d 100644 --- a/assignment-client/src/AssignmentClientMonitor.cpp +++ b/assignment-client/src/AssignmentClientMonitor.cpp @@ -12,7 +12,6 @@ #include #include -#include #include #include "AssignmentClientMonitor.h" @@ -40,13 +39,6 @@ AssignmentClientMonitor::AssignmentClientMonitor(const unsigned int numAssignmen { // start the Logging class with the parent's target name LogHandler::getInstance().setTargetName(ASSIGNMENT_CLIENT_MONITOR_TARGET_NAME); - - // setup a shutdown event listener to handle SIGTERM or WM_CLOSE for us -#ifdef _WIN32 - installNativeEventFilter(&ShutdownEventListener::getInstance()); -#else - ShutdownEventListener::getInstance(); -#endif // create a NodeList so we can receive stats from children DependencyManager::registerInheritance(); From 7c7d727b55a878d4a3610dff083be0067502f5cb Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Thu, 26 Feb 2015 10:07:48 -0800 Subject: [PATCH 09/36] mv ShutdownEventListener into class which is a child of QCoreApplication --- assignment-client/src/AssignmentClient.cpp | 7 ------- assignment-client/src/AssignmentClientApp.cpp | 15 +++++++++------ 2 files changed, 9 insertions(+), 13 deletions(-) diff --git a/assignment-client/src/AssignmentClient.cpp b/assignment-client/src/AssignmentClient.cpp index 38f5c7cc55..86680d2f03 100644 --- a/assignment-client/src/AssignmentClient.cpp +++ b/assignment-client/src/AssignmentClient.cpp @@ -58,13 +58,6 @@ AssignmentClient::AssignmentClient(Assignment::Type requestAssignmentType, QStri // when the domain server hands over an assignment. QUuid nodeUUID = QUuid::createUuid(); nodeList->setSessionUUID(nodeUUID); - - // setup a shutdown event listener to handle SIGTERM or WM_CLOSE for us -#ifdef _WIN32 - installNativeEventFilter(&ShutdownEventListener::getInstance()); -#else - ShutdownEventListener::getInstance(); -#endif // set the logging target to the the CHILD_TARGET_NAME LogHandler::getInstance().setTargetName(ASSIGNMENT_CLIENT_TARGET_NAME); diff --git a/assignment-client/src/AssignmentClientApp.cpp b/assignment-client/src/AssignmentClientApp.cpp index 6e269f35b7..7c6fb50db2 100644 --- a/assignment-client/src/AssignmentClientApp.cpp +++ b/assignment-client/src/AssignmentClientApp.cpp @@ -29,6 +29,14 @@ AssignmentClientApp::AssignmentClientApp(int argc, char* argv[]) : setvbuf(stdout, NULL, _IOLBF, 0); # endif + +# ifdef _WIN32 + installNativeEventFilter(&ShutdownEventListener::getInstance()); +# else + ShutdownEventListener::getInstance(); +# endif + + setOrganizationName("High Fidelity"); setOrganizationDomain("highfidelity.io"); setApplicationName("assignment-client"); @@ -175,16 +183,11 @@ AssignmentClientApp::AssignmentClientApp(int argc, char* argv[]) : if (numForks || minForks || maxForks) { // setup a shutdown event listener to handle SIGTERM or WM_CLOSE for us -# ifdef _WIN32 - installNativeEventFilter(&ShutdownEventListener::getInstance()); -# else - ShutdownEventListener::getInstance(); -# endif - AssignmentClientMonitor monitor(numForks, minForks, maxForks, assignmentPool, walletUUID, assignmentServerHostname, assignmentServerPort); exec(); } else { + // setup a shutdown event listener to handle SIGTERM or WM_CLOSE for us AssignmentClient client(requestAssignmentType, assignmentPool, walletUUID, assignmentServerHostname, assignmentServerPort); exec(); From 8eb4abc49cb8c23c344be69a2e50e813b6b32bf2 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Thu, 26 Feb 2015 19:14:09 +0100 Subject: [PATCH 10/36] Rework FaceTracker --- interface/src/devices/FaceTracker.cpp | 5 ++--- interface/src/devices/FaceTracker.h | 24 +++++++++++++++++------- 2 files changed, 19 insertions(+), 10 deletions(-) diff --git a/interface/src/devices/FaceTracker.cpp b/interface/src/devices/FaceTracker.cpp index 52fe04de77..8d61789715 100644 --- a/interface/src/devices/FaceTracker.cpp +++ b/interface/src/devices/FaceTracker.cpp @@ -11,7 +11,6 @@ #include "FaceTracker.h" -FaceTracker::FaceTracker() : - _estimatedEyePitch(0.0f), - _estimatedEyeYaw(0.0f) { +inline float FaceTracker::getBlendshapeCoefficient(int index) const { + return isValidBlendshapeIndex(index) ? _blendshapeCoefficients[index] : 0.0f; } diff --git a/interface/src/devices/FaceTracker.h b/interface/src/devices/FaceTracker.h index 7c367b7899..07c479e3e3 100644 --- a/interface/src/devices/FaceTracker.h +++ b/interface/src/devices/FaceTracker.h @@ -18,13 +18,17 @@ #include #include -/// Base class for face trackers (Faceshift, Visage). +/// Base class for face trackers (Faceshift, Visage, DDE). class FaceTracker : public QObject { Q_OBJECT public: - FaceTracker(); - virtual ~FaceTracker() {} + virtual bool isActive() const { return false; } + virtual bool isTracking() const { return false; } + + virtual void init() {} + virtual void update(float deltaTime) {} + virtual void reset() {} const glm::vec3& getHeadTranslation() const { return _headTranslation; } const glm::quat& getHeadRotation() const { return _headRotation; } @@ -32,15 +36,21 @@ public: float getEstimatedEyePitch() const { return _estimatedEyePitch; } float getEstimatedEyeYaw() const { return _estimatedEyeYaw; } + int getNumBlendshapes() const { return _blendshapeCoefficients.size(); } + bool isValidBlendshapeIndex(int index) const { return index >= 0 && index < getNumBlendshapes(); } const QVector& getBlendshapeCoefficients() const { return _blendshapeCoefficients; } + float getBlendshapeCoefficient(int index) const; protected: - glm::vec3 _headTranslation; - glm::quat _headRotation; - float _estimatedEyePitch; - float _estimatedEyeYaw; + + glm::vec3 _headTranslation = glm::vec3(0.0f); + glm::quat _headRotation = glm::quat(); + float _estimatedEyePitch = 0.0f; + float _estimatedEyeYaw = 0.0f; QVector _blendshapeCoefficients; + + float _fadeCoefficient = 0.0f; }; #endif // hifi_FaceTracker_h From b6968a6b1538875504b4f90b6d71038b13b75850 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Thu, 26 Feb 2015 19:15:49 +0100 Subject: [PATCH 11/36] Update Facetrackers --- interface/src/devices/DdeFaceTracker.cpp | 18 +---- interface/src/devices/DdeFaceTracker.h | 10 ++- interface/src/devices/Faceshift.cpp | 73 ++++++------------- interface/src/devices/Faceshift.h | 89 ++++++++++++------------ interface/src/devices/Visage.cpp | 3 +- interface/src/devices/Visage.h | 10 +-- 6 files changed, 77 insertions(+), 126 deletions(-) diff --git a/interface/src/devices/DdeFaceTracker.cpp b/interface/src/devices/DdeFaceTracker.cpp index 87a180bd1e..ed0e4057ef 100644 --- a/interface/src/devices/DdeFaceTracker.cpp +++ b/interface/src/devices/DdeFaceTracker.cpp @@ -50,6 +50,8 @@ DdeFaceTracker::DdeFaceTracker() : } DdeFaceTracker::DdeFaceTracker(const QHostAddress& host, quint16 port) : + _host(host), + _port(port), _lastReceiveTimestamp(0), _reset(false), _leftBlinkIndex(0), // see http://support.faceshift.com/support/articles/35129-export-of-blendshapes @@ -63,9 +65,7 @@ DdeFaceTracker::DdeFaceTracker(const QHostAddress& host, quint16 port) : _browUpRightIndex(18), _mouthSmileLeftIndex(28), _mouthSmileRightIndex(29), - _jawOpenIndex(21), - _host(host), - _port(port) + _jawOpenIndex(21) { _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) { // isOpen() does not work as one might expect on QUdpSocket; don't test isOpen() before closing socket. _udpSocket.close(); diff --git a/interface/src/devices/DdeFaceTracker.h b/interface/src/devices/DdeFaceTracker.h index bd5d066732..88528370a2 100644 --- a/interface/src/devices/DdeFaceTracker.h +++ b/interface/src/devices/DdeFaceTracker.h @@ -23,12 +23,10 @@ class DdeFaceTracker : public FaceTracker, public Dependency { SINGLETON_DEPENDENCY public: - //initialization - void init(); - void reset(); - void update(); - - bool isActive() const; + virtual void reset() { _reset = true; } + + virtual bool isActive() const; + virtual bool isTracking() const { return isActive(); } float getLeftBlink() const { return getBlendshapeCoefficient(_leftBlinkIndex); } float getRightBlink() const { return getBlendshapeCoefficient(_rightBlinkIndex); } diff --git a/interface/src/devices/Faceshift.cpp b/interface/src/devices/Faceshift.cpp index 2f541c1c4e..87ee0ef31c 100644 --- a/interface/src/devices/Faceshift.cpp +++ b/interface/src/devices/Faceshift.cpp @@ -25,37 +25,11 @@ using namespace fs; using namespace std; +const QString DEFAULT_FACESHIFT_HOSTNAME = "localhost"; const quint16 FACESHIFT_PORT = 33433; -float STARTING_FACESHIFT_FRAME_TIME = 0.033f; +const float DEFAULT_FACESHIFT_EYE_DEFLECTION = 0.25f; Faceshift::Faceshift() : - _tcpEnabled(true), - _tcpRetryCount(0), - _lastTrackingStateReceived(0), - _averageFrameTime(STARTING_FACESHIFT_FRAME_TIME), - _headAngularVelocity(0), - _headLinearVelocity(0), - _lastHeadTranslation(0), - _filteredHeadTranslation(0), - _eyeGazeLeftPitch(0.0f), - _eyeGazeLeftYaw(0.0f), - _eyeGazeRightPitch(0.0f), - _eyeGazeRightYaw(0.0f), - _leftBlinkIndex(0), // see http://support.faceshift.com/support/articles/35129-export-of-blendshapes - _rightBlinkIndex(1), - _leftEyeOpenIndex(8), - _rightEyeOpenIndex(9), - _browDownLeftIndex(14), - _browDownRightIndex(15), - _browUpCenterIndex(16), - _browUpLeftIndex(17), - _browUpRightIndex(18), - _mouthSmileLeftIndex(28), - _mouthSmileRightIndex(29), - _jawOpenIndex(21), - _longTermAverageEyePitch(0.0f), - _longTermAverageEyeYaw(0.0f), - _longTermAverageInitialized(false), _eyeDeflection("faceshiftEyeDeflection", DEFAULT_FACESHIFT_EYE_DEFLECTION), _hostname("faceshiftHostname", DEFAULT_FACESHIFT_HOSTNAME) { @@ -71,31 +45,15 @@ Faceshift::Faceshift() : #endif } +#ifdef HAVE_FACESHIFT void Faceshift::init() { -#ifdef HAVE_FACESHIFT setTCPEnabled(Menu::getInstance()->isOptionChecked(MenuOption::Faceshift)); -#endif } -bool Faceshift::isConnectedOrConnecting() const { - return _tcpSocket.state() == QAbstractSocket::ConnectedState || - (_tcpRetryCount == 0 && _tcpSocket.state() != QAbstractSocket::UnconnectedState); -} - -bool Faceshift::isActive() const { -#ifdef HAVE_FACESHIFT - const quint64 ACTIVE_TIMEOUT_USECS = 1000000; - return (usecTimestampNow() - _lastTrackingStateReceived) < ACTIVE_TIMEOUT_USECS; -#else - return false; -#endif -} - -void Faceshift::update() { +void Faceshift::update(float deltaTime) { if (!isActive()) { return; } - PerformanceTimer perfTimer("faceshift"); // get the euler angles relative to the window glm::vec3 eulers = glm::degrees(safeEulerAngles(_headRotation * glm::quat(glm::radians(glm::vec3( (_eyeGazeLeftPitch + _eyeGazeRightPitch) / 2.0f, (_eyeGazeLeftYaw + _eyeGazeRightYaw) / 2.0f, 0.0f))))); @@ -116,14 +74,28 @@ void Faceshift::update() { } void Faceshift::reset() { -#ifdef HAVE_FACESHIFT if (_tcpSocket.state() == QAbstractSocket::ConnectedState) { string message; fsBinaryStream::encode_message(message, fsMsgCalibrateNeutral()); send(message); } _longTermAverageInitialized = false; +} + +bool Faceshift::isActive() const { + const quint64 ACTIVE_TIMEOUT_USECS = 1000000; + return (usecTimestampNow() - _lastTrackingStateReceived) < ACTIVE_TIMEOUT_USECS; +} + +bool Faceshift::isTracking() const { + return isActive() && _tracking; +} #endif + + +bool Faceshift::isConnectedOrConnecting() const { + return _tcpSocket.state() == QAbstractSocket::ConnectedState || + (_tcpRetryCount == 0 && _tcpSocket.state() != QAbstractSocket::UnconnectedState); } void Faceshift::updateFakeCoefficients(float leftBlink, float rightBlink, float browUp, @@ -148,12 +120,13 @@ void Faceshift::updateFakeCoefficients(float leftBlink, float rightBlink, float } void Faceshift::setTCPEnabled(bool enabled) { +#ifdef HAVE_FACESHIFT if ((_tcpEnabled = enabled)) { connectSocket(); - } else { _tcpSocket.disconnectFromHost(); } +#endif } void Faceshift::connectSocket() { @@ -202,10 +175,6 @@ void Faceshift::readFromSocket() { receive(_tcpSocket.readAll()); } -float Faceshift::getBlendshapeCoefficient(int index) const { - return (index >= 0 && index < (int)_blendshapeCoefficients.size()) ? _blendshapeCoefficients[index] : 0.0f; -} - void Faceshift::send(const std::string& message) { _tcpSocket.write(message.data(), message.size()); } diff --git a/interface/src/devices/Faceshift.h b/interface/src/devices/Faceshift.h index 0cef3d3e13..f224448b8e 100644 --- a/interface/src/devices/Faceshift.h +++ b/interface/src/devices/Faceshift.h @@ -24,8 +24,7 @@ #include "FaceTracker.h" -const float DEFAULT_FACESHIFT_EYE_DEFLECTION = 0.25f; -const QString DEFAULT_FACESHIFT_HOSTNAME = "localhost"; +const float STARTING_FACESHIFT_FRAME_TIME = 0.033f; /// Handles interaction with the Faceshift software, which provides head position/orientation and facial features. class Faceshift : public FaceTracker, public Dependency { @@ -33,11 +32,17 @@ class Faceshift : public FaceTracker, public Dependency { SINGLETON_DEPENDENCY public: - void init(); +#ifdef HAVE_FACESHIFT + // If we don't have faceshift, use the base class' methods + virtual void init(); + virtual void update(float deltaTime); + virtual void reset(); - bool isConnectedOrConnecting() const; + virtual bool isActive() const; + virtual bool isTracking() const; +#endif - bool isActive() const; + bool isConnectedOrConnecting() const; const glm::vec3& getHeadAngularVelocity() const { return _headAngularVelocity; } @@ -68,9 +73,6 @@ public: QString getHostname() { return _hostname.get(); } void setHostname(const QString& hostname); - - void update(); - void reset(); void updateFakeCoefficients(float leftBlink, float rightBlink, @@ -82,15 +84,12 @@ public: QVector& coefficients) const; signals: - void connectionStateChanged(); public slots: - void setTCPEnabled(bool enabled); private slots: - void connectSocket(); void noteConnected(); void noteError(QAbstractSocket::SocketError error); @@ -101,8 +100,6 @@ private: Faceshift(); virtual ~Faceshift() {} - float getBlendshapeCoefficient(int index) const; - void send(const std::string& message); void receive(const QByteArray& buffer); @@ -113,48 +110,48 @@ private: fs::fsBinaryStream _stream; #endif - bool _tcpEnabled; - int _tcpRetryCount; - bool _tracking; - quint64 _lastTrackingStateReceived; - float _averageFrameTime; + bool _tcpEnabled = true; + int _tcpRetryCount = 0; + bool _tracking = false; + quint64 _lastTrackingStateReceived = 0; + float _averageFrameTime = STARTING_FACESHIFT_FRAME_TIME; - glm::vec3 _headAngularVelocity; - glm::vec3 _headLinearVelocity; - glm::vec3 _lastHeadTranslation; - glm::vec3 _filteredHeadTranslation; + glm::vec3 _headAngularVelocity = glm::vec3(0.0f); + glm::vec3 _headLinearVelocity = glm::vec3(0.0f); + glm::vec3 _lastHeadTranslation = glm::vec3(0.0f); + glm::vec3 _filteredHeadTranslation = glm::vec3(0.0f); // degrees - float _eyeGazeLeftPitch; - float _eyeGazeLeftYaw; - float _eyeGazeRightPitch; - float _eyeGazeRightYaw; - - int _leftBlinkIndex; - int _rightBlinkIndex; - int _leftEyeOpenIndex; - int _rightEyeOpenIndex; - - // Brows - int _browDownLeftIndex; - int _browDownRightIndex; - int _browUpCenterIndex; - int _browUpLeftIndex; - int _browUpRightIndex; - - int _mouthSmileLeftIndex; - int _mouthSmileRightIndex; - - int _jawOpenIndex; + float _eyeGazeLeftPitch = 0.0f; + float _eyeGazeLeftYaw = 0.0f; + float _eyeGazeRightPitch = 0.0f; + float _eyeGazeRightYaw = 0.0f; // degrees - float _longTermAverageEyePitch; - float _longTermAverageEyeYaw; - bool _longTermAverageInitialized; + float _longTermAverageEyePitch = 0.0f; + float _longTermAverageEyeYaw = 0.0f; + bool _longTermAverageInitialized = false; Setting::Handle _eyeDeflection; Setting::Handle _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 diff --git a/interface/src/devices/Visage.cpp b/interface/src/devices/Visage.cpp index 39bda83e61..45c19a6ab3 100644 --- a/interface/src/devices/Visage.cpp +++ b/interface/src/devices/Visage.cpp @@ -126,13 +126,12 @@ void Visage::init() { updateEnabled(); } -void Visage::update() { +void Visage::update(float deltaTime) { #ifdef HAVE_VISAGE _active = (_tracker->getTrackingData(_data) == TRACK_STAT_OK); if (!_active) { return; } - PerformanceTimer perfTimer("visage"); _headRotation = glm::quat(glm::vec3(-_data->faceRotation[0], -_data->faceRotation[1], _data->faceRotation[2])); _headTranslation = (glm::vec3(_data->faceTranslation[0], _data->faceTranslation[1], _data->faceTranslation[2]) - _headOrigin) * TRANSLATION_SCALE; diff --git a/interface/src/devices/Visage.h b/interface/src/devices/Visage.h index 690a9f3066..cd2ec3ecad 100644 --- a/interface/src/devices/Visage.h +++ b/interface/src/devices/Visage.h @@ -31,12 +31,12 @@ class Visage : public FaceTracker, public Dependency { SINGLETON_DEPENDENCY public: - void init(); + virtual void init(); + virtual void update(float deltaTime); + virtual void reset(); - bool isActive() const { return _active; } - - void update(); - void reset(); + virtual bool isActive() const { return _active; } + virtual bool isTracking() const { return isActive(); } public slots: From f560f97c6b5c1ed0b3381a8be5439843caaeec51 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Thu, 26 Feb 2015 19:18:05 +0100 Subject: [PATCH 12/36] Only update active FaceTracker --- interface/src/Application.cpp | 36 ++++------------------------------- interface/src/Application.h | 3 --- 2 files changed, 4 insertions(+), 35 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 0bdd8f8f53..e1b4aa40ea 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -1859,35 +1859,6 @@ void Application::updateMouseRay() { } } -void Application::updateFaceshift() { - bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings); - PerformanceWarning warn(showWarnings, "Application::updateFaceshift()"); - auto faceshift = DependencyManager::get(); - // 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()->update(); -} - -void Application::updateDDE() { - bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings); - PerformanceWarning warn(showWarnings, "Application::updateDDE()"); - - // Update Cara - DependencyManager::get()->update(); -} - void Application::updateMyAvatarLookAtPosition() { PerformanceTimer perfTimer("lookAt"); bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings); @@ -2067,12 +2038,13 @@ void Application::update(float deltaTime) { { PerformanceTimer perfTimer("devices"); DeviceTracker::updateAll(); - updateFaceshift(); - updateVisage(); + FaceTracker* tracker = getActiveFaceTracker(); + if (tracker) { + tracker->update(deltaTime); + } SixenseManager::getInstance().update(deltaTime); JoystickScriptingInterface::getInstance().update(); _prioVR.update(deltaTime); - } // Dispatch input events diff --git a/interface/src/Application.h b/interface/src/Application.h index 9cd19c8259..4a8e712d30 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -421,9 +421,6 @@ private: // Various helper functions called during update() void updateLOD(); void updateMouseRay(); - void updateFaceshift(); - void updateVisage(); - void updateDDE(); void updateMyAvatarLookAtPosition(); void updateThreads(float deltaTime); void updateMetavoxels(float deltaTime); From 682b3f5e61c109a659e8f2ea11a2926b92dc6049 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Thu, 26 Feb 2015 19:18:52 +0100 Subject: [PATCH 13/36] Remove unused angular velocity --- interface/src/avatar/Head.cpp | 1 - interface/src/avatar/Head.h | 4 ---- 2 files changed, 5 deletions(-) diff --git a/interface/src/avatar/Head.cpp b/interface/src/avatar/Head.cpp index 52f1b3ee86..a6458c7a22 100644 --- a/interface/src/avatar/Head.cpp +++ b/interface/src/avatar/Head.cpp @@ -42,7 +42,6 @@ Head::Head(Avatar* owningAvatar) : _mouth2(0.0f), _mouth3(0.0f), _mouth4(0.0f), - _angularVelocity(0,0,0), _renderLookatVectors(false), _saccade(0.0f, 0.0f, 0.0f), _saccadeTarget(0.0f, 0.0f, 0.0f), diff --git a/interface/src/avatar/Head.h b/interface/src/avatar/Head.h index 89eea35903..6c53c2d7aa 100644 --- a/interface/src/avatar/Head.h +++ b/interface/src/avatar/Head.h @@ -55,9 +55,6 @@ public: /// \return orientationBody * orientationBasePitch glm::quat getCameraOrientation () const; - - const glm::vec3& getAngularVelocity() const { return _angularVelocity; } - void setAngularVelocity(glm::vec3 angularVelocity) { _angularVelocity = angularVelocity; } void setCorrectedLookAtPosition(glm::vec3 correctedLookAtPosition); glm::vec3 getCorrectedLookAtPosition(); @@ -130,7 +127,6 @@ private: float _mouth2; float _mouth3; float _mouth4; - glm::vec3 _angularVelocity; bool _renderLookatVectors; glm::vec3 _saccade; glm::vec3 _saccadeTarget; From e37ef226fc6b04378d2d8ce48960dc49d5cd4312 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Thu, 26 Feb 2015 19:21:14 +0100 Subject: [PATCH 14/36] Simplify lookForward compute --- interface/src/avatar/MyAvatar.cpp | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index ba628ea0d4..9cdd38dbc8 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -892,13 +892,7 @@ void MyAvatar::updateLookAtTargetAvatar() { _lookAtTargetAvatar.clear(); _targetAvatarPosition = glm::vec3(0.0f); - glm::quat faceRotation = Application::getInstance()->getViewFrustum()->getOrientation(); - FaceTracker* tracker = Application::getInstance()->getActiveFaceTracker(); - if (tracker) { - // If faceshift or other face tracker in use, add on the actual angle of the head - faceRotation *= tracker->getHeadRotation(); - } - glm::vec3 lookForward = faceRotation * IDENTITY_FRONT; + glm::vec3 lookForward = getHead()->getFinalOrientationInWorldFrame() * IDENTITY_FRONT; glm::vec3 cameraPosition = Application::getInstance()->getCamera()->getPosition(); float smallestAngleTo = glm::radians(Application::getInstance()->getCamera()->getFieldOfView()) / 2.0f; From fcb293d0b2155d4334610dc6448a2073356bbca7 Mon Sep 17 00:00:00 2001 From: Sam Gateau Date: Thu, 26 Feb 2015 10:45:00 -0800 Subject: [PATCH 15/36] CLean up before pr --- examples/example/misc/sunLightExample.js | 1 - interface/src/Application.cpp | 4 -- libraries/model/src/model/Stage.cpp | 56 +++++++++++++++++------- libraries/model/src/model/Stage.h | 55 +---------------------- 4 files changed, 42 insertions(+), 74 deletions(-) diff --git a/examples/example/misc/sunLightExample.js b/examples/example/misc/sunLightExample.js index 0bc3b0dfea..7f38211052 100644 --- a/examples/example/misc/sunLightExample.js +++ b/examples/example/misc/sunLightExample.js @@ -26,7 +26,6 @@ function ticktack() { Scene.setYearTime(day); } Scene.setDayTime(hour); - } Script.setInterval(ticktack, 41); diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 298814f484..46fec006ca 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -2493,8 +2493,6 @@ void Application::loadViewFrustum(Camera& camera, ViewFrustum& viewFrustum) { glm::vec3 Application::getSunDirection() { // Sun direction is in fact just the location of the sun relative to the origin - // return glm::normalize(_environment.getClosestData(_myCamera.getPosition()).getSunLocation(_myCamera.getPosition())); - auto skyStage = DependencyManager::get()->getSkyStage(); return skyStage->getSunLight()->getDirection(); } @@ -2875,9 +2873,7 @@ void Application::displaySide(Camera& theCamera, bool selfAvatarOnly, RenderArgs { DependencyManager::get()->setAmbientLightMode(getRenderAmbientLight()); - // DependencyManager::get()->setGlobalLight(-getSunDirection(), GLOBAL_LIGHT_COLOR, GLOBAL_LIGHT_INTENSITY); auto skyStage = DependencyManager::get()->getSkyStage(); -// DependencyManager::get()->setGlobalLight(-getSunDirection(), GLOBAL_LIGHT_COLOR, skyStage->_light->getIntensity()); DependencyManager::get()->setGlobalLight(skyStage->getSunLight()->getDirection(), skyStage->getSunLight()->getColor(), skyStage->getSunLight()->getIntensity()); PROFILE_RANGE("DeferredLighting"); diff --git a/libraries/model/src/model/Stage.cpp b/libraries/model/src/model/Stage.cpp index dcd633f35c..12ed186cf6 100644 --- a/libraries/model/src/model/Stage.cpp +++ b/libraries/model/src/model/Stage.cpp @@ -21,8 +21,6 @@ void EarthSunModel::updateAll() const { } 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)); @@ -54,9 +52,7 @@ void EarthSunModel::updateWorldToSurface() const { _surfacePos = Vec3d(_surfaceToWorldMat * Vec4d(0.0, 0.0, 0.0, 1.0)); } -void EarthSunModel::updateSurfaceToEye() const -{ - +void EarthSunModel::updateSurfaceToEye() const { _surfaceToEyeMat = glm::inverse(_eyeToSurfaceMat); _worldToEyeMat = _surfaceToEyeMat * _worldToSurfaceMat; _eyeToWorldMat = _surfaceToWorldMat * _eyeToSurfaceMat; @@ -76,8 +72,7 @@ void EarthSunModel::updateSun() const { // 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)); _surfaceSunDir = glm::normalize(Vec3(lssd.x, lssd.y, lssd.z)); -} - +} float moduloRange(float val, float minVal, float maxVal) { float range = maxVal - minVal; @@ -86,30 +81,48 @@ float moduloRange(float val, float minVal, float maxVal) { 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 = moduloRange(lat, -90.0f, 90.0f); + _latitude = validateLatitude(lat); invalidate(); } void EarthSunModel::setLongitude(float lon) { - _longitude = moduloRange(lon, -180.0f, 180.0f); + _longitude = validateLongitude(lon); invalidate(); } void EarthSunModel::setAltitude(float altitude) { - _altitude = moduloRange(altitude, -1000.f, 100000.f); + _altitude = validateAltitude(altitude); invalidate(); } void EarthSunModel::setSunLatitude(float lat) { - _sunLatitude = moduloRange(lat, -90.0f, 90.0f); + _sunLatitude = validateLatitude(lat); invalidate(); } void EarthSunModel::setSunLongitude(float lon) { - _sunLongitude = moduloRange(lon, -180.0f, 180.0f); + _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()) @@ -119,8 +132,11 @@ SunSkyStage::SunSkyStage() : setSunIntensity(1.0f); setSunColor(Vec3(1.0f, 1.0f, 1.0f)); - // setOriginLocation(45.0f, 20.0f, 1.0f); + // Default origin location is a special place in the world... + setOriginLocation(122.407f, 37.777f, 0.03f); + // 6pm setDayTime(18.0f); + // Begining of march setYearTime(60.0f); } @@ -151,12 +167,20 @@ 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 - _earthSunModel.setSunLongitude(_earthSunModel.getLongitude() + (-180.0 + 360.0 * _dayTime / NUM_HOURS_PER_DAY)); + // 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(-(23.0 + 44.0/60.0)*cos(glm::radians((360.0/365.0)*(_yearTime + 10)))); + _earthSunModel.setSunLatitude(evalSunDeclinaison(_yearTime)); Vec3d sunLightDir = -_earthSunModel.getSurfaceSunDir(); diff --git a/libraries/model/src/model/Stage.h b/libraries/model/src/model/Stage.h index 9b2922e163..f99d2c1648 100644 --- a/libraries/model/src/model/Stage.h +++ b/libraries/model/src/model/Stage.h @@ -22,16 +22,6 @@ typedef glm::mat4 Mat4; class EarthSunModel { public: - enum Preset - { - Toulouse = 0, - SanFrancisco, - Sydney, - Num_Presets, - }; - static const std::string PresetNames[Num_Presets]; - //void assignPreset( Preset p); - //Preset preset() const { return mPreset; } void setScale(float scale); float getScale() const { return _scale; } @@ -108,46 +98,6 @@ protected: static Mat4d evalWorldToGeoLocationMat(double longitude, double latitude, double altitude, double scale); }; -namespace gpu { - class Batch; -}; - -class ProgramObject; - -class Skybox { -public: - void recordBatch(gpu::Batch& batch, const Transform& viewTransform, const Mat4& projection); - - Skybox(); - ~Skybox(); -protected: - ProgramObject* createSkyProgram(const char* from, int* locations); - ProgramObject* _skyFromAtmosphereProgram; - ProgramObject* _skyFromSpaceProgram; - enum { - CAMERA_POS_LOCATION, - LIGHT_POS_LOCATION, - INV_WAVELENGTH_LOCATION, - CAMERA_HEIGHT2_LOCATION, - OUTER_RADIUS_LOCATION, - OUTER_RADIUS2_LOCATION, - INNER_RADIUS_LOCATION, - KR_ESUN_LOCATION, - KM_ESUN_LOCATION, - KR_4PI_LOCATION, - KM_4PI_LOCATION, - SCALE_LOCATION, - SCALE_DEPTH_LOCATION, - SCALE_OVER_SCALE_DEPTH_LOCATION, - G_LOCATION, - G2_LOCATION, - LOCATION_COUNT - }; - - int _skyFromAtmosphereUniformLocations[LOCATION_COUNT]; - int _skyFromSpaceUniformLocations[LOCATION_COUNT]; -}; - // Sun sky stage generates the rendering primitives to display a scene realistically // at the specified location and time around earth class SunSkyStage { @@ -181,9 +131,8 @@ public: protected: LightPointer _sunLight; - // default day is 1st of january at noun - float _dayTime = 12.0f; - int _yearTime = 0; + float _dayTime; + int _yearTime; mutable EarthSunModel _earthSunModel; From c3a72574391f35d4c0a6dabfa89fb24117b18b14 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Thu, 26 Feb 2015 11:03:06 -0800 Subject: [PATCH 16/36] Remove unused light properties from entity properties window --- examples/html/entityProperties.html | 70 ++--------------------------- 1 file changed, 4 insertions(+), 66 deletions(-) diff --git a/examples/html/entityProperties.html b/examples/html/entityProperties.html index ad2b359e79..38a2ca5ea8 100644 --- a/examples/html/entityProperties.html +++ b/examples/html/entityProperties.html @@ -132,17 +132,7 @@ var elLightDiffuseGreen = document.getElementById("property-light-diffuse-green"); 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 elLightLinearAttenuation = document.getElementById("property-light-linear-attenuation"); - var elLightQuadraticAttenuation = document.getElementById("property-light-quadratic-attenuation"); var elLightExponent = document.getElementById("property-light-exponent"); var elLightCutoff = document.getElementById("property-light-cutoff"); @@ -294,17 +284,7 @@ elLightDiffuseGreen.value = properties.diffuseColor.green; 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; - elLightLinearAttenuation.value = properties.linearAttenuation; - elLightQuadraticAttenuation.value = properties.quadraticAttenuation; elLightExponent.value = properties.exponent; elLightCutoff.value = properties.cutoff; } @@ -381,21 +361,7 @@ elLightDiffuseGreen.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')); - elLightLinearAttenuation.addEventListener('change', createEmitNumberPropertyUpdateFunction('linearAttenuation')); - elLightQuadraticAttenuation.addEventListener('change', createEmitNumberPropertyUpdateFunction('quadraticAttenuation')); elLightExponent.addEventListener('change', createEmitNumberPropertyUpdateFunction('exponent')); elLightCutoff.addEventListener('change', createEmitNumberPropertyUpdateFunction('cutoff')); @@ -715,7 +681,7 @@
-
Diffuse
+
Color
R
G
@@ -723,47 +689,19 @@
-
Ambient
-
-
R
-
G
-
B
-
-
-
-
Specular
-
-
R
-
G
-
B
-
-
-
-
Constant Attenuation
+
Intensity
-
Linear Attenuation
-
- -
-
-
-
Quadratic Attenuation
-
- -
-
-
-
Exponent
+
Spot Light Exponent
-
Cutoff (degrees)
+
Spot Light Cutoff (degrees)
From e42b708b562d1fc9e7a916c110d7a5c726945305 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Thu, 26 Feb 2015 11:03:47 -0800 Subject: [PATCH 17/36] Update deferredLightingEffect::add*Light methods --- interface/src/avatar/Avatar.cpp | 3 +-- .../src/RenderableLightEntityItem.cpp | 7 +++---- .../src/DeferredLightingEffect.cpp | 21 ++++++++++--------- .../render-utils/src/DeferredLightingEffect.h | 11 ++++------ 4 files changed, 19 insertions(+), 23 deletions(-) diff --git a/interface/src/avatar/Avatar.cpp b/interface/src/avatar/Avatar.cpp index 6dc3d4b339..467f63ccef 100644 --- a/interface/src/avatar/Avatar.cpp +++ b/interface/src/avatar/Avatar.cpp @@ -380,8 +380,7 @@ void Avatar::render(const glm::vec3& cameraPosition, RenderMode renderMode, bool foreach (const AvatarManager::LocalLight& light, DependencyManager::get()->getLocalLights()) { glm::vec3 direction = orientation * light.direction; DependencyManager::get()->addSpotLight(position - direction * distance, - distance * 2.0f, glm::vec3(), light.color, light.color, 1.0f, 0.5f, 0.0f, direction, - LIGHT_EXPONENT, LIGHT_CUTOFF); + distance * 2.0f, light.color, 0.5f, orientation, LIGHT_EXPONENT, LIGHT_CUTOFF); } } diff --git a/libraries/entities-renderer/src/RenderableLightEntityItem.cpp b/libraries/entities-renderer/src/RenderableLightEntityItem.cpp index 1e0a9b6fc7..978ca11d9d 100644 --- a/libraries/entities-renderer/src/RenderableLightEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableLightEntityItem.cpp @@ -48,7 +48,7 @@ void RenderableLightEntityItem::render(RenderArgs* args) { 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 intensity = getConstantAttenuation(); float linearAttenuation = getLinearAttenuation(); float quadraticAttenuation = getQuadraticAttenuation(); float exponent = getExponent(); @@ -56,11 +56,10 @@ void RenderableLightEntityItem::render(RenderArgs* args) { if (_isSpotlight) { DependencyManager::get()->addSpotLight(position, largestDiameter / 2.0f, - ambient, diffuse, specular, constantAttenuation, linearAttenuation, quadraticAttenuation, - direction, exponent, cutoff); + diffuse, intensity, rotation, exponent, cutoff); } else { DependencyManager::get()->addPointLight(position, largestDiameter / 2.0f, - ambient, diffuse, specular, constantAttenuation, linearAttenuation, quadraticAttenuation); + diffuse, intensity); } #ifdef WANT_DEBUG diff --git a/libraries/render-utils/src/DeferredLightingEffect.cpp b/libraries/render-utils/src/DeferredLightingEffect.cpp index 1f5d0ce4c3..5e203b041d 100644 --- a/libraries/render-utils/src/DeferredLightingEffect.cpp +++ b/libraries/render-utils/src/DeferredLightingEffect.cpp @@ -126,15 +126,16 @@ void DeferredLightingEffect::renderSolidCone(float base, float height, int slice releaseSimpleProgram(); } -void DeferredLightingEffect::addPointLight(const glm::vec3& position, float radius, const glm::vec3& ambient, - const glm::vec3& diffuse, const glm::vec3& specular, float constantAttenuation, - float linearAttenuation, float quadraticAttenuation) { - addSpotLight(position, radius, ambient, diffuse, specular, constantAttenuation, linearAttenuation, quadraticAttenuation); +void DeferredLightingEffect::addPointLight(const glm::vec3& position, float radius, const glm::vec3& color, + float intensity) { + addSpotLight(position, radius, color, intensity); } -void DeferredLightingEffect::addSpotLight(const glm::vec3& position, float radius, const glm::vec3& ambient, - const glm::vec3& diffuse, const glm::vec3& specular, float constantAttenuation, float linearAttenuation, - float quadraticAttenuation, const glm::vec3& direction, float exponent, float cutoff) { +// Remove: ambient, specular, *Attenuation, direction +// Add: intensity, radius +// Rename: diffuseColor -> color +void DeferredLightingEffect::addSpotLight(const glm::vec3& position, float radius, const glm::vec3& color, + float intensity, const glm::quat& orientation, float exponent, float cutoff) { int lightID = _pointLights.size() + _spotLights.size() + _globalLights.size(); if (lightID >= _allocatedLights.size()) { @@ -144,8 +145,8 @@ void DeferredLightingEffect::addSpotLight(const glm::vec3& position, float radiu lp->setPosition(position); lp->setMaximumRadius(radius); - lp->setColor(diffuse); - lp->setIntensity(1.0f); + lp->setColor(color); + lp->setIntensity(intensity); //lp->setShowContour(quadraticAttenuation); if (exponent == 0.0f && cutoff == PI) { @@ -153,7 +154,7 @@ void DeferredLightingEffect::addSpotLight(const glm::vec3& position, float radiu _pointLights.push_back(lightID); } else { - lp->setDirection(direction); + lp->setOrientation(orientation); lp->setSpotAngle(cutoff); lp->setSpotExponent(exponent); lp->setType(model::Light::SPOT); diff --git a/libraries/render-utils/src/DeferredLightingEffect.h b/libraries/render-utils/src/DeferredLightingEffect.h index eeb92f19c7..c375f3eb52 100644 --- a/libraries/render-utils/src/DeferredLightingEffect.h +++ b/libraries/render-utils/src/DeferredLightingEffect.h @@ -57,15 +57,12 @@ public: void renderSolidCone(float base, float height, int slices, int stacks); /// 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), - 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 constantAttenuation = 1.0f, float linearAttenuation = 0.0f, float quadraticAttenuation = 0.0f); + void addPointLight(const glm::vec3& position, float radius, const glm::vec3& color = glm::vec3(0.0f, 0.0f, 0.0f), + float intensity = 0.5f); /// 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), - 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 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); + void addSpotLight(const glm::vec3& position, float radius, const glm::vec3& color = 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); /// 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); } From fdf9fdd8778d38263c4c3c17d1228ddeb9e32e9c Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Thu, 26 Feb 2015 20:05:47 +0100 Subject: [PATCH 18/36] Relax head/lean when not tracking --- interface/src/avatar/MyAvatar.cpp | 9 +------- interface/src/devices/FaceTracker.cpp | 30 +++++++++++++++++++++++++++ interface/src/devices/FaceTracker.h | 12 +++++------ interface/src/devices/Faceshift.cpp | 2 ++ interface/src/devices/Visage.cpp | 12 +++++------ interface/src/devices/Visage.h | 6 +++--- 6 files changed, 48 insertions(+), 23 deletions(-) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 9cdd38dbc8..8c4ea73775 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -1158,15 +1158,8 @@ void MyAvatar::updateOrientation(float deltaTime) { pitch *= DEGREES_PER_RADIAN; roll *= DEGREES_PER_RADIAN; - // Record the angular velocity - Head* head = getHead(); - if (deltaTime > 0.0f) { - glm::vec3 angularVelocity(pitch - head->getBasePitch(), yaw - head->getBaseYaw(), roll - head->getBaseRoll()); - angularVelocity *= 1.0f / deltaTime; - head->setAngularVelocity(angularVelocity); - } - //Invert yaw and roll when in mirror mode + Head* head = getHead(); if (Application::getInstance()->getCamera()->getMode() == CAMERA_MODE_MIRROR) { head->setBaseYaw(-yaw); head->setBasePitch(pitch); diff --git a/interface/src/devices/FaceTracker.cpp b/interface/src/devices/FaceTracker.cpp index 8d61789715..e570e39345 100644 --- a/interface/src/devices/FaceTracker.cpp +++ b/interface/src/devices/FaceTracker.cpp @@ -14,3 +14,33 @@ inline float FaceTracker::getBlendshapeCoefficient(int index) const { return isValidBlendshapeIndex(index) ? _blendshapeCoefficients[index] : 0.0f; } + +float FaceTracker::getFadeCoefficient() const { + // TODO: apply exponential relaxation + return _relaxationStatus; +} + +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) { + static const float RELAXATION_TIME = 0.4; // sec + + if (isTracking()) { + if (_relaxationStatus == 1.0f) { + return; + } + _relaxationStatus += deltaTime / RELAXATION_TIME; + } else { + if (_relaxationStatus == 0.0f) { + return; + } + _relaxationStatus -= deltaTime / RELAXATION_TIME; + } + _relaxationStatus = glm::clamp(_relaxationStatus, 0.0f, 1.0f); +} \ No newline at end of file diff --git a/interface/src/devices/FaceTracker.h b/interface/src/devices/FaceTracker.h index 07c479e3e3..89ba1f22f6 100644 --- a/interface/src/devices/FaceTracker.h +++ b/interface/src/devices/FaceTracker.h @@ -27,11 +27,13 @@ public: virtual bool isTracking() const { return false; } virtual void init() {} - virtual void update(float deltaTime) {} + virtual void update(float deltaTime); virtual void reset() {} - const glm::vec3& getHeadTranslation() const { return _headTranslation; } - const glm::quat& getHeadRotation() const { return _headRotation; } + float getFadeCoefficient() const; + + const glm::vec3 getHeadTranslation() const; + const glm::quat getHeadRotation() const; float getEstimatedEyePitch() const { return _estimatedEyePitch; } float getEstimatedEyeYaw() const { return _estimatedEyeYaw; } @@ -42,15 +44,13 @@ public: float getBlendshapeCoefficient(int index) const; protected: - - glm::vec3 _headTranslation = glm::vec3(0.0f); glm::quat _headRotation = glm::quat(); float _estimatedEyePitch = 0.0f; float _estimatedEyeYaw = 0.0f; QVector _blendshapeCoefficients; - float _fadeCoefficient = 0.0f; + float _relaxationStatus = 0.0f; // Between 0.0f and 1.0f }; #endif // hifi_FaceTracker_h diff --git a/interface/src/devices/Faceshift.cpp b/interface/src/devices/Faceshift.cpp index 87ee0ef31c..a2bb4e74a9 100644 --- a/interface/src/devices/Faceshift.cpp +++ b/interface/src/devices/Faceshift.cpp @@ -54,6 +54,8 @@ void Faceshift::update(float deltaTime) { if (!isActive()) { return; } + FaceTracker::update(deltaTime); + // get the euler angles relative to the window glm::vec3 eulers = glm::degrees(safeEulerAngles(_headRotation * glm::quat(glm::radians(glm::vec3( (_eyeGazeLeftPitch + _eyeGazeRightPitch) / 2.0f, (_eyeGazeLeftYaw + _eyeGazeRightYaw) / 2.0f, 0.0f))))); diff --git a/interface/src/devices/Visage.cpp b/interface/src/devices/Visage.cpp index 45c19a6ab3..010b872bc6 100644 --- a/interface/src/devices/Visage.cpp +++ b/interface/src/devices/Visage.cpp @@ -41,7 +41,6 @@ const glm::vec3 DEFAULT_HEAD_ORIGIN(0.0f, 0.0f, 0.7f); Visage::Visage() : _enabled(false), - _active(false), _headOrigin(DEFAULT_HEAD_ORIGIN) { #ifdef HAVE_VISAGE @@ -119,19 +118,20 @@ static const QMultiHash >& getActionUnitNameMap() } #endif -const float TRANSLATION_SCALE = 20.0f; +#ifdef HAVE_VISAGE +const float TRANSLATION_SCALE = 20.0f; void Visage::init() { connect(DependencyManager::get().data(), SIGNAL(connectionStateChanged()), SLOT(updateEnabled())); updateEnabled(); } void Visage::update(float deltaTime) { -#ifdef HAVE_VISAGE - _active = (_tracker->getTrackingData(_data) == TRACK_STAT_OK); - if (!_active) { + if (!isActive()) { return; } + FaceTracker::update(deltaTime); + _headRotation = glm::quat(glm::vec3(-_data->faceRotation[0], -_data->faceRotation[1], _data->faceRotation[2])); _headTranslation = (glm::vec3(_data->faceTranslation[0], _data->faceTranslation[1], _data->faceTranslation[2]) - _headOrigin) * TRANSLATION_SCALE; @@ -163,12 +163,12 @@ void Visage::update(float deltaTime) { } _blendshapeCoefficients[leftEyeBlinkIndex] = 1.0f - _data->eyeClosure[1]; _blendshapeCoefficients[rightEyeBlinkIndex] = 1.0f - _data->eyeClosure[0]; -#endif } void Visage::reset() { _headOrigin += _headTranslation / TRANSLATION_SCALE; } +#endif void Visage::updateEnabled() { setEnabled(Menu::getInstance()->isOptionChecked(MenuOption::Visage) && diff --git a/interface/src/devices/Visage.h b/interface/src/devices/Visage.h index cd2ec3ecad..3ff1ea8c27 100644 --- a/interface/src/devices/Visage.h +++ b/interface/src/devices/Visage.h @@ -31,15 +31,16 @@ class Visage : public FaceTracker, public Dependency { SINGLETON_DEPENDENCY public: +#ifdef HAVE_VISAGE virtual void init(); virtual void update(float deltaTime); virtual void reset(); - virtual bool isActive() const { return _active; } + virtual bool isActive() const { return _tracker->getTrackingData(_data) == TRACK_STAT_OK; } virtual bool isTracking() const { return isActive(); } +#endif public slots: - void updateEnabled(); private: @@ -55,7 +56,6 @@ private: void setEnabled(bool enabled); bool _enabled; - bool _active; glm::vec3 _headOrigin; }; From b04dbf7a34b85ee5c013e12aedd0f66f1f14dbee Mon Sep 17 00:00:00 2001 From: dev Date: Thu, 26 Feb 2015 11:27:40 -0800 Subject: [PATCH 19/36] fixing compilation issue on macos --- libraries/model/src/model/Stage.cpp | 264 ++++++++++++++-------------- 1 file changed, 133 insertions(+), 131 deletions(-) diff --git a/libraries/model/src/model/Stage.cpp b/libraries/model/src/model/Stage.cpp index 12ed186cf6..dd5a44a0cb 100644 --- a/libraries/model/src/model/Stage.cpp +++ b/libraries/model/src/model/Stage.cpp @@ -1,19 +1,21 @@ -// -// 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 -using namespace model; - - +// +// 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 +#include + +using namespace model; + + void EarthSunModel::updateAll() const { updateWorldToSurface(); updateSurfaceToEye(); @@ -72,118 +74,118 @@ void EarthSunModel::updateSun() const { // 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)); _surfaceSunDir = glm::normalize(Vec3(lssd.x, lssd.y, lssd.z)); -} - -float moduloRange(float val, float minVal, float maxVal) { - float range = maxVal - minVal; - float rval = (val - minVal) / range; - float 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); - // 6pm - setDayTime(18.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::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 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); + // 6pm + setDayTime(18.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::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)); +} + From bc8d688cdea8dab4871523a66c6a123198b6ecc2 Mon Sep 17 00:00:00 2001 From: Sam Gateau Date: Thu, 26 Feb 2015 12:04:33 -0800 Subject: [PATCH 20/36] fixing tab maybe --- examples/example/misc/sunLightExample.js | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/examples/example/misc/sunLightExample.js b/examples/example/misc/sunLightExample.js index 7f38211052..bc00a39246 100644 --- a/examples/example/misc/sunLightExample.js +++ b/examples/example/misc/sunLightExample.js @@ -11,21 +11,21 @@ var intensity = 1.0; var day = 0.0; var hour = 12.0; -var longitude = 0.0; -var latitude = -45.0; +var longitude = -115.0; +var latitude = -31.0; Scene.setDayTime(hour); -Scene.setOriginLocation(longitude, latitude, 0.0); +//Scene.setOriginLocation(longitude, latitude, 0.0); function ticktack() { hour += 0.1; - //Scene.setSunIntensity(Math.cos(time)); - if (hour > 24.0) { - hour = 0.0; - day++; - Scene.setYearTime(day); - } - Scene.setDayTime(hour); + //Scene.setSunIntensity(Math.cos(time)); + if (hour > 24.0) { + hour = 0.0; + day++; + Scene.setYearTime(day); + } + Scene.setDayTime(hour); } Script.setInterval(ticktack, 41); From 96d5a2ab4221e214d364e4437374a5059454209f Mon Sep 17 00:00:00 2001 From: Sam Gateau Date: Thu, 26 Feb 2015 12:10:08 -0800 Subject: [PATCH 21/36] fixing tab maybe --- examples/example/misc/sunLightExample.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/example/misc/sunLightExample.js b/examples/example/misc/sunLightExample.js index bc00a39246..47fbb9761e 100644 --- a/examples/example/misc/sunLightExample.js +++ b/examples/example/misc/sunLightExample.js @@ -18,7 +18,7 @@ Scene.setDayTime(hour); //Scene.setOriginLocation(longitude, latitude, 0.0); function ticktack() { - hour += 0.1; + hour += 0.1; //Scene.setSunIntensity(Math.cos(time)); if (hour > 24.0) { hour = 0.0; From 3c5f11e6ed0268115275e8dd297562a102484af2 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Thu, 26 Feb 2015 14:23:11 -0800 Subject: [PATCH 22/36] Add initial support for multi-selection in properties window --- examples/editEntities.js | 31 +++++++++++++++++-------- examples/html/entityProperties.html | 35 ++++++++++++++++++++++++----- 2 files changed, 52 insertions(+), 14 deletions(-) diff --git a/examples/editEntities.js b/examples/editEntities.js index 9b13b167e7..ef6472e4b8 100644 --- a/examples/editEntities.js +++ b/examples/editEntities.js @@ -934,24 +934,37 @@ PropertiesTool = function(opts) { data = { type: 'update', }; - if (selectionManager.hasSelection()) { - data.id = selectionManager.selections[0].id; - data.properties = Entities.getEntityProperties(selectionManager.selections[0]); - data.properties.rotation = Quat.safeEulerAngles(data.properties.rotation); + var selections = []; + for (var i = 0; i < selectionManager.selections.length; i++) { + var entity = {}; + entity.id = selectionManager.selections[i].id; + entity.properties = Entities.getEntityProperties(selectionManager.selections[i]); + entity.properties.rotation = Quat.safeEulerAngles(entity.properties.rotation); + selections.push(entity); } + data.selections = selections; webView.eventBridge.emitScriptEvent(JSON.stringify(data)); }); webView.eventBridge.webEventReceived.connect(function(data) { - print(data); data = JSON.parse(data); if (data.type == "update") { selectionManager.saveProperties(); - if (data.properties.rotation !== undefined) { - var rotation = data.properties.rotation; - data.properties.rotation = Quat.fromPitchYawRollDegrees(rotation.x, rotation.y, rotation.z); + if (selectionManager.selections.length > 1) { + properties = { + locked: data.properties.locked, + visible: data.properties.visible, + }; + for (var i = 0; i < selectionManager.selections.length; i++) { + Entities.editEntity(selectionManager.selections[i], properties); + } + } else { + if (data.properties.rotation !== undefined) { + var rotation = data.properties.rotation; + data.properties.rotation = Quat.fromPitchYawRollDegrees(rotation.x, rotation.y, rotation.z); + } + Entities.editEntity(selectionManager.selections[0], data.properties); } - Entities.editEntity(selectionManager.selections[0], data.properties); pushCommandForSelections(); selectionManager._update(); } else if (data.type == "action") { diff --git a/examples/html/entityProperties.html b/examples/html/entityProperties.html index ad2b359e79..f264b569d6 100644 --- a/examples/html/entityProperties.html +++ b/examples/html/entityProperties.html @@ -171,12 +171,37 @@ EventBridge.scriptEventReceived.connect(function(data) { data = JSON.parse(data); if (data.type == "update") { - if (data.properties === undefined) { - disableChildren(document.getElementById("properties"), 'input'); - } else { - var properties = data.properties; + if (data.selections.length == 0) { + elType.innerHTML = "No Selection"; + elID.innerHTML = ""; + disableChildren(document.getElementById("properties-list"), 'input'); + } else if (data.selections.length > 1) { + var selections = data.selections; - elID.innerHTML = data.id; + var ids = []; + var types = {}; + + for (var i = 0; i < selections.length; i++) { + ids.push(selections[i].id); + var type = selections[i].properties.type; + if (types[type] === undefined) { + types[type] = 0; + } + types[type]++; + } + elID.innerHTML = ids.join("
"); + + 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; From ecc003c5e1885f45f0a7f261d0cb7eeff9fd5384 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Thu, 26 Feb 2015 14:23:25 -0800 Subject: [PATCH 23/36] Adjust colors for disabled input elements --- examples/html/style.css | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/examples/html/style.css b/examples/html/style.css index 7177b8c8ba..0aedc43480 100644 --- a/examples/html/style.css +++ b/examples/html/style.css @@ -189,6 +189,11 @@ input, textarea { font-size: 7.5pt; } +input:disabled, textarea:disabled { + background-color: rgb(102, 102, 102); + color: rgb(160, 160, 160); +} + #properties-list input[type=button] { cursor: pointer; background-color: rgb(51, 102, 102); @@ -199,6 +204,11 @@ input, textarea { color: rgb(204, 204, 204); } +#properties-list input[type=button]:disabled { + background-color: rgb(41, 82, 82); + color: rgb(160, 160, 160); +} + #properties-list .property { padding: 6pt 6pt; border-top: 0.75pt solid rgb(63, 63, 63); From 74bc48ce55049cd0fb4e409d2a3461b4430380e4 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Thu, 26 Feb 2015 14:34:32 -0800 Subject: [PATCH 24/36] Add message to edit entities list for when no entities are nearby --- examples/html/entityList.html | 20 +++++++++++++++----- examples/html/style.css | 8 ++++++++ 2 files changed, 23 insertions(+), 5 deletions(-) diff --git a/examples/html/entityList.html b/examples/html/entityList.html index bbfa4d81b8..bcc1c117ea 100644 --- a/examples/html/entityList.html +++ b/examples/html/entityList.html @@ -20,6 +20,7 @@ elRefresh = document.getElementById("refresh"); elDelete = document.getElementById("delete"); elTeleport = document.getElementById("teleport"); + elNoEntitiesMessage = document.getElementById("no-entities"); document.getElementById("entity-type").onclick = function() { setSortColumn('type'); @@ -155,11 +156,18 @@ } } else if (data.type == "update") { var newEntities = data.entities; - for (var i = 0; i < newEntities.length; i++) { - var id = newEntities[i].id; - addEntity(id, newEntities[i].type, newEntities[i].url); + if (newEntities.length == 0) { + elEntityTable.style.display = "none"; + elNoEntitiesMessage.style.display = "block"; + } else { + elEntityTable.style.display = "table"; + elNoEntitiesMessage.style.display = "none"; + for (var i = 0; i < newEntities.length; i++) { + var id = newEntities[i].id; + addEntity(id, newEntities[i].type, newEntities[i].url); + } + updateSelectedEntities(data.selectedIDs); } - updateSelectedEntities(data.selectedIDs); } }); setTimeout(refreshEntities, 1000); @@ -194,6 +202,8 @@
- +
+ No entities found within 50 meter radius. Try moving to a different location and refreshing. +
diff --git a/examples/html/style.css b/examples/html/style.css index 7177b8c8ba..5d60835e47 100644 --- a/examples/html/style.css +++ b/examples/html/style.css @@ -257,3 +257,11 @@ td { vertical-align: top; } + +#no-entities { + display: none; + font-size: 120%; + padding: 10pt; + font-weight: bold; + font-style: italic; +} From dc2b670fa8e6358a3f60d15ec6133abb67b5a9e2 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Thu, 26 Feb 2015 14:46:05 -0800 Subject: [PATCH 25/36] Remove extraneous comments --- libraries/render-utils/src/DeferredLightingEffect.cpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/libraries/render-utils/src/DeferredLightingEffect.cpp b/libraries/render-utils/src/DeferredLightingEffect.cpp index 5e203b041d..c8ad3711d3 100644 --- a/libraries/render-utils/src/DeferredLightingEffect.cpp +++ b/libraries/render-utils/src/DeferredLightingEffect.cpp @@ -131,9 +131,6 @@ void DeferredLightingEffect::addPointLight(const glm::vec3& position, float radi addSpotLight(position, radius, color, intensity); } -// Remove: ambient, specular, *Attenuation, direction -// Add: intensity, radius -// Rename: diffuseColor -> color void DeferredLightingEffect::addSpotLight(const glm::vec3& position, float radius, const glm::vec3& color, float intensity, const glm::quat& orientation, float exponent, float cutoff) { From d60618a582801b9d9e0e4e4b5c1e07080e58a1b6 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Thu, 26 Feb 2015 14:58:04 -0800 Subject: [PATCH 26/36] Remove unused variables from RenderableLightEntityItem::render --- .../src/RenderableLightEntityItem.cpp | 22 +++++-------------- 1 file changed, 5 insertions(+), 17 deletions(-) diff --git a/libraries/entities-renderer/src/RenderableLightEntityItem.cpp b/libraries/entities-renderer/src/RenderableLightEntityItem.cpp index 978ca11d9d..7f630f1c8c 100644 --- a/libraries/entities-renderer/src/RenderableLightEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableLightEntityItem.cpp @@ -36,30 +36,18 @@ void RenderableLightEntityItem::render(RenderArgs* args) { float diffuseG = getDiffuseColor()[GREEN_INDEX] / MAX_COLOR; float diffuseB = getDiffuseColor()[BLUE_INDEX] / MAX_COLOR; - float ambientR = getAmbientColor()[RED_INDEX] / MAX_COLOR; - float ambientG = getAmbientColor()[GREEN_INDEX] / MAX_COLOR; - float ambientB = getAmbientColor()[BLUE_INDEX] / MAX_COLOR; + glm::vec3 color = glm::vec3(diffuseR, diffuseG, diffuseB); - float specularR = getSpecularColor()[RED_INDEX] / MAX_COLOR; - 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 intensity = getConstantAttenuation(); - float linearAttenuation = getLinearAttenuation(); - float quadraticAttenuation = getQuadraticAttenuation(); float exponent = getExponent(); float cutoff = glm::radians(getCutoff()); if (_isSpotlight) { - DependencyManager::get()->addSpotLight(position, largestDiameter / 2.0f, - diffuse, intensity, rotation, exponent, cutoff); + DependencyManager::get()->addSpotLight(position, largestDiameter / 2.0f, + color, intensity, rotation, exponent, cutoff); } else { - DependencyManager::get()->addPointLight(position, largestDiameter / 2.0f, - diffuse, intensity); + DependencyManager::get()->addPointLight(position, largestDiameter / 2.0f, + color, intensity); } #ifdef WANT_DEBUG From e3b3c8e1ef8f23324f188efd7f01ad5f9e3b34f5 Mon Sep 17 00:00:00 2001 From: Sam Gateau Date: Thu, 26 Feb 2015 16:09:21 -0800 Subject: [PATCH 27/36] Setting the defalt at a better time of the day --- libraries/model/src/model/Stage.cpp | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/libraries/model/src/model/Stage.cpp b/libraries/model/src/model/Stage.cpp index dd5a44a0cb..8befec2ed3 100644 --- a/libraries/model/src/model/Stage.cpp +++ b/libraries/model/src/model/Stage.cpp @@ -136,8 +136,8 @@ SunSkyStage::SunSkyStage() : // Default origin location is a special place in the world... setOriginLocation(122.407f, 37.777f, 0.03f); - // 6pm - setDayTime(18.0f); + // Noun + setDayTime(12.0f); // Begining of march setYearTime(60.0f); } @@ -185,7 +185,10 @@ void SunSkyStage::updateGraphicsObject() const { _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)); + } From c80995170af3a813a8f0885c9c6f825348c9e7c7 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Thu, 26 Feb 2015 17:17:19 -0800 Subject: [PATCH 28/36] -n and -t are okay together --- assignment-client/src/AssignmentClientApp.cpp | 5 ----- 1 file changed, 5 deletions(-) diff --git a/assignment-client/src/AssignmentClientApp.cpp b/assignment-client/src/AssignmentClientApp.cpp index 7c6fb50db2..cea952a806 100644 --- a/assignment-client/src/AssignmentClientApp.cpp +++ b/assignment-client/src/AssignmentClientApp.cpp @@ -120,11 +120,6 @@ AssignmentClientApp::AssignmentClientApp(int argc, char* argv[]) : requestAssignmentType = (Assignment::Type) argumentVariantMap.value(ASSIGNMENT_TYPE_OVERRIDE_OPTION).toInt(); } if (parser.isSet(clientTypeOption)) { - if (numForks || minForks || maxForks) { - qCritical() << "don't use -t with forking mode."; - parser.showHelp(); - Q_UNREACHABLE(); - } requestAssignmentType = (Assignment::Type) parser.value(clientTypeOption).toInt(); } From f6a9bd187090049e807c8ff51e32d3d5647ea276 Mon Sep 17 00:00:00 2001 From: Sam Gateau Date: Thu, 26 Feb 2015 17:26:41 -0800 Subject: [PATCH 29/36] REfining the naming and introducing an orientation offset --- examples/example/misc/sunLightExample.js | 10 ++++++---- libraries/model/src/model/Stage.cpp | 15 ++++++++++++++ libraries/model/src/model/Stage.h | 12 +++++++++++ .../src/SceneScriptingInterface.cpp | 20 +++++++++++-------- .../src/SceneScriptingInterface.h | 8 ++++---- 5 files changed, 49 insertions(+), 16 deletions(-) diff --git a/examples/example/misc/sunLightExample.js b/examples/example/misc/sunLightExample.js index 47fbb9761e..9c58d0bac3 100644 --- a/examples/example/misc/sunLightExample.js +++ b/examples/example/misc/sunLightExample.js @@ -13,9 +13,11 @@ 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.setDayTime(hour); -//Scene.setOriginLocation(longitude, latitude, 0.0); +Scene.setStageDayTime(hour); +Scene.setStageOrientation(stageOrientation); +Scene.setStageLocation(longitude, latitude, 0.0); function ticktack() { hour += 0.1; @@ -23,9 +25,9 @@ function ticktack() { if (hour > 24.0) { hour = 0.0; day++; - Scene.setYearTime(day); + Scene.setStageYearTime(day); } - Scene.setDayTime(hour); + Scene.setStageDayTime(hour); } Script.setInterval(ticktack, 41); diff --git a/libraries/model/src/model/Stage.cpp b/libraries/model/src/model/Stage.cpp index 8befec2ed3..d867056e8a 100644 --- a/libraries/model/src/model/Stage.cpp +++ b/libraries/model/src/model/Stage.cpp @@ -73,9 +73,19 @@ void EarthSunModel::updateSun() const { // 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; @@ -155,6 +165,11 @@ void SunSkyStage::setYearTime(unsigned int day) { 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); diff --git a/libraries/model/src/model/Stage.h b/libraries/model/src/model/Stage.h index f99d2c1648..762e2d9717 100644 --- a/libraries/model/src/model/Stage.h +++ b/libraries/model/src/model/Stage.h @@ -33,6 +33,10 @@ public: 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; } @@ -67,6 +71,8 @@ protected: double _scale = 1000.0; //Km double _earthRadius = 6360.0; + Quat _surfaceOrientation; + double _longitude = 0.0; double _latitude = 0.0; double _altitude = 0.01; @@ -114,6 +120,12 @@ public: 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(); } diff --git a/libraries/script-engine/src/SceneScriptingInterface.cpp b/libraries/script-engine/src/SceneScriptingInterface.cpp index ff255a3e5e..9cac521225 100644 --- a/libraries/script-engine/src/SceneScriptingInterface.cpp +++ b/libraries/script-engine/src/SceneScriptingInterface.cpp @@ -13,10 +13,20 @@ #include "SceneScriptingInterface.h" - Q_INVOKABLE void setOriginGeoLocation(float longitude, float latitude, float altitude); -void SceneScriptingInterface::setOriginLocation(float longitude, float latitude, float altitude) { +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); } @@ -24,12 +34,6 @@ void SceneScriptingInterface::setSunIntensity(float intensity) { _skyStage->setSunIntensity(intensity); } -void SceneScriptingInterface::setDayTime(float hour) { - _skyStage->setDayTime(hour); -} -void SceneScriptingInterface::setYearTime(int day) { - _skyStage->setYearTime(day); -} model::SunSkyStagePointer SceneScriptingInterface::getSkyStage() const { return _skyStage; diff --git a/libraries/script-engine/src/SceneScriptingInterface.h b/libraries/script-engine/src/SceneScriptingInterface.h index 3fc909f9a0..8ae9424c95 100644 --- a/libraries/script-engine/src/SceneScriptingInterface.h +++ b/libraries/script-engine/src/SceneScriptingInterface.h @@ -23,14 +23,14 @@ class SceneScriptingInterface : public QObject, public Dependency { SINGLETON_DEPENDENCY public: - Q_INVOKABLE void setOriginLocation(float longitude, float latitude, float altitude); + 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); - Q_INVOKABLE void setDayTime(float hour); - Q_INVOKABLE void setYearTime(int day); - model::SunSkyStagePointer getSkyStage() const; protected: From b8322556a65a1c3cb2d15eb0de8354191f2d1b17 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Thu, 26 Feb 2015 17:34:24 -0800 Subject: [PATCH 30/36] address code-review comments --- assignment-client/src/AssignmentClientApp.cpp | 7 +------ assignment-client/src/AssignmentClientMonitor.cpp | 6 +++--- libraries/networking/src/LimitedNodeList.h | 1 - 3 files changed, 4 insertions(+), 10 deletions(-) diff --git a/assignment-client/src/AssignmentClientApp.cpp b/assignment-client/src/AssignmentClientApp.cpp index cea952a806..cfb77c8542 100644 --- a/assignment-client/src/AssignmentClientApp.cpp +++ b/assignment-client/src/AssignmentClientApp.cpp @@ -29,14 +29,13 @@ AssignmentClientApp::AssignmentClientApp(int argc, char* argv[]) : 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"); @@ -141,7 +140,6 @@ AssignmentClientApp::AssignmentClientApp(int argc, char* argv[]) : walletUUID = parser.value(walletDestinationOption); } - QString assignmentServerHostname; if (argumentVariantMap.contains(ASSIGNMENT_WALLET_DESTINATION_ID_OPTION)) { assignmentServerHostname = argumentVariantMap.value(CUSTOM_ASSIGNMENT_SERVER_HOSTNAME_OPTION).toString(); @@ -150,7 +148,6 @@ AssignmentClientApp::AssignmentClientApp(int argc, char* argv[]) : 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)) { @@ -177,12 +174,10 @@ AssignmentClientApp::AssignmentClientApp(int argc, char* argv[]) : if (numForks || minForks || maxForks) { - // setup a shutdown event listener to handle SIGTERM or WM_CLOSE for us AssignmentClientMonitor monitor(numForks, minForks, maxForks, assignmentPool, walletUUID, assignmentServerHostname, assignmentServerPort); exec(); } else { - // setup a shutdown event listener to handle SIGTERM or WM_CLOSE for us AssignmentClient client(requestAssignmentType, assignmentPool, walletUUID, assignmentServerHostname, assignmentServerPort); exec(); diff --git a/assignment-client/src/AssignmentClientMonitor.cpp b/assignment-client/src/AssignmentClientMonitor.cpp index ffc402c04d..7517669d0b 100644 --- a/assignment-client/src/AssignmentClientMonitor.cpp +++ b/assignment-client/src/AssignmentClientMonitor.cpp @@ -43,8 +43,7 @@ AssignmentClientMonitor::AssignmentClientMonitor(const unsigned int numAssignmen // create a NodeList so we can receive stats from children DependencyManager::registerInheritance(); auto addressManager = DependencyManager::set(); - auto nodeList = DependencyManager::set(DEFAULT_ASSIGNMENT_CLIENT_MONITOR_PORT, - DEFAULT_ASSIGNMENT_CLIENT_MONITOR_DTLS_PORT); + auto nodeList = DependencyManager::set(DEFAULT_ASSIGNMENT_CLIENT_MONITOR_PORT); connect(&nodeList->getNodeSocket(), &QUdpSocket::readyRead, this, &AssignmentClientMonitor::readPendingDatagrams); @@ -55,7 +54,8 @@ AssignmentClientMonitor::AssignmentClientMonitor(const unsigned int numAssignmen spawnChildClient(); } - connect(&_checkSparesTimer, SIGNAL(timeout()), SLOT(checkSpares())); + connect(&_checkSparesTimer, &QTimer::timeout, this, &AssignmentClientMonitor::checkSpares); + _checkSparesTimer.start(NODE_SILENCE_THRESHOLD_MSECS * 3); } diff --git a/libraries/networking/src/LimitedNodeList.h b/libraries/networking/src/LimitedNodeList.h index 02234ee4f7..afc98de169 100644 --- a/libraries/networking/src/LimitedNodeList.h +++ b/libraries/networking/src/LimitedNodeList.h @@ -54,7 +54,6 @@ const QString ASSIGNMENT_CLIENT_MONITOR_LOCAL_PORT_SMEM_KEY = "assignment-client const char DEFAULT_ASSIGNMENT_CLIENT_MONITOR_HOSTNAME[] = "localhost"; const unsigned short DEFAULT_ASSIGNMENT_CLIENT_MONITOR_PORT = 40104; -const unsigned short DEFAULT_ASSIGNMENT_CLIENT_MONITOR_DTLS_PORT = 40105; class HifiSockAddr; From 74f0d98fd6ff65ae26dfda6374edc03c2a1d5ec9 Mon Sep 17 00:00:00 2001 From: Sam Gateau Date: Thu, 26 Feb 2015 17:44:04 -0800 Subject: [PATCH 31/36] REfining the naming and introducing an orientation offset --- examples/example/misc/sunLightExample.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/example/misc/sunLightExample.js b/examples/example/misc/sunLightExample.js index 9c58d0bac3..93fc06d088 100644 --- a/examples/example/misc/sunLightExample.js +++ b/examples/example/misc/sunLightExample.js @@ -11,8 +11,8 @@ var intensity = 1.0; var day = 0.0; var hour = 12.0; -var longitude = -115.0; -var latitude = -31.0; +var longitude = 115.0; +var latitude = 31.0; var stageOrientation = Quat.fromPitchYawRollDegrees(0.0, 180.0, 0.0); Scene.setStageDayTime(hour); From c7eeebe52cc4b030a6bd6f3436497b4ee8047426 Mon Sep 17 00:00:00 2001 From: Sam Gateau Date: Thu, 26 Feb 2015 18:07:43 -0800 Subject: [PATCH 32/36] and fixing a bug with shadowing of lightmapped surface --- examples/example/misc/sunLightExample.js | 3 ++- libraries/render-utils/src/DeferredGlobalLight.slh | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/examples/example/misc/sunLightExample.js b/examples/example/misc/sunLightExample.js index 93fc06d088..42837c6836 100644 --- a/examples/example/misc/sunLightExample.js +++ b/examples/example/misc/sunLightExample.js @@ -18,7 +18,7 @@ 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)); @@ -31,3 +31,4 @@ function ticktack() { } Script.setInterval(ticktack, 41); +*/ \ No newline at end of file diff --git a/libraries/render-utils/src/DeferredGlobalLight.slh b/libraries/render-utils/src/DeferredGlobalLight.slh index 6868b96c24..0fe2d18e74 100755 --- a/libraries/render-utils/src/DeferredGlobalLight.slh +++ b/libraries/render-utils/src/DeferredGlobalLight.slh @@ -95,7 +95,8 @@ vec3 evalAmbienSphereGlobalColor(float shadowAttenuation, vec3 position, vec3 no vec3 evalLightmappedColor(float shadowAttenuation, vec3 normal, vec3 diffuse, vec3 lightmap) { Light light = getLight(); - float diffuseDot = dot(normal, getLightDirection(light)); + vec3 fragNormal = vec3(invViewMat * vec4(normal, 0.0)); + float diffuseDot = dot(fragNormal, -getLightDirection(light)); // 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 From 9849efe0130082673622349ffc45559e68beafb4 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Fri, 27 Feb 2015 15:33:24 +0100 Subject: [PATCH 33/36] Exponential relaxation --- interface/src/devices/FaceTracker.cpp | 13 +++++++------ interface/src/devices/FaceTracker.h | 1 + 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/interface/src/devices/FaceTracker.cpp b/interface/src/devices/FaceTracker.cpp index e570e39345..f1ab35859b 100644 --- a/interface/src/devices/FaceTracker.cpp +++ b/interface/src/devices/FaceTracker.cpp @@ -16,8 +16,7 @@ inline float FaceTracker::getBlendshapeCoefficient(int index) const { } float FaceTracker::getFadeCoefficient() const { - // TODO: apply exponential relaxation - return _relaxationStatus; + return _fadeCoefficient; } const glm::vec3 FaceTracker::getHeadTranslation() const { @@ -29,18 +28,20 @@ const glm::quat FaceTracker::getHeadRotation() const { } void FaceTracker::update(float deltaTime) { - static const float RELAXATION_TIME = 0.4; // sec + static const float RELAXATION_TIME = 1.0f; // sec + static const float LAMBDA = 1.5; if (isTracking()) { if (_relaxationStatus == 1.0f) { return; } - _relaxationStatus += deltaTime / RELAXATION_TIME; + _relaxationStatus = glm::clamp(_relaxationStatus + deltaTime / RELAXATION_TIME, 0.0f, 1.0f); + _fadeCoefficient = std::exp(-LAMBDA * _relaxationStatus); } else { if (_relaxationStatus == 0.0f) { return; } - _relaxationStatus -= deltaTime / RELAXATION_TIME; + _relaxationStatus = glm::clamp(_relaxationStatus - deltaTime / RELAXATION_TIME, 0.0f, 1.0f); + _fadeCoefficient = 1.0f - std::exp(-LAMBDA * (1.0f - _relaxationStatus)); } - _relaxationStatus = glm::clamp(_relaxationStatus, 0.0f, 1.0f); } \ No newline at end of file diff --git a/interface/src/devices/FaceTracker.h b/interface/src/devices/FaceTracker.h index 89ba1f22f6..1ec0468dec 100644 --- a/interface/src/devices/FaceTracker.h +++ b/interface/src/devices/FaceTracker.h @@ -51,6 +51,7 @@ protected: QVector _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 From 8615bb7cff3a39a37cd50301977e35c58b4bd6d0 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Fri, 27 Feb 2015 15:58:28 +0100 Subject: [PATCH 34/36] Make relaxation go to EPSILON within TIME --- interface/src/devices/FaceTracker.cpp | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/interface/src/devices/FaceTracker.cpp b/interface/src/devices/FaceTracker.cpp index f1ab35859b..d6ccc38a45 100644 --- a/interface/src/devices/FaceTracker.cpp +++ b/interface/src/devices/FaceTracker.cpp @@ -28,20 +28,25 @@ const glm::quat FaceTracker::getHeadRotation() const { } void FaceTracker::update(float deltaTime) { - static const float RELAXATION_TIME = 1.0f; // sec + // Based on exponential distributions: http://en.wikipedia.org/wiki/Exponential_distribution + static const float EPSILON = 0.02f; static const float LAMBDA = 1.5; + static const float INVERSE_AT_EPSILON = -std::log(EPSILON) / LAMBDA; // So that f(1) = EPSILON ~ 0 + 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 = std::exp(-LAMBDA * _relaxationStatus); + _fadeCoefficient = 1.0f - std::exp(-LAMBDA * _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 = 1.0f - std::exp(-LAMBDA * (1.0f - _relaxationStatus)); + _fadeCoefficient = std::exp(-LAMBDA * (1.0f - _relaxationStatus) * INVERSE_AT_EPSILON); } } \ No newline at end of file From db90fcdb6220a7a377cd816d765631230dcbc0a5 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Fri, 27 Feb 2015 16:09:15 +0100 Subject: [PATCH 35/36] Simplify expression --- interface/src/devices/FaceTracker.cpp | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/interface/src/devices/FaceTracker.cpp b/interface/src/devices/FaceTracker.cpp index d6ccc38a45..d3e0600057 100644 --- a/interface/src/devices/FaceTracker.cpp +++ b/interface/src/devices/FaceTracker.cpp @@ -29,9 +29,8 @@ const glm::quat FaceTracker::getHeadRotation() const { void FaceTracker::update(float deltaTime) { // Based on exponential distributions: http://en.wikipedia.org/wiki/Exponential_distribution - static const float EPSILON = 0.02f; - static const float LAMBDA = 1.5; - static const float INVERSE_AT_EPSILON = -std::log(EPSILON) / LAMBDA; // So that f(1) = EPSILON ~ 0 + 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()) { @@ -40,13 +39,13 @@ void FaceTracker::update(float deltaTime) { return; } _relaxationStatus = glm::clamp(_relaxationStatus + deltaTime / RELAXATION_TIME, 0.0f, 1.0f); - _fadeCoefficient = 1.0f - std::exp(-LAMBDA * _relaxationStatus * INVERSE_AT_EPSILON); + _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(-LAMBDA * (1.0f - _relaxationStatus) * INVERSE_AT_EPSILON); + _fadeCoefficient = std::exp(-(1.0f - _relaxationStatus) * INVERSE_AT_EPSILON); } } \ No newline at end of file From 01cac7445a2cee96522e1dd180adf508a35ed40c Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Fri, 27 Feb 2015 10:58:04 -0800 Subject: [PATCH 36/36] add suppressions for log-spam caused by idle assignment-client --- domain-server/src/DomainServer.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/domain-server/src/DomainServer.cpp b/domain-server/src/DomainServer.cpp index 64e0d335b1..9aec456587 100644 --- a/domain-server/src/DomainServer.cpp +++ b/domain-server/src/DomainServer.cpp @@ -32,6 +32,7 @@ #include #include #include +#include #include "DomainServerNodeData.h" @@ -943,8 +944,10 @@ void DomainServer::readAvailableDatagrams() { if (requestAssignment.getType() != Assignment::AgentType || 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() - << "from" << senderSockAddr; + << "from" << senderSockAddr; noisyMessageTimer.restart(); } @@ -974,6 +977,8 @@ void DomainServer::readAvailableDatagrams() { } else { if (requestAssignment.getType() != Assignment::AgentType || 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() << "from" << senderSockAddr; noisyMessageTimer.restart();