mirror of
https://github.com/AleziaKurdis/overte.git
synced 2025-04-07 13:12:39 +02:00
Merge branch 'master' of https://github.com/highfidelity/hifi into hdr
This commit is contained in:
commit
248f172832
61 changed files with 881 additions and 655 deletions
12
BUILD.md
12
BUILD.md
|
@ -1,7 +1,7 @@
|
|||
###Dependencies
|
||||
|
||||
* [cmake](http://www.cmake.org/cmake/resources/software.html) ~> 3.3.2
|
||||
* [Qt](http://www.qt.io/download-open-source) ~> 5.5.1
|
||||
* [Qt](http://www.qt.io/download-open-source) ~> 5.6.1
|
||||
* [OpenSSL](https://www.openssl.org/community/binaries.html) ~> 1.0.1m
|
||||
* IMPORTANT: Using the recommended version of OpenSSL is critical to avoid security vulnerabilities.
|
||||
* [VHACD](https://github.com/virneo/v-hacd)(clone this repository)(Optional)
|
||||
|
@ -41,14 +41,14 @@ If you would like to use a specific install of a dependency instead of the versi
|
|||
Hifi uses CMake to generate build files and project files for your platform.
|
||||
|
||||
####Qt
|
||||
In order for CMake to find the Qt5 find modules, you will need to set an ENV variable pointing to your Qt installation.
|
||||
In order for CMake to find the Qt5 find modules, you will need to set a QT_CMAKE_PREFIX_PATH environment variable pointing to your Qt installation.
|
||||
|
||||
For example, a Qt5 5.5.1 installation to /usr/local/qt5 would require that QT_CMAKE_PREFIX_PATH be set with the following command. This can either be entered directly into your shell session before you build or in your shell profile (e.g.: ~/.bash_profile, ~/.bashrc, ~/.zshrc - this depends on your shell and environment).
|
||||
This can either be entered directly into your shell session before you build or in your shell profile (e.g.: ~/.bash_profile, ~/.bashrc, ~/.zshrc - this depends on your shell and environment).
|
||||
|
||||
The path it needs to be set to will depend on where and how Qt5 was installed. e.g.
|
||||
|
||||
export QT_CMAKE_PREFIX_PATH=/usr/local/qt/5.5.1/clang_64/lib/cmake/
|
||||
export QT_CMAKE_PREFIX_PATH=/usr/local/Cellar/qt5/5.5.1/lib/cmake
|
||||
export QT_CMAKE_PREFIX_PATH=/usr/local/qt/5.6.1/clang_64/lib/cmake/
|
||||
export QT_CMAKE_PREFIX_PATH=/usr/local/Cellar/qt5/5.6.1-1/lib/cmake
|
||||
export QT_CMAKE_PREFIX_PATH=/usr/local/opt/qt5/lib/cmake
|
||||
|
||||
####Generating build files
|
||||
|
@ -65,7 +65,7 @@ Any variables that need to be set for CMake to find dependencies can be set as E
|
|||
|
||||
For example, to pass the QT_CMAKE_PREFIX_PATH variable during build file generation:
|
||||
|
||||
cmake .. -DQT_CMAKE_PREFIX_PATH=/usr/local/qt/5.5.1/lib/cmake
|
||||
cmake .. -DQT_CMAKE_PREFIX_PATH=/usr/local/qt/5.6.1/lib/cmake
|
||||
|
||||
####Finding Dependencies
|
||||
|
||||
|
|
26
BUILD_OSX.md
26
BUILD_OSX.md
|
@ -1,25 +1,31 @@
|
|||
Please read the [general build guide](BUILD.md) for information on dependencies required for all platforms. Only OS X specific instructions are found in this file.
|
||||
|
||||
###Homebrew
|
||||
[Homebrew](http://brew.sh/) is an excellent package manager for OS X. It makes install of all High Fidelity dependencies very simple.
|
||||
[Homebrew](http://brew.sh/) is an excellent package manager for OS X. It makes install of some High Fidelity dependencies very simple.
|
||||
|
||||
brew tap homebrew/versions
|
||||
brew install cmake openssl qt55
|
||||
brew install cmake openssl
|
||||
|
||||
We no longer require install of qt5 via our [homebrew formulas repository](https://github.com/highfidelity/homebrew-formulas). Versions of Qt that are 5.5.x provide a mechanism to disable the wireless scanning we previously had a custom patch for.
|
||||
###OpenSSL
|
||||
|
||||
###OpenSSL and Qt
|
||||
|
||||
Assuming you've installed OpenSSL or Qt 5 using the homebrew instructions above, you'll need to set OPENSSL_ROOT_DIR and QT_CMAKE_PREFIX_PATH so CMake can find your installations.
|
||||
Assuming you've installed OpenSSL using the homebrew instructions above, you'll need to set OPENSSL_ROOT_DIR so CMake can find your installations.
|
||||
For OpenSSL installed via homebrew, set OPENSSL_ROOT_DIR:
|
||||
|
||||
export OPENSSL_ROOT_DIR=/usr/local/Cellar/openssl/1.0.2h_1/
|
||||
|
||||
For Qt 5.5.1 installed via homebrew, set QT_CMAKE_PREFIX_PATH as follows.
|
||||
|
||||
export QT_CMAKE_PREFIX_PATH=/usr/local/Cellar/qt55/5.5.1/lib/cmake
|
||||
Note that this uses the version from the homebrew formula at the time of this writing, and the version in the path will likely change.
|
||||
|
||||
Note that these use the versions from homebrew formulae at the time of this writing, and the version in the path will likely change.
|
||||
###Qt
|
||||
You can use the online installer or the offline installer.
|
||||
|
||||
* [Download the online installer](http://www.qt.io/download-open-source/#section-2)
|
||||
* When it asks you to select components, select the following:
|
||||
* Qt > Qt 5.6
|
||||
|
||||
* [Download the offline installer](http://download.qt.io/official_releases/qt/5.6/5.6.1-1/qt-opensource-mac-x64-clang-5.6.1-1.dmg)
|
||||
|
||||
Once Qt is installed, you need to manually configure the following:
|
||||
* Set the QT_CMAKE_PREFIX_PATH environment variable to your `Qt5.6.1/5.6/clang_64/lib/cmake/` directory.
|
||||
|
||||
###Xcode
|
||||
If Xcode is your editor of choice, you can ask CMake to generate Xcode project files instead of Unix Makefiles.
|
||||
|
|
12
BUILD_WIN.md
12
BUILD_WIN.md
|
@ -27,17 +27,17 @@ We expect nmake.exe to be located at the following path.
|
|||
###Qt
|
||||
You can use the online installer or the offline installer. If you use the offline installer, be sure to select the "OpenGL" version.
|
||||
|
||||
* [Download the online installer](http://qt-project.org/downloads)
|
||||
* [Download the online installer](http://www.qt.io/download-open-source/#section-2)
|
||||
* When it asks you to select components, ONLY select one of the following, 32- or 64-bit to match your build preference:
|
||||
* Qt > Qt 5.5.1 > **msvc2013 32-bit**
|
||||
* Qt > Qt 5.5.1 > **msvc2013 64-bit**
|
||||
* Qt > Qt 5.6.1 > **msvc2013 32-bit**
|
||||
* Qt > Qt 5.6.1 > **msvc2013 64-bit**
|
||||
|
||||
* Download the offline installer, 32- or 64-bit to match your build preference:
|
||||
* [32-bit](http://download.qt.io/official_releases/qt/5.5/5.5.1/qt-opensource-windows-x86-msvc2013-5.5.1.exe)
|
||||
* [64-bit](http://download.qt.io/official_releases/qt/5.5/5.5.1/qt-opensource-windows-x86-msvc2013_64-5.5.1.exe)
|
||||
* [32-bit](http://download.qt.io/official_releases/qt/5.6/5.6.1-1/qt-opensource-windows-x86-msvc2013-5.6.1-1.exe)
|
||||
* [64-bit](http://download.qt.io/official_releases/qt/5.6/5.6.1-1/qt-opensource-windows-x86-msvc2013_64-5.6.1-1.exe)
|
||||
|
||||
Once Qt is installed, you need to manually configure the following:
|
||||
* Set the QT_CMAKE_PREFIX_PATH environment variable to your `Qt\5.5.1\msvc2013\lib\cmake` or `Qt\5.5.1\msvc2013_64\lib\cmake` directory.
|
||||
* Set the QT_CMAKE_PREFIX_PATH environment variable to your `Qt\5.6.1\msvc2013\lib\cmake` or `Qt\5.6.1\msvc2013_64\lib\cmake` directory.
|
||||
* You can set an environment variable from Control Panel > System > Advanced System Settings > Environment Variables > New
|
||||
|
||||
###External Libraries
|
||||
|
|
|
@ -2,6 +2,11 @@ set(TARGET_NAME assignment-client)
|
|||
|
||||
setup_hifi_project(Core Gui Network Script Quick Widgets WebSockets)
|
||||
|
||||
# Fix up the rpath so macdeployqt works
|
||||
if (APPLE)
|
||||
set_target_properties(${TARGET_NAME} PROPERTIES INSTALL_RPATH "@executable_path/../Frameworks")
|
||||
endif ()
|
||||
|
||||
# link in the shared libraries
|
||||
link_hifi_libraries(
|
||||
audio avatars octree gpu model fbx entities
|
||||
|
|
|
@ -16,26 +16,6 @@ macro(fixup_interface)
|
|||
string(REPLACE " " "\\ " ESCAPED_INSTALL_PATH ${INTERFACE_INSTALL_DIR})
|
||||
set(_INTERFACE_INSTALL_PATH "${ESCAPED_INSTALL_PATH}/${ESCAPED_BUNDLE_NAME}.app")
|
||||
|
||||
# install QtWebProcess from Qt to the application bundle
|
||||
# since it is missed by macdeployqt
|
||||
# https://bugreports.qt.io/browse/QTBUG-35211
|
||||
set(LIBEXEC_PATH "${_INTERFACE_INSTALL_PATH}/Contents/libexec")
|
||||
install(
|
||||
PROGRAMS "${QT_DIR}/libexec/QtWebProcess"
|
||||
DESTINATION ${LIBEXEC_PATH}
|
||||
COMPONENT ${CLIENT_COMPONENT}
|
||||
)
|
||||
|
||||
set(QTWEBPROCESS_PATH "\${CMAKE_INSTALL_PREFIX}/${LIBEXEC_PATH}")
|
||||
|
||||
# we also need a qt.conf in the directory of QtWebProcess
|
||||
install(CODE "
|
||||
file(WRITE ${QTWEBPROCESS_PATH}/qt.conf
|
||||
\"[Paths]\nPlugins = ../PlugIns\nImports = ../Resources/qml\nQml2Imports = ../Resources/qml\"
|
||||
)"
|
||||
COMPONENT ${CLIENT_COMPONENT}
|
||||
)
|
||||
|
||||
find_program(MACDEPLOYQT_COMMAND macdeployqt PATHS "${QT_DIR}/bin" NO_DEFAULT_PATH)
|
||||
|
||||
if (NOT MACDEPLOYQT_COMMAND AND (PRODUCTION_BUILD OR PR_BUILD))
|
||||
|
@ -49,7 +29,6 @@ macro(fixup_interface)
|
|||
execute_process(COMMAND ${MACDEPLOYQT_COMMAND}\
|
||||
\${CMAKE_INSTALL_PREFIX}/${_INTERFACE_INSTALL_PATH}/\
|
||||
-verbose=2 -qmldir=${CMAKE_SOURCE_DIR}/interface/resources/qml/\
|
||||
-executable=\${CMAKE_INSTALL_PREFIX}/${_INTERFACE_INSTALL_PATH}/Contents/libexec/QtWebProcess\
|
||||
)"
|
||||
COMPONENT ${CLIENT_COMPONENT}
|
||||
)
|
||||
|
|
|
@ -59,7 +59,12 @@ macro(install_beside_console)
|
|||
set(EXECUTABLE_NEEDING_FIXUP "\${CMAKE_INSTALL_PREFIX}/${COMPONENT_INSTALL_DIR}/${TARGET_NAME}")
|
||||
string(REPLACE " " "\\ " ESCAPED_EXECUTABLE_NAME ${EXECUTABLE_NEEDING_FIXUP})
|
||||
|
||||
# configure Info.plist for COMPONENT_APP
|
||||
install(CODE "
|
||||
set(MACOSX_BUNDLE_EXECUTABLE_NAME domain-server)
|
||||
set(MACOSX_BUNDLE_GUI_IDENTIFIER com.highfidelity.server-components)
|
||||
set(MACOSX_BUNDLE_BUNDLE_NAME Sandbox\\ Components)
|
||||
configure_file(${HF_CMAKE_DIR}/templates/MacOSXBundleSandboxComponentsInfo.plist.in ${ESCAPED_BUNDLE_NAME}/Contents/Info.plist)
|
||||
execute_process(COMMAND ${MACDEPLOYQT_COMMAND} ${ESCAPED_BUNDLE_NAME} -verbose=2 -executable=${ESCAPED_EXECUTABLE_NAME})"
|
||||
COMPONENT ${SERVER_COMPONENT}
|
||||
)
|
||||
|
|
36
cmake/templates/MacOSXBundleSandboxComponentsInfo.plist.in
Normal file
36
cmake/templates/MacOSXBundleSandboxComponentsInfo.plist.in
Normal file
|
@ -0,0 +1,36 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>CFBundleDevelopmentRegion</key>
|
||||
<string>English</string>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>${MACOSX_BUNDLE_EXECUTABLE_NAME}</string>
|
||||
<key>CFBundleGetInfoString</key>
|
||||
<string>${MACOSX_BUNDLE_INFO_STRING}</string>
|
||||
<key>CFBundleIconFile</key>
|
||||
<string>${MACOSX_BUNDLE_ICON_FILE}</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>${MACOSX_BUNDLE_GUI_IDENTIFIER}</string>
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>6.0</string>
|
||||
<key>CFBundleLongVersionString</key>
|
||||
<string>${MACOSX_BUNDLE_LONG_VERSION_STRING}</string>
|
||||
<key>CFBundleName</key>
|
||||
<string>${MACOSX_BUNDLE_BUNDLE_NAME}</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>APPL</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>${MACOSX_BUNDLE_SHORT_VERSION_STRING}</string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>????</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>${MACOSX_BUNDLE_BUNDLE_VERSION}</string>
|
||||
<key>CSResourcesFileMapped</key>
|
||||
<true/>
|
||||
<key>LSRequiresCarbon</key>
|
||||
<true/>
|
||||
<key>NSHumanReadableCopyright</key>
|
||||
<string>${MACOSX_BUNDLE_COPYRIGHT}</string>
|
||||
</dict>
|
||||
</plist>
|
|
@ -9,6 +9,11 @@ endif ()
|
|||
# setup the project and link required Qt modules
|
||||
setup_hifi_project(Network)
|
||||
|
||||
# Fix up the rpath so macdeployqt works
|
||||
if (APPLE)
|
||||
set_target_properties(${TARGET_NAME} PROPERTIES INSTALL_RPATH "@executable_path/../Frameworks")
|
||||
endif ()
|
||||
|
||||
# TODO: find a solution that will handle web file changes in resources on windows without a re-build.
|
||||
# Currently the resources are only copied on post-build. If one is changed but the domain-server is not, they will
|
||||
# not be re-copied. This is worked-around on OS X/UNIX by using a symlink.
|
||||
|
|
|
@ -1756,6 +1756,7 @@ bool DomainServer::handleHTTPSRequest(HTTPSConnection* connection, const QUrl &u
|
|||
.arg(authorizationCode, oauthRedirectURL().toString(), _oauthClientID, _oauthClientSecret);
|
||||
|
||||
QNetworkRequest tokenRequest(tokenRequestUrl);
|
||||
tokenRequest.setAttribute(QNetworkRequest::FollowRedirectsAttribute, true);
|
||||
tokenRequest.setHeader(QNetworkRequest::UserAgentHeader, HIGH_FIDELITY_USER_AGENT);
|
||||
tokenRequest.setHeader(QNetworkRequest::ContentTypeHeader, "application/x-www-form-urlencoded");
|
||||
|
||||
|
@ -1949,6 +1950,7 @@ QNetworkReply* DomainServer::profileRequestGivenTokenReply(QNetworkReply* tokenR
|
|||
profileURL.setQuery(QString("%1=%2").arg(OAUTH_JSON_ACCESS_TOKEN_KEY, accessToken));
|
||||
|
||||
QNetworkRequest profileRequest(profileURL);
|
||||
profileRequest.setAttribute(QNetworkRequest::FollowRedirectsAttribute, true);
|
||||
profileRequest.setHeader(QNetworkRequest::UserAgentHeader, HIGH_FIDELITY_USER_AGENT);
|
||||
return NetworkAccessManager::getInstance().get(profileRequest);
|
||||
}
|
||||
|
|
|
@ -213,6 +213,7 @@ void IceServer::requestDomainPublicKey(const QUuid& domainID) {
|
|||
publicKeyURL.setPath(publicKeyPath);
|
||||
|
||||
QNetworkRequest publicKeyRequest { publicKeyURL };
|
||||
publicKeyRequest.setAttribute(QNetworkRequest::FollowRedirectsAttribute, true);
|
||||
publicKeyRequest.setAttribute(QNetworkRequest::User, domainID);
|
||||
|
||||
qDebug() << "Requesting public key for domain with ID" << domainID;
|
||||
|
|
|
@ -42,12 +42,12 @@ endif ()
|
|||
if (ANDROID)
|
||||
set(PLATFORM_QT_COMPONENTS AndroidExtras)
|
||||
else ()
|
||||
set(PLATFORM_QT_COMPONENTS WebEngine WebEngineWidgets WebKitWidgets)
|
||||
set(PLATFORM_QT_COMPONENTS WebEngine WebEngineWidgets)
|
||||
endif ()
|
||||
|
||||
find_package(
|
||||
Qt5 COMPONENTS
|
||||
Gui Multimedia Network OpenGL Qml Quick Script ScriptTools Svg
|
||||
Gui Multimedia Network OpenGL Qml Quick Script Svg
|
||||
${PLATFORM_QT_COMPONENTS}
|
||||
WebChannel WebSockets
|
||||
)
|
||||
|
@ -123,7 +123,8 @@ if (APPLE)
|
|||
add_executable(${TARGET_NAME} MACOSX_BUNDLE ${INTERFACE_SRCS} ${QM})
|
||||
|
||||
# make sure the output name for the .app bundle is correct
|
||||
set_target_properties(${TARGET_NAME} PROPERTIES OUTPUT_NAME ${INTERFACE_BUNDLE_NAME})
|
||||
# Fix up the rpath so macdeployqt works
|
||||
set_target_properties(${TARGET_NAME} PROPERTIES INSTALL_RPATH "@executable_path/../Frameworks")
|
||||
elseif (WIN32)
|
||||
# configure an rc file for the chosen icon
|
||||
set(CONFIGURE_ICON_PATH "${CMAKE_CURRENT_SOURCE_DIR}/icon/${INTERFACE_ICON_FILENAME}")
|
||||
|
@ -241,16 +242,10 @@ include_directories("${PROJECT_SOURCE_DIR}/src")
|
|||
target_link_libraries(
|
||||
${TARGET_NAME}
|
||||
Qt5::Gui Qt5::Network Qt5::Multimedia Qt5::OpenGL
|
||||
Qt5::Qml Qt5::Quick Qt5::Script Qt5::ScriptTools Qt5::Svg
|
||||
Qt5::WebChannel Qt5::WebEngine Qt5::WebEngineWidgets Qt5::WebKitWidgets
|
||||
Qt5::Qml Qt5::Quick Qt5::Script Qt5::Svg
|
||||
Qt5::WebChannel Qt5::WebEngine
|
||||
)
|
||||
|
||||
# Issue causes build failure unless we add this directory.
|
||||
# See https://bugreports.qt.io/browse/QTBUG-43351
|
||||
if (WIN32)
|
||||
add_paths_to_fixup_libs(${Qt5_DIR}/../../../plugins/qtwebengine)
|
||||
endif()
|
||||
|
||||
if (UNIX)
|
||||
target_link_libraries(${TARGET_NAME} pthread)
|
||||
endif(UNIX)
|
||||
|
|
|
@ -223,12 +223,12 @@ ScrollingWindow {
|
|||
var newWindow = component.createObject(desktop);
|
||||
request.openIn(newWindow.webView)
|
||||
}
|
||||
Component.onCompleted: {
|
||||
desktop.initWebviewProfileHandlers(webview.profile)
|
||||
}
|
||||
|
||||
|
||||
//profile: desktop.browserProfile
|
||||
Component.onCompleted: {
|
||||
desktop.initWebviewProfileHandlers(webview.profile)
|
||||
}
|
||||
|
||||
profile: desktop.browserProfile
|
||||
}
|
||||
|
||||
} // item
|
||||
|
@ -245,4 +245,4 @@ ScrollingWindow {
|
|||
break;
|
||||
}
|
||||
}
|
||||
} // dialog
|
||||
} // dialog
|
||||
|
|
|
@ -5,7 +5,7 @@ WebEngineView {
|
|||
id: root
|
||||
property var newUrl;
|
||||
|
||||
profile.httpUserAgent: "Mozilla/5.0 Chrome (HighFidelityInterface)"
|
||||
profile: desktop.browserProfile
|
||||
|
||||
Component.onCompleted: {
|
||||
console.log("Connecting JS messaging to Hifi Logging")
|
||||
|
@ -13,7 +13,6 @@ WebEngineView {
|
|||
root.javaScriptConsoleMessage.connect(function(level, message, lineNumber, sourceID) {
|
||||
console.log("Web Window JS message: " + sourceID + " " + lineNumber + " " + message);
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
// FIXME hack to get the URL with the auth token included. Remove when we move to Qt 5.6
|
||||
|
@ -61,8 +60,4 @@ WebEngineView {
|
|||
request.openIn(newWindow.webView);
|
||||
}
|
||||
}
|
||||
|
||||
// This breaks the webchannel used for passing messages. Fixed in Qt 5.6
|
||||
// See https://bugreports.qt.io/browse/QTBUG-49521
|
||||
//profile: desktop.browserProfile
|
||||
}
|
||||
|
|
|
@ -52,7 +52,7 @@ ModalWindow {
|
|||
// Set from OffscreenUi::getOpenFile()
|
||||
property int options; // <-- FIXME unused
|
||||
|
||||
property string iconText: text !== "" ? hifi.glyphs.scriptUpload : ""
|
||||
property string iconText: root.title !== "" ? hifi.glyphs.scriptUpload : ""
|
||||
property int iconSize: 40
|
||||
|
||||
property bool selectDirectory: false;
|
||||
|
|
|
@ -89,6 +89,7 @@ Rectangle {
|
|||
property int dropSamples: 9;
|
||||
property int dropSpread: 0;
|
||||
DropShadow {
|
||||
visible: desktop.gradientsSupported;
|
||||
source: place;
|
||||
anchors.fill: place;
|
||||
horizontalOffset: dropHorizontalOffset;
|
||||
|
@ -99,6 +100,7 @@ Rectangle {
|
|||
spread: dropSpread;
|
||||
}
|
||||
DropShadow {
|
||||
visible: desktop.gradientsSupported;
|
||||
source: users;
|
||||
anchors.fill: users;
|
||||
horizontalOffset: dropHorizontalOffset;
|
||||
|
|
|
@ -109,7 +109,7 @@ Decoration {
|
|||
verticalOffset: 2
|
||||
samples: 2
|
||||
color: hifi.colors.baseGrayShadow60
|
||||
visible: (window && window.focus)
|
||||
visible: (desktop.gradientsSupported && window && window.focus)
|
||||
cached: true
|
||||
}
|
||||
}
|
||||
|
|
|
@ -133,7 +133,6 @@
|
|||
#include "scripting/LocationScriptingInterface.h"
|
||||
#include "scripting/MenuScriptingInterface.h"
|
||||
#include "scripting/SettingsScriptingInterface.h"
|
||||
#include "scripting/WebWindowClass.h"
|
||||
#include "scripting/WindowScriptingInterface.h"
|
||||
#include "scripting/ControllerScriptingInterface.h"
|
||||
#include "scripting/ToolbarScriptingInterface.h"
|
||||
|
@ -176,8 +175,6 @@ static const int MAX_CONCURRENT_RESOURCE_DOWNLOADS = 16;
|
|||
// For processing on QThreadPool, target 2 less than the ideal number of threads, leaving
|
||||
// 2 logical cores available for time sensitive tasks.
|
||||
static const int MIN_PROCESSING_THREAD_POOL_SIZE = 2;
|
||||
static const int PROCESSING_THREAD_POOL_SIZE = std::max(MIN_PROCESSING_THREAD_POOL_SIZE,
|
||||
QThread::idealThreadCount() - 2);
|
||||
|
||||
static const QString SNAPSHOT_EXTENSION = ".jpg";
|
||||
static const QString SVO_EXTENSION = ".svo";
|
||||
|
@ -537,7 +534,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer) :
|
|||
PluginContainer* pluginContainer = dynamic_cast<PluginContainer*>(this); // set the container for any plugins that care
|
||||
PluginManager::getInstance()->setContainer(pluginContainer);
|
||||
|
||||
QThreadPool::globalInstance()->setMaxThreadCount(PROCESSING_THREAD_POOL_SIZE);
|
||||
QThreadPool::globalInstance()->setMaxThreadCount(MIN_PROCESSING_THREAD_POOL_SIZE);
|
||||
thread()->setPriority(QThread::HighPriority);
|
||||
thread()->setObjectName("Main Thread");
|
||||
|
||||
|
@ -707,6 +704,8 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer) :
|
|||
connect(addressManager.data(), &AddressManager::hostChanged, this, &Application::updateWindowTitle);
|
||||
connect(this, &QCoreApplication::aboutToQuit, addressManager.data(), &AddressManager::storeCurrentAddress);
|
||||
|
||||
connect(this, &Application::activeDisplayPluginChanged, this, &Application::updateThreadPoolCount);
|
||||
|
||||
// Save avatar location immediately after a teleport.
|
||||
connect(getMyAvatar(), &MyAvatar::positionGoneTo,
|
||||
DependencyManager::get<AddressManager>().data(), &AddressManager::storeCurrentAddress);
|
||||
|
@ -4858,7 +4857,6 @@ void Application::registerScriptEngineWithApplicationServices(ScriptEngine* scri
|
|||
scriptEngine->registerGetterSetter("location", LocationScriptingInterface::locationGetter,
|
||||
LocationScriptingInterface::locationSetter);
|
||||
|
||||
scriptEngine->registerFunction("WebWindow", WebWindowClass::constructor, 1);
|
||||
scriptEngine->registerFunction("OverlayWebWindow", QmlWebWindowClass::constructor);
|
||||
scriptEngine->registerFunction("OverlayWindow", QmlWindowClass::constructor);
|
||||
|
||||
|
@ -5034,6 +5032,7 @@ bool Application::askToLoadScript(const QString& scriptFilenameOrURL) {
|
|||
bool Application::askToWearAvatarAttachmentUrl(const QString& url) {
|
||||
QNetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance();
|
||||
QNetworkRequest networkRequest = QNetworkRequest(url);
|
||||
networkRequest.setAttribute(QNetworkRequest::FollowRedirectsAttribute, true);
|
||||
networkRequest.setHeader(QNetworkRequest::UserAgentHeader, HIGH_FIDELITY_USER_AGENT);
|
||||
QNetworkReply* reply = networkAccessManager.get(networkRequest);
|
||||
int requestNumber = ++_avatarAttachmentRequest;
|
||||
|
@ -5727,3 +5726,18 @@ void Application::sendHoverLeaveEntity(QUuid id, PointerEvent event) {
|
|||
EntityItemID entityItemID(id);
|
||||
emit getEntities()->hoverLeaveEntity(entityItemID, event);
|
||||
}
|
||||
|
||||
// FIXME? perhaps two, one for the main thread and one for the offscreen UI rendering thread?
|
||||
static const int UI_RESERVED_THREADS = 1;
|
||||
// Windows won't let you have all the cores
|
||||
static const int OS_RESERVED_THREADS = 1;
|
||||
|
||||
void Application::updateThreadPoolCount() const {
|
||||
auto reservedThreads = UI_RESERVED_THREADS + OS_RESERVED_THREADS + _displayPlugin->getRequiredThreadCount();
|
||||
auto availableThreads = QThread::idealThreadCount() - reservedThreads;
|
||||
auto threadPoolSize = std::max(MIN_PROCESSING_THREAD_POOL_SIZE, availableThreads);
|
||||
qDebug() << "Ideal Thread Count " << QThread::idealThreadCount();
|
||||
qDebug() << "Reserved threads " << reservedThreads;
|
||||
qDebug() << "Setting thread pool size to " << threadPoolSize;
|
||||
QThreadPool::globalInstance()->setMaxThreadCount(threadPoolSize);
|
||||
}
|
||||
|
|
|
@ -286,6 +286,7 @@ public slots:
|
|||
bool exportEntities(const QString& filename, const QVector<EntityItemID>& entityIDs, const glm::vec3* givenOffset = nullptr);
|
||||
bool exportEntities(const QString& filename, float x, float y, float z, float scale);
|
||||
bool importEntities(const QString& url);
|
||||
void updateThreadPoolCount() const;
|
||||
|
||||
static void setLowVelocityFilter(bool lowVelocityFilter);
|
||||
Q_INVOKABLE void loadDialog();
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
#include <avatar/AvatarActionHold.h>
|
||||
#include <ObjectActionOffset.h>
|
||||
#include <ObjectActionSpring.h>
|
||||
#include <ObjectActionTravelOriented.h>
|
||||
#include <LogHandler.h>
|
||||
|
||||
#include "InterfaceActionFactory.h"
|
||||
|
@ -29,6 +30,8 @@ EntityActionPointer interfaceActionFactory(EntityActionType type, const QUuid& i
|
|||
return std::make_shared<ObjectActionSpring>(id, ownerEntity);
|
||||
case ACTION_TYPE_HOLD:
|
||||
return std::make_shared<AvatarActionHold>(id, ownerEntity);
|
||||
case ACTION_TYPE_TRAVEL_ORIENTED:
|
||||
return std::make_shared<ObjectActionTravelOriented>(id, ownerEntity);
|
||||
}
|
||||
|
||||
Q_ASSERT_X(false, Q_FUNC_INFO, "Unknown entity action type");
|
||||
|
|
|
@ -59,8 +59,6 @@ const float DISPLAYNAME_ALPHA = 1.0f;
|
|||
const float DISPLAYNAME_BACKGROUND_ALPHA = 0.4f;
|
||||
const glm::vec3 HAND_TO_PALM_OFFSET(0.0f, 0.12f, 0.08f);
|
||||
|
||||
const int SENSOR_TO_WORLD_MATRIX_INDEX = 65534;
|
||||
|
||||
namespace render {
|
||||
template <> const ItemKey payloadGetKey(const AvatarSharedPointer& avatar) {
|
||||
return ItemKey::Builder::opaqueShape();
|
||||
|
@ -853,32 +851,54 @@ glm::vec3 Avatar::getDefaultJointTranslation(int index) const {
|
|||
}
|
||||
|
||||
glm::quat Avatar::getAbsoluteJointRotationInObjectFrame(int index) const {
|
||||
if (index == SENSOR_TO_WORLD_MATRIX_INDEX) {
|
||||
glm::mat4 sensorToWorldMatrix = getSensorToWorldMatrix();
|
||||
bool success;
|
||||
Transform avatarTransform;
|
||||
Transform::mult(avatarTransform, getParentTransform(success), getLocalTransform());
|
||||
glm::mat4 invAvatarMat = avatarTransform.getInverseMatrix();
|
||||
return glmExtractRotation(invAvatarMat * sensorToWorldMatrix);
|
||||
} else {
|
||||
glm::quat rotation;
|
||||
_skeletonModel->getAbsoluteJointRotationInRigFrame(index, rotation);
|
||||
return Quaternions::Y_180 * rotation;
|
||||
switch(index) {
|
||||
case SENSOR_TO_WORLD_MATRIX_INDEX: {
|
||||
glm::mat4 sensorToWorldMatrix = getSensorToWorldMatrix();
|
||||
bool success;
|
||||
Transform avatarTransform;
|
||||
Transform::mult(avatarTransform, getParentTransform(success), getLocalTransform());
|
||||
glm::mat4 invAvatarMat = avatarTransform.getInverseMatrix();
|
||||
return glmExtractRotation(invAvatarMat * sensorToWorldMatrix);
|
||||
}
|
||||
case CONTROLLER_LEFTHAND_INDEX: {
|
||||
Transform controllerLeftHandTransform = Transform(getControllerLeftHandMatrix());
|
||||
return controllerLeftHandTransform.getRotation();
|
||||
}
|
||||
case CONTROLLER_RIGHTHAND_INDEX: {
|
||||
Transform controllerRightHandTransform = Transform(getControllerRightHandMatrix());
|
||||
return controllerRightHandTransform.getRotation();
|
||||
}
|
||||
default: {
|
||||
glm::quat rotation;
|
||||
_skeletonModel->getAbsoluteJointRotationInRigFrame(index, rotation);
|
||||
return Quaternions::Y_180 * rotation;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
glm::vec3 Avatar::getAbsoluteJointTranslationInObjectFrame(int index) const {
|
||||
if (index == SENSOR_TO_WORLD_MATRIX_INDEX) {
|
||||
glm::mat4 sensorToWorldMatrix = getSensorToWorldMatrix();
|
||||
bool success;
|
||||
Transform avatarTransform;
|
||||
Transform::mult(avatarTransform, getParentTransform(success), getLocalTransform());
|
||||
glm::mat4 invAvatarMat = avatarTransform.getInverseMatrix();
|
||||
return extractTranslation(invAvatarMat * sensorToWorldMatrix);
|
||||
} else {
|
||||
glm::vec3 translation;
|
||||
_skeletonModel->getAbsoluteJointTranslationInRigFrame(index, translation);
|
||||
return Quaternions::Y_180 * translation;
|
||||
switch(index) {
|
||||
case SENSOR_TO_WORLD_MATRIX_INDEX: {
|
||||
glm::mat4 sensorToWorldMatrix = getSensorToWorldMatrix();
|
||||
bool success;
|
||||
Transform avatarTransform;
|
||||
Transform::mult(avatarTransform, getParentTransform(success), getLocalTransform());
|
||||
glm::mat4 invAvatarMat = avatarTransform.getInverseMatrix();
|
||||
return extractTranslation(invAvatarMat * sensorToWorldMatrix);
|
||||
}
|
||||
case CONTROLLER_LEFTHAND_INDEX: {
|
||||
Transform controllerLeftHandTransform = Transform(getControllerLeftHandMatrix());
|
||||
return controllerLeftHandTransform.getTranslation();
|
||||
}
|
||||
case CONTROLLER_RIGHTHAND_INDEX: {
|
||||
Transform controllerRightHandTransform = Transform(getControllerRightHandMatrix());
|
||||
return controllerRightHandTransform.getTranslation();
|
||||
}
|
||||
default: {
|
||||
glm::vec3 translation;
|
||||
_skeletonModel->getAbsoluteJointTranslationInRigFrame(index, translation);
|
||||
return Quaternions::Y_180 * translation;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -889,6 +909,10 @@ int Avatar::getJointIndex(const QString& name) const {
|
|||
Q_RETURN_ARG(int, result), Q_ARG(const QString&, name));
|
||||
return result;
|
||||
}
|
||||
int result = getFauxJointIndex(name);
|
||||
if (result != -1) {
|
||||
return result;
|
||||
}
|
||||
return _skeletonModel->isActive() ? _skeletonModel->getFBXGeometry().getJointIndex(name) : -1;
|
||||
}
|
||||
|
||||
|
|
|
@ -56,6 +56,10 @@ void AvatarActionHold::prepareForPhysicsSimulation() {
|
|||
}
|
||||
|
||||
withWriteLock([&]{
|
||||
glm::vec3 avatarRigidBodyPosition;
|
||||
glm::quat avatarRigidBodyRotation;
|
||||
getAvatarRigidBodyLocation(avatarRigidBodyPosition, avatarRigidBodyRotation);
|
||||
|
||||
if (_ignoreIK) {
|
||||
return;
|
||||
}
|
||||
|
@ -70,9 +74,6 @@ void AvatarActionHold::prepareForPhysicsSimulation() {
|
|||
palmRotation = holdingAvatar->getUncachedLeftPalmRotation();
|
||||
}
|
||||
|
||||
glm::vec3 avatarRigidBodyPosition;
|
||||
glm::quat avatarRigidBodyRotation;
|
||||
getAvatarRigidBodyLocation(avatarRigidBodyPosition, avatarRigidBodyRotation);
|
||||
|
||||
// determine the difference in translation and rotation between the avatar's
|
||||
// rigid body and the palm position. The avatar's rigid body will be moved by bullet
|
||||
|
@ -124,13 +125,20 @@ bool AvatarActionHold::getTarget(float deltaTimeStep, glm::quat& rotation, glm::
|
|||
if (pose.isValid()) {
|
||||
linearVelocity = pose.getVelocity();
|
||||
angularVelocity = pose.getAngularVelocity();
|
||||
|
||||
if (isRightHand) {
|
||||
pose = avatarManager->getMyAvatar()->getRightHandControllerPoseInAvatarFrame();
|
||||
} else {
|
||||
pose = avatarManager->getMyAvatar()->getLeftHandControllerPoseInAvatarFrame();
|
||||
}
|
||||
}
|
||||
|
||||
if (_ignoreIK && pose.isValid()) {
|
||||
// We cannot ignore other avatars IK and this is not the point of this option
|
||||
// This is meant to make the grabbing behavior more reactive.
|
||||
palmPosition = pose.getTranslation();
|
||||
palmRotation = pose.getRotation();
|
||||
Transform avatarTransform;
|
||||
auto myAvatar = DependencyManager::get<AvatarManager>()->getMyAvatar();
|
||||
avatarTransform = myAvatar->getTransform();
|
||||
palmPosition = avatarTransform.transform(pose.getTranslation() / myAvatar->getTargetScale());
|
||||
palmRotation = avatarTransform.getRotation() * pose.getRotation();
|
||||
} else {
|
||||
glm::vec3 avatarRigidBodyPosition;
|
||||
glm::quat avatarRigidBodyRotation;
|
||||
|
@ -159,11 +167,17 @@ bool AvatarActionHold::getTarget(float deltaTimeStep, glm::quat& rotation, glm::
|
|||
}
|
||||
} else { // regular avatar
|
||||
if (isRightHand) {
|
||||
palmPosition = holdingAvatar->getRightPalmPosition();
|
||||
palmRotation = holdingAvatar->getRightPalmRotation();
|
||||
Transform controllerRightTransform = Transform(holdingAvatar->getControllerRightHandMatrix());
|
||||
Transform avatarTransform = holdingAvatar->getTransform();
|
||||
palmRotation = avatarTransform.getRotation() * controllerRightTransform.getRotation();
|
||||
palmPosition = avatarTransform.getTranslation() +
|
||||
(avatarTransform.getRotation() * controllerRightTransform.getTranslation());
|
||||
} else {
|
||||
palmPosition = holdingAvatar->getLeftPalmPosition();
|
||||
palmRotation = holdingAvatar->getLeftPalmRotation();
|
||||
Transform controllerLeftTransform = Transform(holdingAvatar->getControllerLeftHandMatrix());
|
||||
Transform avatarTransform = holdingAvatar->getTransform();
|
||||
palmRotation = avatarTransform.getRotation() * controllerLeftTransform.getRotation();
|
||||
palmPosition = avatarTransform.getTranslation() +
|
||||
(avatarTransform.getRotation() * controllerLeftTransform.getTranslation());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -532,11 +532,21 @@ void MyAvatar::updateFromHMDSensorMatrix(const glm::mat4& hmdSensorMatrix) {
|
|||
_hmdSensorFacing = getFacingDir2D(_hmdSensorOrientation);
|
||||
}
|
||||
|
||||
void MyAvatar::updateJointFromController(controller::Action poseKey, ThreadSafeValueCache<glm::mat4>& matrixCache) {
|
||||
assert(QThread::currentThread() == thread());
|
||||
auto userInputMapper = DependencyManager::get<UserInputMapper>();
|
||||
controller::Pose controllerPose = userInputMapper->getPoseState(poseKey);
|
||||
Transform transform;
|
||||
transform.setTranslation(controllerPose.getTranslation());
|
||||
transform.setRotation(controllerPose.getRotation());
|
||||
glm::mat4 controllerMatrix = transform.getMatrix();
|
||||
matrixCache.set(controllerMatrix);
|
||||
}
|
||||
|
||||
// best called at end of main loop, after physics.
|
||||
// update sensor to world matrix from current body position and hmd sensor.
|
||||
// This is so the correct camera can be used for rendering.
|
||||
void MyAvatar::updateSensorToWorldMatrix() {
|
||||
|
||||
// update the sensor mat so that the body position will end up in the desired
|
||||
// position when driven from the head.
|
||||
glm::mat4 desiredMat = createMatFromQuatAndPos(getOrientation(), getPosition());
|
||||
|
@ -545,10 +555,14 @@ void MyAvatar::updateSensorToWorldMatrix() {
|
|||
lateUpdatePalms();
|
||||
|
||||
if (_enableDebugDrawSensorToWorldMatrix) {
|
||||
DebugDraw::getInstance().addMarker("sensorToWorldMatrix", glmExtractRotation(_sensorToWorldMatrix), extractTranslation(_sensorToWorldMatrix), glm::vec4(1));
|
||||
DebugDraw::getInstance().addMarker("sensorToWorldMatrix", glmExtractRotation(_sensorToWorldMatrix),
|
||||
extractTranslation(_sensorToWorldMatrix), glm::vec4(1));
|
||||
}
|
||||
|
||||
_sensorToWorldMatrixCache.set(_sensorToWorldMatrix);
|
||||
|
||||
updateJointFromController(controller::Action::LEFT_HAND, _controllerLeftHandMatrixCache);
|
||||
updateJointFromController(controller::Action::RIGHT_HAND, _controllerRightHandMatrixCache);
|
||||
}
|
||||
|
||||
// Update avatar head rotation with sensor data
|
||||
|
@ -2215,3 +2229,31 @@ bool MyAvatar::didTeleport() {
|
|||
bool MyAvatar::hasDriveInput() const {
|
||||
return fabsf(_driveKeys[TRANSLATE_X]) > 0.0f || fabsf(_driveKeys[TRANSLATE_Y]) > 0.0f || fabsf(_driveKeys[TRANSLATE_Z]) > 0.0f;
|
||||
}
|
||||
|
||||
glm::quat MyAvatar::getAbsoluteJointRotationInObjectFrame(int index) const {
|
||||
switch(index) {
|
||||
case CONTROLLER_LEFTHAND_INDEX: {
|
||||
return getLeftHandControllerPoseInAvatarFrame().getRotation();
|
||||
}
|
||||
case CONTROLLER_RIGHTHAND_INDEX: {
|
||||
return getRightHandControllerPoseInAvatarFrame().getRotation();
|
||||
}
|
||||
default: {
|
||||
return Avatar::getAbsoluteJointRotationInObjectFrame(index);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
glm::vec3 MyAvatar::getAbsoluteJointTranslationInObjectFrame(int index) const {
|
||||
switch(index) {
|
||||
case CONTROLLER_LEFTHAND_INDEX: {
|
||||
return getLeftHandControllerPoseInAvatarFrame().getTranslation();
|
||||
}
|
||||
case CONTROLLER_RIGHTHAND_INDEX: {
|
||||
return getRightHandControllerPoseInAvatarFrame().getTranslation();
|
||||
}
|
||||
default: {
|
||||
return Avatar::getAbsoluteJointTranslationInObjectFrame(index);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
#include <Sound.h>
|
||||
|
||||
#include <controllers/Pose.h>
|
||||
#include <controllers/Actions.h>
|
||||
|
||||
#include "Avatar.h"
|
||||
#include "AtRestDetector.h"
|
||||
|
@ -117,6 +118,9 @@ public:
|
|||
// as it moves through the world.
|
||||
void updateFromHMDSensorMatrix(const glm::mat4& hmdSensorMatrix);
|
||||
|
||||
// read the location of a hand controller and save the transform
|
||||
void updateJointFromController(controller::Action poseKey, ThreadSafeValueCache<glm::mat4>& matrixCache);
|
||||
|
||||
// best called at end of main loop, just before rendering.
|
||||
// update sensor to world matrix from current body position and hmd sensor.
|
||||
// This is so the correct camera can be used for rendering.
|
||||
|
@ -270,6 +274,9 @@ public:
|
|||
Q_INVOKABLE void setCharacterControllerEnabled(bool enabled);
|
||||
Q_INVOKABLE bool getCharacterControllerEnabled();
|
||||
|
||||
virtual glm::quat getAbsoluteJointRotationInObjectFrame(int index) const override;
|
||||
virtual glm::vec3 getAbsoluteJointTranslationInObjectFrame(int index) const override;
|
||||
|
||||
public slots:
|
||||
void increaseSize();
|
||||
void decreaseSize();
|
||||
|
@ -410,9 +417,8 @@ private:
|
|||
bool _useSnapTurn { true };
|
||||
bool _clearOverlayWhenMoving { true };
|
||||
|
||||
// working copy of sensorToWorldMatrix.
|
||||
// See AvatarData for thread-safe _sensorToWorldMatrixCache, used for outward facing access
|
||||
glm::mat4 _sensorToWorldMatrix;
|
||||
// working copies -- see AvatarData for thread-safe _sensorToWorldMatrixCache, used for outward facing access
|
||||
glm::mat4 _sensorToWorldMatrix { glm::mat4() };
|
||||
|
||||
// cache of the current HMD sensor position and orientation
|
||||
// in sensor space.
|
||||
|
|
|
@ -1,182 +0,0 @@
|
|||
//
|
||||
// WebWindowClass.cpp
|
||||
// interface/src/scripting
|
||||
//
|
||||
// Created by Ryan Huffman on 11/06/14.
|
||||
// Copyright 2014 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
|
||||
#include <QVBoxLayout>
|
||||
#include <QApplication>
|
||||
#include <QMainWindow>
|
||||
#include <QDockWidget>
|
||||
#include <QWebFrame>
|
||||
#include <QWebView>
|
||||
#include <QListWidget>
|
||||
#include <QStyleFactory>
|
||||
|
||||
#include "Application.h"
|
||||
#include "ui/DataWebPage.h"
|
||||
#include "MainWindow.h"
|
||||
#include "WebWindowClass.h"
|
||||
#include "WindowScriptingInterface.h"
|
||||
|
||||
ScriptEventBridge::ScriptEventBridge(QObject* parent) : QObject(parent) {
|
||||
}
|
||||
|
||||
void ScriptEventBridge::emitWebEvent(const QString& data) {
|
||||
emit webEventReceived(data);
|
||||
}
|
||||
|
||||
void ScriptEventBridge::emitScriptEvent(const QString& data) {
|
||||
emit scriptEventReceived(data);
|
||||
}
|
||||
|
||||
WebWindowClass::WebWindowClass(const QString& title, const QString& url, int width, int height)
|
||||
: QObject(NULL), _eventBridge(new ScriptEventBridge(this)) {
|
||||
auto dialogWidget = new QDialog(qApp->getWindow(), Qt::Window);
|
||||
dialogWidget->setWindowTitle(title);
|
||||
dialogWidget->resize(width, height);
|
||||
dialogWidget->installEventFilter(this);
|
||||
connect(dialogWidget, &QDialog::finished, this, &WebWindowClass::hasClosed);
|
||||
|
||||
auto layout = new QVBoxLayout(dialogWidget);
|
||||
layout->setContentsMargins(0, 0, 0, 0);
|
||||
dialogWidget->setLayout(layout);
|
||||
|
||||
_webView = new QWebView(dialogWidget);
|
||||
|
||||
layout->addWidget(_webView);
|
||||
|
||||
addEventBridgeToWindowObject();
|
||||
|
||||
_windowWidget = dialogWidget;
|
||||
|
||||
auto style = QStyleFactory::create("fusion");
|
||||
if (style) {
|
||||
_webView->setStyle(style);
|
||||
}
|
||||
|
||||
_webView->setPage(new DataWebPage());
|
||||
if (!url.startsWith("http") && !url.startsWith("file://")) {
|
||||
_webView->setUrl(QUrl::fromLocalFile(url));
|
||||
} else {
|
||||
_webView->setUrl(url);
|
||||
}
|
||||
|
||||
connect(this, &WebWindowClass::destroyed, _windowWidget, &QWidget::deleteLater);
|
||||
connect(_webView->page()->mainFrame(), &QWebFrame::javaScriptWindowObjectCleared,
|
||||
this, &WebWindowClass::addEventBridgeToWindowObject);
|
||||
}
|
||||
|
||||
WebWindowClass::~WebWindowClass() {
|
||||
}
|
||||
|
||||
bool WebWindowClass::eventFilter(QObject* sender, QEvent* event) {
|
||||
if (sender == _windowWidget) {
|
||||
if (event->type() == QEvent::Move) {
|
||||
emit moved(getPosition());
|
||||
}
|
||||
if (event->type() == QEvent::Resize) {
|
||||
emit resized(getSize());
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void WebWindowClass::hasClosed() {
|
||||
emit closed();
|
||||
}
|
||||
|
||||
void WebWindowClass::addEventBridgeToWindowObject() {
|
||||
_webView->page()->mainFrame()->addToJavaScriptWindowObject("EventBridge", _eventBridge);
|
||||
}
|
||||
|
||||
void WebWindowClass::setVisible(bool visible) {
|
||||
if (visible) {
|
||||
QMetaObject::invokeMethod(_windowWidget, "showNormal", Qt::AutoConnection);
|
||||
QMetaObject::invokeMethod(_windowWidget, "raise", Qt::AutoConnection);
|
||||
}
|
||||
QMetaObject::invokeMethod(_windowWidget, "setVisible", Qt::AutoConnection, Q_ARG(bool, visible));
|
||||
}
|
||||
|
||||
void WebWindowClass::setURL(const QString& url) {
|
||||
if (QThread::currentThread() != thread()) {
|
||||
QMetaObject::invokeMethod(this, "setURL", Qt::AutoConnection, Q_ARG(QString, url));
|
||||
return;
|
||||
}
|
||||
_webView->setUrl(url);
|
||||
}
|
||||
|
||||
QSizeF WebWindowClass::getSize() const {
|
||||
QSizeF size = _windowWidget->size();
|
||||
return size;
|
||||
}
|
||||
|
||||
void WebWindowClass::setSize(QSizeF size) {
|
||||
setSize(size.width(), size.height());
|
||||
}
|
||||
|
||||
void WebWindowClass::setSize(int width, int height) {
|
||||
if (QThread::currentThread() != thread()) {
|
||||
QMetaObject::invokeMethod(this, "setSize", Qt::AutoConnection, Q_ARG(int, width), Q_ARG(int, height));
|
||||
return;
|
||||
}
|
||||
_windowWidget->resize(width, height);
|
||||
}
|
||||
|
||||
glm::vec2 WebWindowClass::getPosition() const {
|
||||
QPoint position = _windowWidget->pos();
|
||||
return glm::vec2(position.x(), position.y());
|
||||
}
|
||||
|
||||
void WebWindowClass::setPosition(glm::vec2 position) {
|
||||
setPosition(position.x, position.y);
|
||||
}
|
||||
|
||||
void WebWindowClass::setPosition(int x, int y) {
|
||||
if (QThread::currentThread() != thread()) {
|
||||
QMetaObject::invokeMethod(this, "setPosition", Qt::AutoConnection, Q_ARG(int, x), Q_ARG(int, y));
|
||||
return;
|
||||
}
|
||||
_windowWidget->move(x, y);
|
||||
}
|
||||
|
||||
void WebWindowClass::raise() {
|
||||
QMetaObject::invokeMethod(_windowWidget, "showNormal", Qt::AutoConnection);
|
||||
QMetaObject::invokeMethod(_windowWidget, "raise", Qt::AutoConnection);
|
||||
}
|
||||
|
||||
QScriptValue WebWindowClass::constructor(QScriptContext* context, QScriptEngine* engine) {
|
||||
WebWindowClass* retVal;
|
||||
QString file = context->argument(0).toString();
|
||||
if (context->argument(4).toBool()) {
|
||||
qWarning() << "ToolWindow views with WebWindow are no longer supported. Use OverlayWebWindow instead";
|
||||
return QScriptValue();
|
||||
} else {
|
||||
qWarning() << "WebWindow views are deprecated. Use OverlayWebWindow instead";
|
||||
}
|
||||
QMetaObject::invokeMethod(DependencyManager::get<WindowScriptingInterface>().data(), "doCreateWebWindow", Qt::BlockingQueuedConnection,
|
||||
Q_RETURN_ARG(WebWindowClass*, retVal),
|
||||
Q_ARG(const QString&, file),
|
||||
Q_ARG(QString, context->argument(1).toString()),
|
||||
Q_ARG(int, context->argument(2).toInteger()),
|
||||
Q_ARG(int, context->argument(3).toInteger()));
|
||||
|
||||
connect(engine, &QScriptEngine::destroyed, retVal, &WebWindowClass::deleteLater);
|
||||
|
||||
return engine->newQObject(retVal);
|
||||
}
|
||||
|
||||
void WebWindowClass::setTitle(const QString& title) {
|
||||
if (QThread::currentThread() != thread()) {
|
||||
QMetaObject::invokeMethod(this, "setTitle", Qt::AutoConnection, Q_ARG(QString, title));
|
||||
return;
|
||||
}
|
||||
_windowWidget->setWindowTitle(title);
|
||||
}
|
|
@ -1,80 +0,0 @@
|
|||
//
|
||||
// WebWindowClass.h
|
||||
// interface/src/scripting
|
||||
//
|
||||
// Created by Ryan Huffman on 11/06/14.
|
||||
// Copyright 2014 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#ifndef hifi_WebWindowClass_h
|
||||
#define hifi_WebWindowClass_h
|
||||
|
||||
#include <QScriptContext>
|
||||
#include <QScriptEngine>
|
||||
#include <QWebView>
|
||||
|
||||
class ScriptEventBridge : public QObject {
|
||||
Q_OBJECT
|
||||
public:
|
||||
ScriptEventBridge(QObject* parent = NULL);
|
||||
|
||||
public slots:
|
||||
void emitWebEvent(const QString& data);
|
||||
void emitScriptEvent(const QString& data);
|
||||
|
||||
signals:
|
||||
void webEventReceived(const QString& data);
|
||||
void scriptEventReceived(const QString& data);
|
||||
|
||||
};
|
||||
|
||||
class WebWindowClass : public QObject {
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(QObject* eventBridge READ getEventBridge)
|
||||
Q_PROPERTY(QString url READ getURL)
|
||||
Q_PROPERTY(glm::vec2 position READ getPosition WRITE setPosition);
|
||||
Q_PROPERTY(QSizeF size READ getSize WRITE setSize);
|
||||
|
||||
public:
|
||||
WebWindowClass(const QString& title, const QString& url, int width, int height);
|
||||
~WebWindowClass();
|
||||
|
||||
static QScriptValue constructor(QScriptContext* context, QScriptEngine* engine);
|
||||
|
||||
public slots:
|
||||
void setVisible(bool visible);
|
||||
glm::vec2 getPosition() const;
|
||||
void setPosition(int x, int y);
|
||||
void setPosition(glm::vec2 position);
|
||||
QSizeF getSize() const;
|
||||
void setSize(QSizeF size);
|
||||
void setSize(int width, int height);
|
||||
QString getURL() const { return _webView->url().url(); }
|
||||
void setURL(const QString& url);
|
||||
void raise();
|
||||
ScriptEventBridge* getEventBridge() const { return _eventBridge; }
|
||||
void addEventBridgeToWindowObject();
|
||||
void setTitle(const QString& title);
|
||||
|
||||
signals:
|
||||
void visibilityChanged(bool visible); // Tool window
|
||||
void moved(glm::vec2 position);
|
||||
void resized(QSizeF size);
|
||||
void closed();
|
||||
|
||||
protected:
|
||||
virtual bool eventFilter(QObject* sender, QEvent* event) override;
|
||||
|
||||
private slots:
|
||||
void hasClosed();
|
||||
|
||||
private:
|
||||
QWidget* _windowWidget;
|
||||
QWebView* _webView;
|
||||
ScriptEventBridge* _eventBridge;
|
||||
};
|
||||
|
||||
#endif
|
|
@ -21,7 +21,6 @@
|
|||
#include "MainWindow.h"
|
||||
#include "Menu.h"
|
||||
#include "OffscreenUi.h"
|
||||
#include "WebWindowClass.h"
|
||||
|
||||
#include "WindowScriptingInterface.h"
|
||||
|
||||
|
@ -61,10 +60,6 @@ WindowScriptingInterface::WindowScriptingInterface() {
|
|||
});
|
||||
}
|
||||
|
||||
WebWindowClass* WindowScriptingInterface::doCreateWebWindow(const QString& title, const QString& url, int width, int height) {
|
||||
return new WebWindowClass(title, url, width, height);
|
||||
}
|
||||
|
||||
QScriptValue WindowScriptingInterface::hasFocus() {
|
||||
return qApp->hasFocus();
|
||||
}
|
||||
|
|
|
@ -16,9 +16,6 @@
|
|||
#include <QtCore/QString>
|
||||
#include <QtScript/QScriptValue>
|
||||
|
||||
class WebWindowClass;
|
||||
|
||||
|
||||
class CustomPromptResult {
|
||||
public:
|
||||
QVariant value;
|
||||
|
@ -65,9 +62,6 @@ signals:
|
|||
void snapshotTaken(const QString& path, bool notify);
|
||||
void snapshotShared(const QString& error);
|
||||
|
||||
private slots:
|
||||
WebWindowClass* doCreateWebWindow(const QString& title, const QString& url, int width, int height);
|
||||
|
||||
private:
|
||||
QString getPreviousBrowseLocation() const;
|
||||
void setPreviousBrowseLocation(const QString& location);
|
||||
|
|
|
@ -1,54 +0,0 @@
|
|||
//
|
||||
// DataWebPage.cpp
|
||||
// interface/src/ui
|
||||
//
|
||||
// Created by Stephen Birarda on 2014-09-22.
|
||||
// Copyright 2014 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#include <qnetworkrequest.h>
|
||||
|
||||
#include "Application.h"
|
||||
#include <AddressManager.h>
|
||||
#include <OAuthNetworkAccessManager.h>
|
||||
|
||||
#include "DataWebPage.h"
|
||||
|
||||
DataWebPage::DataWebPage(QObject* parent) :
|
||||
QWebPage(parent)
|
||||
{
|
||||
// use an OAuthNetworkAccessManager instead of regular QNetworkAccessManager so our requests are authed
|
||||
setNetworkAccessManager(OAuthNetworkAccessManager::getInstance());
|
||||
|
||||
// give the page an empty stylesheet
|
||||
settings()->setUserStyleSheetUrl(QUrl());
|
||||
}
|
||||
|
||||
void DataWebPage::javaScriptConsoleMessage(const QString& message, int lineNumber, const QString& sourceID) {
|
||||
qDebug() << "JS console message at line" << lineNumber << "from" << sourceID << "-" << message;
|
||||
}
|
||||
|
||||
bool DataWebPage::acceptNavigationRequest(QWebFrame* frame, const QNetworkRequest& request, QWebPage::NavigationType type) {
|
||||
// Handle hifi:// links and links to files with particular extensions
|
||||
QString urlString = request.url().toString();
|
||||
if (qApp->canAcceptURL(urlString)) {
|
||||
if (qApp->acceptURL(urlString)) {
|
||||
return false; // we handled it, so QWebPage doesn't need to handle it
|
||||
}
|
||||
}
|
||||
|
||||
// Make hyperlinks with target="_blank" open in user's Web browser
|
||||
if (type == QWebPage::NavigationTypeLinkClicked && frame == nullptr) {
|
||||
qApp->openUrl(request.url());
|
||||
return false; // We handled it.
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
QString DataWebPage::userAgentForUrl(const QUrl& url) const {
|
||||
return HIGH_FIDELITY_USER_AGENT;
|
||||
}
|
|
@ -1,26 +0,0 @@
|
|||
//
|
||||
// DataWebPage.h
|
||||
// interface/src/ui
|
||||
//
|
||||
// Created by Stephen Birarda on 2014-09-22.
|
||||
// Copyright 2014 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#ifndef hifi_DataWebPage_h
|
||||
#define hifi_DataWebPage_h
|
||||
|
||||
#include <qwebpage.h>
|
||||
|
||||
class DataWebPage : public QWebPage {
|
||||
public:
|
||||
DataWebPage(QObject* parent = 0);
|
||||
protected:
|
||||
void javaScriptConsoleMessage(const QString & message, int lineNumber, const QString & sourceID) override;
|
||||
bool acceptNavigationRequest(QWebFrame* frame, const QNetworkRequest& request, QWebPage::NavigationType type) override;
|
||||
virtual QString userAgentForUrl(const QUrl& url) const override;
|
||||
};
|
||||
|
||||
#endif // hifi_DataWebPage_h
|
|
@ -228,6 +228,7 @@ void ModelHandler::update() {
|
|||
QUrl url(_model.item(i,0)->data(Qt::UserRole).toString());
|
||||
QNetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance();
|
||||
QNetworkRequest request(url);
|
||||
request.setAttribute(QNetworkRequest::FollowRedirectsAttribute, true);
|
||||
request.setHeader(QNetworkRequest::UserAgentHeader, HIGH_FIDELITY_USER_AGENT);
|
||||
QNetworkReply* reply = networkAccessManager.head(request);
|
||||
connect(reply, SIGNAL(finished()), SLOT(downloadFinished()));
|
||||
|
@ -280,6 +281,7 @@ void ModelHandler::queryNewFiles(QString marker) {
|
|||
url.setQuery(query);
|
||||
QNetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance();
|
||||
QNetworkRequest request(url);
|
||||
request.setAttribute(QNetworkRequest::FollowRedirectsAttribute, true);
|
||||
request.setHeader(QNetworkRequest::UserAgentHeader, HIGH_FIDELITY_USER_AGENT);
|
||||
QNetworkReply* reply = networkAccessManager.get(request);
|
||||
connect(reply, SIGNAL(finished()), SLOT(downloadFinished()));
|
||||
|
|
|
@ -161,6 +161,7 @@ void ScriptEditorWidget::loadFile(const QString& scriptPath) {
|
|||
} else {
|
||||
QNetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance();
|
||||
QNetworkRequest networkRequest = QNetworkRequest(url);
|
||||
networkRequest.setAttribute(QNetworkRequest::FollowRedirectsAttribute, true);
|
||||
networkRequest.setHeader(QNetworkRequest::UserAgentHeader, HIGH_FIDELITY_USER_AGENT);
|
||||
QNetworkReply* reply = networkAccessManager.get(networkRequest);
|
||||
qDebug() << "Downloading included script at" << scriptPath;
|
||||
|
|
|
@ -33,6 +33,7 @@ void AutoUpdater::checkForUpdate() {
|
|||
void AutoUpdater::getLatestVersionData() {
|
||||
QNetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance();
|
||||
QNetworkRequest latestVersionRequest(BUILDS_XML_URL);
|
||||
latestVersionRequest.setAttribute(QNetworkRequest::FollowRedirectsAttribute, true);
|
||||
latestVersionRequest.setHeader(QNetworkRequest::UserAgentHeader, HIGH_FIDELITY_USER_AGENT);
|
||||
QNetworkReply* reply = networkAccessManager.get(latestVersionRequest);
|
||||
connect(reply, &QNetworkReply::finished, this, &AutoUpdater::parseLatestVersionData);
|
||||
|
|
|
@ -374,6 +374,16 @@ QByteArray AvatarData::toByteArray(bool cullSmallChanges, bool sendAll) {
|
|||
}
|
||||
}
|
||||
|
||||
// faux joints
|
||||
Transform controllerLeftHandTransform = Transform(getControllerLeftHandMatrix());
|
||||
destinationBuffer += packOrientationQuatToSixBytes(destinationBuffer, controllerLeftHandTransform.getRotation());
|
||||
destinationBuffer += packFloatVec3ToSignedTwoByteFixed(destinationBuffer, controllerLeftHandTransform.getTranslation(),
|
||||
TRANSLATION_COMPRESSION_RADIX);
|
||||
Transform controllerRightHandTransform = Transform(getControllerRightHandMatrix());
|
||||
destinationBuffer += packOrientationQuatToSixBytes(destinationBuffer, controllerRightHandTransform.getRotation());
|
||||
destinationBuffer += packFloatVec3ToSignedTwoByteFixed(destinationBuffer, controllerRightHandTransform.getTranslation(),
|
||||
TRANSLATION_COMPRESSION_RADIX);
|
||||
|
||||
#ifdef WANT_DEBUG
|
||||
if (sendAll) {
|
||||
qDebug() << "AvatarData::toByteArray" << cullSmallChanges << sendAll
|
||||
|
@ -429,6 +439,20 @@ bool AvatarData::shouldLogError(const quint64& now) {
|
|||
return false;
|
||||
}
|
||||
|
||||
|
||||
const unsigned char* unpackFauxJoint(const unsigned char* sourceBuffer, ThreadSafeValueCache<glm::mat4>& matrixCache) {
|
||||
glm::quat orientation;
|
||||
glm::vec3 position;
|
||||
Transform transform;
|
||||
sourceBuffer += unpackOrientationQuatFromSixBytes(sourceBuffer, orientation);
|
||||
sourceBuffer += unpackFloatVec3FromSignedTwoByteFixed(sourceBuffer, position, TRANSLATION_COMPRESSION_RADIX);
|
||||
transform.setTranslation(position);
|
||||
transform.setRotation(orientation);
|
||||
matrixCache.set(transform.getMatrix());
|
||||
return sourceBuffer;
|
||||
}
|
||||
|
||||
|
||||
#define PACKET_READ_CHECK(ITEM_NAME, SIZE_TO_READ) \
|
||||
if ((endPosition - sourceBuffer) < (int)SIZE_TO_READ) { \
|
||||
if (shouldLogError(now)) { \
|
||||
|
@ -655,6 +679,10 @@ int AvatarData::parseDataFromBuffer(const QByteArray& buffer) {
|
|||
}
|
||||
#endif
|
||||
|
||||
// faux joints
|
||||
sourceBuffer = unpackFauxJoint(sourceBuffer, _controllerLeftHandMatrixCache);
|
||||
sourceBuffer = unpackFauxJoint(sourceBuffer, _controllerRightHandMatrixCache);
|
||||
|
||||
int numBytesRead = sourceBuffer - startPosition;
|
||||
_averageBytesReceived.updateAverage(numBytesRead);
|
||||
return numBytesRead;
|
||||
|
@ -915,7 +943,24 @@ void AvatarData::clearJointsData() {
|
|||
}
|
||||
}
|
||||
|
||||
int AvatarData::getFauxJointIndex(const QString& name) const {
|
||||
if (name == "_SENSOR_TO_WORLD_MATRIX") {
|
||||
return SENSOR_TO_WORLD_MATRIX_INDEX;
|
||||
}
|
||||
if (name == "_CONTROLLER_LEFTHAND") {
|
||||
return CONTROLLER_LEFTHAND_INDEX;
|
||||
}
|
||||
if (name == "_CONTROLLER_RIGHTHAND") {
|
||||
return CONTROLLER_RIGHTHAND_INDEX;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
int AvatarData::getJointIndex(const QString& name) const {
|
||||
int result = getFauxJointIndex(name);
|
||||
if (result != -1) {
|
||||
return result;
|
||||
}
|
||||
QReadLocker readLock(&_jointDataLock);
|
||||
return _jointIndices.value(name) - 1;
|
||||
}
|
||||
|
@ -1161,6 +1206,7 @@ void AvatarData::updateJointMappings() {
|
|||
if (_skeletonModelURL.fileName().toLower().endsWith(".fst")) {
|
||||
QNetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance();
|
||||
QNetworkRequest networkRequest = QNetworkRequest(_skeletonModelURL);
|
||||
networkRequest.setAttribute(QNetworkRequest::FollowRedirectsAttribute, true);
|
||||
networkRequest.setHeader(QNetworkRequest::UserAgentHeader, HIGH_FIDELITY_USER_AGENT);
|
||||
QNetworkReply* networkReply = networkAccessManager.get(networkRequest);
|
||||
connect(networkReply, &QNetworkReply::finished, this, &AvatarData::setJointMappingsFromNetworkReply);
|
||||
|
@ -1743,6 +1789,17 @@ glm::mat4 AvatarData::getSensorToWorldMatrix() const {
|
|||
return _sensorToWorldMatrixCache.get();
|
||||
}
|
||||
|
||||
// thread-safe
|
||||
glm::mat4 AvatarData::getControllerLeftHandMatrix() const {
|
||||
return _controllerLeftHandMatrixCache.get();
|
||||
}
|
||||
|
||||
// thread-safe
|
||||
glm::mat4 AvatarData::getControllerRightHandMatrix() const {
|
||||
return _controllerRightHandMatrixCache.get();
|
||||
}
|
||||
|
||||
|
||||
QScriptValue RayToAvatarIntersectionResultToScriptValue(QScriptEngine* engine, const RayToAvatarIntersectionResult& value) {
|
||||
QScriptValue obj = engine->newObject();
|
||||
obj.setProperty("intersects", value.intersects);
|
||||
|
|
|
@ -173,6 +173,8 @@ class AvatarData : public QObject, public SpatiallyNestable {
|
|||
Q_PROPERTY(QUuid sessionUUID READ getSessionUUID)
|
||||
|
||||
Q_PROPERTY(glm::mat4 sensorToWorldMatrix READ getSensorToWorldMatrix)
|
||||
Q_PROPERTY(glm::mat4 controllerLeftHandMatrix READ getControllerLeftHandMatrix)
|
||||
Q_PROPERTY(glm::mat4 controllerRightHandMatrix READ getControllerRightHandMatrix)
|
||||
|
||||
public:
|
||||
|
||||
|
@ -356,6 +358,8 @@ public:
|
|||
|
||||
// thread safe
|
||||
Q_INVOKABLE glm::mat4 getSensorToWorldMatrix() const;
|
||||
Q_INVOKABLE glm::mat4 getControllerLeftHandMatrix() const;
|
||||
Q_INVOKABLE glm::mat4 getControllerRightHandMatrix() const;
|
||||
|
||||
public slots:
|
||||
void sendAvatarDataPacket();
|
||||
|
@ -369,6 +373,8 @@ public slots:
|
|||
virtual bool setAbsoluteJointRotationInObjectFrame(int index, const glm::quat& rotation) override { return false; }
|
||||
virtual bool setAbsoluteJointTranslationInObjectFrame(int index, const glm::vec3& translation) override { return false; }
|
||||
|
||||
float getTargetScale() { return _targetScale; }
|
||||
|
||||
protected:
|
||||
glm::vec3 _handPosition;
|
||||
|
||||
|
@ -433,6 +439,10 @@ protected:
|
|||
|
||||
// used to transform any sensor into world space, including the _hmdSensorMat, or hand controllers.
|
||||
ThreadSafeValueCache<glm::mat4> _sensorToWorldMatrixCache { glm::mat4() };
|
||||
ThreadSafeValueCache<glm::mat4> _controllerLeftHandMatrixCache { glm::mat4() };
|
||||
ThreadSafeValueCache<glm::mat4> _controllerRightHandMatrixCache { glm::mat4() };
|
||||
|
||||
int getFauxJointIndex(const QString& name) const;
|
||||
|
||||
private:
|
||||
friend void avatarStateFromFrame(const QByteArray& frameData, AvatarData* _avatar);
|
||||
|
@ -519,5 +529,10 @@ Q_DECLARE_METATYPE(RayToAvatarIntersectionResult)
|
|||
QScriptValue RayToAvatarIntersectionResultToScriptValue(QScriptEngine* engine, const RayToAvatarIntersectionResult& results);
|
||||
void RayToAvatarIntersectionResultFromScriptValue(const QScriptValue& object, RayToAvatarIntersectionResult& results);
|
||||
|
||||
// faux joint indexes (-1 means invalid)
|
||||
const int SENSOR_TO_WORLD_MATRIX_INDEX = 65534; // -2
|
||||
const int CONTROLLER_RIGHTHAND_INDEX = 65533; // -3
|
||||
const int CONTROLLER_LEFTHAND_INDEX = 65532; // -4
|
||||
|
||||
|
||||
#endif // hifi_AvatarData_h
|
||||
|
|
|
@ -325,7 +325,6 @@ QString UserInputMapper::getActionName(Action action) const {
|
|||
return QString();
|
||||
}
|
||||
|
||||
|
||||
QVector<QString> UserInputMapper::getActionNames() const {
|
||||
Locker locker(_lock);
|
||||
QVector<QString> result;
|
||||
|
@ -335,6 +334,12 @@ QVector<QString> UserInputMapper::getActionNames() const {
|
|||
return result;
|
||||
}
|
||||
|
||||
Pose UserInputMapper::getPoseState(Action action) const {
|
||||
assert(QThread::currentThread() == thread());
|
||||
return _poseStates[toInt(action)];
|
||||
}
|
||||
|
||||
|
||||
bool UserInputMapper::triggerHapticPulse(float strength, float duration, controller::Hand hand) {
|
||||
Locker locker(_lock);
|
||||
bool toReturn = false;
|
||||
|
|
|
@ -81,7 +81,7 @@ namespace controller {
|
|||
QVector<Action> getAllActions() const;
|
||||
QString getActionName(Action action) const;
|
||||
float getActionState(Action action) const { return _actionStates[toInt(action)]; }
|
||||
Pose getPoseState(Action action) const { return _poseStates[toInt(action)]; }
|
||||
Pose getPoseState(Action action) const;
|
||||
int findAction(const QString& actionName) const;
|
||||
QVector<QString> getActionNames() const;
|
||||
Input inputFromAction(Action action) const { return getActionInputs()[toInt(action)].first; }
|
||||
|
|
|
@ -69,6 +69,8 @@ public:
|
|||
virtual bool wantVsync() const { return true; }
|
||||
void setVsyncEnabled(bool vsyncEnabled) { _vsyncEnabled = vsyncEnabled; }
|
||||
bool isVsyncEnabled() const { return _vsyncEnabled; }
|
||||
// Three threads, one for rendering, one for texture transfers, one reserved for the GL driver
|
||||
int getRequiredThreadCount() const override { return 3; }
|
||||
|
||||
protected:
|
||||
friend class PresentThread;
|
||||
|
|
|
@ -527,9 +527,11 @@ void HmdDisplayPlugin::compositeExtra() {
|
|||
if (_presentHandPoses[index] == IDENTITY_MATRIX) {
|
||||
return;
|
||||
}
|
||||
const auto& points = _presentHandLaserPoints[index];
|
||||
const auto& lasers = _presentHandLasers[index];
|
||||
geometryCache->renderGlowLine(batch, points.first, points.second, lasers.color);
|
||||
const auto& laser = _presentHandLasers[index];
|
||||
if (laser.valid()) {
|
||||
const auto& points = _presentHandLaserPoints[index];
|
||||
geometryCache->renderGlowLine(batch, points.first, points.second, laser.color);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
|
|
@ -100,6 +100,9 @@ EntityActionType EntityActionInterface::actionTypeFromString(QString actionTypeS
|
|||
if (normalizedActionTypeString == "hold") {
|
||||
return ACTION_TYPE_HOLD;
|
||||
}
|
||||
if (normalizedActionTypeString == "traveloriented") {
|
||||
return ACTION_TYPE_TRAVEL_ORIENTED;
|
||||
}
|
||||
|
||||
qDebug() << "Warning -- EntityActionInterface::actionTypeFromString got unknown action-type name" << actionTypeString;
|
||||
return ACTION_TYPE_NONE;
|
||||
|
@ -115,6 +118,8 @@ QString EntityActionInterface::actionTypeToString(EntityActionType actionType) {
|
|||
return "spring";
|
||||
case ACTION_TYPE_HOLD:
|
||||
return "hold";
|
||||
case ACTION_TYPE_TRAVEL_ORIENTED:
|
||||
return "travel-oriented";
|
||||
}
|
||||
assert(false);
|
||||
return "none";
|
||||
|
|
|
@ -28,7 +28,8 @@ enum EntityActionType {
|
|||
ACTION_TYPE_NONE = 0,
|
||||
ACTION_TYPE_OFFSET = 1000,
|
||||
ACTION_TYPE_SPRING = 2000,
|
||||
ACTION_TYPE_HOLD = 3000
|
||||
ACTION_TYPE_HOLD = 3000,
|
||||
ACTION_TYPE_TRAVEL_ORIENTED = 4000
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -191,6 +191,7 @@ FSTReader::ModelType FSTReader::predictModelType(const QVariantHash& mapping) {
|
|||
QVariantHash FSTReader::downloadMapping(const QString& url) {
|
||||
QNetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance();
|
||||
QNetworkRequest networkRequest = QNetworkRequest(url);
|
||||
networkRequest.setAttribute(QNetworkRequest::FollowRedirectsAttribute, true);
|
||||
networkRequest.setHeader(QNetworkRequest::UserAgentHeader, HIGH_FIDELITY_USER_AGENT);
|
||||
QNetworkReply* reply = networkAccessManager.get(networkRequest);
|
||||
qDebug() << "Downloading avatar file at " << url;
|
||||
|
|
|
@ -282,6 +282,7 @@ QNetworkReply* OBJReader::request(QUrl& url, bool isTest) {
|
|||
});
|
||||
QNetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance();
|
||||
QNetworkRequest netRequest(url);
|
||||
netRequest.setAttribute(QNetworkRequest::FollowRedirectsAttribute, true);
|
||||
QNetworkReply* netReply = isTest ? networkAccessManager.head(netRequest) : networkAccessManager.get(netRequest);
|
||||
if (!qApp || aboutToQuit) {
|
||||
netReply->deleteLater();
|
||||
|
|
|
@ -218,7 +218,7 @@ void AccountManager::sendRequest(const QString& path,
|
|||
QNetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance();
|
||||
|
||||
QNetworkRequest networkRequest;
|
||||
|
||||
networkRequest.setAttribute(QNetworkRequest::FollowRedirectsAttribute, true);
|
||||
networkRequest.setHeader(QNetworkRequest::UserAgentHeader, _userAgentGetter());
|
||||
|
||||
networkRequest.setRawHeader(METAVERSE_SESSION_ID_HEADER,
|
||||
|
@ -484,6 +484,7 @@ void AccountManager::requestAccessToken(const QString& login, const QString& pas
|
|||
QNetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance();
|
||||
|
||||
QNetworkRequest request;
|
||||
request.setAttribute(QNetworkRequest::FollowRedirectsAttribute, true);
|
||||
request.setHeader(QNetworkRequest::UserAgentHeader, _userAgentGetter());
|
||||
|
||||
QUrl grantURL = _authURL;
|
||||
|
@ -578,6 +579,7 @@ void AccountManager::requestProfile() {
|
|||
profileURL.setPath("/api/v1/user/profile");
|
||||
|
||||
QNetworkRequest profileRequest(profileURL);
|
||||
profileRequest.setAttribute(QNetworkRequest::FollowRedirectsAttribute, true);
|
||||
profileRequest.setHeader(QNetworkRequest::UserAgentHeader, _userAgentGetter());
|
||||
profileRequest.setRawHeader(ACCESS_TOKEN_AUTHORIZATION_HEADER, _accountInfo.getAccessToken().authorizationHeaderValue());
|
||||
|
||||
|
|
|
@ -836,6 +836,7 @@ void AddressManager::ifLocalSandboxRunningElse(std::function<void()> localSandbo
|
|||
|
||||
QNetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance();
|
||||
QNetworkRequest sandboxStatus(SANDBOX_STATUS_URL);
|
||||
sandboxStatus.setAttribute(QNetworkRequest::FollowRedirectsAttribute, true);
|
||||
sandboxStatus.setHeader(QNetworkRequest::UserAgentHeader, HIGH_FIDELITY_USER_AGENT);
|
||||
QNetworkReply* reply = networkAccessManager.get(sandboxStatus);
|
||||
|
||||
|
|
|
@ -49,6 +49,7 @@ void HTTPResourceRequest::cleanupTimer() {
|
|||
|
||||
void HTTPResourceRequest::doSend() {
|
||||
QNetworkRequest networkRequest(_url);
|
||||
networkRequest.setAttribute(QNetworkRequest::FollowRedirectsAttribute, true);
|
||||
networkRequest.setHeader(QNetworkRequest::UserAgentHeader, HIGH_FIDELITY_USER_AGENT);
|
||||
|
||||
if (_cacheEnabled) {
|
||||
|
|
|
@ -37,6 +37,7 @@ QNetworkReply* OAuthNetworkAccessManager::createRequest(QNetworkAccessManager::O
|
|||
if (accountManager->hasValidAccessToken()
|
||||
&& req.url().host() == NetworkingConstants::METAVERSE_SERVER_URL.host()) {
|
||||
QNetworkRequest authenticatedRequest(req);
|
||||
authenticatedRequest.setAttribute(QNetworkRequest::FollowRedirectsAttribute, true);
|
||||
authenticatedRequest.setHeader(QNetworkRequest::UserAgentHeader, HIGH_FIDELITY_USER_AGENT);
|
||||
authenticatedRequest.setRawHeader(ACCESS_TOKEN_AUTHORIZATION_HEADER,
|
||||
accountManager->getAccountInfo().getAccessToken().authorizationHeaderValue());
|
||||
|
|
|
@ -47,12 +47,12 @@ PacketVersion versionForPacketType(PacketType packetType) {
|
|||
case PacketType::EntityAdd:
|
||||
case PacketType::EntityEdit:
|
||||
case PacketType::EntityData:
|
||||
return VERSION_WEB_ENTITIES_SUPPORT_DPI;
|
||||
return VERSION_ENTITIES_ARROW_ACTION;
|
||||
case PacketType::AvatarIdentity:
|
||||
case PacketType::AvatarData:
|
||||
case PacketType::BulkAvatarData:
|
||||
case PacketType::KillAvatar:
|
||||
return static_cast<PacketVersion>(AvatarMixerPacketVersion::SensorToWorldMat);
|
||||
return static_cast<PacketVersion>(AvatarMixerPacketVersion::HandControllerJoints);
|
||||
case PacketType::ICEServerHeartbeat:
|
||||
return 18; // ICE Server Heartbeat signing
|
||||
case PacketType::AssetGetInfo:
|
||||
|
|
|
@ -187,13 +187,15 @@ const PacketVersion VERSION_ENTITIES_PROPERLY_ENCODE_SHAPE_EDITS = 60;
|
|||
const PacketVersion VERSION_MODEL_ENTITIES_SUPPORT_STATIC_MESH = 61;
|
||||
const PacketVersion VERSION_MODEL_ENTITIES_SUPPORT_SIMPLE_HULLS = 62;
|
||||
const PacketVersion VERSION_WEB_ENTITIES_SUPPORT_DPI = 63;
|
||||
const PacketVersion VERSION_ENTITIES_ARROW_ACTION = 64;
|
||||
|
||||
enum class AvatarMixerPacketVersion : PacketVersion {
|
||||
TranslationSupport = 17,
|
||||
SoftAttachmentSupport,
|
||||
AvatarEntities,
|
||||
AbsoluteSixByteRotations,
|
||||
SensorToWorldMat
|
||||
SensorToWorldMat,
|
||||
HandControllerJoints
|
||||
};
|
||||
|
||||
enum class DomainConnectRequestVersion : PacketVersion {
|
||||
|
|
206
libraries/physics/src/ObjectActionTravelOriented.cpp
Normal file
206
libraries/physics/src/ObjectActionTravelOriented.cpp
Normal file
|
@ -0,0 +1,206 @@
|
|||
//
|
||||
// ObjectActionTravelOriented.cpp
|
||||
// libraries/physics/src
|
||||
//
|
||||
// Created by Seth Alves 2015-6-5
|
||||
// Copyright 2015 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#include <glm/gtc/quaternion.hpp>
|
||||
|
||||
#include "QVariantGLM.h"
|
||||
#include "ObjectActionTravelOriented.h"
|
||||
|
||||
const uint16_t ObjectActionTravelOriented::actionVersion = 1;
|
||||
|
||||
|
||||
ObjectActionTravelOriented::ObjectActionTravelOriented(const QUuid& id, EntityItemPointer ownerEntity) :
|
||||
ObjectAction(ACTION_TYPE_TRAVEL_ORIENTED, id, ownerEntity) {
|
||||
#if WANT_DEBUG
|
||||
qDebug() << "ObjectActionTravelOriented::ObjectActionTravelOriented";
|
||||
#endif
|
||||
}
|
||||
|
||||
ObjectActionTravelOriented::~ObjectActionTravelOriented() {
|
||||
#if WANT_DEBUG
|
||||
qDebug() << "ObjectActionTravelOriented::~ObjectActionTravelOriented";
|
||||
#endif
|
||||
}
|
||||
|
||||
void ObjectActionTravelOriented::updateActionWorker(btScalar deltaTimeStep) {
|
||||
withReadLock([&] {
|
||||
auto ownerEntity = _ownerEntity.lock();
|
||||
if (!ownerEntity) {
|
||||
return;
|
||||
}
|
||||
void* physicsInfo = ownerEntity->getPhysicsInfo();
|
||||
if (!physicsInfo) {
|
||||
return;
|
||||
}
|
||||
ObjectMotionState* motionState = static_cast<ObjectMotionState*>(physicsInfo);
|
||||
btRigidBody* rigidBody = motionState->getRigidBody();
|
||||
if (!rigidBody) {
|
||||
qDebug() << "ObjectActionTravelOriented::updateActionWorker no rigidBody";
|
||||
return;
|
||||
}
|
||||
const float MAX_TIMESCALE = 600.0f; // 10 min is a long time
|
||||
if (_angularTimeScale > MAX_TIMESCALE) {
|
||||
return;
|
||||
}
|
||||
|
||||
// find normalized velocity
|
||||
glm::vec3 velocity = bulletToGLM(rigidBody->getLinearVelocity());
|
||||
float speed = glm::length(velocity);
|
||||
const float TRAVEL_ORIENTED_TOO_SLOW = 0.001f; // meters / second
|
||||
if (speed < TRAVEL_ORIENTED_TOO_SLOW) {
|
||||
return;
|
||||
}
|
||||
glm::vec3 direction = glm::normalize(velocity);
|
||||
|
||||
// find current angle of "forward"
|
||||
btQuaternion bodyRotation = rigidBody->getOrientation();
|
||||
glm::quat orientation = bulletToGLM(bodyRotation);
|
||||
glm::vec3 forwardInWorldFrame = glm::normalize(orientation * _forward);
|
||||
|
||||
// find the rotation that would line up direction and forward
|
||||
glm::quat neededRotation = glm::rotation(forwardInWorldFrame, direction);
|
||||
glm::quat rotationalTarget = neededRotation * orientation;
|
||||
|
||||
btVector3 targetAngularVelocity(0.0f, 0.0f, 0.0f);
|
||||
|
||||
auto alignmentDot = bodyRotation.dot(glmToBullet(rotationalTarget));
|
||||
const float ALMOST_ONE = 0.99999f;
|
||||
if (glm::abs(alignmentDot) < ALMOST_ONE) {
|
||||
btQuaternion target = glmToBullet(rotationalTarget);
|
||||
if (alignmentDot < 0.0f) {
|
||||
target = -target;
|
||||
}
|
||||
// if dQ is the incremental rotation that gets an object from Q0 to Q1 then:
|
||||
//
|
||||
// Q1 = dQ * Q0
|
||||
//
|
||||
// solving for dQ gives:
|
||||
//
|
||||
// dQ = Q1 * Q0^
|
||||
btQuaternion deltaQ = target * bodyRotation.inverse();
|
||||
float speed = deltaQ.getAngle() / _angularTimeScale;
|
||||
targetAngularVelocity = speed * deltaQ.getAxis();
|
||||
if (speed > rigidBody->getAngularSleepingThreshold()) {
|
||||
rigidBody->activate();
|
||||
}
|
||||
}
|
||||
// this action is aggresively critically damped and defeats the current velocity
|
||||
rigidBody->setAngularVelocity(targetAngularVelocity);
|
||||
});
|
||||
}
|
||||
|
||||
const float MIN_TIMESCALE = 0.1f;
|
||||
|
||||
|
||||
bool ObjectActionTravelOriented::updateArguments(QVariantMap arguments) {
|
||||
glm::vec3 forward;
|
||||
float angularTimeScale;
|
||||
|
||||
bool needUpdate = false;
|
||||
bool somethingChanged = ObjectAction::updateArguments(arguments);
|
||||
withReadLock([&]{
|
||||
bool ok = true;
|
||||
forward = EntityActionInterface::extractVec3Argument("travel oriented action", arguments, "forward", ok, true);
|
||||
if (!ok) {
|
||||
forward = _forward;
|
||||
}
|
||||
ok = true;
|
||||
angularTimeScale =
|
||||
EntityActionInterface::extractFloatArgument("travel oriented action", arguments, "angularTimeScale", ok, false);
|
||||
if (!ok) {
|
||||
angularTimeScale = _angularTimeScale;
|
||||
}
|
||||
|
||||
if (somethingChanged ||
|
||||
forward != _forward ||
|
||||
angularTimeScale != _angularTimeScale) {
|
||||
// something changed
|
||||
needUpdate = true;
|
||||
}
|
||||
});
|
||||
|
||||
if (needUpdate) {
|
||||
withWriteLock([&] {
|
||||
_forward = forward;
|
||||
_angularTimeScale = glm::max(MIN_TIMESCALE, glm::abs(angularTimeScale));
|
||||
_active = (_forward != glm::vec3());
|
||||
|
||||
auto ownerEntity = _ownerEntity.lock();
|
||||
if (ownerEntity) {
|
||||
ownerEntity->setActionDataDirty(true);
|
||||
ownerEntity->setActionDataNeedsTransmit(true);
|
||||
}
|
||||
});
|
||||
activateBody();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
QVariantMap ObjectActionTravelOriented::getArguments() {
|
||||
QVariantMap arguments = ObjectAction::getArguments();
|
||||
withReadLock([&] {
|
||||
arguments["forward"] = glmToQMap(_forward);
|
||||
arguments["angularTimeScale"] = _angularTimeScale;
|
||||
});
|
||||
return arguments;
|
||||
}
|
||||
|
||||
QByteArray ObjectActionTravelOriented::serialize() const {
|
||||
QByteArray serializedActionArguments;
|
||||
QDataStream dataStream(&serializedActionArguments, QIODevice::WriteOnly);
|
||||
|
||||
dataStream << ACTION_TYPE_TRAVEL_ORIENTED;
|
||||
dataStream << getID();
|
||||
dataStream << ObjectActionTravelOriented::actionVersion;
|
||||
|
||||
withReadLock([&] {
|
||||
dataStream << _forward;
|
||||
dataStream << _angularTimeScale;
|
||||
|
||||
dataStream << localTimeToServerTime(_expires);
|
||||
dataStream << _tag;
|
||||
});
|
||||
|
||||
return serializedActionArguments;
|
||||
}
|
||||
|
||||
void ObjectActionTravelOriented::deserialize(QByteArray serializedArguments) {
|
||||
QDataStream dataStream(serializedArguments);
|
||||
|
||||
EntityActionType type;
|
||||
dataStream >> type;
|
||||
assert(type == getType());
|
||||
|
||||
QUuid id;
|
||||
dataStream >> id;
|
||||
assert(id == getID());
|
||||
|
||||
uint16_t serializationVersion;
|
||||
dataStream >> serializationVersion;
|
||||
if (serializationVersion != ObjectActionTravelOriented::actionVersion) {
|
||||
assert(false);
|
||||
return;
|
||||
}
|
||||
|
||||
withWriteLock([&] {
|
||||
dataStream >> _forward;
|
||||
dataStream >> _angularTimeScale;
|
||||
|
||||
quint64 serverExpires;
|
||||
dataStream >> serverExpires;
|
||||
_expires = serverTimeToLocalTime(serverExpires);
|
||||
|
||||
dataStream >> _tag;
|
||||
|
||||
_active = (_forward != glm::vec3());
|
||||
});
|
||||
}
|
39
libraries/physics/src/ObjectActionTravelOriented.h
Normal file
39
libraries/physics/src/ObjectActionTravelOriented.h
Normal file
|
@ -0,0 +1,39 @@
|
|||
//
|
||||
// ObjectActionTravelOriented.h
|
||||
// libraries/physics/src
|
||||
//
|
||||
// Created by Seth Alves 2016-8-28
|
||||
// Copyright 2015 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#ifndef hifi_ObjectActionTravelOriented_h
|
||||
#define hifi_ObjectActionTravelOriented_h
|
||||
|
||||
#include "ObjectAction.h"
|
||||
|
||||
class ObjectActionTravelOriented : public ObjectAction {
|
||||
public:
|
||||
ObjectActionTravelOriented(const QUuid& id, EntityItemPointer ownerEntity);
|
||||
virtual ~ObjectActionTravelOriented();
|
||||
|
||||
virtual bool updateArguments(QVariantMap arguments) override;
|
||||
virtual QVariantMap getArguments() override;
|
||||
|
||||
virtual void updateActionWorker(float deltaTimeStep) override;
|
||||
|
||||
virtual QByteArray serialize() const override;
|
||||
virtual void deserialize(QByteArray serializedArguments) override;
|
||||
|
||||
protected:
|
||||
static const uint16_t actionVersion;
|
||||
|
||||
glm::vec3 _forward { glm::vec3() }; // the vector in object space that should point in the direction of travel
|
||||
float _angularTimeScale { 0.1f };
|
||||
|
||||
glm::vec3 _angularVelocityTarget;
|
||||
};
|
||||
|
||||
#endif // hifi_ObjectActionTravelOriented_h
|
|
@ -128,6 +128,7 @@ public:
|
|||
Present = QEvent::User + 1
|
||||
};
|
||||
|
||||
virtual int getRequiredThreadCount() const { return 0; }
|
||||
virtual bool isHmd() const { return false; }
|
||||
virtual int getHmdScreen() const { return -1; }
|
||||
/// By default, all HMDs are stereo
|
||||
|
|
|
@ -185,6 +185,7 @@ void ScriptsModel::requestDefaultFiles(QString marker) {
|
|||
|
||||
QNetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance();
|
||||
QNetworkRequest request(url);
|
||||
request.setAttribute(QNetworkRequest::FollowRedirectsAttribute, true);
|
||||
request.setHeader(QNetworkRequest::UserAgentHeader, HIGH_FIDELITY_USER_AGENT);
|
||||
QNetworkReply* reply = networkAccessManager.get(request);
|
||||
connect(reply, SIGNAL(finished()), SLOT(downloadFinished()));
|
||||
|
|
|
@ -45,6 +45,7 @@ XMLHttpRequestClass::XMLHttpRequestClass(QScriptEngine* engine) :
|
|||
_timer(this),
|
||||
_numRedirects(0) {
|
||||
|
||||
_request.setAttribute(QNetworkRequest::FollowRedirectsAttribute, true);
|
||||
_timer.setSingleShot(true);
|
||||
}
|
||||
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
#include <QtGui/QVector3D>
|
||||
#include <QtGui/QQuaternion>
|
||||
#include <glm/gtc/quaternion.hpp>
|
||||
#include <QAbstractSocket>
|
||||
|
||||
#include "RegisteredMetaTypes.h"
|
||||
|
||||
|
@ -32,6 +33,7 @@ int xColorMetaTypeId = qRegisterMetaType<xColor>();
|
|||
int pickRayMetaTypeId = qRegisterMetaType<PickRay>();
|
||||
int collisionMetaTypeId = qRegisterMetaType<Collision>();
|
||||
int qMapURLStringMetaTypeId = qRegisterMetaType<QMap<QUrl,QString>>();
|
||||
int socketErrorMetaTypeId = qRegisterMetaType<QAbstractSocket::SocketError>();
|
||||
|
||||
void registerMetaTypes(QScriptEngine* engine) {
|
||||
qScriptRegisterMetaType(engine, mat4toScriptValue, mat4FromScriptValue);
|
||||
|
|
|
@ -155,7 +155,7 @@ void bindActionToQmlAction(QObject* qmlAction, QAction* action) {
|
|||
QObject::connect(qmlAction, SIGNAL(triggered()), action, SLOT(trigger()));
|
||||
}
|
||||
|
||||
class QQuickMenuItem;
|
||||
class QQuickMenuItem1;
|
||||
|
||||
void VrMenu::addAction(QMenu* menu, QAction* action) {
|
||||
Q_ASSERT(!MenuUserData::hasData(action));
|
||||
|
@ -167,10 +167,9 @@ void VrMenu::addAction(QMenu* menu, QAction* action) {
|
|||
}
|
||||
QObject* menuQml = findMenuObject(userData->uuid.toString());
|
||||
Q_ASSERT(menuQml);
|
||||
QQuickMenuItem* returnedValue { nullptr };
|
||||
|
||||
QQuickMenuItem1* returnedValue { nullptr };
|
||||
bool invokeResult = QMetaObject::invokeMethod(menuQml, "addItem", Qt::DirectConnection,
|
||||
Q_RETURN_ARG(QQuickMenuItem*, returnedValue),
|
||||
Q_RETURN_ARG(QQuickMenuItem1*, returnedValue),
|
||||
Q_ARG(QString, action->text()));
|
||||
|
||||
Q_ASSERT(invokeResult);
|
||||
|
@ -206,10 +205,10 @@ void VrMenu::insertAction(QAction* before, QAction* action) {
|
|||
beforeQml = findMenuObject(beforeUserData->uuid.toString());
|
||||
}
|
||||
QObject* menu = beforeQml->parent();
|
||||
QQuickMenuItem* returnedValue { nullptr };
|
||||
QQuickMenuItem1* returnedValue { nullptr };
|
||||
// FIXME this needs to find the index of the beforeQml item and call insertItem(int, object)
|
||||
bool invokeResult = QMetaObject::invokeMethod(menu, "addItem", Qt::DirectConnection,
|
||||
Q_RETURN_ARG(QQuickMenuItem*, returnedValue),
|
||||
Q_RETURN_ARG(QQuickMenuItem1*, returnedValue),
|
||||
Q_ARG(QString, action->text()));
|
||||
Q_ASSERT(invokeResult);
|
||||
QObject* result = reinterpret_cast<QObject*>(returnedValue); // returnedValue.value<QObject*>();
|
||||
|
|
|
@ -58,6 +58,9 @@ public:
|
|||
void unsuppressKeyboard() override;
|
||||
bool isKeyboardVisible() override;
|
||||
|
||||
// Needs an additional thread for VR submission
|
||||
int getRequiredThreadCount() const override { return Parent::getRequiredThreadCount() + 1; }
|
||||
|
||||
protected:
|
||||
bool internalActivate() override;
|
||||
void internalDeactivate() override;
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
/* global setEntityCustomData, getEntityCustomData, flatten, Xform, Script, Quat, Vec3, MyAvatar, Entities, Overlays, Settings, Reticle, Controller, Camera, Messages, Mat4 */
|
||||
|
||||
(function() { // BEGIN LOCAL_SCOPE
|
||||
|
||||
|
@ -24,6 +25,9 @@ var WANT_DEBUG = false;
|
|||
var WANT_DEBUG_STATE = false;
|
||||
var WANT_DEBUG_SEARCH_NAME = null;
|
||||
|
||||
var FORCE_IGNORE_IK = true;
|
||||
var SHOW_GRAB_POINT_SPHERE = true;
|
||||
|
||||
//
|
||||
// these tune time-averaging and "on" value for analog trigger
|
||||
//
|
||||
|
@ -59,6 +63,7 @@ var EQUIP_SPHERE_COLOR = {
|
|||
var EQUIP_SPHERE_ALPHA = 0.15;
|
||||
var EQUIP_SPHERE_SCALE_FACTOR = 0.65;
|
||||
|
||||
|
||||
//
|
||||
// distant manipulation
|
||||
//
|
||||
|
@ -87,21 +92,21 @@ var COLORS_GRAB_DISTANCE_HOLD = {
|
|||
blue: 214
|
||||
};
|
||||
|
||||
|
||||
var PICK_MAX_DISTANCE = 500; // max length of pick-ray
|
||||
|
||||
//
|
||||
// near grabbing
|
||||
//
|
||||
|
||||
var EQUIP_RADIUS = 0.1; // radius used for palm vs equip-hotspot for equipping.
|
||||
var EQUIP_RADIUS = 0.2; // radius used for palm vs equip-hotspot for equipping.
|
||||
// if EQUIP_HOTSPOT_RENDER_RADIUS is greater than zero, the hotspot will appear before the hand
|
||||
// has reached the required position, and then grow larger once the hand is close enough to equip.
|
||||
var EQUIP_HOTSPOT_RENDER_RADIUS = 0.0; // radius used for palm vs equip-hotspot for rendering hot-spots
|
||||
var MAX_EQUIP_HOTSPOT_RADIUS = 1.0;
|
||||
|
||||
var NEAR_GRABBING_ACTION_TIMEFRAME = 0.05; // how quickly objects move to their new position
|
||||
|
||||
var NEAR_GRAB_RADIUS = 0.15; // radius used for palm vs object for near grabbing.
|
||||
var NEAR_GRAB_RADIUS = 0.07; // radius used for palm vs object for near grabbing.
|
||||
var NEAR_GRAB_MAX_DISTANCE = 1.0; // you cannot grab objects that are this far away from your hand
|
||||
|
||||
var NEAR_GRAB_PICK_RADIUS = 0.25; // radius used for search ray vs object for near grabbing.
|
||||
|
@ -112,6 +117,13 @@ var NEAR_GRABBING_KINEMATIC = true; // force objects to be kinematic when near-g
|
|||
// if an equipped item is "adjusted" to be too far from the hand it's in, it will be unequipped.
|
||||
var CHECK_TOO_FAR_UNEQUIP_TIME = 0.3; // seconds, duration between checks
|
||||
|
||||
|
||||
var GRAB_POINT_SPHERE_OFFSET = { x: 0.0, y: 0.2, z: 0.0 };
|
||||
var GRAB_POINT_SPHERE_RADIUS = NEAR_GRAB_RADIUS;
|
||||
var GRAB_POINT_SPHERE_COLOR = { red: 20, green: 90, blue: 238 };
|
||||
var GRAB_POINT_SPHERE_ALPHA = 0.85;
|
||||
|
||||
|
||||
//
|
||||
// other constants
|
||||
//
|
||||
|
@ -168,7 +180,7 @@ var USE_BLACKLIST = true;
|
|||
var blacklist = [];
|
||||
|
||||
var FORBIDDEN_GRAB_NAMES = ["Grab Debug Entity", "grab pointer"];
|
||||
var FORBIDDEN_GRAB_TYPES = ['Unknown', 'Light', 'PolyLine', 'Zone'];
|
||||
var FORBIDDEN_GRAB_TYPES = ["Unknown", "Light", "PolyLine", "Zone"];
|
||||
|
||||
// states for the state machine
|
||||
var STATE_OFF = 0;
|
||||
|
@ -183,7 +195,6 @@ var STATE_ENTITY_TOUCHING = 7;
|
|||
// "collidesWith" is specified by comma-separated list of group names
|
||||
// the possible group names are: static, dynamic, kinematic, myAvatar, otherAvatar
|
||||
var COLLIDES_WITH_WHILE_GRABBED = "dynamic,otherAvatar";
|
||||
var COLLIDES_WITH_WHILE_MULTI_GRABBED = "dynamic";
|
||||
|
||||
var HEART_BEAT_INTERVAL = 5 * MSECS_PER_SEC;
|
||||
var HEART_BEAT_TIMEOUT = 15 * MSECS_PER_SEC;
|
||||
|
@ -273,11 +284,9 @@ function projectOntoEntityXYPlane(entityID, worldPos) {
|
|||
y: (1 - normalizedPos.y) * props.dimensions.y }; // flip y-axis
|
||||
}
|
||||
|
||||
function handLaserIntersectEntity(entityID, hand) {
|
||||
var standardControllerValue = (hand === RIGHT_HAND) ? Controller.Standard.RightHand : Controller.Standard.LeftHand;
|
||||
var pose = Controller.getPoseValue(standardControllerValue);
|
||||
var worldHandPosition = Vec3.sum(Vec3.multiplyQbyV(MyAvatar.orientation, pose.translation), MyAvatar.position);
|
||||
var worldHandRotation = Quat.multiply(MyAvatar.orientation, pose.rotation);
|
||||
function handLaserIntersectEntity(entityID, start) {
|
||||
var worldHandPosition = start.position;
|
||||
var worldHandRotation = start.orientation;
|
||||
|
||||
var props = entityPropertiesCache.getProps(entityID);
|
||||
|
||||
|
@ -355,7 +364,7 @@ function entityIsGrabbedByOther(entityID) {
|
|||
for (var actionIndex = 0; actionIndex < actionIDs.length; actionIndex++) {
|
||||
var actionID = actionIDs[actionIndex];
|
||||
var actionArguments = Entities.getActionArguments(entityID, actionID);
|
||||
var tag = actionArguments["tag"];
|
||||
var tag = actionArguments.tag;
|
||||
if (tag == getTag()) {
|
||||
// we see a grab-*uuid* shaped tag, but it's our tag, so that's okay.
|
||||
continue;
|
||||
|
@ -680,9 +689,7 @@ EquipHotspotBuddy.prototype.update = function(deltaTime, timestamp) {
|
|||
|
||||
if (overlayInfoSet.timestamp != timestamp && overlayInfoSet.currentSize <= 0.05) {
|
||||
// this is an old overlay, that has finished fading out, delete it!
|
||||
overlayInfoSet.overlays.forEach(function(overlay) {
|
||||
Overlays.deleteOverlay(overlay);
|
||||
});
|
||||
overlayInfoSet.overlays.forEach(Overlays.deleteOverlay);
|
||||
delete this.map[keys[i]];
|
||||
} else {
|
||||
// update overlay position, rotation to follow the object it's attached to.
|
||||
|
@ -714,16 +721,36 @@ var equipHotspotBuddy = new EquipHotspotBuddy();
|
|||
|
||||
function MyController(hand) {
|
||||
this.hand = hand;
|
||||
if (this.hand === RIGHT_HAND) {
|
||||
this.getHandPosition = MyAvatar.getRightPalmPosition;
|
||||
// this.getHandRotation = MyAvatar.getRightPalmRotation;
|
||||
} else {
|
||||
this.getHandPosition = MyAvatar.getLeftPalmPosition;
|
||||
// this.getHandRotation = MyAvatar.getLeftPalmRotation;
|
||||
}
|
||||
this.getHandRotation = function() {
|
||||
var controllerHandInput = (this.hand === RIGHT_HAND) ? Controller.Standard.RightHand : Controller.Standard.LeftHand;
|
||||
return Quat.multiply(MyAvatar.orientation, Controller.getPoseValue(controllerHandInput).rotation);
|
||||
this.autoUnequipCounter = 0;
|
||||
|
||||
// handPosition is where the avatar's hand appears to be, in-world.
|
||||
this.getHandPosition = function () {
|
||||
if (this.hand === RIGHT_HAND) {
|
||||
return MyAvatar.getRightPalmPosition();
|
||||
} else {
|
||||
return MyAvatar.getLeftPalmPosition();
|
||||
}
|
||||
};
|
||||
this.getHandRotation = function () {
|
||||
if (this.hand === RIGHT_HAND) {
|
||||
return MyAvatar.getRightPalmRotation();
|
||||
} else {
|
||||
return MyAvatar.getLeftPalmRotation();
|
||||
}
|
||||
};
|
||||
// controllerLocation is where the controller would be, in-world.
|
||||
this.getControllerLocation = function (doOffset) {
|
||||
var standardControllerValue = (hand === RIGHT_HAND) ? Controller.Standard.RightHand : Controller.Standard.LeftHand;
|
||||
var pose = Controller.getPoseValue(standardControllerValue);
|
||||
|
||||
var orientation = Quat.multiply(MyAvatar.orientation, pose.rotation);
|
||||
var position = Vec3.sum(Vec3.multiplyQbyV(MyAvatar.orientation, pose.translation), MyAvatar.position);
|
||||
// add to the real position so the grab-point is out in front of the hand, a bit
|
||||
if (doOffset) {
|
||||
position = Vec3.sum(position, Vec3.multiplyQbyV(orientation, GRAB_POINT_SPHERE_OFFSET));
|
||||
}
|
||||
|
||||
return {position: position, orientation: orientation};
|
||||
};
|
||||
|
||||
this.actionID = null; // action this script created...
|
||||
|
@ -830,6 +857,39 @@ function MyController(hand) {
|
|||
}
|
||||
};
|
||||
|
||||
this.grabPointSphereOn = function() {
|
||||
if (!SHOW_GRAB_POINT_SPHERE) {
|
||||
return;
|
||||
}
|
||||
if (!MyAvatar.sessionUUID) {
|
||||
return;
|
||||
}
|
||||
if (!this.grabPointSphere) {
|
||||
this.grabPointSphere = Overlays.addOverlay("sphere", {
|
||||
localPosition: GRAB_POINT_SPHERE_OFFSET,
|
||||
localRotation: { x: 0, y: 0, z: 0, w: 1 },
|
||||
dimensions: GRAB_POINT_SPHERE_RADIUS,
|
||||
color: GRAB_POINT_SPHERE_COLOR,
|
||||
alpha: GRAB_POINT_SPHERE_ALPHA,
|
||||
solid: true,
|
||||
visible: true,
|
||||
ignoreRayIntersection: true,
|
||||
drawInFront: false,
|
||||
parentID: MyAvatar.sessionUUID,
|
||||
parentJointIndex: MyAvatar.getJointIndex(this.hand === RIGHT_HAND ?
|
||||
"_CONTROLLER_RIGHTHAND" :
|
||||
"_CONTROLLER_LEFTHAND")
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
this.grabPointSphereOff = function() {
|
||||
if (this.grabPointSphere) {
|
||||
Overlays.deleteOverlay(this.grabPointSphere);
|
||||
this.grabPointSphere = null;
|
||||
}
|
||||
};
|
||||
|
||||
this.searchSphereOn = function(location, size, color) {
|
||||
|
||||
var rotation = Quat.lookAt(location, Camera.getPosition(), Vec3.UP);
|
||||
|
@ -905,10 +965,14 @@ function MyController(hand) {
|
|||
var searchSphereLocation = Vec3.sum(distantPickRay.origin,
|
||||
Vec3.multiply(distantPickRay.direction, this.searchSphereDistance));
|
||||
this.searchSphereOn(searchSphereLocation, SEARCH_SPHERE_SIZE * this.searchSphereDistance,
|
||||
(this.triggerSmoothedGrab() || this.secondarySqueezed()) ? COLORS_GRAB_SEARCHING_FULL_SQUEEZE : COLORS_GRAB_SEARCHING_HALF_SQUEEZE);
|
||||
(this.triggerSmoothedGrab() || this.secondarySqueezed()) ?
|
||||
COLORS_GRAB_SEARCHING_FULL_SQUEEZE :
|
||||
COLORS_GRAB_SEARCHING_HALF_SQUEEZE);
|
||||
if (PICK_WITH_HAND_RAY) {
|
||||
this.overlayLineOn(handPosition, searchSphereLocation,
|
||||
(this.triggerSmoothedGrab() || this.secondarySqueezed()) ? COLORS_GRAB_SEARCHING_FULL_SQUEEZE : COLORS_GRAB_SEARCHING_HALF_SQUEEZE);
|
||||
(this.triggerSmoothedGrab() || this.secondarySqueezed()) ?
|
||||
COLORS_GRAB_SEARCHING_FULL_SQUEEZE :
|
||||
COLORS_GRAB_SEARCHING_HALF_SQUEEZE);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -958,7 +1022,8 @@ function MyController(hand) {
|
|||
this.turnOffVisualizations = function() {
|
||||
|
||||
this.overlayLineOff();
|
||||
|
||||
this.grabPointSphereOff();
|
||||
this.lineOff();
|
||||
this.searchSphereOff();
|
||||
restore2DMode();
|
||||
|
||||
|
@ -1029,19 +1094,20 @@ function MyController(hand) {
|
|||
}
|
||||
if (!this.waitForTriggerRelease && this.triggerSmoothedSqueezed()) {
|
||||
this.lastPickTime = 0;
|
||||
var controllerHandInput = (this.hand === RIGHT_HAND) ? Controller.Standard.RightHand : Controller.Standard.LeftHand;
|
||||
this.startingHandRotation = Controller.getPoseValue(controllerHandInput).rotation;
|
||||
this.startingHandRotation = this.getControllerLocation(true).orientation;
|
||||
if (this.triggerSmoothedSqueezed()) {
|
||||
this.setState(STATE_SEARCHING, "trigger squeeze detected");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
var candidateEntities = Entities.findEntities(this.getHandPosition(), EQUIP_HOTSPOT_RENDER_RADIUS);
|
||||
this.grabPointSphereOn();
|
||||
|
||||
var candidateEntities = Entities.findEntities(this.getControllerLocation(true).position, MAX_EQUIP_HOTSPOT_RADIUS);
|
||||
entityPropertiesCache.addEntities(candidateEntities);
|
||||
var potentialEquipHotspot = this.chooseBestEquipHotspot(candidateEntities);
|
||||
if (!this.waitForTriggerRelease) {
|
||||
this.updateEquipHaptics(potentialEquipHotspot, this.getHandPosition());
|
||||
this.updateEquipHaptics(potentialEquipHotspot, this.getControllerLocation(true).position);
|
||||
}
|
||||
|
||||
var nearEquipHotspots = this.chooseNearEquipHotspots(candidateEntities, EQUIP_HOTSPOT_RENDER_RADIUS);
|
||||
|
@ -1060,23 +1126,27 @@ function MyController(hand) {
|
|||
!potentialEquipHotspot && this.prevPotentialEquipHotspot) {
|
||||
Controller.triggerHapticPulse(HAPTIC_TEXTURE_STRENGTH, HAPTIC_TEXTURE_DURATION, this.hand);
|
||||
this.lastHapticPulseLocation = currentLocation;
|
||||
} else if (potentialEquipHotspot && Vec3.distance(this.lastHapticPulseLocation, currentLocation) > HAPTIC_TEXTURE_DISTANCE) {
|
||||
} else if (potentialEquipHotspot &&
|
||||
Vec3.distance(this.lastHapticPulseLocation, currentLocation) > HAPTIC_TEXTURE_DISTANCE) {
|
||||
Controller.triggerHapticPulse(HAPTIC_TEXTURE_STRENGTH, HAPTIC_TEXTURE_DURATION, this.hand);
|
||||
this.lastHapticPulseLocation = currentLocation;
|
||||
}
|
||||
this.prevPotentialEquipHotspot = potentialEquipHotspot;
|
||||
};
|
||||
|
||||
this.heartBeatIsStale = function(data) {
|
||||
var now = Date.now();
|
||||
return data.heartBeat === undefined || now - data.heartBeat > HEART_BEAT_TIMEOUT;
|
||||
};
|
||||
|
||||
// Performs ray pick test from the hand controller into the world
|
||||
// @param {number} which hand to use, RIGHT_HAND or LEFT_HAND
|
||||
// @returns {object} returns object with two keys entityID and distance
|
||||
//
|
||||
this.calcRayPickInfo = function(hand) {
|
||||
|
||||
var standardControllerValue = (hand === RIGHT_HAND) ? Controller.Standard.RightHand : Controller.Standard.LeftHand;
|
||||
var pose = Controller.getPoseValue(standardControllerValue);
|
||||
var worldHandPosition = Vec3.sum(Vec3.multiplyQbyV(MyAvatar.orientation, pose.translation), MyAvatar.position);
|
||||
var worldHandRotation = Quat.multiply(MyAvatar.orientation, pose.rotation);
|
||||
var controllerLocation = this.getControllerLocation(true);
|
||||
var worldHandPosition = controllerLocation.position;
|
||||
var worldHandRotation = controllerLocation.orientation;
|
||||
|
||||
var pickRay = {
|
||||
origin: PICK_WITH_HAND_RAY ? worldHandPosition : Camera.position,
|
||||
|
@ -1196,7 +1266,7 @@ function MyController(hand) {
|
|||
var okToEquipFromOtherHand = ((this.getOtherHandController().state == STATE_NEAR_GRABBING ||
|
||||
this.getOtherHandController().state == STATE_DISTANCE_HOLDING) &&
|
||||
this.getOtherHandController().grabbedEntity == hotspot.entityID);
|
||||
if (refCount > 0 && !okToEquipFromOtherHand) {
|
||||
if (refCount > 0 && !this.heartBeatIsStale(grabProps) && !okToEquipFromOtherHand) {
|
||||
if (debug) {
|
||||
print("equip is skipping '" + props.name + "': grabbed by someone else");
|
||||
}
|
||||
|
@ -1213,20 +1283,21 @@ function MyController(hand) {
|
|||
var physical = propsArePhysical(props);
|
||||
var grabbable = false;
|
||||
var debug = (WANT_DEBUG_SEARCH_NAME && props.name === WANT_DEBUG_SEARCH_NAME);
|
||||
var refCount = ("refCount" in grabProps) ? grabProps.refCount : 0;
|
||||
|
||||
if (physical) {
|
||||
// physical things default to grabbable
|
||||
grabbable = true;
|
||||
} else {
|
||||
// non-physical things default to non-grabbable unless they are already grabbed
|
||||
if ("refCount" in grabProps && grabProps.refCount > 0) {
|
||||
if (refCount > 0) {
|
||||
grabbable = true;
|
||||
} else {
|
||||
grabbable = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (grabbableProps.hasOwnProperty("grabbable")) {
|
||||
if (grabbableProps.hasOwnProperty("grabbable") && refCount === 0) {
|
||||
grabbable = grabbableProps.grabbable;
|
||||
}
|
||||
|
||||
|
@ -1321,7 +1392,7 @@ function MyController(hand) {
|
|||
return _this.collectEquipHotspots(entityID);
|
||||
})).filter(function(hotspot) {
|
||||
return (_this.hotspotIsEquippable(hotspot) &&
|
||||
Vec3.distance(hotspot.worldPosition, _this.getHandPosition()) < hotspot.radius + distance);
|
||||
Vec3.distance(hotspot.worldPosition, _this.getControllerLocation(true).position) < hotspot.radius + distance);
|
||||
});
|
||||
return equippableHotspots;
|
||||
};
|
||||
|
@ -1332,8 +1403,8 @@ function MyController(hand) {
|
|||
if (equippableHotspots.length > 0) {
|
||||
// sort by distance
|
||||
equippableHotspots.sort(function(a, b) {
|
||||
var aDistance = Vec3.distance(a.worldPosition, this.getHandPosition());
|
||||
var bDistance = Vec3.distance(b.worldPosition, this.getHandPosition());
|
||||
var aDistance = Vec3.distance(a.worldPosition, this.getControllerLocation(true).position);
|
||||
var bDistance = Vec3.distance(b.worldPosition, this.getControllerLocation(true).position);
|
||||
return aDistance - bDistance;
|
||||
});
|
||||
return equippableHotspots[0];
|
||||
|
@ -1359,6 +1430,8 @@ function MyController(hand) {
|
|||
this.isInitialGrab = false;
|
||||
this.shouldResetParentOnRelease = false;
|
||||
|
||||
this.grabPointSphereOn();
|
||||
|
||||
this.checkForStrayChildren();
|
||||
|
||||
if (this.triggerSmoothedReleased()) {
|
||||
|
@ -1366,7 +1439,7 @@ function MyController(hand) {
|
|||
return;
|
||||
}
|
||||
|
||||
var handPosition = this.getHandPosition();
|
||||
var handPosition = this.getControllerLocation(true).position;
|
||||
|
||||
var rayPickInfo = this.calcRayPickInfo(this.hand);
|
||||
|
||||
|
@ -1374,10 +1447,10 @@ function MyController(hand) {
|
|||
entityPropertiesCache.addEntity(rayPickInfo.entityID);
|
||||
}
|
||||
|
||||
var candidateEntities = Entities.findEntities(handPosition, NEAR_GRAB_RADIUS);
|
||||
entityPropertiesCache.addEntities(candidateEntities);
|
||||
var candidateHotSpotEntities = Entities.findEntities(handPosition, MAX_EQUIP_HOTSPOT_RADIUS);
|
||||
entityPropertiesCache.addEntities(candidateHotSpotEntities);
|
||||
|
||||
var potentialEquipHotspot = this.chooseBestEquipHotspot(candidateEntities);
|
||||
var potentialEquipHotspot = this.chooseBestEquipHotspot(candidateHotSpotEntities);
|
||||
if (potentialEquipHotspot) {
|
||||
if (this.triggerSmoothedGrab()) {
|
||||
this.grabbedHotspot = potentialEquipHotspot;
|
||||
|
@ -1387,6 +1460,7 @@ function MyController(hand) {
|
|||
}
|
||||
}
|
||||
|
||||
var candidateEntities = Entities.findEntities(handPosition, NEAR_GRAB_RADIUS);
|
||||
var grabbableEntities = candidateEntities.filter(function(entity) {
|
||||
return _this.entityIsNearGrabbable(entity, handPosition, NEAR_GRAB_MAX_DISTANCE);
|
||||
});
|
||||
|
@ -1546,18 +1620,13 @@ function MyController(hand) {
|
|||
};
|
||||
|
||||
this.distanceHoldingEnter = function() {
|
||||
Messages.sendLocalMessage('Hifi-Teleport-Disabler','both');
|
||||
Messages.sendLocalMessage('Hifi-Teleport-Disabler', 'both');
|
||||
this.clearEquipHaptics();
|
||||
this.grabPointSphereOff();
|
||||
|
||||
// controller pose is in avatar frame
|
||||
var device = (this.hand === RIGHT_HAND) ? Controller.Standard.RightHand : Controller.Standard.LeftHand;
|
||||
var avatarControllerPose = Controller.getPoseValue(device);
|
||||
var worldControllerPosition = this.getControllerLocation(true).position;
|
||||
|
||||
// transform it into world frame
|
||||
var worldControllerPosition = Vec3.sum(MyAvatar.position,
|
||||
Vec3.multiplyQbyV(MyAvatar.orientation, avatarControllerPose.translation));
|
||||
|
||||
// also transform the position into room space
|
||||
// transform the position into room space
|
||||
var worldToSensorMat = Mat4.inverse(MyAvatar.getSensorToWorldMatrix());
|
||||
var roomControllerPosition = Mat4.transformPoint(worldToSensorMat, worldControllerPosition);
|
||||
|
||||
|
@ -1620,14 +1689,10 @@ function MyController(hand) {
|
|||
|
||||
this.heartBeat(this.grabbedEntity);
|
||||
|
||||
// controller pose is in avatar frame
|
||||
var device = (this.hand === RIGHT_HAND) ? Controller.Standard.RightHand : Controller.Standard.LeftHand;
|
||||
var avatarControllerPose = Controller.getPoseValue(device);
|
||||
|
||||
// transform it into world frame
|
||||
var worldControllerPosition = Vec3.sum(MyAvatar.position,
|
||||
Vec3.multiplyQbyV(MyAvatar.orientation, avatarControllerPose.translation));
|
||||
var worldControllerRotation = Quat.multiply(MyAvatar.orientation, avatarControllerPose.rotation);
|
||||
var controllerLocation = this.getControllerLocation(true);
|
||||
var worldControllerPosition = controllerLocation.position;
|
||||
var worldControllerRotation = controllerLocation.orientation;
|
||||
|
||||
// also transform the position into room space
|
||||
var worldToSensorMat = Mat4.inverse(MyAvatar.getSensorToWorldMatrix());
|
||||
|
@ -1698,8 +1763,6 @@ function MyController(hand) {
|
|||
}
|
||||
}
|
||||
|
||||
var handPosition = this.getHandPosition();
|
||||
|
||||
// visualizations
|
||||
|
||||
var rayPickInfo = this.calcRayPickInfo(this.hand);
|
||||
|
@ -1764,10 +1827,7 @@ function MyController(hand) {
|
|||
};
|
||||
|
||||
this.dropGestureProcess = function(deltaTime) {
|
||||
var standardControllerValue = (this.hand === RIGHT_HAND) ? Controller.Standard.RightHand : Controller.Standard.LeftHand;
|
||||
var pose = Controller.getPoseValue(standardControllerValue);
|
||||
var worldHandRotation = Quat.multiply(MyAvatar.orientation, pose.rotation);
|
||||
|
||||
var worldHandRotation = this.getControllerLocation(true).orientation;
|
||||
var localHandUpAxis = this.hand === RIGHT_HAND ? {
|
||||
x: 1,
|
||||
y: 0,
|
||||
|
@ -1806,14 +1866,14 @@ function MyController(hand) {
|
|||
this.nearGrabbingEnter = function() {
|
||||
if (this.hand === 0) {
|
||||
Messages.sendLocalMessage('Hifi-Teleport-Disabler', 'left');
|
||||
|
||||
}
|
||||
if (this.hand === 1) {
|
||||
Messages.sendLocalMessage('Hifi-Teleport-Disabler', 'right');
|
||||
|
||||
}
|
||||
this.grabPointSphereOff();
|
||||
this.lineOff();
|
||||
this.overlayLineOff();
|
||||
this.searchSphereOff();
|
||||
|
||||
this.dropGestureReset();
|
||||
this.clearEquipHaptics();
|
||||
|
@ -1835,12 +1895,23 @@ function MyController(hand) {
|
|||
var grabbedProperties = Entities.getEntityProperties(this.grabbedEntity, GRABBABLE_PROPERTIES);
|
||||
this.activateEntity(this.grabbedEntity, grabbedProperties, false);
|
||||
|
||||
// var handRotation = this.getHandRotation();
|
||||
var handRotation = (this.hand === RIGHT_HAND) ? MyAvatar.getRightPalmRotation() : MyAvatar.getLeftPalmRotation();
|
||||
var handPosition = this.getHandPosition();
|
||||
|
||||
var grabbableData = getEntityCustomData(GRABBABLE_DATA_KEY, this.grabbedEntity, DEFAULT_GRABBABLE_DATA);
|
||||
this.ignoreIK = grabbableData.ignoreIK ? grabbableData.ignoreIK : false;
|
||||
if (FORCE_IGNORE_IK) {
|
||||
this.ignoreIK = true;
|
||||
} else {
|
||||
this.ignoreIK = grabbableData.ignoreIK ? grabbableData.ignoreIK : false;
|
||||
}
|
||||
|
||||
var handRotation;
|
||||
var handPosition;
|
||||
if (this.ignoreIK) {
|
||||
var controllerLocation = this.getControllerLocation(false);
|
||||
handRotation = controllerLocation.orientation;
|
||||
handPosition = controllerLocation.position;
|
||||
} else {
|
||||
handRotation = this.getHandRotation();
|
||||
handPosition = this.getHandPosition();
|
||||
}
|
||||
|
||||
var hasPresetPosition = false;
|
||||
if (this.state == STATE_HOLD && this.grabbedHotspot) {
|
||||
|
@ -1879,12 +1950,21 @@ function MyController(hand) {
|
|||
}
|
||||
Messages.sendMessage('Hifi-Object-Manipulation', JSON.stringify({
|
||||
action: 'grab',
|
||||
grabbedEntity: this.grabbedEntity
|
||||
grabbedEntity: this.grabbedEntity,
|
||||
joint: this.hand === RIGHT_HAND ? "RightHand" : "LeftHand"
|
||||
}));
|
||||
} else {
|
||||
// grab entity via parenting
|
||||
this.actionID = null;
|
||||
var handJointIndex = MyAvatar.getJointIndex(this.hand === RIGHT_HAND ? "RightHand" : "LeftHand");
|
||||
var handJointIndex;
|
||||
if (this.ignoreIK) {
|
||||
handJointIndex = MyAvatar.getJointIndex(this.hand === RIGHT_HAND ?
|
||||
"_CONTROLLER_RIGHTHAND" :
|
||||
"_CONTROLLER_LEFTHAND");
|
||||
} else {
|
||||
handJointIndex = MyAvatar.getJointIndex(this.hand === RIGHT_HAND ? "RightHand" : "LeftHand");
|
||||
}
|
||||
|
||||
var reparentProps = {
|
||||
parentID: MyAvatar.sessionUUID,
|
||||
parentJointIndex: handJointIndex,
|
||||
|
@ -1892,14 +1972,15 @@ function MyController(hand) {
|
|||
angularVelocity: {x: 0, y: 0, z: 0}
|
||||
};
|
||||
if (hasPresetPosition) {
|
||||
reparentProps["localPosition"] = this.offsetPosition;
|
||||
reparentProps["localRotation"] = this.offsetRotation;
|
||||
reparentProps.localPosition = this.offsetPosition;
|
||||
reparentProps.localRotation = this.offsetRotation;
|
||||
}
|
||||
Entities.editEntity(this.grabbedEntity, reparentProps);
|
||||
|
||||
Messages.sendMessage('Hifi-Object-Manipulation', JSON.stringify({
|
||||
action: 'equip',
|
||||
grabbedEntity: this.grabbedEntity
|
||||
grabbedEntity: this.grabbedEntity,
|
||||
joint: this.hand === RIGHT_HAND ? "RightHand" : "LeftHand"
|
||||
}));
|
||||
}
|
||||
|
||||
|
@ -1937,6 +2018,8 @@ function MyController(hand) {
|
|||
|
||||
this.nearGrabbing = function(deltaTime, timestamp) {
|
||||
|
||||
this.grabPointSphereOff();
|
||||
|
||||
if (this.state == STATE_NEAR_GRABBING && !this.triggerClicked) {
|
||||
this.callEntityMethodOnGrabbed("releaseGrab");
|
||||
this.setState(STATE_OFF, "trigger released");
|
||||
|
@ -1967,9 +2050,10 @@ function MyController(hand) {
|
|||
|
||||
// store the offset attach points into preferences.
|
||||
if (USE_ATTACH_POINT_SETTINGS && this.grabbedHotspot && this.grabbedEntity) {
|
||||
var props = Entities.getEntityProperties(this.grabbedEntity, ["localPosition", "localRotation"]);
|
||||
if (props && props.localPosition && props.localRotation) {
|
||||
storeAttachPointForHotspotInSettings(this.grabbedHotspot, this.hand, props.localPosition, props.localRotation);
|
||||
var prefprops = Entities.getEntityProperties(this.grabbedEntity, ["localPosition", "localRotation"]);
|
||||
if (prefprops && prefprops.localPosition && prefprops.localRotation) {
|
||||
storeAttachPointForHotspotInSettings(this.grabbedHotspot, this.hand,
|
||||
prefprops.localPosition, prefprops.localRotation);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1988,22 +2072,34 @@ function MyController(hand) {
|
|||
"position", "rotation", "dimensions",
|
||||
"registrationPoint"]);
|
||||
if (!props.position) {
|
||||
// server may have reset, taking our equipped entity with it. move back to "off" stte
|
||||
// server may have reset, taking our equipped entity with it. move back to "off" state
|
||||
this.callEntityMethodOnGrabbed("releaseGrab");
|
||||
this.setState(STATE_OFF, "entity has no position property");
|
||||
return;
|
||||
}
|
||||
|
||||
var now = Date.now();
|
||||
if (now - this.lastUnequipCheckTime > MSECS_PER_SEC * CHECK_TOO_FAR_UNEQUIP_TIME) {
|
||||
if (this.state == STATE_HOLD && now - this.lastUnequipCheckTime > MSECS_PER_SEC * CHECK_TOO_FAR_UNEQUIP_TIME) {
|
||||
this.lastUnequipCheckTime = now;
|
||||
|
||||
if (props.parentID == MyAvatar.sessionUUID) {
|
||||
var handPosition = this.getHandPosition();
|
||||
var handPosition;
|
||||
if (this.ignoreIK) {
|
||||
handPosition = this.getControllerLocation(false).position;
|
||||
} else {
|
||||
handPosition = this.getHandPosition();
|
||||
}
|
||||
|
||||
var TEAR_AWAY_DISTANCE = 0.1;
|
||||
var dist = distanceBetweenPointAndEntityBoundingBox(handPosition, props);
|
||||
if (dist > TEAR_AWAY_DISTANCE) {
|
||||
this.autoUnequipCounter += 1;
|
||||
} else {
|
||||
this.autoUnequipCounter = 0;
|
||||
}
|
||||
|
||||
if (this.autoUnequipCounter > 1) {
|
||||
// for whatever reason, the held/equipped entity has been pulled away. ungrab or unequip.
|
||||
print("handControllerGrab -- autoreleasing held or equipped item because it is far from hand." +
|
||||
props.parentID + ", dist = " + dist);
|
||||
|
||||
|
@ -2076,16 +2172,15 @@ function MyController(hand) {
|
|||
};
|
||||
|
||||
this.nearTriggerEnter = function() {
|
||||
|
||||
this.clearEquipHaptics();
|
||||
|
||||
this.grabPointSphereOff();
|
||||
Controller.triggerShortHapticPulse(1.0, this.hand);
|
||||
this.callEntityMethodOnGrabbed("startNearTrigger");
|
||||
};
|
||||
|
||||
this.farTriggerEnter = function() {
|
||||
this.clearEquipHaptics();
|
||||
|
||||
this.grabPointSphereOff();
|
||||
this.callEntityMethodOnGrabbed("startFarTrigger");
|
||||
};
|
||||
|
||||
|
@ -2105,10 +2200,9 @@ function MyController(hand) {
|
|||
return;
|
||||
}
|
||||
|
||||
var handPosition = this.getHandPosition();
|
||||
var pickRay = {
|
||||
origin: handPosition,
|
||||
direction: Quat.getUp(this.getHandRotation())
|
||||
origin: this.getControllerLocation().position,
|
||||
direction: Quat.getUp(this.getControllerLocation().orientation)
|
||||
};
|
||||
|
||||
var now = Date.now();
|
||||
|
@ -2137,7 +2231,7 @@ function MyController(hand) {
|
|||
|
||||
this.entityTouchingEnter = function() {
|
||||
// test for intersection between controller laser and web entity plane.
|
||||
var intersectInfo = handLaserIntersectEntity(this.grabbedEntity, this.hand);
|
||||
var intersectInfo = handLaserIntersectEntity(this.grabbedEntity, this.getControllerLocation(true));
|
||||
if (intersectInfo) {
|
||||
var pointerEvent = {
|
||||
type: "Press",
|
||||
|
@ -2162,7 +2256,7 @@ function MyController(hand) {
|
|||
|
||||
this.entityTouchingExit = function() {
|
||||
// test for intersection between controller laser and web entity plane.
|
||||
var intersectInfo = handLaserIntersectEntity(this.grabbedEntity, this.hand);
|
||||
var intersectInfo = handLaserIntersectEntity(this.grabbedEntity, this.getControllerLocation(true));
|
||||
if (intersectInfo) {
|
||||
var pointerEvent;
|
||||
if (this.deadspotExpired) {
|
||||
|
@ -2200,7 +2294,7 @@ function MyController(hand) {
|
|||
}
|
||||
|
||||
// test for intersection between controller laser and web entity plane.
|
||||
var intersectInfo = handLaserIntersectEntity(this.grabbedEntity, this.hand);
|
||||
var intersectInfo = handLaserIntersectEntity(this.grabbedEntity, this.getControllerLocation(true));
|
||||
if (intersectInfo) {
|
||||
|
||||
if (Entities.keyboardFocusEntity != this.grabbedEntity) {
|
||||
|
@ -2237,7 +2331,7 @@ function MyController(hand) {
|
|||
};
|
||||
|
||||
this.release = function() {
|
||||
Messages.sendLocalMessage('Hifi-Teleport-Disabler','none');
|
||||
Messages.sendLocalMessage('Hifi-Teleport-Disabler', 'none');
|
||||
this.turnOffVisualizations();
|
||||
|
||||
var noVelocity = false;
|
||||
|
@ -2249,16 +2343,7 @@ function MyController(hand) {
|
|||
// If this looks like the release after adjusting something still held in the other hand, print the position
|
||||
// and rotation of the held thing to help content creators set the userData.
|
||||
var grabData = getEntityCustomData(GRAB_USER_DATA_KEY, this.grabbedEntity, {});
|
||||
if (grabData.refCount > 1) {
|
||||
var grabbedProperties = Entities.getEntityProperties(this.grabbedEntity, ["localPosition", "localRotation"]);
|
||||
if (grabbedProperties && grabbedProperties.localPosition && grabbedProperties.localRotation) {
|
||||
print((this.hand === RIGHT_HAND ? '"LeftHand"' : '"RightHand"') + ":" +
|
||||
'[{"x":' + grabbedProperties.localPosition.x + ', "y":' + grabbedProperties.localPosition.y +
|
||||
', "z":' + grabbedProperties.localPosition.z + '}, {"x":' + grabbedProperties.localRotation.x +
|
||||
', "y":' + grabbedProperties.localRotation.y + ', "z":' + grabbedProperties.localRotation.z +
|
||||
', "w":' + grabbedProperties.localRotation.w + '}]');
|
||||
}
|
||||
}
|
||||
this.printNewOffsets = (grabData.refCount > 1);
|
||||
|
||||
if (this.actionID !== null) {
|
||||
Entities.deleteAction(this.grabbedEntity, this.actionID);
|
||||
|
@ -2272,17 +2357,17 @@ function MyController(hand) {
|
|||
noVelocity = true;
|
||||
}
|
||||
}
|
||||
|
||||
this.deactivateEntity(this.grabbedEntity, noVelocity);
|
||||
|
||||
Messages.sendMessage('Hifi-Object-Manipulation', JSON.stringify({
|
||||
action: 'release',
|
||||
grabbedEntity: this.grabbedEntity,
|
||||
joint: this.hand === RIGHT_HAND ? "RightHand" : "LeftHand"
|
||||
}));
|
||||
}
|
||||
|
||||
this.deactivateEntity(this.grabbedEntity, noVelocity);
|
||||
this.actionID = null;
|
||||
|
||||
Messages.sendMessage('Hifi-Object-Manipulation', JSON.stringify({
|
||||
action: 'release',
|
||||
grabbedEntity: this.grabbedEntity,
|
||||
joint: this.hand === RIGHT_HAND ? "RightHand" : "LeftHand"
|
||||
}));
|
||||
|
||||
this.grabbedEntity = null;
|
||||
this.grabbedHotspot = null;
|
||||
|
||||
|
@ -2293,13 +2378,14 @@ function MyController(hand) {
|
|||
|
||||
this.cleanup = function() {
|
||||
this.release();
|
||||
this.grabPointSphereOff();
|
||||
};
|
||||
|
||||
this.heartBeat = function(entityID) {
|
||||
var now = Date.now();
|
||||
if (now - this.lastHeartBeat > HEART_BEAT_INTERVAL) {
|
||||
var data = getEntityCustomData(GRAB_USER_DATA_KEY, entityID, {});
|
||||
data["heartBeat"] = now;
|
||||
data.heartBeat = now;
|
||||
setEntityCustomData(GRAB_USER_DATA_KEY, entityID, data);
|
||||
this.lastHeartBeat = now;
|
||||
}
|
||||
|
@ -2308,12 +2394,14 @@ function MyController(hand) {
|
|||
this.resetAbandonedGrab = function(entityID) {
|
||||
print("cleaning up abandoned grab on " + entityID);
|
||||
var data = getEntityCustomData(GRAB_USER_DATA_KEY, entityID, {});
|
||||
data["refCount"] = 1;
|
||||
data.refCount = 1;
|
||||
setEntityCustomData(GRAB_USER_DATA_KEY, entityID, data);
|
||||
this.deactivateEntity(entityID, false);
|
||||
};
|
||||
|
||||
this.activateEntity = function(entityID, grabbedProperties, wasLoaded) {
|
||||
this.autoUnequipCounter = 0;
|
||||
|
||||
if (this.entityActivated) {
|
||||
return;
|
||||
}
|
||||
|
@ -2327,29 +2415,29 @@ function MyController(hand) {
|
|||
// get re-instated after all the grabs have been released) be correct.
|
||||
Script.clearTimeout(delayedDeactivateTimeout);
|
||||
delayedDeactivateTimeout = null;
|
||||
grabbedProperties["collidesWith"] = delayedDeactivateFunc();
|
||||
grabbedProperties.collidesWith = delayedDeactivateFunc();
|
||||
}
|
||||
|
||||
var data = getEntityCustomData(GRAB_USER_DATA_KEY, entityID, {});
|
||||
var now = Date.now();
|
||||
|
||||
if (wasLoaded) {
|
||||
data["refCount"] = 1;
|
||||
data.refCount = 1;
|
||||
} else {
|
||||
data["refCount"] = data["refCount"] ? data["refCount"] + 1 : 1;
|
||||
data.refCount = data.refCount ? data.refCount + 1 : 1;
|
||||
|
||||
// zero gravity and set ignoreForCollisions in a way that lets us put them back, after all grabs are done
|
||||
if (data["refCount"] == 1) {
|
||||
data["heartBeat"] = now;
|
||||
if (data.refCount == 1) {
|
||||
data.heartBeat = now;
|
||||
this.lastHeartBeat = now;
|
||||
|
||||
this.isInitialGrab = true;
|
||||
data["gravity"] = grabbedProperties.gravity;
|
||||
data["collidesWith"] = grabbedProperties.collidesWith;
|
||||
data["collisionless"] = grabbedProperties.collisionless;
|
||||
data["dynamic"] = grabbedProperties.dynamic;
|
||||
data["parentID"] = wasLoaded ? NULL_UUID : grabbedProperties.parentID;
|
||||
data["parentJointIndex"] = grabbedProperties.parentJointIndex;
|
||||
data.gravity = grabbedProperties.gravity;
|
||||
data.collidesWith = grabbedProperties.collidesWith;
|
||||
data.collisionless = grabbedProperties.collisionless;
|
||||
data.dynamic = grabbedProperties.dynamic;
|
||||
data.parentID = wasLoaded ? NULL_UUID : grabbedProperties.parentID;
|
||||
data.parentJointIndex = grabbedProperties.parentJointIndex;
|
||||
|
||||
var whileHeldProperties = {
|
||||
gravity: {
|
||||
|
@ -2363,9 +2451,8 @@ function MyController(hand) {
|
|||
"collidesWith": COLLIDES_WITH_WHILE_GRABBED
|
||||
};
|
||||
Entities.editEntity(entityID, whileHeldProperties);
|
||||
} else if (data["refCount"] > 1) {
|
||||
if (data["heartBeat"] === undefined ||
|
||||
now - data["heartBeat"] > HEART_BEAT_TIMEOUT) {
|
||||
} else if (data.refCount > 1) {
|
||||
if (this.heartBeatIsStale(data)) {
|
||||
// this entity has userData suggesting it is grabbed, but nobody is updating the hearbeat.
|
||||
// deactivate it before grabbing.
|
||||
this.resetAbandonedGrab(entityID);
|
||||
|
@ -2380,7 +2467,8 @@ function MyController(hand) {
|
|||
// bootstrap themselves with the held object. This happens because the meaning of "otherAvatar" in
|
||||
// the collision mask hinges on who the physics simulation owner is.
|
||||
Entities.editEntity(entityID, {
|
||||
"collidesWith": COLLIDES_WITH_WHILE_MULTI_GRABBED
|
||||
// "collidesWith": removeAvatarsFromCollidesWith(grabbedProperties.collidesWith)
|
||||
collisionless: true
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -2393,6 +2481,10 @@ function MyController(hand) {
|
|||
// unhook them.
|
||||
var handJointIndex = MyAvatar.getJointIndex(this.hand === RIGHT_HAND ? "RightHand" : "LeftHand");
|
||||
var children = Entities.getChildrenIDsOfJoint(MyAvatar.sessionUUID, handJointIndex);
|
||||
var controllerJointIndex = MyAvatar.getJointIndex(this.hand === RIGHT_HAND ?
|
||||
"_CONTROLLER_RIGHTHAND" :
|
||||
"_CONTROLLER_LEFTHAND");
|
||||
children.concat(Entities.getChildrenIDsOfJoint(MyAvatar.sessionUUID, controllerJointIndex));
|
||||
children.forEach(function(childID) {
|
||||
print("disconnecting stray child of hand: (" + _this.hand + ") " + childID);
|
||||
Entities.editEntity(childID, {
|
||||
|
@ -2411,9 +2503,9 @@ function MyController(hand) {
|
|||
collidesWith: collidesWith
|
||||
});
|
||||
var data = getEntityCustomData(GRAB_USER_DATA_KEY, entityID, {});
|
||||
if (data && data["refCount"]) {
|
||||
data["refCount"] = data["refCount"] - 1;
|
||||
if (data["refCount"] < 1) {
|
||||
if (data && data.refCount) {
|
||||
data.refCount = data.refCount - 1;
|
||||
if (data.refCount < 1) {
|
||||
data = null;
|
||||
}
|
||||
} else {
|
||||
|
@ -2433,24 +2525,24 @@ function MyController(hand) {
|
|||
|
||||
var data = getEntityCustomData(GRAB_USER_DATA_KEY, entityID, {});
|
||||
var doDelayedDeactivate = false;
|
||||
if (data && data["refCount"]) {
|
||||
data["refCount"] = data["refCount"] - 1;
|
||||
if (data["refCount"] < 1) {
|
||||
if (data && data.refCount) {
|
||||
data.refCount = data.refCount - 1;
|
||||
if (data.refCount < 1) {
|
||||
deactiveProps = {
|
||||
gravity: data["gravity"],
|
||||
gravity: data.gravity,
|
||||
// don't set collidesWith myAvatar back right away, because thrown things tend to bounce off the
|
||||
// avatar's capsule.
|
||||
collidesWith: removeMyAvatarFromCollidesWith(data["collidesWith"]),
|
||||
collisionless: data["collisionless"],
|
||||
dynamic: data["dynamic"],
|
||||
parentID: data["parentID"],
|
||||
parentJointIndex: data["parentJointIndex"]
|
||||
collidesWith: removeMyAvatarFromCollidesWith(data.collidesWith),
|
||||
collisionless: data.collisionless,
|
||||
dynamic: data.dynamic,
|
||||
parentID: data.parentID,
|
||||
parentJointIndex: data.parentJointIndex
|
||||
};
|
||||
|
||||
doDelayedDeactivate = (data["collidesWith"].indexOf("myAvatar") >= 0);
|
||||
doDelayedDeactivate = (data.collidesWith.indexOf("myAvatar") >= 0);
|
||||
|
||||
if (doDelayedDeactivate) {
|
||||
var delayedCollidesWith = data["collidesWith"];
|
||||
var delayedCollidesWith = data.collidesWith;
|
||||
var delayedEntityID = entityID;
|
||||
delayedDeactivateFunc = function() {
|
||||
// set collidesWith back to original value a bit later than the rest
|
||||
|
@ -2470,19 +2562,19 @@ function MyController(hand) {
|
|||
|
||||
if (!noVelocity &&
|
||||
parentID == MyAvatar.sessionUUID &&
|
||||
Vec3.length(data["gravity"]) > 0.0 &&
|
||||
data["dynamic"] &&
|
||||
data["parentID"] == NULL_UUID &&
|
||||
!data["collisionless"]) {
|
||||
deactiveProps["velocity"] = this.currentVelocity;
|
||||
Vec3.length(data.gravity) > 0.0 &&
|
||||
data.dynamic &&
|
||||
data.parentID == NULL_UUID &&
|
||||
!data.collisionless) {
|
||||
deactiveProps.velocity = this.currentVelocity;
|
||||
}
|
||||
if (noVelocity) {
|
||||
deactiveProps["velocity"] = {
|
||||
deactiveProps.velocity = {
|
||||
x: 0.0,
|
||||
y: 0.0,
|
||||
z: 0.0
|
||||
};
|
||||
deactiveProps["angularVelocity"] = {
|
||||
deactiveProps.angularVelocity = {
|
||||
x: 0.0,
|
||||
y: 0.0,
|
||||
z: 0.0
|
||||
|
@ -2508,6 +2600,17 @@ function MyController(hand) {
|
|||
}
|
||||
};
|
||||
Entities.editEntity(entityID, deactiveProps);
|
||||
|
||||
if (this.printNewOffsets) {
|
||||
var grabbedProperties = Entities.getEntityProperties(this.grabbedEntity, ["localPosition", "localRotation"]);
|
||||
if (grabbedProperties && grabbedProperties.localPosition && grabbedProperties.localRotation) {
|
||||
print((this.hand === RIGHT_HAND ? '"LeftHand"' : '"RightHand"') + ":" +
|
||||
'[{"x":' + grabbedProperties.localPosition.x + ', "y":' + grabbedProperties.localPosition.y +
|
||||
', "z":' + grabbedProperties.localPosition.z + '}, {"x":' + grabbedProperties.localRotation.x +
|
||||
', "y":' + grabbedProperties.localRotation.y + ', "z":' + grabbedProperties.localRotation.z +
|
||||
', "w":' + grabbedProperties.localRotation.w + '}]');
|
||||
}
|
||||
}
|
||||
} else if (noVelocity) {
|
||||
Entities.editEntity(entityID, {
|
||||
velocity: {
|
||||
|
@ -2520,7 +2623,7 @@ function MyController(hand) {
|
|||
y: 0.0,
|
||||
z: 0.0
|
||||
},
|
||||
dynamic: data["dynamic"]
|
||||
dynamic: data.dynamic
|
||||
});
|
||||
}
|
||||
} else {
|
||||
|
@ -2567,9 +2670,13 @@ function update(deltaTime) {
|
|||
|
||||
if (handToDisable !== LEFT_HAND && handToDisable !== 'both') {
|
||||
leftController.update(deltaTime, timestamp);
|
||||
} else {
|
||||
leftController.release();
|
||||
}
|
||||
if (handToDisable !== RIGHT_HAND && handToDisable !== 'both') {
|
||||
rightController.update(deltaTime, timestamp);
|
||||
} else {
|
||||
rightController.release();
|
||||
}
|
||||
equipHotspotBuddy.update(deltaTime, timestamp);
|
||||
entityPropertiesCache.update();
|
||||
|
@ -2620,7 +2727,7 @@ var handleHandMessages = function(channel, message, sender) {
|
|||
selectedController.nearGrabbingEnter();
|
||||
|
||||
} catch (e) {
|
||||
print("WARNING: error parsing Hifi-Hand-Grab message");
|
||||
print("WARNING: handControllerGrab.js -- error parsing Hifi-Hand-Grab message: " + message);
|
||||
}
|
||||
|
||||
} else if (channel === 'Hifi-Hand-RayPick-Blacklist') {
|
||||
|
@ -2640,7 +2747,7 @@ var handleHandMessages = function(channel, message, sender) {
|
|||
}
|
||||
|
||||
} catch (e) {
|
||||
print("WARNING: error parsing Hifi-Hand-RayPick-Blacklist message");
|
||||
print("WARNING: handControllerGrab.js -- error parsing Hifi-Hand-RayPick-Blacklist message: " + message);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -94,7 +94,6 @@ function Teleporter() {
|
|||
|
||||
this.initialize = function() {
|
||||
this.createMappings();
|
||||
this.disableGrab();
|
||||
};
|
||||
|
||||
this.createMappings = function() {
|
||||
|
@ -218,10 +217,6 @@ function Teleporter() {
|
|||
this.updateConnected = null;
|
||||
this.inCoolIn = false;
|
||||
inTeleportMode = false;
|
||||
|
||||
Script.setTimeout(function() {
|
||||
_this.enableGrab();
|
||||
}, 200);
|
||||
};
|
||||
|
||||
this.update = function() {
|
||||
|
@ -494,14 +489,6 @@ function Teleporter() {
|
|||
});
|
||||
};
|
||||
|
||||
this.disableGrab = function() {
|
||||
Messages.sendLocalMessage('Hifi-Hand-Disabler', this.teleportHand);
|
||||
};
|
||||
|
||||
this.enableGrab = function() {
|
||||
Messages.sendLocalMessage('Hifi-Hand-Disabler', 'none');
|
||||
};
|
||||
|
||||
this.triggerHaptics = function() {
|
||||
var hand = this.teleportHand === 'left' ? 0 : 1;
|
||||
var haptic = Controller.triggerShortHapticPulse(0.2, hand);
|
||||
|
|
|
@ -73,8 +73,7 @@ var toolBar = (function() {
|
|||
width: toolWidth,
|
||||
height: toolHeight,
|
||||
alpha: 0.9,
|
||||
visible: true,
|
||||
showButtonDown: true
|
||||
visible: true
|
||||
});
|
||||
|
||||
toolBar.showTool(browseDirectoryButton, true);
|
||||
|
|
|
@ -130,8 +130,6 @@ Tool = function(properties, selectable, selected) { // selectable and selected a
|
|||
if (update) {
|
||||
if (selectable) {
|
||||
this.toggle();
|
||||
} else if (properties.showButtonDown) {
|
||||
this.buttonDown(true);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
|
|
|
@ -56,6 +56,7 @@ public:
|
|||
explicit FileDownloader(QUrl imageUrl, QObject *parent = 0) : QObject(parent) {
|
||||
connect(&m_WebCtrl, SIGNAL(finished(QNetworkReply*)), this, SLOT(fileDownloaded(QNetworkReply*)));
|
||||
QNetworkRequest request(imageUrl);
|
||||
request.setAttribute(QNetworkRequest::FollowRedirectsAttribute, true);
|
||||
m_WebCtrl.get(request);
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue