mirror of
https://github.com/overte-org/overte.git
synced 2025-08-04 04:23:33 +02:00
merge upstream/master into andrew/thermonuclear
This commit is contained in:
commit
ff7559c2c2
41 changed files with 1094 additions and 294 deletions
15
BUILD.md
15
BUILD.md
|
@ -96,12 +96,13 @@ Currently building on Windows has been tested using the following compilers:
|
||||||
|
|
||||||
#####Windows SDK 7.1
|
#####Windows SDK 7.1
|
||||||
|
|
||||||
Whichever version of Visual Studio you use, you will need [Microsoft Windows SDK for Windows 7 and .NET Framework 4](http://www.microsoft.com/en-us/download/details.aspx?id=8279).
|
If using Visual Studio 2010, or using Visual Studio 2013 but building as a Visual Studio 2010 project, you need [Microsoft Windows SDK for Windows 7 and .NET Framework 4](http://www.microsoft.com/en-us/download/details.aspx?id=8279).
|
||||||
|
|
||||||
NOTE: If using Visual Studio C++ 2010 Express, you need to follow a specific install order. See below before installing the Windows SDK.
|
NOTE: If using Visual Studio C++ 2010 Express, you need to follow a specific install order. See below before installing the Windows SDK.
|
||||||
|
|
||||||
######Windows 8.1
|
######Windows SDK 8.1
|
||||||
You may have already downloaded the Windows 8 SDK (e.g. if you have previously installed Visual Studio 2013). If so, change CMAKE_PREFIX_PATH in %HIFI_DIR%\CMakeLists.txt to point to the Windows 8 SDK binaries. The default path is `C:\Program Files (x86)\Windows Kits\8.1\Lib\winv6.3\um\x86`
|
|
||||||
|
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`.
|
||||||
|
|
||||||
#####Visual Studio C++ 2010 Express
|
#####Visual Studio C++ 2010 Express
|
||||||
|
|
||||||
|
@ -123,9 +124,11 @@ Some of the build instructions will ask you to start a Visual Studio Command Pro
|
||||||
|
|
||||||
#####Visual Studio 2013
|
#####Visual Studio 2013
|
||||||
|
|
||||||
This product must be purchased separately.
|
You can use the Community or Professional editions of Visual Studio 2013.
|
||||||
|
|
||||||
Visual Studio 2013 doesn't have a shortcut to start a Visual Studio Command Prompt. Instead, start a regular command prompt and then run:
|
You can start a Visual Studio 2013 command prompt using the shortcut provided in the Visual Studio Tools folder installed as part of Visual Studio 2013.
|
||||||
|
|
||||||
|
Or you can start a regular command prompt and then run:
|
||||||
|
|
||||||
"%VS120COMNTOOLS%\vsvars32.bat"
|
"%VS120COMNTOOLS%\vsvars32.bat"
|
||||||
|
|
||||||
|
@ -146,6 +149,8 @@ Once Qt is installed, you need to manually configure the following:
|
||||||
* Make sure the Qt runtime DLLs are loadable. You must do this before you attempt to build because some tools for the build depend on Qt. E.g., add to the PATH: `Qt\5.2.0\msvc2010_opengl\bin\`.
|
* Make sure the Qt runtime DLLs are loadable. You must do this before you attempt to build because some tools for the build depend on Qt. E.g., add to the PATH: `Qt\5.2.0\msvc2010_opengl\bin\`.
|
||||||
* Set the QT_CMAKE_PREFIX_PATH environment variable to your `Qt\5.2.0\msvc2010_opengl` directory.
|
* Set the QT_CMAKE_PREFIX_PATH environment variable to your `Qt\5.2.0\msvc2010_opengl` directory.
|
||||||
|
|
||||||
|
If building as a Visual Studio 2013 project, download and configure the msvc2013 version of Qt instead.
|
||||||
|
|
||||||
####External Libraries
|
####External Libraries
|
||||||
|
|
||||||
CMake will need to know where the headers and libraries for required external dependencies are.
|
CMake will need to know where the headers and libraries for required external dependencies are.
|
||||||
|
|
|
@ -10,6 +10,7 @@
|
||||||
//
|
//
|
||||||
|
|
||||||
#include <QtCore/QProcess>
|
#include <QtCore/QProcess>
|
||||||
|
#include <QtCore/qsharedmemory.h>
|
||||||
#include <QtCore/QThread>
|
#include <QtCore/QThread>
|
||||||
#include <QtCore/QTimer>
|
#include <QtCore/QTimer>
|
||||||
|
|
||||||
|
@ -38,7 +39,8 @@ int hifiSockAddrMeta = qRegisterMetaType<HifiSockAddr>("HifiSockAddr");
|
||||||
AssignmentClient::AssignmentClient(int &argc, char **argv) :
|
AssignmentClient::AssignmentClient(int &argc, char **argv) :
|
||||||
QCoreApplication(argc, argv),
|
QCoreApplication(argc, argv),
|
||||||
_shutdownEventListener(this),
|
_shutdownEventListener(this),
|
||||||
_assignmentServerHostname(DEFAULT_ASSIGNMENT_SERVER_HOSTNAME)
|
_assignmentServerHostname(DEFAULT_ASSIGNMENT_SERVER_HOSTNAME),
|
||||||
|
_localASPortSharedMem(NULL)
|
||||||
{
|
{
|
||||||
LogUtils::init();
|
LogUtils::init();
|
||||||
|
|
||||||
|
@ -89,13 +91,7 @@ AssignmentClient::AssignmentClient(int &argc, char **argv) :
|
||||||
// create a NodeList as an unassigned client
|
// create a NodeList as an unassigned client
|
||||||
NodeList* nodeList = NodeList::createInstance(NodeType::Unassigned);
|
NodeList* nodeList = NodeList::createInstance(NodeType::Unassigned);
|
||||||
|
|
||||||
unsigned short assignmentServerPort = DEFAULT_DOMAIN_SERVER_PORT;
|
quint16 assignmentServerPort = DEFAULT_DOMAIN_SERVER_PORT;
|
||||||
|
|
||||||
// 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();
|
|
||||||
}
|
|
||||||
|
|
||||||
// check for an overriden assignment server hostname
|
// check for an overriden assignment server hostname
|
||||||
if (argumentVariantMap.contains(CUSTOM_ASSIGNMENT_SERVER_HOSTNAME_OPTION)) {
|
if (argumentVariantMap.contains(CUSTOM_ASSIGNMENT_SERVER_HOSTNAME_OPTION)) {
|
||||||
|
@ -103,10 +99,16 @@ AssignmentClient::AssignmentClient(int &argc, char **argv) :
|
||||||
_assignmentServerHostname = argumentVariantMap.value(CUSTOM_ASSIGNMENT_SERVER_HOSTNAME_OPTION).toString();
|
_assignmentServerHostname = argumentVariantMap.value(CUSTOM_ASSIGNMENT_SERVER_HOSTNAME_OPTION).toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
HifiSockAddr assignmentServerSocket(_assignmentServerHostname, assignmentServerPort, true);
|
// check for an overriden assignment server port
|
||||||
nodeList->setAssignmentServerSocket(assignmentServerSocket);
|
if (argumentVariantMap.contains(CUSTOM_ASSIGNMENT_SERVER_PORT_OPTION)) {
|
||||||
|
assignmentServerPort =
|
||||||
|
argumentVariantMap.value(CUSTOM_ASSIGNMENT_SERVER_PORT_OPTION).toString().toUInt();
|
||||||
|
}
|
||||||
|
|
||||||
|
_assignmentServerSocket = HifiSockAddr(_assignmentServerHostname, assignmentServerPort, true);
|
||||||
|
nodeList->setAssignmentServerSocket(_assignmentServerSocket);
|
||||||
|
|
||||||
qDebug() << "Assignment server socket is" << assignmentServerSocket;
|
qDebug() << "Assignment server socket is" << _assignmentServerSocket;
|
||||||
|
|
||||||
// call a timer function every ASSIGNMENT_REQUEST_INTERVAL_MSECS to ask for assignment, if required
|
// call a timer function every ASSIGNMENT_REQUEST_INTERVAL_MSECS to ask for assignment, if required
|
||||||
qDebug() << "Waiting for assignment -" << _requestAssignment;
|
qDebug() << "Waiting for assignment -" << _requestAssignment;
|
||||||
|
@ -129,7 +131,40 @@ AssignmentClient::AssignmentClient(int &argc, char **argv) :
|
||||||
|
|
||||||
void AssignmentClient::sendAssignmentRequest() {
|
void AssignmentClient::sendAssignmentRequest() {
|
||||||
if (!_currentAssignment) {
|
if (!_currentAssignment) {
|
||||||
NodeList::getInstance()->sendAssignment(_requestAssignment);
|
|
||||||
|
NodeList* nodeList = NodeList::getInstance();
|
||||||
|
|
||||||
|
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();
|
||||||
|
|
||||||
|
if (localAssignmentServerPort != _assignmentServerSocket.getPort()) {
|
||||||
|
qDebug() << "Port for local assignment server read from shared memory is"
|
||||||
|
<< localAssignmentServerPort;
|
||||||
|
|
||||||
|
_assignmentServerSocket.setPort(localAssignmentServerPort);
|
||||||
|
nodeList->setAssignmentServerSocket(_assignmentServerSocket);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
nodeList->sendAssignment(_requestAssignment);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -17,6 +17,8 @@
|
||||||
#include "ShutdownEventListener.h"
|
#include "ShutdownEventListener.h"
|
||||||
#include "ThreadedAssignment.h"
|
#include "ThreadedAssignment.h"
|
||||||
|
|
||||||
|
class QSharedMemory;
|
||||||
|
|
||||||
class AssignmentClient : public QCoreApplication {
|
class AssignmentClient : public QCoreApplication {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
|
@ -34,6 +36,8 @@ private:
|
||||||
static SharedAssignmentPointer _currentAssignment;
|
static SharedAssignmentPointer _currentAssignment;
|
||||||
ShutdownEventListener _shutdownEventListener;
|
ShutdownEventListener _shutdownEventListener;
|
||||||
QString _assignmentServerHostname;
|
QString _assignmentServerHostname;
|
||||||
|
HifiSockAddr _assignmentServerSocket;
|
||||||
|
QSharedMemory* _localASPortSharedMem;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // hifi_AssignmentClient_h
|
#endif // hifi_AssignmentClient_h
|
||||||
|
|
|
@ -48,8 +48,13 @@ elseif (UNIX)
|
||||||
select_library_configurations(XINERAMA)
|
select_library_configurations(XINERAMA)
|
||||||
|
|
||||||
elseif (WIN32)
|
elseif (WIN32)
|
||||||
find_library(LIBOVR_LIBRARY_DEBUG NAMES libovrd PATH_SUFFIXES Lib/Win32/VS2010 HINTS ${LIBOVR_SEARCH_DIRS})
|
if (MSVC10)
|
||||||
find_library(LIBOVR_LIBRARY_RELEASE NAMES libovr PATH_SUFFIXES Lib/Win32/VS2010 HINTS ${LIBOVR_SEARCH_DIRS})
|
find_library(LIBOVR_LIBRARY_DEBUG NAMES libovrd PATH_SUFFIXES Lib/Win32/VS2010 HINTS ${LIBOVR_SEARCH_DIRS})
|
||||||
|
find_library(LIBOVR_LIBRARY_RELEASE NAMES libovr PATH_SUFFIXES Lib/Win32/VS2010 HINTS ${LIBOVR_SEARCH_DIRS})
|
||||||
|
elseif (MSVC12)
|
||||||
|
find_library(LIBOVR_LIBRARY_DEBUG NAMES libovrd PATH_SUFFIXES Lib/Win32/VS2013 HINTS ${LIBOVR_SEARCH_DIRS})
|
||||||
|
find_library(LIBOVR_LIBRARY_RELEASE NAMES libovr PATH_SUFFIXES Lib/Win32/VS2013 HINTS ${LIBOVR_SEARCH_DIRS})
|
||||||
|
endif ()
|
||||||
find_package(ATL)
|
find_package(ATL)
|
||||||
endif ()
|
endif ()
|
||||||
|
|
||||||
|
|
|
@ -18,6 +18,7 @@
|
||||||
#include <QtCore/QJsonObject>
|
#include <QtCore/QJsonObject>
|
||||||
#include <QtCore/QJsonArray>
|
#include <QtCore/QJsonArray>
|
||||||
#include <QtCore/QProcess>
|
#include <QtCore/QProcess>
|
||||||
|
#include <QtCore/qsharedmemory.h>
|
||||||
#include <QtCore/QStandardPaths>
|
#include <QtCore/QStandardPaths>
|
||||||
#include <QtCore/QTimer>
|
#include <QtCore/QTimer>
|
||||||
#include <QtCore/QUrlQuery>
|
#include <QtCore/QUrlQuery>
|
||||||
|
@ -228,6 +229,21 @@ void DomainServer::setupNodeListAndAssignments(const QUuid& sessionUUID) {
|
||||||
|
|
||||||
LimitedNodeList* nodeList = LimitedNodeList::createInstance(domainServerPort, domainServerDTLSPort);
|
LimitedNodeList* nodeList = LimitedNodeList::createInstance(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.";
|
||||||
|
}
|
||||||
|
|
||||||
// set our LimitedNodeList UUID to match the UUID from our config
|
// set our LimitedNodeList UUID to match the UUID from our config
|
||||||
// nodes will currently use this to add resources to data-web that relate to our domain
|
// nodes will currently use this to add resources to data-web that relate to our domain
|
||||||
const QString METAVERSE_DOMAIN_ID_KEY_PATH = "metaverse.id";
|
const QString METAVERSE_DOMAIN_ID_KEY_PATH = "metaverse.id";
|
||||||
|
@ -321,9 +337,31 @@ bool DomainServer::optionallySetupAssignmentPayment() {
|
||||||
|
|
||||||
void DomainServer::setupAutomaticNetworking() {
|
void DomainServer::setupAutomaticNetworking() {
|
||||||
|
|
||||||
|
LimitedNodeList* nodeList = LimitedNodeList::getInstance();
|
||||||
|
|
||||||
|
const int STUN_REFLEXIVE_KEEPALIVE_INTERVAL_MSECS = 10 * 1000;
|
||||||
|
const int STUN_IP_ADDRESS_CHECK_INTERVAL_MSECS = 30 * 1000;
|
||||||
|
|
||||||
|
// setup our timer to check our IP via stun every X seconds
|
||||||
|
QTimer* dynamicIPTimer = new QTimer(this);
|
||||||
|
connect(dynamicIPTimer, &QTimer::timeout, this, &DomainServer::requestCurrentPublicSocketViaSTUN);
|
||||||
|
|
||||||
|
if (_automaticNetworkingSetting == FULL_AUTOMATIC_NETWORKING_VALUE) {
|
||||||
|
dynamicIPTimer->start(STUN_REFLEXIVE_KEEPALIVE_INTERVAL_MSECS);
|
||||||
|
|
||||||
|
// setup a timer to heartbeat with the ice-server every so often
|
||||||
|
QTimer* iceHeartbeatTimer = new QTimer(this);
|
||||||
|
connect(iceHeartbeatTimer, &QTimer::timeout, this, &DomainServer::performICEUpdates);
|
||||||
|
iceHeartbeatTimer->start(ICE_HEARBEAT_INTERVAL_MSECS);
|
||||||
|
|
||||||
|
// call our sendHeartbeaToIceServer immediately anytime a local or public socket changes
|
||||||
|
connect(nodeList, &LimitedNodeList::localSockAddrChanged, this, &DomainServer::sendHeartbeatToIceServer);
|
||||||
|
connect(nodeList, &LimitedNodeList::publicSockAddrChanged, this, &DomainServer::sendHeartbeatToIceServer);
|
||||||
|
}
|
||||||
|
|
||||||
if (!didSetupAccountManagerWithAccessToken()) {
|
if (!didSetupAccountManagerWithAccessToken()) {
|
||||||
qDebug() << "Cannot setup domain-server automatic networking without an access token.";
|
qDebug() << "Cannot send heartbeat to data server without an access token.";
|
||||||
qDebug() << "Please add an access token to your config file or via the web interface.";
|
qDebug() << "Add an access token to your config file or via the web interface.";
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -334,37 +372,18 @@ void DomainServer::setupAutomaticNetworking() {
|
||||||
if (_automaticNetworkingSetting == IP_ONLY_AUTOMATIC_NETWORKING_VALUE ||
|
if (_automaticNetworkingSetting == IP_ONLY_AUTOMATIC_NETWORKING_VALUE ||
|
||||||
_automaticNetworkingSetting == FULL_AUTOMATIC_NETWORKING_VALUE) {
|
_automaticNetworkingSetting == FULL_AUTOMATIC_NETWORKING_VALUE) {
|
||||||
|
|
||||||
LimitedNodeList* nodeList = LimitedNodeList::getInstance();
|
|
||||||
const QUuid& domainID = nodeList->getSessionUUID();
|
const QUuid& domainID = nodeList->getSessionUUID();
|
||||||
|
|
||||||
if (!domainID.isNull()) {
|
if (!domainID.isNull()) {
|
||||||
qDebug() << "domain-server" << _automaticNetworkingSetting << "automatic networking enabled for ID"
|
qDebug() << "domain-server" << _automaticNetworkingSetting << "automatic networking enabled for ID"
|
||||||
<< uuidStringWithoutCurlyBraces(domainID) << "via" << _oauthProviderURL.toString();
|
<< uuidStringWithoutCurlyBraces(domainID) << "via" << _oauthProviderURL.toString();
|
||||||
|
|
||||||
const int STUN_IP_ADDRESS_CHECK_INTERVAL_MSECS = 30 * 1000;
|
|
||||||
const int STUN_REFLEXIVE_KEEPALIVE_INTERVAL_MSECS = 10 * 1000;
|
|
||||||
|
|
||||||
// setup our timer to check our IP via stun every X seconds
|
|
||||||
QTimer* dynamicIPTimer = new QTimer(this);
|
|
||||||
connect(dynamicIPTimer, &QTimer::timeout, this, &DomainServer::requestCurrentPublicSocketViaSTUN);
|
|
||||||
|
|
||||||
if (_automaticNetworkingSetting == IP_ONLY_AUTOMATIC_NETWORKING_VALUE) {
|
if (_automaticNetworkingSetting == IP_ONLY_AUTOMATIC_NETWORKING_VALUE) {
|
||||||
dynamicIPTimer->start(STUN_IP_ADDRESS_CHECK_INTERVAL_MSECS);
|
dynamicIPTimer->start(STUN_IP_ADDRESS_CHECK_INTERVAL_MSECS);
|
||||||
|
|
||||||
// send public socket changes to the data server so nodes can find us at our new IP
|
// send public socket changes to the data server so nodes can find us at our new IP
|
||||||
connect(nodeList, &LimitedNodeList::publicSockAddrChanged, this, &DomainServer::performIPAddressUpdate);
|
connect(nodeList, &LimitedNodeList::publicSockAddrChanged, this, &DomainServer::performIPAddressUpdate);
|
||||||
} else {
|
} else {
|
||||||
dynamicIPTimer->start(STUN_REFLEXIVE_KEEPALIVE_INTERVAL_MSECS);
|
|
||||||
|
|
||||||
// setup a timer to heartbeat with the ice-server every so often
|
|
||||||
QTimer* iceHeartbeatTimer = new QTimer(this);
|
|
||||||
connect(iceHeartbeatTimer, &QTimer::timeout, this, &DomainServer::performICEUpdates);
|
|
||||||
iceHeartbeatTimer->start(ICE_HEARBEAT_INTERVAL_MSECS);
|
|
||||||
|
|
||||||
// call our sendHeartbeaToIceServer immediately anytime a local or public socket changes
|
|
||||||
connect(nodeList, &LimitedNodeList::localSockAddrChanged, this, &DomainServer::sendHeartbeatToIceServer);
|
|
||||||
connect(nodeList, &LimitedNodeList::publicSockAddrChanged, this, &DomainServer::sendHeartbeatToIceServer);
|
|
||||||
|
|
||||||
// send our heartbeat to data server so it knows what our network settings are
|
// send our heartbeat to data server so it knows what our network settings are
|
||||||
sendHeartbeatToDataServer();
|
sendHeartbeatToDataServer();
|
||||||
}
|
}
|
||||||
|
|
37
examples/developerMenuItems.js
Normal file
37
examples/developerMenuItems.js
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
//
|
||||||
|
// developerMenuItems.js
|
||||||
|
// examples
|
||||||
|
//
|
||||||
|
// Created by Brad Hefta-Gaub on 2/24/14
|
||||||
|
// Copyright 2013 High Fidelity, Inc.
|
||||||
|
//
|
||||||
|
// Adds a bunch of developer and debugging menu items
|
||||||
|
//
|
||||||
|
// Distributed under the Apache License, Version 2.0.
|
||||||
|
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||||
|
//
|
||||||
|
|
||||||
|
|
||||||
|
function setupMenus() {
|
||||||
|
if (!Menu.menuExists("Developer")) {
|
||||||
|
Menu.addMenu("Developer");
|
||||||
|
}
|
||||||
|
if (!Menu.menuExists("Developer > Entities")) {
|
||||||
|
Menu.addMenu("Developer > Entities");
|
||||||
|
Menu.addMenuItem({ menuName: "Developer > Entities", menuItemName: "Display Model Bounds", isCheckable: true, isChecked: false });
|
||||||
|
Menu.addMenuItem({ menuName: "Developer > Entities", menuItemName: "Display Model Element Bounds", isCheckable: true, isChecked: false });
|
||||||
|
Menu.addMenuItem({ menuName: "Developer > Entities", menuItemName: "Display Model Element Children", isCheckable: true, isChecked: false });
|
||||||
|
Menu.addMenuItem({ menuName: "Developer > Entities", menuItemName: "Disable Light Entities", isCheckable: true, isChecked: false });
|
||||||
|
Menu.addMenuItem({ menuName: "Developer > Entities", menuItemName: "Don't Attempt to Reduce Material Switches", isCheckable: true, isChecked: false });
|
||||||
|
Menu.addMenuItem({ menuName: "Developer > Entities", menuItemName: "Don't Attempt Render Entities as Scene", isCheckable: true, isChecked: false });
|
||||||
|
Menu.addMenu("Developer > Entities > Culling");
|
||||||
|
Menu.addMenuItem({ menuName: "Developer > Entities > Culling", menuItemName: "Don't Cull Out Of View Mesh Parts", isCheckable: true, isChecked: false });
|
||||||
|
Menu.addMenuItem({ menuName: "Developer > Entities > Culling", menuItemName: "Don't Cull Too Small Mesh Parts", isCheckable: true, isChecked: false });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function scriptEnding() {
|
||||||
|
Menu.removeMenu("Developer > Entities");
|
||||||
|
}
|
||||||
|
setupMenus();
|
||||||
|
Script.scriptEnding.connect(scriptEnding);
|
|
@ -19,6 +19,7 @@ var warpPosition = { x: 0, y: 0, z: 0 };
|
||||||
|
|
||||||
var hipsToEyes;
|
var hipsToEyes;
|
||||||
var restoreCountdownTimer;
|
var restoreCountdownTimer;
|
||||||
|
var headTurningTimer = 0.0;
|
||||||
|
|
||||||
// Overlays to show target location
|
// Overlays to show target location
|
||||||
|
|
||||||
|
@ -168,6 +169,20 @@ function update(deltaTime) {
|
||||||
restoreCountDownTimer = 0.0;
|
restoreCountDownTimer = 0.0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
var HEAD_TURN_TIME = 0.10;
|
||||||
|
var HEAD_TURN_DEGREES = 4.0;
|
||||||
|
var HEAD_TURN_START_ANGLE = 45.0;
|
||||||
|
var currentYaw = MyAvatar.getHeadFinalYaw();
|
||||||
|
if (Math.abs(currentYaw) > HEAD_TURN_START_ANGLE) {
|
||||||
|
headTurningTimer += deltaTime;
|
||||||
|
if (headTurningTimer > HEAD_TURN_TIME) {
|
||||||
|
headTurningTimer = 0.0;
|
||||||
|
MyAvatar.orientation = Quat.multiply(Quat.fromPitchYawRollDegrees(0, (currentYaw > 0) ? HEAD_TURN_DEGREES: -HEAD_TURN_DEGREES, 0),
|
||||||
|
MyAvatar.orientation);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
headTurningTimer = 0.0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Controller.keyPressEvent.connect(function(event) {
|
Controller.keyPressEvent.connect(function(event) {
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
var gridColor = { red: 0, green: 0, blue: 0 };
|
var gridColor = { red: 0, green: 0, blue: 0 };
|
||||||
var gridColors = [
|
var gridColors = [
|
||||||
{ red: 0, green: 0, blue: 0 },
|
{ red: 0, green: 0, blue: 0 },
|
||||||
{ red: 128, green: 128, blue: 128 },
|
{ red: 255, green: 255, blue: 255 },
|
||||||
{ red: 255, green: 0, blue: 0 },
|
{ red: 255, green: 0, blue: 0 },
|
||||||
{ red: 0, green: 255, blue: 0},
|
{ red: 0, green: 255, blue: 0},
|
||||||
{ red: 0, green: 0, blue: 255 },
|
{ red: 0, green: 0, blue: 255 },
|
||||||
|
|
|
@ -471,17 +471,20 @@ var leapHands = (function () {
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
hands[h].inactiveCount += 1;
|
if (hands[h].inactiveCount < MAX_HAND_INACTIVE_COUNT) {
|
||||||
|
|
||||||
if (hands[h].inactiveCount === MAX_HAND_INACTIVE_COUNT) {
|
hands[h].inactiveCount += 1;
|
||||||
if (h === 0) {
|
|
||||||
MyAvatar.clearJointData("LeftHand");
|
if (hands[h].inactiveCount === MAX_HAND_INACTIVE_COUNT) {
|
||||||
MyAvatar.clearJointData("LeftForeArm");
|
if (h === 0) {
|
||||||
MyAvatar.clearJointData("LeftArm");
|
MyAvatar.clearJointData("LeftHand");
|
||||||
} else {
|
MyAvatar.clearJointData("LeftForeArm");
|
||||||
MyAvatar.clearJointData("RightHand");
|
MyAvatar.clearJointData("LeftArm");
|
||||||
MyAvatar.clearJointData("RightForeArm");
|
} else {
|
||||||
MyAvatar.clearJointData("RightArm");
|
MyAvatar.clearJointData("RightHand");
|
||||||
|
MyAvatar.clearJointData("RightForeArm");
|
||||||
|
MyAvatar.clearJointData("RightArm");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -200,6 +200,13 @@ SelectionManager = (function() {
|
||||||
return that;
|
return that;
|
||||||
})();
|
})();
|
||||||
|
|
||||||
|
// Normalize degrees to be in the range (-180, 180]
|
||||||
|
function normalizeDegrees(degrees) {
|
||||||
|
while (degrees > 180) degrees -= 360;
|
||||||
|
while (degrees <= -180) degrees += 360;
|
||||||
|
return degrees;
|
||||||
|
}
|
||||||
|
|
||||||
SelectionDisplay = (function () {
|
SelectionDisplay = (function () {
|
||||||
var that = {};
|
var that = {};
|
||||||
|
|
||||||
|
@ -207,6 +214,12 @@ SelectionDisplay = (function () {
|
||||||
|
|
||||||
var GRABBER_DISTANCE_TO_SIZE_RATIO = 0.0075;
|
var GRABBER_DISTANCE_TO_SIZE_RATIO = 0.0075;
|
||||||
|
|
||||||
|
// 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_Y_MULTIPLIER = 0.18;
|
||||||
|
var ROTATION_DISPLAY_LINE_HEIGHT_MULTIPLIER = 0.17;
|
||||||
|
|
||||||
var showExtendedStretchHandles = false;
|
var showExtendedStretchHandles = false;
|
||||||
|
|
||||||
var spaceMode = SPACE_LOCAL;
|
var spaceMode = SPACE_LOCAL;
|
||||||
|
@ -306,7 +319,7 @@ SelectionDisplay = (function () {
|
||||||
var highlightBox = Overlays.addOverlay("cube", {
|
var highlightBox = Overlays.addOverlay("cube", {
|
||||||
position: { x:0, y: 0, z: 0},
|
position: { x:0, y: 0, z: 0},
|
||||||
size: 1,
|
size: 1,
|
||||||
color: { red: 180, green: 180, blue: 180},
|
color: { red: 90, green: 90, blue: 90},
|
||||||
alpha: 1,
|
alpha: 1,
|
||||||
solid: false,
|
solid: false,
|
||||||
visible: false,
|
visible: false,
|
||||||
|
@ -318,7 +331,7 @@ SelectionDisplay = (function () {
|
||||||
var selectionBox = Overlays.addOverlay("cube", {
|
var selectionBox = Overlays.addOverlay("cube", {
|
||||||
position: { x:0, y: 0, z: 0},
|
position: { x:0, y: 0, z: 0},
|
||||||
size: 1,
|
size: 1,
|
||||||
color: { red: 180, green: 180, blue: 180},
|
color: { red: 60, green: 60, blue: 60},
|
||||||
alpha: 1,
|
alpha: 1,
|
||||||
solid: false,
|
solid: false,
|
||||||
visible: false,
|
visible: false,
|
||||||
|
@ -326,6 +339,24 @@ SelectionDisplay = (function () {
|
||||||
lineWidth: 1.0,
|
lineWidth: 1.0,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
var rotationDegreesDisplay = Overlays.addOverlay("text3d", {
|
||||||
|
position: { x:0, y: 0, z: 0},
|
||||||
|
text: "",
|
||||||
|
color: { red: 0, green: 0, blue: 0},
|
||||||
|
backgroundColor: { red: 255, green: 255, blue: 255 },
|
||||||
|
alpha: 0.7,
|
||||||
|
visible: false,
|
||||||
|
isFacingAvatar: true,
|
||||||
|
drawInFront: true,
|
||||||
|
ignoreRayIntersection: true,
|
||||||
|
dimensions: { x: 0, y: 0 },
|
||||||
|
lineHeight: 0.0,
|
||||||
|
topMargin: 0,
|
||||||
|
rightMargin: 0,
|
||||||
|
bottomMargin: 0,
|
||||||
|
leftMargin: 0,
|
||||||
|
});
|
||||||
|
|
||||||
var grabberMoveUp = Overlays.addOverlay("billboard", {
|
var grabberMoveUp = Overlays.addOverlay("billboard", {
|
||||||
url: HIFI_PUBLIC_BUCKET + "images/up-arrow.png",
|
url: HIFI_PUBLIC_BUCKET + "images/up-arrow.png",
|
||||||
position: { x:0, y: 0, z: 0},
|
position: { x:0, y: 0, z: 0},
|
||||||
|
@ -585,6 +616,7 @@ SelectionDisplay = (function () {
|
||||||
rotateOverlayCurrent,
|
rotateOverlayCurrent,
|
||||||
rotateZeroOverlay,
|
rotateZeroOverlay,
|
||||||
rotateCurrentOverlay,
|
rotateCurrentOverlay,
|
||||||
|
rotationDegreesDisplay,
|
||||||
xRailOverlay,
|
xRailOverlay,
|
||||||
yRailOverlay,
|
yRailOverlay,
|
||||||
zRailOverlay,
|
zRailOverlay,
|
||||||
|
@ -848,8 +880,8 @@ SelectionDisplay = (function () {
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
yawHandleRotation = Quat.fromVec3Degrees({ x: 270, y: 270, z: 0 });
|
yawHandleRotation = Quat.fromVec3Degrees({ x: 270, y: 270, z: 0 });
|
||||||
rollHandleRotation = Quat.fromVec3Degrees({ x: 0, y: 0, z: 180 });
|
|
||||||
pitchHandleRotation = Quat.fromVec3Degrees({ x: 180, y: 270, z: 0 });
|
pitchHandleRotation = Quat.fromVec3Degrees({ x: 180, y: 270, z: 0 });
|
||||||
|
rollHandleRotation = Quat.fromVec3Degrees({ x: 0, y: 0, z: 180 });
|
||||||
|
|
||||||
yawNormal = { x: 0, y: 1, z: 0 };
|
yawNormal = { x: 0, y: 1, z: 0 };
|
||||||
rollNormal = { x: 0, y: 0, z: 1 };
|
rollNormal = { x: 0, y: 0, z: 1 };
|
||||||
|
@ -1292,7 +1324,11 @@ SelectionDisplay = (function () {
|
||||||
var vec3Mult = function(v1, v2) {
|
var vec3Mult = function(v1, v2) {
|
||||||
return { x: v1.x * v2.x, y: v1.y * v2.y, z: v1.z * v2.z };
|
return { x: v1.x * v2.x, y: v1.y * v2.y, z: v1.z * v2.z };
|
||||||
}
|
}
|
||||||
var makeStretchTool = function(stretchMode, direction, pivot) {
|
// stretchMode - name of mode
|
||||||
|
// direction - direction to stretch in
|
||||||
|
// pivot - point to use as a pivot
|
||||||
|
// offset - the position of the overlay tool relative to the selections center position
|
||||||
|
var makeStretchTool = function(stretchMode, direction, pivot, offset) {
|
||||||
var signs = {
|
var signs = {
|
||||||
x: direction.x < 0 ? -1 : (direction.x > 0 ? 1 : 0),
|
x: direction.x < 0 ? -1 : (direction.x > 0 ? 1 : 0),
|
||||||
y: direction.y < 0 ? -1 : (direction.y > 0 ? 1 : 0),
|
y: direction.y < 0 ? -1 : (direction.y > 0 ? 1 : 0),
|
||||||
|
@ -1313,6 +1349,7 @@ SelectionDisplay = (function () {
|
||||||
var initialDimensions = null;
|
var initialDimensions = null;
|
||||||
var initialIntersection = null;
|
var initialIntersection = null;
|
||||||
var initialProperties = null;
|
var initialProperties = null;
|
||||||
|
var pickRayPosition = null;
|
||||||
var rotation = null;
|
var rotation = null;
|
||||||
|
|
||||||
var onBegin = function(event) {
|
var onBegin = function(event) {
|
||||||
|
@ -1321,13 +1358,22 @@ SelectionDisplay = (function () {
|
||||||
rotation = spaceMode == SPACE_LOCAL ? properties.rotation : Quat.fromPitchYawRollDegrees(0, 0, 0);
|
rotation = spaceMode == SPACE_LOCAL ? properties.rotation : Quat.fromPitchYawRollDegrees(0, 0, 0);
|
||||||
|
|
||||||
if (spaceMode == SPACE_LOCAL) {
|
if (spaceMode == SPACE_LOCAL) {
|
||||||
|
rotation = SelectionManager.localRotation;
|
||||||
initialPosition = SelectionManager.localPosition;
|
initialPosition = SelectionManager.localPosition;
|
||||||
initialDimensions = SelectionManager.localDimensions;
|
initialDimensions = SelectionManager.localDimensions;
|
||||||
} else {
|
} else {
|
||||||
|
rotation = SelectionManager.worldRotation;
|
||||||
initialPosition = SelectionManager.worldPosition;
|
initialPosition = SelectionManager.worldPosition;
|
||||||
initialDimensions = SelectionManager.worldDimensions;
|
initialDimensions = SelectionManager.worldDimensions;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var scaledOffset = {
|
||||||
|
x: initialDimensions.x * offset.x * 0.5,
|
||||||
|
y: initialDimensions.y * offset.y * 0.5,
|
||||||
|
z: initialDimensions.z * offset.z * 0.5,
|
||||||
|
};
|
||||||
|
pickRayPosition = Vec3.sum(initialPosition, Vec3.multiplyQbyV(rotation, scaledOffset));
|
||||||
|
|
||||||
if (numDimensions == 1 && mask.x) {
|
if (numDimensions == 1 && mask.x) {
|
||||||
var start = Vec3.multiplyQbyV(rotation, { x: -10000, y: 0, z: 0 });
|
var start = Vec3.multiplyQbyV(rotation, { x: -10000, y: 0, z: 0 });
|
||||||
start = Vec3.sum(start, properties.position);
|
start = Vec3.sum(start, properties.position);
|
||||||
|
@ -1381,7 +1427,7 @@ SelectionDisplay = (function () {
|
||||||
planeNormal = Vec3.multiplyQbyV(rotation, planeNormal);
|
planeNormal = Vec3.multiplyQbyV(rotation, planeNormal);
|
||||||
var pickRay = Camera.computePickRay(event.x, event.y);
|
var pickRay = Camera.computePickRay(event.x, event.y);
|
||||||
lastPick = rayPlaneIntersection(pickRay,
|
lastPick = rayPlaneIntersection(pickRay,
|
||||||
initialPosition,
|
pickRayPosition,
|
||||||
planeNormal);
|
planeNormal);
|
||||||
|
|
||||||
// Overlays.editOverlay(normalLine, {
|
// Overlays.editOverlay(normalLine, {
|
||||||
|
@ -1416,7 +1462,7 @@ SelectionDisplay = (function () {
|
||||||
|
|
||||||
var pickRay = Camera.computePickRay(event.x, event.y);
|
var pickRay = Camera.computePickRay(event.x, event.y);
|
||||||
newPick = rayPlaneIntersection(pickRay,
|
newPick = rayPlaneIntersection(pickRay,
|
||||||
initialPosition,
|
pickRayPosition,
|
||||||
planeNormal);
|
planeNormal);
|
||||||
var vector = Vec3.subtract(newPick, lastPick);
|
var vector = Vec3.subtract(newPick, lastPick);
|
||||||
|
|
||||||
|
@ -1491,44 +1537,64 @@ SelectionDisplay = (function () {
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
function addStretchTool(overlay, mode, pivot, direction) {
|
function addStretchTool(overlay, mode, pivot, direction, offset) {
|
||||||
if (!pivot) {
|
if (!pivot) {
|
||||||
pivot = Vec3.multiply(-1, direction);
|
pivot = Vec3.multiply(-1, direction);
|
||||||
pivot.y = direction.y;
|
pivot.y = direction.y;
|
||||||
}
|
}
|
||||||
var tool = makeStretchTool(mode, direction, pivot);
|
var tool = makeStretchTool(mode, direction, pivot, offset);
|
||||||
|
|
||||||
addGrabberTool(overlay, tool);
|
addGrabberTool(overlay, tool);
|
||||||
}
|
}
|
||||||
|
|
||||||
addStretchTool(grabberNEAR, "STRETCH_NEAR", { x: 0, y: 0, z: -1 }, { x: 0, y: 0, z: 1 });
|
addStretchTool(grabberNEAR, "STRETCH_NEAR", { x: 0, y: 0, z: -1 }, { x: 0, y: 0, z: 1 }, { x: 0, y: 0, z: -1 });
|
||||||
addStretchTool(grabberFAR, "STRETCH_FAR", { x: 0, y: 0, z: 1 }, { x: 0, y: 0, z: -1 });
|
addStretchTool(grabberFAR, "STRETCH_FAR", { x: 0, y: 0, z: 1 }, { x: 0, y: 0, z: -1 }, { x: 0, y: 0, z: 1 });
|
||||||
addStretchTool(grabberTOP, "STRETCH_TOP", { x: 0, y: 1, z: 0 }, { x: 0, y: -1, z: 0 });
|
addStretchTool(grabberTOP, "STRETCH_TOP", { x: 0, y: 1, z: 0 }, { x: 0, y: -1, z: 0 }, { x: 0, y: 1, z: 0 });
|
||||||
addStretchTool(grabberBOTTOM, "STRETCH_BOTTOM", { x: 0, y: -1, z: 0 }, { x: 0, y: 1, z: 0 });
|
addStretchTool(grabberBOTTOM, "STRETCH_BOTTOM", { x: 0, y: -1, z: 0 }, { x: 0, y: 1, z: 0 }, { x: 0, y: -1, z: 0 });
|
||||||
addStretchTool(grabberRIGHT, "STRETCH_RIGHT", { x: 1, y: 0, z: 0 }, { x: -1, y: 0, z: 0 });
|
addStretchTool(grabberRIGHT, "STRETCH_RIGHT", { x: 1, y: 0, z: 0 }, { x: -1, y: 0, z: 0 }, { x: 1, y: 0, z: 0 });
|
||||||
addStretchTool(grabberLEFT, "STRETCH_LEFT", { x: -1, y: 0, z: 0 }, { x: 1, y: 0, z: 0 });
|
addStretchTool(grabberLEFT, "STRETCH_LEFT", { x: -1, y: 0, z: 0 }, { x: 1, y: 0, z: 0 }, { x: -1, y: 0, z: 0 });
|
||||||
|
|
||||||
addStretchTool(grabberLBN, "STRETCH_LBN", null, {x: 1, y: 0, z: 1});
|
addStretchTool(grabberLBN, "STRETCH_LBN", null, {x: 1, y: 0, z: 1}, { x: -1, y: -1, z: -1 });
|
||||||
addStretchTool(grabberRBN, "STRETCH_RBN", null, {x: -1, y: 0, z: 1});
|
addStretchTool(grabberRBN, "STRETCH_RBN", null, {x: -1, y: 0, z: 1}, { x: 1, y: -1, z: -1 });
|
||||||
addStretchTool(grabberLBF, "STRETCH_LBF", null, {x: 1, y: 0, z: -1});
|
addStretchTool(grabberLBF, "STRETCH_LBF", null, {x: 1, y: 0, z: -1}, { x: -1, y: -1, z: 1 });
|
||||||
addStretchTool(grabberRBF, "STRETCH_RBF", null, {x: -1, y: 0, z: -1});
|
addStretchTool(grabberRBF, "STRETCH_RBF", null, {x: -1, y: 0, z: -1}, { x: 1, y: -1, z: 1 });
|
||||||
addStretchTool(grabberLTN, "STRETCH_LTN", null, {x: 1, y: 0, z: 1});
|
addStretchTool(grabberLTN, "STRETCH_LTN", null, {x: 1, y: 0, z: 1}, { x: -1, y: 1, z: -1 });
|
||||||
addStretchTool(grabberRTN, "STRETCH_RTN", null, {x: -1, y: 0, z: 1});
|
addStretchTool(grabberRTN, "STRETCH_RTN", null, {x: -1, y: 0, z: 1}, { x: 1, y: 1, z: -1 });
|
||||||
addStretchTool(grabberLTF, "STRETCH_LTF", null, {x: 1, y: 0, z: -1});
|
addStretchTool(grabberLTF, "STRETCH_LTF", null, {x: 1, y: 0, z: -1}, { x: -1, y: 1, z: 1 });
|
||||||
addStretchTool(grabberRTF, "STRETCH_RTF", null, {x: -1, y: 0, z: -1});
|
addStretchTool(grabberRTF, "STRETCH_RTF", null, {x: -1, y: 0, z: -1}, { x: 1, y: 1, z: 1 });
|
||||||
|
|
||||||
addStretchTool(grabberEdgeTR, "STRETCH_EdgeTR", null, {x: 1, y: 1, z: 0});
|
addStretchTool(grabberEdgeTR, "STRETCH_EdgeTR", null, {x: 1, y: 1, z: 0}, { x: 1, y: 1, z: 0 });
|
||||||
addStretchTool(grabberEdgeTL, "STRETCH_EdgeTL", null, {x: -1, y: 1, z: 0});
|
addStretchTool(grabberEdgeTL, "STRETCH_EdgeTL", null, {x: -1, y: 1, z: 0}, { x: -1, y: 1, z: 0 });
|
||||||
addStretchTool(grabberEdgeTF, "STRETCH_EdgeTF", null, {x: 0, y: 1, z: -1});
|
addStretchTool(grabberEdgeTF, "STRETCH_EdgeTF", null, {x: 0, y: 1, z: -1}, { x: 0, y: 1, z: -1 });
|
||||||
addStretchTool(grabberEdgeTN, "STRETCH_EdgeTN", null, {x: 0, y: 1, z: 1});
|
addStretchTool(grabberEdgeTN, "STRETCH_EdgeTN", null, {x: 0, y: 1, z: 1}, { x: 0, y: 1, z: 1 });
|
||||||
addStretchTool(grabberEdgeBR, "STRETCH_EdgeBR", null, {x: -1, y: 0, z: 0});
|
addStretchTool(grabberEdgeBR, "STRETCH_EdgeBR", null, {x: -1, y: 0, z: 0}, { x: 1, y: -1, z: 0 });
|
||||||
addStretchTool(grabberEdgeBL, "STRETCH_EdgeBL", null, {x: 1, y: 0, z: 0});
|
addStretchTool(grabberEdgeBL, "STRETCH_EdgeBL", null, {x: 1, y: 0, z: 0}, { x: -1, y: -1, z: 0 });
|
||||||
addStretchTool(grabberEdgeBF, "STRETCH_EdgeBF", null, {x: 0, y: 0, z: -1});
|
addStretchTool(grabberEdgeBF, "STRETCH_EdgeBF", null, {x: 0, y: 0, z: -1}, { x: 0, y: -1, z: -1 });
|
||||||
addStretchTool(grabberEdgeBN, "STRETCH_EdgeBN", null, {x: 0, y: 0, z: 1});
|
addStretchTool(grabberEdgeBN, "STRETCH_EdgeBN", null, {x: 0, y: 0, z: 1}, { x: 0, y: -1, z: 1 });
|
||||||
addStretchTool(grabberEdgeNR, "STRETCH_EdgeNR", null, {x: -1, y: 0, z: 1});
|
addStretchTool(grabberEdgeNR, "STRETCH_EdgeNR", null, {x: -1, y: 0, z: 1}, { x: 1, y: 0, z: -1 });
|
||||||
addStretchTool(grabberEdgeNL, "STRETCH_EdgeNL", null, {x: 1, y: 0, z: 1});
|
addStretchTool(grabberEdgeNL, "STRETCH_EdgeNL", null, {x: 1, y: 0, z: 1}, { x: -1, y: 0, z: -1 });
|
||||||
addStretchTool(grabberEdgeFR, "STRETCH_EdgeFR", null, {x: -1, y: 0, z: -1});
|
addStretchTool(grabberEdgeFR, "STRETCH_EdgeFR", null, {x: -1, y: 0, z: -1}, { x: 1, y: 0, z: 1 });
|
||||||
addStretchTool(grabberEdgeFL, "STRETCH_EdgeFL", null, {x: 1, y: 0, z: -1});
|
addStretchTool(grabberEdgeFL, "STRETCH_EdgeFL", null, {x: 1, y: 0, z: -1}, { x: -1, y: 0, z: 1 });
|
||||||
|
|
||||||
|
function updateRotationDegreesOverlay(angleFromZero, handleRotation, centerPosition) {
|
||||||
|
var angle = angleFromZero * (Math.PI / 180);
|
||||||
|
var position = {
|
||||||
|
x: Math.cos(angle) * outerRadius * ROTATION_DISPLAY_DISTANCE_MULTIPLIER,
|
||||||
|
y: Math.sin(angle) * outerRadius * ROTATION_DISPLAY_DISTANCE_MULTIPLIER,
|
||||||
|
z: 0,
|
||||||
|
};
|
||||||
|
position = Vec3.multiplyQbyV(handleRotation, position);
|
||||||
|
position = Vec3.sum(centerPosition, position);
|
||||||
|
Overlays.editOverlay(rotationDegreesDisplay, {
|
||||||
|
position: position,
|
||||||
|
dimensions: {
|
||||||
|
x: innerRadius * ROTATION_DISPLAY_SIZE_X_MULTIPLIER,
|
||||||
|
y: innerRadius * ROTATION_DISPLAY_SIZE_Y_MULTIPLIER
|
||||||
|
},
|
||||||
|
lineHeight: innerRadius * ROTATION_DISPLAY_LINE_HEIGHT_MULTIPLIER,
|
||||||
|
text: normalizeDegrees(angleFromZero),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
var initialPosition = SelectionManager.worldPosition;
|
var initialPosition = SelectionManager.worldPosition;
|
||||||
addGrabberTool(yawHandle, {
|
addGrabberTool(yawHandle, {
|
||||||
|
@ -1570,11 +1636,18 @@ SelectionDisplay = (function () {
|
||||||
endAt: 0,
|
endAt: 0,
|
||||||
innerRadius: 0.9,
|
innerRadius: 0.9,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
Overlays.editOverlay(rotationDegreesDisplay, {
|
||||||
|
visible: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
updateRotationDegreesOverlay(0, yawHandleRotation, yawCenter);
|
||||||
},
|
},
|
||||||
onEnd: function(event, reason) {
|
onEnd: function(event, reason) {
|
||||||
Overlays.editOverlay(rotateOverlayInner, { visible: false });
|
Overlays.editOverlay(rotateOverlayInner, { visible: false });
|
||||||
Overlays.editOverlay(rotateOverlayOuter, { visible: false });
|
Overlays.editOverlay(rotateOverlayOuter, { visible: false });
|
||||||
Overlays.editOverlay(rotateOverlayCurrent, { visible: false });
|
Overlays.editOverlay(rotateOverlayCurrent, { visible: false });
|
||||||
|
Overlays.editOverlay(rotationDegreesDisplay, { visible: false });
|
||||||
|
|
||||||
pushCommandForSelections();
|
pushCommandForSelections();
|
||||||
},
|
},
|
||||||
|
@ -1605,12 +1678,9 @@ SelectionDisplay = (function () {
|
||||||
var angleFromZero = Vec3.orientedAngle(centerToZero, centerToIntersect, rotationNormal);
|
var angleFromZero = Vec3.orientedAngle(centerToZero, centerToIntersect, rotationNormal);
|
||||||
|
|
||||||
var distanceFromCenter = Vec3.distance(center, result.intersection);
|
var distanceFromCenter = Vec3.distance(center, result.intersection);
|
||||||
var snapToInner = false;
|
var snapToInner = distanceFromCenter < innerRadius;
|
||||||
// var innerRadius = (Vec3.length(selectionManager.worldDimensions) / 2) * 1.1;
|
var snapAngle = snapToInner ? innerSnapAngle : 1.0;
|
||||||
if (distanceFromCenter < innerRadius) {
|
angleFromZero = Math.floor(angleFromZero / snapAngle) * snapAngle;
|
||||||
angleFromZero = Math.floor(angleFromZero/innerSnapAngle) * innerSnapAngle;
|
|
||||||
snapToInner = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// for debugging
|
// for debugging
|
||||||
if (debug) {
|
if (debug) {
|
||||||
|
@ -1632,7 +1702,9 @@ SelectionDisplay = (function () {
|
||||||
rotation: Quat.multiply(yawChange, initialProperties.rotation),
|
rotation: Quat.multiply(yawChange, initialProperties.rotation),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
updateRotationDegreesOverlay(angleFromZero, yawHandleRotation, yawCenter);
|
||||||
|
|
||||||
// update the rotation display accordingly...
|
// update the rotation display accordingly...
|
||||||
var startAtCurrent = 0;
|
var startAtCurrent = 0;
|
||||||
var endAtCurrent = angleFromZero;
|
var endAtCurrent = angleFromZero;
|
||||||
|
@ -1701,11 +1773,18 @@ SelectionDisplay = (function () {
|
||||||
endAt: 0,
|
endAt: 0,
|
||||||
innerRadius: 0.9,
|
innerRadius: 0.9,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
Overlays.editOverlay(rotationDegreesDisplay, {
|
||||||
|
visible: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
updateRotationDegreesOverlay(0, pitchHandleRotation, pitchCenter);
|
||||||
},
|
},
|
||||||
onEnd: function(event, reason) {
|
onEnd: function(event, reason) {
|
||||||
Overlays.editOverlay(rotateOverlayInner, { visible: false });
|
Overlays.editOverlay(rotateOverlayInner, { visible: false });
|
||||||
Overlays.editOverlay(rotateOverlayOuter, { visible: false });
|
Overlays.editOverlay(rotateOverlayOuter, { visible: false });
|
||||||
Overlays.editOverlay(rotateOverlayCurrent, { visible: false });
|
Overlays.editOverlay(rotateOverlayCurrent, { visible: false });
|
||||||
|
Overlays.editOverlay(rotationDegreesDisplay, { visible: false });
|
||||||
|
|
||||||
pushCommandForSelections();
|
pushCommandForSelections();
|
||||||
},
|
},
|
||||||
|
@ -1736,11 +1815,9 @@ SelectionDisplay = (function () {
|
||||||
var angleFromZero = Vec3.orientedAngle(centerToZero, centerToIntersect, rotationNormal);
|
var angleFromZero = Vec3.orientedAngle(centerToZero, centerToIntersect, rotationNormal);
|
||||||
|
|
||||||
var distanceFromCenter = Vec3.distance(center, result.intersection);
|
var distanceFromCenter = Vec3.distance(center, result.intersection);
|
||||||
var snapToInner = false;
|
var snapToInner = distanceFromCenter < innerRadius;
|
||||||
if (distanceFromCenter < innerRadius) {
|
var snapAngle = snapToInner ? innerSnapAngle : 1.0;
|
||||||
angleFromZero = Math.floor(angleFromZero/innerSnapAngle) * innerSnapAngle;
|
angleFromZero = Math.floor(angleFromZero / snapAngle) * snapAngle;
|
||||||
snapToInner = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// for debugging
|
// for debugging
|
||||||
if (debug) {
|
if (debug) {
|
||||||
|
@ -1764,6 +1841,8 @@ SelectionDisplay = (function () {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
updateRotationDegreesOverlay(angleFromZero, pitchHandleRotation, pitchCenter);
|
||||||
|
|
||||||
// update the rotation display accordingly...
|
// update the rotation display accordingly...
|
||||||
var startAtCurrent = 0;
|
var startAtCurrent = 0;
|
||||||
var endAtCurrent = angleFromZero;
|
var endAtCurrent = angleFromZero;
|
||||||
|
@ -1831,11 +1910,18 @@ SelectionDisplay = (function () {
|
||||||
endAt: 0,
|
endAt: 0,
|
||||||
innerRadius: 0.9,
|
innerRadius: 0.9,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
Overlays.editOverlay(rotationDegreesDisplay, {
|
||||||
|
visible: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
updateRotationDegreesOverlay(0, rollHandleRotation, rollCenter);
|
||||||
},
|
},
|
||||||
onEnd: function(event, reason) {
|
onEnd: function(event, reason) {
|
||||||
Overlays.editOverlay(rotateOverlayInner, { visible: false });
|
Overlays.editOverlay(rotateOverlayInner, { visible: false });
|
||||||
Overlays.editOverlay(rotateOverlayOuter, { visible: false });
|
Overlays.editOverlay(rotateOverlayOuter, { visible: false });
|
||||||
Overlays.editOverlay(rotateOverlayCurrent, { visible: false });
|
Overlays.editOverlay(rotateOverlayCurrent, { visible: false });
|
||||||
|
Overlays.editOverlay(rotationDegreesDisplay, { visible: false });
|
||||||
|
|
||||||
pushCommandForSelections();
|
pushCommandForSelections();
|
||||||
},
|
},
|
||||||
|
@ -1866,11 +1952,9 @@ SelectionDisplay = (function () {
|
||||||
var angleFromZero = Vec3.orientedAngle(centerToZero, centerToIntersect, rotationNormal);
|
var angleFromZero = Vec3.orientedAngle(centerToZero, centerToIntersect, rotationNormal);
|
||||||
|
|
||||||
var distanceFromCenter = Vec3.distance(center, result.intersection);
|
var distanceFromCenter = Vec3.distance(center, result.intersection);
|
||||||
var snapToInner = false;
|
var snapToInner = distanceFromCenter < innerRadius;
|
||||||
if (distanceFromCenter < innerRadius) {
|
var snapAngle = snapToInner ? innerSnapAngle : 1.0;
|
||||||
angleFromZero = Math.floor(angleFromZero/innerSnapAngle) * innerSnapAngle;
|
angleFromZero = Math.floor(angleFromZero / snapAngle) * snapAngle;
|
||||||
snapToInner = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// for debugging
|
// for debugging
|
||||||
if (debug) {
|
if (debug) {
|
||||||
|
@ -1893,6 +1977,8 @@ SelectionDisplay = (function () {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
updateRotationDegreesOverlay(angleFromZero, rollHandleRotation, rollCenter);
|
||||||
|
|
||||||
// update the rotation display accordingly...
|
// update the rotation display accordingly...
|
||||||
var startAtCurrent = 0;
|
var startAtCurrent = 0;
|
||||||
var endAtCurrent = angleFromZero;
|
var endAtCurrent = angleFromZero;
|
||||||
|
|
|
@ -36,25 +36,36 @@ uniform vec2 depthTexCoordOffset;
|
||||||
uniform vec2 depthTexCoordScale;
|
uniform vec2 depthTexCoordScale;
|
||||||
|
|
||||||
void main(void) {
|
void main(void) {
|
||||||
|
float depthVal = texture2D(depthMap, gl_TexCoord[0].st).r;
|
||||||
|
vec4 normalVal = texture2D(normalMap, gl_TexCoord[0].st);
|
||||||
|
vec4 diffuseVal = texture2D(diffuseMap, gl_TexCoord[0].st);
|
||||||
|
vec4 specularVal = texture2D(specularMap, gl_TexCoord[0].st);
|
||||||
|
|
||||||
// compute the view space position using the depth
|
// compute the view space position using the depth
|
||||||
float z = near / (texture2D(depthMap, gl_TexCoord[0].st).r * depthScale - 1.0);
|
float z = near / (depthVal * depthScale - 1.0);
|
||||||
vec4 position = vec4((depthTexCoordOffset + gl_TexCoord[0].st * depthTexCoordScale) * z, z, 0.0);
|
vec4 position = vec4((depthTexCoordOffset + gl_TexCoord[0].st * depthTexCoordScale) * z, z, 0.0);
|
||||||
|
|
||||||
// get the normal from the map
|
// get the normal from the map
|
||||||
vec4 normal = texture2D(normalMap, gl_TexCoord[0].st);
|
vec4 normal = normalVal;
|
||||||
vec4 normalizedNormal = normalize(normal * 2.0 - vec4(1.0, 1.0, 1.0, 2.0));
|
if ((normalVal.a >= 0.45) && (normalVal.a <= 0.55)) {
|
||||||
|
normal.a = 1.0;
|
||||||
// compute the base color based on OpenGL lighting model
|
normalVal.a = 0.0;
|
||||||
float diffuse = dot(normalizedNormal, gl_LightSource[0].position);
|
gl_FragColor = vec4(diffuseVal.rgb * specularVal.rgb, 1.0);
|
||||||
float facingLight = step(0.0, diffuse);
|
} else {
|
||||||
vec4 baseColor = texture2D(diffuseMap, gl_TexCoord[0].st) * (gl_FrontLightModelProduct.sceneColor +
|
vec3 normalizedNormal = normalize(normal.xyz * 2.0 - vec3(1.0));
|
||||||
gl_FrontLightProduct[0].ambient + gl_FrontLightProduct[0].diffuse * (diffuse * facingLight));
|
|
||||||
|
// compute the base color based on OpenGL lighting model
|
||||||
// compute the specular multiplier (sans exponent)
|
float diffuse = dot(normalizedNormal, gl_LightSource[0].position.xyz);
|
||||||
float specular = facingLight * max(0.0, dot(normalize(gl_LightSource[0].position - normalize(position)),
|
float facingLight = step(0.0, diffuse);
|
||||||
normalizedNormal));
|
vec3 baseColor = diffuseVal.rgb * (gl_FrontLightModelProduct.sceneColor.rgb +
|
||||||
|
gl_FrontLightProduct[0].ambient.rgb + gl_FrontLightProduct[0].diffuse.rgb * (diffuse * facingLight));
|
||||||
// add specular contribution
|
|
||||||
vec4 specularColor = texture2D(specularMap, gl_TexCoord[0].st);
|
// compute the specular multiplier (sans exponent)
|
||||||
gl_FragColor = vec4(baseColor.rgb + pow(specular, specularColor.a * 128.0) * specularColor.rgb, normal.a);
|
float specular = facingLight * max(0.0, dot(normalize(gl_LightSource[0].position.xyz - normalize(position.xyz)),
|
||||||
|
normalizedNormal));
|
||||||
|
|
||||||
|
// add specular contribution
|
||||||
|
vec4 specularColor = specularVal;
|
||||||
|
gl_FragColor = vec4(baseColor.rgb + pow(specular, specularColor.a * 128.0) * specularColor.rgb, normal.a);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,7 +31,7 @@ void main(void) {
|
||||||
// set the diffuse, normal, specular data
|
// set the diffuse, normal, specular data
|
||||||
vec4 diffuse = texture2D(diffuseMap, gl_TexCoord[0].st);
|
vec4 diffuse = texture2D(diffuseMap, gl_TexCoord[0].st);
|
||||||
vec4 emissive = texture2D(emissiveMap, interpolatedTexcoord1.st);
|
vec4 emissive = texture2D(emissiveMap, interpolatedTexcoord1.st);
|
||||||
gl_FragData[0] = vec4(gl_Color.rgb * diffuse.rgb * (vec3(emissiveParams.x) + emissiveParams.y * emissive.rgb), mix(gl_Color.a, 1.0 - gl_Color.a, step(diffuse.a, alphaThreshold)));
|
gl_FragData[0] = vec4(gl_Color.rgb * diffuse.rgb, mix(gl_Color.a, 1.0 - gl_Color.a, step(diffuse.a, alphaThreshold)));
|
||||||
gl_FragData[1] = normalize(normal) * 0.5 + vec4(0.5, 0.5, 0.5, 1.0);
|
gl_FragData[1] = normalize(normal) * 0.5 + vec4(0.5, 0.5, 0.5, 0.5);
|
||||||
gl_FragData[2] = vec4(gl_FrontMaterial.specular.rgb, gl_FrontMaterial.shininess / 128.0);
|
gl_FragData[2] = vec4((vec3(emissiveParams.x) + emissiveParams.y * emissive.rgb), gl_FrontMaterial.shininess / 128.0);
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
// model_normal_map.frag
|
// model_normal_map.frag
|
||||||
// fragment shader
|
// fragment shader
|
||||||
//
|
//
|
||||||
// Created by Andrzej Kapolka on 10/14/13.
|
// Created by Andrzej Kapolka on 10/29/13.
|
||||||
// Copyright 2013 High Fidelity, Inc.
|
// Copyright 2013 High Fidelity, Inc.
|
||||||
//
|
//
|
||||||
// Distributed under the Apache License, Version 2.0.
|
// Distributed under the Apache License, Version 2.0.
|
||||||
|
|
|
@ -438,6 +438,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer &startup_time) :
|
||||||
|
|
||||||
void Application::aboutToQuit() {
|
void Application::aboutToQuit() {
|
||||||
_aboutToQuit = true;
|
_aboutToQuit = true;
|
||||||
|
setFullscreen(false); // if you exit while in full screen, you'll get bad behavior when you restart.
|
||||||
}
|
}
|
||||||
|
|
||||||
Application::~Application() {
|
Application::~Application() {
|
||||||
|
@ -651,20 +652,11 @@ void Application::paintGL() {
|
||||||
}
|
}
|
||||||
|
|
||||||
} else if (_myCamera.getMode() == CAMERA_MODE_MIRROR) {
|
} else if (_myCamera.getMode() == CAMERA_MODE_MIRROR) {
|
||||||
//Only behave like a true mirror when in the OR
|
_myCamera.setRotation(_myAvatar->getWorldAlignedOrientation() * glm::quat(glm::vec3(0.0f, PI + _rotateMirror, 0.0f)));
|
||||||
if (OculusManager::isConnected()) {
|
_myCamera.setPosition(_myAvatar->getDefaultEyePosition() +
|
||||||
_myCamera.setRotation(_myAvatar->getWorldAlignedOrientation() * glm::quat(glm::vec3(0.0f, PI + _rotateMirror, 0.0f)));
|
glm::vec3(0, _raiseMirror * _myAvatar->getScale(), 0) +
|
||||||
_myCamera.setPosition(_myAvatar->getHead()->getEyePosition() +
|
(_myAvatar->getOrientation() * glm::quat(glm::vec3(0.0f, _rotateMirror, 0.0f))) *
|
||||||
glm::vec3(0, _raiseMirror * _myAvatar->getScale(), 0) +
|
glm::vec3(0.0f, 0.0f, -1.0f) * MIRROR_FULLSCREEN_DISTANCE * _scaleMirror);
|
||||||
(_myAvatar->getOrientation() * glm::quat(glm::vec3(0.0f, _rotateMirror, 0.0f))) *
|
|
||||||
glm::vec3(0.0f, 0.0f, -1.0f) * MIRROR_FULLSCREEN_DISTANCE * _scaleMirror);
|
|
||||||
} else {
|
|
||||||
_myCamera.setRotation(_myAvatar->getWorldAlignedOrientation() * glm::quat(glm::vec3(0.0f, PI + _rotateMirror, 0.0f)));
|
|
||||||
_myCamera.setPosition(_myAvatar->getHead()->getEyePosition() +
|
|
||||||
glm::vec3(0, _raiseMirror * _myAvatar->getScale(), 0) +
|
|
||||||
(_myAvatar->getOrientation() * glm::quat(glm::vec3(0.0f, _rotateMirror, 0.0f))) *
|
|
||||||
glm::vec3(0.0f, 0.0f, -1.0f) * MIRROR_FULLSCREEN_DISTANCE * _scaleMirror);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update camera position
|
// Update camera position
|
||||||
|
@ -851,7 +843,7 @@ bool Application::event(QEvent* event) {
|
||||||
QFileOpenEvent* fileEvent = static_cast<QFileOpenEvent*>(event);
|
QFileOpenEvent* fileEvent = static_cast<QFileOpenEvent*>(event);
|
||||||
|
|
||||||
if (!fileEvent->url().isEmpty()) {
|
if (!fileEvent->url().isEmpty()) {
|
||||||
AddressManager::getInstance().handleLookupString(fileEvent->url().toLocalFile());
|
AddressManager::getInstance().handleLookupString(fileEvent->url().toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
|
@ -1569,6 +1561,10 @@ void Application::checkBandwidthMeterClick() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void Application::setFullscreen(bool fullscreen) {
|
void Application::setFullscreen(bool fullscreen) {
|
||||||
|
if (Menu::getInstance()->isOptionChecked(MenuOption::Fullscreen) != fullscreen) {
|
||||||
|
Menu::getInstance()->getActionForOption(MenuOption::Fullscreen)->setChecked(fullscreen);
|
||||||
|
}
|
||||||
|
|
||||||
if (Menu::getInstance()->isOptionChecked(MenuOption::EnableVRMode)) {
|
if (Menu::getInstance()->isOptionChecked(MenuOption::EnableVRMode)) {
|
||||||
if (fullscreen) {
|
if (fullscreen) {
|
||||||
// Menu show() after hide() doesn't work with Rift VR display so set height instead.
|
// Menu show() after hide() doesn't work with Rift VR display so set height instead.
|
||||||
|
@ -1579,6 +1575,7 @@ void Application::setFullscreen(bool fullscreen) {
|
||||||
}
|
}
|
||||||
_window->setWindowState(fullscreen ? (_window->windowState() | Qt::WindowFullScreen) :
|
_window->setWindowState(fullscreen ? (_window->windowState() | Qt::WindowFullScreen) :
|
||||||
(_window->windowState() & ~Qt::WindowFullScreen));
|
(_window->windowState() & ~Qt::WindowFullScreen));
|
||||||
|
_window->show();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Application::setEnable3DTVMode(bool enable3DTVMode) {
|
void Application::setEnable3DTVMode(bool enable3DTVMode) {
|
||||||
|
@ -1586,6 +1583,10 @@ void Application::setEnable3DTVMode(bool enable3DTVMode) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void Application::setEnableVRMode(bool enableVRMode) {
|
void Application::setEnableVRMode(bool enableVRMode) {
|
||||||
|
if (Menu::getInstance()->isOptionChecked(MenuOption::EnableVRMode) != enableVRMode) {
|
||||||
|
Menu::getInstance()->getActionForOption(MenuOption::EnableVRMode)->setChecked(enableVRMode);
|
||||||
|
}
|
||||||
|
|
||||||
if (enableVRMode) {
|
if (enableVRMode) {
|
||||||
if (!OculusManager::isConnected()) {
|
if (!OculusManager::isConnected()) {
|
||||||
// attempt to reconnect the Oculus manager - it's possible this was a workaround
|
// attempt to reconnect the Oculus manager - it's possible this was a workaround
|
||||||
|
@ -1596,6 +1597,11 @@ void Application::setEnableVRMode(bool enableVRMode) {
|
||||||
OculusManager::recalibrate();
|
OculusManager::recalibrate();
|
||||||
} else {
|
} else {
|
||||||
OculusManager::abandonCalibration();
|
OculusManager::abandonCalibration();
|
||||||
|
|
||||||
|
_mirrorCamera.setHmdPosition(glm::vec3());
|
||||||
|
_mirrorCamera.setHmdRotation(glm::quat());
|
||||||
|
_myCamera.setHmdPosition(glm::vec3());
|
||||||
|
_myCamera.setHmdRotation(glm::quat());
|
||||||
}
|
}
|
||||||
|
|
||||||
resizeGL(_glWidget->getDeviceWidth(), _glWidget->getDeviceHeight());
|
resizeGL(_glWidget->getDeviceWidth(), _glWidget->getDeviceHeight());
|
||||||
|
@ -3509,7 +3515,6 @@ void Application::deleteVoxelAt(const VoxelDetail& voxel) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void Application::resetSensors() {
|
void Application::resetSensors() {
|
||||||
_mouseX = _glWidget->width() / 2;
|
_mouseX = _glWidget->width() / 2;
|
||||||
_mouseY = _glWidget->height() / 2;
|
_mouseY = _glWidget->height() / 2;
|
||||||
|
@ -3523,7 +3528,11 @@ void Application::resetSensors() {
|
||||||
_prioVR.reset();
|
_prioVR.reset();
|
||||||
//_leapmotion.reset();
|
//_leapmotion.reset();
|
||||||
|
|
||||||
QCursor::setPos(_mouseX, _mouseY);
|
QScreen* currentScreen = _window->windowHandle()->screen();
|
||||||
|
QWindow* mainWindow = _window->windowHandle();
|
||||||
|
QPoint windowCenter = mainWindow->geometry().center();
|
||||||
|
QCursor::setPos(currentScreen, windowCenter);
|
||||||
|
|
||||||
_myAvatar->reset();
|
_myAvatar->reset();
|
||||||
|
|
||||||
QMetaObject::invokeMethod(&_audio, "reset", Qt::QueuedConnection);
|
QMetaObject::invokeMethod(&_audio, "reset", Qt::QueuedConnection);
|
||||||
|
@ -4008,26 +4017,23 @@ ScriptEngine* Application::loadScript(const QString& scriptFilename, bool isUser
|
||||||
return _scriptEnginesHash[scriptURLString];
|
return _scriptEnginesHash[scriptURLString];
|
||||||
}
|
}
|
||||||
|
|
||||||
ScriptEngine* scriptEngine;
|
ScriptEngine* scriptEngine = new ScriptEngine(NO_SCRIPT, "", &_controllerScriptingInterface);
|
||||||
if (scriptFilename.isNull()) {
|
|
||||||
scriptEngine = new ScriptEngine(NO_SCRIPT, "", &_controllerScriptingInterface);
|
|
||||||
} else {
|
|
||||||
// start the script on a new thread...
|
|
||||||
scriptEngine = new ScriptEngine(scriptUrl, &_controllerScriptingInterface);
|
|
||||||
|
|
||||||
if (!scriptEngine->hasScript()) {
|
|
||||||
qDebug() << "Application::loadScript(), script failed to load...";
|
|
||||||
QMessageBox::warning(getWindow(), "Error Loading Script", scriptURLString + " failed to load.");
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
_scriptEnginesHash.insertMulti(scriptURLString, scriptEngine);
|
|
||||||
_runningScriptsWidget->setRunningScripts(getRunningScripts());
|
|
||||||
UserActivityLogger::getInstance().loadedScript(scriptURLString);
|
|
||||||
}
|
|
||||||
scriptEngine->setUserLoaded(isUserLoaded);
|
scriptEngine->setUserLoaded(isUserLoaded);
|
||||||
|
|
||||||
registerScriptEngineWithApplicationServices(scriptEngine);
|
if (scriptFilename.isNull()) {
|
||||||
|
// this had better be the script editor (we should de-couple so somebody who thinks they are loading a script
|
||||||
|
// doesn't just get an empty script engine)
|
||||||
|
|
||||||
|
// we can complete setup now since there isn't a script we have to load
|
||||||
|
registerScriptEngineWithApplicationServices(scriptEngine);
|
||||||
|
} else {
|
||||||
|
// connect to the appropriate signals of this script engine
|
||||||
|
connect(scriptEngine, &ScriptEngine::scriptLoaded, this, &Application::handleScriptEngineLoaded);
|
||||||
|
connect(scriptEngine, &ScriptEngine::errorLoadingScript, this, &Application::handleScriptLoadError);
|
||||||
|
|
||||||
|
// get the script engine object to load the script at the designated script URL
|
||||||
|
scriptEngine->loadURL(scriptUrl);
|
||||||
|
}
|
||||||
|
|
||||||
// restore the main window's active state
|
// restore the main window's active state
|
||||||
if (activateMainWindow && !loadScriptFromEditor) {
|
if (activateMainWindow && !loadScriptFromEditor) {
|
||||||
|
@ -4038,6 +4044,22 @@ ScriptEngine* Application::loadScript(const QString& scriptFilename, bool isUser
|
||||||
return scriptEngine;
|
return scriptEngine;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Application::handleScriptEngineLoaded(const QUrl& scriptURL) {
|
||||||
|
ScriptEngine* scriptEngine = qobject_cast<ScriptEngine*>(sender());
|
||||||
|
|
||||||
|
_scriptEnginesHash.insertMulti(scriptURL.toString(), scriptEngine);
|
||||||
|
_runningScriptsWidget->setRunningScripts(getRunningScripts());
|
||||||
|
UserActivityLogger::getInstance().loadedScript(scriptURL.toString());
|
||||||
|
|
||||||
|
// register our application services and set it off on its own thread
|
||||||
|
registerScriptEngineWithApplicationServices(scriptEngine);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Application::handleScriptLoadError(const QUrl& scriptURL) {
|
||||||
|
qDebug() << "Application::loadScript(), script failed to load...";
|
||||||
|
QMessageBox::warning(getWindow(), "Error Loading Script", scriptURL.toString() + " failed to load.");
|
||||||
|
}
|
||||||
|
|
||||||
void Application::scriptFinished(const QString& scriptName) {
|
void Application::scriptFinished(const QString& scriptName) {
|
||||||
const QString& scriptURLString = QUrl(scriptName).toString();
|
const QString& scriptURLString = QUrl(scriptName).toString();
|
||||||
QHash<QString, ScriptEngine*>::iterator it = _scriptEnginesHash.find(scriptURLString);
|
QHash<QString, ScriptEngine*>::iterator it = _scriptEnginesHash.find(scriptURLString);
|
||||||
|
|
|
@ -71,6 +71,7 @@
|
||||||
#include "scripting/ControllerScriptingInterface.h"
|
#include "scripting/ControllerScriptingInterface.h"
|
||||||
#include "ui/BandwidthDialog.h"
|
#include "ui/BandwidthDialog.h"
|
||||||
#include "ui/BandwidthMeter.h"
|
#include "ui/BandwidthMeter.h"
|
||||||
|
#include "ui/HMDToolsDialog.h"
|
||||||
#include "ui/ModelsBrowser.h"
|
#include "ui/ModelsBrowser.h"
|
||||||
#include "ui/NodeBounds.h"
|
#include "ui/NodeBounds.h"
|
||||||
#include "ui/OctreeStatsDialog.h"
|
#include "ui/OctreeStatsDialog.h"
|
||||||
|
@ -392,9 +393,13 @@ private slots:
|
||||||
void timer();
|
void timer();
|
||||||
void idle();
|
void idle();
|
||||||
void aboutToQuit();
|
void aboutToQuit();
|
||||||
|
|
||||||
|
void handleScriptEngineLoaded(const QUrl& scriptURL);
|
||||||
|
void handleScriptLoadError(const QUrl& scriptURL);
|
||||||
|
|
||||||
void connectedToDomain(const QString& hostname);
|
void connectedToDomain(const QString& hostname);
|
||||||
|
|
||||||
|
friend class HMDToolsDialog;
|
||||||
void setFullscreen(bool fullscreen);
|
void setFullscreen(bool fullscreen);
|
||||||
void setEnable3DTVMode(bool enable3DTVMode);
|
void setEnable3DTVMode(bool enable3DTVMode);
|
||||||
void setEnableVRMode(bool enableVRMode);
|
void setEnableVRMode(bool enableVRMode);
|
||||||
|
|
|
@ -97,6 +97,7 @@ Menu::Menu() :
|
||||||
_jsConsole(NULL),
|
_jsConsole(NULL),
|
||||||
_octreeStatsDialog(NULL),
|
_octreeStatsDialog(NULL),
|
||||||
_lodToolsDialog(NULL),
|
_lodToolsDialog(NULL),
|
||||||
|
_hmdToolsDialog(NULL),
|
||||||
_newLocationDialog(NULL),
|
_newLocationDialog(NULL),
|
||||||
_userLocationsDialog(NULL),
|
_userLocationsDialog(NULL),
|
||||||
#if defined(Q_OS_MAC) || defined(Q_OS_WIN)
|
#if defined(Q_OS_MAC) || defined(Q_OS_WIN)
|
||||||
|
@ -334,6 +335,12 @@ Menu::Menu() :
|
||||||
appInstance, SLOT(cameraMenuChanged()));
|
appInstance, SLOT(cameraMenuChanged()));
|
||||||
addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::UserInterface, Qt::Key_Slash, true);
|
addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::UserInterface, Qt::Key_Slash, true);
|
||||||
|
|
||||||
|
addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::HMDTools, Qt::META | Qt::Key_H,
|
||||||
|
false,
|
||||||
|
this,
|
||||||
|
SLOT(hmdTools(bool)));
|
||||||
|
|
||||||
|
|
||||||
addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::EnableVRMode, 0,
|
addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::EnableVRMode, 0,
|
||||||
false,
|
false,
|
||||||
appInstance,
|
appInstance,
|
||||||
|
@ -438,23 +445,7 @@ Menu::Menu() :
|
||||||
addCheckableActionToQMenuAndActionHash(avatarDebugMenu, MenuOption::RenderBoundingCollisionShapes);
|
addCheckableActionToQMenuAndActionHash(avatarDebugMenu, MenuOption::RenderBoundingCollisionShapes);
|
||||||
addCheckableActionToQMenuAndActionHash(avatarDebugMenu, MenuOption::RenderLookAtVectors, 0, false);
|
addCheckableActionToQMenuAndActionHash(avatarDebugMenu, MenuOption::RenderLookAtVectors, 0, false);
|
||||||
addCheckableActionToQMenuAndActionHash(avatarDebugMenu, MenuOption::RenderFocusIndicator, 0, false);
|
addCheckableActionToQMenuAndActionHash(avatarDebugMenu, MenuOption::RenderFocusIndicator, 0, false);
|
||||||
|
|
||||||
QMenu* entitiesDebugMenu = developerMenu->addMenu("Entities");
|
|
||||||
addCheckableActionToQMenuAndActionHash(entitiesDebugMenu, MenuOption::DisplayModelBounds, 0, false);
|
|
||||||
addCheckableActionToQMenuAndActionHash(entitiesDebugMenu, MenuOption::DisplayModelElementProxy, 0, false);
|
|
||||||
addCheckableActionToQMenuAndActionHash(entitiesDebugMenu, MenuOption::DisplayModelElementChildProxies, 0, false);
|
|
||||||
addCheckableActionToQMenuAndActionHash(entitiesDebugMenu, MenuOption::DisableLightEntities, 0, false);
|
|
||||||
|
|
||||||
addCheckableActionToQMenuAndActionHash(entitiesDebugMenu, MenuOption::DontReduceMaterialSwitches, 0, false);
|
|
||||||
addCheckableActionToQMenuAndActionHash(entitiesDebugMenu, MenuOption::DontRenderEntitiesAsScene, 0, false);
|
|
||||||
|
|
||||||
QMenu* entityCullingMenu = entitiesDebugMenu->addMenu("Culling");
|
|
||||||
addCheckableActionToQMenuAndActionHash(entityCullingMenu, MenuOption::DontCullOutOfViewMeshParts, 0, false);
|
|
||||||
addCheckableActionToQMenuAndActionHash(entityCullingMenu, MenuOption::DontCullTooSmallMeshParts, 0, false);
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
QMenu* voxelOptionsMenu = developerMenu->addMenu("Voxels");
|
QMenu* voxelOptionsMenu = developerMenu->addMenu("Voxels");
|
||||||
addCheckableActionToQMenuAndActionHash(voxelOptionsMenu, MenuOption::VoxelTextures);
|
addCheckableActionToQMenuAndActionHash(voxelOptionsMenu, MenuOption::VoxelTextures);
|
||||||
addCheckableActionToQMenuAndActionHash(voxelOptionsMenu, MenuOption::AmbientOcclusion);
|
addCheckableActionToQMenuAndActionHash(voxelOptionsMenu, MenuOption::AmbientOcclusion);
|
||||||
|
@ -652,6 +643,10 @@ Menu::Menu() :
|
||||||
Menu::~Menu() {
|
Menu::~Menu() {
|
||||||
bandwidthDetailsClosed();
|
bandwidthDetailsClosed();
|
||||||
octreeStatsDetailsClosed();
|
octreeStatsDetailsClosed();
|
||||||
|
if (_hmdToolsDialog) {
|
||||||
|
delete _hmdToolsDialog;
|
||||||
|
_hmdToolsDialog = NULL;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Menu::loadSettings(QSettings* settings) {
|
void Menu::loadSettings(QSettings* settings) {
|
||||||
|
@ -1594,6 +1589,25 @@ void Menu::lodToolsClosed() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Menu::hmdTools(bool showTools) {
|
||||||
|
if (showTools) {
|
||||||
|
if (!_hmdToolsDialog) {
|
||||||
|
_hmdToolsDialog = new HMDToolsDialog(Application::getInstance()->getGLWidget());
|
||||||
|
connect(_hmdToolsDialog, SIGNAL(closed()), SLOT(hmdToolsClosed()));
|
||||||
|
}
|
||||||
|
_hmdToolsDialog->show();
|
||||||
|
_hmdToolsDialog->raise();
|
||||||
|
} else {
|
||||||
|
hmdToolsClosed();
|
||||||
|
}
|
||||||
|
Application::getInstance()->getWindow()->activateWindow();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Menu::hmdToolsClosed() {
|
||||||
|
Menu::getInstance()->getActionForOption(MenuOption::HMDTools)->setChecked(false);
|
||||||
|
_hmdToolsDialog->hide();
|
||||||
|
}
|
||||||
|
|
||||||
void Menu::cycleFrustumRenderMode() {
|
void Menu::cycleFrustumRenderMode() {
|
||||||
_frustumDrawMode = (FrustumDrawMode)((_frustumDrawMode + 1) % FRUSTUM_DRAW_MODE_COUNT);
|
_frustumDrawMode = (FrustumDrawMode)((_frustumDrawMode + 1) % FRUSTUM_DRAW_MODE_COUNT);
|
||||||
updateFrustumRenderModeAction();
|
updateFrustumRenderModeAction();
|
||||||
|
|
|
@ -76,6 +76,7 @@ class QSettings;
|
||||||
class AnimationsDialog;
|
class AnimationsDialog;
|
||||||
class AttachmentsDialog;
|
class AttachmentsDialog;
|
||||||
class BandwidthDialog;
|
class BandwidthDialog;
|
||||||
|
class HMDToolsDialog;
|
||||||
class LodToolsDialog;
|
class LodToolsDialog;
|
||||||
class MetavoxelEditor;
|
class MetavoxelEditor;
|
||||||
class MetavoxelNetworkSimulator;
|
class MetavoxelNetworkSimulator;
|
||||||
|
@ -120,6 +121,7 @@ public:
|
||||||
ViewFrustumOffset getViewFrustumOffset() const { return _viewFrustumOffset; }
|
ViewFrustumOffset getViewFrustumOffset() const { return _viewFrustumOffset; }
|
||||||
OctreeStatsDialog* getOctreeStatsDialog() const { return _octreeStatsDialog; }
|
OctreeStatsDialog* getOctreeStatsDialog() const { return _octreeStatsDialog; }
|
||||||
LodToolsDialog* getLodToolsDialog() const { return _lodToolsDialog; }
|
LodToolsDialog* getLodToolsDialog() const { return _lodToolsDialog; }
|
||||||
|
HMDToolsDialog* getHMDToolsDialog() const { return _hmdToolsDialog; }
|
||||||
int getMaxVoxels() const { return _maxVoxels; }
|
int getMaxVoxels() const { return _maxVoxels; }
|
||||||
QAction* getUseVoxelShader() const { return _useVoxelShader; }
|
QAction* getUseVoxelShader() const { return _useVoxelShader; }
|
||||||
|
|
||||||
|
@ -183,6 +185,7 @@ public slots:
|
||||||
void bandwidthDetails();
|
void bandwidthDetails();
|
||||||
void octreeStatsDetails();
|
void octreeStatsDetails();
|
||||||
void lodTools();
|
void lodTools();
|
||||||
|
void hmdTools(bool showTools);
|
||||||
void loadSettings(QSettings* settings = NULL);
|
void loadSettings(QSettings* settings = NULL);
|
||||||
void saveSettings(QSettings* settings = NULL);
|
void saveSettings(QSettings* settings = NULL);
|
||||||
void importSettings();
|
void importSettings();
|
||||||
|
@ -217,6 +220,7 @@ private slots:
|
||||||
void bandwidthDetailsClosed();
|
void bandwidthDetailsClosed();
|
||||||
void octreeStatsDetailsClosed();
|
void octreeStatsDetailsClosed();
|
||||||
void lodToolsClosed();
|
void lodToolsClosed();
|
||||||
|
void hmdToolsClosed();
|
||||||
void cycleFrustumRenderMode();
|
void cycleFrustumRenderMode();
|
||||||
void runTests();
|
void runTests();
|
||||||
void showMetavoxelEditor();
|
void showMetavoxelEditor();
|
||||||
|
@ -284,6 +288,7 @@ private:
|
||||||
QDialog* _jsConsole;
|
QDialog* _jsConsole;
|
||||||
OctreeStatsDialog* _octreeStatsDialog;
|
OctreeStatsDialog* _octreeStatsDialog;
|
||||||
LodToolsDialog* _lodToolsDialog;
|
LodToolsDialog* _lodToolsDialog;
|
||||||
|
HMDToolsDialog* _hmdToolsDialog;
|
||||||
QPointer<DataWebDialog> _newLocationDialog;
|
QPointer<DataWebDialog> _newLocationDialog;
|
||||||
QPointer<DataWebDialog> _userLocationsDialog;
|
QPointer<DataWebDialog> _userLocationsDialog;
|
||||||
#if defined(Q_OS_MAC) || defined(Q_OS_WIN)
|
#if defined(Q_OS_MAC) || defined(Q_OS_WIN)
|
||||||
|
@ -400,6 +405,7 @@ namespace MenuOption {
|
||||||
const QString NamesAboveHeads = "Names Above Heads";
|
const QString NamesAboveHeads = "Names Above Heads";
|
||||||
const QString GoToUser = "Go To User";
|
const QString GoToUser = "Go To User";
|
||||||
const QString HeadMouse = "Head Mouse";
|
const QString HeadMouse = "Head Mouse";
|
||||||
|
const QString HMDTools = "HMD Tools";
|
||||||
const QString IncreaseAvatarSize = "Increase Avatar Size";
|
const QString IncreaseAvatarSize = "Increase Avatar Size";
|
||||||
const QString IncreaseVoxelSize = "Increase Voxel Size";
|
const QString IncreaseVoxelSize = "Increase Voxel Size";
|
||||||
const QString KeyboardMotorControl = "Enable Keyboard Motor Control";
|
const QString KeyboardMotorControl = "Enable Keyboard Motor Control";
|
||||||
|
|
|
@ -273,7 +273,12 @@ void Head::setCorrectedLookAtPosition(glm::vec3 correctedLookAtPosition) {
|
||||||
_correctedLookAtPosition = correctedLookAtPosition;
|
_correctedLookAtPosition = correctedLookAtPosition;
|
||||||
}
|
}
|
||||||
|
|
||||||
glm::quat Head::getCameraOrientation () const {
|
glm::quat Head::getCameraOrientation() const {
|
||||||
|
// NOTE: Head::getCameraOrientation() is not used for orienting the camera "view" while in Oculus mode, so
|
||||||
|
// you may wonder why this code is here. This method will be called while in Oculus mode to determine how
|
||||||
|
// to change the driving direction while in Oculus mode. It is used to support driving toward where you're
|
||||||
|
// head is looking. Note that in oculus mode, your actual camera view and where your head is looking is not
|
||||||
|
// always the same.
|
||||||
if (OculusManager::isConnected()) {
|
if (OculusManager::isConnected()) {
|
||||||
return getOrientation();
|
return getOrientation();
|
||||||
}
|
}
|
||||||
|
|
|
@ -367,6 +367,15 @@ void MyAvatar::updateFromTrackers(float deltaTime) {
|
||||||
const float TORSO_LENGTH = 0.5f;
|
const float TORSO_LENGTH = 0.5f;
|
||||||
glm::vec3 relativePosition = estimatedPosition - glm::vec3(0.0f, -TORSO_LENGTH, 0.0f);
|
glm::vec3 relativePosition = estimatedPosition - glm::vec3(0.0f, -TORSO_LENGTH, 0.0f);
|
||||||
const float MAX_LEAN = 45.0f;
|
const float MAX_LEAN = 45.0f;
|
||||||
|
|
||||||
|
// Invert left/right lean when in mirror mode
|
||||||
|
// NOTE: this is kinda a hack, it's the same hack we use to make the head tilt. But it's not really a mirror
|
||||||
|
// it just makes you feel like you're looking in a mirror because the body movements of the avatar appear to
|
||||||
|
// match your body movements.
|
||||||
|
if (OculusManager::isConnected() && Application::getInstance()->getCamera()->getMode() == CAMERA_MODE_MIRROR) {
|
||||||
|
relativePosition.x = -relativePosition.x;
|
||||||
|
}
|
||||||
|
|
||||||
head->setLeanSideways(glm::clamp(glm::degrees(atanf(relativePosition.x * _leanScale / TORSO_LENGTH)),
|
head->setLeanSideways(glm::clamp(glm::degrees(atanf(relativePosition.x * _leanScale / TORSO_LENGTH)),
|
||||||
-MAX_LEAN, MAX_LEAN));
|
-MAX_LEAN, MAX_LEAN));
|
||||||
head->setLeanForward(glm::clamp(glm::degrees(atanf(relativePosition.z * _leanScale / TORSO_LENGTH)),
|
head->setLeanForward(glm::clamp(glm::degrees(atanf(relativePosition.z * _leanScale / TORSO_LENGTH)),
|
||||||
|
|
|
@ -135,16 +135,20 @@ glm::vec3 vec3FromLeapVector(const Leap::Vector& vec) {
|
||||||
|
|
||||||
void Leapmotion::update() {
|
void Leapmotion::update() {
|
||||||
#ifdef HAVE_LEAPMOTION
|
#ifdef HAVE_LEAPMOTION
|
||||||
// Check that the controller is actually active
|
bool wasActive = _active;
|
||||||
_active = _controller.isConnected();
|
_active = _controller.isConnected();
|
||||||
if (!_active) {
|
|
||||||
return;
|
if (_active || wasActive) {
|
||||||
|
// Go through all the joints and increment their counter since last update.
|
||||||
|
// Increment all counters once after controller first becomes inactive so that each joint reports itself as inactive.
|
||||||
|
// TODO C++11 for (auto jointIt = _jointsArray.begin(); jointIt != _jointsArray.end(); jointIt++) {
|
||||||
|
for (JointTracker::Vector::iterator jointIt = _jointsArray.begin(); jointIt != _jointsArray.end(); jointIt++) {
|
||||||
|
(*jointIt).tickNewFrame();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// go through all the joints and increment their counter since last update
|
if (!_active) {
|
||||||
// TODO C++11 for (auto jointIt = _jointsArray.begin(); jointIt != _jointsArray.end(); jointIt++) {
|
return;
|
||||||
for (JointTracker::Vector::iterator jointIt = _jointsArray.begin(); jointIt != _jointsArray.end(); jointIt++) {
|
|
||||||
(*jointIt).tickNewFrame();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get the most recent frame and report some basic information
|
// Get the most recent frame and report some basic information
|
||||||
|
|
|
@ -119,14 +119,14 @@ MotionTracker::JointTracker::JointTracker() :
|
||||||
_absFrame(),
|
_absFrame(),
|
||||||
_semantic(""),
|
_semantic(""),
|
||||||
_parent(INVALID_PARENT),
|
_parent(INVALID_PARENT),
|
||||||
_lastUpdate(0)
|
_lastUpdate(1) // Joint inactive
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
MotionTracker::JointTracker::JointTracker(const Semantic& semantic, Index parent) :
|
MotionTracker::JointTracker::JointTracker(const Semantic& semantic, Index parent) :
|
||||||
_semantic(semantic),
|
_semantic(semantic),
|
||||||
_parent(parent),
|
_parent(parent),
|
||||||
_lastUpdate(0)
|
_lastUpdate(1) // Joint inactive
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -14,9 +14,14 @@
|
||||||
|
|
||||||
#include "OculusManager.h"
|
#include "OculusManager.h"
|
||||||
|
|
||||||
|
#include <QDesktopWidget>
|
||||||
|
#include <QGuiApplication>
|
||||||
#include <QOpenGLFramebufferObject>
|
#include <QOpenGLFramebufferObject>
|
||||||
|
#include <QScreen>
|
||||||
|
|
||||||
#include <glm/glm.hpp>
|
#include <glm/glm.hpp>
|
||||||
|
|
||||||
|
#include <SharedUtil.h>
|
||||||
#include <UserActivityLogger.h>
|
#include <UserActivityLogger.h>
|
||||||
|
|
||||||
#include "Application.h"
|
#include "Application.h"
|
||||||
|
@ -75,9 +80,7 @@ glm::vec3 OculusManager::_rightEyePosition = glm::vec3();
|
||||||
void OculusManager::connect() {
|
void OculusManager::connect() {
|
||||||
#ifdef HAVE_LIBOVR
|
#ifdef HAVE_LIBOVR
|
||||||
_calibrationState = UNCALIBRATED;
|
_calibrationState = UNCALIBRATED;
|
||||||
|
|
||||||
qDebug() << "Oculus SDK" << OVR_VERSION_STRING;
|
qDebug() << "Oculus SDK" << OVR_VERSION_STRING;
|
||||||
|
|
||||||
ovr_Initialize();
|
ovr_Initialize();
|
||||||
|
|
||||||
_ovrHmd = ovrHmd_Create(0);
|
_ovrHmd = ovrHmd_Create(0);
|
||||||
|
@ -86,6 +89,7 @@ void OculusManager::connect() {
|
||||||
UserActivityLogger::getInstance().connectedDevice("hmd", "oculus");
|
UserActivityLogger::getInstance().connectedDevice("hmd", "oculus");
|
||||||
}
|
}
|
||||||
_isConnected = true;
|
_isConnected = true;
|
||||||
|
|
||||||
#if defined(__APPLE__) || defined(_WIN32)
|
#if defined(__APPLE__) || defined(_WIN32)
|
||||||
_eyeFov[0] = _ovrHmd->DefaultEyeFov[0];
|
_eyeFov[0] = _ovrHmd->DefaultEyeFov[0];
|
||||||
_eyeFov[1] = _ovrHmd->DefaultEyeFov[1];
|
_eyeFov[1] = _ovrHmd->DefaultEyeFov[1];
|
||||||
|
@ -715,3 +719,59 @@ void OculusManager::overrideOffAxisFrustum(float& left, float& right, float& bot
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int OculusManager::getHMDScreen() {
|
||||||
|
int hmdScreenIndex = -1; // unknown
|
||||||
|
#ifdef HAVE_LIBOVR
|
||||||
|
// TODO: it might be smarter to handle multiple HMDs connected in this case. but for now,
|
||||||
|
// we will simply assume the initialization code that set up _ovrHmd picked the best hmd
|
||||||
|
|
||||||
|
if (_ovrHmd) {
|
||||||
|
QString productNameFromOVR = _ovrHmd->ProductName;
|
||||||
|
|
||||||
|
int hmdWidth = _ovrHmd->Resolution.w;
|
||||||
|
int hmdHeight = _ovrHmd->Resolution.h;
|
||||||
|
int hmdAtX = _ovrHmd->WindowsPos.x;
|
||||||
|
int hmdAtY = _ovrHmd->WindowsPos.y;
|
||||||
|
|
||||||
|
// we will score the likelihood that each screen is a match based on the following
|
||||||
|
// rubrik of potential matching features
|
||||||
|
const int EXACT_NAME_MATCH = 100;
|
||||||
|
const int SIMILAR_NAMES = 10;
|
||||||
|
const int EXACT_LOCATION_MATCH = 50;
|
||||||
|
const int EXACT_RESOLUTION_MATCH = 25;
|
||||||
|
|
||||||
|
int bestMatchScore = 0;
|
||||||
|
|
||||||
|
// look at the display list and see if we can find the best match
|
||||||
|
QDesktopWidget* desktop = QApplication::desktop();
|
||||||
|
int screenNumber = 0;
|
||||||
|
foreach (QScreen* screen, QGuiApplication::screens()) {
|
||||||
|
QString screenName = screen->name();
|
||||||
|
QRect screenRect = desktop->screenGeometry(screenNumber);
|
||||||
|
|
||||||
|
int screenScore = 0;
|
||||||
|
if (screenName == productNameFromOVR) {
|
||||||
|
screenScore += EXACT_NAME_MATCH;
|
||||||
|
}
|
||||||
|
if (similarStrings(screenName, productNameFromOVR)) {
|
||||||
|
screenScore += SIMILAR_NAMES;
|
||||||
|
}
|
||||||
|
if (hmdWidth == screenRect.width() && hmdHeight == screenRect.height()) {
|
||||||
|
screenScore += EXACT_RESOLUTION_MATCH;
|
||||||
|
}
|
||||||
|
if (hmdAtX == screenRect.x() && hmdAtY == screenRect.y()) {
|
||||||
|
screenScore += EXACT_LOCATION_MATCH;
|
||||||
|
}
|
||||||
|
if (screenScore > bestMatchScore) {
|
||||||
|
bestMatchScore = screenScore;
|
||||||
|
hmdScreenIndex = screenNumber;
|
||||||
|
}
|
||||||
|
|
||||||
|
screenNumber++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
return hmdScreenIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -52,11 +52,15 @@ public:
|
||||||
static glm::vec3 getLeftEyePosition() { return _leftEyePosition; }
|
static glm::vec3 getLeftEyePosition() { return _leftEyePosition; }
|
||||||
static glm::vec3 getRightEyePosition() { return _rightEyePosition; }
|
static glm::vec3 getRightEyePosition() { return _rightEyePosition; }
|
||||||
|
|
||||||
|
static int getHMDScreen();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
#ifdef HAVE_LIBOVR
|
#ifdef HAVE_LIBOVR
|
||||||
static void generateDistortionMesh();
|
static void generateDistortionMesh();
|
||||||
static void renderDistortionMesh(ovrPosef eyeRenderPose[ovrEye_Count]);
|
static void renderDistortionMesh(ovrPosef eyeRenderPose[ovrEye_Count]);
|
||||||
|
|
||||||
|
static bool similarNames(const QString& nameA,const QString& nameB);
|
||||||
|
|
||||||
struct DistortionVertex {
|
struct DistortionVertex {
|
||||||
glm::vec2 pos;
|
glm::vec2 pos;
|
||||||
glm::vec2 texR;
|
glm::vec2 texR;
|
||||||
|
|
|
@ -477,7 +477,8 @@ void SixenseManager::emulateMouse(PalmData* palm, int index) {
|
||||||
triggerButton = Qt::LeftButton;
|
triggerButton = Qt::LeftButton;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Menu::getInstance()->isOptionChecked(MenuOption::SixenseLasers)) {
|
if (Menu::getInstance()->isOptionChecked(MenuOption::SixenseLasers)
|
||||||
|
|| Menu::getInstance()->isOptionChecked(MenuOption::EnableVRMode)) {
|
||||||
pos = application->getApplicationOverlay().getPalmClickLocation(palm);
|
pos = application->getApplicationOverlay().getPalmClickLocation(palm);
|
||||||
} else {
|
} else {
|
||||||
// Get directon relative to avatar orientation
|
// Get directon relative to avatar orientation
|
||||||
|
|
|
@ -138,11 +138,9 @@ void AnimationHandle::simulate(float deltaTime) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: When moving the loop/frame calculations to AnimationLoop class, we changed this behavior
|
if (_animationLoop.getMaxFrameIndexHint() != animationGeometry.animationFrames.size()) {
|
||||||
// see AnimationLoop class for more details. Do we need to support clamping the endFrameIndex to
|
_animationLoop.setMaxFrameIndexHint(animationGeometry.animationFrames.size());
|
||||||
// the max number of frames in the geometry???
|
}
|
||||||
//
|
|
||||||
// float endFrameIndex = qMin(_lastFrame, animationGeometry.animationFrames.size() - (_loop ? 0.0f : 1.0f));
|
|
||||||
|
|
||||||
// blend between the closest two frames
|
// blend between the closest two frames
|
||||||
applyFrame(getFrameIndex());
|
applyFrame(getFrameIndex());
|
||||||
|
|
|
@ -829,10 +829,25 @@ void GeometryReader::run() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
QMetaObject::invokeMethod(geometry.data(), "setGeometry", Q_ARG(const FBXGeometry&,
|
std::string urlname = _url.path().toLower().toStdString();
|
||||||
|
FBXGeometry fbxgeo;
|
||||||
|
if (_url.path().toLower().endsWith(".svo")) {
|
||||||
|
fbxgeo = readSVO(_reply->readAll());
|
||||||
|
} else {
|
||||||
|
bool grabLightmaps = true;
|
||||||
|
float lightmapLevel = 1.0f;
|
||||||
|
// HACK: For monday 12/01/2014 we need to kill lighmaps loading in starchamber...
|
||||||
|
if (_url.path().toLower().endsWith("loungev4_11-18.fbx")) {
|
||||||
|
grabLightmaps = false;
|
||||||
|
} else if (_url.path().toLower().endsWith("apt8_reboot.fbx")) {
|
||||||
|
lightmapLevel = 4.0f;
|
||||||
|
}
|
||||||
|
fbxgeo = readFBX(_reply->readAll(), _mapping, grabLightmaps, lightmapLevel);
|
||||||
|
}
|
||||||
|
QMetaObject::invokeMethod(geometry.data(), "setGeometry", Q_ARG(const FBXGeometry&, fbxgeo));
|
||||||
|
|
||||||
|
|
||||||
_url.path().toLower().endsWith(".svo") ? readSVO(_reply->readAll()) : readFBX(_reply->readAll(), _mapping)));
|
// _url.path().toLower().endsWith(".svo") ? readSVO(_reply->readAll()) : readFBX(_reply->readAll(), _mapping)));
|
||||||
|
|
||||||
} catch (const QString& error) {
|
} catch (const QString& error) {
|
||||||
qDebug() << "Error reading " << _url << ": " << error;
|
qDebug() << "Error reading " << _url << ": " << error;
|
||||||
|
|
|
@ -2347,8 +2347,12 @@ int Model::renderMeshesFromList(QVector<int>& list, gpu::Batch& batch, RenderMod
|
||||||
diffuseMap = (_dilatedTextures[i][j] =
|
diffuseMap = (_dilatedTextures[i][j] =
|
||||||
static_cast<DilatableNetworkTexture*>(diffuseMap)->getDilatedTexture(_pupilDilation)).data();
|
static_cast<DilatableNetworkTexture*>(diffuseMap)->getDilatedTexture(_pupilDilation)).data();
|
||||||
}
|
}
|
||||||
GLBATCH(glBindTexture)(GL_TEXTURE_2D, !diffuseMap ?
|
static bool showDiffuse = true;
|
||||||
Application::getInstance()->getTextureCache()->getWhiteTextureID() : diffuseMap->getID());
|
if (showDiffuse && diffuseMap) {
|
||||||
|
GLBATCH(glBindTexture)(GL_TEXTURE_2D, diffuseMap->getID());
|
||||||
|
} else {
|
||||||
|
GLBATCH(glBindTexture)(GL_TEXTURE_2D, Application::getInstance()->getTextureCache()->getWhiteTextureID());
|
||||||
|
}
|
||||||
|
|
||||||
if (locations->texcoordMatrices >= 0) {
|
if (locations->texcoordMatrices >= 0) {
|
||||||
glm::mat4 texcoordTransform[2];
|
glm::mat4 texcoordTransform[2];
|
||||||
|
@ -2377,22 +2381,27 @@ int Model::renderMeshesFromList(QVector<int>& list, gpu::Batch& batch, RenderMod
|
||||||
GLBATCH(glActiveTexture)(GL_TEXTURE0);
|
GLBATCH(glActiveTexture)(GL_TEXTURE0);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (locations->emissiveTextureUnit >= 0) {
|
|
||||||
assert(locations->emissiveParams >= 0); // we should have the emissiveParams defined in the shader
|
|
||||||
GLBATCH(glUniform2f)(locations->emissiveParams, 0.1f, 4.0f);
|
|
||||||
|
|
||||||
GLBATCH(glActiveTexture)(GL_TEXTURE0 + locations->emissiveTextureUnit);
|
|
||||||
Texture* emissiveMap = networkPart.emissiveTexture.data();
|
|
||||||
GLBATCH(glBindTexture)(GL_TEXTURE_2D, !emissiveMap ?
|
|
||||||
Application::getInstance()->getTextureCache()->getWhiteTextureID() : emissiveMap->getID());
|
|
||||||
GLBATCH(glActiveTexture)(GL_TEXTURE0);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (args) {
|
if (args) {
|
||||||
args->_materialSwitches++;
|
args->_materialSwitches++;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// HACK: For unkwon reason (yet!) this code that should be assigned only if the material changes need to be called for every
|
||||||
|
// drawcall with an emissive, so let's do it for now.
|
||||||
|
if (locations->emissiveTextureUnit >= 0) {
|
||||||
|
// assert(locations->emissiveParams >= 0); // we should have the emissiveParams defined in the shader
|
||||||
|
float emissiveOffset = part.emissiveParams.x;
|
||||||
|
float emissiveScale = part.emissiveParams.y;
|
||||||
|
GLBATCH(glUniform2f)(locations->emissiveParams, emissiveOffset, emissiveScale);
|
||||||
|
|
||||||
|
GLBATCH(glActiveTexture)(GL_TEXTURE0 + locations->emissiveTextureUnit);
|
||||||
|
Texture* emissiveMap = networkPart.emissiveTexture.data();
|
||||||
|
GLBATCH(glBindTexture)(GL_TEXTURE_2D, !emissiveMap ?
|
||||||
|
Application::getInstance()->getTextureCache()->getWhiteTextureID() : emissiveMap->getID());
|
||||||
|
GLBATCH(glActiveTexture)(GL_TEXTURE0);
|
||||||
|
}
|
||||||
|
|
||||||
lastMaterialID = part.materialID;
|
lastMaterialID = part.materialID;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -984,7 +984,8 @@ void ApplicationOverlay::renderAudioMeter() {
|
||||||
const int AUDIO_METER_X = MIRROR_VIEW_LEFT_PADDING + MUTE_ICON_SIZE + AUDIO_METER_INSET + AUDIO_METER_GAP;
|
const int AUDIO_METER_X = MIRROR_VIEW_LEFT_PADDING + MUTE_ICON_SIZE + AUDIO_METER_INSET + AUDIO_METER_GAP;
|
||||||
|
|
||||||
int audioMeterY;
|
int audioMeterY;
|
||||||
bool boxed = Menu::getInstance()->isOptionChecked(MenuOption::Mirror) &&
|
bool smallMirrorVisible = Menu::getInstance()->isOptionChecked(MenuOption::Mirror) && !OculusManager::isConnected();
|
||||||
|
bool boxed = smallMirrorVisible &&
|
||||||
!Menu::getInstance()->isOptionChecked(MenuOption::FullscreenMirror);
|
!Menu::getInstance()->isOptionChecked(MenuOption::FullscreenMirror);
|
||||||
if (boxed) {
|
if (boxed) {
|
||||||
audioMeterY = MIRROR_VIEW_HEIGHT + AUDIO_METER_GAP + MUTE_ICON_PADDING;
|
audioMeterY = MIRROR_VIEW_HEIGHT + AUDIO_METER_GAP + MUTE_ICON_PADDING;
|
||||||
|
|
309
interface/src/ui/HMDToolsDialog.cpp
Normal file
309
interface/src/ui/HMDToolsDialog.cpp
Normal file
|
@ -0,0 +1,309 @@
|
||||||
|
//
|
||||||
|
// HMDToolsDialog.cpp
|
||||||
|
// interface/src/ui
|
||||||
|
//
|
||||||
|
// Created by Brad Hefta-Gaub on 7/19/13.
|
||||||
|
// Copyright 2013 High Fidelity, Inc.
|
||||||
|
//
|
||||||
|
// Distributed under the Apache License, Version 2.0.
|
||||||
|
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||||
|
//
|
||||||
|
|
||||||
|
#include <QFormLayout>
|
||||||
|
#include <QGuiApplication>
|
||||||
|
#include <QDialogButtonBox>
|
||||||
|
|
||||||
|
#include <QDesktopWidget>
|
||||||
|
#include <QPushButton>
|
||||||
|
#include <QString>
|
||||||
|
#include <QScreen>
|
||||||
|
#include <QWindow>
|
||||||
|
|
||||||
|
#include <VoxelConstants.h>
|
||||||
|
|
||||||
|
#include "Menu.h"
|
||||||
|
#include "devices/OculusManager.h"
|
||||||
|
#include "ui/HMDToolsDialog.h"
|
||||||
|
|
||||||
|
|
||||||
|
HMDToolsDialog::HMDToolsDialog(QWidget* parent) :
|
||||||
|
QDialog(parent, Qt::Window | Qt::WindowCloseButtonHint | Qt::WindowStaysOnTopHint) ,
|
||||||
|
_previousScreen(NULL),
|
||||||
|
_hmdScreen(NULL),
|
||||||
|
_hmdScreenNumber(-1),
|
||||||
|
_switchModeButton(NULL),
|
||||||
|
_debugDetails(NULL),
|
||||||
|
_previousDialogScreen(NULL),
|
||||||
|
_inHDMMode(false)
|
||||||
|
{
|
||||||
|
this->setWindowTitle("HMD Tools");
|
||||||
|
|
||||||
|
// Create layouter
|
||||||
|
QFormLayout* form = new QFormLayout();
|
||||||
|
const int WIDTH = 350;
|
||||||
|
|
||||||
|
// Add a button to enter
|
||||||
|
_switchModeButton = new QPushButton("Enter HMD Mode");
|
||||||
|
_switchModeButton->setFixedWidth(WIDTH);
|
||||||
|
form->addRow("", _switchModeButton);
|
||||||
|
connect(_switchModeButton,SIGNAL(clicked(bool)),this,SLOT(switchModeClicked(bool)));
|
||||||
|
|
||||||
|
// Create a label with debug details...
|
||||||
|
_debugDetails = new QLabel();
|
||||||
|
_debugDetails->setText(getDebugDetails());
|
||||||
|
const int HEIGHT = 100;
|
||||||
|
_debugDetails->setFixedSize(WIDTH, HEIGHT);
|
||||||
|
form->addRow("", _debugDetails);
|
||||||
|
|
||||||
|
this->QDialog::setLayout(form);
|
||||||
|
|
||||||
|
_wasMoved = false;
|
||||||
|
_previousRect = Application::getInstance()->getWindow()->rect();
|
||||||
|
Application::getInstance()->getWindow()->activateWindow();
|
||||||
|
|
||||||
|
// watch for our application window moving screens. If it does we want to update our screen details
|
||||||
|
QWindow* mainWindow = Application::getInstance()->getWindow()->windowHandle();
|
||||||
|
connect(mainWindow, &QWindow::screenChanged, this, &HMDToolsDialog::applicationWindowScreenChanged);
|
||||||
|
|
||||||
|
// watch for our dialog window moving screens. If it does we want to enforce our rules about
|
||||||
|
// what screens we're allowed on
|
||||||
|
QWindow* dialogWindow = windowHandle();
|
||||||
|
connect(dialogWindow, &QWindow::screenChanged, this, &HMDToolsDialog::dialogWindowScreenChanged);
|
||||||
|
connect(dialogWindow, &QWindow::xChanged, this, &HMDToolsDialog::dialogWindowGeometryChanged);
|
||||||
|
connect(dialogWindow, &QWindow::yChanged, this, &HMDToolsDialog::dialogWindowGeometryChanged);
|
||||||
|
connect(dialogWindow, &QWindow::widthChanged, this, &HMDToolsDialog::dialogWindowGeometryChanged);
|
||||||
|
connect(dialogWindow, &QWindow::heightChanged, this, &HMDToolsDialog::dialogWindowGeometryChanged);
|
||||||
|
|
||||||
|
// when the application is about to quit, leave HDM mode
|
||||||
|
connect(Application::getInstance(), SIGNAL(aboutToQuit()), this, SLOT(aboutToQuit()));
|
||||||
|
|
||||||
|
// keep track of changes to the number of screens
|
||||||
|
connect(QApplication::desktop(), &QDesktopWidget::screenCountChanged, this, &HMDToolsDialog::screenCountChanged);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
HMDToolsDialog::~HMDToolsDialog() {
|
||||||
|
}
|
||||||
|
|
||||||
|
void HMDToolsDialog::applicationWindowScreenChanged(QScreen* screen) {
|
||||||
|
_debugDetails->setText(getDebugDetails());
|
||||||
|
}
|
||||||
|
|
||||||
|
void HMDToolsDialog::dialogWindowGeometryChanged(int arg) {
|
||||||
|
QWindow* dialogWindow = windowHandle();
|
||||||
|
_previousDialogRect = rect();
|
||||||
|
_previousDialogRect = QRect(dialogWindow->mapToGlobal(_previousDialogRect.topLeft()),
|
||||||
|
dialogWindow->mapToGlobal(_previousDialogRect.bottomRight()));
|
||||||
|
_previousDialogScreen = dialogWindow->screen();
|
||||||
|
}
|
||||||
|
|
||||||
|
void HMDToolsDialog::dialogWindowScreenChanged(QScreen* screen) {
|
||||||
|
_debugDetails->setText(getDebugDetails());
|
||||||
|
|
||||||
|
// if we have more than one screen, and a known hmdScreen then try to
|
||||||
|
// keep our dialog off of the hmdScreen
|
||||||
|
if (QApplication::desktop()->screenCount() > 1) {
|
||||||
|
|
||||||
|
// we want to use a local variable here because we are not necesarily in HMD mode
|
||||||
|
int hmdScreenNumber = OculusManager::getHMDScreen();
|
||||||
|
if (_hmdScreenNumber >= 0) {
|
||||||
|
QScreen* hmdScreen = QGuiApplication::screens()[hmdScreenNumber];
|
||||||
|
if (screen == hmdScreen) {
|
||||||
|
qDebug() << "HMD Tools: Whoa! What are you doing? You don't want to move me to the HMD Screen!";
|
||||||
|
QWindow* dialogWindow = windowHandle();
|
||||||
|
|
||||||
|
// try to pick a better screen
|
||||||
|
QScreen* betterScreen = NULL;
|
||||||
|
|
||||||
|
QWindow* appWindow = Application::getInstance()->getWindow()->windowHandle();
|
||||||
|
QScreen* appScreen = appWindow->screen();
|
||||||
|
|
||||||
|
if (_previousDialogScreen && _previousDialogScreen != hmdScreen) {
|
||||||
|
// first, if the previous dialog screen is not the HMD screen, then move it there.
|
||||||
|
betterScreen = appScreen;
|
||||||
|
} else if (appScreen != hmdScreen) {
|
||||||
|
// second, if the application screen is not the HMD screen, then move it there.
|
||||||
|
betterScreen = appScreen;
|
||||||
|
} else if (_previousScreen && _previousScreen != hmdScreen) {
|
||||||
|
// third, if the application screen is the HMD screen, we want to move it to
|
||||||
|
// the previous screen
|
||||||
|
betterScreen = _previousScreen;
|
||||||
|
} else {
|
||||||
|
// last, if we can't use the previous screen the use the primary desktop screen
|
||||||
|
int desktopPrimaryScreenNumber = QApplication::desktop()->primaryScreen();
|
||||||
|
QScreen* desktopPrimaryScreen = QGuiApplication::screens()[desktopPrimaryScreenNumber];
|
||||||
|
betterScreen = desktopPrimaryScreen;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (betterScreen) {
|
||||||
|
dialogWindow->setScreen(betterScreen);
|
||||||
|
dialogWindow->setGeometry(_previousDialogRect);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QString HMDToolsDialog::getDebugDetails() const {
|
||||||
|
QString results;
|
||||||
|
|
||||||
|
int hmdScreenNumber = OculusManager::getHMDScreen();
|
||||||
|
if (hmdScreenNumber >= 0) {
|
||||||
|
results += "HMD Screen: " + QGuiApplication::screens()[hmdScreenNumber]->name() + "\n";
|
||||||
|
} else {
|
||||||
|
results += "HMD Screen Name: Unknown\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
int desktopPrimaryScreenNumber = QApplication::desktop()->primaryScreen();
|
||||||
|
QScreen* desktopPrimaryScreen = QGuiApplication::screens()[desktopPrimaryScreenNumber];
|
||||||
|
results += "Desktop's Primary Screen: " + desktopPrimaryScreen->name() + "\n";
|
||||||
|
|
||||||
|
results += "Application Primary Screen: " + QGuiApplication::primaryScreen()->name() + "\n";
|
||||||
|
QScreen* mainWindowScreen = Application::getInstance()->getWindow()->windowHandle()->screen();
|
||||||
|
results += "Application Main Window Screen: " + mainWindowScreen->name() + "\n";
|
||||||
|
results += "Total Screens: " + QString::number(QApplication::desktop()->screenCount()) + "\n";
|
||||||
|
|
||||||
|
return results;
|
||||||
|
}
|
||||||
|
|
||||||
|
void HMDToolsDialog::switchModeClicked(bool checked) {
|
||||||
|
if (!_inHDMMode) {
|
||||||
|
enterHDMMode();
|
||||||
|
} else {
|
||||||
|
leaveHDMMode();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void HMDToolsDialog::enterHDMMode() {
|
||||||
|
if (!_inHDMMode) {
|
||||||
|
_switchModeButton->setText("Leave HMD Mode");
|
||||||
|
_debugDetails->setText(getDebugDetails());
|
||||||
|
|
||||||
|
_hmdScreenNumber = OculusManager::getHMDScreen();
|
||||||
|
|
||||||
|
if (_hmdScreenNumber >= 0) {
|
||||||
|
QWindow* mainWindow = Application::getInstance()->getWindow()->windowHandle();
|
||||||
|
_hmdScreen = QGuiApplication::screens()[_hmdScreenNumber];
|
||||||
|
|
||||||
|
_previousRect = Application::getInstance()->getWindow()->rect();
|
||||||
|
_previousRect = QRect(mainWindow->mapToGlobal(_previousRect.topLeft()),
|
||||||
|
mainWindow->mapToGlobal(_previousRect.bottomRight()));
|
||||||
|
_previousScreen = mainWindow->screen();
|
||||||
|
QRect rect = QApplication::desktop()->screenGeometry(_hmdScreenNumber);
|
||||||
|
mainWindow->setScreen(_hmdScreen);
|
||||||
|
mainWindow->setGeometry(rect);
|
||||||
|
|
||||||
|
_wasMoved = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// if we're on a single screen setup, then hide our tools window when entering HMD mode
|
||||||
|
if (QApplication::desktop()->screenCount() == 1) {
|
||||||
|
close();
|
||||||
|
}
|
||||||
|
|
||||||
|
Application::getInstance()->setFullscreen(true);
|
||||||
|
Application::getInstance()->setEnableVRMode(true);
|
||||||
|
|
||||||
|
const int SLIGHT_DELAY = 500;
|
||||||
|
QTimer::singleShot(SLIGHT_DELAY, this, SLOT(activateWindowAfterEnterMode()));
|
||||||
|
|
||||||
|
_inHDMMode = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void HMDToolsDialog::activateWindowAfterEnterMode() {
|
||||||
|
Application::getInstance()->getWindow()->activateWindow();
|
||||||
|
|
||||||
|
// center the cursor on the main application window
|
||||||
|
centerCursorOnWidget(Application::getInstance()->getWindow());
|
||||||
|
}
|
||||||
|
|
||||||
|
void HMDToolsDialog::leaveHDMMode() {
|
||||||
|
if (_inHDMMode) {
|
||||||
|
_switchModeButton->setText("Enter HMD Mode");
|
||||||
|
_debugDetails->setText(getDebugDetails());
|
||||||
|
|
||||||
|
Application::getInstance()->setFullscreen(false);
|
||||||
|
Application::getInstance()->setEnableVRMode(false);
|
||||||
|
Application::getInstance()->getWindow()->activateWindow();
|
||||||
|
|
||||||
|
if (_wasMoved) {
|
||||||
|
QWindow* mainWindow = Application::getInstance()->getWindow()->windowHandle();
|
||||||
|
mainWindow->setScreen(_previousScreen);
|
||||||
|
mainWindow->setGeometry(_previousRect);
|
||||||
|
|
||||||
|
const int SLIGHT_DELAY = 1500;
|
||||||
|
QTimer::singleShot(SLIGHT_DELAY, this, SLOT(moveWindowAfterLeaveMode()));
|
||||||
|
}
|
||||||
|
_wasMoved = false;
|
||||||
|
_inHDMMode = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void HMDToolsDialog::moveWindowAfterLeaveMode() {
|
||||||
|
QWindow* mainWindow = Application::getInstance()->getWindow()->windowHandle();
|
||||||
|
mainWindow->setScreen(_previousScreen);
|
||||||
|
mainWindow->setGeometry(_previousRect);
|
||||||
|
Application::getInstance()->getWindow()->activateWindow();
|
||||||
|
Application::getInstance()->resetSensors();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void HMDToolsDialog::reject() {
|
||||||
|
// Just regularly close upon ESC
|
||||||
|
close();
|
||||||
|
}
|
||||||
|
|
||||||
|
void HMDToolsDialog::closeEvent(QCloseEvent* event) {
|
||||||
|
// TODO: consider if we want to prevent closing of this window with event->ignore();
|
||||||
|
this->QDialog::closeEvent(event);
|
||||||
|
emit closed();
|
||||||
|
}
|
||||||
|
|
||||||
|
void HMDToolsDialog::centerCursorOnWidget(QWidget* widget) {
|
||||||
|
QWindow* window = widget->windowHandle();
|
||||||
|
QScreen* screen = window->screen();
|
||||||
|
QPoint windowCenter = window->geometry().center();
|
||||||
|
QCursor::setPos(screen, windowCenter);
|
||||||
|
}
|
||||||
|
|
||||||
|
void HMDToolsDialog::showEvent(QShowEvent* event) {
|
||||||
|
// center the cursor on the hmd tools dialog
|
||||||
|
centerCursorOnWidget(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
void HMDToolsDialog::hideEvent(QHideEvent* event) {
|
||||||
|
// center the cursor on the main application window
|
||||||
|
centerCursorOnWidget(Application::getInstance()->getWindow());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void HMDToolsDialog::aboutToQuit() {
|
||||||
|
if (_inHDMMode) {
|
||||||
|
leaveHDMMode();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void HMDToolsDialog::screenCountChanged(int newCount) {
|
||||||
|
if (!OculusManager::isConnected()) {
|
||||||
|
OculusManager::connect();
|
||||||
|
}
|
||||||
|
int hmdScreenNumber = OculusManager::getHMDScreen();
|
||||||
|
|
||||||
|
if (_inHDMMode && _hmdScreenNumber != hmdScreenNumber) {
|
||||||
|
qDebug() << "HMD Display changed WHILE IN HMD MODE";
|
||||||
|
leaveHDMMode();
|
||||||
|
|
||||||
|
// if there is a new best HDM screen then go back into HDM mode after done leaving
|
||||||
|
if (hmdScreenNumber >= 0) {
|
||||||
|
qDebug() << "Trying to go back into HDM Mode";
|
||||||
|
const int SLIGHT_DELAY = 2000;
|
||||||
|
QTimer::singleShot(SLIGHT_DELAY, this, SLOT(enterHDMMode()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_debugDetails->setText(getDebugDetails());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
63
interface/src/ui/HMDToolsDialog.h
Normal file
63
interface/src/ui/HMDToolsDialog.h
Normal file
|
@ -0,0 +1,63 @@
|
||||||
|
//
|
||||||
|
// HMDToolsDialog.h
|
||||||
|
// interface/src/ui
|
||||||
|
//
|
||||||
|
// Created by Brad Hefta-Gaub on 7/19/13.
|
||||||
|
// Copyright 2013 High Fidelity, Inc.
|
||||||
|
//
|
||||||
|
// Distributed under the Apache License, Version 2.0.
|
||||||
|
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef hifi_HMDToolsDialog_h
|
||||||
|
#define hifi_HMDToolsDialog_h
|
||||||
|
|
||||||
|
#include <QDialog>
|
||||||
|
|
||||||
|
class HMDToolsDialog : public QDialog {
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
// Sets up the UI
|
||||||
|
HMDToolsDialog(QWidget* parent);
|
||||||
|
~HMDToolsDialog();
|
||||||
|
|
||||||
|
QString getDebugDetails() const;
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void closed();
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
void reject();
|
||||||
|
void switchModeClicked(bool checked);
|
||||||
|
void activateWindowAfterEnterMode();
|
||||||
|
void moveWindowAfterLeaveMode();
|
||||||
|
void applicationWindowScreenChanged(QScreen* screen);
|
||||||
|
void dialogWindowScreenChanged(QScreen* screen);
|
||||||
|
void dialogWindowGeometryChanged(int arg);
|
||||||
|
void aboutToQuit();
|
||||||
|
void screenCountChanged(int newCount);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
virtual void closeEvent(QCloseEvent*); // Emits a 'closed' signal when this dialog is closed.
|
||||||
|
virtual void showEvent(QShowEvent* event);
|
||||||
|
virtual void hideEvent(QHideEvent* event);
|
||||||
|
|
||||||
|
private:
|
||||||
|
void centerCursorOnWidget(QWidget* widget);
|
||||||
|
void enterHDMMode();
|
||||||
|
void leaveHDMMode();
|
||||||
|
|
||||||
|
bool _wasMoved;
|
||||||
|
QRect _previousRect;
|
||||||
|
QScreen* _previousScreen;
|
||||||
|
QScreen* _hmdScreen;
|
||||||
|
int _hmdScreenNumber;
|
||||||
|
QPushButton* _switchModeButton;
|
||||||
|
QLabel* _debugDetails;
|
||||||
|
|
||||||
|
QRect _previousDialogRect;
|
||||||
|
QScreen* _previousDialogScreen;
|
||||||
|
bool _inHDMMode;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // hifi_HMDToolsDialog_h
|
|
@ -21,6 +21,7 @@ ToolWindow::ToolWindow(QWidget* parent) :
|
||||||
_hasShown(false),
|
_hasShown(false),
|
||||||
_lastGeometry() {
|
_lastGeometry() {
|
||||||
|
|
||||||
|
setDockOptions(QMainWindow::ForceTabbedDocks);
|
||||||
Application::getInstance()->installEventFilter(this);
|
Application::getInstance()->installEventFilter(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -99,8 +100,17 @@ void ToolWindow::onChildVisibilityUpdated(bool visible) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void ToolWindow::addDockWidget(Qt::DockWidgetArea area, QDockWidget* dockWidget) {
|
void ToolWindow::addDockWidget(Qt::DockWidgetArea area, QDockWidget* dockWidget) {
|
||||||
|
QList<QDockWidget*> dockWidgets = findChildren<QDockWidget*>();
|
||||||
|
|
||||||
QMainWindow::addDockWidget(area, dockWidget);
|
QMainWindow::addDockWidget(area, dockWidget);
|
||||||
|
|
||||||
|
// We want to force tabbing, so retabify all of our widgets.
|
||||||
|
QDockWidget* lastDockWidget = dockWidget;
|
||||||
|
foreach (QDockWidget* nextDockWidget, dockWidgets) {
|
||||||
|
tabifyDockWidget(lastDockWidget, nextDockWidget);
|
||||||
|
lastDockWidget = nextDockWidget;
|
||||||
|
}
|
||||||
|
|
||||||
connect(dockWidget, &QDockWidget::visibilityChanged, this, &ToolWindow::onChildVisibilityUpdated);
|
connect(dockWidget, &QDockWidget::visibilityChanged, this, &ToolWindow::onChildVisibilityUpdated);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -20,7 +20,8 @@ AnimationLoop::AnimationLoop() :
|
||||||
_firstFrame(0.0f),
|
_firstFrame(0.0f),
|
||||||
_lastFrame(FLT_MAX),
|
_lastFrame(FLT_MAX),
|
||||||
_running(false),
|
_running(false),
|
||||||
_frameIndex(0.0f)
|
_frameIndex(0.0f),
|
||||||
|
_maxFrameIndexHint(FLT_MAX)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -55,7 +56,7 @@ void AnimationLoop::simulate(float deltaTime) {
|
||||||
|
|
||||||
// If we knew the number of frames from the animation, we'd consider using it here
|
// If we knew the number of frames from the animation, we'd consider using it here
|
||||||
// animationGeometry.animationFrames.size()
|
// animationGeometry.animationFrames.size()
|
||||||
float maxFrame = _lastFrame;
|
float maxFrame = _maxFrameIndexHint;
|
||||||
float endFrameIndex = qMin(_lastFrame, maxFrame - (_loop ? 0.0f : 1.0f));
|
float endFrameIndex = qMin(_lastFrame, maxFrame - (_loop ? 0.0f : 1.0f));
|
||||||
float startFrameIndex = qMin(_firstFrame, endFrameIndex);
|
float startFrameIndex = qMin(_firstFrame, endFrameIndex);
|
||||||
if ((!_loop && (_frameIndex < startFrameIndex || _frameIndex > endFrameIndex)) || startFrameIndex == endFrameIndex) {
|
if ((!_loop && (_frameIndex < startFrameIndex || _frameIndex > endFrameIndex)) || startFrameIndex == endFrameIndex) {
|
||||||
|
|
|
@ -44,6 +44,9 @@ public:
|
||||||
|
|
||||||
void setFrameIndex(float frameIndex) { _frameIndex = glm::clamp(frameIndex, _firstFrame, _lastFrame); }
|
void setFrameIndex(float frameIndex) { _frameIndex = glm::clamp(frameIndex, _firstFrame, _lastFrame); }
|
||||||
float getFrameIndex() const { return _frameIndex; }
|
float getFrameIndex() const { return _frameIndex; }
|
||||||
|
|
||||||
|
void setMaxFrameIndexHint(float value) { _maxFrameIndexHint = value; }
|
||||||
|
float getMaxFrameIndexHint() const { return _maxFrameIndexHint; }
|
||||||
|
|
||||||
void start() { setRunning(true); }
|
void start() { setRunning(true); }
|
||||||
void stop() { setRunning(false); }
|
void stop() { setRunning(false); }
|
||||||
|
@ -58,6 +61,7 @@ private:
|
||||||
float _lastFrame;
|
float _lastFrame;
|
||||||
bool _running;
|
bool _running;
|
||||||
float _frameIndex;
|
float _frameIndex;
|
||||||
|
float _maxFrameIndexHint;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // hifi_AnimationLoop_h
|
#endif // hifi_AnimationLoop_h
|
||||||
|
|
|
@ -344,7 +344,9 @@ QVector<glm::quat> ModelEntityItem::getAnimationFrame() {
|
||||||
Animation* myAnimation = getAnimation(_animationURL);
|
Animation* myAnimation = getAnimation(_animationURL);
|
||||||
QVector<FBXAnimationFrame> frames = myAnimation->getFrames();
|
QVector<FBXAnimationFrame> frames = myAnimation->getFrames();
|
||||||
int frameCount = frames.size();
|
int frameCount = frames.size();
|
||||||
|
if (_animationLoop.getMaxFrameIndexHint() != frameCount) {
|
||||||
|
_animationLoop.setMaxFrameIndexHint(frameCount);
|
||||||
|
}
|
||||||
if (frameCount > 0) {
|
if (frameCount > 0) {
|
||||||
int animationFrameIndex = (int)(glm::floor(getAnimationFrameIndex())) % frameCount;
|
int animationFrameIndex = (int)(glm::floor(getAnimationFrameIndex())) % frameCount;
|
||||||
if (animationFrameIndex < 0 || animationFrameIndex > frameCount) {
|
if (animationFrameIndex < 0 || animationFrameIndex > frameCount) {
|
||||||
|
|
|
@ -1194,7 +1194,7 @@ int matchTextureUVSetToAttributeChannel(const std::string& texUVSetName, const Q
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
FBXGeometry extractFBXGeometry(const FBXNode& node, const QVariantHash& mapping) {
|
FBXGeometry extractFBXGeometry(const FBXNode& node, const QVariantHash& mapping, bool loadLightmaps, float lightmapLevel) {
|
||||||
QHash<QString, ExtractedMesh> meshes;
|
QHash<QString, ExtractedMesh> meshes;
|
||||||
QHash<QString, QString> modelIDsToNames;
|
QHash<QString, QString> modelIDsToNames;
|
||||||
QHash<QString, int> meshIDsToMeshIndices;
|
QHash<QString, int> meshIDsToMeshIndices;
|
||||||
|
@ -1216,6 +1216,7 @@ FBXGeometry extractFBXGeometry(const FBXNode& node, const QVariantHash& mapping)
|
||||||
QHash<QString, QString> bumpTextures;
|
QHash<QString, QString> bumpTextures;
|
||||||
QHash<QString, QString> specularTextures;
|
QHash<QString, QString> specularTextures;
|
||||||
QHash<QString, QString> emissiveTextures;
|
QHash<QString, QString> emissiveTextures;
|
||||||
|
QHash<QString, QString> ambientTextures;
|
||||||
QHash<QString, QString> localRotations;
|
QHash<QString, QString> localRotations;
|
||||||
QHash<QString, QString> xComponents;
|
QHash<QString, QString> xComponents;
|
||||||
QHash<QString, QString> yComponents;
|
QHash<QString, QString> yComponents;
|
||||||
|
@ -1597,9 +1598,28 @@ FBXGeometry extractFBXGeometry(const FBXNode& node, const QVariantHash& mapping)
|
||||||
} else if (property.properties.at(0) == "Opacity") {
|
} else if (property.properties.at(0) == "Opacity") {
|
||||||
material.opacity = property.properties.at(index).value<double>();
|
material.opacity = property.properties.at(index).value<double>();
|
||||||
}
|
}
|
||||||
|
#if defined(DEBUG_FBXREADER)
|
||||||
|
else {
|
||||||
|
const std::string propname = property.properties.at(0).toString().toStdString();
|
||||||
|
if (propname == "EmissiveFactor") {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#if defined(DEBUG_FBXREADER)
|
||||||
|
else {
|
||||||
|
std::string propname = subobject.name.data();
|
||||||
|
int unknown = 0;
|
||||||
|
if ( (propname == "Version")
|
||||||
|
||(propname == "ShadingModel")
|
||||||
|
||(propname == "Multilayer")) {
|
||||||
|
} else {
|
||||||
|
unknown++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
material.id = getID(object.properties);
|
material.id = getID(object.properties);
|
||||||
materials.insert(material.id, material);
|
materials.insert(material.id, material);
|
||||||
|
@ -1684,10 +1704,13 @@ FBXGeometry extractFBXGeometry(const FBXNode& node, const QVariantHash& mapping)
|
||||||
} else if (type.contains("shininess")) {
|
} else if (type.contains("shininess")) {
|
||||||
counter++;
|
counter++;
|
||||||
|
|
||||||
} else if (type.contains("emissive")) {
|
} else if (loadLightmaps && type.contains("emissive")) {
|
||||||
emissiveTextures.insert(getID(connection.properties, 2), getID(connection.properties, 1));
|
emissiveTextures.insert(getID(connection.properties, 2), getID(connection.properties, 1));
|
||||||
|
|
||||||
|
} else if (loadLightmaps && type.contains("ambient")) {
|
||||||
|
ambientTextures.insert(getID(connection.properties, 2), getID(connection.properties, 1));
|
||||||
} else {
|
} else {
|
||||||
|
std::string typenam = type.data();
|
||||||
counter++;
|
counter++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1930,19 +1953,21 @@ FBXGeometry extractFBXGeometry(const FBXNode& node, const QVariantHash& mapping)
|
||||||
}
|
}
|
||||||
|
|
||||||
FBXTexture emissiveTexture;
|
FBXTexture emissiveTexture;
|
||||||
|
glm::vec2 emissiveParams(0.f, 1.f);
|
||||||
|
emissiveParams.y = lightmapLevel;
|
||||||
QString emissiveTextureID = emissiveTextures.value(childID);
|
QString emissiveTextureID = emissiveTextures.value(childID);
|
||||||
if (!emissiveTextureID.isNull()) {
|
QString ambientTextureID = ambientTextures.value(childID);
|
||||||
emissiveTexture = getTexture(emissiveTextureID, textureNames, textureFilenames, textureContent, textureParams);
|
if (!emissiveTextureID.isNull() || !ambientTextureID.isNull()) {
|
||||||
|
|
||||||
// FBX files generated by 3DSMax have an intermediate texture parent, apparently
|
if (!emissiveTextureID.isNull()) {
|
||||||
foreach (const QString& childTextureID, childMap.values(diffuseTextureID)) {
|
emissiveTexture = getTexture(emissiveTextureID, textureNames, textureFilenames, textureContent, textureParams);
|
||||||
if (textureFilenames.contains(childTextureID)) {
|
emissiveParams.y = 4.0f;
|
||||||
emissiveTexture = getTexture(emissiveTextureID, textureNames, textureFilenames, textureContent, textureParams);
|
} else if (!ambientTextureID.isNull()) {
|
||||||
}
|
emissiveTexture = getTexture(ambientTextureID, textureNames, textureFilenames, textureContent, textureParams);
|
||||||
}
|
}
|
||||||
|
|
||||||
emissiveTexture.texcoordSet = matchTextureUVSetToAttributeChannel(emissiveTexture.texcoordSetName, extracted.texcoordSetMap);
|
emissiveTexture.texcoordSet = matchTextureUVSetToAttributeChannel(emissiveTexture.texcoordSetName, extracted.texcoordSetMap);
|
||||||
|
|
||||||
detectDifferentUVs |= (emissiveTexture.texcoordSet != 0) || (!emissiveTexture.transform.isIdentity());
|
detectDifferentUVs |= (emissiveTexture.texcoordSet != 0) || (!emissiveTexture.transform.isIdentity());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1970,6 +1995,8 @@ FBXGeometry extractFBXGeometry(const FBXNode& node, const QVariantHash& mapping)
|
||||||
if (!emissiveTexture.filename.isNull()) {
|
if (!emissiveTexture.filename.isNull()) {
|
||||||
part.emissiveTexture = emissiveTexture;
|
part.emissiveTexture = emissiveTexture;
|
||||||
}
|
}
|
||||||
|
part.emissiveParams = emissiveParams;
|
||||||
|
|
||||||
part.materialID = material.id;
|
part.materialID = material.id;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2346,10 +2373,10 @@ QByteArray writeMapping(const QVariantHash& mapping) {
|
||||||
return buffer.data();
|
return buffer.data();
|
||||||
}
|
}
|
||||||
|
|
||||||
FBXGeometry readFBX(const QByteArray& model, const QVariantHash& mapping) {
|
FBXGeometry readFBX(const QByteArray& model, const QVariantHash& mapping, bool loadLightmaps, float lightmapLevel) {
|
||||||
QBuffer buffer(const_cast<QByteArray*>(&model));
|
QBuffer buffer(const_cast<QByteArray*>(&model));
|
||||||
buffer.open(QIODevice::ReadOnly);
|
buffer.open(QIODevice::ReadOnly);
|
||||||
return extractFBXGeometry(parseFBX(&buffer), mapping);
|
return extractFBXGeometry(parseFBX(&buffer), mapping, loadLightmaps, lightmapLevel);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool addMeshVoxelsOperation(OctreeElement* element, void* extraData) {
|
bool addMeshVoxelsOperation(OctreeElement* element, void* extraData) {
|
||||||
|
|
|
@ -119,6 +119,7 @@ public:
|
||||||
glm::vec3 diffuseColor;
|
glm::vec3 diffuseColor;
|
||||||
glm::vec3 specularColor;
|
glm::vec3 specularColor;
|
||||||
glm::vec3 emissiveColor;
|
glm::vec3 emissiveColor;
|
||||||
|
glm::vec2 emissiveParams;
|
||||||
float shininess;
|
float shininess;
|
||||||
float opacity;
|
float opacity;
|
||||||
|
|
||||||
|
@ -252,7 +253,7 @@ QByteArray writeMapping(const QVariantHash& mapping);
|
||||||
|
|
||||||
/// Reads FBX geometry from the supplied model and mapping data.
|
/// Reads FBX geometry from the supplied model and mapping data.
|
||||||
/// \exception QString if an error occurs in parsing
|
/// \exception QString if an error occurs in parsing
|
||||||
FBXGeometry readFBX(const QByteArray& model, const QVariantHash& mapping);
|
FBXGeometry readFBX(const QByteArray& model, const QVariantHash& mapping, bool loadLightmaps = true, float lightmapLevel = 1.0f);
|
||||||
|
|
||||||
/// Reads SVO geometry from the supplied model data.
|
/// Reads SVO geometry from the supplied model data.
|
||||||
FBXGeometry readSVO(const QByteArray& model);
|
FBXGeometry readSVO(const QByteArray& model);
|
||||||
|
|
|
@ -44,6 +44,8 @@ const char DEFAULT_ASSIGNMENT_SERVER_HOSTNAME[] = "localhost";
|
||||||
const char STUN_SERVER_HOSTNAME[] = "stun.highfidelity.io";
|
const char STUN_SERVER_HOSTNAME[] = "stun.highfidelity.io";
|
||||||
const unsigned short STUN_SERVER_PORT = 3478;
|
const unsigned short STUN_SERVER_PORT = 3478;
|
||||||
|
|
||||||
|
const QString DOMAIN_SERVER_LOCAL_PORT_SMEM_KEY = "domain-server.local-port";
|
||||||
|
|
||||||
class HifiSockAddr;
|
class HifiSockAddr;
|
||||||
|
|
||||||
typedef QSet<NodeType_t> NodeSet;
|
typedef QSet<NodeType_t> NodeSet;
|
||||||
|
|
|
@ -100,71 +100,6 @@ ScriptEngine::ScriptEngine(const QString& scriptContents, const QString& fileNam
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
ScriptEngine::ScriptEngine(const QUrl& scriptURL,
|
|
||||||
AbstractControllerScriptingInterface* controllerScriptingInterface) :
|
|
||||||
_scriptContents(),
|
|
||||||
_isFinished(false),
|
|
||||||
_isRunning(false),
|
|
||||||
_isInitialized(false),
|
|
||||||
_isAvatar(false),
|
|
||||||
_avatarIdentityTimer(NULL),
|
|
||||||
_avatarBillboardTimer(NULL),
|
|
||||||
_timerFunctionMap(),
|
|
||||||
_isListeningToAudioStream(false),
|
|
||||||
_avatarSound(NULL),
|
|
||||||
_numAvatarSoundSentBytes(0),
|
|
||||||
_controllerScriptingInterface(controllerScriptingInterface),
|
|
||||||
_avatarData(NULL),
|
|
||||||
_scriptName(),
|
|
||||||
_fileNameString(),
|
|
||||||
_quatLibrary(),
|
|
||||||
_vec3Library(),
|
|
||||||
_uuidLibrary(),
|
|
||||||
_animationCache(this),
|
|
||||||
_isUserLoaded(false),
|
|
||||||
_arrayBufferClass(new ArrayBufferClass(this))
|
|
||||||
{
|
|
||||||
QString scriptURLString = scriptURL.toString();
|
|
||||||
_fileNameString = scriptURLString;
|
|
||||||
|
|
||||||
QUrl url(scriptURL);
|
|
||||||
|
|
||||||
// if the scheme length is one or lower, maybe they typed in a file, let's try
|
|
||||||
const int WINDOWS_DRIVE_LETTER_SIZE = 1;
|
|
||||||
if (url.scheme().size() <= WINDOWS_DRIVE_LETTER_SIZE) {
|
|
||||||
url = QUrl::fromLocalFile(scriptURLString);
|
|
||||||
}
|
|
||||||
|
|
||||||
// ok, let's see if it's valid... and if so, load it
|
|
||||||
if (url.isValid()) {
|
|
||||||
if (url.scheme() == "file") {
|
|
||||||
QString fileName = url.toLocalFile();
|
|
||||||
QFile scriptFile(fileName);
|
|
||||||
if (scriptFile.open(QFile::ReadOnly | QFile::Text)) {
|
|
||||||
qDebug() << "Loading file:" << fileName;
|
|
||||||
QTextStream in(&scriptFile);
|
|
||||||
_scriptContents = in.readAll();
|
|
||||||
} else {
|
|
||||||
qDebug() << "ERROR Loading file:" << fileName;
|
|
||||||
emit errorMessage("ERROR Loading file:" + fileName);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
QNetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance();
|
|
||||||
QNetworkReply* reply = networkAccessManager.get(QNetworkRequest(url));
|
|
||||||
qDebug() << "Downloading script at" << url;
|
|
||||||
QEventLoop loop;
|
|
||||||
QObject::connect(reply, SIGNAL(finished()), &loop, SLOT(quit()));
|
|
||||||
loop.exec();
|
|
||||||
if (reply->error() == QNetworkReply::NoError && reply->attribute(QNetworkRequest::HttpStatusCodeAttribute) == 200) {
|
|
||||||
_scriptContents = reply->readAll();
|
|
||||||
} else {
|
|
||||||
qDebug() << "ERROR Loading file:" << url.toString();
|
|
||||||
emit errorMessage("ERROR Loading file:" + url.toString());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void ScriptEngine::setIsAvatar(bool isAvatar) {
|
void ScriptEngine::setIsAvatar(bool isAvatar) {
|
||||||
_isAvatar = isAvatar;
|
_isAvatar = isAvatar;
|
||||||
|
|
||||||
|
@ -217,6 +152,56 @@ bool ScriptEngine::setScriptContents(const QString& scriptContents, const QStrin
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ScriptEngine::loadURL(const QUrl& scriptURL) {
|
||||||
|
if (_isRunning) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString scriptURLString = scriptURL.toString();
|
||||||
|
_fileNameString = scriptURLString;
|
||||||
|
|
||||||
|
QUrl url(scriptURL);
|
||||||
|
|
||||||
|
// if the scheme length is one or lower, maybe they typed in a file, let's try
|
||||||
|
const int WINDOWS_DRIVE_LETTER_SIZE = 1;
|
||||||
|
if (url.scheme().size() <= WINDOWS_DRIVE_LETTER_SIZE) {
|
||||||
|
url = QUrl::fromLocalFile(scriptURLString);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ok, let's see if it's valid... and if so, load it
|
||||||
|
if (url.isValid()) {
|
||||||
|
if (url.scheme() == "file") {
|
||||||
|
QString fileName = url.toLocalFile();
|
||||||
|
QFile scriptFile(fileName);
|
||||||
|
if (scriptFile.open(QFile::ReadOnly | QFile::Text)) {
|
||||||
|
qDebug() << "Loading file:" << fileName;
|
||||||
|
QTextStream in(&scriptFile);
|
||||||
|
_scriptContents = in.readAll();
|
||||||
|
emit scriptLoaded(url);
|
||||||
|
} else {
|
||||||
|
qDebug() << "ERROR Loading file:" << fileName;
|
||||||
|
emit errorLoadingScript(url);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
QNetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance();
|
||||||
|
QNetworkReply* reply = networkAccessManager.get(QNetworkRequest(url));
|
||||||
|
connect(reply, &QNetworkReply::finished, this, &ScriptEngine::handleScriptDownload);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ScriptEngine::handleScriptDownload() {
|
||||||
|
QNetworkReply* reply = qobject_cast<QNetworkReply*>(sender());
|
||||||
|
|
||||||
|
if (reply->error() == QNetworkReply::NoError && reply->attribute(QNetworkRequest::HttpStatusCodeAttribute) == 200) {
|
||||||
|
_scriptContents = reply->readAll();
|
||||||
|
emit scriptLoaded(reply->url());
|
||||||
|
} else {
|
||||||
|
qDebug() << "ERROR Loading file:" << reply->url().toString();
|
||||||
|
emit errorLoadingScript(reply->url());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Q_SCRIPT_DECLARE_QMETAOBJECT(LocalVoxels, QString)
|
Q_SCRIPT_DECLARE_QMETAOBJECT(LocalVoxels, QString)
|
||||||
|
|
||||||
void ScriptEngine::init() {
|
void ScriptEngine::init() {
|
||||||
|
|
|
@ -40,9 +40,6 @@ const unsigned int SCRIPT_DATA_CALLBACK_USECS = floor(((1.0 / 60.0f) * 1000 * 10
|
||||||
class ScriptEngine : public QScriptEngine {
|
class ScriptEngine : public QScriptEngine {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
ScriptEngine(const QUrl& scriptURL,
|
|
||||||
AbstractControllerScriptingInterface* controllerScriptingInterface = NULL);
|
|
||||||
|
|
||||||
ScriptEngine(const QString& scriptContents = NO_SCRIPT,
|
ScriptEngine(const QString& scriptContents = NO_SCRIPT,
|
||||||
const QString& fileNameString = QString(""),
|
const QString& fileNameString = QString(""),
|
||||||
AbstractControllerScriptingInterface* controllerScriptingInterface = NULL);
|
AbstractControllerScriptingInterface* controllerScriptingInterface = NULL);
|
||||||
|
@ -94,6 +91,7 @@ public:
|
||||||
bool isUserLoaded() const { return _isUserLoaded; }
|
bool isUserLoaded() const { return _isUserLoaded; }
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
|
void loadURL(const QUrl& scriptURL);
|
||||||
void stop();
|
void stop();
|
||||||
|
|
||||||
QScriptValue evaluate(const QString& program, const QString& fileName = QString(), int lineNumber = 1);
|
QScriptValue evaluate(const QString& program, const QString& fileName = QString(), int lineNumber = 1);
|
||||||
|
@ -109,6 +107,8 @@ public slots:
|
||||||
void nodeKilled(SharedNodePointer node);
|
void nodeKilled(SharedNodePointer node);
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
|
void scriptLoaded(const QUrl& scriptURL);
|
||||||
|
void errorLoadingScript(const QUrl& scriptURL);
|
||||||
void update(float deltaTime);
|
void update(float deltaTime);
|
||||||
void scriptEnding();
|
void scriptEnding();
|
||||||
void finished(const QString& fileNameString);
|
void finished(const QString& fileNameString);
|
||||||
|
@ -155,6 +155,8 @@ private:
|
||||||
ArrayBufferClass* _arrayBufferClass;
|
ArrayBufferClass* _arrayBufferClass;
|
||||||
|
|
||||||
QHash<QUuid, quint16> _outgoingScriptAudioSequenceNumbers;
|
QHash<QUuid, quint16> _outgoingScriptAudioSequenceNumbers;
|
||||||
|
private slots:
|
||||||
|
void handleScriptDownload();
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // hifi_ScriptEngine_h
|
#endif // hifi_ScriptEngine_h
|
||||||
|
|
|
@ -655,3 +655,24 @@ QString formatSecondsElapsed(float seconds) {
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool similarStrings(const QString& stringA, const QString& stringB) {
|
||||||
|
QStringList aWords = stringA.split(" ");
|
||||||
|
QStringList bWords = stringB.split(" ");
|
||||||
|
float aWordsInB = 0.0f;
|
||||||
|
foreach(QString aWord, aWords) {
|
||||||
|
if (bWords.contains(aWord)) {
|
||||||
|
aWordsInB += 1.0f;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
float bWordsInA = 0.0f;
|
||||||
|
foreach(QString bWord, bWords) {
|
||||||
|
if (aWords.contains(bWord)) {
|
||||||
|
bWordsInA += 1.0f;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
float similarity = 0.5f * (aWordsInB / (float)bWords.size()) + 0.5f * (bWordsInA / (float)aWords.size());
|
||||||
|
const float SIMILAR_ENOUGH = 0.5f; // half the words the same is similar enough for us
|
||||||
|
return similarity >= SIMILAR_ENOUGH;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -131,6 +131,6 @@ bool isNaN(float value);
|
||||||
|
|
||||||
QString formatUsecTime(float usecs, int prec = 3);
|
QString formatUsecTime(float usecs, int prec = 3);
|
||||||
QString formatSecondsElapsed(float seconds);
|
QString formatSecondsElapsed(float seconds);
|
||||||
|
bool similarStrings(const QString& stringA, const QString& stringB);
|
||||||
|
|
||||||
#endif // hifi_SharedUtil_h
|
#endif // hifi_SharedUtil_h
|
||||||
|
|
Loading…
Reference in a new issue