mirror of
https://github.com/JulianGro/overte.git
synced 2025-04-14 11:46:34 +02:00
resolve conflicts on merge with upstream/master
This commit is contained in:
commit
5a601f3676
72 changed files with 2088 additions and 842 deletions
1
BUILD.md
1
BUILD.md
|
@ -4,6 +4,7 @@
|
|||
* [Qt](http://qt-project.org/downloads) ~> 5.3.2
|
||||
* [OpenSSL](https://www.openssl.org/related/binaries.html) ~> 1.0.1g
|
||||
* IMPORTANT: OpenSSL 1.0.1g is critical to avoid a security vulnerability.
|
||||
* [VHACD](https://github.com/virneo/v-hacd)(clone this repository)(Optional)
|
||||
|
||||
####CMake External Project Dependencies
|
||||
|
||||
|
|
17
BUILD_WIN.md
17
BUILD_WIN.md
|
@ -14,7 +14,7 @@ Or you can start a regular command prompt and then run:
|
|||
|
||||
If using Visual Studio 2013 and building as a Visual Studio 2013 project you need the Windows 8 SDK which you should already have as part of installing Visual Studio 2013. You should be able to see it at `C:\Program Files (x86)\Windows Kits\8.1\Lib\winv6.3\um\x86`.
|
||||
|
||||
####nmake & msbuild
|
||||
####nmake
|
||||
|
||||
Some of the external projects may require nmake to compile and install. If it is not installed at the location listed below, please ensure that it is in your PATH so CMake can find it when required.
|
||||
|
||||
|
@ -75,6 +75,21 @@ To prevent these problems, install OpenSSL yourself. Download the following bina
|
|||
|
||||
Install OpenSSL into the Windows system directory, to make sure that Qt uses the version that you've just installed, and not some other version.
|
||||
|
||||
###vhacd
|
||||
Download it directly from https://github.com/virneo/v-hacd
|
||||
|
||||
To build it run the following commands
|
||||
1. cd src\
|
||||
2. mkdir build
|
||||
3. cd build
|
||||
4. cmake ..
|
||||
|
||||
Build using visual studio 2013. Build ALL_BUILD and INSTALL targets both in Release and Debug.
|
||||
|
||||
This will create an output folder with include and lib directory inside it.
|
||||
|
||||
Either copy the contents of output folder to ENV %HIFI_LIB_DIR%/vhacd or create an environment variable VHACD_ROOT_DIR to this output directory.
|
||||
|
||||
###Build High Fidelity using Visual Studio
|
||||
Follow the same build steps from the CMake section of [BUILD.md](BUILD.md), but pass a different generator to CMake.
|
||||
|
||||
|
|
|
@ -18,10 +18,9 @@
|
|||
#include <AccountManager.h>
|
||||
#include <AddressManager.h>
|
||||
#include <Assignment.h>
|
||||
#include <AvatarHashMap.h>
|
||||
#include <HifiConfigVariantMap.h>
|
||||
#include <LogHandler.h>
|
||||
#include <LogUtils.h>
|
||||
#include <LimitedNodeList.h>
|
||||
#include <NodeList.h>
|
||||
#include <PacketHeaders.h>
|
||||
#include <SharedUtil.h>
|
||||
|
@ -40,79 +39,43 @@ SharedAssignmentPointer AssignmentClient::_currentAssignment;
|
|||
|
||||
int hifiSockAddrMeta = qRegisterMetaType<HifiSockAddr>("HifiSockAddr");
|
||||
|
||||
AssignmentClient::AssignmentClient(int &argc, char **argv) :
|
||||
QCoreApplication(argc, argv),
|
||||
AssignmentClient::AssignmentClient(Assignment::Type requestAssignmentType, QString assignmentPool, QUuid walletUUID,
|
||||
QString assignmentServerHostname, quint16 assignmentServerPort) :
|
||||
_assignmentServerHostname(DEFAULT_ASSIGNMENT_SERVER_HOSTNAME),
|
||||
_localASPortSharedMem(NULL)
|
||||
_localASPortSharedMem(NULL),
|
||||
_localACMPortSharedMem(NULL)
|
||||
{
|
||||
LogUtils::init();
|
||||
|
||||
setOrganizationName("High Fidelity");
|
||||
setOrganizationDomain("highfidelity.io");
|
||||
setApplicationName("assignment-client");
|
||||
QSettings::setDefaultFormat(QSettings::IniFormat);
|
||||
|
||||
// create a NodeList as an unassigned client
|
||||
DependencyManager::registerInheritance<LimitedNodeList, NodeList>();
|
||||
auto addressManager = DependencyManager::set<AddressManager>();
|
||||
auto nodeList = DependencyManager::set<NodeList>(NodeType::Unassigned);
|
||||
auto avatarHashMap = DependencyManager::set<AvatarHashMap>();
|
||||
|
||||
// setup a shutdown event listener to handle SIGTERM or WM_CLOSE for us
|
||||
#ifdef _WIN32
|
||||
installNativeEventFilter(&ShutdownEventListener::getInstance());
|
||||
#else
|
||||
ShutdownEventListener::getInstance();
|
||||
#endif
|
||||
|
||||
// make up a uuid for this child so the parent can tell us apart. This id will be changed
|
||||
// when the domain server hands over an assignment.
|
||||
QUuid nodeUUID = QUuid::createUuid();
|
||||
nodeList->setSessionUUID(nodeUUID);
|
||||
|
||||
// set the logging target to the the CHILD_TARGET_NAME
|
||||
LogHandler::getInstance().setTargetName(ASSIGNMENT_CLIENT_TARGET_NAME);
|
||||
|
||||
const QVariantMap argumentVariantMap = HifiConfigVariantMap::mergeCLParametersWithJSONConfig(arguments());
|
||||
|
||||
const QString ASSIGNMENT_TYPE_OVERRIDE_OPTION = "t";
|
||||
const QString ASSIGNMENT_POOL_OPTION = "pool";
|
||||
const QString ASSIGNMENT_WALLET_DESTINATION_ID_OPTION = "wallet";
|
||||
const QString CUSTOM_ASSIGNMENT_SERVER_HOSTNAME_OPTION = "a";
|
||||
const QString CUSTOM_ASSIGNMENT_SERVER_PORT_OPTION = "p";
|
||||
|
||||
Assignment::Type requestAssignmentType = Assignment::AllTypes;
|
||||
|
||||
// check for an assignment type passed on the command line or in the config
|
||||
if (argumentVariantMap.contains(ASSIGNMENT_TYPE_OVERRIDE_OPTION)) {
|
||||
requestAssignmentType = (Assignment::Type) argumentVariantMap.value(ASSIGNMENT_TYPE_OVERRIDE_OPTION).toInt();
|
||||
}
|
||||
|
||||
QString assignmentPool;
|
||||
|
||||
// check for an assignment pool passed on the command line or in the config
|
||||
if (argumentVariantMap.contains(ASSIGNMENT_POOL_OPTION)) {
|
||||
assignmentPool = argumentVariantMap.value(ASSIGNMENT_POOL_OPTION).toString();
|
||||
}
|
||||
|
||||
// setup our _requestAssignment member variable from the passed arguments
|
||||
_requestAssignment = Assignment(Assignment::RequestCommand, requestAssignmentType, assignmentPool);
|
||||
|
||||
// check for a wallet UUID on the command line or in the config
|
||||
// this would represent where the user running AC wants funds sent to
|
||||
if (argumentVariantMap.contains(ASSIGNMENT_WALLET_DESTINATION_ID_OPTION)) {
|
||||
QUuid walletUUID = argumentVariantMap.value(ASSIGNMENT_WALLET_DESTINATION_ID_OPTION).toString();
|
||||
if (!walletUUID.isNull()) {
|
||||
qDebug() << "The destination wallet UUID for credits is" << uuidStringWithoutCurlyBraces(walletUUID);
|
||||
_requestAssignment.setWalletUUID(walletUUID);
|
||||
}
|
||||
|
||||
quint16 assignmentServerPort = DEFAULT_DOMAIN_SERVER_PORT;
|
||||
|
||||
// check for an overriden assignment server hostname
|
||||
if (argumentVariantMap.contains(CUSTOM_ASSIGNMENT_SERVER_HOSTNAME_OPTION)) {
|
||||
if (assignmentServerHostname != "") {
|
||||
// change the hostname for our assignment server
|
||||
_assignmentServerHostname = argumentVariantMap.value(CUSTOM_ASSIGNMENT_SERVER_HOSTNAME_OPTION).toString();
|
||||
}
|
||||
|
||||
// check for an overriden assignment server port
|
||||
if (argumentVariantMap.contains(CUSTOM_ASSIGNMENT_SERVER_PORT_OPTION)) {
|
||||
assignmentServerPort =
|
||||
argumentVariantMap.value(CUSTOM_ASSIGNMENT_SERVER_PORT_OPTION).toString().toUInt();
|
||||
_assignmentServerHostname = assignmentServerHostname;
|
||||
}
|
||||
|
||||
_assignmentServerSocket = HifiSockAddr(_assignmentServerHostname, assignmentServerPort, true);
|
||||
|
@ -123,9 +86,12 @@ AssignmentClient::AssignmentClient(int &argc, char **argv) :
|
|||
// call a timer function every ASSIGNMENT_REQUEST_INTERVAL_MSECS to ask for assignment, if required
|
||||
qDebug() << "Waiting for assignment -" << _requestAssignment;
|
||||
|
||||
QTimer* timer = new QTimer(this);
|
||||
connect(timer, SIGNAL(timeout()), SLOT(sendAssignmentRequest()));
|
||||
timer->start(ASSIGNMENT_REQUEST_INTERVAL_MSECS);
|
||||
if (_assignmentServerHostname != "localhost") {
|
||||
qDebug () << "- will attempt to connect to domain-server on" << _assignmentServerSocket.getPort();
|
||||
}
|
||||
|
||||
connect(&_requestTimer, SIGNAL(timeout()), SLOT(sendAssignmentRequest()));
|
||||
_requestTimer.start(ASSIGNMENT_REQUEST_INTERVAL_MSECS);
|
||||
|
||||
// connect our readPendingDatagrams method to the readyRead() signal of the socket
|
||||
connect(&nodeList->getNodeSocket(), &QUdpSocket::readyRead, this, &AssignmentClient::readPendingDatagrams);
|
||||
|
@ -136,6 +102,45 @@ AssignmentClient::AssignmentClient(int &argc, char **argv) :
|
|||
|
||||
// Create Singleton objects on main thread
|
||||
NetworkAccessManager::getInstance();
|
||||
|
||||
// Hook up a timer to send this child's status to the Monitor once per second
|
||||
setUpStatsToMonitor();
|
||||
}
|
||||
|
||||
|
||||
void AssignmentClient::stopAssignmentClient() {
|
||||
qDebug() << "Exiting.";
|
||||
_requestTimer.stop();
|
||||
_statsTimerACM.stop();
|
||||
QCoreApplication::quit();
|
||||
}
|
||||
|
||||
|
||||
void AssignmentClient::setUpStatsToMonitor() {
|
||||
// Figure out the address to send out stats to
|
||||
quint16 localMonitorServerPort = DEFAULT_ASSIGNMENT_CLIENT_MONITOR_PORT;
|
||||
auto nodeList = DependencyManager::get<NodeList>();
|
||||
|
||||
nodeList->getLocalServerPortFromSharedMemory(ASSIGNMENT_CLIENT_MONITOR_LOCAL_PORT_SMEM_KEY,
|
||||
_localACMPortSharedMem, localMonitorServerPort);
|
||||
_assignmentClientMonitorSocket = HifiSockAddr(DEFAULT_ASSIGNMENT_CLIENT_MONITOR_HOSTNAME, localMonitorServerPort, true);
|
||||
|
||||
// send a stats packet every 1 seconds
|
||||
connect(&_statsTimerACM, &QTimer::timeout, this, &AssignmentClient::sendStatsPacketToACM);
|
||||
_statsTimerACM.start(1000);
|
||||
}
|
||||
|
||||
void AssignmentClient::sendStatsPacketToACM() {
|
||||
// tell the assignment client monitor what this assignment client is doing (if anything)
|
||||
QJsonObject statsObject;
|
||||
auto nodeList = DependencyManager::get<NodeList>();
|
||||
|
||||
if (_currentAssignment) {
|
||||
statsObject["assignment_type"] = _currentAssignment->getTypeName();
|
||||
} else {
|
||||
statsObject["assignment_type"] = "none";
|
||||
}
|
||||
nodeList->sendStats(statsObject, _assignmentClientMonitorSocket);
|
||||
}
|
||||
|
||||
void AssignmentClient::sendAssignmentRequest() {
|
||||
|
@ -145,23 +150,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 +161,6 @@ void AssignmentClient::sendAssignmentRequest() {
|
|||
nodeList->setAssignmentServerSocket(_assignmentServerSocket);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
nodeList->sendAssignment(_requestAssignment);
|
||||
|
@ -227,6 +217,14 @@ void AssignmentClient::readPendingDatagrams() {
|
|||
} else {
|
||||
qDebug() << "Received an assignment that could not be unpacked. Re-requesting.";
|
||||
}
|
||||
} else if (packetTypeForPacket(receivedPacket) == PacketTypeStopNode) {
|
||||
if (senderSockAddr.getAddress() == QHostAddress::LocalHost ||
|
||||
senderSockAddr.getAddress() == QHostAddress::LocalHostIPv6) {
|
||||
qDebug() << "Network told me to exit.";
|
||||
emit stopAssignmentClient();
|
||||
} else {
|
||||
qDebug() << "Got a stop packet from other than localhost.";
|
||||
}
|
||||
} else {
|
||||
// have the NodeList attempt to handle it
|
||||
nodeList->processNodeData(senderSockAddr, receivedPacket);
|
||||
|
|
|
@ -18,10 +18,12 @@
|
|||
|
||||
class QSharedMemory;
|
||||
|
||||
class AssignmentClient : public QCoreApplication {
|
||||
class AssignmentClient : public QObject {
|
||||
Q_OBJECT
|
||||
public:
|
||||
AssignmentClient(int &argc, char **argv);
|
||||
|
||||
AssignmentClient(Assignment::Type requestAssignmentType, QString assignmentPool,
|
||||
QUuid walletUUID, QString assignmentServerHostname, quint16 assignmentServerPort);
|
||||
static const SharedAssignmentPointer& getCurrentAssignment() { return _currentAssignment; }
|
||||
|
||||
private slots:
|
||||
|
@ -29,13 +31,22 @@ private slots:
|
|||
void readPendingDatagrams();
|
||||
void assignmentCompleted();
|
||||
void handleAuthenticationRequest();
|
||||
void sendStatsPacketToACM();
|
||||
void stopAssignmentClient();
|
||||
|
||||
private:
|
||||
void setUpStatsToMonitor();
|
||||
Assignment _requestAssignment;
|
||||
static SharedAssignmentPointer _currentAssignment;
|
||||
QString _assignmentServerHostname;
|
||||
HifiSockAddr _assignmentServerSocket;
|
||||
QSharedMemory* _localASPortSharedMem;
|
||||
QSharedMemory* _localASPortSharedMem; // memory shared with domain server
|
||||
QSharedMemory* _localACMPortSharedMem; // memory shared with assignment client monitor
|
||||
QTimer _requestTimer; // timer for requesting and assignment
|
||||
QTimer _statsTimerACM; // timer for sending stats to assignment client monitor
|
||||
|
||||
protected:
|
||||
HifiSockAddr _assignmentClientMonitorSocket;
|
||||
};
|
||||
|
||||
#endif // hifi_AssignmentClient_h
|
||||
|
|
185
assignment-client/src/AssignmentClientApp.cpp
Normal file
185
assignment-client/src/AssignmentClientApp.cpp
Normal file
|
@ -0,0 +1,185 @@
|
|||
//
|
||||
// AssignmentClientapp.cpp
|
||||
// assignment-client/src
|
||||
//
|
||||
// Created by Seth Alves on 2/19/15.
|
||||
// Copyright 2015 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#include <QCommandLineParser>
|
||||
|
||||
#include <LogHandler.h>
|
||||
#include <SharedUtil.h>
|
||||
#include <HifiConfigVariantMap.h>
|
||||
#include <ShutdownEventListener.h>
|
||||
|
||||
#include "Assignment.h"
|
||||
#include "AssignmentClient.h"
|
||||
#include "AssignmentClientMonitor.h"
|
||||
#include "AssignmentClientApp.h"
|
||||
|
||||
|
||||
AssignmentClientApp::AssignmentClientApp(int argc, char* argv[]) :
|
||||
QCoreApplication(argc, argv)
|
||||
{
|
||||
# ifndef WIN32
|
||||
setvbuf(stdout, NULL, _IOLBF, 0);
|
||||
# endif
|
||||
|
||||
// setup a shutdown event listener to handle SIGTERM or WM_CLOSE for us
|
||||
# ifdef _WIN32
|
||||
installNativeEventFilter(&ShutdownEventListener::getInstance());
|
||||
# else
|
||||
ShutdownEventListener::getInstance();
|
||||
# endif
|
||||
|
||||
setOrganizationName("High Fidelity");
|
||||
setOrganizationDomain("highfidelity.io");
|
||||
setApplicationName("assignment-client");
|
||||
|
||||
// use the verbose message handler in Logging
|
||||
qInstallMessageHandler(LogHandler::verboseMessageHandler);
|
||||
|
||||
// parse command-line
|
||||
QCommandLineParser parser;
|
||||
parser.setApplicationDescription("High Fidelity Assignment Client");
|
||||
parser.addHelpOption();
|
||||
|
||||
const QCommandLineOption helpOption = parser.addHelpOption();
|
||||
|
||||
const QCommandLineOption clientTypeOption(ASSIGNMENT_TYPE_OVERRIDE_OPTION,
|
||||
"run single assignment client of given type", "type");
|
||||
parser.addOption(clientTypeOption);
|
||||
|
||||
const QCommandLineOption poolOption(ASSIGNMENT_POOL_OPTION, "set assignment pool", "pool-name");
|
||||
parser.addOption(poolOption);
|
||||
|
||||
const QCommandLineOption walletDestinationOption(ASSIGNMENT_WALLET_DESTINATION_ID_OPTION,
|
||||
"set wallet destination", "wallet-uuid");
|
||||
parser.addOption(walletDestinationOption);
|
||||
|
||||
const QCommandLineOption assignmentServerHostnameOption(CUSTOM_ASSIGNMENT_SERVER_HOSTNAME_OPTION,
|
||||
"set assignment-server hostname", "hostname");
|
||||
parser.addOption(assignmentServerHostnameOption);
|
||||
|
||||
const QCommandLineOption assignmentServerPortOption(CUSTOM_ASSIGNMENT_SERVER_PORT_OPTION,
|
||||
"set assignment-server port", "port");
|
||||
parser.addOption(assignmentServerPortOption);
|
||||
|
||||
const QCommandLineOption numChildsOption(ASSIGNMENT_NUM_FORKS_OPTION, "number of children to fork", "child-count");
|
||||
parser.addOption(numChildsOption);
|
||||
|
||||
const QCommandLineOption minChildsOption(ASSIGNMENT_MIN_FORKS_OPTION, "minimum number of children", "child-count");
|
||||
parser.addOption(minChildsOption);
|
||||
|
||||
const QCommandLineOption maxChildsOption(ASSIGNMENT_MAX_FORKS_OPTION, "maximum number of children", "child-count");
|
||||
parser.addOption(maxChildsOption);
|
||||
|
||||
|
||||
if (!parser.parse(QCoreApplication::arguments())) {
|
||||
qCritical() << parser.errorText() << endl;
|
||||
parser.showHelp();
|
||||
Q_UNREACHABLE();
|
||||
}
|
||||
|
||||
if (parser.isSet(helpOption)) {
|
||||
parser.showHelp();
|
||||
Q_UNREACHABLE();
|
||||
}
|
||||
|
||||
|
||||
const QVariantMap argumentVariantMap = HifiConfigVariantMap::mergeCLParametersWithJSONConfig(arguments());
|
||||
|
||||
|
||||
unsigned int numForks = 0;
|
||||
if (parser.isSet(numChildsOption)) {
|
||||
numForks = parser.value(numChildsOption).toInt();
|
||||
}
|
||||
|
||||
unsigned int minForks = 0;
|
||||
if (parser.isSet(minChildsOption)) {
|
||||
minForks = parser.value(minChildsOption).toInt();
|
||||
}
|
||||
|
||||
unsigned int maxForks = 0;
|
||||
if (parser.isSet(maxChildsOption)) {
|
||||
maxForks = parser.value(maxChildsOption).toInt();
|
||||
}
|
||||
|
||||
if (!numForks && minForks) {
|
||||
// if the user specified --min but not -n, set -n to --min
|
||||
numForks = minForks;
|
||||
}
|
||||
|
||||
Assignment::Type requestAssignmentType = Assignment::AllTypes;
|
||||
if (argumentVariantMap.contains(ASSIGNMENT_TYPE_OVERRIDE_OPTION)) {
|
||||
requestAssignmentType = (Assignment::Type) argumentVariantMap.value(ASSIGNMENT_TYPE_OVERRIDE_OPTION).toInt();
|
||||
}
|
||||
if (parser.isSet(clientTypeOption)) {
|
||||
requestAssignmentType = (Assignment::Type) parser.value(clientTypeOption).toInt();
|
||||
}
|
||||
|
||||
QString assignmentPool;
|
||||
// check for an assignment pool passed on the command line or in the config
|
||||
if (argumentVariantMap.contains(ASSIGNMENT_POOL_OPTION)) {
|
||||
assignmentPool = argumentVariantMap.value(ASSIGNMENT_POOL_OPTION).toString();
|
||||
}
|
||||
if (parser.isSet(poolOption)) {
|
||||
assignmentPool = parser.value(poolOption);
|
||||
}
|
||||
|
||||
|
||||
QUuid walletUUID;
|
||||
if (argumentVariantMap.contains(ASSIGNMENT_WALLET_DESTINATION_ID_OPTION)) {
|
||||
walletUUID = argumentVariantMap.value(ASSIGNMENT_WALLET_DESTINATION_ID_OPTION).toString();
|
||||
}
|
||||
if (parser.isSet(walletDestinationOption)) {
|
||||
walletUUID = parser.value(walletDestinationOption);
|
||||
}
|
||||
|
||||
QString assignmentServerHostname;
|
||||
if (argumentVariantMap.contains(ASSIGNMENT_WALLET_DESTINATION_ID_OPTION)) {
|
||||
assignmentServerHostname = argumentVariantMap.value(CUSTOM_ASSIGNMENT_SERVER_HOSTNAME_OPTION).toString();
|
||||
}
|
||||
if (parser.isSet(assignmentServerHostnameOption)) {
|
||||
assignmentServerHostname = parser.value(assignmentServerHostnameOption);
|
||||
}
|
||||
|
||||
// check for an overriden assignment server port
|
||||
quint16 assignmentServerPort = DEFAULT_DOMAIN_SERVER_PORT;
|
||||
if (argumentVariantMap.contains(ASSIGNMENT_WALLET_DESTINATION_ID_OPTION)) {
|
||||
assignmentServerPort = argumentVariantMap.value(CUSTOM_ASSIGNMENT_SERVER_PORT_OPTION).toString().toUInt();
|
||||
}
|
||||
if (parser.isSet(assignmentServerPortOption)) {
|
||||
assignmentServerPort = parser.value(assignmentServerPortOption).toInt();
|
||||
}
|
||||
|
||||
|
||||
|
||||
if (parser.isSet(numChildsOption)) {
|
||||
if (minForks && minForks > numForks) {
|
||||
qCritical() << "--min can't be more than -n";
|
||||
parser.showHelp();
|
||||
Q_UNREACHABLE();
|
||||
}
|
||||
if (maxForks && maxForks < numForks) {
|
||||
qCritical() << "--max can't be less than -n";
|
||||
parser.showHelp();
|
||||
Q_UNREACHABLE();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (numForks || minForks || maxForks) {
|
||||
AssignmentClientMonitor monitor(numForks, minForks, maxForks, assignmentPool,
|
||||
walletUUID, assignmentServerHostname, assignmentServerPort);
|
||||
exec();
|
||||
} else {
|
||||
AssignmentClient client(requestAssignmentType, assignmentPool,
|
||||
walletUUID, assignmentServerHostname, assignmentServerPort);
|
||||
exec();
|
||||
}
|
||||
}
|
34
assignment-client/src/AssignmentClientApp.h
Normal file
34
assignment-client/src/AssignmentClientApp.h
Normal file
|
@ -0,0 +1,34 @@
|
|||
//
|
||||
// AssignmentClientapp.h
|
||||
// assignment-client/src
|
||||
//
|
||||
// Created by Seth Alves on 2/19/15.
|
||||
// Copyright 2015 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#ifndef hifi_AssignmentClientApp_h
|
||||
#define hifi_AssignmentClientApp_h
|
||||
|
||||
|
||||
#include <QApplication>
|
||||
|
||||
const QString ASSIGNMENT_TYPE_OVERRIDE_OPTION = "t";
|
||||
const QString ASSIGNMENT_POOL_OPTION = "pool";
|
||||
const QString ASSIGNMENT_WALLET_DESTINATION_ID_OPTION = "wallet";
|
||||
const QString CUSTOM_ASSIGNMENT_SERVER_HOSTNAME_OPTION = "a";
|
||||
const QString CUSTOM_ASSIGNMENT_SERVER_PORT_OPTION = "p";
|
||||
const QString ASSIGNMENT_NUM_FORKS_OPTION = "n";
|
||||
const QString ASSIGNMENT_MIN_FORKS_OPTION = "min";
|
||||
const QString ASSIGNMENT_MAX_FORKS_OPTION = "max";
|
||||
|
||||
|
||||
class AssignmentClientApp : public QCoreApplication {
|
||||
Q_OBJECT
|
||||
public:
|
||||
AssignmentClientApp(int argc, char* argv[]);
|
||||
};
|
||||
|
||||
#endif // hifi_AssignmentClientApp_h
|
8
assignment-client/src/AssignmentClientChildData.cpp
Normal file
8
assignment-client/src/AssignmentClientChildData.cpp
Normal file
|
@ -0,0 +1,8 @@
|
|||
|
||||
#include "AssignmentClientChildData.h"
|
||||
|
||||
|
||||
AssignmentClientChildData::AssignmentClientChildData(QString childType) :
|
||||
_childType(childType)
|
||||
{
|
||||
}
|
32
assignment-client/src/AssignmentClientChildData.h
Normal file
32
assignment-client/src/AssignmentClientChildData.h
Normal file
|
@ -0,0 +1,32 @@
|
|||
//
|
||||
// AssignmentClientChildData.h
|
||||
// assignment-client/src
|
||||
//
|
||||
// Created by Seth Alves on 2/23/2015.
|
||||
// Copyright 2015 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#ifndef hifi_AssignmentClientChildData_h
|
||||
#define hifi_AssignmentClientChildData_h
|
||||
|
||||
#include <Assignment.h>
|
||||
|
||||
|
||||
class AssignmentClientChildData : public NodeData {
|
||||
public:
|
||||
AssignmentClientChildData(QString childType);
|
||||
|
||||
QString getChildType() { return _childType; }
|
||||
void setChildType(QString childType) { _childType = childType; }
|
||||
|
||||
// implement parseData to return 0 so we can be a subclass of NodeData
|
||||
int parseData(const QByteArray& packet) { return 0; }
|
||||
|
||||
private:
|
||||
QString _childType;
|
||||
};
|
||||
|
||||
#endif // hifi_AssignmentClientChildData_h
|
|
@ -12,40 +12,51 @@
|
|||
#include <signal.h>
|
||||
|
||||
#include <LogHandler.h>
|
||||
#include <ShutdownEventListener.h>
|
||||
#include <AddressManager.h>
|
||||
|
||||
#include "AssignmentClientMonitor.h"
|
||||
#include "AssignmentClientApp.h"
|
||||
#include "AssignmentClientChildData.h"
|
||||
#include "PacketHeaders.h"
|
||||
#include "SharedUtil.h"
|
||||
|
||||
const char* NUM_FORKS_PARAMETER = "-n";
|
||||
|
||||
const QString ASSIGNMENT_CLIENT_MONITOR_TARGET_NAME = "assignment-client-monitor";
|
||||
|
||||
AssignmentClientMonitor::AssignmentClientMonitor(int &argc, char **argv, int numAssignmentClientForks) :
|
||||
QCoreApplication(argc, argv)
|
||||
AssignmentClientMonitor::AssignmentClientMonitor(const unsigned int numAssignmentClientForks,
|
||||
const unsigned int minAssignmentClientForks,
|
||||
const unsigned int maxAssignmentClientForks,
|
||||
QString assignmentPool, QUuid walletUUID, QString assignmentServerHostname,
|
||||
quint16 assignmentServerPort) :
|
||||
_numAssignmentClientForks(numAssignmentClientForks),
|
||||
_minAssignmentClientForks(minAssignmentClientForks),
|
||||
_maxAssignmentClientForks(maxAssignmentClientForks),
|
||||
_assignmentPool(assignmentPool),
|
||||
_walletUUID(walletUUID),
|
||||
_assignmentServerHostname(assignmentServerHostname),
|
||||
_assignmentServerPort(assignmentServerPort)
|
||||
{
|
||||
// start the Logging class with the parent's target name
|
||||
LogHandler::getInstance().setTargetName(ASSIGNMENT_CLIENT_MONITOR_TARGET_NAME);
|
||||
|
||||
// setup a shutdown event listener to handle SIGTERM or WM_CLOSE for us
|
||||
#ifdef _WIN32
|
||||
installNativeEventFilter(&ShutdownEventListener::getInstance());
|
||||
#else
|
||||
ShutdownEventListener::getInstance();
|
||||
#endif
|
||||
|
||||
_childArguments = arguments();
|
||||
|
||||
// remove the parameter for the number of forks so it isn't passed to the child forked processes
|
||||
int forksParameterIndex = _childArguments.indexOf(NUM_FORKS_PARAMETER);
|
||||
|
||||
// this removes both the "-n" parameter and the number of forks passed
|
||||
_childArguments.removeAt(forksParameterIndex);
|
||||
_childArguments.removeAt(forksParameterIndex);
|
||||
|
||||
// create a NodeList so we can receive stats from children
|
||||
DependencyManager::registerInheritance<LimitedNodeList, NodeList>();
|
||||
auto addressManager = DependencyManager::set<AddressManager>();
|
||||
auto nodeList = DependencyManager::set<LimitedNodeList>(DEFAULT_ASSIGNMENT_CLIENT_MONITOR_PORT);
|
||||
|
||||
connect(&nodeList->getNodeSocket(), &QUdpSocket::readyRead, this, &AssignmentClientMonitor::readPendingDatagrams);
|
||||
|
||||
nodeList->putLocalPortIntoSharedMemory(ASSIGNMENT_CLIENT_MONITOR_LOCAL_PORT_SMEM_KEY, this);
|
||||
|
||||
// use QProcess to fork off a process for each of the child assignment clients
|
||||
for (int i = 0; i < numAssignmentClientForks; i++) {
|
||||
for (unsigned int i = 0; i < _numAssignmentClientForks; i++) {
|
||||
spawnChildClient();
|
||||
}
|
||||
|
||||
connect(&_checkSparesTimer, &QTimer::timeout, this, &AssignmentClientMonitor::checkSpares);
|
||||
|
||||
_checkSparesTimer.start(NODE_SILENCE_THRESHOLD_MSECS * 3);
|
||||
}
|
||||
|
||||
AssignmentClientMonitor::~AssignmentClientMonitor() {
|
||||
|
@ -53,46 +64,145 @@ AssignmentClientMonitor::~AssignmentClientMonitor() {
|
|||
}
|
||||
|
||||
void AssignmentClientMonitor::stopChildProcesses() {
|
||||
|
||||
QList<QPointer<QProcess> >::Iterator it = _childProcesses.begin();
|
||||
while (it != _childProcesses.end()) {
|
||||
if (!it->isNull()) {
|
||||
qDebug() << "Monitor is terminating child process" << it->data();
|
||||
|
||||
// don't re-spawn this child when it goes down
|
||||
disconnect(it->data(), 0, this, 0);
|
||||
|
||||
it->data()->terminate();
|
||||
it->data()->waitForFinished();
|
||||
}
|
||||
|
||||
it = _childProcesses.erase(it);
|
||||
}
|
||||
auto nodeList = DependencyManager::get<NodeList>();
|
||||
|
||||
nodeList->eachNode([&](const SharedNodePointer& node) {
|
||||
qDebug() << "asking child" << node->getUUID() << "to exit.";
|
||||
node->activateLocalSocket();
|
||||
QByteArray diePacket = byteArrayWithPopulatedHeader(PacketTypeStopNode);
|
||||
nodeList->writeUnverifiedDatagram(diePacket, *node->getActiveSocket());
|
||||
});
|
||||
}
|
||||
|
||||
void AssignmentClientMonitor::spawnChildClient() {
|
||||
QProcess *assignmentClient = new QProcess(this);
|
||||
|
||||
_childProcesses.append(QPointer<QProcess>(assignmentClient));
|
||||
|
||||
|
||||
// unparse the parts of the command-line that the child cares about
|
||||
QStringList _childArguments;
|
||||
if (_assignmentPool != "") {
|
||||
_childArguments.append("--" + ASSIGNMENT_POOL_OPTION);
|
||||
_childArguments.append(_assignmentPool);
|
||||
}
|
||||
if (!_walletUUID.isNull()) {
|
||||
_childArguments.append("--" + ASSIGNMENT_WALLET_DESTINATION_ID_OPTION);
|
||||
_childArguments.append(_walletUUID.toString());
|
||||
}
|
||||
if (_assignmentServerHostname != "") {
|
||||
_childArguments.append("--" + CUSTOM_ASSIGNMENT_SERVER_HOSTNAME_OPTION);
|
||||
_childArguments.append(_assignmentServerHostname);
|
||||
}
|
||||
if (_assignmentServerPort != DEFAULT_DOMAIN_SERVER_PORT) {
|
||||
_childArguments.append("--" + CUSTOM_ASSIGNMENT_SERVER_PORT_OPTION);
|
||||
_childArguments.append(QString::number(_assignmentServerPort));
|
||||
}
|
||||
|
||||
// make sure that the output from the child process appears in our output
|
||||
assignmentClient->setProcessChannelMode(QProcess::ForwardedChannels);
|
||||
|
||||
assignmentClient->start(applicationFilePath(), _childArguments);
|
||||
|
||||
// link the child processes' finished slot to our childProcessFinished slot
|
||||
connect(assignmentClient, SIGNAL(finished(int, QProcess::ExitStatus)), this,
|
||||
SLOT(childProcessFinished(int, QProcess::ExitStatus)));
|
||||
|
||||
assignmentClient->start(QCoreApplication::applicationFilePath(), _childArguments);
|
||||
|
||||
qDebug() << "Spawned a child client with PID" << assignmentClient->pid();
|
||||
}
|
||||
|
||||
void AssignmentClientMonitor::childProcessFinished(int exitCode, QProcess::ExitStatus exitStatus) {
|
||||
qDebug("Replacing dead child assignment client with a new one");
|
||||
|
||||
// remove the old process from our list of child processes
|
||||
qDebug() << "need to remove" << QPointer<QProcess>(qobject_cast<QProcess*>(sender()));
|
||||
_childProcesses.removeOne(QPointer<QProcess>(qobject_cast<QProcess*>(sender())));
|
||||
|
||||
spawnChildClient();
|
||||
|
||||
|
||||
void AssignmentClientMonitor::checkSpares() {
|
||||
auto nodeList = DependencyManager::get<NodeList>();
|
||||
QUuid aSpareId = "";
|
||||
unsigned int spareCount = 0;
|
||||
unsigned int totalCount = 0;
|
||||
|
||||
nodeList->removeSilentNodes();
|
||||
|
||||
nodeList->eachNode([&](const SharedNodePointer& node) {
|
||||
AssignmentClientChildData *childData = static_cast<AssignmentClientChildData*>(node->getLinkedData());
|
||||
totalCount ++;
|
||||
if (childData->getChildType() == "none") {
|
||||
spareCount ++;
|
||||
aSpareId = node->getUUID();
|
||||
}
|
||||
});
|
||||
|
||||
// Spawn or kill children, as needed. If --min or --max weren't specified, allow the child count
|
||||
// to drift up or down as far as needed.
|
||||
if (spareCount < 1 || totalCount < _minAssignmentClientForks) {
|
||||
if (!_maxAssignmentClientForks || totalCount < _maxAssignmentClientForks) {
|
||||
spawnChildClient();
|
||||
}
|
||||
}
|
||||
|
||||
if (spareCount > 1) {
|
||||
if (!_minAssignmentClientForks || totalCount > _minAssignmentClientForks) {
|
||||
// kill aSpareId
|
||||
qDebug() << "asking child" << aSpareId << "to exit.";
|
||||
SharedNodePointer childNode = nodeList->nodeWithUUID(aSpareId);
|
||||
childNode->activateLocalSocket();
|
||||
QByteArray diePacket = byteArrayWithPopulatedHeader(PacketTypeStopNode);
|
||||
nodeList->writeUnverifiedDatagram(diePacket, childNode);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void AssignmentClientMonitor::readPendingDatagrams() {
|
||||
auto nodeList = DependencyManager::get<NodeList>();
|
||||
|
||||
QByteArray receivedPacket;
|
||||
HifiSockAddr senderSockAddr;
|
||||
|
||||
while (nodeList->getNodeSocket().hasPendingDatagrams()) {
|
||||
receivedPacket.resize(nodeList->getNodeSocket().pendingDatagramSize());
|
||||
nodeList->getNodeSocket().readDatagram(receivedPacket.data(), receivedPacket.size(),
|
||||
senderSockAddr.getAddressPointer(), senderSockAddr.getPortPointer());
|
||||
|
||||
if (nodeList->packetVersionAndHashMatch(receivedPacket)) {
|
||||
if (packetTypeForPacket(receivedPacket) == PacketTypeNodeJsonStats) {
|
||||
QUuid packetUUID = uuidFromPacketHeader(receivedPacket);
|
||||
SharedNodePointer matchingNode = nodeList->sendingNodeForPacket(receivedPacket);
|
||||
if (!matchingNode) {
|
||||
// The parent only expects to be talking with prorams running on this same machine.
|
||||
if (senderSockAddr.getAddress() == QHostAddress::LocalHost ||
|
||||
senderSockAddr.getAddress() == QHostAddress::LocalHostIPv6) {
|
||||
if (!packetUUID.isNull()) {
|
||||
matchingNode = DependencyManager::get<LimitedNodeList>()->addOrUpdateNode
|
||||
(packetUUID, NodeType::Unassigned, senderSockAddr, senderSockAddr, false);
|
||||
AssignmentClientChildData *childData = new AssignmentClientChildData("unknown");
|
||||
matchingNode->setLinkedData(childData);
|
||||
} else {
|
||||
// tell unknown assignment-client child to exit.
|
||||
qDebug() << "asking unknown child to exit.";
|
||||
QByteArray diePacket = byteArrayWithPopulatedHeader(PacketTypeStopNode);
|
||||
nodeList->writeUnverifiedDatagram(diePacket, senderSockAddr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (matchingNode) {
|
||||
// update our records about how to reach this child
|
||||
matchingNode->setLocalSocket(senderSockAddr);
|
||||
|
||||
// push past the packet header
|
||||
QDataStream packetStream(receivedPacket);
|
||||
packetStream.skipRawData(numBytesForPacketHeader(receivedPacket));
|
||||
// decode json
|
||||
QVariantMap unpackedVariantMap;
|
||||
packetStream >> unpackedVariantMap;
|
||||
QJsonObject unpackedStatsJSON = QJsonObject::fromVariantMap(unpackedVariantMap);
|
||||
|
||||
// get child's assignment type out of the decoded json
|
||||
QString childType = unpackedStatsJSON["assignment_type"].toString();
|
||||
AssignmentClientChildData *childData =
|
||||
static_cast<AssignmentClientChildData*>(matchingNode->getLinkedData());
|
||||
childData->setChildType(childType);
|
||||
// note when this child talked
|
||||
matchingNode->setLastHeardMicrostamp(usecTimestampNow());
|
||||
}
|
||||
} else {
|
||||
// have the NodeList attempt to handle it
|
||||
nodeList->processNodeData(senderSockAddr, receivedPacket);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -15,25 +15,40 @@
|
|||
#include <QtCore/QCoreApplication>
|
||||
#include <QtCore/qpointer.h>
|
||||
#include <QtCore/QProcess>
|
||||
#include <QtCore/QDateTime>
|
||||
|
||||
#include <Assignment.h>
|
||||
|
||||
#include "AssignmentClientChildData.h"
|
||||
|
||||
extern const char* NUM_FORKS_PARAMETER;
|
||||
|
||||
class AssignmentClientMonitor : public QCoreApplication {
|
||||
|
||||
class AssignmentClientMonitor : public QObject {
|
||||
Q_OBJECT
|
||||
public:
|
||||
AssignmentClientMonitor(int &argc, char **argv, int numAssignmentClientForks);
|
||||
AssignmentClientMonitor(const unsigned int numAssignmentClientForks, const unsigned int minAssignmentClientForks,
|
||||
const unsigned int maxAssignmentClientForks, QString assignmentPool, QUuid walletUUID,
|
||||
QString assignmentServerHostname, quint16 assignmentServerPort);
|
||||
~AssignmentClientMonitor();
|
||||
|
||||
void stopChildProcesses();
|
||||
private slots:
|
||||
void childProcessFinished(int exitCode, QProcess::ExitStatus exitStatus);
|
||||
void readPendingDatagrams();
|
||||
void checkSpares();
|
||||
|
||||
private:
|
||||
void spawnChildClient();
|
||||
QList<QPointer<QProcess> > _childProcesses;
|
||||
|
||||
QStringList _childArguments;
|
||||
QTimer _checkSparesTimer; // every few seconds see if it need fewer or more spare children
|
||||
|
||||
const unsigned int _numAssignmentClientForks;
|
||||
const unsigned int _minAssignmentClientForks;
|
||||
const unsigned int _maxAssignmentClientForks;
|
||||
|
||||
QString _assignmentPool;
|
||||
QUuid _walletUUID;
|
||||
QString _assignmentServerHostname;
|
||||
quint16 _assignmentServerPort;
|
||||
};
|
||||
|
||||
#endif // hifi_AssignmentClientMonitor_h
|
||||
|
|
|
@ -9,34 +9,10 @@
|
|||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#include <LogHandler.h>
|
||||
#include <SharedUtil.h>
|
||||
|
||||
#include "Assignment.h"
|
||||
#include "AssignmentClient.h"
|
||||
#include "AssignmentClientMonitor.h"
|
||||
#include "AssignmentClientApp.h"
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
#ifndef WIN32
|
||||
setvbuf(stdout, NULL, _IOLBF, 0);
|
||||
#endif
|
||||
|
||||
// use the verbose message handler in Logging
|
||||
qInstallMessageHandler(LogHandler::verboseMessageHandler);
|
||||
|
||||
const char* numForksString = getCmdOption(argc, (const char**)argv, NUM_FORKS_PARAMETER);
|
||||
|
||||
int numForks = 0;
|
||||
|
||||
if (numForksString) {
|
||||
numForks = atoi(numForksString);
|
||||
}
|
||||
|
||||
if (numForks) {
|
||||
AssignmentClientMonitor monitor(argc, argv, numForks);
|
||||
return monitor.exec();
|
||||
} else {
|
||||
AssignmentClient client(argc, argv);
|
||||
return client.exec();
|
||||
}
|
||||
AssignmentClientApp app(argc, argv);
|
||||
return 0;
|
||||
}
|
||||
|
|
59
cmake/modules/FindVHACD.cmake
Normal file
59
cmake/modules/FindVHACD.cmake
Normal file
|
@ -0,0 +1,59 @@
|
|||
#
|
||||
# FindVHACD.cmake
|
||||
#
|
||||
# Try to find the V-HACD library that decomposes a 3D surface into a set of "near" convex parts.
|
||||
#
|
||||
# Once done this will define
|
||||
#
|
||||
# VHACD_FOUND - system found V-HACD
|
||||
# VHACD_INCLUDE_DIRS - the V-HACD include directory
|
||||
# VHACD_LIBRARIES - link to this to use V-HACD
|
||||
#
|
||||
# Created on 2/20/2015 by Virendra Singh
|
||||
# Copyright 2015 High Fidelity, Inc.
|
||||
#
|
||||
# Distributed under the Apache License, Version 2.0.
|
||||
# See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
#
|
||||
|
||||
include("${MACRO_DIR}/HifiLibrarySearchHints.cmake")
|
||||
hifi_library_search_hints("vhacd")
|
||||
|
||||
macro(_FIND_VHACD_LIBRARY _var)
|
||||
set(_${_var}_NAMES ${ARGN})
|
||||
find_library(${_var}_LIBRARY_RELEASE
|
||||
NAMES ${_${_var}_NAMES}
|
||||
HINTS
|
||||
${VHACD_SEARCH_DIRS}
|
||||
$ENV{VHACD_ROOT_DIR}
|
||||
PATH_SUFFIXES lib lib/Release
|
||||
)
|
||||
|
||||
find_library(${_var}_LIBRARY_DEBUG
|
||||
NAMES ${_${_var}_NAMES}
|
||||
HINTS
|
||||
${VHACD_SEARCH_DIRS}
|
||||
$ENV{VHACD_ROOT_DIR}
|
||||
PATH_SUFFIXES lib lib/Debug
|
||||
)
|
||||
|
||||
select_library_configurations(${_var})
|
||||
|
||||
mark_as_advanced(${_var}_LIBRARY)
|
||||
mark_as_advanced(${_var}_LIBRARY)
|
||||
endmacro()
|
||||
|
||||
|
||||
find_path(VHACD_INCLUDE_DIRS VHACD.h PATH_SUFFIXES include HINTS ${VHACD_SEARCH_DIRS} $ENV{VHACD_ROOT_DIR})
|
||||
if(NOT WIN32)
|
||||
_FIND_VHACD_LIBRARY(VHACD libVHACD.a)
|
||||
else()
|
||||
_FIND_VHACD_LIBRARY(VHACD VHACD_LIB)
|
||||
endif()
|
||||
set(VHACD_LIBRARIES ${VHACD_LIBRARY})
|
||||
|
||||
include(FindPackageHandleStandardArgs)
|
||||
find_package_handle_standard_args(VHACD "Could NOT find VHACD, try to set the path to VHACD root folder in the system variable VHACD_ROOT_DIR or create a directory vhacd in HIFI_LIB_DIR and paste the necessary files there"
|
||||
VHACD_INCLUDE_DIRS VHACD_LIBRARIES)
|
||||
|
||||
mark_as_advanced(VHACD_INCLUDE_DIRS VHACD_LIBRARIES VHACD_SEARCH_DIRS)
|
|
@ -32,6 +32,7 @@
|
|||
#include <SharedUtil.h>
|
||||
#include <ShutdownEventListener.h>
|
||||
#include <UUID.h>
|
||||
#include <LogHandler.h>
|
||||
|
||||
#include "DomainServerNodeData.h"
|
||||
|
||||
|
@ -246,19 +247,7 @@ void DomainServer::setupNodeListAndAssignments(const QUuid& sessionUUID) {
|
|||
auto nodeList = DependencyManager::set<LimitedNodeList>(domainServerPort, domainServerDTLSPort);
|
||||
|
||||
// no matter the local port, save it to shared mem so that local assignment clients can ask what it is
|
||||
QSharedMemory* sharedPortMem = new QSharedMemory(DOMAIN_SERVER_LOCAL_PORT_SMEM_KEY, this);
|
||||
quint16 localPort = nodeList->getNodeSocket().localPort();
|
||||
|
||||
// attempt to create the shared memory segment
|
||||
if (sharedPortMem->create(sizeof(localPort)) || sharedPortMem->attach()) {
|
||||
sharedPortMem->lock();
|
||||
memcpy(sharedPortMem->data(), &localPort, sizeof(localPort));
|
||||
sharedPortMem->unlock();
|
||||
|
||||
qDebug() << "Wrote local listening port" << localPort << "to shared memory at key" << DOMAIN_SERVER_LOCAL_PORT_SMEM_KEY;
|
||||
} else {
|
||||
qWarning() << "Failed to create and attach to shared memory to share local port with assignment-client children.";
|
||||
}
|
||||
nodeList->putLocalPortIntoSharedMemory(DOMAIN_SERVER_LOCAL_PORT_SMEM_KEY, this);
|
||||
|
||||
// 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
|
||||
|
@ -955,8 +944,10 @@ void DomainServer::readAvailableDatagrams() {
|
|||
|
||||
if (requestAssignment.getType() != Assignment::AgentType
|
||||
|| noisyMessageTimer.elapsed() > NOISY_MESSAGE_INTERVAL_MSECS) {
|
||||
static QString repeatedMessage = LogHandler::getInstance().addOnlyOnceMessageRegex
|
||||
("Received a request for assignment type [^ ]+ from [^ ]+");
|
||||
qDebug() << "Received a request for assignment type" << requestAssignment.getType()
|
||||
<< "from" << senderSockAddr;
|
||||
<< "from" << senderSockAddr;
|
||||
noisyMessageTimer.restart();
|
||||
}
|
||||
|
||||
|
@ -986,6 +977,8 @@ void DomainServer::readAvailableDatagrams() {
|
|||
} else {
|
||||
if (requestAssignment.getType() != Assignment::AgentType
|
||||
|| noisyMessageTimer.elapsed() > NOISY_MESSAGE_INTERVAL_MSECS) {
|
||||
static QString repeatedMessage = LogHandler::getInstance().addOnlyOnceMessageRegex
|
||||
("Unable to fulfill assignment request of type [^ ]+ from [^ ]+");
|
||||
qDebug() << "Unable to fulfill assignment request of type" << requestAssignment.getType()
|
||||
<< "from" << senderSockAddr;
|
||||
noisyMessageTimer.restart();
|
||||
|
|
|
@ -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") {
|
||||
|
|
34
examples/example/misc/sunLightExample.js
Normal file
34
examples/example/misc/sunLightExample.js
Normal file
|
@ -0,0 +1,34 @@
|
|||
//
|
||||
// SunLightExample.js
|
||||
// examples
|
||||
// Sam Gateau
|
||||
// Copyright 2015 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
var intensity = 1.0;
|
||||
var day = 0.0;
|
||||
var hour = 12.0;
|
||||
var longitude = 115.0;
|
||||
var latitude = 31.0;
|
||||
var stageOrientation = Quat.fromPitchYawRollDegrees(0.0, 180.0, 0.0);
|
||||
|
||||
Scene.setStageDayTime(hour);
|
||||
Scene.setStageOrientation(stageOrientation);
|
||||
Scene.setStageLocation(longitude, latitude, 0.0);
|
||||
/*
|
||||
function ticktack() {
|
||||
hour += 0.1;
|
||||
//Scene.setSunIntensity(Math.cos(time));
|
||||
if (hour > 24.0) {
|
||||
hour = 0.0;
|
||||
day++;
|
||||
Scene.setStageYearTime(day);
|
||||
}
|
||||
Scene.setStageDayTime(hour);
|
||||
}
|
||||
|
||||
Script.setInterval(ticktack, 41);
|
||||
*/
|
|
@ -20,6 +20,7 @@
|
|||
elRefresh = document.getElementById("refresh");
|
||||
elDelete = document.getElementById("delete");
|
||||
elTeleport = document.getElementById("teleport");
|
||||
elNoEntitiesMessage = document.getElementById("no-entities");
|
||||
|
||||
document.getElementById("entity-type").onclick = function() {
|
||||
setSortColumn('type');
|
||||
|
@ -155,11 +156,18 @@
|
|||
}
|
||||
} else if (data.type == "update") {
|
||||
var newEntities = data.entities;
|
||||
for (var i = 0; i < newEntities.length; i++) {
|
||||
var id = newEntities[i].id;
|
||||
addEntity(id, newEntities[i].type, newEntities[i].url);
|
||||
if (newEntities.length == 0) {
|
||||
elEntityTable.style.display = "none";
|
||||
elNoEntitiesMessage.style.display = "block";
|
||||
} else {
|
||||
elEntityTable.style.display = "table";
|
||||
elNoEntitiesMessage.style.display = "none";
|
||||
for (var i = 0; i < newEntities.length; i++) {
|
||||
var id = newEntities[i].id;
|
||||
addEntity(id, newEntities[i].type, newEntities[i].url);
|
||||
}
|
||||
updateSelectedEntities(data.selectedIDs);
|
||||
}
|
||||
updateSelectedEntities(data.selectedIDs);
|
||||
}
|
||||
});
|
||||
setTimeout(refreshEntities, 1000);
|
||||
|
@ -194,6 +202,8 @@
|
|||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<div id="no-entities">
|
||||
No entities found within 50 meter radius. Try moving to a different location and refreshing.
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
@ -128,21 +128,11 @@
|
|||
|
||||
var elLightSections = document.querySelectorAll(".light-section");
|
||||
var elLightSpotLight = document.getElementById("property-light-spot-light");
|
||||
var elLightDiffuseRed = document.getElementById("property-light-diffuse-red");
|
||||
var elLightDiffuseGreen = document.getElementById("property-light-diffuse-green");
|
||||
var elLightDiffuseBlue = document.getElementById("property-light-diffuse-blue");
|
||||
var elLightColorRed = document.getElementById("property-light-color-red");
|
||||
var elLightColorGreen = document.getElementById("property-light-color-green");
|
||||
var elLightColorBlue = document.getElementById("property-light-color-blue");
|
||||
|
||||
var elLightAmbientRed = document.getElementById("property-light-ambient-red");
|
||||
var elLightAmbientGreen = document.getElementById("property-light-ambient-green");
|
||||
var elLightAmbientBlue = document.getElementById("property-light-ambient-blue");
|
||||
|
||||
var elLightSpecularRed = document.getElementById("property-light-specular-red");
|
||||
var elLightSpecularGreen = document.getElementById("property-light-specular-green");
|
||||
var elLightSpecularBlue = document.getElementById("property-light-specular-blue");
|
||||
|
||||
var elLightConstantAttenuation = document.getElementById("property-light-constant-attenuation");
|
||||
var elLightLinearAttenuation = document.getElementById("property-light-linear-attenuation");
|
||||
var elLightQuadraticAttenuation = document.getElementById("property-light-quadratic-attenuation");
|
||||
var elLightIntensity = document.getElementById("property-light-intensity");
|
||||
var elLightExponent = document.getElementById("property-light-exponent");
|
||||
var elLightCutoff = document.getElementById("property-light-cutoff");
|
||||
|
||||
|
@ -171,12 +161,37 @@
|
|||
EventBridge.scriptEventReceived.connect(function(data) {
|
||||
data = JSON.parse(data);
|
||||
if (data.type == "update") {
|
||||
if (data.properties === undefined) {
|
||||
disableChildren(document.getElementById("properties"), 'input');
|
||||
} else {
|
||||
var properties = data.properties;
|
||||
if (data.selections.length == 0) {
|
||||
elType.innerHTML = "<i>No Selection</i>";
|
||||
elID.innerHTML = "";
|
||||
disableChildren(document.getElementById("properties-list"), 'input');
|
||||
} else if (data.selections.length > 1) {
|
||||
var selections = data.selections;
|
||||
|
||||
elID.innerHTML = data.id;
|
||||
var ids = [];
|
||||
var types = {};
|
||||
|
||||
for (var i = 0; i < selections.length; i++) {
|
||||
ids.push(selections[i].id);
|
||||
var type = selections[i].properties.type;
|
||||
if (types[type] === undefined) {
|
||||
types[type] = 0;
|
||||
}
|
||||
types[type]++;
|
||||
}
|
||||
elID.innerHTML = ids.join("<br>");
|
||||
|
||||
var typeStrs = [];
|
||||
for (type in types) {
|
||||
typeStrs.push(type + " (" + types[type] + ")");
|
||||
}
|
||||
elType.innerHTML = typeStrs.join(", ");
|
||||
|
||||
disableChildren(document.getElementById("properties-list"), 'input');
|
||||
} else {
|
||||
var properties = data.selections[0].properties;
|
||||
|
||||
elID.innerHTML = properties.id;
|
||||
|
||||
elType.innerHTML = properties.type;
|
||||
|
||||
|
@ -290,21 +305,11 @@
|
|||
elLightSections[i].style.display = 'block';
|
||||
}
|
||||
|
||||
elLightDiffuseRed.value = properties.diffuseColor.red;
|
||||
elLightDiffuseGreen.value = properties.diffuseColor.green;
|
||||
elLightDiffuseBlue.value = properties.diffuseColor.blue;
|
||||
elLightColorRed.value = properties.color.red;
|
||||
elLightColorGreen.value = properties.color.green;
|
||||
elLightColorBlue.value = properties.color.blue;
|
||||
|
||||
elLightAmbientRed.value = properties.ambientColor.red;
|
||||
elLightAmbientGreen.value = properties.ambientColor.green;
|
||||
elLightAmbientBlue.value = properties.ambientColor.blue;
|
||||
|
||||
elLightSpecularRed.value = properties.specularColor.red;
|
||||
elLightSpecularGreen.value = properties.specularColor.green;
|
||||
elLightSpecularBlue.value = properties.specularColor.blue;
|
||||
|
||||
elLightConstantAttenuation.value = properties.constantAttenuation;
|
||||
elLightLinearAttenuation.value = properties.linearAttenuation;
|
||||
elLightQuadraticAttenuation.value = properties.quadraticAttenuation;
|
||||
elLightIntensity.value = properties.intensity;
|
||||
elLightExponent.value = properties.exponent;
|
||||
elLightCutoff.value = properties.cutoff;
|
||||
}
|
||||
|
@ -375,27 +380,13 @@
|
|||
|
||||
elLightSpotLight.addEventListener('change', createEmitCheckedPropertyUpdateFunction('isSpotlight'));
|
||||
|
||||
var lightDiffuseChangeFunction = createEmitColorPropertyUpdateFunction(
|
||||
'diffuseColor', elLightDiffuseRed, elLightDiffuseGreen, elLightDiffuseBlue);
|
||||
elLightDiffuseRed.addEventListener('change', lightDiffuseChangeFunction);
|
||||
elLightDiffuseGreen.addEventListener('change', lightDiffuseChangeFunction);
|
||||
elLightDiffuseBlue.addEventListener('change', lightDiffuseChangeFunction);
|
||||
var lightColorChangeFunction = createEmitColorPropertyUpdateFunction(
|
||||
'color', elLightColorRed, elLightColorGreen, elLightColorBlue);
|
||||
elLightColorRed.addEventListener('change', lightColorChangeFunction);
|
||||
elLightColorGreen.addEventListener('change', lightColorChangeFunction);
|
||||
elLightColorBlue.addEventListener('change', lightColorChangeFunction);
|
||||
|
||||
var lightAmbientChangeFunction = createEmitColorPropertyUpdateFunction(
|
||||
'ambientColor', elLightAmbientRed, elLightAmbientGreen, elLightAmbientBlue);
|
||||
elLightAmbientRed.addEventListener('change', lightAmbientChangeFunction);
|
||||
elLightAmbientGreen.addEventListener('change', lightAmbientChangeFunction);
|
||||
elLightAmbientBlue.addEventListener('change', lightAmbientChangeFunction);
|
||||
|
||||
var lightSpecularChangeFunction = createEmitColorPropertyUpdateFunction(
|
||||
'specularColor', elLightSpecularRed, elLightSpecularGreen, elLightSpecularBlue);
|
||||
elLightSpecularRed.addEventListener('change', lightSpecularChangeFunction);
|
||||
elLightSpecularGreen.addEventListener('change', lightSpecularChangeFunction);
|
||||
elLightSpecularBlue.addEventListener('change', lightSpecularChangeFunction);
|
||||
|
||||
elLightConstantAttenuation.addEventListener('change', createEmitNumberPropertyUpdateFunction('constantAttenuation'));
|
||||
elLightLinearAttenuation.addEventListener('change', createEmitNumberPropertyUpdateFunction('linearAttenuation'));
|
||||
elLightQuadraticAttenuation.addEventListener('change', createEmitNumberPropertyUpdateFunction('quadraticAttenuation'));
|
||||
elLightIntensity.addEventListener('change', createEmitNumberPropertyUpdateFunction('intensity'));
|
||||
elLightExponent.addEventListener('change', createEmitNumberPropertyUpdateFunction('exponent'));
|
||||
elLightCutoff.addEventListener('change', createEmitNumberPropertyUpdateFunction('cutoff'));
|
||||
|
||||
|
@ -448,6 +439,13 @@
|
|||
percentage: parseInt(elRescaleDimensionsPct.value),
|
||||
}));
|
||||
});
|
||||
|
||||
window.onblur = function() {
|
||||
// Fake a change event
|
||||
var ev = document.createEvent("HTMLEvents");
|
||||
ev.initEvent("change", true, true);
|
||||
document.activeElement.dispatchEvent(ev);
|
||||
}
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
|
@ -715,55 +713,27 @@
|
|||
</div>
|
||||
</div>
|
||||
<div class="light-section property">
|
||||
<div class="label">Diffuse</div>
|
||||
<div class="label">Color</div>
|
||||
<div class="value">
|
||||
<div class="input-area">R <input class="coord" type='number' id="property-light-diffuse-red"></input></div>
|
||||
<div class="input-area">G <input class="coord" type='number' id="property-light-diffuse-green"></input></div>
|
||||
<div class="input-area">B <input class="coord" type='number' id="property-light-diffuse-blue"></input></div>
|
||||
<div class="input-area">R <input class="coord" type='number' id="property-light-color-red"></input></div>
|
||||
<div class="input-area">G <input class="coord" type='number' id="property-light-color-green"></input></div>
|
||||
<div class="input-area">B <input class="coord" type='number' id="property-light-color-blue"></input></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="light-section property">
|
||||
<div class="label">Ambient</div>
|
||||
<div class="label">Intensity</div>
|
||||
<div class="value">
|
||||
<div class="input-area">R <input class="coord" type='number' id="property-light-ambient-red"></input></div>
|
||||
<div class="input-area">G <input class="coord" type='number' id="property-light-ambient-green"></input></div>
|
||||
<div class="input-area">B <input class="coord" type='number' id="property-light-ambient-blue"></input></div>
|
||||
<input class="coord" type='number' id="property-light-intensity"></input>
|
||||
</div>
|
||||
</div>
|
||||
<div class="light-section property">
|
||||
<div class="label">Specular</div>
|
||||
<div class="value">
|
||||
<div class="input-area">R <input class="coord" type='number' id="property-light-specular-red"></input></div>
|
||||
<div class="input-area">G <input class="coord" type='number' id="property-light-specular-green"></input></div>
|
||||
<div class="input-area">B <input class="coord" type='number' id="property-light-specular-blue"></input></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="light-section property">
|
||||
<div class="label">Constant Attenuation</div>
|
||||
<div class="value">
|
||||
<input class="coord" type='number' id="property-light-constant-attenuation"></input>
|
||||
</div>
|
||||
</div>
|
||||
<div class="light-section property">
|
||||
<div class="label">Linear Attenuation</div>
|
||||
<div class="value">
|
||||
<input class="coord" type='number' id="property-light-linear-attenuation"></input>
|
||||
</div>
|
||||
</div>
|
||||
<div class="light-section property">
|
||||
<div class="label">Quadratic Attenuation</div>
|
||||
<div class="value">
|
||||
<input class="coord" type='number' id="property-light-quadratic-attenuation"></input>
|
||||
</div>
|
||||
</div>
|
||||
<div class="light-section property">
|
||||
<div class="label">Exponent</div>
|
||||
<div class="label">Spot Light Exponent</div>
|
||||
<div class="value">
|
||||
<input class="coord" type='number' id="property-light-exponent"></input>
|
||||
</div>
|
||||
</div>
|
||||
<div class="light-section property">
|
||||
<div class="label">Cutoff (degrees)</div>
|
||||
<div class="label">Spot Light Cutoff (degrees)</div>
|
||||
<div class="value">
|
||||
<input class="coord" type='number' id="property-light-cutoff"></input>
|
||||
</div>
|
||||
|
|
|
@ -189,6 +189,11 @@ input, textarea {
|
|||
font-size: 7.5pt;
|
||||
}
|
||||
|
||||
input:disabled, textarea:disabled {
|
||||
background-color: rgb(102, 102, 102);
|
||||
color: rgb(160, 160, 160);
|
||||
}
|
||||
|
||||
#properties-list input[type=button] {
|
||||
cursor: pointer;
|
||||
background-color: rgb(51, 102, 102);
|
||||
|
@ -199,6 +204,11 @@ input, textarea {
|
|||
color: rgb(204, 204, 204);
|
||||
}
|
||||
|
||||
#properties-list input[type=button]:disabled {
|
||||
background-color: rgb(41, 82, 82);
|
||||
color: rgb(160, 160, 160);
|
||||
}
|
||||
|
||||
#properties-list .property {
|
||||
padding: 6pt 6pt;
|
||||
border-top: 0.75pt solid rgb(63, 63, 63);
|
||||
|
@ -257,3 +267,11 @@ td {
|
|||
|
||||
vertical-align: top;
|
||||
}
|
||||
|
||||
#no-entities {
|
||||
display: none;
|
||||
font-size: 120%;
|
||||
padding: 10pt;
|
||||
font-weight: bold;
|
||||
font-style: italic;
|
||||
}
|
||||
|
|
|
@ -238,12 +238,12 @@ SelectionDisplay = (function () {
|
|||
|
||||
// These are multipliers for sizing the rotation degrees display while rotating an entity
|
||||
var ROTATION_DISPLAY_DISTANCE_MULTIPLIER = 1.2;
|
||||
var ROTATION_DISPLAY_SIZE_X_MULTIPLIER = 0.5;
|
||||
var ROTATION_DISPLAY_SIZE_X_MULTIPLIER = 0.6;
|
||||
var ROTATION_DISPLAY_SIZE_Y_MULTIPLIER = 0.18;
|
||||
var ROTATION_DISPLAY_LINE_HEIGHT_MULTIPLIER = 0.17;
|
||||
var ROTATION_DISPLAY_LINE_HEIGHT_MULTIPLIER = 0.14;
|
||||
|
||||
var ROTATE_ARROW_WEST_NORTH_URL = HIFI_PUBLIC_BUCKET + "images/rotate-arrow-west-north.png";
|
||||
var ROTATE_ARROW_WEST_SOUTH_URL = HIFI_PUBLIC_BUCKET + "images/rotate-arrow-west-south.png";
|
||||
var ROTATE_ARROW_WEST_NORTH_URL = HIFI_PUBLIC_BUCKET + "images/rotate-arrow-west-north.svg";
|
||||
var ROTATE_ARROW_WEST_SOUTH_URL = HIFI_PUBLIC_BUCKET + "images/rotate-arrow-west-south.svg";
|
||||
|
||||
var showExtendedStretchHandles = false;
|
||||
|
||||
|
@ -280,11 +280,11 @@ SelectionDisplay = (function () {
|
|||
var originalRoll;
|
||||
|
||||
|
||||
var rotateHandleColor = { red: 0, green: 0, blue: 0 };
|
||||
var rotateHandleAlpha = 0.7;
|
||||
var handleColor = { red: 255, green: 255, blue: 255 };
|
||||
var handleAlpha = 0.7;
|
||||
|
||||
var highlightedHandleColor = { red: 255, green: 0, blue: 0 };
|
||||
var highlightedHandleAlpha = 0.7;
|
||||
var highlightedHandleColor = { red: 183, green: 64, blue: 44 };
|
||||
var highlightedHandleAlpha = 0.9;
|
||||
|
||||
var previousHandle = false;
|
||||
var previousHandleColor;
|
||||
|
@ -385,10 +385,10 @@ SelectionDisplay = (function () {
|
|||
});
|
||||
|
||||
var grabberMoveUp = Overlays.addOverlay("billboard", {
|
||||
url: HIFI_PUBLIC_BUCKET + "images/up-arrow.png",
|
||||
url: HIFI_PUBLIC_BUCKET + "images/up-arrow.svg",
|
||||
position: { x:0, y: 0, z: 0},
|
||||
color: { red: 0, green: 0, blue: 0 },
|
||||
alpha: 1.0,
|
||||
color: handleColor,
|
||||
alpha: handleAlpha,
|
||||
visible: false,
|
||||
size: 0.1,
|
||||
scale: 0.1,
|
||||
|
@ -533,7 +533,7 @@ SelectionDisplay = (function () {
|
|||
|
||||
var rotateOverlayTarget = Overlays.addOverlay("circle3d", {
|
||||
position: { x:0, y: 0, z: 0},
|
||||
size: rotateOverlayTargetSize,
|
||||
size: rotateOverlayTargetSize * 2,
|
||||
color: { red: 0, green: 0, blue: 0 },
|
||||
alpha: 0.0,
|
||||
solid: true,
|
||||
|
@ -595,8 +595,8 @@ SelectionDisplay = (function () {
|
|||
var yawHandle = Overlays.addOverlay("billboard", {
|
||||
url: ROTATE_ARROW_WEST_NORTH_URL,
|
||||
position: { x:0, y: 0, z: 0},
|
||||
color: rotateHandleColor,
|
||||
alpha: rotateHandleAlpha,
|
||||
color: handleColor,
|
||||
alpha: handleAlpha,
|
||||
visible: false,
|
||||
size: 0.1,
|
||||
scale: 0.1,
|
||||
|
@ -608,8 +608,8 @@ SelectionDisplay = (function () {
|
|||
var pitchHandle = Overlays.addOverlay("billboard", {
|
||||
url: ROTATE_ARROW_WEST_NORTH_URL,
|
||||
position: { x:0, y: 0, z: 0},
|
||||
color: rotateHandleColor,
|
||||
alpha: rotateHandleAlpha,
|
||||
color: handleColor,
|
||||
alpha: handleAlpha,
|
||||
visible: false,
|
||||
size: 0.1,
|
||||
scale: 0.1,
|
||||
|
@ -621,8 +621,8 @@ SelectionDisplay = (function () {
|
|||
var rollHandle = Overlays.addOverlay("billboard", {
|
||||
url: ROTATE_ARROW_WEST_NORTH_URL,
|
||||
position: { x:0, y: 0, z: 0},
|
||||
color: rotateHandleColor,
|
||||
alpha: rotateHandleAlpha,
|
||||
color: handleColor,
|
||||
alpha: handleAlpha,
|
||||
visible: false,
|
||||
size: 0.1,
|
||||
scale: 0.1,
|
||||
|
@ -1692,7 +1692,7 @@ SelectionDisplay = (function () {
|
|||
y: innerRadius * ROTATION_DISPLAY_SIZE_Y_MULTIPLIER
|
||||
},
|
||||
lineHeight: innerRadius * ROTATION_DISPLAY_LINE_HEIGHT_MULTIPLIER,
|
||||
text: normalizeDegrees(angleFromZero),
|
||||
text: normalizeDegrees(angleFromZero) + "°",
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -1713,15 +1713,17 @@ SelectionDisplay = (function () {
|
|||
Overlays.editOverlay(rotateOverlayInner,
|
||||
{
|
||||
visible: true,
|
||||
size: innerRadius,
|
||||
size: innerRadius * 2,
|
||||
innerRadius: 0.9,
|
||||
startAt: 0,
|
||||
endAt: 360,
|
||||
alpha: innerAlpha
|
||||
});
|
||||
|
||||
Overlays.editOverlay(rotateOverlayOuter,
|
||||
{
|
||||
visible: true,
|
||||
size: outerRadius,
|
||||
size: outerRadius * 2,
|
||||
innerRadius: 0.9,
|
||||
startAt: 0,
|
||||
endAt: 360,
|
||||
|
@ -1731,7 +1733,7 @@ SelectionDisplay = (function () {
|
|||
Overlays.editOverlay(rotateOverlayCurrent,
|
||||
{
|
||||
visible: true,
|
||||
size: outerRadius,
|
||||
size: outerRadius * 2,
|
||||
startAt: 0,
|
||||
endAt: 0,
|
||||
innerRadius: 0.9,
|
||||
|
@ -1809,13 +1811,13 @@ SelectionDisplay = (function () {
|
|||
if (snapToInner) {
|
||||
Overlays.editOverlay(rotateOverlayOuter, { startAt: 0, endAt: 360 });
|
||||
Overlays.editOverlay(rotateOverlayInner, { startAt: startAtRemainder, endAt: endAtRemainder });
|
||||
Overlays.editOverlay(rotateOverlayCurrent, { startAt: startAtCurrent, endAt: endAtCurrent, size: innerRadius,
|
||||
Overlays.editOverlay(rotateOverlayCurrent, { startAt: startAtCurrent, endAt: endAtCurrent, size: innerRadius * 2,
|
||||
majorTickMarksAngle: innerSnapAngle, minorTickMarksAngle: 0,
|
||||
majorTickMarksLength: -0.25, minorTickMarksLength: 0, });
|
||||
} else {
|
||||
Overlays.editOverlay(rotateOverlayInner, { startAt: 0, endAt: 360 });
|
||||
Overlays.editOverlay(rotateOverlayOuter, { startAt: startAtRemainder, endAt: endAtRemainder });
|
||||
Overlays.editOverlay(rotateOverlayCurrent, { startAt: startAtCurrent, endAt: endAtCurrent, size: outerRadius,
|
||||
Overlays.editOverlay(rotateOverlayCurrent, { startAt: startAtCurrent, endAt: endAtCurrent, size: outerRadius * 2,
|
||||
majorTickMarksAngle: 45.0, minorTickMarksAngle: 5,
|
||||
majorTickMarksLength: 0.25, minorTickMarksLength: 0.1, });
|
||||
}
|
||||
|
@ -1840,15 +1842,17 @@ SelectionDisplay = (function () {
|
|||
Overlays.editOverlay(rotateOverlayInner,
|
||||
{
|
||||
visible: true,
|
||||
size: innerRadius,
|
||||
size: innerRadius * 2,
|
||||
innerRadius: 0.9,
|
||||
startAt: 0,
|
||||
endAt: 360,
|
||||
alpha: innerAlpha
|
||||
});
|
||||
|
||||
Overlays.editOverlay(rotateOverlayOuter,
|
||||
{
|
||||
visible: true,
|
||||
size: outerRadius,
|
||||
size: outerRadius * 2,
|
||||
innerRadius: 0.9,
|
||||
startAt: 0,
|
||||
endAt: 360,
|
||||
|
@ -1858,7 +1862,7 @@ SelectionDisplay = (function () {
|
|||
Overlays.editOverlay(rotateOverlayCurrent,
|
||||
{
|
||||
visible: true,
|
||||
size: outerRadius,
|
||||
size: outerRadius * 2,
|
||||
startAt: 0,
|
||||
endAt: 0,
|
||||
innerRadius: 0.9,
|
||||
|
@ -1929,13 +1933,13 @@ SelectionDisplay = (function () {
|
|||
if (snapToInner) {
|
||||
Overlays.editOverlay(rotateOverlayOuter, { startAt: 0, endAt: 360 });
|
||||
Overlays.editOverlay(rotateOverlayInner, { startAt: startAtRemainder, endAt: endAtRemainder });
|
||||
Overlays.editOverlay(rotateOverlayCurrent, { startAt: startAtCurrent, endAt: endAtCurrent, size: innerRadius,
|
||||
Overlays.editOverlay(rotateOverlayCurrent, { startAt: startAtCurrent, endAt: endAtCurrent, size: innerRadius * 2,
|
||||
majorTickMarksAngle: innerSnapAngle, minorTickMarksAngle: 0,
|
||||
majorTickMarksLength: -0.25, minorTickMarksLength: 0, });
|
||||
} else {
|
||||
Overlays.editOverlay(rotateOverlayInner, { startAt: 0, endAt: 360 });
|
||||
Overlays.editOverlay(rotateOverlayOuter, { startAt: startAtRemainder, endAt: endAtRemainder });
|
||||
Overlays.editOverlay(rotateOverlayCurrent, { startAt: startAtCurrent, endAt: endAtCurrent, size: outerRadius,
|
||||
Overlays.editOverlay(rotateOverlayCurrent, { startAt: startAtCurrent, endAt: endAtCurrent, size: outerRadius * 2,
|
||||
majorTickMarksAngle: 45.0, minorTickMarksAngle: 5,
|
||||
majorTickMarksLength: 0.25, minorTickMarksLength: 0.1, });
|
||||
}
|
||||
|
@ -1959,15 +1963,17 @@ SelectionDisplay = (function () {
|
|||
Overlays.editOverlay(rotateOverlayInner,
|
||||
{
|
||||
visible: true,
|
||||
size: innerRadius,
|
||||
size: innerRadius * 2,
|
||||
innerRadius: 0.9,
|
||||
startAt: 0,
|
||||
endAt: 360,
|
||||
alpha: innerAlpha
|
||||
});
|
||||
|
||||
Overlays.editOverlay(rotateOverlayOuter,
|
||||
{
|
||||
visible: true,
|
||||
size: outerRadius,
|
||||
size: outerRadius * 2,
|
||||
innerRadius: 0.9,
|
||||
startAt: 0,
|
||||
endAt: 360,
|
||||
|
@ -1977,7 +1983,7 @@ SelectionDisplay = (function () {
|
|||
Overlays.editOverlay(rotateOverlayCurrent,
|
||||
{
|
||||
visible: true,
|
||||
size: outerRadius,
|
||||
size: outerRadius * 2,
|
||||
startAt: 0,
|
||||
endAt: 0,
|
||||
innerRadius: 0.9,
|
||||
|
@ -2047,13 +2053,13 @@ SelectionDisplay = (function () {
|
|||
if (snapToInner) {
|
||||
Overlays.editOverlay(rotateOverlayOuter, { startAt: 0, endAt: 360 });
|
||||
Overlays.editOverlay(rotateOverlayInner, { startAt: startAtRemainder, endAt: endAtRemainder });
|
||||
Overlays.editOverlay(rotateOverlayCurrent, { startAt: startAtCurrent, endAt: endAtCurrent, size: innerRadius,
|
||||
Overlays.editOverlay(rotateOverlayCurrent, { startAt: startAtCurrent, endAt: endAtCurrent, size: innerRadius * 2,
|
||||
majorTickMarksAngle: innerSnapAngle, minorTickMarksAngle: 0,
|
||||
majorTickMarksLength: -0.25, minorTickMarksLength: 0, });
|
||||
} else {
|
||||
Overlays.editOverlay(rotateOverlayInner, { startAt: 0, endAt: 360 });
|
||||
Overlays.editOverlay(rotateOverlayOuter, { startAt: startAtRemainder, endAt: endAtRemainder });
|
||||
Overlays.editOverlay(rotateOverlayCurrent, { startAt: startAtCurrent, endAt: endAtCurrent, size: outerRadius,
|
||||
Overlays.editOverlay(rotateOverlayCurrent, { startAt: startAtCurrent, endAt: endAtCurrent, size: outerRadius * 2,
|
||||
majorTickMarksAngle: 45.0, minorTickMarksAngle: 5,
|
||||
majorTickMarksLength: 0.25, minorTickMarksLength: 0.1, });
|
||||
}
|
||||
|
@ -2342,14 +2348,14 @@ SelectionDisplay = (function () {
|
|||
case yawHandle:
|
||||
case pitchHandle:
|
||||
case rollHandle:
|
||||
pickedColor = rotateHandleColor;
|
||||
pickedAlpha = rotateHandleAlpha;
|
||||
pickedColor = handleColor;
|
||||
pickedAlpha = handleAlpha;
|
||||
highlightNeeded = true;
|
||||
break;
|
||||
|
||||
case grabberMoveUp:
|
||||
pickedColor = rotateHandleColor;
|
||||
pickedAlpha = rotateHandleAlpha;
|
||||
pickedColor = handleColor;
|
||||
pickedAlpha = handleAlpha;
|
||||
highlightNeeded = true;
|
||||
break;
|
||||
|
||||
|
|
|
@ -82,6 +82,8 @@
|
|||
#include <UserActivityLogger.h>
|
||||
#include <UUID.h>
|
||||
|
||||
#include <SceneScriptingInterface.h>
|
||||
|
||||
#include "Application.h"
|
||||
#include "AudioClient.h"
|
||||
#include "InterfaceVersion.h"
|
||||
|
@ -771,8 +773,8 @@ void Application::paintGL() {
|
|||
|
||||
{
|
||||
PerformanceTimer perfTimer("renderOverlay");
|
||||
_applicationOverlay.renderOverlay(true);
|
||||
if (Menu::getInstance()->isOptionChecked(MenuOption::UserInterface)) {
|
||||
_applicationOverlay.renderOverlay(true);
|
||||
_applicationOverlay.displayOverlayTexture();
|
||||
}
|
||||
}
|
||||
|
@ -1858,35 +1860,6 @@ void Application::updateMouseRay() {
|
|||
}
|
||||
}
|
||||
|
||||
void Application::updateFaceshift() {
|
||||
bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings);
|
||||
PerformanceWarning warn(showWarnings, "Application::updateFaceshift()");
|
||||
auto faceshift = DependencyManager::get<Faceshift>();
|
||||
// Update faceshift
|
||||
faceshift->update();
|
||||
|
||||
// Copy angular velocity if measured by faceshift, to the head
|
||||
if (faceshift->isActive()) {
|
||||
_myAvatar->getHead()->setAngularVelocity(faceshift->getHeadAngularVelocity());
|
||||
}
|
||||
}
|
||||
|
||||
void Application::updateVisage() {
|
||||
bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings);
|
||||
PerformanceWarning warn(showWarnings, "Application::updateVisage()");
|
||||
|
||||
// Update Visage
|
||||
DependencyManager::get<Visage>()->update();
|
||||
}
|
||||
|
||||
void Application::updateDDE() {
|
||||
bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings);
|
||||
PerformanceWarning warn(showWarnings, "Application::updateDDE()");
|
||||
|
||||
// Update Cara
|
||||
DependencyManager::get<DdeFaceTracker>()->update();
|
||||
}
|
||||
|
||||
void Application::updateMyAvatarLookAtPosition() {
|
||||
PerformanceTimer perfTimer("lookAt");
|
||||
bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings);
|
||||
|
@ -2066,8 +2039,10 @@ 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();
|
||||
}
|
||||
|
@ -2488,7 +2463,8 @@ void Application::loadViewFrustum(Camera& camera, ViewFrustum& viewFrustum) {
|
|||
|
||||
glm::vec3 Application::getSunDirection() {
|
||||
// Sun direction is in fact just the location of the sun relative to the origin
|
||||
return glm::normalize(_environment.getClosestData(_myCamera.getPosition()).getSunLocation(_myCamera.getPosition()));
|
||||
auto skyStage = DependencyManager::get<SceneScriptingInterface>()->getSkyStage();
|
||||
return skyStage->getSunLight()->getDirection();
|
||||
}
|
||||
|
||||
void Application::updateShadowMap() {
|
||||
|
@ -2498,7 +2474,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);
|
||||
|
||||
|
@ -2867,7 +2843,9 @@ void Application::displaySide(Camera& theCamera, bool selfAvatarOnly, RenderArgs
|
|||
|
||||
{
|
||||
DependencyManager::get<DeferredLightingEffect>()->setAmbientLightMode(getRenderAmbientLight());
|
||||
DependencyManager::get<DeferredLightingEffect>()->setGlobalLight(-getSunDirection(), GLOBAL_LIGHT_COLOR, GLOBAL_LIGHT_INTENSITY);
|
||||
auto skyStage = DependencyManager::get<SceneScriptingInterface>()->getSkyStage();
|
||||
DependencyManager::get<DeferredLightingEffect>()->setGlobalLight(skyStage->getSunLight()->getDirection(), skyStage->getSunLight()->getColor(), skyStage->getSunLight()->getIntensity());
|
||||
|
||||
PROFILE_RANGE("DeferredLighting");
|
||||
PerformanceTimer perfTimer("lighting");
|
||||
DependencyManager::get<DeferredLightingEffect>()->render();
|
||||
|
|
|
@ -419,9 +419,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);
|
||||
|
|
|
@ -453,7 +453,8 @@ Menu::Menu() {
|
|||
|
||||
QMenu* timingMenu = developerMenu->addMenu("Timing and Stats");
|
||||
QMenu* perfTimerMenu = timingMenu->addMenu("Performance Timer");
|
||||
addCheckableActionToQMenuAndActionHash(perfTimerMenu, MenuOption::DisplayTimingDetails, 0, true);
|
||||
addCheckableActionToQMenuAndActionHash(perfTimerMenu, MenuOption::DisplayDebugTimingDetails, 0, false);
|
||||
addCheckableActionToQMenuAndActionHash(perfTimerMenu, MenuOption::OnlyDisplayTopTen, 0, true);
|
||||
addCheckableActionToQMenuAndActionHash(perfTimerMenu, MenuOption::ExpandUpdateTiming, 0, false);
|
||||
addCheckableActionToQMenuAndActionHash(perfTimerMenu, MenuOption::ExpandMyAvatarTiming, 0, false);
|
||||
addCheckableActionToQMenuAndActionHash(perfTimerMenu, MenuOption::ExpandMyAvatarSimulateTiming, 0, false);
|
||||
|
|
|
@ -150,7 +150,7 @@ namespace MenuOption {
|
|||
const QString DisplayModelTriangles = "Display Model Triangles";
|
||||
const QString DisplayModelElementChildProxies = "Display Model Element Children";
|
||||
const QString DisplayModelElementProxy = "Display Model Element Bounds";
|
||||
const QString DisplayTimingDetails = "Display Timing Details";
|
||||
const QString DisplayDebugTimingDetails = "Display Timing Details";
|
||||
const QString DontDoPrecisionPicking = "Don't Do Precision Picking";
|
||||
const QString DontFadeOnOctreeServerChanges = "Don't Fade In/Out on Octree Server Changes";
|
||||
const QString DontRenderEntitiesAsScene = "Don't Render Entities as Scene";
|
||||
|
@ -198,6 +198,7 @@ namespace MenuOption {
|
|||
const QString OctreeStats = "Voxel and Entity Statistics";
|
||||
const QString OffAxisProjection = "Off-Axis Projection";
|
||||
const QString OldVoxelCullingMode = "Old Voxel Culling Mode";
|
||||
const QString OnlyDisplayTopTen = "Only Display Top Ten";
|
||||
const QString Pair = "Pair";
|
||||
const QString PipelineWarnings = "Log Render Pipeline Warnings";
|
||||
const QString Preferences = "Preferences...";
|
||||
|
|
|
@ -380,8 +380,7 @@ void Avatar::render(const glm::vec3& cameraPosition, RenderMode renderMode, bool
|
|||
foreach (const AvatarManager::LocalLight& light, DependencyManager::get<AvatarManager>()->getLocalLights()) {
|
||||
glm::vec3 direction = orientation * light.direction;
|
||||
DependencyManager::get<DeferredLightingEffect>()->addSpotLight(position - direction * distance,
|
||||
distance * 2.0f, glm::vec3(), light.color, light.color, 1.0f, 0.5f, 0.0f, direction,
|
||||
LIGHT_EXPONENT, LIGHT_CUTOFF);
|
||||
distance * 2.0f, light.color, 0.5f, orientation, LIGHT_EXPONENT, LIGHT_CUTOFF);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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),
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -880,13 +880,7 @@ void MyAvatar::updateLookAtTargetAvatar() {
|
|||
_lookAtTargetAvatar.clear();
|
||||
_targetAvatarPosition = glm::vec3(0.0f);
|
||||
|
||||
glm::quat faceRotation = Application::getInstance()->getViewFrustum()->getOrientation();
|
||||
FaceTracker* tracker = Application::getInstance()->getActiveFaceTracker();
|
||||
if (tracker) {
|
||||
// If faceshift or other face tracker in use, add on the actual angle of the head
|
||||
faceRotation *= tracker->getHeadRotation();
|
||||
}
|
||||
glm::vec3 lookForward = faceRotation * IDENTITY_FRONT;
|
||||
glm::vec3 lookForward = getHead()->getFinalOrientationInWorldFrame() * IDENTITY_FRONT;
|
||||
glm::vec3 cameraPosition = Application::getInstance()->getCamera()->getPosition();
|
||||
|
||||
float smallestAngleTo = glm::radians(Application::getInstance()->getCamera()->getFieldOfView()) / 2.0f;
|
||||
|
@ -1152,15 +1146,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);
|
||||
|
|
|
@ -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
|
||||
|
@ -64,10 +66,11 @@ DdeFaceTracker::DdeFaceTracker(const QHostAddress& host, quint16 port) :
|
|||
_mouthSmileLeftIndex(28),
|
||||
_mouthSmileRightIndex(29),
|
||||
_jawOpenIndex(21),
|
||||
_host(host),
|
||||
_port(port)
|
||||
_previousTranslation(glm::vec3()),
|
||||
_previousRotation(glm::quat())
|
||||
{
|
||||
_blendshapeCoefficients.resize(NUM_EXPRESSION);
|
||||
_previousExpressions.resize(NUM_EXPRESSION);
|
||||
|
||||
connect(&_udpSocket, SIGNAL(readyRead()), SLOT(readPendingDatagrams()));
|
||||
connect(&_udpSocket, SIGNAL(error(QAbstractSocket::SocketError)), SLOT(socketErrorOccurred(QAbstractSocket::SocketError)));
|
||||
|
@ -80,18 +83,6 @@ DdeFaceTracker::~DdeFaceTracker() {
|
|||
}
|
||||
}
|
||||
|
||||
void DdeFaceTracker::init() {
|
||||
|
||||
}
|
||||
|
||||
void DdeFaceTracker::reset() {
|
||||
_reset = true;
|
||||
}
|
||||
|
||||
void DdeFaceTracker::update() {
|
||||
|
||||
}
|
||||
|
||||
void DdeFaceTracker::setEnabled(bool enabled) {
|
||||
// isOpen() does not work as one might expect on QUdpSocket; don't test isOpen() before closing socket.
|
||||
_udpSocket.close();
|
||||
|
@ -151,37 +142,6 @@ float DdeFaceTracker::getBlendshapeCoefficient(int index) const {
|
|||
return (index >= 0 && index < (int)_blendshapeCoefficients.size()) ? _blendshapeCoefficients[index] : 0.0f;
|
||||
}
|
||||
|
||||
static const float DDE_MIN_RANGE = -0.2f;
|
||||
static const float DDE_MAX_RANGE = 1.5f;
|
||||
float rescaleCoef(float ddeCoef) {
|
||||
return (ddeCoef - DDE_MIN_RANGE) / (DDE_MAX_RANGE - DDE_MIN_RANGE);
|
||||
}
|
||||
|
||||
const int MIN = 0;
|
||||
const int AVG = 1;
|
||||
const int MAX = 2;
|
||||
const float LONG_TERM_AVERAGE = 0.999f;
|
||||
|
||||
|
||||
void resetCoefficient(float * coefficient, float currentValue) {
|
||||
coefficient[MIN] = coefficient[MAX] = coefficient[AVG] = currentValue;
|
||||
}
|
||||
|
||||
float updateAndGetCoefficient(float * coefficient, float currentValue, bool scaleToRange = false) {
|
||||
coefficient[MIN] = (currentValue < coefficient[MIN]) ? currentValue : coefficient[MIN];
|
||||
coefficient[MAX] = (currentValue > coefficient[MAX]) ? currentValue : coefficient[MAX];
|
||||
coefficient[AVG] = LONG_TERM_AVERAGE * coefficient[AVG] + (1.0f - LONG_TERM_AVERAGE) * currentValue;
|
||||
if (coefficient[MAX] > coefficient[MIN]) {
|
||||
if (scaleToRange) {
|
||||
return glm::clamp((currentValue - coefficient[AVG]) / (coefficient[MAX] - coefficient[MIN]), 0.0f, 1.0f);
|
||||
} else {
|
||||
return glm::clamp(currentValue - coefficient[AVG], 0.0f, 1.0f);
|
||||
}
|
||||
} else {
|
||||
return 0.0f;
|
||||
}
|
||||
}
|
||||
|
||||
void DdeFaceTracker::decodePacket(const QByteArray& buffer) {
|
||||
if(buffer.size() > MIN_PACKET_SIZE) {
|
||||
Packet packet;
|
||||
|
@ -196,9 +156,6 @@ void DdeFaceTracker::decodePacket(const QByteArray& buffer) {
|
|||
if (_reset || (_lastReceiveTimestamp == 0)) {
|
||||
memcpy(&_referenceTranslation, &translation, sizeof(glm::vec3));
|
||||
memcpy(&_referenceRotation, &rotation, sizeof(glm::quat));
|
||||
|
||||
resetCoefficient(_rightEye, packet.expressions[0]);
|
||||
resetCoefficient(_leftEye, packet.expressions[1]);
|
||||
_reset = false;
|
||||
}
|
||||
|
||||
|
@ -207,51 +164,75 @@ void DdeFaceTracker::decodePacket(const QByteArray& buffer) {
|
|||
translation -= _referenceTranslation;
|
||||
translation /= LEAN_DAMPING_FACTOR;
|
||||
translation.x *= -1;
|
||||
|
||||
_headTranslation = (translation + _previousTranslation) / 2.0f;
|
||||
_previousTranslation = translation;
|
||||
|
||||
// Compute relative rotation
|
||||
rotation = glm::inverse(_referenceRotation) * rotation;
|
||||
|
||||
// copy values
|
||||
_headTranslation = translation;
|
||||
_headRotation = rotation;
|
||||
|
||||
if (_lastReceiveTimestamp == 0) {
|
||||
// On first packet, reset coefficients
|
||||
}
|
||||
|
||||
// Set blendshapes
|
||||
float EYE_MAGNIFIER = 4.0f;
|
||||
float rightEye = glm::clamp((updateAndGetCoefficient(_rightEye, packet.expressions[0])) * EYE_MAGNIFIER, 0.0f, 1.0f);
|
||||
_blendshapeCoefficients[_rightBlinkIndex] = rightEye;
|
||||
float leftEye = glm::clamp((updateAndGetCoefficient(_leftEye, packet.expressions[1])) * EYE_MAGNIFIER, 0.0f, 1.0f);
|
||||
_blendshapeCoefficients[_leftBlinkIndex] = leftEye;
|
||||
_headRotation = (rotation + _previousRotation) / 2.0f;
|
||||
_previousRotation = rotation;
|
||||
|
||||
|
||||
float leftBrow = 1.0f - rescaleCoef(packet.expressions[14]);
|
||||
if (leftBrow < 0.5f) {
|
||||
_blendshapeCoefficients[_browDownLeftIndex] = 1.0f - 2.0f * leftBrow;
|
||||
_blendshapeCoefficients[_browUpLeftIndex] = 0.0f;
|
||||
// The DDE coefficients, overall, range from -0.2 to 1.5 or so. However, individual coefficients typically vary much
|
||||
// less than this.packet.expressions[1]
|
||||
|
||||
// Eye blendshapes
|
||||
static const float RELAXED_EYE_VALUE = 0.2f;
|
||||
static const float EYE_OPEN_SCALE = 4.0f;
|
||||
static const float EYE_BLINK_SCALE = 2.5f;
|
||||
float leftEye = (packet.expressions[1] + _previousExpressions[1]) / 2.0f - RELAXED_EYE_VALUE;
|
||||
float rightEye = (packet.expressions[0] + _previousExpressions[0]) / 2.0f - RELAXED_EYE_VALUE;
|
||||
if (leftEye > 0.0f) {
|
||||
_blendshapeCoefficients[_leftBlinkIndex] = glm::clamp(EYE_BLINK_SCALE * leftEye, 0.0f, 1.0f);
|
||||
_blendshapeCoefficients[_leftEyeOpenIndex] = 0.0f;
|
||||
} else {
|
||||
_blendshapeCoefficients[_leftBlinkIndex] = 0.0f;
|
||||
_blendshapeCoefficients[_leftEyeOpenIndex] = glm::clamp(EYE_OPEN_SCALE * -leftEye, 0.0f, 1.0f);
|
||||
}
|
||||
if (rightEye > 0.0f) {
|
||||
_blendshapeCoefficients[_rightBlinkIndex] = glm::clamp(EYE_BLINK_SCALE * rightEye, 0.0f, 1.0f);
|
||||
_blendshapeCoefficients[_rightEyeOpenIndex] = 0.0f;
|
||||
} else {
|
||||
_blendshapeCoefficients[_rightBlinkIndex] = 0.0f;
|
||||
_blendshapeCoefficients[_rightEyeOpenIndex] = glm::clamp(EYE_OPEN_SCALE * -rightEye, 0.0f, 1.0f);
|
||||
}
|
||||
_previousExpressions[1] = packet.expressions[1];
|
||||
_previousExpressions[0] = packet.expressions[0];
|
||||
|
||||
// Eyebrow blendshapes
|
||||
static const float BROW_UP_SCALE = 3.0f;
|
||||
static const float BROW_DOWN_SCALE = 3.0f;
|
||||
float browCenter = (packet.expressions[17] + _previousExpressions[17]) / 2.0f;
|
||||
if (browCenter > 0) {
|
||||
float browUp = glm::clamp(BROW_UP_SCALE * browCenter, 0.0f, 1.0f);
|
||||
_blendshapeCoefficients[_browUpCenterIndex] = browUp;
|
||||
_blendshapeCoefficients[_browUpLeftIndex] = browUp;
|
||||
_blendshapeCoefficients[_browDownLeftIndex] = 0.0f;
|
||||
_blendshapeCoefficients[_browUpLeftIndex] = 2.0f * (leftBrow - 0.5f);
|
||||
}
|
||||
float rightBrow = 1.0f - rescaleCoef(packet.expressions[15]);
|
||||
if (rightBrow < 0.5f) {
|
||||
_blendshapeCoefficients[_browDownRightIndex] = 1.0f - 2.0f * rightBrow;
|
||||
_blendshapeCoefficients[_browUpRightIndex] = 0.0f;
|
||||
} else {
|
||||
_blendshapeCoefficients[_browUpRightIndex] = browUp;
|
||||
_blendshapeCoefficients[_browDownRightIndex] = 0.0f;
|
||||
_blendshapeCoefficients[_browUpRightIndex] = 2.0f * (rightBrow - 0.5f);
|
||||
} else {
|
||||
float browDown = glm::clamp(BROW_DOWN_SCALE * -browCenter, 0.0f, 1.0f);
|
||||
_blendshapeCoefficients[_browUpCenterIndex] = 0.0f;
|
||||
_blendshapeCoefficients[_browUpLeftIndex] = 0.0f;
|
||||
_blendshapeCoefficients[_browDownLeftIndex] = browDown;
|
||||
_blendshapeCoefficients[_browUpRightIndex] = 0.0f;
|
||||
_blendshapeCoefficients[_browDownRightIndex] = browDown;
|
||||
}
|
||||
|
||||
float JAW_OPEN_MAGNIFIER = 1.4f;
|
||||
_blendshapeCoefficients[_jawOpenIndex] = rescaleCoef(packet.expressions[21]) * JAW_OPEN_MAGNIFIER;
|
||||
|
||||
float SMILE_MULTIPLIER = 2.0f;
|
||||
_blendshapeCoefficients[_mouthSmileLeftIndex] = glm::clamp(packet.expressions[24] * SMILE_MULTIPLIER, 0.0f, 1.0f);
|
||||
_blendshapeCoefficients[_mouthSmileRightIndex] = glm::clamp(packet.expressions[23] * SMILE_MULTIPLIER, 0.0f, 1.0f);
|
||||
|
||||
|
||||
_previousExpressions[17] = packet.expressions[17];
|
||||
|
||||
// Mouth blendshapes
|
||||
static const float JAW_OPEN_THRESHOLD = 0.16f;
|
||||
static const float JAW_OPEN_SCALE = 1.4f;
|
||||
static const float SMILE_THRESHOLD = 0.18f;
|
||||
static const float SMILE_SCALE = 1.5f;
|
||||
float smileLeft = (packet.expressions[24] + _previousExpressions[24]) / 2.0f;
|
||||
float smileRight = (packet.expressions[23] + _previousExpressions[23]) / 2.0f;
|
||||
_blendshapeCoefficients[_jawOpenIndex] = glm::clamp(JAW_OPEN_SCALE * (packet.expressions[21] - JAW_OPEN_THRESHOLD),
|
||||
0.0f, 1.0f);
|
||||
_blendshapeCoefficients[_mouthSmileLeftIndex] = glm::clamp(SMILE_SCALE * (smileLeft - SMILE_THRESHOLD), 0.0f, 1.0f);
|
||||
_blendshapeCoefficients[_mouthSmileRightIndex] = glm::clamp(SMILE_SCALE * (smileRight - SMILE_THRESHOLD), 0.0f, 1.0f);
|
||||
_previousExpressions[24] = packet.expressions[24];
|
||||
_previousExpressions[23] = packet.expressions[23];
|
||||
|
||||
} else {
|
||||
qDebug() << "[Error] DDE Face Tracker Decode Error";
|
||||
}
|
||||
|
|
|
@ -23,12 +23,10 @@ class DdeFaceTracker : public FaceTracker, public Dependency {
|
|||
SINGLETON_DEPENDENCY
|
||||
|
||||
public:
|
||||
//initialization
|
||||
void init();
|
||||
void reset();
|
||||
void update();
|
||||
|
||||
bool isActive() const;
|
||||
virtual void reset() { _reset = true; }
|
||||
|
||||
virtual bool isActive() const;
|
||||
virtual bool isTracking() const { return isActive(); }
|
||||
|
||||
float getLeftBlink() const { return getBlendshapeCoefficient(_leftBlinkIndex); }
|
||||
float getRightBlink() const { return getBlendshapeCoefficient(_rightBlinkIndex); }
|
||||
|
@ -90,10 +88,11 @@ private:
|
|||
int _mouthSmileRightIndex;
|
||||
|
||||
int _jawOpenIndex;
|
||||
|
||||
float _leftEye[3];
|
||||
float _rightEye[3];
|
||||
|
||||
|
||||
// Previous values for simple smoothing
|
||||
glm::vec3 _previousTranslation;
|
||||
glm::quat _previousRotation;
|
||||
QVector<float> _previousExpressions;
|
||||
};
|
||||
|
||||
#endif // hifi_DdeFaceTracker_h
|
|
@ -9,9 +9,60 @@
|
|||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#include <GLMHelpers.h>
|
||||
|
||||
#include "FaceTracker.h"
|
||||
|
||||
FaceTracker::FaceTracker() :
|
||||
_estimatedEyePitch(0.0f),
|
||||
_estimatedEyeYaw(0.0f) {
|
||||
inline float FaceTracker::getBlendshapeCoefficient(int index) const {
|
||||
return isValidBlendshapeIndex(index) ? glm::mix(0.0f, _blendshapeCoefficients[index], getFadeCoefficient())
|
||||
: 0.0f;
|
||||
}
|
||||
|
||||
const QVector<float>& FaceTracker::getBlendshapeCoefficients() const {
|
||||
static QVector<float> blendshapes;
|
||||
float fadeCoefficient = getFadeCoefficient();
|
||||
if (fadeCoefficient == 1.0f) {
|
||||
return _blendshapeCoefficients;
|
||||
} else {
|
||||
blendshapes.resize(_blendshapeCoefficients.size());
|
||||
for (int i = 0; i < _blendshapeCoefficients.size(); i++) {
|
||||
blendshapes[i] = glm::mix(0.0f, _blendshapeCoefficients[i], fadeCoefficient);
|
||||
}
|
||||
return blendshapes;
|
||||
}
|
||||
}
|
||||
|
||||
float FaceTracker::getFadeCoefficient() const {
|
||||
return _fadeCoefficient;
|
||||
}
|
||||
|
||||
const glm::vec3 FaceTracker::getHeadTranslation() const {
|
||||
return glm::mix(glm::vec3(0.0f), _headTranslation, getFadeCoefficient());
|
||||
}
|
||||
|
||||
const glm::quat FaceTracker::getHeadRotation() const {
|
||||
return safeMix(glm::quat(), _headRotation, getFadeCoefficient());
|
||||
}
|
||||
|
||||
void FaceTracker::update(float deltaTime) {
|
||||
// Based on exponential distributions: http://en.wikipedia.org/wiki/Exponential_distribution
|
||||
static const float EPSILON = 0.02f; // MUST BE < 1.0f
|
||||
static const float INVERSE_AT_EPSILON = -std::log(EPSILON); // So that f(1.0f) = EPSILON ~ 0.0f
|
||||
static const float RELAXATION_TIME = 0.8f; // sec
|
||||
|
||||
if (isTracking()) {
|
||||
if (_relaxationStatus == 1.0f) {
|
||||
_fadeCoefficient = 1.0f;
|
||||
return;
|
||||
}
|
||||
_relaxationStatus = glm::clamp(_relaxationStatus + deltaTime / RELAXATION_TIME, 0.0f, 1.0f);
|
||||
_fadeCoefficient = 1.0f - std::exp(-_relaxationStatus * INVERSE_AT_EPSILON);
|
||||
} else {
|
||||
if (_relaxationStatus == 0.0f) {
|
||||
_fadeCoefficient = 0.0f;
|
||||
return;
|
||||
}
|
||||
_relaxationStatus = glm::clamp(_relaxationStatus - deltaTime / RELAXATION_TIME, 0.0f, 1.0f);
|
||||
_fadeCoefficient = std::exp(-(1.0f - _relaxationStatus) * INVERSE_AT_EPSILON);
|
||||
}
|
||||
}
|
|
@ -18,29 +18,40 @@
|
|||
#include <glm/glm.hpp>
|
||||
#include <glm/gtc/quaternion.hpp>
|
||||
|
||||
/// Base class for face trackers (Faceshift, Visage).
|
||||
/// Base class for face trackers (Faceshift, Visage, DDE).
|
||||
class FaceTracker : public QObject {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
FaceTracker();
|
||||
virtual ~FaceTracker() {}
|
||||
virtual bool isActive() const { return false; }
|
||||
virtual bool isTracking() const { return false; }
|
||||
|
||||
const glm::vec3& getHeadTranslation() const { return _headTranslation; }
|
||||
const glm::quat& getHeadRotation() const { return _headRotation; }
|
||||
virtual void init() {}
|
||||
virtual void update(float deltaTime);
|
||||
virtual void reset() {}
|
||||
|
||||
float getFadeCoefficient() const;
|
||||
|
||||
const glm::vec3 getHeadTranslation() const;
|
||||
const glm::quat getHeadRotation() const;
|
||||
|
||||
float getEstimatedEyePitch() const { return _estimatedEyePitch; }
|
||||
float getEstimatedEyeYaw() const { return _estimatedEyeYaw; }
|
||||
|
||||
const QVector<float>& getBlendshapeCoefficients() const { return _blendshapeCoefficients; }
|
||||
int getNumBlendshapes() const { return _blendshapeCoefficients.size(); }
|
||||
bool isValidBlendshapeIndex(int index) const { return index >= 0 && index < getNumBlendshapes(); }
|
||||
const QVector<float>& getBlendshapeCoefficients() const;
|
||||
float getBlendshapeCoefficient(int index) const;
|
||||
|
||||
protected:
|
||||
|
||||
glm::vec3 _headTranslation;
|
||||
glm::quat _headRotation;
|
||||
float _estimatedEyePitch;
|
||||
float _estimatedEyeYaw;
|
||||
glm::vec3 _headTranslation = glm::vec3(0.0f);
|
||||
glm::quat _headRotation = glm::quat();
|
||||
float _estimatedEyePitch = 0.0f;
|
||||
float _estimatedEyeYaw = 0.0f;
|
||||
QVector<float> _blendshapeCoefficients;
|
||||
|
||||
float _relaxationStatus = 0.0f; // Between 0.0f and 1.0f
|
||||
float _fadeCoefficient = 0.0f; // Between 0.0f and 1.0f
|
||||
};
|
||||
|
||||
#endif // hifi_FaceTracker_h
|
||||
|
|
|
@ -25,37 +25,11 @@ using namespace fs;
|
|||
|
||||
using namespace std;
|
||||
|
||||
const QString DEFAULT_FACESHIFT_HOSTNAME = "localhost";
|
||||
const quint16 FACESHIFT_PORT = 33433;
|
||||
float STARTING_FACESHIFT_FRAME_TIME = 0.033f;
|
||||
const float DEFAULT_FACESHIFT_EYE_DEFLECTION = 0.25f;
|
||||
|
||||
Faceshift::Faceshift() :
|
||||
_tcpEnabled(true),
|
||||
_tcpRetryCount(0),
|
||||
_lastTrackingStateReceived(0),
|
||||
_averageFrameTime(STARTING_FACESHIFT_FRAME_TIME),
|
||||
_headAngularVelocity(0),
|
||||
_headLinearVelocity(0),
|
||||
_lastHeadTranslation(0),
|
||||
_filteredHeadTranslation(0),
|
||||
_eyeGazeLeftPitch(0.0f),
|
||||
_eyeGazeLeftYaw(0.0f),
|
||||
_eyeGazeRightPitch(0.0f),
|
||||
_eyeGazeRightYaw(0.0f),
|
||||
_leftBlinkIndex(0), // see http://support.faceshift.com/support/articles/35129-export-of-blendshapes
|
||||
_rightBlinkIndex(1),
|
||||
_leftEyeOpenIndex(8),
|
||||
_rightEyeOpenIndex(9),
|
||||
_browDownLeftIndex(14),
|
||||
_browDownRightIndex(15),
|
||||
_browUpCenterIndex(16),
|
||||
_browUpLeftIndex(17),
|
||||
_browUpRightIndex(18),
|
||||
_mouthSmileLeftIndex(28),
|
||||
_mouthSmileRightIndex(29),
|
||||
_jawOpenIndex(21),
|
||||
_longTermAverageEyePitch(0.0f),
|
||||
_longTermAverageEyeYaw(0.0f),
|
||||
_longTermAverageInitialized(false),
|
||||
_eyeDeflection("faceshiftEyeDeflection", DEFAULT_FACESHIFT_EYE_DEFLECTION),
|
||||
_hostname("faceshiftHostname", DEFAULT_FACESHIFT_HOSTNAME)
|
||||
{
|
||||
|
@ -71,31 +45,17 @@ Faceshift::Faceshift() :
|
|||
#endif
|
||||
}
|
||||
|
||||
#ifdef HAVE_FACESHIFT
|
||||
void Faceshift::init() {
|
||||
#ifdef HAVE_FACESHIFT
|
||||
setTCPEnabled(Menu::getInstance()->isOptionChecked(MenuOption::Faceshift));
|
||||
#endif
|
||||
}
|
||||
|
||||
bool Faceshift::isConnectedOrConnecting() const {
|
||||
return _tcpSocket.state() == QAbstractSocket::ConnectedState ||
|
||||
(_tcpRetryCount == 0 && _tcpSocket.state() != QAbstractSocket::UnconnectedState);
|
||||
}
|
||||
|
||||
bool Faceshift::isActive() const {
|
||||
#ifdef HAVE_FACESHIFT
|
||||
const quint64 ACTIVE_TIMEOUT_USECS = 1000000;
|
||||
return (usecTimestampNow() - _lastTrackingStateReceived) < ACTIVE_TIMEOUT_USECS;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
void Faceshift::update() {
|
||||
void Faceshift::update(float deltaTime) {
|
||||
if (!isActive()) {
|
||||
return;
|
||||
}
|
||||
PerformanceTimer perfTimer("faceshift");
|
||||
FaceTracker::update(deltaTime);
|
||||
|
||||
// get the euler angles relative to the window
|
||||
glm::vec3 eulers = glm::degrees(safeEulerAngles(_headRotation * glm::quat(glm::radians(glm::vec3(
|
||||
(_eyeGazeLeftPitch + _eyeGazeRightPitch) / 2.0f, (_eyeGazeLeftYaw + _eyeGazeRightYaw) / 2.0f, 0.0f)))));
|
||||
|
@ -116,14 +76,28 @@ void Faceshift::update() {
|
|||
}
|
||||
|
||||
void Faceshift::reset() {
|
||||
#ifdef HAVE_FACESHIFT
|
||||
if (_tcpSocket.state() == QAbstractSocket::ConnectedState) {
|
||||
string message;
|
||||
fsBinaryStream::encode_message(message, fsMsgCalibrateNeutral());
|
||||
send(message);
|
||||
}
|
||||
_longTermAverageInitialized = false;
|
||||
}
|
||||
|
||||
bool Faceshift::isActive() const {
|
||||
const quint64 ACTIVE_TIMEOUT_USECS = 1000000;
|
||||
return (usecTimestampNow() - _lastTrackingStateReceived) < ACTIVE_TIMEOUT_USECS;
|
||||
}
|
||||
|
||||
bool Faceshift::isTracking() const {
|
||||
return isActive() && _tracking;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
bool Faceshift::isConnectedOrConnecting() const {
|
||||
return _tcpSocket.state() == QAbstractSocket::ConnectedState ||
|
||||
(_tcpRetryCount == 0 && _tcpSocket.state() != QAbstractSocket::UnconnectedState);
|
||||
}
|
||||
|
||||
void Faceshift::updateFakeCoefficients(float leftBlink, float rightBlink, float browUp,
|
||||
|
@ -148,12 +122,13 @@ void Faceshift::updateFakeCoefficients(float leftBlink, float rightBlink, float
|
|||
}
|
||||
|
||||
void Faceshift::setTCPEnabled(bool enabled) {
|
||||
#ifdef HAVE_FACESHIFT
|
||||
if ((_tcpEnabled = enabled)) {
|
||||
connectSocket();
|
||||
|
||||
} else {
|
||||
_tcpSocket.disconnectFromHost();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void Faceshift::connectSocket() {
|
||||
|
@ -202,10 +177,6 @@ void Faceshift::readFromSocket() {
|
|||
receive(_tcpSocket.readAll());
|
||||
}
|
||||
|
||||
float Faceshift::getBlendshapeCoefficient(int index) const {
|
||||
return (index >= 0 && index < (int)_blendshapeCoefficients.size()) ? _blendshapeCoefficients[index] : 0.0f;
|
||||
}
|
||||
|
||||
void Faceshift::send(const std::string& message) {
|
||||
_tcpSocket.write(message.data(), message.size());
|
||||
}
|
||||
|
|
|
@ -24,8 +24,7 @@
|
|||
|
||||
#include "FaceTracker.h"
|
||||
|
||||
const float DEFAULT_FACESHIFT_EYE_DEFLECTION = 0.25f;
|
||||
const QString DEFAULT_FACESHIFT_HOSTNAME = "localhost";
|
||||
const float STARTING_FACESHIFT_FRAME_TIME = 0.033f;
|
||||
|
||||
/// Handles interaction with the Faceshift software, which provides head position/orientation and facial features.
|
||||
class Faceshift : public FaceTracker, public Dependency {
|
||||
|
@ -33,11 +32,17 @@ class Faceshift : public FaceTracker, public Dependency {
|
|||
SINGLETON_DEPENDENCY
|
||||
|
||||
public:
|
||||
void init();
|
||||
#ifdef HAVE_FACESHIFT
|
||||
// If we don't have faceshift, use the base class' methods
|
||||
virtual void init();
|
||||
virtual void update(float deltaTime);
|
||||
virtual void reset();
|
||||
|
||||
bool isConnectedOrConnecting() const;
|
||||
virtual bool isActive() const;
|
||||
virtual bool isTracking() const;
|
||||
#endif
|
||||
|
||||
bool isActive() const;
|
||||
bool isConnectedOrConnecting() const;
|
||||
|
||||
const glm::vec3& getHeadAngularVelocity() const { return _headAngularVelocity; }
|
||||
|
||||
|
@ -68,9 +73,6 @@ public:
|
|||
|
||||
QString getHostname() { return _hostname.get(); }
|
||||
void setHostname(const QString& hostname);
|
||||
|
||||
void update();
|
||||
void reset();
|
||||
|
||||
void updateFakeCoefficients(float leftBlink,
|
||||
float rightBlink,
|
||||
|
@ -82,15 +84,12 @@ public:
|
|||
QVector<float>& coefficients) const;
|
||||
|
||||
signals:
|
||||
|
||||
void connectionStateChanged();
|
||||
|
||||
public slots:
|
||||
|
||||
void setTCPEnabled(bool enabled);
|
||||
|
||||
private slots:
|
||||
|
||||
void connectSocket();
|
||||
void noteConnected();
|
||||
void noteError(QAbstractSocket::SocketError error);
|
||||
|
@ -101,8 +100,6 @@ private:
|
|||
Faceshift();
|
||||
virtual ~Faceshift() {}
|
||||
|
||||
float getBlendshapeCoefficient(int index) const;
|
||||
|
||||
void send(const std::string& message);
|
||||
void receive(const QByteArray& buffer);
|
||||
|
||||
|
@ -113,48 +110,48 @@ private:
|
|||
fs::fsBinaryStream _stream;
|
||||
#endif
|
||||
|
||||
bool _tcpEnabled;
|
||||
int _tcpRetryCount;
|
||||
bool _tracking;
|
||||
quint64 _lastTrackingStateReceived;
|
||||
float _averageFrameTime;
|
||||
bool _tcpEnabled = true;
|
||||
int _tcpRetryCount = 0;
|
||||
bool _tracking = false;
|
||||
quint64 _lastTrackingStateReceived = 0;
|
||||
float _averageFrameTime = STARTING_FACESHIFT_FRAME_TIME;
|
||||
|
||||
glm::vec3 _headAngularVelocity;
|
||||
glm::vec3 _headLinearVelocity;
|
||||
glm::vec3 _lastHeadTranslation;
|
||||
glm::vec3 _filteredHeadTranslation;
|
||||
glm::vec3 _headAngularVelocity = glm::vec3(0.0f);
|
||||
glm::vec3 _headLinearVelocity = glm::vec3(0.0f);
|
||||
glm::vec3 _lastHeadTranslation = glm::vec3(0.0f);
|
||||
glm::vec3 _filteredHeadTranslation = glm::vec3(0.0f);
|
||||
|
||||
// degrees
|
||||
float _eyeGazeLeftPitch;
|
||||
float _eyeGazeLeftYaw;
|
||||
float _eyeGazeRightPitch;
|
||||
float _eyeGazeRightYaw;
|
||||
|
||||
int _leftBlinkIndex;
|
||||
int _rightBlinkIndex;
|
||||
int _leftEyeOpenIndex;
|
||||
int _rightEyeOpenIndex;
|
||||
|
||||
// Brows
|
||||
int _browDownLeftIndex;
|
||||
int _browDownRightIndex;
|
||||
int _browUpCenterIndex;
|
||||
int _browUpLeftIndex;
|
||||
int _browUpRightIndex;
|
||||
|
||||
int _mouthSmileLeftIndex;
|
||||
int _mouthSmileRightIndex;
|
||||
|
||||
int _jawOpenIndex;
|
||||
float _eyeGazeLeftPitch = 0.0f;
|
||||
float _eyeGazeLeftYaw = 0.0f;
|
||||
float _eyeGazeRightPitch = 0.0f;
|
||||
float _eyeGazeRightYaw = 0.0f;
|
||||
|
||||
// degrees
|
||||
float _longTermAverageEyePitch;
|
||||
float _longTermAverageEyeYaw;
|
||||
bool _longTermAverageInitialized;
|
||||
float _longTermAverageEyePitch = 0.0f;
|
||||
float _longTermAverageEyeYaw = 0.0f;
|
||||
bool _longTermAverageInitialized = false;
|
||||
|
||||
Setting::Handle<float> _eyeDeflection;
|
||||
Setting::Handle<QString> _hostname;
|
||||
|
||||
// see http://support.faceshift.com/support/articles/35129-export-of-blendshapes
|
||||
int _leftBlinkIndex = 0;
|
||||
int _rightBlinkIndex = 1;
|
||||
int _leftEyeOpenIndex = 8;
|
||||
int _rightEyeOpenIndex = 9;
|
||||
|
||||
// Brows
|
||||
int _browDownLeftIndex = 14;
|
||||
int _browDownRightIndex = 15;
|
||||
int _browUpCenterIndex = 16;
|
||||
int _browUpLeftIndex = 17;
|
||||
int _browUpRightIndex = 18;
|
||||
|
||||
int _mouthSmileLeftIndex = 28;
|
||||
int _mouthSmileRightIndex = 29;
|
||||
|
||||
int _jawOpenIndex = 21;
|
||||
};
|
||||
|
||||
#endif // hifi_Faceshift_h
|
||||
|
|
|
@ -41,7 +41,6 @@ const glm::vec3 DEFAULT_HEAD_ORIGIN(0.0f, 0.0f, 0.7f);
|
|||
|
||||
Visage::Visage() :
|
||||
_enabled(false),
|
||||
_active(false),
|
||||
_headOrigin(DEFAULT_HEAD_ORIGIN) {
|
||||
|
||||
#ifdef HAVE_VISAGE
|
||||
|
@ -119,20 +118,20 @@ static const QMultiHash<QByteArray, QPair<int, float> >& getActionUnitNameMap()
|
|||
}
|
||||
#endif
|
||||
|
||||
const float TRANSLATION_SCALE = 20.0f;
|
||||
|
||||
#ifdef HAVE_VISAGE
|
||||
const float TRANSLATION_SCALE = 20.0f;
|
||||
void Visage::init() {
|
||||
connect(DependencyManager::get<Faceshift>().data(), SIGNAL(connectionStateChanged()), SLOT(updateEnabled()));
|
||||
updateEnabled();
|
||||
}
|
||||
|
||||
void Visage::update() {
|
||||
#ifdef HAVE_VISAGE
|
||||
_active = (_tracker->getTrackingData(_data) == TRACK_STAT_OK);
|
||||
if (!_active) {
|
||||
void Visage::update(float deltaTime) {
|
||||
if (!isActive()) {
|
||||
return;
|
||||
}
|
||||
PerformanceTimer perfTimer("visage");
|
||||
FaceTracker::update(deltaTime);
|
||||
|
||||
_headRotation = glm::quat(glm::vec3(-_data->faceRotation[0], -_data->faceRotation[1], _data->faceRotation[2]));
|
||||
_headTranslation = (glm::vec3(_data->faceTranslation[0], _data->faceTranslation[1], _data->faceTranslation[2]) -
|
||||
_headOrigin) * TRANSLATION_SCALE;
|
||||
|
@ -164,12 +163,12 @@ void Visage::update() {
|
|||
}
|
||||
_blendshapeCoefficients[leftEyeBlinkIndex] = 1.0f - _data->eyeClosure[1];
|
||||
_blendshapeCoefficients[rightEyeBlinkIndex] = 1.0f - _data->eyeClosure[0];
|
||||
#endif
|
||||
}
|
||||
|
||||
void Visage::reset() {
|
||||
_headOrigin += _headTranslation / TRANSLATION_SCALE;
|
||||
}
|
||||
#endif
|
||||
|
||||
void Visage::updateEnabled() {
|
||||
setEnabled(Menu::getInstance()->isOptionChecked(MenuOption::Visage) &&
|
||||
|
|
|
@ -31,15 +31,16 @@ class Visage : public FaceTracker, public Dependency {
|
|||
SINGLETON_DEPENDENCY
|
||||
|
||||
public:
|
||||
void init();
|
||||
#ifdef HAVE_VISAGE
|
||||
virtual void init();
|
||||
virtual void update(float deltaTime);
|
||||
virtual void reset();
|
||||
|
||||
bool isActive() const { return _active; }
|
||||
|
||||
void update();
|
||||
void reset();
|
||||
virtual bool isActive() const { return _tracker->getTrackingData(_data) == TRACK_STAT_OK; }
|
||||
virtual bool isTracking() const { return isActive(); }
|
||||
#endif
|
||||
|
||||
public slots:
|
||||
|
||||
void updateEnabled();
|
||||
|
||||
private:
|
||||
|
@ -55,7 +56,6 @@ private:
|
|||
void setEnabled(bool enabled);
|
||||
|
||||
bool _enabled;
|
||||
bool _active;
|
||||
|
||||
glm::vec3 _headOrigin;
|
||||
};
|
||||
|
|
|
@ -34,7 +34,8 @@
|
|||
|
||||
using namespace std;
|
||||
|
||||
const int STATS_PELS_PER_LINE = 20;
|
||||
const int STATS_PELS_PER_LINE = 16;
|
||||
const int STATS_PELS_INITIALOFFSET = 12;
|
||||
|
||||
const int STATS_GENERAL_MIN_WIDTH = 165;
|
||||
const int STATS_PING_MIN_WIDTH = 190;
|
||||
|
@ -170,7 +171,7 @@ void Stats::drawBackground(unsigned int rgba, int x, int y, int width, int heigh
|
|||
}
|
||||
|
||||
bool Stats::includeTimingRecord(const QString& name) {
|
||||
if (Menu::getInstance()->isOptionChecked(MenuOption::DisplayTimingDetails)) {
|
||||
if (Menu::getInstance()->isOptionChecked(MenuOption::DisplayDebugTimingDetails)) {
|
||||
if (name.startsWith("/idle/update/")) {
|
||||
if (name.startsWith("/idle/update/myAvatar/")) {
|
||||
if (name.startsWith("/idle/update/myAvatar/simulate/")) {
|
||||
|
@ -231,7 +232,7 @@ void Stats::display(
|
|||
|
||||
PerformanceTimer::tallyAllTimerRecords(); // do this even if we're not displaying them, so they don't stack up
|
||||
|
||||
if (_expanded && Menu::getInstance()->isOptionChecked(MenuOption::DisplayTimingDetails)) {
|
||||
if (_expanded && Menu::getInstance()->isOptionChecked(MenuOption::DisplayDebugTimingDetails)) {
|
||||
|
||||
columnOneWidth = _generalStatsWidth + _pingStatsWidth + _geoStatsWidth; // 3 columns wide...
|
||||
// we will also include room for 1 line per timing record and a header of 4 lines
|
||||
|
@ -239,15 +240,21 @@ void Stats::display(
|
|||
|
||||
const QMap<QString, PerformanceTimerRecord>& allRecords = PerformanceTimer::getAllTimerRecords();
|
||||
QMapIterator<QString, PerformanceTimerRecord> i(allRecords);
|
||||
bool onlyDisplayTopTen = Menu::getInstance()->isOptionChecked(MenuOption::OnlyDisplayTopTen);
|
||||
int statsLines = 0;
|
||||
while (i.hasNext()) {
|
||||
i.next();
|
||||
if (includeTimingRecord(i.key())) {
|
||||
lines++;
|
||||
statsLines++;
|
||||
if (onlyDisplayTopTen && statsLines == 10) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
drawBackground(backgroundColor, horizontalOffset, 0, columnOneWidth, lines * STATS_PELS_PER_LINE + 10);
|
||||
drawBackground(backgroundColor, horizontalOffset, 0, columnOneWidth, (lines + 1) * STATS_PELS_PER_LINE);
|
||||
horizontalOffset += 5;
|
||||
|
||||
int columnOneHorizontalOffset = horizontalOffset;
|
||||
|
@ -256,7 +263,7 @@ void Stats::display(
|
|||
QString avatarNodes = QString("Avatars: %1").arg(totalAvatars);
|
||||
QString framesPerSecond = QString("Framerate: %1 FPS").arg(fps, 3, 'f', 0);
|
||||
|
||||
verticalOffset += STATS_PELS_PER_LINE;
|
||||
verticalOffset = STATS_PELS_INITIALOFFSET; // first one is offset by less than a line
|
||||
drawText(horizontalOffset, verticalOffset, scale, rotation, font, serverNodes.toUtf8().constData(), color);
|
||||
verticalOffset += STATS_PELS_PER_LINE;
|
||||
drawText(horizontalOffset, verticalOffset, scale, rotation, font, avatarNodes.toUtf8().constData(), color);
|
||||
|
@ -275,9 +282,10 @@ void Stats::display(
|
|||
|
||||
|
||||
// TODO: the display of these timing details should all be moved to JavaScript
|
||||
if (_expanded && Menu::getInstance()->isOptionChecked(MenuOption::DisplayTimingDetails)) {
|
||||
if (_expanded && Menu::getInstance()->isOptionChecked(MenuOption::DisplayDebugTimingDetails)) {
|
||||
bool onlyDisplayTopTen = Menu::getInstance()->isOptionChecked(MenuOption::OnlyDisplayTopTen);
|
||||
// Timing details...
|
||||
verticalOffset += STATS_PELS_PER_LINE * 6; // skip 6 lines to be under the other columns
|
||||
verticalOffset += STATS_PELS_PER_LINE * 4; // skip 3 lines to be under the other columns
|
||||
drawText(columnOneHorizontalOffset, verticalOffset, scale, rotation, font,
|
||||
"-------------------------------------------------------- Function "
|
||||
"------------------------------------------------------- --msecs- -calls--", color);
|
||||
|
@ -296,6 +304,7 @@ void Stats::display(
|
|||
}
|
||||
}
|
||||
|
||||
int linesDisplayed = 0;
|
||||
QMapIterator<float, QString> j(sortedRecords);
|
||||
j.toBack();
|
||||
while (j.hasPrevious()) {
|
||||
|
@ -311,11 +320,15 @@ void Stats::display(
|
|||
|
||||
verticalOffset += STATS_PELS_PER_LINE;
|
||||
drawText(columnOneHorizontalOffset, verticalOffset, scale, rotation, font, perfLine.toUtf8().constData(), color);
|
||||
linesDisplayed++;
|
||||
if (onlyDisplayTopTen && linesDisplayed == 10) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
verticalOffset = 0;
|
||||
verticalOffset = STATS_PELS_INITIALOFFSET;
|
||||
horizontalOffset = _lastHorizontalOffset + _generalStatsWidth + 1;
|
||||
|
||||
if (Menu::getInstance()->isOptionChecked(MenuOption::TestPing)) {
|
||||
|
@ -351,7 +364,7 @@ void Stats::display(
|
|||
|
||||
// only draw our background if column one didn't draw a wide background
|
||||
if (columnOneWidth == _generalStatsWidth) {
|
||||
drawBackground(backgroundColor, horizontalOffset, 0, _pingStatsWidth, lines * STATS_PELS_PER_LINE + 10);
|
||||
drawBackground(backgroundColor, horizontalOffset, 0, _pingStatsWidth, (lines + 1) * STATS_PELS_PER_LINE);
|
||||
}
|
||||
horizontalOffset += 5;
|
||||
|
||||
|
@ -377,7 +390,6 @@ void Stats::display(
|
|||
voxelAvgPing = QString("Entities avg ping: --");
|
||||
}
|
||||
|
||||
verticalOffset += STATS_PELS_PER_LINE;
|
||||
drawText(horizontalOffset, verticalOffset, scale, rotation, font, audioPing.toUtf8().constData(), color);
|
||||
verticalOffset += STATS_PELS_PER_LINE;
|
||||
drawText(horizontalOffset, verticalOffset, scale, rotation, font, avatarPing.toUtf8().constData(), color);
|
||||
|
@ -396,17 +408,17 @@ void Stats::display(
|
|||
drawText(horizontalOffset, verticalOffset, scale, rotation, font, voxelMaxPing.toUtf8().constData(), color);
|
||||
}
|
||||
|
||||
verticalOffset = 0;
|
||||
verticalOffset = STATS_PELS_INITIALOFFSET;
|
||||
horizontalOffset = _lastHorizontalOffset + _generalStatsWidth + _pingStatsWidth + 2;
|
||||
}
|
||||
|
||||
MyAvatar* myAvatar = DependencyManager::get<AvatarManager>()->getMyAvatar();
|
||||
glm::vec3 avatarPos = myAvatar->getPosition();
|
||||
|
||||
lines = _expanded ? 8 : 3;
|
||||
lines = _expanded ? 7 : 3;
|
||||
|
||||
if (columnOneWidth == _generalStatsWidth) {
|
||||
drawBackground(backgroundColor, horizontalOffset, 0, _geoStatsWidth, lines * STATS_PELS_PER_LINE + 10);
|
||||
drawBackground(backgroundColor, horizontalOffset, 0, _geoStatsWidth, (lines + 1) * STATS_PELS_PER_LINE);
|
||||
}
|
||||
horizontalOffset += 5;
|
||||
|
||||
|
@ -418,7 +430,6 @@ void Stats::display(
|
|||
QString avatarBodyYaw = QString("Yaw: %1").arg(myAvatar->getBodyYaw(), -1, 'f', 1);
|
||||
QString avatarMixerStats;
|
||||
|
||||
verticalOffset += STATS_PELS_PER_LINE;
|
||||
drawText(horizontalOffset, verticalOffset, scale, rotation, font, avatarPosition.toUtf8().constData(), color);
|
||||
verticalOffset += STATS_PELS_PER_LINE;
|
||||
drawText(horizontalOffset, verticalOffset, scale, rotation, font, avatarVelocity.toUtf8().constData(), color);
|
||||
|
@ -476,13 +487,13 @@ void Stats::display(
|
|||
}
|
||||
}
|
||||
|
||||
verticalOffset = 0;
|
||||
verticalOffset = STATS_PELS_INITIALOFFSET;
|
||||
horizontalOffset = _lastHorizontalOffset + _generalStatsWidth + _pingStatsWidth + _geoStatsWidth + 3;
|
||||
|
||||
lines = _expanded ? 14 : 3;
|
||||
lines = _expanded ? 10 : 2;
|
||||
|
||||
drawBackground(backgroundColor, horizontalOffset, 0, glCanvas->width() - horizontalOffset,
|
||||
lines * STATS_PELS_PER_LINE + 10);
|
||||
(lines + 1) * STATS_PELS_PER_LINE);
|
||||
horizontalOffset += 5;
|
||||
|
||||
// Model/Entity render details
|
||||
|
@ -491,7 +502,6 @@ void Stats::display(
|
|||
octreeStats << "Entity Items rendered: " << entities->getItemsRendered()
|
||||
<< " / Out of view:" << entities->getItemsOutOfView()
|
||||
<< " / Too small:" << entities->getItemsTooSmall();
|
||||
verticalOffset += STATS_PELS_PER_LINE;
|
||||
drawText(horizontalOffset, verticalOffset, scale, rotation, font, (char*)octreeStats.str().c_str(), color);
|
||||
|
||||
if (_expanded) {
|
||||
|
|
|
@ -32,35 +32,22 @@ void RenderableLightEntityItem::render(RenderArgs* args) {
|
|||
float largestDiameter = glm::max(dimensions.x, dimensions.y, dimensions.z);
|
||||
|
||||
const float MAX_COLOR = 255.0f;
|
||||
float diffuseR = getDiffuseColor()[RED_INDEX] / MAX_COLOR;
|
||||
float diffuseG = getDiffuseColor()[GREEN_INDEX] / MAX_COLOR;
|
||||
float diffuseB = getDiffuseColor()[BLUE_INDEX] / MAX_COLOR;
|
||||
float colorR = getColor()[RED_INDEX] / MAX_COLOR;
|
||||
float colorG = getColor()[GREEN_INDEX] / MAX_COLOR;
|
||||
float colorB = getColor()[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(colorR, colorG, colorB);
|
||||
|
||||
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 constantAttenuation = getConstantAttenuation();
|
||||
float linearAttenuation = getLinearAttenuation();
|
||||
float quadraticAttenuation = getQuadraticAttenuation();
|
||||
float intensity = getIntensity();
|
||||
float exponent = getExponent();
|
||||
float cutoff = glm::radians(getCutoff());
|
||||
|
||||
if (_isSpotlight) {
|
||||
DependencyManager::get<DeferredLightingEffect>()->addSpotLight(position, largestDiameter / 2.0f,
|
||||
ambient, diffuse, specular, constantAttenuation, linearAttenuation, quadraticAttenuation,
|
||||
direction, exponent, cutoff);
|
||||
DependencyManager::get<DeferredLightingEffect>()->addSpotLight(position, largestDiameter / 2.0f,
|
||||
color, intensity, rotation, exponent, cutoff);
|
||||
} else {
|
||||
DependencyManager::get<DeferredLightingEffect>()->addPointLight(position, largestDiameter / 2.0f,
|
||||
ambient, diffuse, specular, constantAttenuation, linearAttenuation, quadraticAttenuation);
|
||||
DependencyManager::get<DeferredLightingEffect>()->addPointLight(position, largestDiameter / 2.0f,
|
||||
color, intensity);
|
||||
}
|
||||
|
||||
#ifdef WANT_DEBUG
|
||||
|
|
|
@ -49,12 +49,7 @@ EntityItemProperties::EntityItemProperties() :
|
|||
CONSTRUCT_PROPERTY(ignoreForCollisions, ENTITY_ITEM_DEFAULT_IGNORE_FOR_COLLISIONS),
|
||||
CONSTRUCT_PROPERTY(collisionsWillMove, ENTITY_ITEM_DEFAULT_COLLISIONS_WILL_MOVE),
|
||||
CONSTRUCT_PROPERTY(isSpotlight, false),
|
||||
CONSTRUCT_PROPERTY(diffuseColor, ),
|
||||
CONSTRUCT_PROPERTY(ambientColor, ),
|
||||
CONSTRUCT_PROPERTY(specularColor, ),
|
||||
CONSTRUCT_PROPERTY(constantAttenuation, 1.0f),
|
||||
CONSTRUCT_PROPERTY(linearAttenuation, 0.0f),
|
||||
CONSTRUCT_PROPERTY(quadraticAttenuation, 0.0f),
|
||||
CONSTRUCT_PROPERTY(intensity, 1.0f),
|
||||
CONSTRUCT_PROPERTY(exponent, 0.0f),
|
||||
CONSTRUCT_PROPERTY(cutoff, PI),
|
||||
CONSTRUCT_PROPERTY(locked, ENTITY_ITEM_DEFAULT_LOCKED),
|
||||
|
@ -222,12 +217,7 @@ EntityPropertyFlags EntityItemProperties::getChangedProperties() const {
|
|||
CHECK_PROPERTY_CHANGE(PROP_IGNORE_FOR_COLLISIONS, ignoreForCollisions);
|
||||
CHECK_PROPERTY_CHANGE(PROP_COLLISIONS_WILL_MOVE, collisionsWillMove);
|
||||
CHECK_PROPERTY_CHANGE(PROP_IS_SPOTLIGHT, isSpotlight);
|
||||
CHECK_PROPERTY_CHANGE(PROP_DIFFUSE_COLOR, diffuseColor);
|
||||
CHECK_PROPERTY_CHANGE(PROP_AMBIENT_COLOR, ambientColor);
|
||||
CHECK_PROPERTY_CHANGE(PROP_SPECULAR_COLOR, specularColor);
|
||||
CHECK_PROPERTY_CHANGE(PROP_CONSTANT_ATTENUATION, constantAttenuation);
|
||||
CHECK_PROPERTY_CHANGE(PROP_LINEAR_ATTENUATION, linearAttenuation);
|
||||
CHECK_PROPERTY_CHANGE(PROP_QUADRATIC_ATTENUATION, quadraticAttenuation);
|
||||
CHECK_PROPERTY_CHANGE(PROP_INTENSITY, intensity);
|
||||
CHECK_PROPERTY_CHANGE(PROP_EXPONENT, exponent);
|
||||
CHECK_PROPERTY_CHANGE(PROP_CUTOFF, cutoff);
|
||||
CHECK_PROPERTY_CHANGE(PROP_LOCKED, locked);
|
||||
|
@ -281,12 +271,7 @@ QScriptValue EntityItemProperties::copyToScriptValue(QScriptEngine* engine) cons
|
|||
COPY_PROPERTY_TO_QSCRIPTVALUE(ignoreForCollisions);
|
||||
COPY_PROPERTY_TO_QSCRIPTVALUE(collisionsWillMove);
|
||||
COPY_PROPERTY_TO_QSCRIPTVALUE(isSpotlight);
|
||||
COPY_PROPERTY_TO_QSCRIPTVALUE_COLOR_GETTER(diffuseColor, getDiffuseColor());
|
||||
COPY_PROPERTY_TO_QSCRIPTVALUE_COLOR_GETTER(ambientColor, getAmbientColor());
|
||||
COPY_PROPERTY_TO_QSCRIPTVALUE_COLOR_GETTER(specularColor, getSpecularColor());
|
||||
COPY_PROPERTY_TO_QSCRIPTVALUE(constantAttenuation);
|
||||
COPY_PROPERTY_TO_QSCRIPTVALUE(linearAttenuation);
|
||||
COPY_PROPERTY_TO_QSCRIPTVALUE(quadraticAttenuation);
|
||||
COPY_PROPERTY_TO_QSCRIPTVALUE(intensity);
|
||||
COPY_PROPERTY_TO_QSCRIPTVALUE(exponent);
|
||||
COPY_PROPERTY_TO_QSCRIPTVALUE(cutoff);
|
||||
COPY_PROPERTY_TO_QSCRIPTVALUE(locked);
|
||||
|
@ -359,12 +344,7 @@ void EntityItemProperties::copyFromScriptValue(const QScriptValue& object) {
|
|||
COPY_PROPERTY_FROM_QSCRIPTVALUE_BOOL(ignoreForCollisions, setIgnoreForCollisions);
|
||||
COPY_PROPERTY_FROM_QSCRIPTVALUE_BOOL(collisionsWillMove, setCollisionsWillMove);
|
||||
COPY_PROPERTY_FROM_QSCRIPTVALUE_BOOL(isSpotlight, setIsSpotlight);
|
||||
COPY_PROPERTY_FROM_QSCRIPTVALUE_COLOR(diffuseColor, setDiffuseColor);
|
||||
COPY_PROPERTY_FROM_QSCRIPTVALUE_COLOR(ambientColor, setAmbientColor);
|
||||
COPY_PROPERTY_FROM_QSCRIPTVALUE_COLOR(specularColor, setSpecularColor);
|
||||
COPY_PROPERTY_FROM_QSCRIPTVALUE_FLOAT(constantAttenuation, setConstantAttenuation);
|
||||
COPY_PROPERTY_FROM_QSCRIPTVALUE_FLOAT(linearAttenuation, setLinearAttenuation);
|
||||
COPY_PROPERTY_FROM_QSCRIPTVALUE_FLOAT(quadraticAttenuation, setQuadraticAttenuation);
|
||||
COPY_PROPERTY_FROM_QSCRIPTVALUE_FLOAT(intensity, setIntensity);
|
||||
COPY_PROPERTY_FROM_QSCRIPTVALUE_FLOAT(exponent, setExponent);
|
||||
COPY_PROPERTY_FROM_QSCRIPTVALUE_FLOAT(cutoff, setCutoff);
|
||||
COPY_PROPERTY_FROM_QSCRIPTVALUE_BOOL(locked, setLocked);
|
||||
|
@ -543,12 +523,8 @@ bool EntityItemProperties::encodeEntityEditPacket(PacketType command, EntityItem
|
|||
|
||||
if (properties.getType() == EntityTypes::Light) {
|
||||
APPEND_ENTITY_PROPERTY(PROP_IS_SPOTLIGHT, appendValue, properties.getIsSpotlight());
|
||||
APPEND_ENTITY_PROPERTY(PROP_DIFFUSE_COLOR, appendColor, properties.getDiffuseColor());
|
||||
APPEND_ENTITY_PROPERTY(PROP_AMBIENT_COLOR, appendColor, properties.getAmbientColor());
|
||||
APPEND_ENTITY_PROPERTY(PROP_SPECULAR_COLOR, appendColor, properties.getSpecularColor());
|
||||
APPEND_ENTITY_PROPERTY(PROP_CONSTANT_ATTENUATION, appendValue, properties.getConstantAttenuation());
|
||||
APPEND_ENTITY_PROPERTY(PROP_LINEAR_ATTENUATION, appendValue, properties.getLinearAttenuation());
|
||||
APPEND_ENTITY_PROPERTY(PROP_QUADRATIC_ATTENUATION, appendValue, properties.getQuadraticAttenuation());
|
||||
APPEND_ENTITY_PROPERTY(PROP_COLOR, appendColor, properties.getColor());
|
||||
APPEND_ENTITY_PROPERTY(PROP_INTENSITY, appendValue, properties.getIntensity());
|
||||
APPEND_ENTITY_PROPERTY(PROP_EXPONENT, appendValue, properties.getExponent());
|
||||
APPEND_ENTITY_PROPERTY(PROP_CUTOFF, appendValue, properties.getCutoff());
|
||||
}
|
||||
|
@ -765,12 +741,8 @@ bool EntityItemProperties::decodeEntityEditPacket(const unsigned char* data, int
|
|||
|
||||
if (properties.getType() == EntityTypes::Light) {
|
||||
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_IS_SPOTLIGHT, bool, setIsSpotlight);
|
||||
READ_ENTITY_PROPERTY_COLOR_TO_PROPERTIES(PROP_DIFFUSE_COLOR, setDiffuseColor);
|
||||
READ_ENTITY_PROPERTY_COLOR_TO_PROPERTIES(PROP_AMBIENT_COLOR, setAmbientColor);
|
||||
READ_ENTITY_PROPERTY_COLOR_TO_PROPERTIES(PROP_SPECULAR_COLOR, setSpecularColor);
|
||||
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_CONSTANT_ATTENUATION, float, setConstantAttenuation);
|
||||
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_LINEAR_ATTENUATION, float, setLinearAttenuation);
|
||||
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_QUADRATIC_ATTENUATION, float, setQuadraticAttenuation);
|
||||
READ_ENTITY_PROPERTY_COLOR_TO_PROPERTIES(PROP_COLOR, setColor);
|
||||
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_INTENSITY, float, setIntensity);
|
||||
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_EXPONENT, float, setExponent);
|
||||
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_CUTOFF, float, setCutoff);
|
||||
}
|
||||
|
@ -835,12 +807,7 @@ void EntityItemProperties::markAllChanged() {
|
|||
_ignoreForCollisionsChanged = true;
|
||||
_collisionsWillMoveChanged = true;
|
||||
|
||||
_diffuseColorChanged = true;
|
||||
_ambientColorChanged = true;
|
||||
_specularColorChanged = true;
|
||||
_constantAttenuationChanged = true;
|
||||
_linearAttenuationChanged = true;
|
||||
_quadraticAttenuationChanged = true;
|
||||
_intensityChanged = true;
|
||||
_exponentChanged = true;
|
||||
_cutoffChanged = true;
|
||||
_lockedChanged = true;
|
||||
|
|
|
@ -66,12 +66,12 @@ enum EntityPropertyList {
|
|||
|
||||
// property used by Light entity
|
||||
PROP_IS_SPOTLIGHT,
|
||||
PROP_DIFFUSE_COLOR,
|
||||
PROP_AMBIENT_COLOR,
|
||||
PROP_SPECULAR_COLOR,
|
||||
PROP_CONSTANT_ATTENUATION,
|
||||
PROP_LINEAR_ATTENUATION,
|
||||
PROP_QUADRATIC_ATTENUATION,
|
||||
PROP_DIFFUSE_COLOR_UNUSED,
|
||||
PROP_AMBIENT_COLOR_UNUSED,
|
||||
PROP_SPECULAR_COLOR_UNUSED,
|
||||
PROP_INTENSITY, // Previously PROP_CONSTANT_ATTENUATION
|
||||
PROP_LINEAR_ATTENUATION_UNUSED,
|
||||
PROP_QUADRATIC_ATTENUATION_UNUSED,
|
||||
PROP_EXPONENT,
|
||||
PROP_CUTOFF,
|
||||
|
||||
|
@ -165,12 +165,7 @@ public:
|
|||
DEFINE_PROPERTY(PROP_IGNORE_FOR_COLLISIONS, IgnoreForCollisions, ignoreForCollisions, bool);
|
||||
DEFINE_PROPERTY(PROP_COLLISIONS_WILL_MOVE, CollisionsWillMove, collisionsWillMove, bool);
|
||||
DEFINE_PROPERTY(PROP_IS_SPOTLIGHT, IsSpotlight, isSpotlight, bool);
|
||||
DEFINE_PROPERTY_REF(PROP_DIFFUSE_COLOR, DiffuseColor, diffuseColor, xColor);
|
||||
DEFINE_PROPERTY_REF(PROP_AMBIENT_COLOR, AmbientColor, ambientColor, xColor);
|
||||
DEFINE_PROPERTY_REF(PROP_SPECULAR_COLOR, SpecularColor, specularColor, xColor);
|
||||
DEFINE_PROPERTY(PROP_CONSTANT_ATTENUATION, ConstantAttenuation, constantAttenuation, float);
|
||||
DEFINE_PROPERTY(PROP_LINEAR_ATTENUATION, LinearAttenuation, linearAttenuation, float);
|
||||
DEFINE_PROPERTY(PROP_QUADRATIC_ATTENUATION, QuadraticAttenuation, quadraticAttenuation, float);
|
||||
DEFINE_PROPERTY(PROP_INTENSITY, Intensity, intensity, float);
|
||||
DEFINE_PROPERTY(PROP_EXPONENT, Exponent, exponent, float);
|
||||
DEFINE_PROPERTY(PROP_CUTOFF, Cutoff, cutoff, float);
|
||||
DEFINE_PROPERTY(PROP_LOCKED, Locked, locked, bool);
|
||||
|
@ -288,12 +283,7 @@ inline QDebug operator<<(QDebug debug, const EntityItemProperties& properties) {
|
|||
DEBUG_PROPERTY_IF_CHANGED(debug, properties, IgnoreForCollisions, ignoreForCollisions, "");
|
||||
DEBUG_PROPERTY_IF_CHANGED(debug, properties, CollisionsWillMove, collisionsWillMove, "");
|
||||
DEBUG_PROPERTY_IF_CHANGED(debug, properties, IsSpotlight, isSpotlight, "");
|
||||
DEBUG_PROPERTY_IF_CHANGED(debug, properties, DiffuseColor, diffuseColor, "");
|
||||
DEBUG_PROPERTY_IF_CHANGED(debug, properties, AmbientColor, ambientColor, "");
|
||||
DEBUG_PROPERTY_IF_CHANGED(debug, properties, SpecularColor, specularColor, "");
|
||||
DEBUG_PROPERTY_IF_CHANGED(debug, properties, ConstantAttenuation, constantAttenuation, "");
|
||||
DEBUG_PROPERTY_IF_CHANGED(debug, properties, LinearAttenuation, linearAttenuation, "");
|
||||
DEBUG_PROPERTY_IF_CHANGED(debug, properties, QuadraticAttenuation, quadraticAttenuation, "");
|
||||
DEBUG_PROPERTY_IF_CHANGED(debug, properties, Intensity, intensity, "");
|
||||
DEBUG_PROPERTY_IF_CHANGED(debug, properties, Exponent, exponent, "");
|
||||
DEBUG_PROPERTY_IF_CHANGED(debug, properties, Cutoff, cutoff, "");
|
||||
DEBUG_PROPERTY_IF_CHANGED(debug, properties, Locked, locked, "");
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
|
||||
#include <ByteCountCoding.h>
|
||||
|
||||
#include "EntityItemID.h"
|
||||
#include "EntityTree.h"
|
||||
#include "EntityTreeElement.h"
|
||||
#include "LightEntityItem.h"
|
||||
|
@ -32,12 +33,8 @@ LightEntityItem::LightEntityItem(const EntityItemID& entityItemID, const EntityI
|
|||
|
||||
// default property values
|
||||
const quint8 MAX_COLOR = 255;
|
||||
_ambientColor[RED_INDEX] = _ambientColor[GREEN_INDEX] = _ambientColor[BLUE_INDEX] = 0;
|
||||
_diffuseColor[RED_INDEX] = _diffuseColor[GREEN_INDEX] = _diffuseColor[BLUE_INDEX] = MAX_COLOR;
|
||||
_specularColor[RED_INDEX] = _specularColor[GREEN_INDEX] = _specularColor[BLUE_INDEX] = MAX_COLOR;
|
||||
_constantAttenuation = 1.0f;
|
||||
_linearAttenuation = 0.0f;
|
||||
_quadraticAttenuation = 0.0f;
|
||||
_color[RED_INDEX] = _color[GREEN_INDEX] = _color[BLUE_INDEX] = 0;
|
||||
_intensity = 1.0f;
|
||||
_exponent = 0.0f;
|
||||
_cutoff = PI;
|
||||
|
||||
|
@ -54,12 +51,8 @@ EntityItemProperties LightEntityItem::getProperties() const {
|
|||
EntityItemProperties properties = EntityItem::getProperties(); // get the properties from our base class
|
||||
|
||||
COPY_ENTITY_PROPERTY_TO_PROPERTIES(isSpotlight, getIsSpotlight);
|
||||
COPY_ENTITY_PROPERTY_TO_PROPERTIES(diffuseColor, getDiffuseXColor);
|
||||
COPY_ENTITY_PROPERTY_TO_PROPERTIES(ambientColor, getAmbientXColor);
|
||||
COPY_ENTITY_PROPERTY_TO_PROPERTIES(specularColor, getSpecularXColor);
|
||||
COPY_ENTITY_PROPERTY_TO_PROPERTIES(constantAttenuation, getConstantAttenuation);
|
||||
COPY_ENTITY_PROPERTY_TO_PROPERTIES(linearAttenuation, getLinearAttenuation);
|
||||
COPY_ENTITY_PROPERTY_TO_PROPERTIES(quadraticAttenuation, getQuadraticAttenuation);
|
||||
COPY_ENTITY_PROPERTY_TO_PROPERTIES(color, getXColor);
|
||||
COPY_ENTITY_PROPERTY_TO_PROPERTIES(intensity, getIntensity);
|
||||
COPY_ENTITY_PROPERTY_TO_PROPERTIES(exponent, getExponent);
|
||||
COPY_ENTITY_PROPERTY_TO_PROPERTIES(cutoff, getCutoff);
|
||||
|
||||
|
@ -70,17 +63,11 @@ bool LightEntityItem::setProperties(const EntityItemProperties& properties) {
|
|||
bool somethingChanged = EntityItem::setProperties(properties); // set the properties in our base class
|
||||
|
||||
SET_ENTITY_PROPERTY_FROM_PROPERTIES(isSpotlight, setIsSpotlight);
|
||||
SET_ENTITY_PROPERTY_FROM_PROPERTIES(diffuseColor, setDiffuseColor);
|
||||
SET_ENTITY_PROPERTY_FROM_PROPERTIES(ambientColor, setAmbientColor);
|
||||
SET_ENTITY_PROPERTY_FROM_PROPERTIES(specularColor, setSpecularColor);
|
||||
SET_ENTITY_PROPERTY_FROM_PROPERTIES(isSpotlight, setIsSpotlight);
|
||||
SET_ENTITY_PROPERTY_FROM_PROPERTIES(constantAttenuation, setConstantAttenuation);
|
||||
SET_ENTITY_PROPERTY_FROM_PROPERTIES(linearAttenuation, setLinearAttenuation);
|
||||
SET_ENTITY_PROPERTY_FROM_PROPERTIES(quadraticAttenuation, setQuadraticAttenuation);
|
||||
SET_ENTITY_PROPERTY_FROM_PROPERTIES(color, setColor);
|
||||
SET_ENTITY_PROPERTY_FROM_PROPERTIES(intensity, setIntensity);
|
||||
SET_ENTITY_PROPERTY_FROM_PROPERTIES(exponent, setExponent);
|
||||
SET_ENTITY_PROPERTY_FROM_PROPERTIES(cutoff, setCutoff);
|
||||
|
||||
|
||||
if (somethingChanged) {
|
||||
bool wantDebug = false;
|
||||
if (wantDebug) {
|
||||
|
@ -101,15 +88,37 @@ int LightEntityItem::readEntitySubclassDataFromBuffer(const unsigned char* data,
|
|||
int bytesRead = 0;
|
||||
const unsigned char* dataAt = data;
|
||||
|
||||
READ_ENTITY_PROPERTY(PROP_IS_SPOTLIGHT, bool, _isSpotlight);
|
||||
READ_ENTITY_PROPERTY_COLOR(PROP_DIFFUSE_COLOR, _diffuseColor);
|
||||
READ_ENTITY_PROPERTY_COLOR(PROP_AMBIENT_COLOR, _ambientColor);
|
||||
READ_ENTITY_PROPERTY_COLOR(PROP_SPECULAR_COLOR, _specularColor);
|
||||
READ_ENTITY_PROPERTY(PROP_CONSTANT_ATTENUATION, float, _constantAttenuation);
|
||||
READ_ENTITY_PROPERTY(PROP_LINEAR_ATTENUATION, float, _linearAttenuation);
|
||||
READ_ENTITY_PROPERTY(PROP_QUADRATIC_ATTENUATION, float, _quadraticAttenuation);
|
||||
READ_ENTITY_PROPERTY(PROP_EXPONENT, float, _exponent);
|
||||
READ_ENTITY_PROPERTY(PROP_CUTOFF, float, _cutoff);
|
||||
if (args.bitstreamVersion < VERSION_ENTITIES_LIGHT_HAS_INTENSITY_AND_COLOR_PROPERTIES) {
|
||||
rgbColor ignoredColor;
|
||||
float ignoredAttenuation;
|
||||
|
||||
READ_ENTITY_PROPERTY(PROP_IS_SPOTLIGHT, bool, _isSpotlight);
|
||||
|
||||
// _diffuseColor has been renamed to _color
|
||||
READ_ENTITY_PROPERTY_COLOR(PROP_DIFFUSE_COLOR_UNUSED, _color);
|
||||
|
||||
// Ambient and specular color are from an older format and are no longer supported.
|
||||
// Their values will be ignored.
|
||||
READ_ENTITY_PROPERTY_COLOR(PROP_AMBIENT_COLOR_UNUSED, ignoredColor);
|
||||
READ_ENTITY_PROPERTY_COLOR(PROP_SPECULAR_COLOR_UNUSED, ignoredColor);
|
||||
|
||||
// _constantAttenuation has been renamed to _intensity
|
||||
READ_ENTITY_PROPERTY(PROP_INTENSITY, float, _intensity);
|
||||
|
||||
// Linear and quadratic attenuation are from an older format and are no longer supported.
|
||||
// Their values will be ignored.
|
||||
READ_ENTITY_PROPERTY(PROP_LINEAR_ATTENUATION_UNUSED, float, ignoredAttenuation);
|
||||
READ_ENTITY_PROPERTY(PROP_QUADRATIC_ATTENUATION_UNUSED, float, ignoredAttenuation);
|
||||
|
||||
READ_ENTITY_PROPERTY(PROP_EXPONENT, float, _exponent);
|
||||
READ_ENTITY_PROPERTY(PROP_CUTOFF, float, _cutoff);
|
||||
} else {
|
||||
READ_ENTITY_PROPERTY(PROP_IS_SPOTLIGHT, bool, _isSpotlight);
|
||||
READ_ENTITY_PROPERTY_COLOR(PROP_COLOR, _color);
|
||||
READ_ENTITY_PROPERTY(PROP_INTENSITY, float, _intensity);
|
||||
READ_ENTITY_PROPERTY(PROP_EXPONENT, float, _exponent);
|
||||
READ_ENTITY_PROPERTY(PROP_CUTOFF, float, _cutoff);
|
||||
}
|
||||
|
||||
return bytesRead;
|
||||
}
|
||||
|
@ -119,12 +128,8 @@ int LightEntityItem::readEntitySubclassDataFromBuffer(const unsigned char* data,
|
|||
EntityPropertyFlags LightEntityItem::getEntityProperties(EncodeBitstreamParams& params) const {
|
||||
EntityPropertyFlags requestedProperties = EntityItem::getEntityProperties(params);
|
||||
requestedProperties += PROP_IS_SPOTLIGHT;
|
||||
requestedProperties += PROP_DIFFUSE_COLOR;
|
||||
requestedProperties += PROP_AMBIENT_COLOR;
|
||||
requestedProperties += PROP_SPECULAR_COLOR;
|
||||
requestedProperties += PROP_CONSTANT_ATTENUATION;
|
||||
requestedProperties += PROP_LINEAR_ATTENUATION;
|
||||
requestedProperties += PROP_QUADRATIC_ATTENUATION;
|
||||
requestedProperties += PROP_COLOR;
|
||||
requestedProperties += PROP_INTENSITY;
|
||||
requestedProperties += PROP_EXPONENT;
|
||||
requestedProperties += PROP_CUTOFF;
|
||||
return requestedProperties;
|
||||
|
@ -140,12 +145,8 @@ void LightEntityItem::appendSubclassData(OctreePacketData* packetData, EncodeBit
|
|||
|
||||
bool successPropertyFits = true;
|
||||
APPEND_ENTITY_PROPERTY(PROP_IS_SPOTLIGHT, appendValue, getIsSpotlight());
|
||||
APPEND_ENTITY_PROPERTY(PROP_DIFFUSE_COLOR, appendColor, getDiffuseColor());
|
||||
APPEND_ENTITY_PROPERTY(PROP_AMBIENT_COLOR, appendColor, getAmbientColor());
|
||||
APPEND_ENTITY_PROPERTY(PROP_SPECULAR_COLOR, appendColor, getSpecularColor());
|
||||
APPEND_ENTITY_PROPERTY(PROP_CONSTANT_ATTENUATION, appendValue, getConstantAttenuation());
|
||||
APPEND_ENTITY_PROPERTY(PROP_LINEAR_ATTENUATION, appendValue, getLinearAttenuation());
|
||||
APPEND_ENTITY_PROPERTY(PROP_QUADRATIC_ATTENUATION, appendValue, getQuadraticAttenuation());
|
||||
APPEND_ENTITY_PROPERTY(PROP_COLOR, appendColor, getColor());
|
||||
APPEND_ENTITY_PROPERTY(PROP_INTENSITY, appendValue, getIntensity());
|
||||
APPEND_ENTITY_PROPERTY(PROP_EXPONENT, appendValue, getExponent());
|
||||
APPEND_ENTITY_PROPERTY(PROP_CUTOFF, appendValue, getCutoff());
|
||||
}
|
||||
|
|
|
@ -43,53 +43,23 @@ public:
|
|||
ReadBitstreamToTreeParams& args,
|
||||
EntityPropertyFlags& propertyFlags, bool overwriteLocalData);
|
||||
|
||||
const rgbColor& getAmbientColor() const { return _ambientColor; }
|
||||
xColor getAmbientXColor() const {
|
||||
xColor color = { _ambientColor[RED_INDEX], _ambientColor[GREEN_INDEX], _ambientColor[BLUE_INDEX] }; return color;
|
||||
const rgbColor& getColor() const { return _color; }
|
||||
xColor getXColor() const {
|
||||
xColor color = { _color[RED_INDEX], _color[GREEN_INDEX], _color[BLUE_INDEX] }; return color;
|
||||
}
|
||||
|
||||
void setAmbientColor(const rgbColor& value) { memcpy(_ambientColor, value, sizeof(_ambientColor)); }
|
||||
void setAmbientColor(const xColor& value) {
|
||||
_ambientColor[RED_INDEX] = value.red;
|
||||
_ambientColor[GREEN_INDEX] = value.green;
|
||||
_ambientColor[BLUE_INDEX] = value.blue;
|
||||
}
|
||||
|
||||
const rgbColor& getDiffuseColor() const { return _diffuseColor; }
|
||||
xColor getDiffuseXColor() const {
|
||||
xColor color = { _diffuseColor[RED_INDEX], _diffuseColor[GREEN_INDEX], _diffuseColor[BLUE_INDEX] }; return color;
|
||||
}
|
||||
|
||||
void setDiffuseColor(const rgbColor& value) { memcpy(_diffuseColor, value, sizeof(_diffuseColor)); }
|
||||
void setDiffuseColor(const xColor& value) {
|
||||
_diffuseColor[RED_INDEX] = value.red;
|
||||
_diffuseColor[GREEN_INDEX] = value.green;
|
||||
_diffuseColor[BLUE_INDEX] = value.blue;
|
||||
}
|
||||
|
||||
const rgbColor& getSpecularColor() const { return _specularColor; }
|
||||
xColor getSpecularXColor() const {
|
||||
xColor color = { _specularColor[RED_INDEX], _specularColor[GREEN_INDEX], _specularColor[BLUE_INDEX] }; return color;
|
||||
}
|
||||
|
||||
void setSpecularColor(const rgbColor& value) { memcpy(_specularColor, value, sizeof(_specularColor)); }
|
||||
void setSpecularColor(const xColor& value) {
|
||||
_specularColor[RED_INDEX] = value.red;
|
||||
_specularColor[GREEN_INDEX] = value.green;
|
||||
_specularColor[BLUE_INDEX] = value.blue;
|
||||
void setColor(const rgbColor& value) { memcpy(_color, value, sizeof(_color)); }
|
||||
void setColor(const xColor& value) {
|
||||
_color[RED_INDEX] = value.red;
|
||||
_color[GREEN_INDEX] = value.green;
|
||||
_color[BLUE_INDEX] = value.blue;
|
||||
}
|
||||
|
||||
bool getIsSpotlight() const { return _isSpotlight; }
|
||||
void setIsSpotlight(bool value) { _isSpotlight = value; }
|
||||
|
||||
float getConstantAttenuation() const { return _constantAttenuation; }
|
||||
void setConstantAttenuation(float value) { _constantAttenuation = value; }
|
||||
|
||||
float getLinearAttenuation() const { return _linearAttenuation; }
|
||||
void setLinearAttenuation(float value) { _linearAttenuation = value; }
|
||||
|
||||
float getQuadraticAttenuation() const { return _quadraticAttenuation; }
|
||||
void setQuadraticAttenuation(float value) { _quadraticAttenuation = value; }
|
||||
float getIntensity() const { return _intensity; }
|
||||
void setIntensity(float value) { _intensity = value; }
|
||||
|
||||
float getExponent() const { return _exponent; }
|
||||
void setExponent(float value) { _exponent = value; }
|
||||
|
@ -103,13 +73,9 @@ public:
|
|||
protected:
|
||||
|
||||
// properties of a light
|
||||
rgbColor _ambientColor;
|
||||
rgbColor _diffuseColor;
|
||||
rgbColor _specularColor;
|
||||
rgbColor _color;
|
||||
bool _isSpotlight;
|
||||
float _constantAttenuation;
|
||||
float _linearAttenuation;
|
||||
float _quadraticAttenuation;
|
||||
float _intensity;
|
||||
float _exponent;
|
||||
float _cutoff;
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -648,7 +648,7 @@ void HeightfieldHeightEditor::select() {
|
|||
const float CONVERSION_SCALE = 65534.0f / numeric_limits<quint16>::max();
|
||||
for (int i = 0; i < rawSize; i++, dest += size) {
|
||||
for (quint16* lineDest = dest, *end = dest + rawSize; lineDest != end; lineDest++, src++) {
|
||||
*lineDest = (quint16)(*src * CONVERSION_SCALE) + CONVERSION_OFFSET;
|
||||
*lineDest = (*src == 0) ? 0 : (quint16)(*src * CONVERSION_SCALE) + CONVERSION_OFFSET;
|
||||
}
|
||||
}
|
||||
emit heightChanged(_height = new HeightfieldHeight(size, contents));
|
||||
|
|
209
libraries/model/src/model/Stage.cpp
Normal file
209
libraries/model/src/model/Stage.cpp
Normal file
|
@ -0,0 +1,209 @@
|
|||
//
|
||||
// Stage.cpp
|
||||
// libraries/model/src/model
|
||||
//
|
||||
// Created by Sam Gateau on 2/24/2015.
|
||||
// Copyright 2014 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
#include "Stage.h"
|
||||
|
||||
#include <glm/gtx/transform.hpp>
|
||||
#include <math.h>
|
||||
|
||||
using namespace model;
|
||||
|
||||
|
||||
void EarthSunModel::updateAll() const {
|
||||
updateWorldToSurface();
|
||||
updateSurfaceToEye();
|
||||
updateSun();
|
||||
}
|
||||
|
||||
Mat4d EarthSunModel::evalWorldToGeoLocationMat(double longitude, double latitude, double absAltitude, double scale) {
|
||||
// Longitude is along Z axis but - from east to west
|
||||
Mat4d rotLon = glm::rotate(glm::radians(longitude), Vec3d(0.0, 0.0, 1.0));
|
||||
|
||||
// latitude is along X axis + from south to north
|
||||
Mat4d rotLat = glm::rotate(-glm::radians(latitude), Vec3d(1.0, 0.0, 0.0));
|
||||
|
||||
// translation is movin to the earth surface + altiture at the radius along Y axis
|
||||
Mat4d surfaceT = glm::translate(Vec3d(0.0, -absAltitude, 0.0));
|
||||
|
||||
// Mat4d worldScale = glm::scale(Vec3d(scale));
|
||||
|
||||
Mat4d worldToGeoLocMat = surfaceT * rotLat * rotLon;
|
||||
|
||||
return worldToGeoLocMat;
|
||||
}
|
||||
|
||||
void EarthSunModel::updateWorldToSurface() const {
|
||||
// Check if the final position is too close to the earth center ?
|
||||
double absAltitude = _earthRadius + _altitude;
|
||||
if ( absAltitude < 0.01) {
|
||||
absAltitude = 0.01;
|
||||
}
|
||||
|
||||
// Final world to local Frame
|
||||
_worldToSurfaceMat = evalWorldToGeoLocationMat(_longitude, _latitude, absAltitude, _scale);
|
||||
// and the inverse
|
||||
_surfaceToWorldMat = glm::inverse(_worldToSurfaceMat);
|
||||
|
||||
_surfacePos = Vec3d(_surfaceToWorldMat * Vec4d(0.0, 0.0, 0.0, 1.0));
|
||||
}
|
||||
|
||||
void EarthSunModel::updateSurfaceToEye() const {
|
||||
_surfaceToEyeMat = glm::inverse(_eyeToSurfaceMat);
|
||||
_worldToEyeMat = _surfaceToEyeMat * _worldToSurfaceMat;
|
||||
_eyeToWorldMat = _surfaceToWorldMat * _eyeToSurfaceMat;
|
||||
_eyePos = Vec3d(_eyeToWorldMat * Vec4d(0.0, 0.0, 0.0, 1.0) );
|
||||
_eyeDir = Vec3d(_eyeToWorldMat * Vec4d(0.0, 0.0, -1.0, 0.0) );
|
||||
}
|
||||
|
||||
void EarthSunModel::updateSun() const {
|
||||
// Longitude is along Y axis but - from east to west
|
||||
Mat4d rotSunLon;
|
||||
|
||||
Mat4d rotSun = evalWorldToGeoLocationMat(_sunLongitude, _sunLatitude, _earthRadius, _scale);
|
||||
rotSun = glm::inverse(rotSun);
|
||||
|
||||
_sunDir = Vec3d(rotSun * Vec4d(0.0, 1.0, 0.0, 0.0));
|
||||
|
||||
// sun direction is looking up toward Y axis at the specified sun lat, long
|
||||
Vec3d lssd = Vec3d(_worldToSurfaceMat * Vec4d(_sunDir.x, _sunDir.y, _sunDir.z, 0.0));
|
||||
|
||||
// apply surface rotation offset
|
||||
glm::dquat dSurfOrient(_surfaceOrientation);
|
||||
lssd = glm::rotate(dSurfOrient, lssd);
|
||||
|
||||
_surfaceSunDir = glm::normalize(Vec3(lssd.x, lssd.y, lssd.z));
|
||||
}
|
||||
|
||||
void EarthSunModel::setSurfaceOrientation(const Quat& orientation) {
|
||||
_surfaceOrientation = orientation;
|
||||
invalidate();
|
||||
}
|
||||
|
||||
double moduloRange(double val, double minVal, double maxVal) {
|
||||
double range = maxVal - minVal;
|
||||
double rval = (val - minVal) / range;
|
||||
double intval;
|
||||
return modf(rval, &intval) * range + minVal;
|
||||
}
|
||||
|
||||
const float MAX_LONGITUDE = 180.0f;
|
||||
const float MAX_LATITUDE = 90.0f;
|
||||
|
||||
float validateLongitude(float lon) {
|
||||
return moduloRange(lon, -MAX_LONGITUDE, MAX_LONGITUDE);
|
||||
}
|
||||
|
||||
float validateLatitude(float lat) {
|
||||
return moduloRange(lat, -MAX_LATITUDE, MAX_LATITUDE);
|
||||
}
|
||||
|
||||
float validateAltitude(float altitude) {
|
||||
const float MIN_ALTITUDE = -1000.0f;
|
||||
const float MAX_ALTITUDE = 100000.0f;
|
||||
return std::min(std::max(altitude, MIN_ALTITUDE), MAX_ALTITUDE);
|
||||
}
|
||||
|
||||
void EarthSunModel::setLatitude(float lat) {
|
||||
_latitude = validateLatitude(lat);
|
||||
invalidate();
|
||||
}
|
||||
void EarthSunModel::setLongitude(float lon) {
|
||||
_longitude = validateLongitude(lon);
|
||||
invalidate();
|
||||
}
|
||||
void EarthSunModel::setAltitude(float altitude) {
|
||||
_altitude = validateAltitude(altitude);
|
||||
invalidate();
|
||||
}
|
||||
|
||||
void EarthSunModel::setSunLatitude(float lat) {
|
||||
_sunLatitude = validateLatitude(lat);
|
||||
invalidate();
|
||||
}
|
||||
void EarthSunModel::setSunLongitude(float lon) {
|
||||
_sunLongitude = validateLongitude(lon);
|
||||
invalidate();
|
||||
}
|
||||
|
||||
const int NUM_DAYS_PER_YEAR = 365;
|
||||
const float NUM_HOURS_PER_DAY = 24.0f;
|
||||
const float NUM_HOURS_PER_HALF_DAY = NUM_HOURS_PER_DAY * 0.5f;
|
||||
|
||||
SunSkyStage::SunSkyStage() :
|
||||
_sunLight(new Light())
|
||||
{
|
||||
_sunLight->setType(Light::SUN);
|
||||
|
||||
setSunIntensity(1.0f);
|
||||
setSunColor(Vec3(1.0f, 1.0f, 1.0f));
|
||||
|
||||
// Default origin location is a special place in the world...
|
||||
setOriginLocation(122.407f, 37.777f, 0.03f);
|
||||
// Noun
|
||||
setDayTime(12.0f);
|
||||
// Begining of march
|
||||
setYearTime(60.0f);
|
||||
}
|
||||
|
||||
SunSkyStage::~SunSkyStage() {
|
||||
}
|
||||
|
||||
void SunSkyStage::setDayTime(float hour) {
|
||||
_dayTime = moduloRange(hour, 0.f, NUM_HOURS_PER_DAY);
|
||||
invalidate();
|
||||
}
|
||||
|
||||
void SunSkyStage::setYearTime(unsigned int day) {
|
||||
_yearTime = day % NUM_DAYS_PER_YEAR;
|
||||
invalidate();
|
||||
}
|
||||
|
||||
void SunSkyStage::setOriginOrientation(const Quat& orientation) {
|
||||
_earthSunModel.setSurfaceOrientation(orientation);
|
||||
invalidate();
|
||||
}
|
||||
|
||||
void SunSkyStage::setOriginLocation(float longitude, float latitude, float altitude) {
|
||||
_earthSunModel.setLongitude(longitude);
|
||||
_earthSunModel.setLatitude(latitude);
|
||||
_earthSunModel.setAltitude(altitude);
|
||||
invalidate();
|
||||
}
|
||||
|
||||
void SunSkyStage::setSunColor(const Vec3& color) {
|
||||
_sunLight->setColor(color);
|
||||
}
|
||||
void SunSkyStage::setSunIntensity(float intensity) {
|
||||
_sunLight->setIntensity(intensity);
|
||||
}
|
||||
|
||||
// THe sun declinaison calculus is taken from https://en.wikipedia.org/wiki/Position_of_the_Sun
|
||||
double evalSunDeclinaison(double dayNumber) {
|
||||
return -(23.0 + 44.0/60.0)*cos(glm::radians((360.0/365.0)*(dayNumber + 10.0)));
|
||||
}
|
||||
|
||||
void SunSkyStage::updateGraphicsObject() const {
|
||||
// Always update the sunLongitude based on the current dayTime and the current origin
|
||||
// The day time is supposed to be local at the origin
|
||||
double signedNormalizedDayTime = (_dayTime - NUM_HOURS_PER_HALF_DAY) / NUM_HOURS_PER_HALF_DAY;
|
||||
double sunLongitude = _earthSunModel.getLongitude() + (MAX_LONGITUDE * signedNormalizedDayTime);
|
||||
_earthSunModel.setSunLongitude(sunLongitude);
|
||||
|
||||
// And update the sunLAtitude as the declinaison depending of the time of the year
|
||||
_earthSunModel.setSunLatitude(evalSunDeclinaison(_yearTime));
|
||||
|
||||
Vec3d sunLightDir = -_earthSunModel.getSurfaceSunDir();
|
||||
_sunLight->setDirection(Vec3(sunLightDir.x, sunLightDir.y, sunLightDir.z));
|
||||
|
||||
double originAlt = _earthSunModel.getAltitude();
|
||||
_sunLight->setPosition(Vec3(0.0f, originAlt, 0.0f));
|
||||
|
||||
}
|
||||
|
161
libraries/model/src/model/Stage.h
Normal file
161
libraries/model/src/model/Stage.h
Normal file
|
@ -0,0 +1,161 @@
|
|||
//
|
||||
// Stage.h
|
||||
// libraries/model/src/model
|
||||
//
|
||||
// Created by Sam Gateau on 2/24/2015.
|
||||
// Copyright 2014 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
#ifndef hifi_model_Stage_h
|
||||
#define hifi_model_Stage_h
|
||||
|
||||
#include "Light.h"
|
||||
|
||||
namespace model {
|
||||
|
||||
typedef glm::dvec3 Vec3d;
|
||||
typedef glm::dvec4 Vec4d;
|
||||
typedef glm::dmat4 Mat4d;
|
||||
typedef glm::mat4 Mat4;
|
||||
|
||||
class EarthSunModel {
|
||||
public:
|
||||
|
||||
void setScale(float scale);
|
||||
float getScale() const { return _scale; }
|
||||
|
||||
void setLatitude(float lat);
|
||||
float getLatitude() const { return _latitude; }
|
||||
void setLongitude(float lon);
|
||||
float getLongitude() const { return _longitude; }
|
||||
void setAltitude(float altitude);
|
||||
float getAltitude() const { return _altitude; }
|
||||
|
||||
|
||||
void setSurfaceOrientation(const Quat& orientation);
|
||||
const Quat& getSurfaceOrientation() const { valid(); return _surfaceOrientation; }
|
||||
|
||||
const Vec3d& getSurfacePos() const { valid(); return _surfacePos; }
|
||||
|
||||
const Mat4d& getSurfaceToWorldMat() const { valid(); return _surfaceToWorldMat; }
|
||||
const Mat4d& getWoldToSurfaceMat() const { valid(); return _worldToSurfaceMat; }
|
||||
|
||||
const Mat4d& getEyeToSurfaceMat() const { valid(); return _eyeToSurfaceMat; }
|
||||
const Mat4d& getSurfaceToEyeMat() const { valid(); return _surfaceToEyeMat; }
|
||||
|
||||
const Mat4d& getEyeToWorldMat() const { valid(); return _eyeToWorldMat; }
|
||||
const Mat4d& getWorldToEyeMat() const { valid(); return _worldToEyeMat; }
|
||||
|
||||
|
||||
//or set the surfaceToEye mat directly
|
||||
void setEyeToSurfaceMat( const Mat4d& e2s);
|
||||
|
||||
const Vec3d& getEyePos() const { valid(); return _eyePos; }
|
||||
const Vec3d& getEyeDir() const { valid(); return _eyeDir; }
|
||||
|
||||
void setSunLongitude(float lon);
|
||||
float getSunLongitude() const { return _sunLongitude; }
|
||||
|
||||
void setSunLatitude(float lat);
|
||||
float getSunLatitude() const { return _sunLatitude; }
|
||||
|
||||
const Vec3d& getWorldSunDir() const { valid(); return _sunDir; }
|
||||
const Vec3d& getSurfaceSunDir() const { valid(); return _surfaceSunDir; }
|
||||
|
||||
|
||||
EarthSunModel() { valid(); }
|
||||
|
||||
protected:
|
||||
double _scale = 1000.0; //Km
|
||||
double _earthRadius = 6360.0;
|
||||
|
||||
Quat _surfaceOrientation;
|
||||
|
||||
double _longitude = 0.0;
|
||||
double _latitude = 0.0;
|
||||
double _altitude = 0.01;
|
||||
mutable Vec3d _surfacePos;
|
||||
mutable Mat4d _worldToSurfaceMat;
|
||||
mutable Mat4d _surfaceToWorldMat;
|
||||
void updateWorldToSurface() const;
|
||||
|
||||
mutable Mat4d _surfaceToEyeMat;
|
||||
mutable Mat4d _eyeToSurfaceMat;
|
||||
mutable Vec3d _eyeDir;
|
||||
mutable Vec3d _eyePos;
|
||||
void updateSurfaceToEye() const;
|
||||
|
||||
mutable Mat4d _worldToEyeMat;
|
||||
mutable Mat4d _eyeToWorldMat;
|
||||
|
||||
double _sunLongitude = 0.0;
|
||||
double _sunLatitude = 0.0;
|
||||
mutable Vec3d _sunDir;
|
||||
mutable Vec3d _surfaceSunDir;
|
||||
void updateSun() const;
|
||||
|
||||
mutable bool _invalid = true;
|
||||
void invalidate() const { _invalid = true; }
|
||||
void valid() const { if (_invalid) { updateAll(); _invalid = false; } }
|
||||
void updateAll() const;
|
||||
|
||||
static Mat4d evalWorldToGeoLocationMat(double longitude, double latitude, double altitude, double scale);
|
||||
};
|
||||
|
||||
// Sun sky stage generates the rendering primitives to display a scene realistically
|
||||
// at the specified location and time around earth
|
||||
class SunSkyStage {
|
||||
public:
|
||||
|
||||
SunSkyStage();
|
||||
~SunSkyStage();
|
||||
|
||||
// time of the day (local to the position) expressed in decimal hour in the range [0.0, 24.0]
|
||||
void setDayTime(float hour);
|
||||
float getDayTime() const { return _dayTime; }
|
||||
|
||||
// time of the year expressed in day in the range [0, 365]
|
||||
void setYearTime(unsigned int day);
|
||||
unsigned int getYearTime() const { return _yearTime; }
|
||||
|
||||
// Origin orientation used to modify the cardinal axis alignement used.
|
||||
// THe default is north along +Z axis and west along +X axis. this orientation gets added
|
||||
// to the transform stack producing the sun light direction.
|
||||
void setOriginOrientation(const Quat& orientation);
|
||||
const Quat& getOriginOrientation() const { return _earthSunModel.getSurfaceOrientation(); }
|
||||
|
||||
// Location used to define the sun & sky is a longitude and latitude [rad] and a earth surface altitude [km]
|
||||
void setOriginLocation(float longitude, float latitude, float surfaceAltitude);
|
||||
float getOriginLatitude() const { return _earthSunModel.getLatitude(); }
|
||||
float getOriginLongitude() const { return _earthSunModel.getLongitude(); }
|
||||
float getOriginSurfaceAltitude() const { return _earthSunModel.getAltitude(); }
|
||||
|
||||
// Sun properties
|
||||
void setSunColor(const Vec3& color);
|
||||
const Vec3& getSunColor() const { return getSunLight()->getColor(); }
|
||||
void setSunIntensity(float intensity);
|
||||
float getSunIntensity() const { return getSunLight()->getIntensity(); }
|
||||
|
||||
LightPointer getSunLight() const { valid(); return _sunLight; }
|
||||
|
||||
protected:
|
||||
LightPointer _sunLight;
|
||||
|
||||
float _dayTime;
|
||||
int _yearTime;
|
||||
|
||||
mutable EarthSunModel _earthSunModel;
|
||||
|
||||
mutable bool _invalid = true;
|
||||
void invalidate() const { _invalid = true; }
|
||||
void valid() const { if (_invalid) { updateGraphicsObject(); _invalid = false; } }
|
||||
void updateGraphicsObject() const;
|
||||
};
|
||||
|
||||
typedef QSharedPointer< SunSkyStage > SunSkyStagePointer;
|
||||
|
||||
};
|
||||
|
||||
#endif
|
|
@ -76,7 +76,7 @@ const QString AddressManager::currentPath(bool withOrientation) const {
|
|||
pathString += "/" + orientationString;
|
||||
} 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();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
#include <qsharedpointer.h>
|
||||
#include <QtNetwork/qudpsocket.h>
|
||||
#include <QtNetwork/qhostaddress.h>
|
||||
#include <QSharedMemory>
|
||||
|
||||
#include <tbb/concurrent_unordered_map.h>
|
||||
|
||||
|
@ -49,6 +50,10 @@ const char STUN_SERVER_HOSTNAME[] = "stun.highfidelity.io";
|
|||
const unsigned short STUN_SERVER_PORT = 3478;
|
||||
|
||||
const QString DOMAIN_SERVER_LOCAL_PORT_SMEM_KEY = "domain-server.local-port";
|
||||
const QString ASSIGNMENT_CLIENT_MONITOR_LOCAL_PORT_SMEM_KEY = "assignment-client-monitor.local-port";
|
||||
|
||||
const char DEFAULT_ASSIGNMENT_CLIENT_MONITOR_HOSTNAME[] = "localhost";
|
||||
const unsigned short DEFAULT_ASSIGNMENT_CLIENT_MONITOR_PORT = 40104;
|
||||
|
||||
class HifiSockAddr;
|
||||
|
||||
|
@ -168,6 +173,9 @@ public:
|
|||
|
||||
return SharedNodePointer();
|
||||
}
|
||||
|
||||
void putLocalPortIntoSharedMemory(const QString key, QObject* parent);
|
||||
bool getLocalServerPortFromSharedMemory(const QString key, QSharedMemory*& sharedMem, quint16& localPort);
|
||||
|
||||
public slots:
|
||||
void reset();
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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; }
|
||||
|
|
|
@ -70,9 +70,11 @@ 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;
|
||||
return VERSION_ENTITIES_LIGHT_HAS_INTENSITY_AND_COLOR_PROPERTIES;
|
||||
case PacketTypeEntityErase:
|
||||
return 2;
|
||||
case PacketTypeAudioStreamStats:
|
||||
|
@ -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);
|
||||
|
|
|
@ -67,7 +67,7 @@ enum PacketType {
|
|||
PacketTypeEntityErase,
|
||||
PacketTypeEntityAddResponse,
|
||||
PacketTypeOctreeDataNack, // 45
|
||||
UNUSED_10,
|
||||
PacketTypeStopNode,
|
||||
PacketTypeAudioEnvironment,
|
||||
PacketTypeEntityEditNack,
|
||||
PacketTypeSignedTransactionPayment,
|
||||
|
@ -86,7 +86,7 @@ const QSet<PacketType> NON_VERIFIED_PACKETS = QSet<PacketType>()
|
|||
<< 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;
|
||||
|
@ -128,6 +128,7 @@ const PacketVersion VERSION_ENTITIES_MODELS_HAVE_ANIMATION_SETTINGS = 5;
|
|||
const PacketVersion VERSION_ENTITIES_HAVE_USER_DATA = 6;
|
||||
const PacketVersion VERSION_ENTITIES_HAS_LAST_SIMULATED_TIME = 7;
|
||||
const PacketVersion VERSION_MODEL_ENTITIES_SUPPORT_SHAPE_TYPE = 8;
|
||||
const PacketVersion VERSION_ENTITIES_LIGHT_HAS_INTENSITY_AND_COLOR_PROPERTIES = 9;
|
||||
const PacketVersion VERSION_OCTREE_HAS_FILE_BREAKS = 1;
|
||||
|
||||
#endif // hifi_PacketHeaders_h
|
||||
|
|
|
@ -63,6 +63,10 @@ void EntityMotionState::stepKinematicSimulation(quint64 now) {
|
|||
_entity->simulate(now);
|
||||
}
|
||||
|
||||
bool EntityMotionState::isMoving() const {
|
||||
return _entity->isMoving();
|
||||
}
|
||||
|
||||
// This callback is invoked by the physics simulation in two cases:
|
||||
// (1) when the RigidBody is first added to the world
|
||||
// (irregardless of MotionType: STATIC, DYNAMIC, or KINEMATIC)
|
||||
|
|
|
@ -36,28 +36,30 @@ public:
|
|||
virtual ~EntityMotionState();
|
||||
|
||||
/// \return MOTION_TYPE_DYNAMIC or MOTION_TYPE_STATIC based on params set in EntityItem
|
||||
MotionType computeMotionType() const;
|
||||
virtual MotionType computeMotionType() const;
|
||||
|
||||
void updateKinematicState(uint32_t substep);
|
||||
void stepKinematicSimulation(quint64 now);
|
||||
virtual void updateKinematicState(uint32_t substep);
|
||||
virtual void stepKinematicSimulation(quint64 now);
|
||||
|
||||
virtual bool isMoving() const;
|
||||
|
||||
// this relays incoming position/rotation to the RigidBody
|
||||
void getWorldTransform(btTransform& worldTrans) const;
|
||||
virtual void getWorldTransform(btTransform& worldTrans) const;
|
||||
|
||||
// this relays outgoing position/rotation to the EntityItem
|
||||
void setWorldTransform(const btTransform& worldTrans);
|
||||
virtual void setWorldTransform(const btTransform& worldTrans);
|
||||
|
||||
// these relay incoming values to the RigidBody
|
||||
void updateObjectEasy(uint32_t flags, uint32_t frame);
|
||||
void updateObjectVelocities();
|
||||
virtual void updateObjectEasy(uint32_t flags, uint32_t frame);
|
||||
virtual void updateObjectVelocities();
|
||||
|
||||
void computeShapeInfo(ShapeInfo& shapeInfo);
|
||||
float computeMass(const ShapeInfo& shapeInfo) const;
|
||||
virtual void computeShapeInfo(ShapeInfo& shapeInfo);
|
||||
virtual float computeMass(const ShapeInfo& shapeInfo) const;
|
||||
|
||||
void sendUpdate(OctreeEditPacketSender* packetSender, uint32_t frame);
|
||||
virtual void sendUpdate(OctreeEditPacketSender* packetSender, uint32_t frame);
|
||||
|
||||
uint32_t getIncomingDirtyFlags() const;
|
||||
void clearIncomingDirtyFlags(uint32_t flags) { _entity->clearDirtyFlags(flags); }
|
||||
virtual uint32_t getIncomingDirtyFlags() const;
|
||||
virtual void clearIncomingDirtyFlags(uint32_t flags) { _entity->clearDirtyFlags(flags); }
|
||||
|
||||
EntityItem* getEntity() const { return _entity; }
|
||||
|
||||
|
|
|
@ -101,6 +101,8 @@ public:
|
|||
void setKinematic(bool kinematic, uint32_t substep);
|
||||
virtual void stepKinematicSimulation(quint64 now) = 0;
|
||||
|
||||
virtual bool isMoving() const = 0;
|
||||
|
||||
friend class PhysicsEngine;
|
||||
protected:
|
||||
void setRigidBody(btRigidBody* body);
|
||||
|
|
|
@ -439,6 +439,10 @@ void PhysicsEngine::addObject(const ShapeInfo& shapeInfo, btCollisionShape* shap
|
|||
const float DYNAMIC_LINEAR_VELOCITY_THRESHOLD = 0.05f; // 5 cm/sec
|
||||
const float DYNAMIC_ANGULAR_VELOCITY_THRESHOLD = 0.087266f; // ~5 deg/sec
|
||||
body->setSleepingThresholds(DYNAMIC_LINEAR_VELOCITY_THRESHOLD, DYNAMIC_ANGULAR_VELOCITY_THRESHOLD);
|
||||
if (!motionState->isMoving()) {
|
||||
// try to initialize this object as inactive
|
||||
body->forceActivationState(ISLAND_SLEEPING);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case MOTION_TYPE_STATIC:
|
||||
|
|
|
@ -1,15 +1,15 @@
|
|||
set(TARGET_NAME render-utils)
|
||||
|
||||
AUTOSCRIBE_SHADER_LIB()
|
||||
|
||||
# pull in the resources.qrc file
|
||||
qt5_add_resources(QT_RESOURCES_FILE "${CMAKE_CURRENT_SOURCE_DIR}/res/fonts/fonts.qrc")
|
||||
|
||||
# use setup_hifi_library macro to setup our project and link appropriate Qt modules
|
||||
setup_hifi_library(Widgets OpenGL Network Script)
|
||||
|
||||
add_dependency_external_projects(glm)
|
||||
find_package(GLM REQUIRED)
|
||||
target_include_directories(${TARGET_NAME} PUBLIC ${GLM_INCLUDE_DIRS})
|
||||
|
||||
set(TARGET_NAME render-utils)
|
||||
|
||||
AUTOSCRIBE_SHADER_LIB()
|
||||
|
||||
# pull in the resources.qrc file
|
||||
qt5_add_resources(QT_RESOURCES_FILE "${CMAKE_CURRENT_SOURCE_DIR}/res/fonts/fonts.qrc")
|
||||
|
||||
# use setup_hifi_library macro to setup our project and link appropriate Qt modules
|
||||
setup_hifi_library(Widgets OpenGL Network Script)
|
||||
|
||||
add_dependency_external_projects(glm)
|
||||
find_package(GLM REQUIRED)
|
||||
target_include_directories(${TARGET_NAME} PUBLIC ${GLM_INCLUDE_DIRS})
|
||||
|
||||
link_hifi_libraries(animation fbx shared gpu)
|
|
@ -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
|
||||
|
|
|
@ -126,15 +126,13 @@ 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) {
|
||||
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 +142,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 +151,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);
|
||||
|
|
|
@ -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); }
|
||||
|
|
40
libraries/script-engine/src/SceneScriptingInterface.cpp
Normal file
40
libraries/script-engine/src/SceneScriptingInterface.cpp
Normal file
|
@ -0,0 +1,40 @@
|
|||
//
|
||||
// SceneScriptingInterface.cpp
|
||||
// interface/src/scripting
|
||||
//
|
||||
// Created by Sam Gateau on 2/24/15.
|
||||
// Copyright 2014 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#include <AddressManager.h>
|
||||
|
||||
#include "SceneScriptingInterface.h"
|
||||
|
||||
void SceneScriptingInterface::setStageOrientation(const glm::quat& orientation) {
|
||||
_skyStage->setOriginOrientation(orientation);
|
||||
}
|
||||
void SceneScriptingInterface::setStageLocation(float longitude, float latitude, float altitude) {
|
||||
_skyStage->setOriginLocation(longitude, latitude, altitude);
|
||||
}
|
||||
|
||||
void SceneScriptingInterface::setStageDayTime(float hour) {
|
||||
_skyStage->setDayTime(hour);
|
||||
}
|
||||
void SceneScriptingInterface::setStageYearTime(int day) {
|
||||
_skyStage->setYearTime(day);
|
||||
}
|
||||
|
||||
void SceneScriptingInterface::setSunColor(const glm::vec3& color) {
|
||||
_skyStage->setSunColor(color);
|
||||
}
|
||||
void SceneScriptingInterface::setSunIntensity(float intensity) {
|
||||
_skyStage->setSunIntensity(intensity);
|
||||
}
|
||||
|
||||
|
||||
model::SunSkyStagePointer SceneScriptingInterface::getSkyStage() const {
|
||||
return _skyStage;
|
||||
}
|
43
libraries/script-engine/src/SceneScriptingInterface.h
Normal file
43
libraries/script-engine/src/SceneScriptingInterface.h
Normal file
|
@ -0,0 +1,43 @@
|
|||
//
|
||||
// SceneScriptingInterface.h
|
||||
// interface/src/scripting
|
||||
//
|
||||
// Created by Sam Gateau on 2/24/15.
|
||||
// Copyright 2014 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#ifndef hifi_SceneScriptingInterface_h
|
||||
#define hifi_SceneScriptingInterface_h
|
||||
|
||||
#include <qscriptengine.h>
|
||||
|
||||
#include <DependencyManager.h>
|
||||
|
||||
#include "model/Stage.h"
|
||||
|
||||
class SceneScriptingInterface : public QObject, public Dependency {
|
||||
Q_OBJECT
|
||||
SINGLETON_DEPENDENCY
|
||||
|
||||
public:
|
||||
Q_INVOKABLE void setStageOrientation(const glm::quat& orientation);
|
||||
Q_INVOKABLE void setStageLocation(float longitude, float latitude, float altitude);
|
||||
Q_INVOKABLE void setStageDayTime(float hour);
|
||||
Q_INVOKABLE void setStageYearTime(int day);
|
||||
|
||||
Q_INVOKABLE void setSunColor(const glm::vec3& color);
|
||||
Q_INVOKABLE void setSunIntensity(float intensity);
|
||||
|
||||
model::SunSkyStagePointer getSkyStage() const;
|
||||
|
||||
protected:
|
||||
SceneScriptingInterface() {};
|
||||
~SceneScriptingInterface() {};
|
||||
|
||||
model::SunSkyStagePointer _skyStage = model::SunSkyStagePointer(new model::SunSkyStage());
|
||||
};
|
||||
|
||||
#endif // hifi_SceneScriptingInterface_h
|
|
@ -39,6 +39,8 @@
|
|||
#include "TypedArrays.h"
|
||||
#include "XMLHttpRequestClass.h"
|
||||
|
||||
#include "SceneScriptingInterface.h"
|
||||
|
||||
#include "MIDIEvent.h"
|
||||
|
||||
|
||||
|
@ -310,6 +312,8 @@ void ScriptEngine::init() {
|
|||
|
||||
_isInitialized = true;
|
||||
|
||||
auto sceneScriptingInterface = DependencyManager::set<SceneScriptingInterface>();
|
||||
|
||||
_entityScriptingInterface.init();
|
||||
|
||||
// register various meta-types
|
||||
|
@ -353,6 +357,7 @@ void ScriptEngine::init() {
|
|||
registerGlobalObject("Vec3", &_vec3Library);
|
||||
registerGlobalObject("Uuid", &_uuidLibrary);
|
||||
registerGlobalObject("AnimationCache", DependencyManager::get<AnimationCache>().data());
|
||||
registerGlobalObject("Scene", DependencyManager::get<SceneScriptingInterface>().data());
|
||||
|
||||
// constants
|
||||
globalObject().setProperty("TREE_SCALE", newVariant(QVariant(TREE_SCALE)));
|
||||
|
|
|
@ -101,6 +101,22 @@ QString LogHandler::printMessage(LogMsgType type, const QMessageLogContext& cont
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
// see if this message is one we should only print once
|
||||
foreach(const QString& regexString, getInstance()._onlyOnceMessageRegexes) {
|
||||
QRegExp onlyOnceRegex(regexString);
|
||||
if (onlyOnceRegex.indexIn(message) != -1) {
|
||||
if (!_onlyOnceMessageCountHash.contains(message)) {
|
||||
// we have a match and haven't yet printed this message.
|
||||
_onlyOnceMessageCountHash[message] = 1;
|
||||
// break the foreach so we output the first match
|
||||
break;
|
||||
} else {
|
||||
// We've already printed this message, don't print it again.
|
||||
return QString();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// log prefix is in the following format
|
||||
|
|
|
@ -48,6 +48,7 @@ public:
|
|||
static void verboseMessageHandler(QtMsgType type, const QMessageLogContext& context, const QString &message);
|
||||
|
||||
const QString& addRepeatedMessageRegex(const QString& regexString) { return *_repeatedMessageRegexes.insert(regexString); }
|
||||
const QString& addOnlyOnceMessageRegex(const QString& regexString) { return *_onlyOnceMessageRegexes.insert(regexString); }
|
||||
private:
|
||||
LogHandler();
|
||||
|
||||
|
@ -58,6 +59,9 @@ private:
|
|||
QSet<QString> _repeatedMessageRegexes;
|
||||
QHash<QString, int> _repeatMessageCountHash;
|
||||
QHash<QString, QString> _lastRepeatedMessage;
|
||||
|
||||
QSet<QString> _onlyOnceMessageRegexes;
|
||||
QHash<QString, int> _onlyOnceMessageCountHash;
|
||||
};
|
||||
|
||||
#endif // hifi_LogHandler_h
|
||||
#endif // hifi_LogHandler_h
|
||||
|
|
|
@ -35,6 +35,7 @@ ShutdownEventListener::ShutdownEventListener(QObject* parent) :
|
|||
#ifndef Q_OS_WIN
|
||||
// be a signal handler for SIGTERM so we can stop our children when we get it
|
||||
signal(SIGTERM, signalHandler);
|
||||
signal(SIGINT, signalHandler);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
|
|
@ -3,3 +3,8 @@ add_subdirectory(bitstream2json)
|
|||
add_subdirectory(json2bitstream)
|
||||
add_subdirectory(mtc)
|
||||
add_subdirectory(scribe)
|
||||
|
||||
find_package(VHACD)
|
||||
if(VHACD_FOUND)
|
||||
add_subdirectory(vhacd)
|
||||
endif()
|
||||
|
|
23
tools/vhacd/CMakeLists.txt
Normal file
23
tools/vhacd/CMakeLists.txt
Normal file
|
@ -0,0 +1,23 @@
|
|||
set(TARGET_NAME vhacd)
|
||||
setup_hifi_project()
|
||||
link_hifi_libraries(shared model fbx gpu networking octree)
|
||||
|
||||
#find_package(VHACD REQUIRED) done in CMakeList.txt in parent directory
|
||||
target_include_directories(${TARGET_NAME} PUBLIC ${VHACD_INCLUDE_DIRS})
|
||||
target_link_libraries(${TARGET_NAME} ${VHACD_LIBRARIES})
|
||||
|
||||
if(NOT WIN32)
|
||||
find_package( Threads)
|
||||
target_link_libraries(${TARGET_NAME} ${CMAKE_THREAD_LIBS_INIT})
|
||||
|
||||
include(FindOpenMP)
|
||||
if(OPENMP_FOUND)
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${OpenMP_C_FLAGS}")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${OpenMP_CXX_FLAGS}")
|
||||
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${OpenMP_EXE_LINKER_FLAGS}")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
add_dependency_external_projects(glm)
|
||||
find_package(GLM REQUIRED)
|
||||
target_include_directories(${TARGET_NAME} PUBLIC ${GLM_INCLUDE_DIRS})
|
129
tools/vhacd/src/VHACDUtil.cpp
Normal file
129
tools/vhacd/src/VHACDUtil.cpp
Normal file
|
@ -0,0 +1,129 @@
|
|||
//
|
||||
// VHACDUtil.cpp
|
||||
// tools/vhacd/src
|
||||
//
|
||||
// Created by Virendra Singh on 2/20/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 <QVector>
|
||||
#include "VHACDUtil.h"
|
||||
|
||||
|
||||
//Read all the meshes from provided FBX file
|
||||
bool vhacd::VHACDUtil::loadFBX(const QString filename, vhacd::LoadFBXResults *results){
|
||||
|
||||
// open the fbx file
|
||||
QFile fbx(filename);
|
||||
if (!fbx.open(QIODevice::ReadOnly)) {
|
||||
return false;
|
||||
}
|
||||
std::cout << "Reading FBX.....\n";
|
||||
|
||||
QByteArray fbxContents = fbx.readAll();
|
||||
FBXGeometry geometry = readFBX(fbxContents, QVariantHash());
|
||||
//results->meshCount = geometry.meshes.count();
|
||||
|
||||
int count = 0;
|
||||
foreach(FBXMesh mesh, geometry.meshes){
|
||||
//get vertices for each mesh
|
||||
QVector<glm::vec3> vertices = mesh.vertices;
|
||||
|
||||
//get the triangle indices for each mesh
|
||||
QVector<int> triangles;
|
||||
foreach(FBXMeshPart part, mesh.parts){
|
||||
QVector<int> indices = part.triangleIndices;
|
||||
triangles += indices;
|
||||
}
|
||||
|
||||
//only read meshes with triangles
|
||||
if (triangles.count() <= 0){
|
||||
continue;
|
||||
}
|
||||
results->perMeshVertices.append(vertices);
|
||||
results->perMeshTriangleIndices.append(triangles);
|
||||
count++;
|
||||
}
|
||||
|
||||
results->meshCount = count;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool vhacd::VHACDUtil::computeVHACD(vhacd::LoadFBXResults *meshes, VHACD::IVHACD::Parameters params, vhacd::ComputeResults *results)const{
|
||||
VHACD::IVHACD * interfaceVHACD = VHACD::CreateVHACD();
|
||||
int meshCount = meshes->meshCount;
|
||||
int count = 0;
|
||||
std::cout << "Performing V-HACD computation on " << meshCount << " meshes ..... " << std::endl;
|
||||
|
||||
for (int i = 0; i < meshCount; i++){
|
||||
|
||||
std::vector<glm::vec3> vertices = meshes->perMeshVertices.at(i).toStdVector();
|
||||
std::vector<int> triangles = meshes->perMeshTriangleIndices.at(i).toStdVector();
|
||||
int nPoints = (unsigned int)vertices.size();
|
||||
int nTriangles = (unsigned int)triangles.size() / 3;
|
||||
std::cout << "Mesh " << i + 1 << " : ";
|
||||
// compute approximate convex decomposition
|
||||
bool res = interfaceVHACD->Compute(&vertices[0].x, 3, nPoints, &triangles[0], 3, nTriangles, params);
|
||||
if (!res){
|
||||
std::cout << "V-HACD computation failed for Mesh : " << i + 1 << std::endl;
|
||||
continue;
|
||||
}
|
||||
count++; //For counting number of successfull computations
|
||||
|
||||
//Number of hulls for the mesh
|
||||
unsigned int nConvexHulls = interfaceVHACD->GetNConvexHulls();
|
||||
results->convexHullsCountList.append(nConvexHulls);
|
||||
|
||||
//get all the convex hulls for this mesh
|
||||
QVector<VHACD::IVHACD::ConvexHull> convexHulls;
|
||||
for (unsigned int j = 0; j < nConvexHulls; j++){
|
||||
VHACD::IVHACD::ConvexHull hull;
|
||||
interfaceVHACD->GetConvexHull(j, hull);
|
||||
convexHulls.append(hull);
|
||||
}
|
||||
results->convexHullList.append(convexHulls);
|
||||
} //end of for loop
|
||||
|
||||
results->meshCount = count;
|
||||
|
||||
//release memory
|
||||
interfaceVHACD->Clean();
|
||||
interfaceVHACD->Release();
|
||||
|
||||
if (count > 0){
|
||||
return true;
|
||||
}
|
||||
else{
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
vhacd::VHACDUtil:: ~VHACDUtil(){
|
||||
//nothing to be cleaned
|
||||
}
|
||||
|
||||
//ProgressClaback implementation
|
||||
void vhacd::ProgressCallback::Update(const double overallProgress, const double stageProgress, const double operationProgress,
|
||||
const char * const stage, const char * const operation){
|
||||
int progress = (int)(overallProgress + 0.5);
|
||||
|
||||
if (progress < 10){
|
||||
std::cout << "\b\b";
|
||||
}
|
||||
else{
|
||||
std::cout << "\b\b\b";
|
||||
}
|
||||
|
||||
std::cout << progress << "%";
|
||||
|
||||
if (progress >= 100){
|
||||
std::cout << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
vhacd::ProgressCallback::ProgressCallback(void){}
|
||||
vhacd::ProgressCallback::~ProgressCallback(){}
|
55
tools/vhacd/src/VHACDUtil.h
Normal file
55
tools/vhacd/src/VHACDUtil.h
Normal file
|
@ -0,0 +1,55 @@
|
|||
//
|
||||
// VHACDUtil.h
|
||||
// tools/vhacd/src
|
||||
//
|
||||
// Created by Virendra Singh on 2/20/15.
|
||||
// Copyright 2015 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#ifndef hifi_VHACDUtil_h
|
||||
#define hifi_VHACDUtil_h
|
||||
|
||||
#include <iostream>
|
||||
#include <iomanip>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <chrono> //c++11 feature
|
||||
#include <QFile>
|
||||
#include <FBXReader.h>
|
||||
#include <VHACD.h>
|
||||
|
||||
namespace vhacd{
|
||||
|
||||
typedef struct{
|
||||
int meshCount;
|
||||
QVector<int> convexHullsCountList;
|
||||
QVector<QVector<VHACD::IVHACD::ConvexHull>> convexHullList;
|
||||
}ComputeResults;
|
||||
|
||||
typedef struct{
|
||||
int meshCount;
|
||||
QVector<QVector<glm::vec3>> perMeshVertices;
|
||||
QVector<QVector<int>> perMeshTriangleIndices;
|
||||
}LoadFBXResults;
|
||||
|
||||
class VHACDUtil{
|
||||
public:
|
||||
bool loadFBX(const QString filename, vhacd::LoadFBXResults *results);
|
||||
bool computeVHACD(vhacd::LoadFBXResults *meshes, VHACD::IVHACD::Parameters params, vhacd::ComputeResults *results)const;
|
||||
~VHACDUtil();
|
||||
};
|
||||
|
||||
class ProgressCallback : public VHACD::IVHACD::IUserCallback{
|
||||
public:
|
||||
ProgressCallback(void);
|
||||
~ProgressCallback();
|
||||
|
||||
//Couldn't follow coding guideline here due to virtual function declared in IUserCallback
|
||||
void Update(const double overallProgress, const double stageProgress, const double operationProgress,
|
||||
const char * const stage, const char * const operation);
|
||||
};
|
||||
}
|
||||
#endif //hifi_VHACDUtil_h
|
111
tools/vhacd/src/main.cpp
Normal file
111
tools/vhacd/src/main.cpp
Normal file
|
@ -0,0 +1,111 @@
|
|||
//
|
||||
// main.cpp
|
||||
// tools/vhacd/src
|
||||
//
|
||||
// Created by Virendra Singh on 2/20/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 <stdio.h>
|
||||
#include <iostream>
|
||||
#include <iomanip>
|
||||
#include <VHACD.h>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include "VHACDUtil.h"
|
||||
|
||||
using namespace std;
|
||||
using namespace VHACD;
|
||||
|
||||
int main(int argc, char * argv[]){
|
||||
vector<int> triangles; // array of indexes
|
||||
vector<float> points; // array of coordinates
|
||||
vhacd::VHACDUtil vUtil;
|
||||
vhacd::LoadFBXResults fbx; //mesh data from loaded fbx file
|
||||
vhacd::ComputeResults results; // results after computing vhacd
|
||||
VHACD::IVHACD::Parameters params;
|
||||
vhacd::ProgressCallback pCallBack;
|
||||
if (argc < 2){
|
||||
cout << "please provide a FBX file as argument\n ";
|
||||
return 1;
|
||||
}
|
||||
string filename(argv[1]);
|
||||
if (filename.empty()){
|
||||
cout << "please provide a FBX file as argument\n ";
|
||||
return 1;
|
||||
}
|
||||
|
||||
QString fname = QString::fromStdString(filename);
|
||||
|
||||
//set parameters for V-HACD
|
||||
params.m_callback = &pCallBack; //progress callback
|
||||
params.m_resolution = 50000;
|
||||
params.m_depth = 10;
|
||||
params.m_concavity = 0.003;
|
||||
params.m_alpha = 0.05; // controls the bias toward clipping along symmetry planes
|
||||
params.m_pca = 1; // enable/disable normalizing the mesh before applying the convex decomposition
|
||||
params.m_mode = 1; // 0: voxel - based approximate convex decomposition, 1 : tetrahedron - based approximate convex decomposition
|
||||
params.m_maxNumVerticesPerCH = 128;
|
||||
params.m_minVolumePerCH = 0.0001; // controls the adaptive sampling of the generated convex - hulls
|
||||
|
||||
// load the mesh
|
||||
|
||||
auto begin = std::chrono::high_resolution_clock::now();
|
||||
if (!vUtil.loadFBX(fname, &fbx)){
|
||||
cout << "Error in opening FBX file....";
|
||||
return 1;
|
||||
}
|
||||
auto end = std::chrono::high_resolution_clock::now();
|
||||
auto loadDuration = std::chrono::duration_cast<std::chrono::nanoseconds>(end - begin).count();
|
||||
|
||||
//perform vhacd computation
|
||||
begin = std::chrono::high_resolution_clock::now();
|
||||
if (!vUtil.computeVHACD(&fbx, params, &results)){
|
||||
cout << "Compute Failed...";
|
||||
return 1;
|
||||
}
|
||||
end = std::chrono::high_resolution_clock::now();
|
||||
auto computeDuration = std::chrono::duration_cast<std::chrono::nanoseconds>(end - begin).count();
|
||||
|
||||
int totalVertices = 0;
|
||||
for (int i = 0; i < fbx.meshCount; i++){
|
||||
totalVertices += fbx.perMeshVertices.at(i).count();
|
||||
}
|
||||
|
||||
int totalTriangles = 0;
|
||||
for (int i = 0; i < fbx.meshCount; i++){
|
||||
totalTriangles += fbx.perMeshTriangleIndices.at(i).count();
|
||||
}
|
||||
|
||||
int totalHulls = 0;
|
||||
QVector<int> hullCounts = results.convexHullsCountList;
|
||||
for (int i = 0; i < results.meshCount; i++){
|
||||
totalHulls += hullCounts.at(i);
|
||||
}
|
||||
cout << endl << "Summary of V-HACD Computation..................." << endl;
|
||||
cout << "File Path : " << fname.toStdString() << endl;
|
||||
cout << "Number Of Meshes : " << fbx.meshCount << endl;
|
||||
cout << "Processed Meshes : " << results.meshCount << endl;
|
||||
cout << "Total vertices : " << totalVertices << endl;
|
||||
cout << "Total Triangles : " << totalTriangles << endl;
|
||||
cout << "Total Convex Hulls : " << totalHulls << endl;
|
||||
cout << "Total FBX load time: " << (double)loadDuration / 1000000000.00 << " seconds" << endl;
|
||||
cout << "V-HACD Compute time: " << (double)computeDuration / 1000000000.00 << " seconds" << endl;
|
||||
cout << endl << "Summary per convex hull ........................" << endl <<endl;
|
||||
for (int i = 0; i < results.meshCount; i++){
|
||||
cout << "Mesh : " << i + 1 << endl;
|
||||
QVector<VHACD::IVHACD::ConvexHull> chList = results.convexHullList.at(i);
|
||||
cout << "\t" << "Number Of Hulls : " << chList.count() << endl;
|
||||
|
||||
for (int j = 0; j < results.convexHullList.at(i).count(); j++){
|
||||
cout << "\tHUll : " << j + 1 << endl;
|
||||
cout << "\t\tNumber Of Points : " << chList.at(j).m_nPoints << endl;
|
||||
cout << "\t\tNumber Of Triangles : " << chList.at(j).m_nTriangles << endl;
|
||||
}
|
||||
}
|
||||
|
||||
getchar();
|
||||
return 0;
|
||||
}
|
Loading…
Reference in a new issue