mirror of
https://github.com/lubosz/overte.git
synced 2025-04-27 15:35:30 +02:00
Merge branch 'master' into feature/secondary-pose-support
This commit is contained in:
commit
78c6564174
61 changed files with 1013 additions and 165 deletions
BUILD_WIN.mdCMakeLists.txt
cmake
domain-server/src
interface
libraries
controllers/src/controllers
entities-renderer/src
entities/src
fbx/src
gpu-gl/src/gpu/gl41
gpu/src/gpu
model/src/model
networking/src
render-utils/src
script-engine/src
shared/src
plugins
hifiNeuron/src
hifiSdl2/src
hifiSixense/src
openvr/src
scripts/system
tools/atp-client/src
unpublishedScripts
35
BUILD_WIN.md
35
BUILD_WIN.md
|
@ -1,42 +1,45 @@
|
|||
This is a stand-alone guide for creating your first High Fidelity build for Windows 64-bit.
|
||||
|
||||
## Building High Fidelity
|
||||
Note: We are now using Visual Studio 2017 and Qt 5.9.1. If you are upgrading from Visual Studio 2013 and Qt 5.6.2, do a clean uninstall of those versions before going through this guide.
|
||||
|
||||
### Step 1. Installing Visual Studio 2013
|
||||
Note: The prerequisites will require about 10 GB of space on your drive.
|
||||
|
||||
If you don't already have the Community or Professional edition of Visual Studio 2013, download and install [Visual Studio Community 2013](https://www.visualstudio.com/en-us/news/releasenotes/vs2013-community-vs). You do not need to install any of the optional components when going through the installer.
|
||||
### Step 1. Visual Studio 2017
|
||||
|
||||
Note: Newer versions of Visual Studio are not yet compatible.
|
||||
If you don’t have Community or Professional edition of Visual Studio 2017, download [Visual Studio Community 2017](https://www.visualstudio.com/downloads/).
|
||||
|
||||
When selecting components, check "Desktop development with C++." Also check "Windows 8.1 SDK and UCRT SDK" and "VC++ 2015.3 v140 toolset (x86,x64)" on the Summary toolbar on the right.
|
||||
|
||||
### Step 2. Installing CMake
|
||||
|
||||
Download and install the [CMake 3.8.0 win64-x64 Installer](https://cmake.org/files/v3.8/cmake-3.8.0-win64-x64.msi). Make sure "Add CMake to system PATH for all users" is checked when going through the installer.
|
||||
Download and install the latest version of CMake 3.9. Download the file named win64-x64 Installer from the [CMake Website](https://cmake.org/download/). Make sure to check "Add CMake to system PATH for all users" when prompted during installation.
|
||||
|
||||
### Step 3. Installing Qt
|
||||
|
||||
Download and install the [Qt 5.6.2 for Windows 64-bit (VS 2013)](http://download.qt.io/official_releases/qt/5.6/5.6.2/qt-opensource-windows-x86-msvc2013_64-5.6.2.exe).
|
||||
Download and install the [Qt Online Installer](https://www.qt.io/download-open-source/?hsCtaTracking=f977210e-de67-475f-a32b-65cec207fd03%7Cd62710cd-e1db-46aa-8d4d-2f1c1ffdacea). While installing, you only need to have the following components checked under Qt 5.9.1: "msvc2017 64-bit", "Qt WebEngine", and "Qt Script (Deprecated)".
|
||||
|
||||
Keep the default components checked when going through the installer.
|
||||
Note: Installing the Sources is optional but recommended if you have room for them (~2GB).
|
||||
|
||||
### Step 4. Setting Qt Environment Variable
|
||||
|
||||
Go to `Control Panel > System > Advanced System Settings > Environment Variables > New...` (or search “Environment Variables” in Start Search).
|
||||
* Set "Variable name": `QT_CMAKE_PREFIX_PATH`
|
||||
* Set "Variable value": `%QT_DIR%\5.6\msvc2013_64\lib\cmake`
|
||||
* Set "Variable value": `C:\Qt\5.9.1\msvc2017_64\lib\cmake`
|
||||
|
||||
### Step 5. Installing OpenSSL
|
||||
|
||||
Download and install the [Win64 OpenSSL v1.0.2L Installer](https://slproweb.com/download/Win64OpenSSL-1_0_2L.exe).
|
||||
Download and install the Win64 OpenSSL v1.0.2 Installer[https://slproweb.com/products/Win32OpenSSL.html].
|
||||
|
||||
### Step 6. Running CMake to Generate Build Files
|
||||
|
||||
Run Command Prompt from Start and run the following commands:
|
||||
````
|
||||
```
|
||||
cd "%HIFI_DIR%"
|
||||
mkdir build
|
||||
cd build
|
||||
cmake .. -G "Visual Studio 12 Win64"
|
||||
````
|
||||
cmake .. -G "Visual Studio 15 Win64"
|
||||
```
|
||||
|
||||
Where `%HIFI_DIR%` is the directory for the highfidelity repository.
|
||||
|
||||
|
@ -72,14 +75,6 @@ For any problems after Step #6, first try this:
|
|||
|
||||
Remove `CMakeCache.txt` found in the `%HIFI_DIR%\build` directory.
|
||||
|
||||
#### nmake cannot be found
|
||||
|
||||
Make sure nmake.exe is located at the following path:
|
||||
|
||||
C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\bin
|
||||
|
||||
If not, add the directory where nmake is located to the PATH environment variable.
|
||||
|
||||
#### Qt is throwing an error
|
||||
|
||||
Make sure you have the correct version (5.6.2) installed and `QT_CMAKE_PREFIX_PATH` environment variable is set correctly.
|
||||
Make sure you have the correct version (5.9.1) installed and `QT_CMAKE_PREFIX_PATH` environment variable is set correctly.
|
||||
|
|
|
@ -1,4 +1,8 @@
|
|||
cmake_minimum_required(VERSION 3.2)
|
||||
if (WIN32)
|
||||
cmake_minimum_required(VERSION 3.7)
|
||||
else()
|
||||
cmake_minimum_required(VERSION 3.2)
|
||||
endif()
|
||||
|
||||
if (USE_ANDROID_TOOLCHAIN)
|
||||
set(CMAKE_TOOLCHAIN_FILE "${CMAKE_CURRENT_SOURCE_DIR}/cmake/android/android.toolchain.cmake")
|
||||
|
@ -33,6 +37,10 @@ set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -DDEBUG")
|
|||
find_package( Threads )
|
||||
|
||||
if (WIN32)
|
||||
if (NOT "${CMAKE_SIZEOF_VOID_P}" EQUAL "8")
|
||||
message( FATAL_ERROR "Only 64 bit builds supported." )
|
||||
endif()
|
||||
|
||||
add_definitions(-DNOMINMAX -D_CRT_SECURE_NO_WARNINGS)
|
||||
|
||||
if (NOT WINDOW_SDK_PATH)
|
||||
|
@ -41,16 +49,13 @@ if (WIN32)
|
|||
|
||||
# sets path for Microsoft SDKs
|
||||
# if you get build error about missing 'glu32' this path is likely wrong
|
||||
if (MSVC10)
|
||||
set(WINDOW_SDK_PATH "C:\\Program Files\\Microsoft SDKs\\Windows\\v7.1 " CACHE PATH "Windows SDK PATH")
|
||||
elseif (MSVC12)
|
||||
if ("${CMAKE_SIZEOF_VOID_P}" EQUAL "8")
|
||||
set(WINDOW_SDK_FOLDER "x64")
|
||||
else()
|
||||
set(WINDOW_SDK_FOLDER "x86")
|
||||
endif()
|
||||
if (MSVC_VERSION GREATER_EQUAL 1910) # VS 2017
|
||||
set(WINDOW_SDK_PATH "C:/Program Files (x86)/Windows Kits/10/Lib/${CMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION}/x64" CACHE PATH "Windows SDK PATH")
|
||||
elseif (MSVC_VERSION GREATER_EQUAL 1800) # VS 2013
|
||||
set(WINDOW_SDK_PATH "C:\\Program Files (x86)\\Windows Kits\\8.1\\Lib\\winv6.3\\um\\${WINDOW_SDK_FOLDER}" CACHE PATH "Windows SDK PATH")
|
||||
endif ()
|
||||
else()
|
||||
message( FATAL_ERROR "Visual Studio 2013 or higher required." )
|
||||
endif()
|
||||
|
||||
if (DEBUG_DISCOVERED_SDK_PATH)
|
||||
message(STATUS "The discovered Windows SDK path is ${WINDOW_SDK_PATH}")
|
||||
|
@ -103,7 +108,7 @@ else ()
|
|||
endif ()
|
||||
|
||||
if (APPLE)
|
||||
set(CMAKE_XCODE_ATTRIBUTE_CLANG_CXX_LANGUAGE_STANDARD "c++0x")
|
||||
set(CMAKE_XCODE_ATTRIBUTE_CLANG_CXX_LANGUAGE_STANDARD "c++11")
|
||||
set(CMAKE_XCODE_ATTRIBUTE_CLANG_CXX_LIBRARY "libc++")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} --stdlib=libc++")
|
||||
endif ()
|
||||
|
|
4
cmake/externals/quazip/CMakeLists.txt
vendored
4
cmake/externals/quazip/CMakeLists.txt
vendored
|
@ -21,8 +21,8 @@ endif ()
|
|||
|
||||
ExternalProject_Add(
|
||||
${EXTERNAL_NAME}
|
||||
URL https://s3-us-west-1.amazonaws.com/hifi-production/dependencies/quazip-0.7.2.zip
|
||||
URL_MD5 2955176048a31262c09259ca8d309d19
|
||||
URL https://hifi-public.s3.amazonaws.com/dependencies/quazip-0.7.3.zip
|
||||
URL_MD5 ed03754d39b9da1775771819b8001d45
|
||||
BINARY_DIR ${EXTERNAL_PROJECT_PREFIX}/build
|
||||
CMAKE_ARGS ${QUAZIP_CMAKE_ARGS}
|
||||
LOG_DOWNLOAD 1
|
||||
|
|
|
@ -126,8 +126,14 @@ macro(SET_PACKAGING_PARAMETERS)
|
|||
|
||||
# check if we need to find signtool
|
||||
if (PRODUCTION_BUILD OR PR_BUILD)
|
||||
find_program(SIGNTOOL_EXECUTABLE signtool PATHS "C:/Program Files (x86)/Windows Kits/8.1" PATH_SUFFIXES "bin/x64")
|
||||
|
||||
if (MSVC_VERSION GREATER_EQUAL 1910) # VS 2017
|
||||
find_program(SIGNTOOL_EXECUTABLE signtool PATHS "C:/Program Files (x86)/Windows Kits/10" PATH_SUFFIXES "bin/${CMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION}/x64")
|
||||
elseif (MSVC_VERSION GREATER_EQUAL 1800) # VS 2013
|
||||
find_program(SIGNTOOL_EXECUTABLE signtool PATHS "C:/Program Files (x86)/Windows Kits/8.1" PATH_SUFFIXES "bin/x64")
|
||||
else()
|
||||
message( FATAL_ERROR "Visual Studio 2013 or higher required." )
|
||||
endif()
|
||||
|
||||
if (NOT SIGNTOOL_EXECUTABLE)
|
||||
message(FATAL_ERROR "Code signing of executables was requested but signtool.exe could not be found.")
|
||||
endif ()
|
||||
|
|
|
@ -385,7 +385,7 @@ SharedNodePointer DomainGatekeeper::processAgentConnectRequest(const NodeConnect
|
|||
// user is attempting to prove their identity to us, but we don't have enough information
|
||||
sendConnectionTokenPacket(username, nodeConnection.senderSockAddr);
|
||||
// ask for their public key right now to make sure we have it
|
||||
requestUserPublicKey(username);
|
||||
requestUserPublicKey(username, true);
|
||||
getGroupMemberships(username); // optimistically get started on group memberships
|
||||
#ifdef WANT_DEBUG
|
||||
qDebug() << "stalling login because we have no username-signature:" << username;
|
||||
|
@ -521,7 +521,10 @@ bool DomainGatekeeper::verifyUserSignature(const QString& username,
|
|||
const HifiSockAddr& senderSockAddr) {
|
||||
// it's possible this user can be allowed to connect, but we need to check their username signature
|
||||
auto lowerUsername = username.toLower();
|
||||
QByteArray publicKeyArray = _userPublicKeys.value(lowerUsername);
|
||||
KeyFlagPair publicKeyPair = _userPublicKeys.value(lowerUsername);
|
||||
|
||||
QByteArray publicKeyArray = publicKeyPair.first;
|
||||
bool isOptimisticKey = publicKeyPair.second;
|
||||
|
||||
const QUuid& connectionToken = _connectionTokenHash.value(lowerUsername);
|
||||
|
||||
|
@ -555,10 +558,16 @@ bool DomainGatekeeper::verifyUserSignature(const QString& username,
|
|||
return true;
|
||||
|
||||
} else {
|
||||
if (!senderSockAddr.isNull()) {
|
||||
qDebug() << "Error decrypting username signature for " << username << "- denying connection.";
|
||||
// we only send back a LoginError if this wasn't an "optimistic" key
|
||||
// (a key that we hoped would work but is probably stale)
|
||||
|
||||
if (!senderSockAddr.isNull() && !isOptimisticKey) {
|
||||
qDebug() << "Error decrypting username signature for" << username << "- denying connection.";
|
||||
sendConnectionDeniedPacket("Error decrypting username signature.", senderSockAddr,
|
||||
DomainHandler::ConnectionRefusedReason::LoginError);
|
||||
} else if (!senderSockAddr.isNull()) {
|
||||
qDebug() << "Error decrypting username signature for" << username << "with optimisitic key -"
|
||||
<< "re-requesting public key and delaying connection";
|
||||
}
|
||||
|
||||
// free up the public key, we don't need it anymore
|
||||
|
@ -604,20 +613,7 @@ bool DomainGatekeeper::isWithinMaxCapacity() {
|
|||
return true;
|
||||
}
|
||||
|
||||
|
||||
void DomainGatekeeper::preloadAllowedUserPublicKeys() {
|
||||
QStringList allowedUsers = _server->_settingsManager.getAllNames();
|
||||
|
||||
if (allowedUsers.size() > 0) {
|
||||
// in the future we may need to limit how many requests here - for now assume that lists of allowed users are not
|
||||
// going to create > 100 requests
|
||||
foreach(const QString& username, allowedUsers) {
|
||||
requestUserPublicKey(username);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void DomainGatekeeper::requestUserPublicKey(const QString& username) {
|
||||
void DomainGatekeeper::requestUserPublicKey(const QString& username, bool isOptimistic) {
|
||||
// don't request public keys for the standard psuedo-account-names
|
||||
if (NodePermissions::standardNames.contains(username, Qt::CaseInsensitive)) {
|
||||
return;
|
||||
|
@ -628,7 +624,7 @@ void DomainGatekeeper::requestUserPublicKey(const QString& username) {
|
|||
// public-key request for this username is already flight, not rerequesting
|
||||
return;
|
||||
}
|
||||
_inFlightPublicKeyRequests += lowerUsername;
|
||||
_inFlightPublicKeyRequests.insert(lowerUsername, isOptimistic);
|
||||
|
||||
// even if we have a public key for them right now, request a new one in case it has just changed
|
||||
JSONCallbackParameters callbackParams;
|
||||
|
@ -640,7 +636,7 @@ void DomainGatekeeper::requestUserPublicKey(const QString& username) {
|
|||
|
||||
const QString USER_PUBLIC_KEY_PATH = "api/v1/users/%1/public_key";
|
||||
|
||||
qDebug() << "Requesting public key for user" << username;
|
||||
qDebug().nospace() << "Requesting " << (isOptimistic ? "optimistic " : " ") << "public key for user " << username;
|
||||
|
||||
DependencyManager::get<AccountManager>()->sendRequest(USER_PUBLIC_KEY_PATH.arg(username),
|
||||
AccountManagerAuth::None,
|
||||
|
@ -662,16 +658,21 @@ void DomainGatekeeper::publicKeyJSONCallback(QNetworkReply& requestReply) {
|
|||
QJsonObject jsonObject = QJsonDocument::fromJson(requestReply.readAll()).object();
|
||||
QString username = extractUsernameFromPublicKeyRequest(requestReply);
|
||||
|
||||
bool isOptimisticKey = _inFlightPublicKeyRequests.take(username);
|
||||
|
||||
if (jsonObject["status"].toString() == "success" && !username.isEmpty()) {
|
||||
// pull the public key as a QByteArray from this response
|
||||
const QString JSON_DATA_KEY = "data";
|
||||
const QString JSON_PUBLIC_KEY_KEY = "public_key";
|
||||
|
||||
_userPublicKeys[username.toLower()] =
|
||||
QByteArray::fromBase64(jsonObject[JSON_DATA_KEY].toObject()[JSON_PUBLIC_KEY_KEY].toString().toUtf8());
|
||||
}
|
||||
qDebug().nospace() << "Extracted " << (isOptimisticKey ? "optimistic " : " ") << "public key for " << username.toLower();
|
||||
|
||||
_inFlightPublicKeyRequests.remove(username);
|
||||
_userPublicKeys[username.toLower()] =
|
||||
{
|
||||
QByteArray::fromBase64(jsonObject[JSON_DATA_KEY].toObject()[JSON_PUBLIC_KEY_KEY].toString().toUtf8()),
|
||||
isOptimisticKey
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
void DomainGatekeeper::publicKeyJSONErrorCallback(QNetworkReply& requestReply) {
|
||||
|
@ -927,9 +928,12 @@ void DomainGatekeeper::getDomainOwnerFriendsList() {
|
|||
callbackParams.errorCallbackMethod = "getDomainOwnerFriendsListErrorCallback";
|
||||
|
||||
const QString GET_FRIENDS_LIST_PATH = "api/v1/user/friends";
|
||||
DependencyManager::get<AccountManager>()->sendRequest(GET_FRIENDS_LIST_PATH, AccountManagerAuth::Required,
|
||||
QNetworkAccessManager::GetOperation, callbackParams, QByteArray(),
|
||||
NULL, QVariantMap());
|
||||
if (DependencyManager::get<AccountManager>()->hasValidAccessToken()) {
|
||||
DependencyManager::get<AccountManager>()->sendRequest(GET_FRIENDS_LIST_PATH, AccountManagerAuth::Required,
|
||||
QNetworkAccessManager::GetOperation, callbackParams, QByteArray(),
|
||||
NULL, QVariantMap());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void DomainGatekeeper::getDomainOwnerFriendsListJSONCallback(QNetworkReply& requestReply) {
|
||||
|
|
|
@ -39,8 +39,6 @@ public:
|
|||
const QUuid& walletUUID, const QString& nodeVersion);
|
||||
QUuid assignmentUUIDForPendingAssignment(const QUuid& tempUUID);
|
||||
|
||||
void preloadAllowedUserPublicKeys();
|
||||
|
||||
void removeICEPeer(const QUuid& peerUUID) { _icePeers.remove(peerUUID); }
|
||||
|
||||
static void sendProtocolMismatchConnectionDenial(const HifiSockAddr& senderSockAddr);
|
||||
|
@ -93,7 +91,7 @@ private:
|
|||
|
||||
void pingPunchForConnectingPeer(const SharedNetworkPeer& peer);
|
||||
|
||||
void requestUserPublicKey(const QString& username);
|
||||
void requestUserPublicKey(const QString& username, bool isOptimistic = false);
|
||||
|
||||
DomainServer* _server;
|
||||
|
||||
|
@ -102,8 +100,17 @@ private:
|
|||
QHash<QUuid, SharedNetworkPeer> _icePeers;
|
||||
|
||||
QHash<QString, QUuid> _connectionTokenHash;
|
||||
QHash<QString, QByteArray> _userPublicKeys;
|
||||
QSet<QString> _inFlightPublicKeyRequests; // keep track of which we've already asked for
|
||||
|
||||
// the word "optimistic" below is used for keys that we request during user connection before the user has
|
||||
// had a chance to upload a new public key
|
||||
|
||||
// we don't send back user signature decryption errors for those keys so that there isn't a thrasing of key re-generation
|
||||
// and connection refusal
|
||||
|
||||
using KeyFlagPair = QPair<QByteArray, bool>;
|
||||
|
||||
QHash<QString, KeyFlagPair> _userPublicKeys; // keep track of keys and flag them as optimistic or not
|
||||
QHash<QString, bool> _inFlightPublicKeyRequests; // keep track of keys we've asked for (and if it was optimistic)
|
||||
QSet<QString> _domainOwnerFriends; // keep track of friends of the domain owner
|
||||
QSet<QString> _inFlightGroupMembershipsRequests; // keep track of which we've already asked for
|
||||
|
||||
|
|
|
@ -160,9 +160,7 @@ DomainServer::DomainServer(int argc, char* argv[]) :
|
|||
getTemporaryName();
|
||||
}
|
||||
|
||||
_gatekeeper.preloadAllowedUserPublicKeys(); // so they can connect on first request
|
||||
|
||||
//send signal to DomainMetadata when descriptors changed
|
||||
// send signal to DomainMetadata when descriptors changed
|
||||
_metadata = new DomainMetadata(this);
|
||||
connect(&_settingsManager, &DomainServerSettingsManager::settingsUpdated,
|
||||
_metadata, &DomainMetadata::descriptorsChanged);
|
||||
|
|
|
@ -1,6 +1,15 @@
|
|||
{
|
||||
"name": "Vive to Standard",
|
||||
"channels": [
|
||||
{ "from": "Vive.LY", "to": "Standard.LeftIndexPoint",
|
||||
"peek": true,
|
||||
"filters": [ { "type": "hysteresis", "min": 0.7, "max": 0.75 } ]
|
||||
},
|
||||
{ "from": "Vive.RY", "to": "Standard.RightIndexPoint",
|
||||
"peek": true,
|
||||
"filters": [ { "type": "hysteresis", "min": 0.7, "max": 0.75 } ]
|
||||
},
|
||||
|
||||
{ "from": "Vive.LY", "when": "Vive.LSY", "filters": ["invert"], "to": "Standard.LY" },
|
||||
{ "from": "Vive.LX", "when": "Vive.LSX", "to": "Standard.LX" },
|
||||
{
|
||||
|
@ -13,6 +22,10 @@
|
|||
|
||||
{ "from": "Vive.LeftGrip", "to": "Standard.LeftGrip" },
|
||||
{ "from": "Vive.LS", "to": "Standard.LS" },
|
||||
{ "from": "Vive.LSTouch", "to": "Standard.LeftThumbUp",
|
||||
"peek": true,
|
||||
"filters": [ { "type": "logicalNot" } ]
|
||||
},
|
||||
{ "from": "Vive.LSTouch", "to": "Standard.LSTouch" },
|
||||
|
||||
{ "from": "Vive.RY", "when": "Vive.RSY", "filters": ["invert"], "to": "Standard.RY" },
|
||||
|
@ -27,6 +40,10 @@
|
|||
|
||||
{ "from": "Vive.RightGrip", "to": "Standard.RightGrip" },
|
||||
{ "from": "Vive.RS", "to": "Standard.RS" },
|
||||
{ "from": "Vive.RSTouch", "to": "Standard.RightThumbUp",
|
||||
"peek": true,
|
||||
"filters": [ { "type": "logicalNot" } ]
|
||||
},
|
||||
{ "from": "Vive.RSTouch", "to": "Standard.RSTouch" },
|
||||
|
||||
{ "from": "Vive.LSCenter", "to": "Standard.LeftPrimaryThumb" },
|
||||
|
@ -59,7 +76,7 @@
|
|||
|
||||
{ "from": "Vive.Head", "to" : "Standard.Head"},
|
||||
|
||||
{ "from": "Vive.RightArm", "to" : "Standard.RightArm"},
|
||||
{ "from": "Vive.LeftArm", "to" : "Standard.LeftArm"}
|
||||
{ "from": "Vive.RightArm", "to" : "Standard.RightArm" },
|
||||
{ "from": "Vive.LeftArm", "to" : "Standard.LeftArm" }
|
||||
]
|
||||
}
|
||||
|
|
|
@ -151,13 +151,17 @@ ScrollingWindow {
|
|||
var SHAPE_TYPE_SIMPLE_HULL = 1;
|
||||
var SHAPE_TYPE_SIMPLE_COMPOUND = 2;
|
||||
var SHAPE_TYPE_STATIC_MESH = 3;
|
||||
|
||||
var SHAPE_TYPE_BOX = 4;
|
||||
var SHAPE_TYPE_SPHERE = 5;
|
||||
|
||||
var SHAPE_TYPES = [];
|
||||
SHAPE_TYPES[SHAPE_TYPE_NONE] = "No Collision";
|
||||
SHAPE_TYPES[SHAPE_TYPE_SIMPLE_HULL] = "Basic - Whole model";
|
||||
SHAPE_TYPES[SHAPE_TYPE_SIMPLE_COMPOUND] = "Good - Sub-meshes";
|
||||
SHAPE_TYPES[SHAPE_TYPE_STATIC_MESH] = "Exact - All polygons";
|
||||
|
||||
SHAPE_TYPES[SHAPE_TYPE_BOX] = "Box";
|
||||
SHAPE_TYPES[SHAPE_TYPE_SPHERE] = "Sphere";
|
||||
|
||||
var SHAPE_TYPE_DEFAULT = SHAPE_TYPE_STATIC_MESH;
|
||||
var DYNAMIC_DEFAULT = false;
|
||||
var prompt = desktop.customInputDialog({
|
||||
|
@ -196,6 +200,12 @@ ScrollingWindow {
|
|||
case SHAPE_TYPE_STATIC_MESH:
|
||||
shapeType = "static-mesh";
|
||||
break;
|
||||
case SHAPE_TYPE_BOX:
|
||||
shapeType = "box";
|
||||
break;
|
||||
case SHAPE_TYPE_SPHERE:
|
||||
shapeType = "sphere";
|
||||
break;
|
||||
default:
|
||||
shapeType = "none";
|
||||
}
|
||||
|
|
71
interface/resources/qml/controls-uit/RadioButton.qml
Normal file
71
interface/resources/qml/controls-uit/RadioButton.qml
Normal file
|
@ -0,0 +1,71 @@
|
|||
//
|
||||
// RadioButton.qml
|
||||
//
|
||||
// Created by Cain Kilgore on 20th July 2017
|
||||
// Copyright 2017 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
|
||||
//
|
||||
|
||||
import QtQuick 2.5
|
||||
import QtQuick.Controls 1.4 as Original
|
||||
import QtQuick.Controls.Styles 1.4
|
||||
|
||||
import "../styles-uit"
|
||||
import "../controls-uit" as HifiControls
|
||||
|
||||
Original.RadioButton {
|
||||
id: radioButton
|
||||
HifiConstants { id: hifi }
|
||||
|
||||
property int colorScheme: hifi.colorSchemes.light
|
||||
readonly property bool isLightColorScheme: colorScheme == hifi.colorSchemes.light
|
||||
|
||||
readonly property int boxSize: 14
|
||||
readonly property int boxRadius: 3
|
||||
readonly property int checkSize: 10
|
||||
readonly property int checkRadius: 2
|
||||
|
||||
style: RadioButtonStyle {
|
||||
indicator: Rectangle {
|
||||
id: box
|
||||
width: boxSize
|
||||
height: boxSize
|
||||
radius: 7
|
||||
gradient: Gradient {
|
||||
GradientStop {
|
||||
position: 0.2
|
||||
color: pressed || hovered
|
||||
? (radioButton.isLightColorScheme ? hifi.colors.checkboxDarkStart : hifi.colors.checkboxLightStart)
|
||||
: (radioButton.isLightColorScheme ? hifi.colors.checkboxLightStart : hifi.colors.checkboxDarkStart)
|
||||
}
|
||||
GradientStop {
|
||||
position: 1.0
|
||||
color: pressed || hovered
|
||||
? (radioButton.isLightColorScheme ? hifi.colors.checkboxDarkFinish : hifi.colors.checkboxLightFinish)
|
||||
: (radioButton.isLightColorScheme ? hifi.colors.checkboxLightFinish : hifi.colors.checkboxDarkFinish)
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
id: check
|
||||
width: checkSize
|
||||
height: checkSize
|
||||
radius: 7
|
||||
anchors.centerIn: parent
|
||||
color: "#00B4EF"
|
||||
border.width: 1
|
||||
border.color: "#36CDFF"
|
||||
visible: checked && !pressed || !checked && pressed
|
||||
}
|
||||
}
|
||||
|
||||
label: RalewaySemiBold {
|
||||
text: control.text
|
||||
size: hifi.fontSizes.inputLabel
|
||||
color: isLightColorScheme ? hifi.colors.lightGray : hifi.colors.lightGrayText
|
||||
x: radioButton.boxSize / 2
|
||||
}
|
||||
}
|
||||
}
|
17
interface/resources/qml/controls/RadioButton.qml
Normal file
17
interface/resources/qml/controls/RadioButton.qml
Normal file
|
@ -0,0 +1,17 @@
|
|||
import QtQuick.Controls 1.3 as Original
|
||||
import QtQuick.Controls.Styles 1.3
|
||||
import "../styles"
|
||||
import "."
|
||||
Original.RadioButton {
|
||||
text: "Radio Button"
|
||||
style: RadioButtonStyle {
|
||||
indicator: FontAwesome {
|
||||
text: control.checked ? "\uf046" : "\uf096"
|
||||
}
|
||||
label: Text {
|
||||
text: control.text
|
||||
renderType: Text.QtRendering
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,101 @@
|
|||
//
|
||||
// PrimaryHandPreference.qml
|
||||
//
|
||||
// Created by Cain Kilgore on 20th July 2017
|
||||
// Copyright 2017 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
|
||||
//
|
||||
|
||||
import QtQuick 2.5
|
||||
|
||||
import "../../controls-uit"
|
||||
|
||||
Preference {
|
||||
id: root
|
||||
property alias box1: box1
|
||||
property alias box2: box2
|
||||
|
||||
height: control.height + hifi.dimensions.controlInterlineHeight
|
||||
|
||||
Component.onCompleted: {
|
||||
if (preference.value == "left") {
|
||||
box1.checked = true;
|
||||
} else {
|
||||
box2.checked = true;
|
||||
}
|
||||
}
|
||||
|
||||
function save() {
|
||||
if (box1.checked && !box2.checked) {
|
||||
preference.value = "left";
|
||||
}
|
||||
if (!box1.checked && box2.checked) {
|
||||
preference.value = "right";
|
||||
}
|
||||
preference.save();
|
||||
}
|
||||
|
||||
Item {
|
||||
id: control
|
||||
anchors {
|
||||
left: parent.left
|
||||
right: parent.right
|
||||
bottom: parent.bottom
|
||||
}
|
||||
height: Math.max(labelName.height, box1.height, box2.height)
|
||||
|
||||
Label {
|
||||
id: labelName
|
||||
text: root.label + ":"
|
||||
colorScheme: hifi.colorSchemes.dark
|
||||
anchors {
|
||||
left: parent.left
|
||||
right: box1.left
|
||||
rightMargin: hifi.dimensions.labelPadding
|
||||
verticalCenter: parent.verticalCenter
|
||||
}
|
||||
horizontalAlignment: Text.AlignRight
|
||||
wrapMode: Text.Wrap
|
||||
}
|
||||
|
||||
RadioButton {
|
||||
id: box1
|
||||
text: "Left"
|
||||
width: 60
|
||||
anchors {
|
||||
right: box2.left
|
||||
verticalCenter: parent.verticalCenter
|
||||
}
|
||||
onClicked: {
|
||||
if (box2.checked) {
|
||||
box2.checked = false;
|
||||
}
|
||||
if (!box1.checked && !box2.checked) {
|
||||
box1.checked = true;
|
||||
}
|
||||
}
|
||||
colorScheme: hifi.colorSchemes.dark
|
||||
}
|
||||
|
||||
RadioButton {
|
||||
id: box2
|
||||
text: "Right"
|
||||
width: 60
|
||||
anchors {
|
||||
right: parent.right
|
||||
verticalCenter: parent.verticalCenter
|
||||
}
|
||||
onClicked: {
|
||||
if (box1.checked) {
|
||||
box1.checked = false;
|
||||
}
|
||||
if (!box1.checked && !box2.checked) {
|
||||
box2.checked = true;
|
||||
}
|
||||
}
|
||||
colorScheme: hifi.colorSchemes.dark
|
||||
}
|
||||
}
|
||||
}
|
|
@ -73,6 +73,7 @@ Preference {
|
|||
property var buttonBuilder: Component { ButtonPreference { } }
|
||||
property var comboBoxBuilder: Component { ComboBoxPreference { } }
|
||||
property var spinnerSliderBuilder: Component { SpinnerSliderPreference { } }
|
||||
property var primaryHandBuilder: Component { PrimaryHandPreference { } }
|
||||
property var preferences: []
|
||||
property int checkBoxCount: 0
|
||||
|
||||
|
@ -134,6 +135,11 @@ Preference {
|
|||
checkBoxCount = 0;
|
||||
builder = spinnerSliderBuilder;
|
||||
break;
|
||||
|
||||
case Preference.PrimaryHand:
|
||||
checkBoxCount++;
|
||||
builder = primaryHandBuilder;
|
||||
break;
|
||||
};
|
||||
|
||||
if (builder) {
|
||||
|
|
|
@ -17,7 +17,7 @@ PreferencesDialog {
|
|||
id: root
|
||||
objectName: "GeneralPreferencesDialog"
|
||||
title: "General Settings"
|
||||
showCategories: ["UI", "Snapshots", "Scripts", "Privacy", "Octree", "HMD", "Sixense Controllers", "Perception Neuron", "Kinect", "Leap Motion"]
|
||||
showCategories: ["UI", "Snapshots", "Scripts", "Privacy", "Octree", "HMD", "Game Controller", "Sixense Controllers", "Perception Neuron", "Kinect", "Leap Motion"]
|
||||
property var settings: Settings {
|
||||
category: root.objectName
|
||||
property alias x: root.x
|
||||
|
|
|
@ -152,13 +152,17 @@ Rectangle {
|
|||
var SHAPE_TYPE_SIMPLE_HULL = 1;
|
||||
var SHAPE_TYPE_SIMPLE_COMPOUND = 2;
|
||||
var SHAPE_TYPE_STATIC_MESH = 3;
|
||||
|
||||
var SHAPE_TYPE_BOX = 4;
|
||||
var SHAPE_TYPE_SPHERE = 5;
|
||||
|
||||
var SHAPE_TYPES = [];
|
||||
SHAPE_TYPES[SHAPE_TYPE_NONE] = "No Collision";
|
||||
SHAPE_TYPES[SHAPE_TYPE_SIMPLE_HULL] = "Basic - Whole model";
|
||||
SHAPE_TYPES[SHAPE_TYPE_SIMPLE_COMPOUND] = "Good - Sub-meshes";
|
||||
SHAPE_TYPES[SHAPE_TYPE_STATIC_MESH] = "Exact - All polygons";
|
||||
|
||||
SHAPE_TYPES[SHAPE_TYPE_BOX] = "Box";
|
||||
SHAPE_TYPES[SHAPE_TYPE_SPHERE] = "Sphere";
|
||||
|
||||
var SHAPE_TYPE_DEFAULT = SHAPE_TYPE_STATIC_MESH;
|
||||
var DYNAMIC_DEFAULT = false;
|
||||
var prompt = tabletRoot.customInputDialog({
|
||||
|
@ -197,6 +201,12 @@ Rectangle {
|
|||
case SHAPE_TYPE_STATIC_MESH:
|
||||
shapeType = "static-mesh";
|
||||
break;
|
||||
case SHAPE_TYPE_BOX:
|
||||
shapeType = "box";
|
||||
break;
|
||||
case SHAPE_TYPE_SPHERE:
|
||||
shapeType = "sphere";
|
||||
break;
|
||||
default:
|
||||
shapeType = "none";
|
||||
}
|
||||
|
|
|
@ -145,7 +145,9 @@ Rectangle {
|
|||
model: ["No Collision",
|
||||
"Basic - Whole model",
|
||||
"Good - Sub-meshes",
|
||||
"Exact - All polygons"]
|
||||
"Exact - All polygons",
|
||||
"Box",
|
||||
"Sphere"]
|
||||
}
|
||||
|
||||
Row {
|
||||
|
|
|
@ -32,6 +32,6 @@ StackView {
|
|||
TabletPreferencesDialog {
|
||||
id: root
|
||||
objectName: "TabletGeneralPreferences"
|
||||
showCategories: ["UI", "Snapshots", "Scripts", "Privacy", "Octree", "HMD", "Sixense Controllers", "Perception Neuron", "Kinect", "Vive Pucks Configuration", "Leap Motion"]
|
||||
showCategories: ["UI", "Snapshots", "Scripts", "Privacy", "Octree", "HMD", "Game Controller", "Sixense Controllers", "Perception Neuron", "Kinect", "Leap Motion"]
|
||||
}
|
||||
}
|
||||
|
|
|
@ -82,6 +82,7 @@ Preference {
|
|||
property var buttonBuilder: Component { ButtonPreference { } }
|
||||
property var comboBoxBuilder: Component { ComboBoxPreference { } }
|
||||
property var spinnerSliderBuilder: Component { SpinnerSliderPreference { } }
|
||||
property var primaryHandBuilder: Component { PrimaryHandPreference { } }
|
||||
property var preferences: []
|
||||
property int checkBoxCount: 0
|
||||
|
||||
|
@ -144,10 +145,16 @@ Preference {
|
|||
//to be not overlapped when drop down is active
|
||||
zpos = root.z + 1000 - itemNum
|
||||
break;
|
||||
|
||||
case Preference.SpinnerSlider:
|
||||
checkBoxCount = 0;
|
||||
builder = spinnerSliderBuilder;
|
||||
break;
|
||||
|
||||
case Preference.PrimaryHand:
|
||||
checkBoxCount++;
|
||||
builder = primaryHandBuilder;
|
||||
break;
|
||||
};
|
||||
|
||||
if (builder) {
|
||||
|
|
|
@ -255,6 +255,12 @@ MyAvatar::~MyAvatar() {
|
|||
_lookAtTargetAvatar.reset();
|
||||
}
|
||||
|
||||
void MyAvatar::setDominantHand(const QString& hand) {
|
||||
if (hand == DOMINANT_LEFT_HAND || hand == DOMINANT_RIGHT_HAND) {
|
||||
_dominantHand = hand;
|
||||
}
|
||||
}
|
||||
|
||||
void MyAvatar::registerMetaTypes(QScriptEngine* engine) {
|
||||
QScriptValue value = engine->newQObject(this, QScriptEngine::QtOwnership, QScriptEngine::ExcludeDeleteLater | QScriptEngine::ExcludeChildObjects);
|
||||
engine->globalObject().setProperty("MyAvatar", value);
|
||||
|
@ -926,6 +932,7 @@ void MyAvatar::saveData() {
|
|||
Settings settings;
|
||||
settings.beginGroup("Avatar");
|
||||
|
||||
settings.setValue("dominantHand", _dominantHand);
|
||||
settings.setValue("headPitch", getHead()->getBasePitch());
|
||||
|
||||
settings.setValue("scale", _targetScale);
|
||||
|
@ -1122,7 +1129,7 @@ void MyAvatar::loadData() {
|
|||
setCollisionSoundURL(settings.value("collisionSoundURL", DEFAULT_AVATAR_COLLISION_SOUND_URL).toString());
|
||||
setSnapTurn(settings.value("useSnapTurn", _useSnapTurn).toBool());
|
||||
setClearOverlayWhenMoving(settings.value("clearOverlayWhenMoving", _clearOverlayWhenMoving).toBool());
|
||||
|
||||
setDominantHand(settings.value("dominantHand", _dominantHand).toString().toLower());
|
||||
settings.endGroup();
|
||||
|
||||
setEnableMeshVisible(Menu::getInstance()->isOptionChecked(MenuOption::MeshVisible));
|
||||
|
|
|
@ -43,6 +43,7 @@ enum AudioListenerMode {
|
|||
FROM_CAMERA,
|
||||
CUSTOM
|
||||
};
|
||||
|
||||
Q_DECLARE_METATYPE(AudioListenerMode);
|
||||
|
||||
class MyAvatar : public Avatar {
|
||||
|
@ -141,6 +142,9 @@ class MyAvatar : public Avatar {
|
|||
Q_PROPERTY(float hmdRollControlDeadZone READ getHMDRollControlDeadZone WRITE setHMDRollControlDeadZone)
|
||||
Q_PROPERTY(float hmdRollControlRate READ getHMDRollControlRate WRITE setHMDRollControlRate)
|
||||
|
||||
const QString DOMINANT_LEFT_HAND = "left";
|
||||
const QString DOMINANT_RIGHT_HAND = "right";
|
||||
|
||||
public:
|
||||
enum DriveKeys {
|
||||
TRANSLATE_X = 0,
|
||||
|
@ -339,6 +343,9 @@ public:
|
|||
Q_INVOKABLE bool getClearOverlayWhenMoving() const { return _clearOverlayWhenMoving; }
|
||||
Q_INVOKABLE void setClearOverlayWhenMoving(bool on) { _clearOverlayWhenMoving = on; }
|
||||
|
||||
Q_INVOKABLE void setDominantHand(const QString& hand);
|
||||
Q_INVOKABLE QString getDominantHand() const { return _dominantHand; }
|
||||
|
||||
Q_INVOKABLE void setHMDLeanRecenterEnabled(bool value) { _hmdLeanRecenterEnabled = value; }
|
||||
Q_INVOKABLE bool getHMDLeanRecenterEnabled() const { return _hmdLeanRecenterEnabled; }
|
||||
|
||||
|
@ -424,7 +431,6 @@ public:
|
|||
Q_INVOKABLE QString getFullAvatarModelName() const { return _fullAvatarModelName; }
|
||||
void resetFullAvatarURL();
|
||||
|
||||
|
||||
virtual void setAttachmentData(const QVector<AttachmentData>& attachmentData) override;
|
||||
|
||||
MyCharacterController* getCharacterController() { return &_characterController; }
|
||||
|
@ -683,6 +689,7 @@ private:
|
|||
QUrl _fstAnimGraphOverrideUrl;
|
||||
bool _useSnapTurn { true };
|
||||
bool _clearOverlayWhenMoving { true };
|
||||
QString _dominantHand { DOMINANT_RIGHT_HAND };
|
||||
|
||||
const float ROLL_CONTROL_DEAD_ZONE_DEFAULT = 8.0f; // deg
|
||||
const float ROLL_CONTROL_RATE_DEFAULT = 2.5f; // deg/sec/deg
|
||||
|
|
|
@ -181,6 +181,11 @@ void setupPreferences() {
|
|||
preference->setStep(1);
|
||||
preferences->addPreference(preference);
|
||||
}
|
||||
{
|
||||
auto getter = [=]()->QString { return myAvatar->getDominantHand(); };
|
||||
auto setter = [=](const QString& value) { myAvatar->setDominantHand(value); };
|
||||
preferences->addPreference(new PrimaryHandPreference(AVATAR_TUNING, "Dominant Hand", getter, setter));
|
||||
}
|
||||
{
|
||||
auto getter = [=]()->float { return myAvatar->getUniformScale(); };
|
||||
auto setter = [=](float value) { myAvatar->setTargetScale(value); };
|
||||
|
@ -300,17 +305,6 @@ void setupPreferences() {
|
|||
preferences->addPreference(preference);
|
||||
}
|
||||
|
||||
|
||||
{
|
||||
auto getter = []()->float { return controller::InputDevice::getReticleMoveSpeed(); };
|
||||
auto setter = [](float value) { controller::InputDevice::setReticleMoveSpeed(value); };
|
||||
auto preference = new SpinnerPreference("Sixense Controllers", "Reticle movement speed", getter, setter);
|
||||
preference->setMin(0);
|
||||
preference->setMax(100);
|
||||
preference->setStep(1);
|
||||
preferences->addPreference(preference);
|
||||
}
|
||||
|
||||
{
|
||||
static const QString RENDER("Graphics");
|
||||
auto renderConfig = qApp->getRenderEngine()->getConfiguration();
|
||||
|
|
|
@ -15,20 +15,6 @@
|
|||
|
||||
namespace controller {
|
||||
|
||||
const float DEFAULT_HAND_RETICLE_MOVE_SPEED = 37.5f;
|
||||
float InputDevice::_reticleMoveSpeed = DEFAULT_HAND_RETICLE_MOVE_SPEED;
|
||||
|
||||
//Constants for getCursorPixelRangeMultiplier()
|
||||
const float MIN_PIXEL_RANGE_MULT = 0.4f;
|
||||
const float MAX_PIXEL_RANGE_MULT = 2.0f;
|
||||
const float RANGE_MULT = (MAX_PIXEL_RANGE_MULT - MIN_PIXEL_RANGE_MULT) * 0.01f;
|
||||
|
||||
//Returns a multiplier to be applied to the cursor range for the controllers
|
||||
float InputDevice::getCursorPixelRangeMult() {
|
||||
//scales (0,100) to (MINIMUM_PIXEL_RANGE_MULT, MAXIMUM_PIXEL_RANGE_MULT)
|
||||
return InputDevice::_reticleMoveSpeed * RANGE_MULT + MIN_PIXEL_RANGE_MULT;
|
||||
}
|
||||
|
||||
float InputDevice::getButton(int channel) const {
|
||||
if (!_buttonPressedMap.empty()) {
|
||||
if (_buttonPressedMap.find(channel) != _buttonPressedMap.end()) {
|
||||
|
|
|
@ -73,10 +73,6 @@ public:
|
|||
int getDeviceID() { return _deviceID; }
|
||||
void setDeviceID(int deviceID) { _deviceID = deviceID; }
|
||||
|
||||
static float getCursorPixelRangeMult();
|
||||
static float getReticleMoveSpeed() { return _reticleMoveSpeed; }
|
||||
static void setReticleMoveSpeed(float reticleMoveSpeed) { _reticleMoveSpeed = reticleMoveSpeed; }
|
||||
|
||||
Input makeInput(StandardButtonChannel button) const;
|
||||
Input makeInput(StandardAxisChannel axis) const;
|
||||
Input makeInput(StandardPoseChannel pose) const;
|
||||
|
@ -99,9 +95,6 @@ protected:
|
|||
ButtonPressedMap _buttonPressedMap;
|
||||
AxisStateMap _axisStateMap;
|
||||
PoseStateMap _poseStateMap;
|
||||
|
||||
private:
|
||||
static float _reticleMoveSpeed;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
#include "filters/DeadZoneFilter.h"
|
||||
#include "filters/HysteresisFilter.h"
|
||||
#include "filters/InvertFilter.h"
|
||||
#include "filters/NotFilter.h"
|
||||
#include "filters/PulseFilter.h"
|
||||
#include "filters/ScaleFilter.h"
|
||||
#include "filters/TranslateFilter.h"
|
||||
|
@ -40,6 +41,7 @@ REGISTER_FILTER_CLASS_INSTANCE(ConstrainToPositiveIntegerFilter, "constrainToPos
|
|||
REGISTER_FILTER_CLASS_INSTANCE(DeadZoneFilter, "deadZone")
|
||||
REGISTER_FILTER_CLASS_INSTANCE(HysteresisFilter, "hysteresis")
|
||||
REGISTER_FILTER_CLASS_INSTANCE(InvertFilter, "invert")
|
||||
REGISTER_FILTER_CLASS_INSTANCE(NotFilter, "logicalNot")
|
||||
REGISTER_FILTER_CLASS_INSTANCE(ScaleFilter, "scale")
|
||||
REGISTER_FILTER_CLASS_INSTANCE(PulseFilter, "pulse")
|
||||
REGISTER_FILTER_CLASS_INSTANCE(TranslateFilter, "translate")
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
#include "filters/DeadZoneFilter.h"
|
||||
#include "filters/HysteresisFilter.h"
|
||||
#include "filters/InvertFilter.h"
|
||||
#include "filters/NotFilter.h"
|
||||
#include "filters/PulseFilter.h"
|
||||
#include "filters/ScaleFilter.h"
|
||||
#include "filters/TranslateFilter.h"
|
||||
|
@ -148,6 +149,11 @@ QObject* RouteBuilderProxy::pulse(float interval) {
|
|||
return this;
|
||||
}
|
||||
|
||||
QObject* RouteBuilderProxy::logicalNot() {
|
||||
addFilter(std::make_shared<NotFilter>());
|
||||
return this;
|
||||
}
|
||||
|
||||
void RouteBuilderProxy::addFilter(Filter::Pointer filter) {
|
||||
_route->filters.push_back(filter);
|
||||
}
|
||||
|
|
|
@ -53,6 +53,7 @@ class RouteBuilderProxy : public QObject {
|
|||
Q_INVOKABLE QObject* postTransform(glm::mat4 transform);
|
||||
Q_INVOKABLE QObject* rotate(glm::quat rotation);
|
||||
Q_INVOKABLE QObject* lowVelocity(float rotationConstant, float translationConstant);
|
||||
Q_INVOKABLE QObject* logicalNot();
|
||||
|
||||
private:
|
||||
void to(const Endpoint::Pointer& destination);
|
||||
|
|
|
@ -0,0 +1,10 @@
|
|||
#include "NotFilter.h"
|
||||
|
||||
using namespace controller;
|
||||
|
||||
NotFilter::NotFilter() {
|
||||
}
|
||||
|
||||
float NotFilter::apply(float value) const {
|
||||
return (value == 0.0f) ? 1.0f : 0.0f;
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
#pragma once
|
||||
#ifndef hifi_Controllers_Filters_Not_h
|
||||
#define hifi_Controllers_Filters_Not_h
|
||||
|
||||
#include "../Filter.h"
|
||||
|
||||
namespace controller {
|
||||
|
||||
class NotFilter : public Filter {
|
||||
REGISTER_FILTER_CLASS(NotFilter);
|
||||
public:
|
||||
NotFilter();
|
||||
|
||||
virtual float apply(float value) const override;
|
||||
virtual Pose apply(Pose value) const override { return value; }
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
@ -23,6 +23,7 @@
|
|||
#include <PerfStat.h>
|
||||
#include <render/Scene.h>
|
||||
#include <DependencyManager.h>
|
||||
#include <shared/QtHelpers.h>
|
||||
|
||||
#include "EntityTreeRenderer.h"
|
||||
#include "EntitiesRendererLogging.h"
|
||||
|
@ -1282,3 +1283,11 @@ void RenderableModelEntityItem::mapJoints(const QStringList& modelJointNames) {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool RenderableModelEntityItem::getMeshes(MeshProxyList& result) {
|
||||
if (!_model || !_model->isLoaded()) {
|
||||
return false;
|
||||
}
|
||||
BLOCKING_INVOKE_METHOD(_model.get(), "getMeshes", Q_RETURN_ARG(MeshProxyList, result));
|
||||
return !result.isEmpty();
|
||||
}
|
||||
|
|
|
@ -116,6 +116,8 @@ public:
|
|||
return _animation;
|
||||
}
|
||||
|
||||
bool getMeshes(MeshProxyList& result) override;
|
||||
|
||||
private:
|
||||
QVariantMap parseTexturesToMap(QString textures);
|
||||
void remapTextures();
|
||||
|
|
|
@ -1663,6 +1663,7 @@ bool RenderablePolyVoxEntityItem::getMeshes(MeshProxyList& result) {
|
|||
// the mesh will be in voxel-space. transform it into object-space
|
||||
meshProxy = new SimpleMeshProxy(
|
||||
_mesh->map([=](glm::vec3 position){ return glm::vec3(transform * glm::vec4(position, 1.0f)); },
|
||||
[=](glm::vec3 color){ return color; },
|
||||
[=](glm::vec3 normal){ return glm::normalize(glm::vec3(transform * glm::vec4(normal, 0.0f))); },
|
||||
[&](uint32_t index){ return index; }));
|
||||
result << meshProxy;
|
||||
|
|
|
@ -182,7 +182,6 @@ OctreeElement::AppendState EntityItem::appendEntityData(OctreePacketData* packet
|
|||
|
||||
EntityPropertyFlags propertyFlags(PROP_LAST_ITEM);
|
||||
EntityPropertyFlags requestedProperties = getEntityProperties(params);
|
||||
EntityPropertyFlags propertiesDidntFit = requestedProperties;
|
||||
|
||||
// If we are being called for a subsequent pass at appendEntityData() that failed to completely encode this item,
|
||||
// then our entityTreeElementExtraEncodeData should include data about which properties we need to append.
|
||||
|
@ -190,6 +189,8 @@ OctreeElement::AppendState EntityItem::appendEntityData(OctreePacketData* packet
|
|||
requestedProperties = entityTreeElementExtraEncodeData->entities.value(getEntityItemID());
|
||||
}
|
||||
|
||||
EntityPropertyFlags propertiesDidntFit = requestedProperties;
|
||||
|
||||
LevelDetails entityLevel = packetData->startLevel();
|
||||
|
||||
quint64 lastEdited = getLastEdited();
|
||||
|
|
|
@ -1736,9 +1736,7 @@ glm::mat4 EntityScriptingInterface::getEntityTransform(const QUuid& entityID) {
|
|||
if (entity) {
|
||||
glm::mat4 translation = glm::translate(entity->getPosition());
|
||||
glm::mat4 rotation = glm::mat4_cast(entity->getRotation());
|
||||
glm::mat4 registration = glm::translate(ENTITY_ITEM_DEFAULT_REGISTRATION_POINT -
|
||||
entity->getRegistrationPoint());
|
||||
result = translation * rotation * registration;
|
||||
result = translation * rotation;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -1753,9 +1751,7 @@ glm::mat4 EntityScriptingInterface::getEntityLocalTransform(const QUuid& entityI
|
|||
if (entity) {
|
||||
glm::mat4 translation = glm::translate(entity->getLocalPosition());
|
||||
glm::mat4 rotation = glm::mat4_cast(entity->getLocalOrientation());
|
||||
glm::mat4 registration = glm::translate(ENTITY_ITEM_DEFAULT_REGISTRATION_POINT -
|
||||
entity->getRegistrationPoint());
|
||||
result = translation * rotation * registration;
|
||||
result = translation * rotation;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
|
@ -118,7 +118,7 @@ glm::vec3 OBJTokenizer::getVec3() {
|
|||
auto z = getFloat();
|
||||
auto v = glm::vec3(x, y, z);
|
||||
while (isNextTokenFloat()) {
|
||||
// the spec(s) get(s) vague here. might be w, might be a color... chop it off.
|
||||
// ignore any following floats
|
||||
nextToken();
|
||||
}
|
||||
return v;
|
||||
|
@ -139,7 +139,7 @@ bool OBJTokenizer::getVertex(glm::vec3& vertex, glm::vec3& vertexColor) {
|
|||
// only a single value) that it's a vertex color.
|
||||
r = getFloat();
|
||||
if (isNextTokenFloat()) {
|
||||
// Safe to assume the following values are the green/blue components.
|
||||
// Safe to assume the following values are the green/blue components.
|
||||
g = getFloat();
|
||||
b = getFloat();
|
||||
|
||||
|
@ -351,6 +351,8 @@ bool OBJReader::parseOBJGroup(OBJTokenizer& tokenizer, const QVariantHash& mappi
|
|||
bool result = true;
|
||||
int originalFaceCountForDebugging = 0;
|
||||
QString currentGroup;
|
||||
bool anyVertexColor { false };
|
||||
int vertexCount { 0 };
|
||||
|
||||
setMeshPartDefaults(meshPart, QString("dontknow") + QString::number(mesh.parts.count()));
|
||||
|
||||
|
@ -412,14 +414,25 @@ bool OBJReader::parseOBJGroup(OBJTokenizer& tokenizer, const QVariantHash& mappi
|
|||
#endif
|
||||
}
|
||||
} else if (token == "v") {
|
||||
glm::vec3 vertex, vertexColor;
|
||||
glm::vec3 vertex;
|
||||
glm::vec3 vertexColor { glm::vec3(1.0f) };
|
||||
|
||||
bool hasVertexColor = tokenizer.getVertex(vertex, vertexColor);
|
||||
vertices.append(vertex);
|
||||
|
||||
if(hasVertexColor) {
|
||||
|
||||
// if any vertex has color, they all need to.
|
||||
if (hasVertexColor && !anyVertexColor) {
|
||||
// we've had a gap of zero or more vertices without color, followed
|
||||
// by one that has color. catch up:
|
||||
for (int i = 0; i < vertexCount; i++) {
|
||||
vertexColors.append(glm::vec3(1.0f));
|
||||
}
|
||||
anyVertexColor = true;
|
||||
}
|
||||
if (anyVertexColor) {
|
||||
vertexColors.append(vertexColor);
|
||||
}
|
||||
vertexCount++;
|
||||
} else if (token == "vn") {
|
||||
normals.append(tokenizer.getVec3());
|
||||
} else if (token == "vt") {
|
||||
|
|
|
@ -40,8 +40,6 @@ static QString formatFloat(double n) {
|
|||
}
|
||||
|
||||
bool writeOBJToTextStream(QTextStream& out, QList<MeshPointer> meshes) {
|
||||
int attributeTypeNormal = gpu::Stream::InputSlot::NORMAL; // libraries/gpu/src/gpu/Stream.h
|
||||
|
||||
// each mesh's vertices are numbered from zero. We're combining all their vertices into one list here,
|
||||
// so keep track of the start index for each mesh.
|
||||
QList<int> meshVertexStartOffset;
|
||||
|
@ -49,10 +47,15 @@ bool writeOBJToTextStream(QTextStream& out, QList<MeshPointer> meshes) {
|
|||
int currentVertexStartOffset = 0;
|
||||
int currentNormalStartOffset = 0;
|
||||
|
||||
// write out vertices
|
||||
// write out vertices (and maybe colors)
|
||||
foreach (const MeshPointer& mesh, meshes) {
|
||||
meshVertexStartOffset.append(currentVertexStartOffset);
|
||||
const gpu::BufferView& vertexBuffer = mesh->getVertexBuffer();
|
||||
|
||||
const gpu::BufferView& colorsBufferView = mesh->getAttributeBuffer(gpu::Stream::COLOR);
|
||||
gpu::BufferView::Index numColors = (gpu::BufferView::Index)colorsBufferView.getNumElements();
|
||||
gpu::BufferView::Index colorIndex = 0;
|
||||
|
||||
int vertexCount = 0;
|
||||
gpu::BufferView::Iterator<const glm::vec3> vertexItr = vertexBuffer.cbegin<const glm::vec3>();
|
||||
while (vertexItr != vertexBuffer.cend<const glm::vec3>()) {
|
||||
|
@ -60,7 +63,15 @@ bool writeOBJToTextStream(QTextStream& out, QList<MeshPointer> meshes) {
|
|||
out << "v ";
|
||||
out << formatFloat(v[0]) << " ";
|
||||
out << formatFloat(v[1]) << " ";
|
||||
out << formatFloat(v[2]) << "\n";
|
||||
out << formatFloat(v[2]);
|
||||
if (colorIndex < numColors) {
|
||||
glm::vec3 color = colorsBufferView.get<glm::vec3>(colorIndex);
|
||||
out << " " << formatFloat(color[0]);
|
||||
out << " " << formatFloat(color[1]);
|
||||
out << " " << formatFloat(color[2]);
|
||||
colorIndex++;
|
||||
}
|
||||
out << "\n";
|
||||
vertexItr++;
|
||||
vertexCount++;
|
||||
}
|
||||
|
@ -72,7 +83,7 @@ bool writeOBJToTextStream(QTextStream& out, QList<MeshPointer> meshes) {
|
|||
bool haveNormals = true;
|
||||
foreach (const MeshPointer& mesh, meshes) {
|
||||
meshNormalStartOffset.append(currentNormalStartOffset);
|
||||
const gpu::BufferView& normalsBufferView = mesh->getAttributeBuffer(attributeTypeNormal);
|
||||
const gpu::BufferView& normalsBufferView = mesh->getAttributeBuffer(gpu::Stream::InputSlot::NORMAL);
|
||||
gpu::BufferView::Index numNormals = (gpu::BufferView::Index)normalsBufferView.getNumElements();
|
||||
for (gpu::BufferView::Index i = 0; i < numNormals; i++) {
|
||||
glm::vec3 normal = normalsBufferView.get<glm::vec3>(i);
|
||||
|
|
|
@ -95,7 +95,7 @@ void GL41Backend::updateInput() {
|
|||
// GLenum perLocationStride = strides[bufferNum];
|
||||
GLenum perLocationStride = attrib._element.getLocationSize();
|
||||
GLuint stride = (GLuint)strides[bufferNum];
|
||||
GLuint pointer = (GLuint)(attrib._offset + offsets[bufferNum]);
|
||||
uintptr_t pointer = (uintptr_t)(attrib._offset + offsets[bufferNum]);
|
||||
GLboolean isNormalized = attrib._element.isNormalized();
|
||||
|
||||
for (size_t locNum = 0; locNum < locationCount; ++locNum) {
|
||||
|
|
|
@ -192,7 +192,7 @@ public:
|
|||
BufferView(const BufferPointer& buffer, Size offset, Size size, const Element& element = DEFAULT_ELEMENT);
|
||||
BufferView(const BufferPointer& buffer, Size offset, Size size, uint16 stride, const Element& element = DEFAULT_ELEMENT);
|
||||
|
||||
Size getNumElements() const { return (_size - _offset) / _stride; }
|
||||
Size getNumElements() const { return _size / _stride; }
|
||||
|
||||
//Template iterator with random access on the buffer sysmem
|
||||
template<typename T>
|
||||
|
|
|
@ -11,8 +11,6 @@
|
|||
|
||||
#include "Geometry.h"
|
||||
|
||||
#include <QDebug>
|
||||
|
||||
using namespace model;
|
||||
|
||||
Mesh::Mesh() :
|
||||
|
@ -136,11 +134,13 @@ Box Mesh::evalPartsBound(int partStart, int partEnd) const {
|
|||
|
||||
|
||||
model::MeshPointer Mesh::map(std::function<glm::vec3(glm::vec3)> vertexFunc,
|
||||
std::function<glm::vec3(glm::vec3)> colorFunc,
|
||||
std::function<glm::vec3(glm::vec3)> normalFunc,
|
||||
std::function<uint32_t(uint32_t)> indexFunc) {
|
||||
std::function<uint32_t(uint32_t)> indexFunc) const {
|
||||
// vertex data
|
||||
const gpu::BufferView& vertexBufferView = getVertexBuffer();
|
||||
gpu::BufferView::Index numVertices = (gpu::BufferView::Index)getNumVertices();
|
||||
|
||||
gpu::Resource::Size vertexSize = numVertices * sizeof(glm::vec3);
|
||||
unsigned char* resultVertexData = new unsigned char[vertexSize];
|
||||
unsigned char* vertexDataCursor = resultVertexData;
|
||||
|
@ -151,6 +151,21 @@ model::MeshPointer Mesh::map(std::function<glm::vec3(glm::vec3)> vertexFunc,
|
|||
vertexDataCursor += sizeof(pos);
|
||||
}
|
||||
|
||||
// color data
|
||||
int attributeTypeColor = gpu::Stream::COLOR;
|
||||
const gpu::BufferView& colorsBufferView = getAttributeBuffer(attributeTypeColor);
|
||||
gpu::BufferView::Index numColors = (gpu::BufferView::Index)colorsBufferView.getNumElements();
|
||||
|
||||
gpu::Resource::Size colorSize = numColors * sizeof(glm::vec3);
|
||||
unsigned char* resultColorData = new unsigned char[colorSize];
|
||||
unsigned char* colorDataCursor = resultColorData;
|
||||
|
||||
for (gpu::BufferView::Index i = 0; i < numColors; i++) {
|
||||
glm::vec3 color = colorFunc(colorsBufferView.get<glm::vec3>(i));
|
||||
memcpy(colorDataCursor, &color, sizeof(color));
|
||||
colorDataCursor += sizeof(color);
|
||||
}
|
||||
|
||||
// normal data
|
||||
int attributeTypeNormal = gpu::Stream::InputSlot::NORMAL; // libraries/gpu/src/gpu/Stream.h
|
||||
const gpu::BufferView& normalsBufferView = getAttributeBuffer(attributeTypeNormal);
|
||||
|
@ -187,6 +202,12 @@ model::MeshPointer Mesh::map(std::function<glm::vec3(glm::vec3)> vertexFunc,
|
|||
gpu::BufferView resultVertexBufferView(resultVertexBufferPointer, vertexElement);
|
||||
result->setVertexBuffer(resultVertexBufferView);
|
||||
|
||||
gpu::Element colorElement = gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::XYZ);
|
||||
gpu::Buffer* resultColorsBuffer = new gpu::Buffer(colorSize, resultColorData);
|
||||
gpu::BufferPointer resultColorsBufferPointer(resultColorsBuffer);
|
||||
gpu::BufferView resultColorsBufferView(resultColorsBufferPointer, colorElement);
|
||||
result->addAttribute(attributeTypeColor, resultColorsBufferView);
|
||||
|
||||
gpu::Element normalElement = gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::XYZ);
|
||||
gpu::Buffer* resultNormalsBuffer = new gpu::Buffer(normalSize, resultNormalData);
|
||||
gpu::BufferPointer resultNormalsBufferPointer(resultNormalsBuffer);
|
||||
|
@ -215,6 +236,7 @@ model::MeshPointer Mesh::map(std::function<glm::vec3(glm::vec3)> vertexFunc,
|
|||
|
||||
|
||||
void Mesh::forEach(std::function<void(glm::vec3)> vertexFunc,
|
||||
std::function<void(glm::vec3)> colorFunc,
|
||||
std::function<void(glm::vec3)> normalFunc,
|
||||
std::function<void(uint32_t)> indexFunc) {
|
||||
// vertex data
|
||||
|
@ -224,6 +246,14 @@ void Mesh::forEach(std::function<void(glm::vec3)> vertexFunc,
|
|||
vertexFunc(vertexBufferView.get<glm::vec3>(i));
|
||||
}
|
||||
|
||||
// color data
|
||||
int attributeTypeColor = gpu::Stream::InputSlot::COLOR; // libraries/gpu/src/gpu/Stream.h
|
||||
const gpu::BufferView& colorsBufferView = getAttributeBuffer(attributeTypeColor);
|
||||
gpu::BufferView::Index numColors = (gpu::BufferView::Index)colorsBufferView.getNumElements();
|
||||
for (gpu::BufferView::Index i = 0; i < numColors; i++) {
|
||||
colorFunc(colorsBufferView.get<glm::vec3>(i));
|
||||
}
|
||||
|
||||
// normal data
|
||||
int attributeTypeNormal = gpu::Stream::InputSlot::NORMAL; // libraries/gpu/src/gpu/Stream.h
|
||||
const gpu::BufferView& normalsBufferView = getAttributeBuffer(attributeTypeNormal);
|
||||
|
|
|
@ -123,10 +123,12 @@ public:
|
|||
|
||||
// create a copy of this mesh after passing its vertices, normals, and indexes though the provided functions
|
||||
MeshPointer map(std::function<glm::vec3(glm::vec3)> vertexFunc,
|
||||
std::function<glm::vec3(glm::vec3)> colorFunc,
|
||||
std::function<glm::vec3(glm::vec3)> normalFunc,
|
||||
std::function<uint32_t(uint32_t)> indexFunc);
|
||||
std::function<uint32_t(uint32_t)> indexFunc) const;
|
||||
|
||||
void forEach(std::function<void(glm::vec3)> vertexFunc,
|
||||
std::function<void(glm::vec3)> colorFunc,
|
||||
std::function<void(glm::vec3)> normalFunc,
|
||||
std::function<void(uint32_t)> indexFunc);
|
||||
|
||||
|
|
|
@ -327,7 +327,7 @@ void NodeList::sendDomainServerCheckIn() {
|
|||
<< "but no keypair is present. Waiting for keypair generation to complete.";
|
||||
accountManager->generateNewUserKeypair();
|
||||
|
||||
// don't send the check in packet - wait for the keypair first
|
||||
// don't send the check in packet - wait for the new public key to be available to the domain-server first
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
#include <PerfStat.h>
|
||||
#include <ViewFrustum.h>
|
||||
#include <GLMHelpers.h>
|
||||
#include <model-networking/SimpleMeshProxy.h>
|
||||
|
||||
#include "AbstractViewStateInterface.h"
|
||||
#include "MeshPartPayload.h"
|
||||
|
@ -462,6 +463,41 @@ bool Model::convexHullContains(glm::vec3 point) {
|
|||
return false;
|
||||
}
|
||||
|
||||
MeshProxyList Model::getMeshes() const {
|
||||
MeshProxyList result;
|
||||
const Geometry::Pointer& renderGeometry = getGeometry();
|
||||
const Geometry::GeometryMeshes& meshes = renderGeometry->getMeshes();
|
||||
|
||||
if (!isLoaded()) {
|
||||
return result;
|
||||
}
|
||||
|
||||
Transform offset;
|
||||
offset.setScale(_scale);
|
||||
offset.postTranslate(_offset);
|
||||
glm::mat4 offsetMat = offset.getMatrix();
|
||||
|
||||
for (std::shared_ptr<const model::Mesh> mesh : meshes) {
|
||||
if (!mesh) {
|
||||
continue;
|
||||
}
|
||||
|
||||
MeshProxy* meshProxy = new SimpleMeshProxy(
|
||||
mesh->map(
|
||||
[=](glm::vec3 position) {
|
||||
return glm::vec3(offsetMat * glm::vec4(position, 1.0f));
|
||||
},
|
||||
[=](glm::vec3 color) { return color; },
|
||||
[=](glm::vec3 normal) {
|
||||
return glm::normalize(glm::vec3(offsetMat * glm::vec4(normal, 0.0f)));
|
||||
},
|
||||
[&](uint32_t index) { return index; }));
|
||||
result << meshProxy;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void Model::calculateTriangleSets() {
|
||||
PROFILE_RANGE(render, __FUNCTION__);
|
||||
|
||||
|
|
|
@ -257,6 +257,8 @@ public:
|
|||
int getResourceDownloadAttempts() { return _renderWatcher.getResourceDownloadAttempts(); }
|
||||
int getResourceDownloadAttemptsRemaining() { return _renderWatcher.getResourceDownloadAttemptsRemaining(); }
|
||||
|
||||
Q_INVOKABLE MeshProxyList getMeshes() const;
|
||||
|
||||
public slots:
|
||||
void loadURLFinished(bool success);
|
||||
|
||||
|
|
|
@ -38,16 +38,22 @@ QString ModelScriptingInterface::meshToOBJ(MeshProxyList in) {
|
|||
QScriptValue ModelScriptingInterface::appendMeshes(MeshProxyList in) {
|
||||
// figure out the size of the resulting mesh
|
||||
size_t totalVertexCount { 0 };
|
||||
size_t totalAttributeCount { 0 };
|
||||
size_t totalColorCount { 0 };
|
||||
size_t totalNormalCount { 0 };
|
||||
size_t totalIndexCount { 0 };
|
||||
foreach (const MeshProxy* meshProxy, in) {
|
||||
MeshPointer mesh = meshProxy->getMeshPointer();
|
||||
totalVertexCount += mesh->getNumVertices();
|
||||
|
||||
int attributeTypeColor = gpu::Stream::InputSlot::COLOR; // libraries/gpu/src/gpu/Stream.h
|
||||
const gpu::BufferView& colorsBufferView = mesh->getAttributeBuffer(attributeTypeColor);
|
||||
gpu::BufferView::Index numColors = (gpu::BufferView::Index)colorsBufferView.getNumElements();
|
||||
totalColorCount += numColors;
|
||||
|
||||
int attributeTypeNormal = gpu::Stream::InputSlot::NORMAL; // libraries/gpu/src/gpu/Stream.h
|
||||
const gpu::BufferView& normalsBufferView = mesh->getAttributeBuffer(attributeTypeNormal);
|
||||
gpu::BufferView::Index numNormals = (gpu::BufferView::Index)normalsBufferView.getNumElements();
|
||||
totalAttributeCount += numNormals;
|
||||
totalNormalCount += numNormals;
|
||||
|
||||
totalIndexCount += mesh->getNumIndices();
|
||||
}
|
||||
|
@ -57,7 +63,11 @@ QScriptValue ModelScriptingInterface::appendMeshes(MeshProxyList in) {
|
|||
unsigned char* combinedVertexData = new unsigned char[combinedVertexSize];
|
||||
unsigned char* combinedVertexDataCursor = combinedVertexData;
|
||||
|
||||
gpu::Resource::Size combinedNormalSize = totalAttributeCount * sizeof(glm::vec3);
|
||||
gpu::Resource::Size combinedColorSize = totalColorCount * sizeof(glm::vec3);
|
||||
unsigned char* combinedColorData = new unsigned char[combinedColorSize];
|
||||
unsigned char* combinedColorDataCursor = combinedColorData;
|
||||
|
||||
gpu::Resource::Size combinedNormalSize = totalNormalCount * sizeof(glm::vec3);
|
||||
unsigned char* combinedNormalData = new unsigned char[combinedNormalSize];
|
||||
unsigned char* combinedNormalDataCursor = combinedNormalData;
|
||||
|
||||
|
@ -74,6 +84,10 @@ QScriptValue ModelScriptingInterface::appendMeshes(MeshProxyList in) {
|
|||
memcpy(combinedVertexDataCursor, &position, sizeof(position));
|
||||
combinedVertexDataCursor += sizeof(position);
|
||||
},
|
||||
[&](glm::vec3 color){
|
||||
memcpy(combinedColorDataCursor, &color, sizeof(color));
|
||||
combinedColorDataCursor += sizeof(color);
|
||||
},
|
||||
[&](glm::vec3 normal){
|
||||
memcpy(combinedNormalDataCursor, &normal, sizeof(normal));
|
||||
combinedNormalDataCursor += sizeof(normal);
|
||||
|
@ -96,6 +110,13 @@ QScriptValue ModelScriptingInterface::appendMeshes(MeshProxyList in) {
|
|||
gpu::BufferView combinedVertexBufferView(combinedVertexBufferPointer, vertexElement);
|
||||
result->setVertexBuffer(combinedVertexBufferView);
|
||||
|
||||
int attributeTypeColor = gpu::Stream::InputSlot::COLOR; // libraries/gpu/src/gpu/Stream.h
|
||||
gpu::Element colorElement = gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::XYZ);
|
||||
gpu::Buffer* combinedColorsBuffer = new gpu::Buffer(combinedColorSize, combinedColorData);
|
||||
gpu::BufferPointer combinedColorsBufferPointer(combinedColorsBuffer);
|
||||
gpu::BufferView combinedColorsBufferView(combinedColorsBufferPointer, colorElement);
|
||||
result->addAttribute(attributeTypeColor, combinedColorsBufferView);
|
||||
|
||||
int attributeTypeNormal = gpu::Stream::InputSlot::NORMAL; // libraries/gpu/src/gpu/Stream.h
|
||||
gpu::Element normalElement = gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::XYZ);
|
||||
gpu::Buffer* combinedNormalsBuffer = new gpu::Buffer(combinedNormalSize, combinedNormalData);
|
||||
|
@ -132,12 +153,48 @@ QScriptValue ModelScriptingInterface::transformMesh(glm::mat4 transform, MeshPro
|
|||
}
|
||||
|
||||
model::MeshPointer result = mesh->map([&](glm::vec3 position){ return glm::vec3(transform * glm::vec4(position, 1.0f)); },
|
||||
[&](glm::vec3 color){ return color; },
|
||||
[&](glm::vec3 normal){ return glm::vec3(transform * glm::vec4(normal, 0.0f)); },
|
||||
[&](uint32_t index){ return index; });
|
||||
MeshProxy* resultProxy = new SimpleMeshProxy(result);
|
||||
return meshToScriptValue(_modelScriptEngine, resultProxy);
|
||||
}
|
||||
|
||||
QScriptValue ModelScriptingInterface::getVertexCount(MeshProxy* meshProxy) {
|
||||
if (!meshProxy) {
|
||||
return QScriptValue(false);
|
||||
}
|
||||
MeshPointer mesh = meshProxy->getMeshPointer();
|
||||
if (!mesh) {
|
||||
return QScriptValue(false);
|
||||
}
|
||||
|
||||
gpu::BufferView::Index numVertices = (gpu::BufferView::Index)mesh->getNumVertices();
|
||||
|
||||
return numVertices;
|
||||
}
|
||||
|
||||
QScriptValue ModelScriptingInterface::getVertex(MeshProxy* meshProxy, int vertexIndex) {
|
||||
if (!meshProxy) {
|
||||
return QScriptValue(false);
|
||||
}
|
||||
MeshPointer mesh = meshProxy->getMeshPointer();
|
||||
if (!mesh) {
|
||||
return QScriptValue(false);
|
||||
}
|
||||
|
||||
const gpu::BufferView& vertexBufferView = mesh->getVertexBuffer();
|
||||
gpu::BufferView::Index numVertices = (gpu::BufferView::Index)mesh->getNumVertices();
|
||||
|
||||
if (vertexIndex < 0 || vertexIndex >= numVertices) {
|
||||
return QScriptValue(false);
|
||||
}
|
||||
|
||||
glm::vec3 pos = vertexBufferView.get<glm::vec3>(vertexIndex);
|
||||
return vec3toScriptValue(_modelScriptEngine, pos);
|
||||
}
|
||||
|
||||
|
||||
QScriptValue ModelScriptingInterface::newMesh(const QVector<glm::vec3>& vertices,
|
||||
const QVector<glm::vec3>& normals,
|
||||
const QVector<MeshFace>& faces) {
|
||||
|
|
|
@ -29,6 +29,8 @@ public:
|
|||
Q_INVOKABLE QScriptValue newMesh(const QVector<glm::vec3>& vertices,
|
||||
const QVector<glm::vec3>& normals,
|
||||
const QVector<MeshFace>& faces);
|
||||
Q_INVOKABLE QScriptValue getVertexCount(MeshProxy* meshProxy);
|
||||
Q_INVOKABLE QScriptValue getVertex(MeshProxy* meshProxy, int vertexIndex);
|
||||
|
||||
private:
|
||||
QScriptEngine* _modelScriptEngine { nullptr };
|
||||
|
|
|
@ -56,6 +56,7 @@ public:
|
|||
Checkbox,
|
||||
Button,
|
||||
ComboBox,
|
||||
PrimaryHand,
|
||||
// Special casing for an unusual preference
|
||||
Avatar
|
||||
};
|
||||
|
@ -339,6 +340,14 @@ public:
|
|||
Type getType() override { return Checkbox; }
|
||||
};
|
||||
|
||||
class PrimaryHandPreference : public StringPreference {
|
||||
Q_OBJECT
|
||||
public:
|
||||
PrimaryHandPreference(const QString& category, const QString& name, Getter getter, Setter setter)
|
||||
: StringPreference(category, name, getter, setter) { }
|
||||
Type getType() override { return PrimaryHand; }
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
|
|
@ -92,9 +92,8 @@ FileStorage::FileStorage(const QString& filename) : _file(filename) {
|
|||
|
||||
FileStorage::~FileStorage() {
|
||||
if (_mapped) {
|
||||
if (!_file.unmap(_mapped)) {
|
||||
throw std::runtime_error("Unable to unmap file");
|
||||
}
|
||||
_file.unmap(_mapped);
|
||||
_mapped = nullptr;
|
||||
}
|
||||
if (_file.isOpen()) {
|
||||
_file.close();
|
||||
|
|
|
@ -367,6 +367,12 @@ void NeuronPlugin::init() {
|
|||
|
||||
auto preferences = DependencyManager::get<Preferences>();
|
||||
static const QString NEURON_PLUGIN { "Perception Neuron" };
|
||||
{
|
||||
auto getter = [this]()->bool { return _enabled; };
|
||||
auto setter = [this](bool value) { _enabled = value; saveSettings(); };
|
||||
auto preference = new CheckPreference(NEURON_PLUGIN, "Enabled", getter, setter);
|
||||
preferences->addPreference(preference);
|
||||
}
|
||||
{
|
||||
auto getter = [this]()->QString { return _serverAddress; };
|
||||
auto setter = [this](const QString& value) { _serverAddress = value; saveSettings(); };
|
||||
|
@ -387,12 +393,6 @@ void NeuronPlugin::init() {
|
|||
preference->setStep(1);
|
||||
preferences->addPreference(preference);
|
||||
}
|
||||
{
|
||||
auto getter = [this]()->bool { return _enabled; };
|
||||
auto setter = [this](bool value) { _enabled = value; saveSettings(); };
|
||||
auto preference = new CheckPreference(NEURON_PLUGIN, "Enabled", getter, setter);
|
||||
preferences->addPreference(preference);
|
||||
}
|
||||
}
|
||||
|
||||
bool NeuronPlugin::isSupported() const {
|
||||
|
@ -455,6 +455,10 @@ void NeuronPlugin::deactivate() {
|
|||
}
|
||||
|
||||
void NeuronPlugin::pluginUpdate(float deltaTime, const controller::InputCalibrationData& inputCalibrationData) {
|
||||
if (!_enabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
std::vector<NeuronJoint> joints;
|
||||
{
|
||||
// lock and copy
|
||||
|
|
|
@ -11,8 +11,10 @@
|
|||
|
||||
#include <qapplication.h>
|
||||
|
||||
#include <PerfStat.h>
|
||||
#include <controllers/UserInputMapper.h>
|
||||
#include <PerfStat.h>
|
||||
#include <Preferences.h>
|
||||
#include <SettingHandle.h>
|
||||
|
||||
#include "SDL2Manager.h"
|
||||
|
||||
|
@ -38,10 +40,13 @@ static_assert(
|
|||
(int)controller::RY == (int)SDL_CONTROLLER_AXIS_RIGHTY &&
|
||||
(int)controller::LT == (int)SDL_CONTROLLER_AXIS_TRIGGERLEFT &&
|
||||
(int)controller::RT == (int)SDL_CONTROLLER_AXIS_TRIGGERRIGHT,
|
||||
"SDL2 equvalence: Enums and values from StandardControls.h are assumed to match enums from SDL_gamecontroller.h");
|
||||
"SDL2 equivalence: Enums and values from StandardControls.h are assumed to match enums from SDL_gamecontroller.h");
|
||||
|
||||
|
||||
const char* SDL2Manager::NAME = "SDL2";
|
||||
const char* SDL2Manager::SDL2_ID_STRING = "SDL2";
|
||||
|
||||
const bool DEFAULT_ENABLED = false;
|
||||
|
||||
SDL_JoystickID SDL2Manager::getInstanceId(SDL_GameController* controller) {
|
||||
SDL_Joystick* joystick = SDL_GameControllerGetJoystick(controller);
|
||||
|
@ -49,6 +54,20 @@ SDL_JoystickID SDL2Manager::getInstanceId(SDL_GameController* controller) {
|
|||
}
|
||||
|
||||
void SDL2Manager::init() {
|
||||
loadSettings();
|
||||
|
||||
auto preferences = DependencyManager::get<Preferences>();
|
||||
static const QString SDL2_PLUGIN { "Game Controller" };
|
||||
{
|
||||
auto getter = [this]()->bool { return _isEnabled; };
|
||||
auto setter = [this](bool value) {
|
||||
_isEnabled = value;
|
||||
saveSettings();
|
||||
};
|
||||
auto preference = new CheckPreference(SDL2_PLUGIN, "Enabled", getter, setter);
|
||||
preferences->addPreference(preference);
|
||||
}
|
||||
|
||||
bool initSuccess = (SDL_Init(SDL_INIT_GAMECONTROLLER | SDL_INIT_HAPTIC) == 0);
|
||||
|
||||
if (initSuccess) {
|
||||
|
@ -110,6 +129,27 @@ void SDL2Manager::deactivate() {
|
|||
InputPlugin::deactivate();
|
||||
}
|
||||
|
||||
const char* SETTINGS_ENABLED_KEY = "enabled";
|
||||
|
||||
void SDL2Manager::saveSettings() const {
|
||||
Settings settings;
|
||||
QString idString = getID();
|
||||
settings.beginGroup(idString);
|
||||
{
|
||||
settings.setValue(QString(SETTINGS_ENABLED_KEY), _isEnabled);
|
||||
}
|
||||
settings.endGroup();
|
||||
}
|
||||
|
||||
void SDL2Manager::loadSettings() {
|
||||
Settings settings;
|
||||
QString idString = getID();
|
||||
settings.beginGroup(idString);
|
||||
{
|
||||
_isEnabled = settings.value(SETTINGS_ENABLED_KEY, QVariant(DEFAULT_ENABLED)).toBool();
|
||||
}
|
||||
settings.endGroup();
|
||||
}
|
||||
|
||||
bool SDL2Manager::isSupported() const {
|
||||
return true;
|
||||
|
@ -122,6 +162,10 @@ void SDL2Manager::pluginFocusOutEvent() {
|
|||
}
|
||||
|
||||
void SDL2Manager::pluginUpdate(float deltaTime, const controller::InputCalibrationData& inputCalibrationData) {
|
||||
if (!_isEnabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (_isInitialized) {
|
||||
auto userInputMapper = DependencyManager::get<controller::UserInputMapper>();
|
||||
for (auto joystick : _openJoysticks) {
|
||||
|
|
|
@ -25,6 +25,7 @@ public:
|
|||
// Plugin functions
|
||||
bool isSupported() const override;
|
||||
const QString getName() const override { return NAME; }
|
||||
const QString getID() const override { return SDL2_ID_STRING; }
|
||||
|
||||
QStringList getSubdeviceNames() override;
|
||||
|
||||
|
@ -39,6 +40,9 @@ public:
|
|||
void pluginFocusOutEvent() override;
|
||||
void pluginUpdate(float deltaTime, const controller::InputCalibrationData& inputCalibrationData) override;
|
||||
|
||||
virtual void saveSettings() const override;
|
||||
virtual void loadSettings() override;
|
||||
|
||||
signals:
|
||||
void joystickAdded(Joystick* joystick);
|
||||
void joystickRemoved(Joystick* joystick);
|
||||
|
@ -77,8 +81,10 @@ private:
|
|||
int buttonRelease() const { return SDL_RELEASED; }
|
||||
|
||||
QMap<SDL_JoystickID, Joystick::Pointer> _openJoysticks;
|
||||
bool _isInitialized { false } ;
|
||||
bool _isEnabled { false };
|
||||
bool _isInitialized { false };
|
||||
static const char* NAME;
|
||||
static const char* SDL2_ID_STRING;
|
||||
QStringList _subdeviceNames;
|
||||
};
|
||||
|
||||
|
|
|
@ -29,6 +29,7 @@
|
|||
#include <PathUtils.h>
|
||||
#include <PerfStat.h>
|
||||
#include <ui-plugins/PluginContainer.h>
|
||||
#include <Preferences.h>
|
||||
#include <SettingHandle.h>
|
||||
|
||||
#include <QLoggingCategory>
|
||||
|
@ -46,19 +47,26 @@ static const unsigned int BUTTON_TRIGGER = 1U << 8;
|
|||
|
||||
const glm::vec3 SixenseManager::DEFAULT_AVATAR_POSITION { -0.25f, -0.35f, -0.3f }; // in hydra frame
|
||||
const float SixenseManager::CONTROLLER_THRESHOLD { 0.35f };
|
||||
|
||||
bool SixenseManager::_isEnabled = false;
|
||||
bool SixenseManager::_sixenseLoaded = false;
|
||||
|
||||
#define BAIL_IF_NOT_ENABLED \
|
||||
if (!_isEnabled) { \
|
||||
return; \
|
||||
}
|
||||
|
||||
#define BAIL_IF_NOT_LOADED \
|
||||
if (!_sixenseLoaded) { \
|
||||
return; \
|
||||
}
|
||||
|
||||
|
||||
|
||||
const char* SixenseManager::NAME { "Sixense" };
|
||||
const char* SixenseManager::HYDRA_ID_STRING { "Razer Hydra" };
|
||||
const char* SixenseManager::SIXENSE_ID_STRING { "Sixense" };
|
||||
|
||||
const char* MENU_PARENT { "Developer" };
|
||||
const bool DEFAULT_ENABLED = false;
|
||||
|
||||
const char* MENU_PARENT{ "Developer" };
|
||||
const char* MENU_NAME { "Sixense" };
|
||||
const char* MENU_PATH { "Developer" ">" "Sixense" };
|
||||
const char* TOGGLE_SMOOTH { "Smooth Sixense Movement" };
|
||||
|
@ -73,6 +81,22 @@ bool SixenseManager::isSupported() const {
|
|||
#endif
|
||||
}
|
||||
|
||||
void SixenseManager::init() {
|
||||
loadSettings();
|
||||
|
||||
auto preferences = DependencyManager::get<Preferences>();
|
||||
static const QString SIXENSE_PLUGIN { "Sixense Controllers" };
|
||||
{
|
||||
auto getter = [this]()->bool { return _isEnabled; };
|
||||
auto setter = [this](bool value) {
|
||||
_isEnabled = value;
|
||||
saveSettings();
|
||||
};
|
||||
auto preference = new CheckPreference(SIXENSE_PLUGIN, "Enabled", getter, setter);
|
||||
preferences->addPreference(preference);
|
||||
}
|
||||
}
|
||||
|
||||
bool SixenseManager::activate() {
|
||||
InputPlugin::activate();
|
||||
|
||||
|
@ -133,6 +157,7 @@ void SixenseManager::setSixenseFilter(bool filter) {
|
|||
}
|
||||
|
||||
void SixenseManager::pluginUpdate(float deltaTime, const controller::InputCalibrationData& inputCalibrationData) {
|
||||
BAIL_IF_NOT_ENABLED
|
||||
BAIL_IF_NOT_LOADED
|
||||
|
||||
#ifdef HAVE_SIXENSE
|
||||
|
@ -553,14 +578,19 @@ QString SixenseManager::InputDevice::getDefaultMappingConfig() const {
|
|||
return MAPPING_JSON;
|
||||
}
|
||||
|
||||
const char* SETTINGS_ENABLED_KEY = "enabled";
|
||||
const char* SETTINGS_AVATAR_POSITION_KEY = "avatarPosition";
|
||||
const char* SETTINGS_AVATAR_ROTATION_KEY = "avatarPosition";
|
||||
|
||||
// virtual
|
||||
void SixenseManager::saveSettings() const {
|
||||
Settings settings;
|
||||
QString idString = getID();
|
||||
settings.beginGroup(idString);
|
||||
{
|
||||
settings.setVec3Value(QString("avatarPosition"), _inputDevice->_avatarPosition);
|
||||
settings.setQuatValue(QString("avatarRotation"), _inputDevice->_avatarRotation);
|
||||
settings.setValue(QString(SETTINGS_ENABLED_KEY), _isEnabled);
|
||||
settings.setVec3Value(QString(SETTINGS_AVATAR_POSITION_KEY), _inputDevice->_avatarPosition);
|
||||
settings.setQuatValue(QString(SETTINGS_AVATAR_ROTATION_KEY), _inputDevice->_avatarRotation);
|
||||
}
|
||||
settings.endGroup();
|
||||
}
|
||||
|
@ -570,8 +600,9 @@ void SixenseManager::loadSettings() {
|
|||
QString idString = getID();
|
||||
settings.beginGroup(idString);
|
||||
{
|
||||
settings.getVec3ValueIfValid(QString("avatarPosition"), _inputDevice->_avatarPosition);
|
||||
settings.getQuatValueIfValid(QString("avatarRotation"), _inputDevice->_avatarRotation);
|
||||
_isEnabled = settings.value(SETTINGS_ENABLED_KEY, QVariant(DEFAULT_ENABLED)).toBool();
|
||||
settings.getVec3ValueIfValid(QString(SETTINGS_AVATAR_POSITION_KEY), _inputDevice->_avatarPosition);
|
||||
settings.getQuatValueIfValid(QString(SETTINGS_AVATAR_ROTATION_KEY), _inputDevice->_avatarRotation);
|
||||
}
|
||||
settings.endGroup();
|
||||
}
|
||||
|
|
|
@ -29,12 +29,14 @@ public:
|
|||
// Plugin functions
|
||||
virtual bool isSupported() const override;
|
||||
virtual const QString getName() const override { return NAME; }
|
||||
virtual const QString getID() const override { return HYDRA_ID_STRING; }
|
||||
virtual const QString getID() const override { return SIXENSE_ID_STRING; }
|
||||
|
||||
// Sixense always seems to initialize even if the hydras are not present. Is there
|
||||
// a way we can properly detect whether the hydras are present?
|
||||
// bool isHandController() const override { return true; }
|
||||
|
||||
virtual void init() override;
|
||||
|
||||
virtual bool activate() override;
|
||||
virtual void deactivate() override;
|
||||
|
||||
|
@ -93,8 +95,9 @@ private:
|
|||
std::shared_ptr<InputDevice> _inputDevice { std::make_shared<InputDevice>() };
|
||||
|
||||
static const char* NAME;
|
||||
static const char* HYDRA_ID_STRING;
|
||||
static const char* SIXENSE_ID_STRING;
|
||||
|
||||
static bool _isEnabled;
|
||||
static bool _sixenseLoaded;
|
||||
};
|
||||
|
||||
|
|
|
@ -282,7 +282,7 @@ public:
|
|||
static const vr::VRTextureBounds_t leftBounds{ 0, 0, 0.5f, 1 };
|
||||
static const vr::VRTextureBounds_t rightBounds{ 0.5f, 0, 1, 1 };
|
||||
|
||||
vr::Texture_t texture{ (void*)_colors[currentColorBuffer], vr::TextureType_OpenGL, vr::ColorSpace_Auto };
|
||||
vr::Texture_t texture{ (void*)(uintptr_t)_colors[currentColorBuffer], vr::TextureType_OpenGL, vr::ColorSpace_Auto };
|
||||
vr::VRCompositor()->Submit(vr::Eye_Left, &texture, &leftBounds);
|
||||
vr::VRCompositor()->Submit(vr::Eye_Right, &texture, &rightBounds);
|
||||
_plugin._presentRate.increment();
|
||||
|
@ -643,7 +643,7 @@ void OpenVrDisplayPlugin::hmdPresent() {
|
|||
_submitThread->waitForPresent();
|
||||
} else {
|
||||
GLuint glTexId = getGLBackend()->getTextureID(_compositeFramebuffer->getRenderBuffer(0));
|
||||
vr::Texture_t vrTexture { (void*)glTexId, vr::TextureType_OpenGL, vr::ColorSpace_Auto };
|
||||
vr::Texture_t vrTexture { (void*)(uintptr_t)glTexId, vr::TextureType_OpenGL, vr::ColorSpace_Auto };
|
||||
vr::VRCompositor()->Submit(vr::Eye_Left, &vrTexture, &OPENVR_TEXTURE_BOUNDS_LEFT);
|
||||
vr::VRCompositor()->Submit(vr::Eye_Right, &vrTexture, &OPENVR_TEXTURE_BOUNDS_RIGHT);
|
||||
vr::VRCompositor()->PostPresentHandoff();
|
||||
|
|
|
@ -129,7 +129,7 @@ void releaseOpenVrSystem() {
|
|||
#endif
|
||||
|
||||
// HACK: workaround openvr crash, call submit with an invalid texture, right before VR_Shutdown.
|
||||
const GLuint INVALID_GL_TEXTURE_HANDLE = -1;
|
||||
const void* INVALID_GL_TEXTURE_HANDLE = (void*)(uintptr_t)-1;
|
||||
vr::Texture_t vrTexture{ (void*)INVALID_GL_TEXTURE_HANDLE, vr::TextureType_OpenGL, vr::ColorSpace_Auto };
|
||||
static vr::VRTextureBounds_t OPENVR_TEXTURE_BOUNDS_LEFT{ 0, 0, 0.5f, 1 };
|
||||
static vr::VRTextureBounds_t OPENVR_TEXTURE_BOUNDS_RIGHT{ 0.5f, 0, 1, 1 };
|
||||
|
|
|
@ -337,6 +337,8 @@ var toolBar = (function () {
|
|||
var SHAPE_TYPE_SIMPLE_HULL = 1;
|
||||
var SHAPE_TYPE_SIMPLE_COMPOUND = 2;
|
||||
var SHAPE_TYPE_STATIC_MESH = 3;
|
||||
var SHAPE_TYPE_BOX = 4;
|
||||
var SHAPE_TYPE_SPHERE = 5;
|
||||
var DYNAMIC_DEFAULT = false;
|
||||
|
||||
function handleNewModelDialogResult(result) {
|
||||
|
@ -353,6 +355,12 @@ var toolBar = (function () {
|
|||
case SHAPE_TYPE_STATIC_MESH:
|
||||
shapeType = "static-mesh";
|
||||
break;
|
||||
case SHAPE_TYPE_BOX:
|
||||
shapeType = "box";
|
||||
break;
|
||||
case SHAPE_TYPE_SPHERE:
|
||||
shapeType = "sphere";
|
||||
break;
|
||||
default:
|
||||
shapeType = "none";
|
||||
}
|
||||
|
@ -450,6 +458,8 @@ var toolBar = (function () {
|
|||
SHAPE_TYPES[SHAPE_TYPE_SIMPLE_HULL] = "Basic - Whole model";
|
||||
SHAPE_TYPES[SHAPE_TYPE_SIMPLE_COMPOUND] = "Good - Sub-meshes";
|
||||
SHAPE_TYPES[SHAPE_TYPE_STATIC_MESH] = "Exact - All polygons";
|
||||
SHAPE_TYPES[SHAPE_TYPE_BOX] = "Box";
|
||||
SHAPE_TYPES[SHAPE_TYPE_SPHERE] = "Sphere";
|
||||
var SHAPE_TYPE_DEFAULT = SHAPE_TYPE_STATIC_MESH;
|
||||
|
||||
// tablet version of new-model dialog
|
||||
|
@ -654,6 +664,7 @@ var toolBar = (function () {
|
|||
selectionDisplay.triggerMapping.enable();
|
||||
print("starting tablet in landscape mode");
|
||||
tablet.landscape = true;
|
||||
entityIconOverlayManager.setIconsSelectable(null,false);
|
||||
// Not sure what the following was meant to accomplish, but it currently causes
|
||||
// everybody else to think that Interface has lost focus overall. fogbugzid:558
|
||||
// Window.setFocus();
|
||||
|
@ -981,6 +992,7 @@ function mouseClickEvent(event) {
|
|||
} else {
|
||||
selectionManager.addEntity(foundEntity, true);
|
||||
}
|
||||
|
||||
if (wantDebug) {
|
||||
print("Model selected: " + foundEntity);
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
/* globals EntityIconOverlayManager:true */
|
||||
|
||||
EntityIconOverlayManager = function(entityTypes, getOverlayPropertiesFunc) {
|
||||
|
||||
var visible = false;
|
||||
|
||||
// List of all created overlays
|
||||
|
@ -69,6 +70,29 @@ EntityIconOverlayManager = function(entityTypes, getOverlayPropertiesFunc) {
|
|||
}
|
||||
};
|
||||
|
||||
|
||||
this.setIconsSelectable = function(arrayOfSelectedEntityIDs, isIconsSelectable) {
|
||||
if (arrayOfSelectedEntityIDs === null) {
|
||||
for (var id in entityOverlays) {
|
||||
Overlays.editOverlay(entityOverlays[id], {
|
||||
ignoreRayIntersection: isIconsSelectable
|
||||
});
|
||||
}
|
||||
} else {
|
||||
for (var id in entityOverlays) {
|
||||
if (arrayOfSelectedEntityIDs.indexOf(id) !== -1) { // in the entityOverlays array and selectable
|
||||
Overlays.editOverlay(entityOverlays[id], {
|
||||
ignoreRayIntersection: isIconsSelectable
|
||||
});
|
||||
} else {
|
||||
Overlays.editOverlay(entityOverlays[id], {
|
||||
ignoreRayIntersection: !isIconsSelectable
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// Allocate or get an unused overlay
|
||||
function getOverlay() {
|
||||
var overlay;
|
||||
|
@ -114,6 +138,9 @@ EntityIconOverlayManager = function(entityTypes, getOverlayPropertiesFunc) {
|
|||
overlayProperties[key] = customProperties[key];
|
||||
}
|
||||
}
|
||||
if(properties.type === 'ParticleEffect' || properties.type === 'Light'){
|
||||
overlayProperties.ignoreRayIntersection = true;
|
||||
}
|
||||
Overlays.editOverlay(overlay, overlayProperties);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4060,6 +4060,8 @@ SelectionDisplay = (function() {
|
|||
return false;
|
||||
}
|
||||
|
||||
entityIconOverlayManager.setIconsSelectable(selectionManager.selections,true);
|
||||
|
||||
// ignore ray intersection for our selection box and yaw/pitch/roll
|
||||
result = Overlays.findRayIntersection(pickRay, true, null, [ yawHandle, pitchHandle, rollHandle, selectionBox ] );
|
||||
if (result.intersects) {
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
#include <DependencyManager.h>
|
||||
#include <SettingHandle.h>
|
||||
#include <AssetUpload.h>
|
||||
#include <StatTracker.h>
|
||||
|
||||
#include "ATPClientApp.h"
|
||||
|
||||
|
@ -137,6 +138,7 @@ ATPClientApp::ATPClientApp(int argc, char* argv[]) :
|
|||
Setting::init();
|
||||
DependencyManager::registerInheritance<LimitedNodeList, NodeList>();
|
||||
|
||||
DependencyManager::set<StatTracker>();
|
||||
DependencyManager::set<AccountManager>([&]{ return QString(HIGH_FIDELITY_ATP_CLIENT_USER_AGENT); });
|
||||
DependencyManager::set<AddressManager>();
|
||||
DependencyManager::set<NodeList>(NodeType::Agent, _listenPort);
|
||||
|
|
36
unpublishedScripts/DomainContent/Cupcake/eatable.js
Normal file
36
unpublishedScripts/DomainContent/Cupcake/eatable.js
Normal file
|
@ -0,0 +1,36 @@
|
|||
//
|
||||
// eatable.js
|
||||
//
|
||||
// Created by Alan-Michael Moody on 7/24/2017
|
||||
// Copyright 2017 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
|
||||
//
|
||||
|
||||
(function () {
|
||||
var NOMNOM_SOUND = SoundCache.getSound('http://hifi-content.s3.amazonaws.com/DomainContent/production/audio/vegcrunch.wav');
|
||||
|
||||
var _entityID;
|
||||
|
||||
this.preload = function (entityID) {
|
||||
_entityID = entityID;
|
||||
};
|
||||
|
||||
this.collisionWithEntity = function(entityUuid, collisionEntityID, collisionInfo) {
|
||||
var entity = Entities.getEntityProperties(collisionEntityID, ['userData', 'name']);
|
||||
var isClone = (entity.name.substring(1).split('-')[0] === 'clone');
|
||||
var isEatable = (JSON.parse(entity.userData).eatable);
|
||||
|
||||
if (isEatable && isClone) {
|
||||
Audio.playSound(NOMNOM_SOUND, {
|
||||
position: Entities.getEntityProperties(_entityID, ['position']).position,
|
||||
volume: 0.2,
|
||||
localOnly: false
|
||||
});
|
||||
|
||||
Entities.deleteEntity(collisionEntityID);
|
||||
}
|
||||
};
|
||||
});
|
56
unpublishedScripts/gravity.js
Normal file
56
unpublishedScripts/gravity.js
Normal file
|
@ -0,0 +1,56 @@
|
|||
//
|
||||
// gravity.js
|
||||
//
|
||||
// Created by Alan-Michael Moody on 7/24/17
|
||||
// Copyright 2017 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
|
||||
//
|
||||
|
||||
(function () {
|
||||
|
||||
var _entityID;
|
||||
|
||||
this.preload = function (entityID) {
|
||||
_entityID = entityID;
|
||||
};
|
||||
|
||||
function update(deltatime) {
|
||||
var planet = Entities.getEntityProperties(_entityID);
|
||||
|
||||
//normalization happens in rotationBetween.
|
||||
var direction = Vec3.subtract(MyAvatar.position, planet.position);
|
||||
var localUp = Quat.getUp(MyAvatar.orientation);
|
||||
|
||||
MyAvatar.orientation = Quat.normalize(Quat.multiply(Quat.rotationBetween(localUp, direction), MyAvatar.orientation));
|
||||
}
|
||||
|
||||
function init() {
|
||||
Script.update.connect(update);
|
||||
}
|
||||
|
||||
function clean() {
|
||||
Script.update.disconnect(update);
|
||||
MyAvatar.orientation = Quat.fromVec3Degrees({
|
||||
x: 0,
|
||||
y: 0,
|
||||
z: 0
|
||||
});
|
||||
}
|
||||
|
||||
var _switch = true;
|
||||
|
||||
this.clickDownOnEntity = function(uuid, mouseEvent) {
|
||||
|
||||
if (_switch) {
|
||||
init();
|
||||
} else {
|
||||
clean();
|
||||
}
|
||||
_switch = !_switch;
|
||||
};
|
||||
|
||||
Script.scriptEnding.connect(clean);
|
||||
|
||||
});
|
91
unpublishedScripts/marketplace/dart/createDart.js
Normal file
91
unpublishedScripts/marketplace/dart/createDart.js
Normal file
|
@ -0,0 +1,91 @@
|
|||
"use strict";
|
||||
//
|
||||
// createDart.js
|
||||
//
|
||||
// Created by MrRoboman on 17/05/04
|
||||
// Copyright 2017 High Fidelity, Inc.
|
||||
//
|
||||
// Creates five throwing darts.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
|
||||
var MODEL_URL = "https://hifi-content.s3.amazonaws.com/wadewatts/dart.fbx";
|
||||
var SCRIPT_URL = Script.resolvePath("./dart.js?v=" + Date.now());
|
||||
var START_POSITION = Vec3.sum(MyAvatar.position, Vec3.multiply(Quat.getFront(MyAvatar.orientation), 0.75));
|
||||
var START_ROTATION = MyAvatar.orientation
|
||||
var SCALE_FACTOR = 1;
|
||||
|
||||
var dart = {
|
||||
type: "Model",
|
||||
shapeType: "box",
|
||||
name: "Dart",
|
||||
description: "Throw it at something!",
|
||||
script: SCRIPT_URL,
|
||||
modelURL: MODEL_URL,
|
||||
position: START_POSITION,
|
||||
rotation: START_ROTATION,
|
||||
lifetime: 300,
|
||||
gravity: {
|
||||
x: 0,
|
||||
y: -9.8,
|
||||
z: 0
|
||||
},
|
||||
dimensions: {
|
||||
x: 0.1,
|
||||
y: 0.1,
|
||||
z: 0.3
|
||||
},
|
||||
dynamic: true,
|
||||
owningAvatarID: MyAvatar.sessionUUID,
|
||||
userData: JSON.stringify({
|
||||
grabbableKey: {
|
||||
grabbable: true,
|
||||
invertSolidWhileHeld: true,
|
||||
ignoreIK: false
|
||||
}
|
||||
})
|
||||
};
|
||||
|
||||
var avatarUp = Quat.getUp(MyAvatar.orientation);
|
||||
var platformPosition = Vec3.sum(START_POSITION, Vec3.multiply(avatarUp, -0.05));
|
||||
var platform = {
|
||||
type: "Box",
|
||||
name: "Dart Platform",
|
||||
description: "Holds darts",
|
||||
position: platformPosition,
|
||||
rotation: START_ROTATION,
|
||||
lifetime: 60,
|
||||
dimensions: {
|
||||
x: 0.15 * 5,
|
||||
y: 0.01,
|
||||
z: 0.3
|
||||
},
|
||||
color: {
|
||||
red: 129,
|
||||
green: 92,
|
||||
blue: 11
|
||||
},
|
||||
owningAvatarID: MyAvatar.sessionUUID,
|
||||
userData: JSON.stringify({
|
||||
grabbableKey: {
|
||||
grabbable: true,
|
||||
invertSolidWhileHeld: true,
|
||||
ignoreIK: false
|
||||
}
|
||||
})
|
||||
};
|
||||
|
||||
|
||||
Entities.addEntity(platform);
|
||||
|
||||
var dartCount = 5;
|
||||
var avatarRight = Quat.getRight(MyAvatar.orientation);
|
||||
for (var i = 0; i < dartCount; i++) {
|
||||
var j = i - Math.floor(dartCount / 2);
|
||||
var position = Vec3.sum(START_POSITION, Vec3.multiply(avatarRight, 0.15 * j));
|
||||
dart.position = position;
|
||||
Entities.addEntity(dart);
|
||||
}
|
||||
|
||||
Script.stop();
|
81
unpublishedScripts/marketplace/dart/dart.js
Normal file
81
unpublishedScripts/marketplace/dart/dart.js
Normal file
|
@ -0,0 +1,81 @@
|
|||
"use strict";
|
||||
//
|
||||
// dart.js
|
||||
//
|
||||
// Created by MrRoboman on 17/05/13
|
||||
// Copyright 2017 High Fidelity, Inc.
|
||||
//
|
||||
// Simple throwing dart. Sticks to static objects.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
|
||||
(function() {
|
||||
var THROW_FACTOR = 3;
|
||||
var DART_SOUND_URL = Script.resolvePath('https://hifi-content.s3.amazonaws.com/wadewatts/dart.wav?v=' + Date.now());
|
||||
|
||||
var Dart = function() {};
|
||||
|
||||
Dart.prototype = {
|
||||
|
||||
preload: function(entityID) {
|
||||
this.entityID = entityID;
|
||||
this.actionID = null;
|
||||
this.soundHasPlayed = true;
|
||||
this.dartSound = SoundCache.getSound(DART_SOUND_URL);
|
||||
},
|
||||
|
||||
playDartSound: function(sound) {
|
||||
if (this.soundHasPlayed) {
|
||||
return;
|
||||
}
|
||||
this.soundHasPlayed = true;
|
||||
var position = Entities.getEntityProperties(this.entityID, 'position').position;
|
||||
var audioProperties = {
|
||||
volume: 0.15,
|
||||
position: position
|
||||
};
|
||||
Audio.playSound(this.dartSound, audioProperties);
|
||||
},
|
||||
|
||||
releaseGrab: function() {
|
||||
this.soundHasPlayed = false;
|
||||
var velocity = Entities.getEntityProperties(this.entityID, 'velocity').velocity;
|
||||
|
||||
var newVelocity = {};
|
||||
Object.keys(velocity).forEach(function(key) {
|
||||
newVelocity[key] = velocity[key] * THROW_FACTOR;
|
||||
});
|
||||
|
||||
Entities.editEntity(this.entityID, {
|
||||
velocity: newVelocity
|
||||
});
|
||||
|
||||
if (this.actionID) {
|
||||
Entities.deleteAction(this.entityID, this.actionID);
|
||||
}
|
||||
this.actionID = Entities.addAction("travel-oriented", this.entityID, {
|
||||
forward: { x: 0, y: 0, z: 1 },
|
||||
angularTimeScale: 0.1,
|
||||
tag: "throwing dart",
|
||||
ttl: 3600
|
||||
});
|
||||
},
|
||||
|
||||
collisionWithEntity: function(myID, otherID, collisionInfo) {
|
||||
this.playDartSound();
|
||||
|
||||
Entities.editEntity(myID, {
|
||||
velocity: {x: 0, y: 0, z: 0},
|
||||
angularVelocity: {x: 0, y: 0, z: 0}
|
||||
});
|
||||
|
||||
if (this.actionID) {
|
||||
Entities.deleteAction(myID, this.actionID);
|
||||
this.actionID = null;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
return new Dart();
|
||||
});
|
Loading…
Reference in a new issue