mirror of
https://github.com/overte-org/overte.git
synced 2025-04-20 12:43:54 +02:00
Merge branch 'master' into 20280
Conflicts: interface/src/Application.h
This commit is contained in:
commit
3c7cdc16ce
209 changed files with 7477 additions and 4935 deletions
2
.gitignore
vendored
2
.gitignore
vendored
|
@ -3,7 +3,7 @@ CMakeCache.txt
|
|||
CMakeFiles/
|
||||
CMakeScripts/
|
||||
cmake_install.cmake
|
||||
build/
|
||||
build*/
|
||||
Makefile
|
||||
*.user
|
||||
|
||||
|
|
9
BUILD.md
9
BUILD.md
|
@ -6,12 +6,13 @@
|
|||
* [OpenSSL](https://www.openssl.org/related/binaries.html) ~> 1.0.1g
|
||||
* IMPORTANT: OpenSSL 1.0.1g is critical to avoid a security vulnerability.
|
||||
* [Intel Threading Building Blocks](https://www.threadingbuildingblocks.org/) ~> 4.3
|
||||
* [Bullet Physics Engine](http://bulletphysics.org) ~> 2.82
|
||||
* [Bullet Physics Engine](https://code.google.com/p/bullet/downloads/list) ~> 2.82
|
||||
* [Gverb](https://github.com/highfidelity/gverb/archive/master.zip) (direct download to latest version)
|
||||
|
||||
### OS Specific Build Guides
|
||||
* [BUILD_WIN.md](BUILD_WIN.md) - additional instructions for Windows.
|
||||
* [BUILD_OSX.md](BUILD_OSX.md) - additional instructions for OS X.
|
||||
* [BUILD_LINUX.md](BUILD_LINUX.md) - additional instructions for Linux.
|
||||
* [BUILD_WIN.md](BUILD_WIN.md) - additional instructions for Windows.
|
||||
|
||||
###CMake
|
||||
Hifi uses CMake to generate build files and project files for your platform.
|
||||
|
@ -54,11 +55,11 @@ In the examples below the variable $NAME would be replaced by the name of the de
|
|||
|
||||
####QXmpp
|
||||
|
||||
You can find QXmpp [here](https://github.com/qxmpp-project/qxmpp). The inclusion of the QXmpp enables text chat in the Interface client.
|
||||
You can [find QXmpp here](https://github.com/qxmpp-project/qxmpp), 0.7.6 is the version you want. The inclusion of the QXmpp enables text chat in the Interface client.
|
||||
|
||||
OS X users who tap our [homebrew formulas repository](https://github.com/highfidelity/homebrew-formulas) can install QXmpp via homebrew - `brew install highfidelity/formulas/qxmpp`.
|
||||
|
||||
####Devices
|
||||
|
||||
You can support external input/output devices such as Leap Motion, Faceshift, PrioVR, MIDI, Razr Hydra and more by adding each individual SDK in the visible building path. Refer to the readme file available in each device folder in [interface/external/](interface/external) for the detailed explanation of the requirements to use the device.
|
||||
You can support external input/output devices such as Oculus Rift, Leap Motion, Faceshift, PrioVR, MIDI, Razr Hydra and more by adding each individual SDK in the visible building path. Refer to the readme file available in each device folder in [interface/external/](interface/external) for the detailed explanation of the requirements to use the device.
|
||||
|
||||
|
|
51
BUILD_WIN.md
51
BUILD_WIN.md
|
@ -1,15 +1,10 @@
|
|||
Please read the [general build guide](BUILD.md) for information on dependencies required for all platforms. Only Windows specific instructions are found in this file.
|
||||
|
||||
###Windows Dependencies
|
||||
###Windows Specific Dependencies
|
||||
* [GLEW](http://glew.sourceforge.net/) ~> 1.10.0
|
||||
* [freeglut MSVC](http://www.transmissionzero.co.uk/software/freeglut-devel/) ~> 2.8.1
|
||||
* [zLib](http://www.zlib.net/) ~> 1.2.8
|
||||
|
||||
###Visual Studio
|
||||
|
||||
Currently building on Windows has been tested using the following compilers:
|
||||
* Visual Studio 2013
|
||||
* Visual Studio 2013 Express
|
||||
* (remember that you need all other dependencies listed in [BUILD.md](BUILD.md))
|
||||
|
||||
####Visual Studio 2013
|
||||
|
||||
|
@ -30,23 +25,29 @@ You can use the online installer or the offline installer. If you use the offlin
|
|||
|
||||
NOTE: Qt does not support 64-bit builds on Windows 7, so you must use the 32-bit version of libraries for interface.exe to run. The 32-bit version of the static library is the one linked by our CMake find modules.
|
||||
|
||||
* Download the online installer [here](http://qt-project.org/downloads)
|
||||
* [Download the online installer](http://qt-project.org/downloads)
|
||||
* When it asks you to select components, ONLY select the following:
|
||||
* Qt > Qt 5.3.2 > **msvc2013 32-bit OpenGL**
|
||||
|
||||
* Download the offline installer [here](http://download.qt-project.org/official_releases/qt/5.3/5.3.2/qt-opensource-windows-x86-msvc2013_opengl-5.3.2.exe)
|
||||
* [Download the offline installer](http://download.qt-project.org/official_releases/qt/5.3/5.3.2/qt-opensource-windows-x86-msvc2013_opengl-5.3.2.exe)
|
||||
|
||||
Once Qt is installed, you need to manually configure the following:
|
||||
* Make sure the Qt runtime DLLs are loadable. You must do this before you attempt to build because some tools for the build depend on Qt. E.g., add to the PATH: `Qt\5.3.2\msvc2013_opengl\bin\`.
|
||||
* Go to Control Panel > System > Advanced System Settings > Environment Variables > New ...
|
||||
* Set the QT_CMAKE_PREFIX_PATH environment variable to your `Qt\5.3.2\msvc2013_opengl` directory.
|
||||
|
||||
###External Libraries
|
||||
|
||||
As it stands, Hifi/Interface is a 32-bit application, so all libraries should also be 32-bit.
|
||||
|
||||
CMake will need to know where the headers and libraries for required external dependencies are.
|
||||
|
||||
The recommended route for CMake to find the external dependencies is to place all of the dependencies in one folder and set one ENV variable - HIFI_LIB_DIR. That ENV variable should point to a directory with the following structure:
|
||||
|
||||
root_lib_dir
|
||||
-> bullet
|
||||
-> include
|
||||
-> lib
|
||||
-> freeglut
|
||||
-> bin
|
||||
-> include
|
||||
|
@ -76,7 +77,7 @@ As with the Qt libraries, you will need to make sure that directories containing
|
|||
|
||||
###OpenSSL
|
||||
|
||||
QT will use OpenSSL if it's available, but it doesn't install it, so you must install it separately.
|
||||
Qt will use OpenSSL if it's available, but it doesn't install it, so you must install it separately.
|
||||
|
||||
Your system may already have several versions of the OpenSSL DLL's (ssleay32.dll, libeay32.dll) lying around, but they may be the wrong version. If these DLL's are in the PATH then QT will try to use them, and if they're the wrong version then you will see the following errors in the console:
|
||||
|
||||
|
@ -90,9 +91,9 @@ Your system may already have several versions of the OpenSSL DLL's (ssleay32.dll
|
|||
|
||||
To prevent these problems, install OpenSSL yourself. Download the following binary packages [from this website](http://slproweb.com/products/Win32OpenSSL.html):
|
||||
* Visual C++ 2008 Redistributables
|
||||
* Win32 OpenSSL v1.0.1h
|
||||
* Win32 OpenSSL v1.0.1L
|
||||
|
||||
Install OpenSSL into the Windows system directory, to make sure that QT uses the version that you've just installed, and not some other version.
|
||||
Install OpenSSL into the Windows system directory, to make sure that Qt uses the version that you've just installed, and not some other version.
|
||||
|
||||
###Intel Threading Building Blocks (TBB)
|
||||
|
||||
|
@ -111,8 +112,10 @@ Add the following environment variables (remember to substitute your own directo
|
|||
|
||||
Add to the PATH: `%HIFI_LIB_DIR%\zlib`
|
||||
|
||||
Important! This should be added at the beginning of the path, not the end. That's because your
|
||||
system likely has many copies of zlib1.dll, and you want High Fidelity to use the correct version. If High Fidelity picks up the wrong zlib1.dll then it might be unable to use it, and that would cause it to fail to start, showing only the cryptic error "The application was unable to start correctly: 0xc0000022".
|
||||
(The PATH environment variable is where Windows looks for its DLL's and executables. There's a great tool for editing these variables with ease, [Rapid Environment Editor](http://www.rapidee.com/en/download))
|
||||
|
||||
Important! This should be added at the beginning of the path, not the end (your
|
||||
system likely has many copies of zlib1.dll, and you want High Fidelity to use the correct version). If High Fidelity picks up the wrong zlib1.dll then it might be unable to use it, and that would cause it to fail to start, showing only the cryptic error "The application was unable to start correctly: 0xc0000022".
|
||||
|
||||
###freeglut
|
||||
|
||||
|
@ -132,12 +135,26 @@ This package contains only headers, so there's nothing to add to the PATH.
|
|||
|
||||
Be careful with glm. For the folder other libraries would normally call 'include', the folder containing the headers, glm opts to use 'glm'. You will have a glm folder nested inside the top-level glm folder.
|
||||
|
||||
###Gverb
|
||||
|
||||
1. Go to https://github.com/highfidelity/gverb
|
||||
Or download the sources directly via this link:
|
||||
https://github.com/highfidelity/gverb/archive/master.zip
|
||||
|
||||
2. Extract the archive
|
||||
|
||||
3. Place the directories “include” and “src” in interface/external/gverb
|
||||
(Normally next to this readme)
|
||||
|
||||
4. Clear your build directory, run cmake, build and you should be all set.
|
||||
|
||||
|
||||
###Bullet
|
||||
|
||||
Bullet 2.82 source can be downloaded [here](https://code.google.com/p/bullet/downloads/detail?name=bullet-2.82-r2704.zip). Bullet does not come with prebuilt libraries, you need to make those yourself.
|
||||
Bullet 2.82 source can be [downloaded here](https://code.google.com/p/bullet/downloads/detail?name=bullet-2.82-r2704.zip). Bullet does not come with prebuilt libraries, you need to make those yourself.
|
||||
|
||||
* Download the zip file and extract into a temporary folder
|
||||
* Create a directory named cmakebuild. Bullet comes with a build\ directory by default, however, that directory is intended for use with premake, and considering premake doesn't support VS2013, I prefer to run the cmake build on its own directory.
|
||||
* Create a directory named cmakebuild. Bullet comes with a build\ directory by default, however, that directory is intended for use with premake, and considering premake doesn't support VS2013, we prefer to run the cmake build on its own directory.
|
||||
* Make the following modifications to Bullet's source:
|
||||
1. In file: Extras\HACD\hacdICHull.cpp --- in line: 17 --- insert: #include <algorithm>
|
||||
2. In file: src\MiniCL\cl_MiniCL_Defs.h --- comment lines 364 to 372
|
||||
|
@ -162,7 +179,7 @@ You now have Bullet libraries compiled, now you need to put them in the right pl
|
|||
_Note that the INSTALL target should handle the copying of files into an install directory automatically, however, without modifications to Cmake, the install target didn't work right for me, please update this instructions if you get that working right - Leo <leo@highfidelity.io>_
|
||||
|
||||
###Build High Fidelity using Visual Studio
|
||||
Follow the same build steps from the CMake section, but pass a different generator to CMake.
|
||||
Follow the same build steps from the CMake section of [BUILD.md](BUILD.md), but pass a different generator to CMake.
|
||||
|
||||
cmake .. -DZLIB_LIBRARY=%ZLIB_LIBRARY% -DZLIB_INCLUDE_DIR=%ZLIB_INCLUDE_DIR% -G "Visual Studio 12"
|
||||
|
||||
|
|
|
@ -61,7 +61,7 @@ Any target can be terminated with Ctrl-C (SIGINT) in the associated Terminal win
|
|||
|
||||
This assignment-client will grab one assignment from the domain-server. You can tell the assignment-client what type you want it to be with the `-t` option. You can also run an assignment-client that forks off *n* assignment-clients with the `-n` option.
|
||||
|
||||
./assignment-client -n 6
|
||||
./assignment-client -n 4
|
||||
|
||||
To test things out you'll want to run the Interface client.
|
||||
|
||||
|
|
|
@ -169,7 +169,9 @@ void Agent::run() {
|
|||
}
|
||||
|
||||
QNetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance();
|
||||
QNetworkReply *reply = networkAccessManager.get(QNetworkRequest(scriptURL));
|
||||
QNetworkRequest networkRequest = QNetworkRequest(scriptURL);
|
||||
networkRequest.setHeader(QNetworkRequest::UserAgentHeader, HIGH_FIDELITY_USER_AGENT);
|
||||
QNetworkReply* reply = networkAccessManager.get(networkRequest);
|
||||
|
||||
QNetworkDiskCache* cache = new QNetworkDiskCache();
|
||||
QString cachePath = QStandardPaths::writableLocation(QStandardPaths::DataLocation);
|
||||
|
|
|
@ -9,10 +9,11 @@
|
|||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#include <QtCore/QProcess>
|
||||
#include <QtCore/qsharedmemory.h>
|
||||
#include <QtCore/QThread>
|
||||
#include <QtCore/QTimer>
|
||||
#include <QProcess>
|
||||
#include <QSettings>
|
||||
#include <QSharedMemory>
|
||||
#include <QThread>
|
||||
#include <QTimer>
|
||||
|
||||
#include <AccountManager.h>
|
||||
#include <AddressManager.h>
|
||||
|
|
|
@ -13,21 +13,22 @@
|
|||
#include <openssl/rsa.h>
|
||||
#include <openssl/x509.h>
|
||||
|
||||
#include <QtCore/QDir>
|
||||
#include <QtCore/QJsonDocument>
|
||||
#include <QtCore/QJsonObject>
|
||||
#include <QtCore/QJsonArray>
|
||||
#include <QtCore/QProcess>
|
||||
#include <QtCore/qsharedmemory.h>
|
||||
#include <QtCore/QStandardPaths>
|
||||
#include <QtCore/QTimer>
|
||||
#include <QtCore/QUrlQuery>
|
||||
#include <QDir>
|
||||
#include <QJsonDocument>
|
||||
#include <QJsonObject>
|
||||
#include <QJsonArray>
|
||||
#include <QProcess>
|
||||
#include <QSharedMemory>
|
||||
#include <QStandardPaths>
|
||||
#include <QTimer>
|
||||
#include <QUrlQuery>
|
||||
|
||||
#include <AccountManager.h>
|
||||
#include <HifiConfigVariantMap.h>
|
||||
#include <HTTPConnection.h>
|
||||
#include <LogUtils.h>
|
||||
#include <PacketHeaders.h>
|
||||
#include <Settings.h>
|
||||
#include <SharedUtil.h>
|
||||
#include <ShutdownEventListener.h>
|
||||
#include <UUID.h>
|
||||
|
@ -1712,6 +1713,7 @@ bool DomainServer::handleHTTPSRequest(HTTPSConnection* connection, const QUrl &u
|
|||
.arg(authorizationCode, oauthRedirectURL().toString(), _oauthClientID, _oauthClientSecret);
|
||||
|
||||
QNetworkRequest tokenRequest(tokenRequestUrl);
|
||||
tokenRequest.setHeader(QNetworkRequest::UserAgentHeader, HIGH_FIDELITY_USER_AGENT);
|
||||
tokenRequest.setHeader(QNetworkRequest::ContentTypeHeader, "application/x-www-form-urlencoded");
|
||||
|
||||
QNetworkReply* tokenReply = NetworkAccessManager::getInstance().post(tokenRequest, tokenPostBody.toLocal8Bit());
|
||||
|
@ -1901,7 +1903,9 @@ QNetworkReply* DomainServer::profileRequestGivenTokenReply(QNetworkReply* tokenR
|
|||
profileURL.setPath("/api/v1/user/profile");
|
||||
profileURL.setQuery(QString("%1=%2").arg(OAUTH_JSON_ACCESS_TOKEN_KEY, accessToken));
|
||||
|
||||
return NetworkAccessManager::getInstance().get(QNetworkRequest(profileURL));
|
||||
QNetworkRequest profileRequest(profileURL);
|
||||
profileRequest.setHeader(QNetworkRequest::UserAgentHeader, HIGH_FIDELITY_USER_AGENT);
|
||||
return NetworkAccessManager::getInstance().get(profileRequest);
|
||||
}
|
||||
|
||||
const QString DS_SETTINGS_SESSIONS_GROUP = "web-sessions";
|
||||
|
@ -1920,10 +1924,8 @@ Headers DomainServer::setupCookieHeadersFromProfileReply(QNetworkReply* profileR
|
|||
_cookieSessionHash.insert(cookieUUID, sessionData);
|
||||
|
||||
// persist the cookie to settings file so we can get it back on DS relaunch
|
||||
QSettings localSettings;
|
||||
localSettings.beginGroup(DS_SETTINGS_SESSIONS_GROUP);
|
||||
QVariant sessionVariant = QVariant::fromValue(sessionData);
|
||||
localSettings.setValue(cookieUUID.toString(), QVariant::fromValue(sessionData));
|
||||
QStringList path = QStringList() << DS_SETTINGS_SESSIONS_GROUP << cookieUUID.toString();
|
||||
SettingHandles::SettingHandle<QVariant>(path).set(QVariant::fromValue(sessionData));
|
||||
|
||||
// setup expiry for cookie to 1 month from today
|
||||
QDateTime cookieExpiry = QDateTime::currentDateTimeUtc().addMonths(1);
|
||||
|
@ -1943,11 +1945,12 @@ Headers DomainServer::setupCookieHeadersFromProfileReply(QNetworkReply* profileR
|
|||
|
||||
void DomainServer::loadExistingSessionsFromSettings() {
|
||||
// read data for existing web sessions into memory so existing sessions can be leveraged
|
||||
QSettings domainServerSettings;
|
||||
Settings domainServerSettings;
|
||||
domainServerSettings.beginGroup(DS_SETTINGS_SESSIONS_GROUP);
|
||||
|
||||
foreach(const QString& uuidKey, domainServerSettings.childKeys()) {
|
||||
_cookieSessionHash.insert(QUuid(uuidKey), domainServerSettings.value(uuidKey).value<DomainServerWebSessionData>());
|
||||
_cookieSessionHash.insert(QUuid(uuidKey),
|
||||
domainServerSettings.value(uuidKey).value<DomainServerWebSessionData>());
|
||||
qDebug() << "Pulled web session from settings - cookie UUID is" << uuidKey;
|
||||
}
|
||||
}
|
||||
|
|
118
examples/blocks.js
Normal file
118
examples/blocks.js
Normal file
|
@ -0,0 +1,118 @@
|
|||
//
|
||||
// Blocks.js
|
||||
//
|
||||
// Created by Philip Rosedale on January 26, 2015
|
||||
// Copyright 2015 High Fidelity, Inc.
|
||||
//
|
||||
// Create a bunch of building blocks and drop them onto a playing surface in front of you.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
var FLOOR_SIZE = 7.5;
|
||||
var FLOOR_THICKNESS = 0.10;
|
||||
var EDGE_THICKESS = 0.25;
|
||||
var SCALE = 0.25;
|
||||
|
||||
var NUM_BLOCKS = 25;
|
||||
var DROP_HEIGHT = SCALE * 8.0;
|
||||
|
||||
var GRAVITY = -1.0;
|
||||
var LIFETIME = 6000;
|
||||
var DAMPING = 0.50;
|
||||
|
||||
var blockTypes = [];
|
||||
blockTypes.push({ x: 1, y: 1, z: 1, red: 255, green: 0, blue: 0 });
|
||||
blockTypes.push({ x: 1, y: 1, z: 2, red: 0, green: 255, blue: 0 });
|
||||
blockTypes.push({ x: 1, y: 2, z: 5, red: 0, green: 0, blue: 255 });
|
||||
blockTypes.push({ x: 1, y: 2, z: 2, red: 255, green: 255, blue: 0 });
|
||||
blockTypes.push({ x: 1, y: 1, z: 5, red: 0, green: 255, blue: 255 });
|
||||
|
||||
var center = Vec3.sum(MyAvatar.position, Vec3.multiply(FLOOR_SIZE * 2.0, Quat.getFront(Camera.getOrientation())));
|
||||
|
||||
var floor = Entities.addEntity(
|
||||
{ type: "Box",
|
||||
position: Vec3.subtract(center, { x: 0, y: SCALE / 2.0, z: 0 }),
|
||||
dimensions: { x: FLOOR_SIZE, y: FLOOR_THICKNESS, z: FLOOR_SIZE },
|
||||
color: { red: 128, green: 128, blue: 128 },
|
||||
gravity: { x: 0, y: 0, z: 0 },
|
||||
ignoreCollisions: false,
|
||||
locked: true,
|
||||
lifetime: LIFETIME });
|
||||
|
||||
var edge1 = Entities.addEntity(
|
||||
{ type: "Box",
|
||||
position: Vec3.sum(center, { x: FLOOR_SIZE / 2.0, y: FLOOR_THICKNESS / 2.0, z: 0 }),
|
||||
dimensions: { x: EDGE_THICKESS, y: EDGE_THICKESS, z: FLOOR_SIZE },
|
||||
color: { red: 128, green: 128, blue: 128 },
|
||||
gravity: { x: 0, y: 0, z: 0 },
|
||||
ignoreCollisions: false,
|
||||
visible: true,
|
||||
locked: true,
|
||||
lifetime: LIFETIME });
|
||||
|
||||
var edge2 = Entities.addEntity(
|
||||
{ type: "Box",
|
||||
position: Vec3.sum(center, { x: -FLOOR_SIZE / 2.0, y: FLOOR_THICKNESS / 2.0, z: 0 }),
|
||||
dimensions: { x: EDGE_THICKESS, y: EDGE_THICKESS, z: FLOOR_SIZE },
|
||||
color: { red: 128, green: 128, blue: 128 },
|
||||
gravity: { x: 0, y: 0, z: 0 },
|
||||
ignoreCollisions: false,
|
||||
visible: true,
|
||||
locked: true,
|
||||
lifetime: LIFETIME });
|
||||
|
||||
var edge3 = Entities.addEntity(
|
||||
{ type: "Box",
|
||||
position: Vec3.sum(center, { x: 0, y: FLOOR_THICKNESS / 2.0, z: -FLOOR_SIZE / 2.0 }),
|
||||
dimensions: { x: FLOOR_SIZE, y: EDGE_THICKESS, z: EDGE_THICKESS },
|
||||
color: { red: 128, green: 128, blue: 128 },
|
||||
gravity: { x: 0, y: 0, z: 0 },
|
||||
ignoreCollisions: false,
|
||||
visible: true,
|
||||
locked: true,
|
||||
lifetime: LIFETIME });
|
||||
|
||||
var edge4 = Entities.addEntity(
|
||||
{ type: "Box",
|
||||
position: Vec3.sum(center, { x: 0, y: FLOOR_THICKNESS / 2.0, z: FLOOR_SIZE / 2.0 }),
|
||||
dimensions: { x: FLOOR_SIZE, y: EDGE_THICKESS, z: EDGE_THICKESS },
|
||||
color: { red: 128, green: 128, blue: 128 },
|
||||
gravity: { x: 0, y: 0, z: 0 },
|
||||
ignoreCollisions: false,
|
||||
visible: true,
|
||||
locked: true,
|
||||
lifetime: LIFETIME });
|
||||
|
||||
blocks = [];
|
||||
|
||||
for (var i = 0; i < NUM_BLOCKS; i++) {
|
||||
var which = Math.floor(Math.random() * blockTypes.length);
|
||||
var type = blockTypes[which];
|
||||
blocks.push(Entities.addEntity(
|
||||
{ type: "Box",
|
||||
position: { x: center.x + (Math.random() - 0.5) * (FLOOR_SIZE * 0.75),
|
||||
y: center.y + DROP_HEIGHT,
|
||||
z: center.z + (Math.random() - 0.5) * (FLOOR_SIZE * 0.75) },
|
||||
dimensions: { x: type.x * SCALE, y: type.y * SCALE, z: type.z * SCALE },
|
||||
color: { red: type.red, green: type.green, blue: type.blue },
|
||||
gravity: { x: 0, y: GRAVITY, z: 0 },
|
||||
ignoreCollisions: false,
|
||||
damping: DAMPING,
|
||||
lifetime: LIFETIME,
|
||||
collisionsWillMove: true }));
|
||||
}
|
||||
|
||||
function scriptEnding() {
|
||||
Entities.deleteEntity(edge1);
|
||||
Entities.deleteEntity(edge2);
|
||||
Entities.deleteEntity(edge3);
|
||||
Entities.deleteEntity(edge4);
|
||||
Entities.deleteEntity(floor);
|
||||
|
||||
for (var i = 0; i < NUM_BLOCKS; i++) {
|
||||
Entities.deleteEntity(blocks[i]);
|
||||
}
|
||||
}
|
||||
|
||||
Script.scriptEnding.connect(scriptEnding);
|
|
@ -304,7 +304,6 @@ function makePlatform(gravity, scale, size) {
|
|||
}
|
||||
|
||||
function entityCollisionWithEntity(entity1, entity2, collision) {
|
||||
|
||||
if (((entity1.id == bulletID.id) || (entity1.id == targetID.id)) &&
|
||||
((entity2.id == bulletID.id) || (entity2.id == targetID.id))) {
|
||||
score++;
|
||||
|
@ -486,7 +485,8 @@ function mousePressEvent(event) {
|
|||
if (clickedOverlay == offButton) {
|
||||
Script.stop();
|
||||
} else if (clickedOverlay == platformButton) {
|
||||
makePlatform(-9.8, 1.0, 5);
|
||||
var platformSize = 3;
|
||||
makePlatform(-9.8, 1.0, platformSize);
|
||||
} else if (clickedOverlay == gridButton) {
|
||||
makeGrid("Box", 1.0, 3);
|
||||
}
|
||||
|
@ -501,6 +501,7 @@ function scriptEnding() {
|
|||
Overlays.deleteOverlay(pointer[1]);
|
||||
Overlays.deleteOverlay(text);
|
||||
MyAvatar.detachOne(gunModel);
|
||||
MyAvatar.detachOne(gunModel);
|
||||
clearPose();
|
||||
}
|
||||
|
||||
|
|
|
@ -19,8 +19,8 @@ var entityPropertyDialogBox = EntityPropertyDialogBox;
|
|||
|
||||
var MIN_ANGULAR_SIZE = 2;
|
||||
var MAX_ANGULAR_SIZE = 45;
|
||||
var allowLargeModels = false;
|
||||
var allowSmallModels = false;
|
||||
var allowLargeModels = true;
|
||||
var allowSmallModels = true;
|
||||
var wantEntityGlow = false;
|
||||
|
||||
var LEFT = 0;
|
||||
|
@ -28,15 +28,16 @@ var RIGHT = 1;
|
|||
|
||||
var jointList = MyAvatar.getJointNames();
|
||||
|
||||
var STICKS = 0;
|
||||
var MAPPED = 1;
|
||||
var mode = STICKS;
|
||||
var LASER_WIDTH = 3;
|
||||
var LASER_COLOR = { red: 50, green: 150, blue: 200 };
|
||||
var DROP_COLOR = { red: 200, green: 200, blue: 200 };
|
||||
var DROP_WIDTH = 4;
|
||||
var DROP_DISTANCE = 5.0;
|
||||
|
||||
var LASER_WIDTH = 4;
|
||||
var LASER_COLOR = [{ red: 200, green: 150, blue: 50 }, // STICKS
|
||||
{ red: 50, green: 150, blue: 200 }]; // MAPPED
|
||||
var LASER_LENGTH_FACTOR = 500;
|
||||
|
||||
var velocity = { x: 0, y: 0, z: 0 };
|
||||
|
||||
var lastAccurateIntersection = null;
|
||||
var accurateIntersections = 0;
|
||||
var totalIntersections = 0;
|
||||
|
@ -107,6 +108,7 @@ function controller(wichSide) {
|
|||
|
||||
this.positionAtGrab;
|
||||
this.rotationAtGrab;
|
||||
this.gravityAtGrab;
|
||||
this.modelPositionAtGrab;
|
||||
this.modelRotationAtGrab;
|
||||
this.jointsIntersectingFromStart = [];
|
||||
|
@ -114,13 +116,21 @@ function controller(wichSide) {
|
|||
this.laser = Overlays.addOverlay("line3d", {
|
||||
start: { x: 0, y: 0, z: 0 },
|
||||
end: { x: 0, y: 0, z: 0 },
|
||||
color: LASER_COLOR[mode],
|
||||
color: LASER_COLOR,
|
||||
alpha: 1,
|
||||
visible: false,
|
||||
lineWidth: LASER_WIDTH,
|
||||
anchor: "MyAvatar"
|
||||
});
|
||||
|
||||
this.dropLine = Overlays.addOverlay("line3d", {
|
||||
start: { x: 0, y: 0, z: 0 },
|
||||
end: { x: 0, y: 0, z: 0 },
|
||||
color: DROP_COLOR,
|
||||
alpha: 1,
|
||||
visible: false,
|
||||
lineWidth: DROP_WIDTH });
|
||||
|
||||
this.guideScale = 0.02;
|
||||
this.ball = Overlays.addOverlay("sphere", {
|
||||
position: { x: 0, y: 0, z: 0 },
|
||||
|
@ -158,6 +168,7 @@ function controller(wichSide) {
|
|||
this.entityID = entityID;
|
||||
this.modelURL = properties.modelURL;
|
||||
|
||||
|
||||
this.oldModelPosition = properties.position;
|
||||
this.oldModelRotation = properties.rotation;
|
||||
this.oldModelHalfDiagonal = Vec3.length(properties.dimensions) / 2.0;
|
||||
|
@ -166,6 +177,10 @@ function controller(wichSide) {
|
|||
this.rotationAtGrab = this.rotation;
|
||||
this.modelPositionAtGrab = properties.position;
|
||||
this.modelRotationAtGrab = properties.rotation;
|
||||
this.gravityAtGrab = properties.gravity;
|
||||
Entities.editEntity(entityID, { gravity: { x: 0, y: 0, z: 0 }, velocity: { x: 0, y: 0, z: 0 } });
|
||||
|
||||
|
||||
this.jointsIntersectingFromStart = [];
|
||||
for (var i = 0; i < jointList.length; i++) {
|
||||
var distance = Vec3.distance(MyAvatar.getJointPosition(jointList[i]), this.oldModelPosition);
|
||||
|
@ -174,10 +189,14 @@ function controller(wichSide) {
|
|||
}
|
||||
}
|
||||
this.showLaser(false);
|
||||
Overlays.editOverlay(this.dropLine, { visible: true });
|
||||
}
|
||||
|
||||
this.release = function () {
|
||||
if (this.grabbing) {
|
||||
|
||||
Entities.editEntity(this.entityID, { gravity: this.gravityAtGrab });
|
||||
|
||||
jointList = MyAvatar.getJointNames();
|
||||
|
||||
var closestJointIndex = -1;
|
||||
|
@ -216,6 +235,8 @@ function controller(wichSide) {
|
|||
Entities.deleteEntity(this.entityID);
|
||||
}
|
||||
}
|
||||
|
||||
Overlays.editOverlay(this.dropLine, { visible: false });
|
||||
}
|
||||
|
||||
this.grabbing = false;
|
||||
|
@ -288,7 +309,6 @@ function controller(wichSide) {
|
|||
end: endPosition
|
||||
});
|
||||
|
||||
|
||||
Overlays.editOverlay(this.ball, {
|
||||
position: endPosition
|
||||
});
|
||||
|
@ -300,7 +320,7 @@ function controller(wichSide) {
|
|||
start: Vec3.sum(endPosition, Vec3.multiply(this.up, 2 * this.guideScale)),
|
||||
end: Vec3.sum(endPosition, Vec3.multiply(this.up, -2 * this.guideScale))
|
||||
});
|
||||
this.showLaser(!this.grabbing || mode == STICKS);
|
||||
this.showLaser(!this.grabbing);
|
||||
|
||||
if (this.glowedIntersectingModel.isKnownID) {
|
||||
Entities.editEntity(this.glowedIntersectingModel, { glowLevel: 0.0 });
|
||||
|
@ -332,7 +352,7 @@ function controller(wichSide) {
|
|||
Overlays.editOverlay(this.leftRight, { visible: show });
|
||||
Overlays.editOverlay(this.topDown, { visible: show });
|
||||
}
|
||||
this.moveEntity = function () {
|
||||
this.moveEntity = function (deltaTime) {
|
||||
if (this.grabbing) {
|
||||
if (!this.entityID.isKnownID) {
|
||||
print("Unknown grabbed ID " + this.entityID.id + ", isKnown: " + this.entityID.isKnownID);
|
||||
|
@ -344,55 +364,34 @@ function controller(wichSide) {
|
|||
var newPosition;
|
||||
var newRotation;
|
||||
|
||||
switch (mode) {
|
||||
case STICKS:
|
||||
newPosition = Vec3.sum(this.palmPosition,
|
||||
Vec3.multiply(this.front, this.x));
|
||||
newPosition = Vec3.sum(newPosition,
|
||||
Vec3.multiply(this.up, this.y));
|
||||
newPosition = Vec3.sum(newPosition,
|
||||
Vec3.multiply(this.right, this.z));
|
||||
|
||||
|
||||
newRotation = Quat.multiply(this.rotation,
|
||||
Quat.inverse(this.oldRotation));
|
||||
newRotation = Quat.multiply(newRotation,
|
||||
this.oldModelRotation);
|
||||
break;
|
||||
case MAPPED:
|
||||
var forward = Vec3.multiplyQbyV(MyAvatar.orientation, { x: 0, y: 0, z: -1 });
|
||||
var d = Vec3.dot(forward, MyAvatar.position);
|
||||
|
||||
var factor1 = Vec3.dot(forward, this.positionAtGrab) - d;
|
||||
var factor2 = Vec3.dot(forward, this.modelPositionAtGrab) - d;
|
||||
var vector = Vec3.subtract(this.palmPosition, this.positionAtGrab);
|
||||
|
||||
if (factor2 < 0) {
|
||||
factor2 = 0;
|
||||
}
|
||||
if (factor1 <= 0) {
|
||||
factor1 = 1;
|
||||
factor2 = 1;
|
||||
}
|
||||
|
||||
newPosition = Vec3.sum(this.modelPositionAtGrab,
|
||||
Vec3.multiply(vector,
|
||||
factor2 / factor1));
|
||||
|
||||
newRotation = Quat.multiply(this.rotation,
|
||||
Quat.inverse(this.rotationAtGrab));
|
||||
newRotation = Quat.multiply(newRotation, newRotation);
|
||||
newRotation = Quat.multiply(newRotation,
|
||||
this.modelRotationAtGrab);
|
||||
break;
|
||||
var CONSTANT_SCALING_FACTOR = 5.0;
|
||||
var MINIMUM_SCALING_DISTANCE = 2.0;
|
||||
var distanceToModel = Vec3.length(Vec3.subtract(this.oldModelPosition, this.palmPosition));
|
||||
if (distanceToModel < MINIMUM_SCALING_DISTANCE) {
|
||||
distanceToModel = MINIMUM_SCALING_DISTANCE;
|
||||
}
|
||||
|
||||
var deltaPalm = Vec3.multiply(distanceToModel * CONSTANT_SCALING_FACTOR, Vec3.subtract(this.palmPosition, this.oldPalmPosition));
|
||||
newPosition = Vec3.sum(this.oldModelPosition, deltaPalm);
|
||||
|
||||
newRotation = Quat.multiply(this.rotation,
|
||||
Quat.inverse(this.rotationAtGrab));
|
||||
newRotation = Quat.multiply(newRotation, newRotation);
|
||||
newRotation = Quat.multiply(newRotation,
|
||||
this.modelRotationAtGrab);
|
||||
|
||||
velocity = Vec3.multiply(1.0 / deltaTime, Vec3.subtract(newPosition, this.oldModelPosition));
|
||||
|
||||
Entities.editEntity(this.entityID, {
|
||||
position: newPosition,
|
||||
rotation: newRotation
|
||||
rotation: newRotation,
|
||||
velocity: velocity
|
||||
});
|
||||
this.oldModelRotation = newRotation;
|
||||
this.oldModelPosition = newPosition;
|
||||
|
||||
Overlays.editOverlay(this.dropLine, { start: newPosition, end: Vec3.sum(newPosition, { x: 0, y: -DROP_DISTANCE, z: 0 }) });
|
||||
|
||||
var indicesToRemove = [];
|
||||
for (var i = 0; i < this.jointsIntersectingFromStart.length; ++i) {
|
||||
var distance = Vec3.distance(MyAvatar.getJointPosition(this.jointsIntersectingFromStart[i]), this.oldModelPosition);
|
||||
|
@ -428,15 +427,6 @@ function controller(wichSide) {
|
|||
this.triggerValue = Controller.getTriggerValue(this.trigger);
|
||||
|
||||
var bumperValue = Controller.isButtonPressed(this.bumper);
|
||||
if (bumperValue && !this.bumperValue) {
|
||||
if (mode === STICKS) {
|
||||
mode = MAPPED;
|
||||
} else if (mode === MAPPED) {
|
||||
mode = STICKS;
|
||||
}
|
||||
Overlays.editOverlay(leftController.laser, { color: LASER_COLOR[mode] });
|
||||
Overlays.editOverlay(rightController.laser, { color: LASER_COLOR[mode] });
|
||||
}
|
||||
this.bumperValue = bumperValue;
|
||||
|
||||
|
||||
|
@ -548,61 +538,37 @@ function controller(wichSide) {
|
|||
var leftController = new controller(LEFT);
|
||||
var rightController = new controller(RIGHT);
|
||||
|
||||
function moveEntities() {
|
||||
function moveEntities(deltaTime) {
|
||||
if (leftController.grabbing && rightController.grabbing && rightController.entityID.id == leftController.entityID.id) {
|
||||
var newPosition = leftController.oldModelPosition;
|
||||
var rotation = leftController.oldModelRotation;
|
||||
var ratio = 1;
|
||||
|
||||
var u = Vec3.normalize(Vec3.subtract(rightController.oldPalmPosition, leftController.oldPalmPosition));
|
||||
var v = Vec3.normalize(Vec3.subtract(rightController.palmPosition, leftController.palmPosition));
|
||||
|
||||
switch (mode) {
|
||||
case STICKS:
|
||||
var oldLeftPoint = Vec3.sum(leftController.oldPalmPosition, Vec3.multiply(leftController.oldFront, leftController.x));
|
||||
var oldRightPoint = Vec3.sum(rightController.oldPalmPosition, Vec3.multiply(rightController.oldFront, rightController.x));
|
||||
|
||||
var oldMiddle = Vec3.multiply(Vec3.sum(oldLeftPoint, oldRightPoint), 0.5);
|
||||
var oldLength = Vec3.length(Vec3.subtract(oldLeftPoint, oldRightPoint));
|
||||
|
||||
|
||||
var leftPoint = Vec3.sum(leftController.palmPosition, Vec3.multiply(leftController.front, leftController.x));
|
||||
var rightPoint = Vec3.sum(rightController.palmPosition, Vec3.multiply(rightController.front, rightController.x));
|
||||
|
||||
var middle = Vec3.multiply(Vec3.sum(leftPoint, rightPoint), 0.5);
|
||||
var length = Vec3.length(Vec3.subtract(leftPoint, rightPoint));
|
||||
|
||||
|
||||
ratio = length / oldLength;
|
||||
newPosition = Vec3.sum(middle,
|
||||
Vec3.multiply(Vec3.subtract(leftController.oldModelPosition, oldMiddle), ratio));
|
||||
break;
|
||||
case MAPPED:
|
||||
var u = Vec3.normalize(Vec3.subtract(rightController.oldPalmPosition, leftController.oldPalmPosition));
|
||||
var v = Vec3.normalize(Vec3.subtract(rightController.palmPosition, leftController.palmPosition));
|
||||
|
||||
var cos_theta = Vec3.dot(u, v);
|
||||
if (cos_theta > 1) {
|
||||
cos_theta = 1;
|
||||
}
|
||||
var angle = Math.acos(cos_theta) / Math.PI * 180;
|
||||
if (angle < 0.1) {
|
||||
return;
|
||||
|
||||
}
|
||||
var w = Vec3.normalize(Vec3.cross(u, v));
|
||||
|
||||
rotation = Quat.multiply(Quat.angleAxis(angle, w), leftController.oldModelRotation);
|
||||
|
||||
|
||||
leftController.positionAtGrab = leftController.palmPosition;
|
||||
leftController.rotationAtGrab = leftController.rotation;
|
||||
leftController.modelPositionAtGrab = leftController.oldModelPosition;
|
||||
leftController.modelRotationAtGrab = rotation;
|
||||
rightController.positionAtGrab = rightController.palmPosition;
|
||||
rightController.rotationAtGrab = rightController.rotation;
|
||||
rightController.modelPositionAtGrab = rightController.oldModelPosition;
|
||||
rightController.modelRotationAtGrab = rotation;
|
||||
break;
|
||||
var cos_theta = Vec3.dot(u, v);
|
||||
if (cos_theta > 1) {
|
||||
cos_theta = 1;
|
||||
}
|
||||
var angle = Math.acos(cos_theta) / Math.PI * 180;
|
||||
if (angle < 0.1) {
|
||||
return;
|
||||
}
|
||||
var w = Vec3.normalize(Vec3.cross(u, v));
|
||||
|
||||
rotation = Quat.multiply(Quat.angleAxis(angle, w), leftController.oldModelRotation);
|
||||
|
||||
|
||||
leftController.positionAtGrab = leftController.palmPosition;
|
||||
leftController.rotationAtGrab = leftController.rotation;
|
||||
leftController.modelPositionAtGrab = leftController.oldModelPosition;
|
||||
leftController.modelRotationAtGrab = rotation;
|
||||
rightController.positionAtGrab = rightController.palmPosition;
|
||||
rightController.rotationAtGrab = rightController.rotation;
|
||||
rightController.modelPositionAtGrab = rightController.oldModelPosition;
|
||||
rightController.modelRotationAtGrab = rotation;
|
||||
|
||||
Entities.editEntity(leftController.entityID, {
|
||||
position: newPosition,
|
||||
rotation: rotation,
|
||||
|
@ -612,7 +578,6 @@ function moveEntities() {
|
|||
y: leftController.oldModelHalfDiagonal * ratio,
|
||||
z: leftController.oldModelHalfDiagonal * ratio }
|
||||
|
||||
|
||||
});
|
||||
leftController.oldModelPosition = newPosition;
|
||||
leftController.oldModelRotation = rotation;
|
||||
|
@ -623,8 +588,8 @@ function moveEntities() {
|
|||
rightController.oldModelHalfDiagonal *= ratio;
|
||||
return;
|
||||
}
|
||||
leftController.moveEntity();
|
||||
rightController.moveEntity();
|
||||
leftController.moveEntity(deltaTime);
|
||||
rightController.moveEntity(deltaTime);
|
||||
}
|
||||
|
||||
var hydraConnected = false;
|
||||
|
@ -642,7 +607,7 @@ function checkController(deltaTime) {
|
|||
|
||||
leftController.update();
|
||||
rightController.update();
|
||||
moveEntities();
|
||||
moveEntities(deltaTime);
|
||||
} else {
|
||||
if (hydraConnected) {
|
||||
hydraConnected = false;
|
||||
|
|
|
@ -10,29 +10,42 @@
|
|||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
HIFI_PUBLIC_BUCKET = "http://s3.amazonaws.com/hifi-public/";
|
||||
|
||||
hitSound = SoundCache.getSound(HIFI_PUBLIC_BUCKET + "sounds/Collisions-ballhitsandcatches/billiards/collision1.wav");
|
||||
var rightHandAnimation = HIFI_PUBLIC_BUCKET + "animations/RightHandAnimPhilip.fbx";
|
||||
var leftHandAnimation = HIFI_PUBLIC_BUCKET + "animations/LeftHandAnimPhilip.fbx";
|
||||
|
||||
var BALL_SIZE = 0.08;
|
||||
var PADDLE_SIZE = 0.20;
|
||||
var PADDLE_THICKNESS = 0.06;
|
||||
var PADDLE_COLOR = { red: 184, green: 134, blue: 11 };
|
||||
var BALL_COLOR = { red: 255, green: 0, blue: 0 };
|
||||
var LINE_COLOR = { red: 255, green: 255, blue: 0 };
|
||||
var PADDLE_OFFSET = { x: 0.05, y: 0.0, z: 0.0 };
|
||||
var PADDLE_BOX_OFFSET = { x: 0.05, y: 0.0, z: 0.0 };
|
||||
|
||||
var HOLD_POSITION_LEFT_OFFSET = { x: -0.15, y: 0.05, z: -0.05 };
|
||||
var HOLD_POSITION_RIGHT_OFFSET = { x: -0.15, y: 0.05, z: 0.05 };
|
||||
var PADDLE_ORIENTATION = Quat.fromPitchYawRollDegrees(0,0,0);
|
||||
var GRAVITY = 0.0;
|
||||
var SPRING_FORCE = 15.0;
|
||||
var lastSoundTime = 0;
|
||||
var gameOn = false;
|
||||
var leftHanded = false;
|
||||
var leftHanded = true;
|
||||
var controllerID;
|
||||
|
||||
if (leftHanded) {
|
||||
controllerID = 1;
|
||||
} else {
|
||||
controllerID = 3;
|
||||
|
||||
function setControllerID() {
|
||||
if (leftHanded) {
|
||||
controllerID = 1;
|
||||
} else {
|
||||
controllerID = 3;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
HIFI_PUBLIC_BUCKET = "http://s3.amazonaws.com/hifi-public/";
|
||||
hitSound = SoundCache.getSound(HIFI_PUBLIC_BUCKET + "sounds/Collisions-ballhitsandcatches/billiards/collision1.wav");
|
||||
setControllerID();
|
||||
Menu.addMenu("PaddleBall");
|
||||
Menu.addMenuItem({ menuName: "PaddleBall", menuItemName: "Left-Handed", isCheckable: true, isChecked: true });
|
||||
|
||||
var screenSize = Controller.getViewportDimensions();
|
||||
var offButton = Overlays.addOverlay("image", {
|
||||
|
@ -73,7 +86,7 @@ function createEntities() {
|
|||
modelURL = "http://public.highfidelity.io/models/attachments/pong_paddle.fbx";
|
||||
paddleModel = Entities.addEntity(
|
||||
{ type: "Model",
|
||||
position: Vec3.sum(Controller.getSpatialControlPosition(controllerID), PADDLE_OFFSET),
|
||||
position: Vec3.sum(Controller.getSpatialControlPosition(controllerID), PADDLE_BOX_OFFSET),
|
||||
dimensions: { x: PADDLE_SIZE * 1.5, y: PADDLE_THICKNESS, z: PADDLE_SIZE * 1.25 },
|
||||
color: PADDLE_COLOR,
|
||||
gravity: { x: 0, y: 0, z: 0 },
|
||||
|
@ -90,6 +103,10 @@ function createEntities() {
|
|||
alpha: 1,
|
||||
visible: true,
|
||||
lineWidth: 2 });
|
||||
|
||||
MyAvatar.stopAnimation(leftHandAnimation);
|
||||
MyAvatar.stopAnimation(rightHandAnimation);
|
||||
MyAvatar.startAnimation(leftHanded ? leftHandAnimation: rightHandAnimation, 15.0, 1.0, false, true, 0.0, 6);
|
||||
}
|
||||
|
||||
function deleteEntities() {
|
||||
|
@ -97,6 +114,7 @@ function deleteEntities() {
|
|||
Entities.deleteEntity(paddle);
|
||||
Entities.deleteEntity(paddleModel);
|
||||
Overlays.deleteOverlay(line);
|
||||
MyAvatar.stopAnimation(leftHanded ? leftHandAnimation: rightHandAnimation);
|
||||
}
|
||||
|
||||
function update(deltaTime) {
|
||||
|
@ -120,18 +138,23 @@ function update(deltaTime) {
|
|||
if (!ball.isKnownID) {
|
||||
ball = Entities.identifyEntity(ball);
|
||||
} else {
|
||||
var paddleOrientation = leftHanded ? PADDLE_ORIENTATION : Quat.multiply(PADDLE_ORIENTATION, Quat.fromPitchYawRollDegrees(0, 180, 0));
|
||||
var paddleWorldOrientation = Quat.multiply(Quat.multiply(MyAvatar.orientation, Controller.getSpatialControlRawRotation(controllerID)), paddleOrientation);
|
||||
var holdPosition = Vec3.sum(leftHanded ? MyAvatar.getLeftPalmPosition() : MyAvatar.getRightPalmPosition(),
|
||||
Vec3.multiplyQbyV(paddleWorldOrientation, leftHanded ? HOLD_POSITION_LEFT_OFFSET : HOLD_POSITION_RIGHT_OFFSET ));
|
||||
|
||||
var props = Entities.getEntityProperties(ball);
|
||||
var spring = Vec3.subtract(palmPosition, props.position);
|
||||
var paddleWorldOrientation = Quat.multiply(MyAvatar.orientation, Controller.getSpatialControlRawRotation(controllerID));
|
||||
var spring = Vec3.subtract(holdPosition, props.position);
|
||||
var springLength = Vec3.length(spring);
|
||||
|
||||
spring = Vec3.normalize(spring);
|
||||
var ballVelocity = Vec3.sum(props.velocity, Vec3.multiply(springLength * SPRING_FORCE * deltaTime, spring));
|
||||
Entities.editEntity(ball, { velocity: ballVelocity });
|
||||
Overlays.editOverlay(line, { start: props.position, end: palmPosition });
|
||||
Entities.editEntity(paddle, { position: palmPosition,
|
||||
Overlays.editOverlay(line, { start: props.position, end: holdPosition });
|
||||
Entities.editEntity(paddle, { position: holdPosition,
|
||||
velocity: Controller.getSpatialControlVelocity(controllerID),
|
||||
rotation: paddleWorldOrientation });
|
||||
Entities.editEntity(paddleModel, { position: Vec3.sum(palmPosition, Vec3.multiplyQbyV(paddleWorldOrientation, PADDLE_OFFSET)),
|
||||
Entities.editEntity(paddleModel, { position: Vec3.sum(holdPosition, Vec3.multiplyQbyV(paddleWorldOrientation, PADDLE_BOX_OFFSET)),
|
||||
velocity: Controller.getSpatialControlVelocity(controllerID),
|
||||
rotation: paddleWorldOrientation });
|
||||
}
|
||||
|
@ -159,14 +182,30 @@ function mousePressEvent(event) {
|
|||
}
|
||||
}
|
||||
|
||||
function menuItemEvent(menuItem) {
|
||||
oldHanded = leftHanded;
|
||||
if (menuItem == "Left-Handed") {
|
||||
leftHanded = Menu.isOptionChecked("Left-Handed");
|
||||
}
|
||||
if ((leftHanded != oldHanded) && gameOn) {
|
||||
setControllerID();
|
||||
deleteEntities();
|
||||
createEntities();
|
||||
}
|
||||
}
|
||||
|
||||
function scriptEnding() {
|
||||
if (gameOn) {
|
||||
deleteEntities();
|
||||
}
|
||||
Overlays.deleteOverlay(offButton);
|
||||
MyAvatar.stopAnimation(leftHandAnimation);
|
||||
MyAvatar.stopAnimation(rightHandAnimation);
|
||||
Menu.removeMenu("PaddleBall");
|
||||
}
|
||||
|
||||
Entities.entityCollisionWithEntity.connect(entityCollisionWithEntity);
|
||||
Menu.menuItemEvent.connect(menuItemEvent);
|
||||
Controller.mousePressEvent.connect(mousePressEvent);
|
||||
Script.scriptEnding.connect(scriptEnding);
|
||||
Script.update.connect(update);
|
||||
|
|
|
@ -12,34 +12,38 @@
|
|||
//
|
||||
|
||||
HIFI_PUBLIC_BUCKET = "http://s3.amazonaws.com/hifi-public/";
|
||||
Script.include("libraries/stringHelpers.js");
|
||||
Script.include("libraries/dataviewHelpers.js");
|
||||
Script.include("libraries/httpMultiPart.js");
|
||||
Script.include("libraries/modelUploader.js");
|
||||
Script.include("libraries/toolBars.js");
|
||||
Script.include("libraries/progressDialog.js");
|
||||
|
||||
Script.include("libraries/entitySelectionTool.js");
|
||||
Script.include([
|
||||
"libraries/stringHelpers.js",
|
||||
"libraries/dataviewHelpers.js",
|
||||
"libraries/httpMultiPart.js",
|
||||
"libraries/modelUploader.js",
|
||||
"libraries/toolBars.js",
|
||||
"libraries/progressDialog.js",
|
||||
|
||||
"libraries/entitySelectionTool.js",
|
||||
"libraries/ModelImporter.js",
|
||||
|
||||
"libraries/ExportMenu.js",
|
||||
"libraries/ToolTip.js",
|
||||
|
||||
"libraries/entityPropertyDialogBox.js",
|
||||
"libraries/entityCameraTool.js",
|
||||
"libraries/gridTool.js",
|
||||
"libraries/entityList.js",
|
||||
]);
|
||||
|
||||
var selectionDisplay = SelectionDisplay;
|
||||
var selectionManager = SelectionManager;
|
||||
|
||||
Script.include("libraries/ModelImporter.js");
|
||||
var modelImporter = new ModelImporter();
|
||||
|
||||
Script.include("libraries/ExportMenu.js");
|
||||
Script.include("libraries/ToolTip.js");
|
||||
|
||||
Script.include("libraries/entityPropertyDialogBox.js");
|
||||
var entityPropertyDialogBox = EntityPropertyDialogBox;
|
||||
|
||||
Script.include("libraries/entityCameraTool.js");
|
||||
var cameraManager = new CameraManager();
|
||||
|
||||
Script.include("libraries/gridTool.js");
|
||||
var grid = Grid();
|
||||
gridTool = GridTool({ horizontalGrid: grid });
|
||||
gridTool.setVisible(false);
|
||||
|
||||
Script.include("libraries/entityList.js");
|
||||
var entityListTool = EntityListTool();
|
||||
|
||||
var hasShownPropertiesTool = false;
|
||||
|
@ -52,10 +56,17 @@ selectionManager.addEventListener(function() {
|
|||
// Open properties and model list, but force selection of model list tab
|
||||
propertiesTool.setVisible(false);
|
||||
entityListTool.setVisible(false);
|
||||
gridTool.setVisible(false);
|
||||
propertiesTool.setVisible(true);
|
||||
entityListTool.setVisible(true);
|
||||
gridTool.setVisible(true);
|
||||
hasShownPropertiesTool = true;
|
||||
}
|
||||
if (!selectionManager.hasSelection()) {
|
||||
toolBar.setActive(false);
|
||||
} else {
|
||||
toolBar.setActive(true);
|
||||
}
|
||||
});
|
||||
|
||||
var windowDimensions = Controller.getViewportDimensions();
|
||||
|
@ -123,11 +134,13 @@ var toolBar = (function () {
|
|||
function initialize() {
|
||||
toolBar = new ToolBar(0, 0, ToolBar.VERTICAL);
|
||||
|
||||
// Hide active button for now - this may come back, so not deleting yet.
|
||||
activeButton = toolBar.addTool({
|
||||
imageURL: toolIconUrl + "models-tool.svg",
|
||||
subImage: { x: 0, y: Tool.IMAGE_WIDTH, width: Tool.IMAGE_WIDTH, height: Tool.IMAGE_HEIGHT },
|
||||
width: toolWidth,
|
||||
height: toolHeight,
|
||||
// subImage: { x: 0, y: Tool.IMAGE_WIDTH, width: Tool.IMAGE_WIDTH, height: Tool.IMAGE_HEIGHT },
|
||||
subImage: { x: 0, y: Tool.IMAGE_WIDTH, width: 0, height: 0 },
|
||||
width: 0,//toolWidth,
|
||||
height: 0,//toolHeight,
|
||||
alpha: 0.9,
|
||||
visible: true
|
||||
}, true, false);
|
||||
|
@ -239,7 +252,6 @@ var toolBar = (function () {
|
|||
} else {
|
||||
hasShownPropertiesTool = false;
|
||||
cameraManager.enable();
|
||||
gridTool.setVisible(true);
|
||||
grid.setEnabled(true);
|
||||
}
|
||||
}
|
||||
|
@ -507,7 +519,7 @@ function mousePressEvent(event) {
|
|||
mouseHasMovedSincePress = false;
|
||||
mouseCapturedByTool = false;
|
||||
|
||||
if (toolBar.mousePressEvent(event) || progressDialog.mousePressEvent(event) || gridTool.mousePressEvent(event)) {
|
||||
if (toolBar.mousePressEvent(event) || progressDialog.mousePressEvent(event)) {
|
||||
mouseCapturedByTool = true;
|
||||
return;
|
||||
}
|
||||
|
@ -543,19 +555,16 @@ function mouseMoveEvent(event) {
|
|||
}
|
||||
|
||||
mouseHasMovedSincePress = true;
|
||||
if (isActive) {
|
||||
// allow the selectionDisplay and cameraManager to handle the event first, if it doesn't handle it, then do our own thing
|
||||
if (selectionDisplay.mouseMoveEvent(event) || cameraManager.mouseMoveEvent(event)) {
|
||||
return;
|
||||
}
|
||||
|
||||
lastMousePosition = { x: event.x, y: event.y };
|
||||
|
||||
highlightEntityUnderCursor(lastMousePosition, false);
|
||||
idleMouseTimerId = Script.setTimeout(handleIdleMouse, IDLE_MOUSE_TIMEOUT);
|
||||
} else {
|
||||
cameraManager.mouseMoveEvent(event);
|
||||
// allow the selectionDisplay and cameraManager to handle the event first, if it doesn't handle it, then do our own thing
|
||||
if (selectionDisplay.mouseMoveEvent(event) || cameraManager.mouseMoveEvent(event)) {
|
||||
return;
|
||||
}
|
||||
|
||||
lastMousePosition = { x: event.x, y: event.y };
|
||||
|
||||
highlightEntityUnderCursor(lastMousePosition, false);
|
||||
idleMouseTimerId = Script.setTimeout(handleIdleMouse, IDLE_MOUSE_TIMEOUT);
|
||||
}
|
||||
|
||||
function handleIdleMouse() {
|
||||
|
@ -608,7 +617,7 @@ function mouseReleaseEvent(event) {
|
|||
}
|
||||
|
||||
function mouseClickEvent(event) {
|
||||
if (!isActive) {
|
||||
if (!event.isRightButton) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -619,6 +628,7 @@ function mouseClickEvent(event) {
|
|||
}
|
||||
return;
|
||||
}
|
||||
toolBar.setActive(true);
|
||||
var pickRay = result.pickRay;
|
||||
var foundEntity = result.entityID;
|
||||
|
||||
|
@ -669,6 +679,10 @@ function mouseClickEvent(event) {
|
|||
|
||||
print("Model selected: " + foundEntity.id);
|
||||
selectionDisplay.select(selectedEntityID, event);
|
||||
|
||||
cameraManager.focus(selectionManager.worldPosition,
|
||||
selectionManager.worldDimensions,
|
||||
Menu.isOptionChecked(MENU_EASE_ON_FOCUS));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -816,16 +830,20 @@ function handeMenuEvent(menuItem) {
|
|||
Menu.menuItemEvent.connect(handeMenuEvent);
|
||||
|
||||
Controller.keyPressEvent.connect(function(event) {
|
||||
if (event.text == 'w' || event.text == 'a' || event.text == 's' || event.text == 'd'
|
||||
|| event.text == 'UP' || event.text == 'DOWN' || event.text == 'LEFT' || event.text == 'RIGHT') {
|
||||
toolBar.setActive(false);
|
||||
if (isActive) {
|
||||
cameraManager.keyPressEvent(event);
|
||||
}
|
||||
});
|
||||
|
||||
Controller.keyReleaseEvent.connect(function (event) {
|
||||
if (isActive) {
|
||||
cameraManager.keyReleaseEvent(event);
|
||||
}
|
||||
// since sometimes our menu shortcut keys don't work, trap our menu items here also and fire the appropriate menu items
|
||||
if (event.text == "BACKSPACE" || event.text == "DELETE") {
|
||||
deleteSelectedEntities();
|
||||
} else if (event.text == "ESC") {
|
||||
selectionManager.clearSelections();
|
||||
} else if (event.text == "TAB") {
|
||||
selectionDisplay.toggleSpaceMode();
|
||||
} else if (event.text == "f") {
|
||||
|
@ -846,55 +864,6 @@ Controller.keyReleaseEvent.connect(function (event) {
|
|||
newPosition = Vec3.subtract(newPosition, { x: 0, y: selectionManager.worldDimensions.y * 0.5, z: 0 });
|
||||
grid.setPosition(newPosition);
|
||||
}
|
||||
} else if (isActive) {
|
||||
var delta = null;
|
||||
var increment = event.isShifted ? grid.getMajorIncrement() : grid.getMinorIncrement();
|
||||
|
||||
if (event.text == 'UP') {
|
||||
if (event.isControl || event.isAlt) {
|
||||
delta = { x: 0, y: increment, z: 0 };
|
||||
} else {
|
||||
delta = { x: 0, y: 0, z: -increment };
|
||||
}
|
||||
} else if (event.text == 'DOWN') {
|
||||
if (event.isControl || event.isAlt) {
|
||||
delta = { x: 0, y: -increment, z: 0 };
|
||||
} else {
|
||||
delta = { x: 0, y: 0, z: increment };
|
||||
}
|
||||
} else if (event.text == 'LEFT') {
|
||||
delta = { x: -increment, y: 0, z: 0 };
|
||||
} else if (event.text == 'RIGHT') {
|
||||
delta = { x: increment, y: 0, z: 0 };
|
||||
}
|
||||
|
||||
if (delta != null) {
|
||||
// Adjust delta so that movements are relative to the current camera orientation
|
||||
var lookDirection = Quat.getFront(Camera.getOrientation());
|
||||
lookDirection.z *= -1;
|
||||
|
||||
var angle = Math.atan2(lookDirection.z, lookDirection.x);
|
||||
angle -= (Math.PI / 4);
|
||||
|
||||
var rotation = Math.floor(angle / (Math.PI / 2)) * (Math.PI / 2);
|
||||
var rotator = Quat.fromPitchYawRollRadians(0, rotation, 0);
|
||||
|
||||
delta = Vec3.multiplyQbyV(rotator, delta);
|
||||
|
||||
SelectionManager.saveProperties();
|
||||
|
||||
for (var i = 0; i < selectionManager.selections.length; i++) {
|
||||
var entityID = selectionManager.selections[i];
|
||||
var properties = Entities.getEntityProperties(entityID);
|
||||
Entities.editEntity(entityID, {
|
||||
position: Vec3.sum(properties.position, delta)
|
||||
});
|
||||
}
|
||||
|
||||
pushCommandForSelections();
|
||||
|
||||
selectionManager._update();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -1078,4 +1047,3 @@ PropertiesTool = function(opts) {
|
|||
};
|
||||
|
||||
propertiesTool = PropertiesTool();
|
||||
|
||||
|
|
|
@ -1,4 +1,17 @@
|
|||
// Pool Table
|
||||
// Billiards.js
|
||||
//
|
||||
// Created by Philip Rosedale on January 21, 2015
|
||||
// Copyright 2014 High Fidelity, Inc.
|
||||
//
|
||||
// Creates a pool table in front of you. Hold and release space ball to shoot a ball.
|
||||
// Cue ball will return if falls off table. Delete and reset to restart.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
HIFI_PUBLIC_BUCKET = "http://s3.amazonaws.com/hifi-public/";
|
||||
|
||||
var tableParts = [];
|
||||
var balls = [];
|
||||
var cueBall;
|
||||
|
@ -19,6 +32,10 @@ var cuePosition;
|
|||
|
||||
var startStroke = 0;
|
||||
|
||||
// Sounds to use
|
||||
hitSounds = [];
|
||||
hitSounds.push(SoundCache.getSound(HIFI_PUBLIC_BUCKET + "Collisions-ballhitsandcatches/billiards/collision1.wav"));
|
||||
|
||||
HIFI_PUBLIC_BUCKET = "http://s3.amazonaws.com/hifi-public/";
|
||||
var screenSize = Controller.getViewportDimensions();
|
||||
var reticle = Overlays.addOverlay("image", {
|
||||
|
@ -122,6 +139,7 @@ function makeBalls(pos) {
|
|||
}
|
||||
ballPosition.x += (BALL_GAP + Math.sqrt(3.0) / 2.0 * BALL_SIZE) * SCALE;
|
||||
}
|
||||
|
||||
// Cue Ball
|
||||
cuePosition = { x: pos.x - (LENGTH / 4.0) * SCALE, y: pos.y + HEIGHT / 2.0 + DROP_HEIGHT, z: pos.z };
|
||||
cueBall = Entities.addEntity(
|
||||
|
@ -138,6 +156,15 @@ function makeBalls(pos) {
|
|||
|
||||
}
|
||||
|
||||
function isObjectBall(id) {
|
||||
for (var i; i < balls.length; i++) {
|
||||
if (balls[i].id == id) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
function shootCue(velocity) {
|
||||
var DISTANCE_FROM_CAMERA = BALL_SIZE * 5.0 * SCALE;
|
||||
var camera = Camera.getPosition();
|
||||
|
@ -213,12 +240,28 @@ function update(deltaTime) {
|
|||
|
||||
}
|
||||
|
||||
function entityCollisionWithEntity(entity1, entity2, collision) {
|
||||
/*
|
||||
NOT WORKING YET
|
||||
if ((entity1.id == cueBall.id) || (entity2.id == cueBall.id)) {
|
||||
print("Cue ball collision!");
|
||||
//audioOptions.position = Vec3.sum(Camera.getPosition(), Quat.getFront(Camera.getOrientation()));
|
||||
//Audio.playSound(hitSounds[0], { position: Vec3.sum(Camera.getPosition(), Quat.getFront(Camera.getOrientation())) });
|
||||
}
|
||||
|
||||
else if (isObjectBall(entity1.id) || isObjectBall(entity2.id)) {
|
||||
print("Object ball collision");
|
||||
} */
|
||||
}
|
||||
|
||||
tableCenter = Vec3.sum(MyAvatar.position, Vec3.multiply(4.0, Quat.getFront(Camera.getOrientation())));
|
||||
|
||||
makeTable(tableCenter);
|
||||
makeBalls(tableCenter);
|
||||
|
||||
Entities.entityCollisionWithEntity.connect(entityCollisionWithEntity);
|
||||
Script.scriptEnding.connect(cleanup);
|
||||
Controller.keyPressEvent.connect(keyPressEvent);
|
||||
Controller.keyReleaseEvent.connect(keyReleaseEvent);
|
||||
Script.update.connect(update);
|
||||
|
166
examples/html/gridControls.html
Normal file
166
examples/html/gridControls.html
Normal file
|
@ -0,0 +1,166 @@
|
|||
<html>
|
||||
<head>
|
||||
<link rel="stylesheet" type="text/css" href="style.css">
|
||||
<script>
|
||||
function loaded() {
|
||||
var gridColor = { red: 0, green: 0, blue: 0 };
|
||||
var gridColors = [
|
||||
{ red: 0, green: 0, blue: 0 },
|
||||
{ red: 255, green: 255, blue: 255 },
|
||||
{ red: 255, green: 0, blue: 0 },
|
||||
{ red: 0, green: 255, blue: 0},
|
||||
{ red: 0, green: 0, blue: 255 },
|
||||
];
|
||||
var gridColorIndex = 0;
|
||||
|
||||
elPosY = document.getElementById("horiz-y");
|
||||
elMinorSpacing = document.getElementById("minor-spacing");
|
||||
elMajorSpacing = document.getElementById("major-spacing");
|
||||
elSnapToGrid = document.getElementById("snap-to-grid");
|
||||
elHorizontalGridVisible = document.getElementById("horiz-grid-visible");
|
||||
elMoveToSelection = document.getElementById("move-to-selection");
|
||||
elMoveToAvatar = document.getElementById("move-to-avatar");
|
||||
|
||||
if (window.EventBridge !== undefined) {
|
||||
EventBridge.scriptEventReceived.connect(function(data) {
|
||||
data = JSON.parse(data);
|
||||
|
||||
if (data.origin) {
|
||||
var origin = data.origin;
|
||||
elPosY.value = origin.y.toFixed(2);
|
||||
}
|
||||
|
||||
if (data.minorGridSpacing !== undefined) {
|
||||
elMinorSpacing.value = data.minorGridSpacing;
|
||||
}
|
||||
|
||||
if (data.majorGridEvery !== undefined) {
|
||||
elMajorSpacing.value = data.majorGridEvery;
|
||||
}
|
||||
|
||||
if (data.gridColor) {
|
||||
gridColor = data.gridColor;
|
||||
}
|
||||
|
||||
if (data.snapToGrid !== undefined) {
|
||||
elSnapToGrid.checked = data.snapToGrid == true;
|
||||
}
|
||||
|
||||
if (data.visible !== undefined) {
|
||||
elHorizontalGridVisible.checked = data.visible == true;
|
||||
}
|
||||
});
|
||||
|
||||
function emitUpdate() {
|
||||
EventBridge.emitWebEvent(JSON.stringify({
|
||||
type: "update",
|
||||
origin: {
|
||||
y: elPosY.value,
|
||||
},
|
||||
minorGridSpacing: elMinorSpacing.value,
|
||||
majorGridEvery: elMajorSpacing.value,
|
||||
gridColor: gridColor,
|
||||
colorIndex: gridColorIndex,
|
||||
snapToGrid: elSnapToGrid.checked,
|
||||
visible: elHorizontalGridVisible.checked,
|
||||
}));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
elPosY.addEventListener("change", emitUpdate);
|
||||
elMinorSpacing.addEventListener("change", emitUpdate);
|
||||
elMajorSpacing.addEventListener("change", emitUpdate);
|
||||
elSnapToGrid.addEventListener("change", emitUpdate);
|
||||
elHorizontalGridVisible.addEventListener("change", emitUpdate);
|
||||
|
||||
elMoveToAvatar.addEventListener("click", function() {
|
||||
EventBridge.emitWebEvent(JSON.stringify({
|
||||
type: "action",
|
||||
action: "moveToAvatar",
|
||||
}));
|
||||
});
|
||||
elMoveToSelection.addEventListener("click", function() {
|
||||
EventBridge.emitWebEvent(JSON.stringify({
|
||||
type: "action",
|
||||
action: "moveToSelection",
|
||||
}));
|
||||
});
|
||||
|
||||
var gridColorBox = document.getElementById('grid-color');
|
||||
|
||||
for (var i = 0; i < gridColors.length; i++) {
|
||||
var colors = gridColors[i];
|
||||
var box = document.createElement('div');
|
||||
box.setAttribute('class', 'color-box');
|
||||
box.style.background = 'rgb(' + colors.red + ', ' + colors.green + ', ' + colors.blue + ')';
|
||||
document.getElementById("grid-colors").appendChild(box);
|
||||
box.addEventListener("click", function(color, index) {
|
||||
return function() {
|
||||
gridColor = color;
|
||||
gridColorIndex = index;
|
||||
emitUpdate();
|
||||
}
|
||||
}({ red: colors.red, green: colors.green, blue: colors.blue }, i));
|
||||
}
|
||||
|
||||
EventBridge.emitWebEvent(JSON.stringify({ type: 'init' }));
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
<body onload='loaded();'>
|
||||
<div class="grid-section">
|
||||
|
||||
<div class="property-section">
|
||||
<label>Visible</label>
|
||||
<span>
|
||||
<input type='checkbox' id="horiz-grid-visible">
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div class="property-section">
|
||||
<label>Snap to grid</label>
|
||||
<span>
|
||||
<input type='checkbox' id="snap-to-grid">
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div id="horizontal-position" class="property-section">
|
||||
<label>Position (Y Axis)</label>
|
||||
<span>
|
||||
<input type='number' id="horiz-y" class="number" value="0.0" step="0.1"></input>
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div class="property-section">
|
||||
<label>Minor Grid Size</label>
|
||||
<span>
|
||||
<input type='number' id="minor-spacing" min="0" step="0.01", ></input>
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div class="property-section">
|
||||
<label>Major Grid Every</label>
|
||||
<span>
|
||||
<input type='number' id="major-spacing" min="2" step="1", ></input>
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div class="property-section">
|
||||
<label>Grid Color</label>
|
||||
<span id="grid-colors"></span>
|
||||
</div>
|
||||
|
||||
<div class="property-section">
|
||||
<span>
|
||||
<input type="button" id="move-to-selection" value="Move to Selection">
|
||||
</span>
|
||||
</div>
|
||||
<div class="property-section">
|
||||
<span>
|
||||
<input type="button" id="move-to-avatar" value="Move to Avatar">
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
|
@ -73,8 +73,6 @@ body {
|
|||
}
|
||||
|
||||
.grid-section {
|
||||
border-top: 0.75pt solid #DDD;
|
||||
background-color: #efefef;
|
||||
}
|
||||
|
||||
input[type=button] {
|
||||
|
@ -169,7 +167,7 @@ input {
|
|||
color: rgb(150, 150, 150);
|
||||
}
|
||||
|
||||
#properties-list input, #properties-list textarea {
|
||||
input, textarea {
|
||||
background-color: rgb(102, 102, 102);
|
||||
color: rgb(204, 204, 204);
|
||||
border: none;
|
||||
|
|
|
@ -158,6 +158,11 @@ function handleModes() {
|
|||
avatarOrientation.w != MyAvatar.orientation.w)) {
|
||||
newMode = noMode;
|
||||
}
|
||||
|
||||
if (mode == noMode && newMode != noMode && Camera.mode == "independent") {
|
||||
newMode = noMode;
|
||||
}
|
||||
|
||||
// if leaving noMode
|
||||
if (mode == noMode && newMode != noMode) {
|
||||
saveCameraState();
|
||||
|
|
|
@ -15,6 +15,9 @@ var MOUSE_SENSITIVITY = 0.9;
|
|||
var SCROLL_SENSITIVITY = 0.05;
|
||||
var PAN_ZOOM_SCALE_RATIO = 0.4;
|
||||
|
||||
var KEY_ORBIT_SENSITIVITY = 40;
|
||||
var KEY_ZOOM_SENSITIVITY = 10;
|
||||
|
||||
// Scaling applied based on the size of the object being focused
|
||||
var FOCUS_ZOOM_SCALE = 1.3;
|
||||
|
||||
|
@ -43,6 +46,10 @@ var easeOutCubic = function(t) {
|
|||
|
||||
EASE_TIME = 0.5;
|
||||
|
||||
function clamp(value, minimum, maximum) {
|
||||
return Math.min(Math.max(value, minimum), maximum);
|
||||
}
|
||||
|
||||
function mergeObjects(obj1, obj2) {
|
||||
var newObj = {};
|
||||
for (key in obj1) {
|
||||
|
@ -60,6 +67,49 @@ CameraManager = function() {
|
|||
that.enabled = false;
|
||||
that.mode = MODE_INACTIVE;
|
||||
|
||||
var actions = {
|
||||
orbitLeft: 0,
|
||||
orbitRight: 0,
|
||||
orbitUp: 0,
|
||||
orbitDown: 0,
|
||||
orbitForward: 0,
|
||||
orbitBackward: 0,
|
||||
}
|
||||
|
||||
var keyToActionMapping = {
|
||||
"a": "orbitLeft",
|
||||
"d": "orbitRight",
|
||||
"w": "orbitForward",
|
||||
"s": "orbitBackward",
|
||||
"e": "orbitUp",
|
||||
"c": "orbitDown",
|
||||
|
||||
"LEFT": "orbitLeft",
|
||||
"RIGHT": "orbitRight",
|
||||
"UP": "orbitForward",
|
||||
"DOWN": "orbitBackward",
|
||||
}
|
||||
|
||||
var CAPTURED_KEYS = [];
|
||||
for (key in keyToActionMapping) {
|
||||
CAPTURED_KEYS.push(key);
|
||||
}
|
||||
|
||||
function getActionForKeyEvent(event) {
|
||||
var action = keyToActionMapping[event.text];
|
||||
if (action !== undefined) {
|
||||
if (event.isShifted) {
|
||||
if (action == "orbitForward") {
|
||||
action = "orbitUp";
|
||||
} else if (action == "orbitBackward") {
|
||||
action = "orbitDown";
|
||||
}
|
||||
}
|
||||
return action;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
that.zoomDistance = INITIAL_ZOOM_DISTANCE;
|
||||
that.targetZoomDistance = INITIAL_ZOOM_DISTANCE;
|
||||
|
||||
|
@ -80,7 +130,12 @@ CameraManager = function() {
|
|||
that.lastMousePosition = { x: 0, y: 0 };
|
||||
|
||||
that.enable = function() {
|
||||
if (that.enabled) return;
|
||||
if (Camera.mode == "independent" || that.enabled) return;
|
||||
|
||||
for (var i = 0; i < CAPTURED_KEYS.length; i++) {
|
||||
Controller.captureKeyEvents({ text: CAPTURED_KEYS[i] });
|
||||
}
|
||||
|
||||
that.enabled = true;
|
||||
that.mode = MODE_INACTIVE;
|
||||
|
||||
|
@ -111,6 +166,11 @@ CameraManager = function() {
|
|||
|
||||
that.disable = function(ignoreCamera) {
|
||||
if (!that.enabled) return;
|
||||
|
||||
for (var i = 0; i < CAPTURED_KEYS.length; i++) {
|
||||
Controller.releaseKeyEvents({ text: CAPTURED_KEYS[i] });
|
||||
}
|
||||
|
||||
that.enabled = false;
|
||||
that.mode = MODE_INACTIVE;
|
||||
|
||||
|
@ -207,6 +267,11 @@ CameraManager = function() {
|
|||
if (that.enabled && that.mode != MODE_INACTIVE) {
|
||||
var x = Window.getCursorPositionX();
|
||||
var y = Window.getCursorPositionY();
|
||||
if (!hasDragged) {
|
||||
that.lastMousePosition.x = x;
|
||||
that.lastMousePosition.y = y;
|
||||
hasDragged = true;
|
||||
}
|
||||
if (that.mode == MODE_ORBIT) {
|
||||
var diffX = x - that.lastMousePosition.x;
|
||||
var diffY = y - that.lastMousePosition.y;
|
||||
|
@ -234,9 +299,31 @@ CameraManager = function() {
|
|||
|
||||
that.moveFocalPoint(dPosition);
|
||||
}
|
||||
var newX = Window.x + Window.innerWidth / 2;
|
||||
var newY = Window.y + Window.innerHeight / 2;
|
||||
Window.setCursorPosition(newX, newY);
|
||||
|
||||
var newX = x;
|
||||
var newY = y;
|
||||
var updatePosition = false;
|
||||
|
||||
if (x <= Window.x) {
|
||||
newX = Window.x + Window.innerWidth;
|
||||
updatePosition = true;
|
||||
} else if (x >= (Window.x + Window.innerWidth)) {
|
||||
newX = Window.x;
|
||||
updatePosition = true;
|
||||
}
|
||||
|
||||
if (y <= Window.y) {
|
||||
newY = Window.y + Window.innerHeight;
|
||||
updatePosition = true;
|
||||
} else if (y >= (Window.y + Window.innerHeight)) {
|
||||
newY = Window.y;
|
||||
updatePosition = true;
|
||||
}
|
||||
|
||||
if (updatePosition) {
|
||||
Window.setCursorPosition(newX, newY);
|
||||
}
|
||||
|
||||
that.lastMousePosition.x = newX;
|
||||
that.lastMousePosition.y = newY;
|
||||
|
||||
|
@ -245,6 +332,7 @@ CameraManager = function() {
|
|||
return false;
|
||||
}
|
||||
|
||||
var hasDragged = false;
|
||||
that.mousePressEvent = function(event) {
|
||||
if (cameraTool.mousePressEvent(event)) {
|
||||
return true;
|
||||
|
@ -259,12 +347,7 @@ CameraManager = function() {
|
|||
}
|
||||
|
||||
if (that.mode != MODE_INACTIVE) {
|
||||
var newX = Window.x + Window.innerWidth / 2;
|
||||
var newY = Window.y + Window.innerHeight / 2;
|
||||
Window.setCursorPosition(newX, newY);
|
||||
that.lastMousePosition.x = newX;
|
||||
that.lastMousePosition.y = newY;
|
||||
Window.setCursorVisible(false);
|
||||
hasDragged = false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -279,6 +362,20 @@ CameraManager = function() {
|
|||
that.mode = MODE_INACTIVE;
|
||||
}
|
||||
|
||||
that.keyPressEvent = function(event) {
|
||||
var action = getActionForKeyEvent(event);
|
||||
if (action) {
|
||||
actions[action] = 1;
|
||||
}
|
||||
};
|
||||
|
||||
that.keyReleaseEvent = function(event) {
|
||||
var action = getActionForKeyEvent(event);
|
||||
if (action) {
|
||||
actions[action] = 0;
|
||||
}
|
||||
};
|
||||
|
||||
that.wheelEvent = function(event) {
|
||||
if (!that.enabled) return;
|
||||
|
||||
|
@ -332,6 +429,14 @@ CameraManager = function() {
|
|||
return;
|
||||
}
|
||||
|
||||
// Update based on current actions
|
||||
that.targetYaw += (actions.orbitRight - actions.orbitLeft) * dt * KEY_ORBIT_SENSITIVITY;
|
||||
that.targetPitch += (actions.orbitUp - actions.orbitDown) * dt * KEY_ORBIT_SENSITIVITY;
|
||||
that.targetPitch = clamp(that.targetPitch, -90, 90);
|
||||
that.targetZoomDistance += (actions.orbitBackward - actions.orbitForward) * dt * KEY_ZOOM_SENSITIVITY;
|
||||
that.targetZoomDistance = clamp(that.targetZoomDistance, MIN_ZOOM_DISTANCE, MAX_ZOOM_DISTANCE);
|
||||
|
||||
|
||||
if (easing) {
|
||||
easingTime = Math.min(EASE_TIME, easingTime + dt);
|
||||
}
|
||||
|
@ -383,6 +488,7 @@ CameraManager = function() {
|
|||
});
|
||||
|
||||
Script.update.connect(that.update);
|
||||
Script.scriptEnding.connect(that.disable);
|
||||
|
||||
Controller.wheelEvent.connect(that.wheelEvent);
|
||||
|
||||
|
|
|
@ -2,11 +2,11 @@ Grid = function(opts) {
|
|||
var that = {};
|
||||
|
||||
var colors = [
|
||||
{ red: 0, green: 255, blue: 0 },
|
||||
{ red: 255, green: 255, blue: 255 },
|
||||
{ red: 0, green: 0, blue: 0 },
|
||||
{ red: 0, green: 0, blue: 255 },
|
||||
{ red: 255, green: 255, blue: 255 },
|
||||
{ red: 255, green: 0, blue: 0 },
|
||||
{ red: 0, green: 255, blue: 0 },
|
||||
{ red: 0, green: 0, blue: 255 },
|
||||
];
|
||||
var colorIndex = 0;
|
||||
var gridAlpha = 0.6;
|
||||
|
@ -224,273 +224,50 @@ Grid = function(opts) {
|
|||
GridTool = function(opts) {
|
||||
var that = {};
|
||||
|
||||
var UI_URL = HIFI_PUBLIC_BUCKET + "images/tools/grid-toolbar.svg";
|
||||
var UI_WIDTH = 854;
|
||||
var UI_HEIGHT = 37;
|
||||
|
||||
var horizontalGrid = opts.horizontalGrid;
|
||||
var verticalGrid = opts.verticalGrid;
|
||||
var listeners = [];
|
||||
|
||||
var uiOverlays = {};
|
||||
var allOverlays = [];
|
||||
var url = Script.resolvePath('html/gridControls.html');
|
||||
var webView = new WebWindow('Grid', url, 200, 280);
|
||||
|
||||
function addUIOverlay(key, overlay, x, y, width, height) {
|
||||
uiOverlays[key] = {
|
||||
overlay: overlay,
|
||||
x: x,
|
||||
y: y,
|
||||
width: width,
|
||||
height: height,
|
||||
};
|
||||
allOverlays.push(overlay);
|
||||
}
|
||||
horizontalGrid.addListener(function(data) {
|
||||
webView.eventBridge.emitScriptEvent(JSON.stringify(data));
|
||||
selectionDisplay.updateHandles();
|
||||
});
|
||||
|
||||
var lastKnownWindowWidth = null;
|
||||
function repositionUI() {
|
||||
if (lastKnownWindowWidth == Window.innerWidth) {
|
||||
return;
|
||||
}
|
||||
|
||||
lastKnownWindowWidth = Window.innerWidth;
|
||||
var x = Window.innerWidth / 2 - UI_WIDTH / 2;
|
||||
var y = 10;
|
||||
|
||||
for (var key in uiOverlays) {
|
||||
info = uiOverlays[key];
|
||||
Overlays.editOverlay(info.overlay, {
|
||||
x: x + info.x,
|
||||
y: y + info.y,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// "Spritesheet" is laid out horizontally in this order
|
||||
var UI_SPRITE_LIST = [
|
||||
{ name: "gridText", width: 54 },
|
||||
{ name: "visibleCheckbox", width: 60 },
|
||||
{ name: "snapToGridCheckbox", width: 105 },
|
||||
|
||||
{ name: "color0", width: 27 },
|
||||
{ name: "color1", width: 27 },
|
||||
{ name: "color2", width: 27 },
|
||||
{ name: "color3", width: 27 },
|
||||
{ name: "color4", width: 27 },
|
||||
|
||||
{ name: "minorGridIcon", width: 34 },
|
||||
{ name: "minorGridDecrease", width: 25 },
|
||||
{ name: "minorGridInput", width: 26 },
|
||||
{ name: "minorGridIncrease", width: 25 },
|
||||
|
||||
{ name: "majorGridIcon", width: 40 },
|
||||
{ name: "majorGridDecrease", width: 25 },
|
||||
{ name: "majorGridInput", width: 26 },
|
||||
{ name: "majorGridIncrease", width: 25 },
|
||||
|
||||
{ name: "yPositionLabel", width: 160 },
|
||||
{ name: "moveToLabel", width: 54 },
|
||||
{ name: "moveToAvatar", width: 26 },
|
||||
{ name: "moveToSelection", width: 34 },
|
||||
];
|
||||
|
||||
// Add all overlays from spritesheet
|
||||
var baseOverlay = null;
|
||||
var x = 0;
|
||||
for (var i = 0; i < UI_SPRITE_LIST.length; i++) {
|
||||
var info = UI_SPRITE_LIST[i];
|
||||
|
||||
var props = {
|
||||
imageURL: UI_URL,
|
||||
subImage: { x: x, y: 0, width: info.width, height: UI_HEIGHT },
|
||||
width: info.width,
|
||||
height: UI_HEIGHT,
|
||||
alpha: 1.0,
|
||||
visible: false,
|
||||
};
|
||||
|
||||
var overlay;
|
||||
if (baseOverlay == null) {
|
||||
overlay = Overlays.addOverlay("image", {
|
||||
imageURL: UI_URL,
|
||||
});
|
||||
baseOverlay = overlay;
|
||||
} else {
|
||||
overlay = Overlays.cloneOverlay(baseOverlay);
|
||||
}
|
||||
|
||||
Overlays.editOverlay(overlay, props);
|
||||
|
||||
addUIOverlay(info.name, overlay, x, 0, info.width, UI_HEIGHT);
|
||||
|
||||
x += info.width;
|
||||
}
|
||||
|
||||
// Add Text overlays
|
||||
var textProperties = {
|
||||
color: { red: 255, green: 255, blue: 255 },
|
||||
topMargin: 6,
|
||||
leftMargin: 4,
|
||||
alpha: 1,
|
||||
backgroundAlpha: 0,
|
||||
text: "",
|
||||
font: { size: 12 },
|
||||
visible: false,
|
||||
};
|
||||
var minorGridWidthText = Overlays.addOverlay("text", textProperties);
|
||||
var majorGridEveryText = Overlays.addOverlay("text", textProperties);
|
||||
var yPositionText = Overlays.addOverlay("text", textProperties);
|
||||
|
||||
addUIOverlay('minorGridWidthText', minorGridWidthText, 414, 8, 24, 24);
|
||||
addUIOverlay('majorGridEveryText', majorGridEveryText, 530, 8, 24, 24);
|
||||
addUIOverlay('yPositionText', yPositionText, 660, 8, 24, 24);
|
||||
|
||||
var NUM_COLORS = 5;
|
||||
function updateColorIndex(index) {
|
||||
if (index < 0 || index >= NUM_COLORS) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (var i = 0 ; i < NUM_COLORS; i++) {
|
||||
var info = uiOverlays['color' + i];
|
||||
Overlays.editOverlay(info.overlay, {
|
||||
subImage: {
|
||||
x: info.x,
|
||||
y: i == index ? UI_HEIGHT : 0,
|
||||
width: info.width,
|
||||
height: info.height,
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function updateGridVisible(value) {
|
||||
var info = uiOverlays.visibleCheckbox;
|
||||
Overlays.editOverlay(info.overlay, {
|
||||
subImage: {
|
||||
x: info.x,
|
||||
y: value ? UI_HEIGHT : 0,
|
||||
width: info.width,
|
||||
height: info.height,
|
||||
webView.eventBridge.webEventReceived.connect(function(data) {
|
||||
data = JSON.parse(data);
|
||||
if (data.type == "init") {
|
||||
horizontalGrid.emitUpdate();
|
||||
} else if (data.type == "update") {
|
||||
horizontalGrid.update(data);
|
||||
for (var i = 0; i < listeners.length; i++) {
|
||||
listeners[i](data);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function updateSnapToGrid(value) {
|
||||
var info = uiOverlays.snapToGridCheckbox;
|
||||
Overlays.editOverlay(info.overlay, {
|
||||
subImage: {
|
||||
x: info.x,
|
||||
y: value ? UI_HEIGHT : 0,
|
||||
width: info.width,
|
||||
height: info.height,
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function updateMinorGridWidth(value) {
|
||||
Overlays.editOverlay(minorGridWidthText, {
|
||||
text: value.toFixed(1),
|
||||
});
|
||||
}
|
||||
|
||||
function updateMajorGridEvery(value) {
|
||||
Overlays.editOverlay(majorGridEveryText, {
|
||||
text: value,
|
||||
});
|
||||
}
|
||||
|
||||
function updateYPosition(value) {
|
||||
Overlays.editOverlay(yPositionText, {
|
||||
text: value.toFixed(2),
|
||||
});
|
||||
}
|
||||
|
||||
function updateOverlays() {
|
||||
updateGridVisible(horizontalGrid.getVisible());
|
||||
updateSnapToGrid(horizontalGrid.getSnapToGrid());
|
||||
updateColorIndex(horizontalGrid.getColorIndex());
|
||||
|
||||
updateMinorGridWidth(horizontalGrid.getMinorGridWidth());
|
||||
updateMajorGridEvery(horizontalGrid.getMajorGridEvery());
|
||||
|
||||
updateYPosition(horizontalGrid.getOrigin().y);
|
||||
}
|
||||
|
||||
that.setVisible = function(visible) {
|
||||
for (var i = 0; i < allOverlays.length; i++) {
|
||||
Overlays.editOverlay(allOverlays[i], { visible: visible });
|
||||
}
|
||||
}
|
||||
|
||||
that.mousePressEvent = function(event) {
|
||||
var overlay = Overlays.getOverlayAtPoint({ x: event.x, y: event.y });
|
||||
|
||||
if (allOverlays.indexOf(overlay) >= 0) {
|
||||
if (overlay == uiOverlays.color0.overlay) {
|
||||
horizontalGrid.setColorIndex(0);
|
||||
} else if (overlay == uiOverlays.color1.overlay) {
|
||||
horizontalGrid.setColorIndex(1);
|
||||
} else if (overlay == uiOverlays.color2.overlay) {
|
||||
horizontalGrid.setColorIndex(2);
|
||||
} else if (overlay == uiOverlays.color3.overlay) {
|
||||
horizontalGrid.setColorIndex(3);
|
||||
} else if (overlay == uiOverlays.color4.overlay) {
|
||||
horizontalGrid.setColorIndex(4);
|
||||
} else if (overlay == uiOverlays.visibleCheckbox.overlay) {
|
||||
horizontalGrid.setVisible(!horizontalGrid.getVisible());
|
||||
} else if (overlay == uiOverlays.snapToGridCheckbox.overlay) {
|
||||
horizontalGrid.setSnapToGrid(!horizontalGrid.getSnapToGrid());
|
||||
} else if (overlay == uiOverlays.moveToAvatar.overlay) {
|
||||
} else if (data.type == "action") {
|
||||
var action = data.action;
|
||||
if (action == "moveToAvatar") {
|
||||
var position = MyAvatar.getJointPosition("LeftFoot");
|
||||
if (position.x == 0 && position.y == 0 && position.z == 0) {
|
||||
position = MyAvatar.position;
|
||||
}
|
||||
horizontalGrid.setPosition(position);
|
||||
} else if (overlay == uiOverlays.moveToSelection.overlay) {
|
||||
} else if (action == "moveToSelection") {
|
||||
var newPosition = selectionManager.worldPosition;
|
||||
newPosition = Vec3.subtract(newPosition, { x: 0, y: selectionManager.worldDimensions.y * 0.5, z: 0 });
|
||||
horizontalGrid.setPosition(newPosition);
|
||||
} else if (overlay == uiOverlays.minorGridDecrease.overlay) {
|
||||
var newValue = Math.max(0.1, horizontalGrid.getMinorGridWidth() - 0.1);
|
||||
horizontalGrid.setMinorGridWidth(newValue);
|
||||
} else if (overlay == uiOverlays.minorGridIncrease.overlay) {
|
||||
horizontalGrid.setMinorGridWidth(horizontalGrid.getMinorGridWidth() + 0.1);
|
||||
} else if (overlay == uiOverlays.majorGridDecrease.overlay) {
|
||||
var newValue = Math.max(2, horizontalGrid.getMajorGridEvery() - 1);
|
||||
horizontalGrid.setMajorGridEvery(newValue);
|
||||
} else if (overlay == uiOverlays.majorGridIncrease.overlay) {
|
||||
horizontalGrid.setMajorGridEvery(horizontalGrid.getMajorGridEvery() + 1);
|
||||
} else if (overlay == uiOverlays.yPositionLabel.overlay) {
|
||||
var newValue = Window.prompt("Y Position:", horizontalGrid.getOrigin().y.toFixed(4));
|
||||
if (newValue !== null) {
|
||||
var y = parseFloat(newValue)
|
||||
if (isNaN(y)) {
|
||||
Window.alert("Invalid position");
|
||||
} else {
|
||||
horizontalGrid.setPosition({ x: 0, y: y, z: 0 });
|
||||
}
|
||||
}
|
||||
grid.setPosition(newPosition);
|
||||
}
|
||||
|
||||
// Clicking anywhere within the toolbar will "consume" this press event
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
};
|
||||
|
||||
Script.scriptEnding.connect(function() {
|
||||
for (var i = 0; i < allOverlays.length; i++) {
|
||||
Overlays.deleteOverlay(allOverlays[i]);
|
||||
}
|
||||
});
|
||||
Script.update.connect(repositionUI);
|
||||
|
||||
horizontalGrid.addListener(function() {
|
||||
selectionDisplay.updateHandles();
|
||||
updateOverlays();
|
||||
});
|
||||
that.addListener = function(callback) {
|
||||
listeners.push(callback);
|
||||
}
|
||||
|
||||
updateOverlays();
|
||||
repositionUI();
|
||||
that.setVisible = function(visible) {
|
||||
webView.setVisible(visible);
|
||||
}
|
||||
|
||||
return that;
|
||||
};
|
||||
|
|
|
@ -52,18 +52,16 @@
|
|||
// 2. Declare a text string.
|
||||
// 3. Call createNotifications(text) parsing the text.
|
||||
// example:
|
||||
// var welcome;
|
||||
// if (key.text == "q") { //queries number of users online
|
||||
// var numUsers = GlobalServices.onlineUsers.length;
|
||||
// var welcome = "There are " + numUsers + " users online now.";
|
||||
// createNotification(welcome);
|
||||
// var welcome = "There are " + GlobalServices.onlineUsers.length + " users online now.";
|
||||
// createNotification(welcome);
|
||||
// }
|
||||
|
||||
|
||||
var width = 340.0; //width of notification overlay
|
||||
var height = 40.0; // height of a single line notification overlay
|
||||
var windowDimensions = Controller.getViewportDimensions(); // get the size of the interface window
|
||||
var overlayLocationX = (windowDimensions.x - (width + 20.0));// positions window 20px from the right of the interface window
|
||||
var buttonLocationX = overlayLocationX + (width - 28.0);
|
||||
var overlayLocationX = (windowDimensions.x - (width + 20.0)); // positions window 20px from the right of the interface window
|
||||
var buttonLocationX = overlayLocationX + (width - 28.0);
|
||||
var locationY = 20.0; // position down from top of interface window
|
||||
var topMargin = 13.0;
|
||||
var leftMargin = 10.0;
|
||||
|
@ -71,264 +69,79 @@ var textColor = { red: 228, green: 228, blue: 228}; // text color
|
|||
var backColor = { red: 2, green: 2, blue: 2}; // background color was 38,38,38
|
||||
var backgroundAlpha = 0;
|
||||
var fontSize = 12.0;
|
||||
var persistTime = 10.0; // time in seconds before notification fades
|
||||
var PERSIST_TIME_2D = 10.0; // Time in seconds before notification fades
|
||||
var PERSIST_TIME_3D = 15.0;
|
||||
var persistTime = PERSIST_TIME_2D;
|
||||
var clickedText = false;
|
||||
var frame = 0;
|
||||
var ourWidth = Window.innerWidth;
|
||||
var ourHeight = Window.innerHeight;
|
||||
var ourWidth = Window.innerWidth;
|
||||
var ourHeight = Window.innerHeight;
|
||||
var text = "placeholder";
|
||||
var last_users = GlobalServices.onlineUsers;
|
||||
var users = [];
|
||||
var ctrlIsPressed = false;
|
||||
var ready = true;
|
||||
|
||||
// When our script shuts down, we should clean up all of our overlays
|
||||
function scriptEnding() {
|
||||
for (i = 0; i < notifications.length; i++) {
|
||||
Overlays.deleteOverlay(notifications[i]);
|
||||
Overlays.deleteOverlay(buttons[i]);
|
||||
}
|
||||
}
|
||||
Script.scriptEnding.connect(scriptEnding);
|
||||
|
||||
var notifications = [];
|
||||
var buttons = [];
|
||||
var buttons = [];
|
||||
var times = [];
|
||||
var heights = [];
|
||||
var myAlpha = [];
|
||||
var arrays = [];
|
||||
var isOnHMD = false,
|
||||
ENABLE_VR_MODE = "Enable VR Mode",
|
||||
NOTIFICATIONS_3D_DIRECTION = 0.0, // Degrees from avatar orientation.
|
||||
NOTIFICATIONS_3D_DISTANCE = 0.6, // Horizontal distance from avatar position.
|
||||
NOTIFICATIONS_3D_ELEVATION = -0.8, // Height of top middle of top notification relative to avatar eyes.
|
||||
NOTIFICATIONS_3D_YAW = 0.0, // Degrees relative to notifications direction.
|
||||
NOTIFICATIONS_3D_PITCH = -60.0, // Degrees from vertical.
|
||||
NOTIFICATION_3D_SCALE = 0.002, // Multiplier that converts 2D overlay dimensions to 3D overlay dimensions.
|
||||
NOTIFICATION_3D_BUTTON_WIDTH = 40 * NOTIFICATION_3D_SCALE, // Need a little more room for button in 3D.
|
||||
overlay3DDetails = [];
|
||||
|
||||
// This function creates and sizes the overlays
|
||||
function createNotification(text) {
|
||||
var count = (text.match(/\n/g) || []).length;
|
||||
var breakPoint = 43.0; // length when new line is added
|
||||
var extraLine = 0;
|
||||
var breaks = 0;
|
||||
var height = 40.0;
|
||||
var stack = 0;
|
||||
if (text.length >= breakPoint) {
|
||||
breaks = count;
|
||||
}
|
||||
var extraLine = breaks * 16.0;
|
||||
for (i = 0; i < heights.length; i++) {
|
||||
stack = stack + heights[i];
|
||||
}
|
||||
var level = (stack + 20.0);
|
||||
height = height + extraLine;
|
||||
var overlayProperties = {
|
||||
x: overlayLocationX,
|
||||
y: level,
|
||||
width: width,
|
||||
height: height,
|
||||
color: textColor,
|
||||
backgroundColor: backColor,
|
||||
alpha: backgroundAlpha,
|
||||
topMargin: topMargin,
|
||||
leftMargin: leftMargin,
|
||||
font: {size: fontSize},
|
||||
text: text,
|
||||
};
|
||||
var bLevel = level + 12.0;
|
||||
var buttonProperties = {
|
||||
x: buttonLocationX,
|
||||
y: bLevel,
|
||||
width: 10.0,
|
||||
height: 10.0,
|
||||
subImage: { x: 0, y: 0, width: 10, height: 10 },
|
||||
imageURL: "http://hifi-public.s3.amazonaws.com/images/close-small-light.svg",
|
||||
color: { red: 255, green: 255, blue: 255},
|
||||
visible: true,
|
||||
alpha: backgroundAlpha,
|
||||
};
|
||||
|
||||
Notify(overlayProperties, buttonProperties, height);
|
||||
|
||||
// push data from above to the 2 dimensional array
|
||||
function createArrays(notice, button, createTime, height, myAlpha) {
|
||||
arrays.push([notice, button, createTime, height, myAlpha]);
|
||||
}
|
||||
|
||||
// Pushes data to each array and sets up data for 2nd dimension array
|
||||
// to handle auxiliary data not carried by the overlay class
|
||||
// specifically notification "heights", "times" of creation, and .
|
||||
function Notify(notice, button, height){
|
||||
|
||||
notifications.push((Overlays.addOverlay("text", notice)));
|
||||
buttons.push((Overlays.addOverlay("image",button)));
|
||||
times.push(new Date().getTime() / 1000);
|
||||
height = height + 1.0;
|
||||
heights.push(height);
|
||||
myAlpha.push(0);
|
||||
var last = notifications.length - 1;
|
||||
createArrays(notifications[last], buttons[last], times[last], heights[last], myAlpha[last]);
|
||||
fadeIn(notifications[last], buttons[last])
|
||||
// This handles the final dismissal of a notification after fading
|
||||
function dismiss(firstNoteOut, firstButOut, firstOut) {
|
||||
Overlays.deleteOverlay(firstNoteOut);
|
||||
Overlays.deleteOverlay(firstButOut);
|
||||
notifications.splice(firstOut, 1);
|
||||
buttons.splice(firstOut, 1);
|
||||
times.splice(firstOut, 1);
|
||||
heights.splice(firstOut, 1);
|
||||
myAlpha.splice(firstOut, 1);
|
||||
overlay3DDetails.splice(firstOut, 1);
|
||||
}
|
||||
|
||||
function fadeIn(noticeIn, buttonIn) {
|
||||
var myLength = arrays.length;
|
||||
var q = 0;
|
||||
var pauseTimer = null;
|
||||
pauseTimer = Script.setInterval(function() {
|
||||
q++;
|
||||
var q = 0,
|
||||
qFade,
|
||||
pauseTimer = null;
|
||||
|
||||
pauseTimer = Script.setInterval(function () {
|
||||
q += 1;
|
||||
qFade = q / 10.0;
|
||||
Overlays.editOverlay(noticeIn, {alpha: qFade});
|
||||
Overlays.editOverlay(buttonIn, {alpha: qFade});
|
||||
Overlays.editOverlay(noticeIn, { alpha: qFade });
|
||||
Overlays.editOverlay(buttonIn, { alpha: qFade });
|
||||
if (q >= 9.0) {
|
||||
Script.clearInterval(pauseTimer);
|
||||
}
|
||||
}, 10);
|
||||
}
|
||||
|
||||
|
||||
// push data from above to the 2 dimensional array
|
||||
function createArrays(notice, button, createTime, height, myAlpha) {
|
||||
arrays.push([notice, button, createTime, height, myAlpha]);
|
||||
}
|
||||
// handles mouse clicks on buttons
|
||||
function mousePressEvent(event) {
|
||||
var clickedOverlay = Overlays.getOverlayAtPoint({x: event.x, y: event.y}); //identify which overlay was clicked
|
||||
for (i = 0; i < buttons.length; i++) { //if user clicked a button
|
||||
if(clickedOverlay == buttons[i]) {
|
||||
Overlays.deleteOverlay(notifications[i]);
|
||||
Overlays.deleteOverlay(buttons[i]);
|
||||
notifications.splice(i, 1);
|
||||
buttons.splice(i, 1);
|
||||
times.splice(i, 1);
|
||||
heights.splice(i, 1);
|
||||
myAlpha.splice(i, 1);
|
||||
arrays.splice(i, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Control key remains active only while key is held down
|
||||
function keyReleaseEvent(key) {
|
||||
if (key.key == 16777249) {
|
||||
ctrlIsPressed = false;
|
||||
}
|
||||
}
|
||||
|
||||
// Triggers notification on specific key driven events
|
||||
function keyPressEvent(key) {
|
||||
if (key.key == 16777249) {
|
||||
ctrlIsPressed = true;
|
||||
}
|
||||
if (key.text == "q") { //queries number of users online
|
||||
var numUsers = GlobalServices.onlineUsers.length;
|
||||
var welcome = "There are " + numUsers + " users online now.";
|
||||
createNotification(welcome);
|
||||
}
|
||||
|
||||
if (key.text == "s") {
|
||||
if (ctrlIsPressed == true){
|
||||
var noteString = "Snapshot taken.";
|
||||
createNotification(noteString);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// formats string to add newline every 43 chars
|
||||
function wordWrap(str) {
|
||||
var result = stringDivider(str, 43.0, "\n");
|
||||
createNotification(result);
|
||||
}
|
||||
// wraps whole word to newline
|
||||
function stringDivider(str, slotWidth, spaceReplacer) {
|
||||
if (str.length > slotWidth) {
|
||||
var p = slotWidth;
|
||||
for (; p > 0 && str[p] != ' '; p--) {
|
||||
}
|
||||
if (p > 0) {
|
||||
var left = str.substring(0, p);
|
||||
var right = str.substring(p + 1);
|
||||
return left + spaceReplacer + stringDivider(right, slotWidth, spaceReplacer);
|
||||
}
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
// This fires a notification on window resize
|
||||
function checkSize(){
|
||||
if((Window.innerWidth != ourWidth)||(Window.innerHeight != ourHeight)) {
|
||||
var windowResize = "Window has been resized";
|
||||
ourWidth = Window.innerWidth;
|
||||
ourHeight = Window.innerHeight;
|
||||
windowDimensions = Controller.getViewportDimensions();
|
||||
overlayLocationX = (windowDimensions.x - (width + 60.0));
|
||||
buttonLocationX = overlayLocationX + (width - 35.0);
|
||||
createNotification(windowResize)
|
||||
}
|
||||
}
|
||||
|
||||
// Triggers notification if a user logs on or off
|
||||
function onOnlineUsersChanged(users) {
|
||||
if (!isStartingUp()) { // Skip user notifications at startup.
|
||||
for (user in users) {
|
||||
if (last_users.indexOf(users[user]) == -1.0) {
|
||||
createNotification(users[user] + " has joined");
|
||||
}
|
||||
}
|
||||
for (user in last_users) {
|
||||
if (users.indexOf(last_users[user]) == -1.0) {
|
||||
createNotification(last_users[user] + " has left");
|
||||
}
|
||||
}
|
||||
}
|
||||
last_users = users;
|
||||
}
|
||||
|
||||
// Triggers notification if @MyUserName is mentioned in chat and returns the message to the notification.
|
||||
function onIncomingMessage(user, message) {
|
||||
var myMessage = message;
|
||||
var alertMe = "@" + GlobalServices.myUsername;
|
||||
var thisAlert = user + ": " + myMessage;
|
||||
if (myMessage.indexOf(alertMe) > -1.0) {
|
||||
wordWrap(thisAlert);
|
||||
}
|
||||
}
|
||||
// Triggers mic mute notification
|
||||
function onMuteStateChanged() {
|
||||
var muteState = AudioDevice.getMuted() ? "muted" : "unmuted";
|
||||
var muteString = "Microphone is now " + muteState;
|
||||
createNotification(muteString);
|
||||
}
|
||||
|
||||
function update(){
|
||||
frame++;
|
||||
if ((frame % 60.0) == 0) { // only update once a second
|
||||
checkSize(); // checks for size change to trigger windowResize notification
|
||||
locationY = 20.0;
|
||||
for (var i = 0; i < arrays.length; i++) { //repositions overlays as others fade
|
||||
var nextOverlay = Overlays.getOverlayAtPoint({x: overlayLocationX, y: locationY});
|
||||
Overlays.editOverlay(notifications[i], { x:overlayLocationX, y:locationY});
|
||||
Overlays.editOverlay(buttons[i], { x:buttonLocationX, y:locationY + 12.0});
|
||||
locationY = locationY + arrays[i][3];
|
||||
}
|
||||
}
|
||||
|
||||
// This checks the age of the notification and prepares to fade it after 9.0 seconds (var persistTime - 1)
|
||||
for (var i = 0; i < arrays.length; i++) {
|
||||
if (ready){
|
||||
var j = arrays[i][2];
|
||||
var k = j + persistTime;
|
||||
if (k < (new Date().getTime() / 1000)) {
|
||||
ready = false;
|
||||
noticeOut = arrays[i][0];
|
||||
buttonOut = arrays[i][1];
|
||||
var arraysOut = i;
|
||||
fadeOut(noticeOut, buttonOut, arraysOut);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// this fades the notification ready for dismissal, and removes it from the arrays
|
||||
function fadeOut(noticeOut, buttonOut, arraysOut) {
|
||||
var myLength = arrays.length;
|
||||
var r = 9.0;
|
||||
var pauseTimer = null;
|
||||
pauseTimer = Script.setInterval(function() {
|
||||
r--;
|
||||
rFade = r / 10.0;
|
||||
Overlays.editOverlay(noticeOut, {alpha: rFade});
|
||||
Overlays.editOverlay(buttonOut, {alpha: rFade});
|
||||
var r = 9.0,
|
||||
rFade,
|
||||
pauseTimer = null;
|
||||
|
||||
pauseTimer = Script.setInterval(function () {
|
||||
r -= 1;
|
||||
rFade = r / 10.0;
|
||||
Overlays.editOverlay(noticeOut, { alpha: rFade });
|
||||
Overlays.editOverlay(buttonOut, { alpha: rFade });
|
||||
if (r < 0) {
|
||||
dismiss(noticeOut, buttonOut, arraysOut);
|
||||
arrays.splice(arraysOut, 1);
|
||||
|
@ -338,29 +151,283 @@ function fadeOut(noticeOut, buttonOut, arraysOut) {
|
|||
}, 20);
|
||||
}
|
||||
|
||||
// This handles the final dismissal of a notification after fading
|
||||
function dismiss(firstNoteOut, firstButOut, firstOut) {
|
||||
var working = firstOut
|
||||
Overlays.deleteOverlay(firstNoteOut);
|
||||
Overlays.deleteOverlay(firstButOut);
|
||||
notifications.splice(firstOut, 1);
|
||||
buttons.splice(firstOut, 1);
|
||||
times.splice(firstOut, 1);
|
||||
heights.splice(firstOut, 1);
|
||||
myAlpha.splice(firstOut,1);
|
||||
function calculate3DOverlayPositions(noticeWidth, noticeHeight, y) {
|
||||
// Calculates overlay positions and orientations in avatar coordinates.
|
||||
var noticeY,
|
||||
originOffset,
|
||||
notificationOrientation,
|
||||
notificationPosition,
|
||||
buttonPosition;
|
||||
|
||||
// Notification plane positions
|
||||
noticeY = -y * NOTIFICATION_3D_SCALE - noticeHeight / 2;
|
||||
notificationPosition = { x: 0, y: noticeY, z: 0 };
|
||||
buttonPosition = { x: (noticeWidth - NOTIFICATION_3D_BUTTON_WIDTH) / 2, y: noticeY, z: 0.001 };
|
||||
|
||||
// Rotate plane
|
||||
notificationOrientation = Quat.fromPitchYawRollDegrees(NOTIFICATIONS_3D_PITCH,
|
||||
NOTIFICATIONS_3D_DIRECTION + NOTIFICATIONS_3D_YAW, 0);
|
||||
notificationPosition = Vec3.multiplyQbyV(notificationOrientation, notificationPosition);
|
||||
buttonPosition = Vec3.multiplyQbyV(notificationOrientation, buttonPosition);
|
||||
|
||||
// Translate plane
|
||||
originOffset = Vec3.multiplyQbyV(Quat.fromPitchYawRollDegrees(0, NOTIFICATIONS_3D_DIRECTION, 0),
|
||||
{ x: 0, y: 0, z: -NOTIFICATIONS_3D_DISTANCE });
|
||||
originOffset.y += NOTIFICATIONS_3D_ELEVATION;
|
||||
notificationPosition = Vec3.sum(originOffset, notificationPosition);
|
||||
buttonPosition = Vec3.sum(originOffset, buttonPosition);
|
||||
|
||||
return {
|
||||
notificationOrientation: notificationOrientation,
|
||||
notificationPosition: notificationPosition,
|
||||
buttonPosition: buttonPosition
|
||||
};
|
||||
}
|
||||
|
||||
// This reports the number of users online at startup
|
||||
function reportUsers() {
|
||||
var numUsers = GlobalServices.onlineUsers.length;
|
||||
var welcome = "Welcome! There are " + numUsers + " users online now.";
|
||||
createNotification(welcome);
|
||||
// Pushes data to each array and sets up data for 2nd dimension array
|
||||
// to handle auxiliary data not carried by the overlay class
|
||||
// specifically notification "heights", "times" of creation, and .
|
||||
function notify(notice, button, height) {
|
||||
var noticeWidth,
|
||||
noticeHeight,
|
||||
positions,
|
||||
last;
|
||||
|
||||
if (isOnHMD) {
|
||||
// Calculate 3D values from 2D overlay properties.
|
||||
|
||||
noticeWidth = notice.width * NOTIFICATION_3D_SCALE + NOTIFICATION_3D_BUTTON_WIDTH;
|
||||
noticeHeight = notice.height * NOTIFICATION_3D_SCALE;
|
||||
|
||||
notice.size = { x: noticeWidth, y: noticeHeight };
|
||||
notice.topMargin = 0.75 * notice.topMargin * NOTIFICATION_3D_SCALE;
|
||||
notice.leftMargin = 2 * notice.leftMargin * NOTIFICATION_3D_SCALE;
|
||||
notice.bottomMargin = 0;
|
||||
notice.rightMargin = 0;
|
||||
notice.lineHeight = 10.0 * (fontSize / 12.0) * NOTIFICATION_3D_SCALE;
|
||||
notice.isFacingAvatar = false;
|
||||
|
||||
button.url = button.imageURL;
|
||||
button.scale = button.width * NOTIFICATION_3D_SCALE;
|
||||
button.isFacingAvatar = false;
|
||||
|
||||
positions = calculate3DOverlayPositions(noticeWidth, noticeHeight, notice.y);
|
||||
|
||||
notifications.push((Overlays.addOverlay("text3d", notice)));
|
||||
buttons.push((Overlays.addOverlay("billboard", button)));
|
||||
overlay3DDetails.push({
|
||||
notificationOrientation: positions.notificationOrientation,
|
||||
notificationPosition: positions.notificationPosition,
|
||||
buttonPosition: positions.buttonPosition,
|
||||
width: noticeWidth,
|
||||
height: noticeHeight
|
||||
});
|
||||
} else {
|
||||
notifications.push((Overlays.addOverlay("text", notice)));
|
||||
buttons.push((Overlays.addOverlay("image", button)));
|
||||
}
|
||||
|
||||
height = height + 1.0;
|
||||
heights.push(height);
|
||||
times.push(new Date().getTime() / 1000);
|
||||
myAlpha.push(0);
|
||||
last = notifications.length - 1;
|
||||
createArrays(notifications[last], buttons[last], times[last], heights[last], myAlpha[last]);
|
||||
fadeIn(notifications[last], buttons[last]);
|
||||
}
|
||||
|
||||
// This function creates and sizes the overlays
|
||||
function createNotification(text) {
|
||||
var count = (text.match(/\n/g) || []).length,
|
||||
breakPoint = 43.0, // length when new line is added
|
||||
extraLine = 0,
|
||||
breaks = 0,
|
||||
height = 40.0,
|
||||
stack = 0,
|
||||
level,
|
||||
noticeProperties,
|
||||
bLevel,
|
||||
buttonProperties,
|
||||
i;
|
||||
|
||||
if (text.length >= breakPoint) {
|
||||
breaks = count;
|
||||
}
|
||||
extraLine = breaks * 16.0;
|
||||
for (i = 0; i < heights.length; i += 1) {
|
||||
stack = stack + heights[i];
|
||||
}
|
||||
|
||||
level = (stack + 20.0);
|
||||
height = height + extraLine;
|
||||
noticeProperties = {
|
||||
x: overlayLocationX,
|
||||
y: level,
|
||||
width: width,
|
||||
height: height,
|
||||
color: textColor,
|
||||
backgroundColor: backColor,
|
||||
alpha: backgroundAlpha,
|
||||
topMargin: topMargin,
|
||||
leftMargin: leftMargin,
|
||||
font: {size: fontSize},
|
||||
text: text
|
||||
};
|
||||
|
||||
bLevel = level + 12.0;
|
||||
buttonProperties = {
|
||||
x: buttonLocationX,
|
||||
y: bLevel,
|
||||
width: 10.0,
|
||||
height: 10.0,
|
||||
subImage: { x: 0, y: 0, width: 10, height: 10 },
|
||||
imageURL: "http://hifi-public.s3.amazonaws.com/images/close-small-light.svg",
|
||||
color: { red: 255, green: 255, blue: 255},
|
||||
visible: true,
|
||||
alpha: backgroundAlpha
|
||||
};
|
||||
|
||||
notify(noticeProperties, buttonProperties, height);
|
||||
}
|
||||
|
||||
function deleteNotification(index) {
|
||||
Overlays.deleteOverlay(notifications[index]);
|
||||
Overlays.deleteOverlay(buttons[index]);
|
||||
notifications.splice(index, 1);
|
||||
buttons.splice(index, 1);
|
||||
times.splice(index, 1);
|
||||
heights.splice(index, 1);
|
||||
myAlpha.splice(index, 1);
|
||||
overlay3DDetails.splice(index, 1);
|
||||
arrays.splice(index, 1);
|
||||
}
|
||||
|
||||
// wraps whole word to newline
|
||||
function stringDivider(str, slotWidth, spaceReplacer) {
|
||||
var p,
|
||||
left,
|
||||
right;
|
||||
|
||||
if (str.length > slotWidth) {
|
||||
p = slotWidth;
|
||||
while (p > 0 && str[p] !== ' ') {
|
||||
p -= 1;
|
||||
}
|
||||
|
||||
if (p > 0) {
|
||||
left = str.substring(0, p);
|
||||
right = str.substring(p + 1);
|
||||
return left + spaceReplacer + stringDivider(right, slotWidth, spaceReplacer);
|
||||
}
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
// formats string to add newline every 43 chars
|
||||
function wordWrap(str) {
|
||||
var result = stringDivider(str, 43.0, "\n");
|
||||
createNotification(result);
|
||||
}
|
||||
|
||||
// This fires a notification on window resize
|
||||
function checkSize() {
|
||||
if ((Window.innerWidth !== ourWidth) || (Window.innerHeight !== ourHeight)) {
|
||||
var windowResize = "Window has been resized";
|
||||
ourWidth = Window.innerWidth;
|
||||
ourHeight = Window.innerHeight;
|
||||
windowDimensions = Controller.getViewportDimensions();
|
||||
overlayLocationX = (windowDimensions.x - (width + 60.0));
|
||||
buttonLocationX = overlayLocationX + (width - 35.0);
|
||||
createNotification(windowResize);
|
||||
}
|
||||
}
|
||||
|
||||
function update() {
|
||||
var nextOverlay,
|
||||
noticeOut,
|
||||
buttonOut,
|
||||
arraysOut,
|
||||
defaultEyePosition,
|
||||
avatarOrientation,
|
||||
notificationPosition,
|
||||
notificationOrientation,
|
||||
buttonPosition,
|
||||
positions,
|
||||
i,
|
||||
j,
|
||||
k;
|
||||
|
||||
if (isOnHMD !== Menu.isOptionChecked(ENABLE_VR_MODE)) {
|
||||
while (arrays.length > 0) {
|
||||
deleteNotification(0);
|
||||
}
|
||||
isOnHMD = !isOnHMD;
|
||||
persistTime = isOnHMD ? PERSIST_TIME_3D : PERSIST_TIME_2D;
|
||||
return;
|
||||
}
|
||||
|
||||
frame += 1;
|
||||
if ((frame % 60.0) === 0) { // only update once a second
|
||||
checkSize(); // checks for size change to trigger windowResize notification
|
||||
locationY = 20.0;
|
||||
for (i = 0; i < arrays.length; i += 1) { //repositions overlays as others fade
|
||||
nextOverlay = Overlays.getOverlayAtPoint({ x: overlayLocationX, y: locationY });
|
||||
Overlays.editOverlay(notifications[i], { x: overlayLocationX, y: locationY });
|
||||
Overlays.editOverlay(buttons[i], { x: buttonLocationX, y: locationY + 12.0 });
|
||||
if (isOnHMD) {
|
||||
positions = calculate3DOverlayPositions(overlay3DDetails[i].width, overlay3DDetails[i].height, locationY);
|
||||
overlay3DDetails[i].notificationOrientation = positions.notificationOrientation;
|
||||
overlay3DDetails[i].notificationPosition = positions.notificationPosition;
|
||||
overlay3DDetails[i].buttonPosition = positions.buttonPosition;
|
||||
}
|
||||
locationY = locationY + arrays[i][3];
|
||||
}
|
||||
}
|
||||
|
||||
// This checks the age of the notification and prepares to fade it after 9.0 seconds (var persistTime - 1)
|
||||
for (i = 0; i < arrays.length; i += 1) {
|
||||
if (ready) {
|
||||
j = arrays[i][2];
|
||||
k = j + persistTime;
|
||||
if (k < (new Date().getTime() / 1000)) {
|
||||
ready = false;
|
||||
noticeOut = arrays[i][0];
|
||||
buttonOut = arrays[i][1];
|
||||
arraysOut = i;
|
||||
fadeOut(noticeOut, buttonOut, arraysOut);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (isOnHMD && notifications.length > 0) {
|
||||
// Update 3D overlays to maintain positions relative to avatar
|
||||
defaultEyePosition = MyAvatar.getDefaultEyePosition();
|
||||
avatarOrientation = MyAvatar.orientation;
|
||||
|
||||
for (i = 0; i < notifications.length; i += 1) {
|
||||
notificationPosition = Vec3.sum(defaultEyePosition,
|
||||
Vec3.multiplyQbyV(avatarOrientation, overlay3DDetails[i].notificationPosition));
|
||||
notificationOrientation = Quat.multiply(avatarOrientation, overlay3DDetails[i].notificationOrientation);
|
||||
buttonPosition = Vec3.sum(defaultEyePosition,
|
||||
Vec3.multiplyQbyV(avatarOrientation, overlay3DDetails[i].buttonPosition));
|
||||
Overlays.editOverlay(notifications[i], { position: notificationPosition, rotation: notificationOrientation });
|
||||
Overlays.editOverlay(buttons[i], { position: buttonPosition, rotation: notificationOrientation });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var STARTUP_TIMEOUT = 500, // ms
|
||||
startingUp = true,
|
||||
startupTimer = null;
|
||||
|
||||
// This reports the number of users online at startup
|
||||
function reportUsers() {
|
||||
var welcome;
|
||||
|
||||
welcome = "Welcome! There are " + GlobalServices.onlineUsers.length + " users online now.";
|
||||
createNotification(welcome);
|
||||
}
|
||||
|
||||
function finishStartup() {
|
||||
startingUp = false;
|
||||
Script.clearTimeout(startupTimer);
|
||||
|
@ -378,6 +445,113 @@ function isStartingUp() {
|
|||
return startingUp;
|
||||
}
|
||||
|
||||
// Triggers notification if a user logs on or off
|
||||
function onOnlineUsersChanged(users) {
|
||||
var i;
|
||||
|
||||
if (!isStartingUp()) { // Skip user notifications at startup.
|
||||
for (i = 0; i < users.length; i += 1) {
|
||||
if (last_users.indexOf(users[i]) === -1.0) {
|
||||
createNotification(users[i] + " has joined");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
for (i = 0; i < last_users.length; i += 1) {
|
||||
if (users.indexOf(last_users[i]) === -1.0) {
|
||||
createNotification(last_users[i] + " has left");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
last_users = users;
|
||||
}
|
||||
|
||||
// Triggers notification if @MyUserName is mentioned in chat and returns the message to the notification.
|
||||
function onIncomingMessage(user, message) {
|
||||
var myMessage,
|
||||
alertMe,
|
||||
thisAlert;
|
||||
|
||||
myMessage = message;
|
||||
alertMe = "@" + GlobalServices.myUsername;
|
||||
thisAlert = user + ": " + myMessage;
|
||||
|
||||
if (myMessage.indexOf(alertMe) > -1.0) {
|
||||
wordWrap(thisAlert);
|
||||
}
|
||||
}
|
||||
|
||||
// Triggers mic mute notification
|
||||
function onMuteStateChanged() {
|
||||
var muteState,
|
||||
muteString;
|
||||
|
||||
muteState = AudioDevice.getMuted() ? "muted" : "unmuted";
|
||||
muteString = "Microphone is now " + muteState;
|
||||
createNotification(muteString);
|
||||
}
|
||||
|
||||
// handles mouse clicks on buttons
|
||||
function mousePressEvent(event) {
|
||||
var pickRay,
|
||||
clickedOverlay,
|
||||
i;
|
||||
|
||||
if (isOnHMD) {
|
||||
pickRay = Camera.computePickRay(event.x, event.y);
|
||||
clickedOverlay = Overlays.findRayIntersection(pickRay).overlayID;
|
||||
} else {
|
||||
clickedOverlay = Overlays.getOverlayAtPoint({ x: event.x, y: event.y });
|
||||
}
|
||||
|
||||
for (i = 0; i < buttons.length; i += 1) {
|
||||
if (clickedOverlay === buttons[i]) {
|
||||
deleteNotification(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Control key remains active only while key is held down
|
||||
function keyReleaseEvent(key) {
|
||||
if (key.key === 16777249) {
|
||||
ctrlIsPressed = false;
|
||||
}
|
||||
}
|
||||
|
||||
// Triggers notification on specific key driven events
|
||||
function keyPressEvent(key) {
|
||||
var numUsers,
|
||||
welcome,
|
||||
noteString;
|
||||
|
||||
if (key.key === 16777249) {
|
||||
ctrlIsPressed = true;
|
||||
}
|
||||
|
||||
if (key.text === "q") { //queries number of users online
|
||||
numUsers = GlobalServices.onlineUsers.length;
|
||||
welcome = "There are " + numUsers + " users online now.";
|
||||
createNotification(welcome);
|
||||
}
|
||||
|
||||
if (key.text === "s") {
|
||||
if (ctrlIsPressed === true) {
|
||||
noteString = "Snapshot taken.";
|
||||
createNotification(noteString);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// When our script shuts down, we should clean up all of our overlays
|
||||
function scriptEnding() {
|
||||
var i;
|
||||
|
||||
for (i = 0; i < notifications.length; i += 1) {
|
||||
Overlays.deleteOverlay(notifications[i]);
|
||||
Overlays.deleteOverlay(buttons[i]);
|
||||
}
|
||||
}
|
||||
|
||||
AudioDevice.muteToggled.connect(onMuteStateChanged);
|
||||
Controller.keyPressEvent.connect(keyPressEvent);
|
||||
|
@ -386,3 +560,4 @@ GlobalServices.onlineUsersChanged.connect(onOnlineUsersChanged);
|
|||
GlobalServices.incomingMessage.connect(onIncomingMessage);
|
||||
Controller.keyReleaseEvent.connect(keyReleaseEvent);
|
||||
Script.update.connect(update);
|
||||
Script.scriptEnding.connect(scriptEnding);
|
||||
|
|
182
examples/popcorn.js
Normal file
182
examples/popcorn.js
Normal file
|
@ -0,0 +1,182 @@
|
|||
//
|
||||
// popcorn.js
|
||||
// examples
|
||||
//
|
||||
// Created by Philip Rosedale on January 25, 2014
|
||||
// Copyright 2015 High Fidelity, Inc.
|
||||
//
|
||||
// Creates a bunch of physical balls trapped in a box with a rotating wall in the middle that smacks them around,
|
||||
// and a periodic 'pop' force that shoots them into the air.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
var BALL_SIZE = 0.07;
|
||||
var WALL_THICKNESS = 0.10;
|
||||
var SCALE = 1.0;
|
||||
|
||||
var GRAVITY = -1.0;
|
||||
var LIFETIME = 600;
|
||||
var DAMPING = 0.50;
|
||||
|
||||
var center = Vec3.sum(MyAvatar.position, Vec3.multiply(SCALE * 3.0, Quat.getFront(Camera.getOrientation())));
|
||||
|
||||
var floor = Entities.addEntity(
|
||||
{ type: "Box",
|
||||
position: Vec3.subtract(center, { x: 0, y: SCALE / 2.0, z: 0 }),
|
||||
dimensions: { x: SCALE, y: WALL_THICKNESS, z: SCALE },
|
||||
color: { red: 0, green: 255, blue: 0 },
|
||||
gravity: { x: 0, y: 0, z: 0 },
|
||||
ignoreCollisions: false,
|
||||
lifetime: LIFETIME });
|
||||
|
||||
var ceiling = Entities.addEntity(
|
||||
{ type: "Box",
|
||||
position: Vec3.sum(center, { x: 0, y: SCALE / 2.0, z: 0 }),
|
||||
dimensions: { x: SCALE, y: WALL_THICKNESS, z: SCALE },
|
||||
color: { red: 128, green: 128, blue: 128 },
|
||||
gravity: { x: 0, y: 0, z: 0 },
|
||||
ignoreCollisions: false,
|
||||
visible: true,
|
||||
lifetime: LIFETIME });
|
||||
|
||||
var wall1 = Entities.addEntity(
|
||||
{ type: "Box",
|
||||
position: Vec3.sum(center, { x: SCALE / 2.0, y: 0, z: 0 }),
|
||||
dimensions: { x: WALL_THICKNESS, y: SCALE, z: SCALE },
|
||||
color: { red: 0, green: 255, blue: 0 },
|
||||
gravity: { x: 0, y: 0, z: 0 },
|
||||
ignoreCollisions: false,
|
||||
visible: false,
|
||||
lifetime: LIFETIME });
|
||||
|
||||
var wall2 = Entities.addEntity(
|
||||
{ type: "Box",
|
||||
position: Vec3.subtract(center, { x: SCALE / 2.0, y: 0, z: 0 }),
|
||||
dimensions: { x: WALL_THICKNESS, y: SCALE, z: SCALE },
|
||||
color: { red: 0, green: 255, blue: 0 },
|
||||
gravity: { x: 0, y: 0, z: 0 },
|
||||
ignoreCollisions: false,
|
||||
visible: false,
|
||||
lifetime: LIFETIME });
|
||||
|
||||
var wall3 = Entities.addEntity(
|
||||
{ type: "Box",
|
||||
position: Vec3.subtract(center, { x: 0, y: 0, z: SCALE / 2.0 }),
|
||||
dimensions: { x: SCALE, y: SCALE, z: WALL_THICKNESS },
|
||||
color: { red: 0, green: 255, blue: 0 },
|
||||
gravity: { x: 0, y: 0, z: 0 },
|
||||
ignoreCollisions: false,
|
||||
visible: false,
|
||||
lifetime: LIFETIME });
|
||||
|
||||
var wall4 = Entities.addEntity(
|
||||
{ type: "Box",
|
||||
position: Vec3.sum(center, { x: 0, y: 0, z: SCALE / 2.0 }),
|
||||
dimensions: { x: SCALE, y: SCALE, z: WALL_THICKNESS },
|
||||
color: { red: 0, green: 255, blue: 0 },
|
||||
gravity: { x: 0, y: 0, z: 0 },
|
||||
ignoreCollisions: false,
|
||||
visible: false,
|
||||
lifetime: LIFETIME });
|
||||
|
||||
var corner1 = Entities.addEntity(
|
||||
{ type: "Box",
|
||||
position: Vec3.sum(center, { x: -SCALE / 2.0, y: 0, z: SCALE / 2.0 }),
|
||||
dimensions: { x: WALL_THICKNESS, y: SCALE, z: WALL_THICKNESS },
|
||||
color: { red: 128, green: 128, blue: 128 },
|
||||
ignoreCollisions: false,
|
||||
visible: true,
|
||||
lifetime: LIFETIME });
|
||||
|
||||
var corner2 = Entities.addEntity(
|
||||
{ type: "Box",
|
||||
position: Vec3.sum(center, { x: -SCALE / 2.0, y: 0, z: -SCALE / 2.0 }),
|
||||
dimensions: { x: WALL_THICKNESS, y: SCALE, z: WALL_THICKNESS },
|
||||
color: { red: 128, green: 128, blue: 128 },
|
||||
ignoreCollisions: false,
|
||||
visible: true,
|
||||
lifetime: LIFETIME });
|
||||
|
||||
var corner3 = Entities.addEntity(
|
||||
{ type: "Box",
|
||||
position: Vec3.sum(center, { x: SCALE / 2.0, y: 0, z: SCALE / 2.0 }),
|
||||
dimensions: { x: WALL_THICKNESS, y: SCALE, z: WALL_THICKNESS },
|
||||
color: { red: 128, green: 128, blue: 128 },
|
||||
ignoreCollisions: false,
|
||||
visible: true,
|
||||
lifetime: LIFETIME });
|
||||
|
||||
var corner4 = Entities.addEntity(
|
||||
{ type: "Box",
|
||||
position: Vec3.sum(center, { x: SCALE / 2.0, y: 0, z: -SCALE / 2.0 }),
|
||||
dimensions: { x: WALL_THICKNESS, y: SCALE, z: WALL_THICKNESS },
|
||||
color: { red: 128, green: 128, blue: 128 },
|
||||
ignoreCollisions: false,
|
||||
visible: true,
|
||||
lifetime: LIFETIME });
|
||||
|
||||
var spinner = Entities.addEntity(
|
||||
{ type: "Box",
|
||||
position: center,
|
||||
dimensions: { x: SCALE / 1.5, y: SCALE / 3.0, z: SCALE / 8.0 },
|
||||
color: { red: 255, green: 0, blue: 0 },
|
||||
angularVelocity: { x: 0, y: 360, z: 0 },
|
||||
angularDamping: 0.0,
|
||||
gravity: { x: 0, y: 0, z: 0 },
|
||||
ignoreCollisions: false,
|
||||
visible: true,
|
||||
lifetime: LIFETIME });
|
||||
|
||||
var NUM_BALLS = 70;
|
||||
|
||||
balls = [];
|
||||
|
||||
for (var i = 0; i < NUM_BALLS; i++) {
|
||||
balls.push(Entities.addEntity(
|
||||
{ type: "Sphere",
|
||||
position: { x: center.x + (Math.random() - 0.5) * (SCALE - BALL_SIZE - WALL_THICKNESS),
|
||||
y: center.y + (Math.random() - 0.5) * (SCALE - BALL_SIZE - WALL_THICKNESS) ,
|
||||
z: center.z + (Math.random() - 0.5) * (SCALE - BALL_SIZE - WALL_THICKNESS) },
|
||||
dimensions: { x: BALL_SIZE, y: BALL_SIZE, z: BALL_SIZE },
|
||||
color: { red: Math.random() * 255, green: Math.random() * 255, blue: Math.random() * 255 },
|
||||
gravity: { x: 0, y: GRAVITY, z: 0 },
|
||||
ignoreCollisions: false,
|
||||
damping: DAMPING,
|
||||
lifetime: LIFETIME,
|
||||
collisionsWillMove: true }));
|
||||
}
|
||||
|
||||
var VEL_MAG = 2.0;
|
||||
var CHANCE_OF_POP = 0.007; // 0.01;
|
||||
function update(deltaTime) {
|
||||
for (var i = 0; i < NUM_BALLS; i++) {
|
||||
if (Math.random() < CHANCE_OF_POP) {
|
||||
Entities.editEntity(balls[i], { velocity: { x: (Math.random() - 0.5) * VEL_MAG, y: Math.random() * VEL_MAG, z: (Math.random() - 0.5) * VEL_MAG }});
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
function scriptEnding() {
|
||||
Entities.deleteEntity(wall1);
|
||||
Entities.deleteEntity(wall2);
|
||||
Entities.deleteEntity(wall3);
|
||||
Entities.deleteEntity(wall4);
|
||||
Entities.deleteEntity(corner1);
|
||||
Entities.deleteEntity(corner2);
|
||||
Entities.deleteEntity(corner3);
|
||||
Entities.deleteEntity(corner4);
|
||||
Entities.deleteEntity(floor);
|
||||
Entities.deleteEntity(ceiling);
|
||||
Entities.deleteEntity(spinner);
|
||||
|
||||
for (var i = 0; i < NUM_BALLS; i++) {
|
||||
Entities.deleteEntity(balls[i]);
|
||||
}
|
||||
}
|
||||
|
||||
Script.scriptEnding.connect(scriptEnding);
|
||||
Script.update.connect(update);
|
|
@ -98,8 +98,16 @@ function setupAudioMenus() {
|
|||
}
|
||||
}
|
||||
|
||||
function onDevicechanged() {
|
||||
Menu.removeMenu("Tools > Audio");
|
||||
setupAudioMenus();
|
||||
}
|
||||
|
||||
// Have a small delay before the menu's get setup and the audio devices can switch to the last selected ones
|
||||
Script.setTimeout(function() { setupAudioMenus(); }, 5000);
|
||||
Script.setTimeout(function () {
|
||||
AudioDevice.deviceChanged.connect(onDevicechanged);
|
||||
setupAudioMenus();
|
||||
}, 5000);
|
||||
|
||||
function scriptEnding() {
|
||||
Menu.removeMenu("Tools > Audio");
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
//
|
||||
|
||||
HIFI_PUBLIC_BUCKET = "http://s3.amazonaws.com/hifi-public/";
|
||||
Script.include("libraries/toolBars.js");
|
||||
Script.include("../../libraries/toolBars.js");
|
||||
|
||||
var recordingFile = "recording.rec";
|
||||
|
||||
|
|
|
@ -18,6 +18,10 @@ function setupMenus() {
|
|||
}
|
||||
if (!Menu.menuExists("Developer > Entities")) {
|
||||
Menu.addMenu("Developer > Entities");
|
||||
|
||||
// NOTE: these menu items aren't currently working. I've temporarily removed them. Will add them back once we
|
||||
// rewire these to work
|
||||
/*
|
||||
Menu.addMenuItem({ menuName: "Developer > Entities", menuItemName: "Display Model Bounds", isCheckable: true, isChecked: false });
|
||||
Menu.addMenuItem({ menuName: "Developer > Entities", menuItemName: "Display Model Triangles", isCheckable: true, isChecked: false });
|
||||
Menu.addMenuItem({ menuName: "Developer > Entities", menuItemName: "Display Model Element Bounds", isCheckable: true, isChecked: false });
|
||||
|
@ -26,9 +30,26 @@ function setupMenus() {
|
|||
Menu.addMenuItem({ menuName: "Developer > Entities", menuItemName: "Don't Attempt Render Entities as Scene", isCheckable: true, isChecked: false });
|
||||
Menu.addMenuItem({ menuName: "Developer > Entities", menuItemName: "Don't Do Precision Picking", isCheckable: true, isChecked: false });
|
||||
Menu.addMenuItem({ menuName: "Developer > Entities", menuItemName: "Disable Light Entities", isCheckable: true, isChecked: false });
|
||||
*/
|
||||
Menu.addMenuItem({ menuName: "Developer > Entities", menuItemName: "Don't send collision updates to server", isCheckable: true, isChecked: false });
|
||||
}
|
||||
}
|
||||
|
||||
Menu.menuItemEvent.connect(function (menuItem) {
|
||||
print("menuItemEvent() in JS... menuItem=" + menuItem);
|
||||
|
||||
if (menuItem == "Don't send collision updates to server") {
|
||||
var dontSendUpdates = Menu.isOptionChecked("Don't send collision updates to server");
|
||||
print(" dontSendUpdates... checked=" + dontSendUpdates);
|
||||
Entities.setSendPhysicsUpdates(!dontSendUpdates);
|
||||
}
|
||||
});
|
||||
|
||||
setupMenus();
|
||||
|
||||
// register our scriptEnding callback
|
||||
Script.scriptEnding.connect(scriptEnding);
|
||||
|
||||
function scriptEnding() {
|
||||
Menu.removeMenu("Developer > Entities");
|
||||
}
|
||||
|
|
|
@ -83,12 +83,18 @@ if (APPLE)
|
|||
|
||||
set(MACOSX_BUNDLE_BUNDLE_NAME Interface)
|
||||
set(MACOSX_BUNDLE_GUI_IDENTIFIER io.highfidelity.Interface)
|
||||
|
||||
|
||||
if (${CMAKE_BUILD_TYPE} MATCHES "RELEASE")
|
||||
set(ICON_FILENAME "interface.icns")
|
||||
else ()
|
||||
set(ICON_FILENAME "interface-beta.icns")
|
||||
endif ()
|
||||
|
||||
# set how the icon shows up in the Info.plist file
|
||||
SET(MACOSX_BUNDLE_ICON_FILE interface.icns)
|
||||
SET(MACOSX_BUNDLE_ICON_FILE "${ICON_FILENAME}")
|
||||
|
||||
# set where in the bundle to put the resources file
|
||||
SET_SOURCE_FILES_PROPERTIES(${CMAKE_CURRENT_SOURCE_DIR}/interface.icns PROPERTIES MACOSX_PACKAGE_LOCATION Resources)
|
||||
SET_SOURCE_FILES_PROPERTIES(${CMAKE_CURRENT_SOURCE_DIR}/icon/${ICON_FILENAME} PROPERTIES MACOSX_PACKAGE_LOCATION Resources)
|
||||
|
||||
# grab the directories in resources and put them in the right spot in Resources
|
||||
file(GLOB RESOURCE_SUBDIRS RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}/resources" "${CMAKE_CURRENT_SOURCE_DIR}/resources/*")
|
||||
|
@ -101,7 +107,7 @@ if (APPLE)
|
|||
endif()
|
||||
endforeach()
|
||||
|
||||
SET(INTERFACE_SRCS ${INTERFACE_SRCS} "${CMAKE_CURRENT_SOURCE_DIR}/interface.icns")
|
||||
SET(INTERFACE_SRCS ${INTERFACE_SRCS} "${CMAKE_CURRENT_SOURCE_DIR}/icon/${ICON_FILENAME}")
|
||||
endif()
|
||||
|
||||
# create the executable, make it a bundle on OS X
|
||||
|
|
BIN
interface/icon/interface-beta.icns
Normal file
BIN
interface/icon/interface-beta.icns
Normal file
Binary file not shown.
BIN
interface/icon/interface-beta.ico
Normal file
BIN
interface/icon/interface-beta.ico
Normal file
Binary file not shown.
After Width: | Height: | Size: 361 KiB |
BIN
interface/icon/interface.icns
Normal file
BIN
interface/icon/interface.icns
Normal file
Binary file not shown.
BIN
interface/icon/interface.ico
Normal file
BIN
interface/icon/interface.ico
Normal file
Binary file not shown.
After Width: | Height: | Size: 361 KiB |
Binary file not shown.
|
@ -38,8 +38,8 @@
|
|||
#include <QObject>
|
||||
#include <QWheelEvent>
|
||||
#include <QScreen>
|
||||
#include <QSettings>
|
||||
#include <QShortcut>
|
||||
#include <QSystemTrayIcon>
|
||||
#include <QTimer>
|
||||
#include <QUrl>
|
||||
#include <QWindow>
|
||||
|
@ -73,13 +73,16 @@
|
|||
#include <PhysicsEngine.h>
|
||||
#include <ProgramObject.h>
|
||||
#include <ResourceCache.h>
|
||||
#include <Settings.h>
|
||||
#include <SoundCache.h>
|
||||
#include <TextRenderer.h>
|
||||
#include <UserActivityLogger.h>
|
||||
#include <UUID.h>
|
||||
|
||||
#include "Application.h"
|
||||
#include "Audio.h"
|
||||
#include "InterfaceVersion.h"
|
||||
#include "LODManager.h"
|
||||
#include "Menu.h"
|
||||
#include "ModelUploader.h"
|
||||
#include "Util.h"
|
||||
|
@ -100,7 +103,6 @@
|
|||
#include "gpu/Batch.h"
|
||||
#include "gpu/GLBackend.h"
|
||||
|
||||
|
||||
#include "scripting/AccountScriptingInterface.h"
|
||||
#include "scripting/AudioDeviceScriptingInterface.h"
|
||||
#include "scripting/ClipboardScriptingInterface.h"
|
||||
|
@ -112,9 +114,16 @@
|
|||
#include "scripting/WindowScriptingInterface.h"
|
||||
#include "scripting/WebWindowClass.h"
|
||||
|
||||
#if defined(Q_OS_MAC) || defined(Q_OS_WIN)
|
||||
#include "SpeechRecognizer.h"
|
||||
#endif
|
||||
|
||||
#include "ui/DataWebDialog.h"
|
||||
#include "ui/DialogsManager.h"
|
||||
#include "ui/InfoView.h"
|
||||
#include "ui/LoginDialog.h"
|
||||
#include "ui/Snapshot.h"
|
||||
#include "ui/StandAloneJSConsole.h"
|
||||
#include "ui/Stats.h"
|
||||
|
||||
|
||||
|
@ -137,6 +146,12 @@ const QString SKIP_FILENAME = QStandardPaths::writableLocation(QStandardPaths::D
|
|||
|
||||
const QString DEFAULT_SCRIPTS_JS_URL = "http://s3.amazonaws.com/hifi-public/scripts/defaultScripts.js";
|
||||
|
||||
namespace SettingHandles {
|
||||
const SettingHandle<bool> firstRun("firstRun", true);
|
||||
const SettingHandle<QString> lastScriptLocation("LastScriptLocation");
|
||||
const SettingHandle<QString> scriptsLocation("scriptsLocation");
|
||||
}
|
||||
|
||||
void messageHandler(QtMsgType type, const QMessageLogContext& context, const QString& message) {
|
||||
QString logMessage = LogHandler::getInstance().printMessage((LogMsgType) type, context, message);
|
||||
|
||||
|
@ -153,6 +168,16 @@ bool setupEssentials(int& argc, char** argv) {
|
|||
listenPort = atoi(portStr);
|
||||
}
|
||||
|
||||
// read the ApplicationInfo.ini file for Name/Version/Domain information
|
||||
QSettings::setDefaultFormat(QSettings::IniFormat);
|
||||
QSettings applicationInfo(PathUtils::resourcesPath() + "info/ApplicationInfo.ini", QSettings::IniFormat);
|
||||
// set the associated application properties
|
||||
applicationInfo.beginGroup("INFO");
|
||||
QApplication::setApplicationName(applicationInfo.value("name").toString());
|
||||
QApplication::setApplicationVersion(BUILD_VERSION);
|
||||
QApplication::setOrganizationName(applicationInfo.value("organizationName").toString());
|
||||
QApplication::setOrganizationDomain(applicationInfo.value("organizationDomain").toString());
|
||||
|
||||
DependencyManager::registerInheritance<LimitedNodeList, NodeList>();
|
||||
|
||||
// Set dependencies
|
||||
|
@ -173,6 +198,12 @@ bool setupEssentials(int& argc, char** argv) {
|
|||
auto ddeFaceTracker = DependencyManager::set<DdeFaceTracker>();
|
||||
auto modelBlender = DependencyManager::set<ModelBlender>();
|
||||
auto audioToolBox = DependencyManager::set<AudioToolBox>();
|
||||
auto lodManager = DependencyManager::set<LODManager>();
|
||||
auto jsConsole = DependencyManager::set<StandAloneJSConsole>();
|
||||
auto dialogsManager = DependencyManager::set<DialogsManager>();
|
||||
#if defined(Q_OS_MAC) || defined(Q_OS_WIN)
|
||||
auto speechRecognizer = DependencyManager::set<SpeechRecognizer>();
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -210,8 +241,10 @@ Application::Application(int& argc, char** argv, QElapsedTimer &startup_time) :
|
|||
_mousePressed(false),
|
||||
_enableProcessOctreeThread(true),
|
||||
_octreeProcessor(),
|
||||
_packetsPerSecond(0),
|
||||
_bytesPerSecond(0),
|
||||
_inPacketsPerSecond(0),
|
||||
_outPacketsPerSecond(0),
|
||||
_inBytesPerSecond(0),
|
||||
_outBytesPerSecond(0),
|
||||
_nodeBoundsDisplay(this),
|
||||
_previousScriptLocation(),
|
||||
_applicationOverlay(),
|
||||
|
@ -224,35 +257,21 @@ Application::Application(int& argc, char** argv, QElapsedTimer &startup_time) :
|
|||
_aboutToQuit(false),
|
||||
_notifiedPacketVersionMismatchThisDomain(false)
|
||||
{
|
||||
auto glCanvas = DependencyManager::get<GLCanvas>();
|
||||
auto nodeList = DependencyManager::get<NodeList>();
|
||||
_logger = new FileLogger(this); // After setting organization name in order to get correct directory
|
||||
qInstallMessageHandler(messageHandler);
|
||||
|
||||
QFontDatabase::addApplicationFont(PathUtils::resourcesPath() + "styles/Inconsolata.otf");
|
||||
_window->setWindowTitle("Interface");
|
||||
|
||||
Model::setAbstractViewStateInterface(this); // The model class will sometimes need to know view state details from us
|
||||
|
||||
|
||||
// read the ApplicationInfo.ini file for Name/Version/Domain information
|
||||
QSettings applicationInfo(PathUtils::resourcesPath() + "info/ApplicationInfo.ini", QSettings::IniFormat);
|
||||
|
||||
// set the associated application properties
|
||||
applicationInfo.beginGroup("INFO");
|
||||
|
||||
setApplicationName(applicationInfo.value("name").toString());
|
||||
setApplicationVersion(BUILD_VERSION);
|
||||
setOrganizationName(applicationInfo.value("organizationName").toString());
|
||||
setOrganizationDomain(applicationInfo.value("organizationDomain").toString());
|
||||
|
||||
_logger = new FileLogger(this); // After setting organization name in order to get correct directory
|
||||
|
||||
QSettings::setDefaultFormat(QSettings::IniFormat);
|
||||
auto glCanvas = DependencyManager::get<GLCanvas>();
|
||||
auto nodeList = DependencyManager::get<NodeList>();
|
||||
|
||||
_myAvatar = _avatarManager.getMyAvatar();
|
||||
|
||||
_applicationStartupTime = startup_time;
|
||||
|
||||
QFontDatabase::addApplicationFont(PathUtils::resourcesPath() + "styles/Inconsolata.otf");
|
||||
_window->setWindowTitle("Interface");
|
||||
|
||||
qInstallMessageHandler(messageHandler);
|
||||
|
||||
qDebug() << "[VERSION] Build sequence: " << qPrintable(applicationVersion());
|
||||
|
||||
_bookmarks = new Bookmarks(); // Before setting up the menu
|
||||
|
@ -281,6 +300,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer &startup_time) :
|
|||
auto audioIO = DependencyManager::get<Audio>();
|
||||
audioIO->moveToThread(audioThread);
|
||||
connect(audioThread, &QThread::started, audioIO.data(), &Audio::start);
|
||||
connect(audioIO.data(), SIGNAL(muteToggled()), this, SLOT(audioMuteToggled()));
|
||||
|
||||
audioThread->start();
|
||||
|
||||
|
@ -292,7 +312,8 @@ Application::Application(int& argc, char** argv, QElapsedTimer &startup_time) :
|
|||
connect(&domainHandler, SIGNAL(disconnectedFromDomain()), SLOT(updateWindowTitle()));
|
||||
connect(&domainHandler, SIGNAL(disconnectedFromDomain()), SLOT(clearDomainOctreeDetails()));
|
||||
connect(&domainHandler, &DomainHandler::settingsReceived, this, &Application::domainSettingsReceived);
|
||||
connect(&domainHandler, &DomainHandler::hostnameChanged, Menu::getInstance(), &Menu::clearLoginDialogDisplayedFlag);
|
||||
connect(&domainHandler, &DomainHandler::hostnameChanged,
|
||||
DependencyManager::get<AddressManager>().data(), &AddressManager::storeCurrentAddress);
|
||||
|
||||
// update our location every 5 seconds in the data-server, assuming that we are authenticated with one
|
||||
const qint64 DATA_SERVER_LOCATION_CHANGE_UPDATE_MSECS = 5 * 1000;
|
||||
|
@ -319,7 +340,8 @@ Application::Application(int& argc, char** argv, QElapsedTimer &startup_time) :
|
|||
|
||||
connect(&accountManager, &AccountManager::balanceChanged, this, &Application::updateWindowTitle);
|
||||
|
||||
connect(&accountManager, &AccountManager::authRequired, Menu::getInstance(), &Menu::loginForCurrentDomain);
|
||||
auto dialogsManager = DependencyManager::get<DialogsManager>();
|
||||
connect(&accountManager, &AccountManager::authRequired, dialogsManager.data(), &DialogsManager::showLoginDialog);
|
||||
connect(&accountManager, &AccountManager::usernameChanged, this, &Application::updateWindowTitle);
|
||||
|
||||
// once we have a profile in account manager make sure we generate a new keypair
|
||||
|
@ -340,9 +362,6 @@ Application::Application(int& argc, char** argv, QElapsedTimer &startup_time) :
|
|||
|
||||
connect(addressManager.data(), &AddressManager::rootPlaceNameChanged, this, &Application::updateWindowTitle);
|
||||
|
||||
_settings = new QSettings(this);
|
||||
_numChangedSettings = 0;
|
||||
|
||||
#ifdef _WIN32
|
||||
WSADATA WsaData;
|
||||
int wsaresult = WSAStartup(MAKEWORD(2,2), &WsaData);
|
||||
|
@ -383,7 +402,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer &startup_time) :
|
|||
|
||||
_window->setCentralWidget(glCanvas.data());
|
||||
|
||||
restoreSizeAndPosition();
|
||||
_window->restoreGeometry();
|
||||
|
||||
_window->setVisible(true);
|
||||
glCanvas->setFocusPolicy(Qt::StrongFocus);
|
||||
|
@ -417,23 +436,31 @@ Application::Application(int& argc, char** argv, QElapsedTimer &startup_time) :
|
|||
connect(this, SIGNAL(aboutToQuit()), this, SLOT(aboutToQuit()));
|
||||
|
||||
// check first run...
|
||||
QVariant firstRunValue = _settings->value("firstRun",QVariant(true));
|
||||
if (firstRunValue.isValid() && firstRunValue.toBool()) {
|
||||
bool firstRun = SettingHandles::firstRun.get();
|
||||
if (firstRun) {
|
||||
qDebug() << "This is a first run...";
|
||||
// clear the scripts, and set out script to our default scripts
|
||||
clearScriptsBeforeRunning();
|
||||
loadScript(DEFAULT_SCRIPTS_JS_URL);
|
||||
|
||||
QMutexLocker locker(&_settingsMutex);
|
||||
_settings->setValue("firstRun",QVariant(false));
|
||||
SettingHandles::firstRun.set(false);
|
||||
} else {
|
||||
// do this as late as possible so that all required subsystems are initialized
|
||||
loadScripts();
|
||||
|
||||
QMutexLocker locker(&_settingsMutex);
|
||||
_previousScriptLocation = _settings->value("LastScriptLocation", QVariant("")).toString();
|
||||
_previousScriptLocation = SettingHandles::lastScriptLocation.get();
|
||||
}
|
||||
|
||||
|
||||
loadSettings();
|
||||
int SAVE_SETTINGS_INTERVAL = 10 * MSECS_PER_SECOND; // Let's save every seconds for now
|
||||
connect(&_settingsTimer, &QTimer::timeout, this, &Application::saveSettings);
|
||||
connect(&_settingsThread, SIGNAL(started), &_settingsTimer, SLOT(start));
|
||||
connect(&_settingsThread, &QThread::finished, &_settingsTimer, &QTimer::deleteLater);
|
||||
_settingsTimer.moveToThread(&_settingsThread);
|
||||
_settingsTimer.setSingleShot(false);
|
||||
_settingsTimer.setInterval(SAVE_SETTINGS_INTERVAL);
|
||||
_settingsThread.start();
|
||||
|
||||
_trayIcon->show();
|
||||
|
||||
// set the local loopback interface for local sounds from audio scripts
|
||||
|
@ -454,12 +481,12 @@ void Application::aboutToQuit() {
|
|||
}
|
||||
|
||||
Application::~Application() {
|
||||
saveSettings();
|
||||
|
||||
_entities.getTree()->setSimulation(NULL);
|
||||
qInstallMessageHandler(NULL);
|
||||
|
||||
saveSettings();
|
||||
storeSizeAndPosition();
|
||||
_window->saveGeometry();
|
||||
|
||||
int DELAY_TIME = 1000;
|
||||
UserActivityLogger::getInstance().close(DELAY_TIME);
|
||||
|
@ -496,45 +523,6 @@ Application::~Application() {
|
|||
DependencyManager::destroy<GLCanvas>();
|
||||
}
|
||||
|
||||
void Application::saveSettings() {
|
||||
Menu::getInstance()->saveSettings();
|
||||
_rearMirrorTools->saveSettings(_settings);
|
||||
|
||||
_settings->sync();
|
||||
_numChangedSettings = 0;
|
||||
}
|
||||
|
||||
|
||||
void Application::restoreSizeAndPosition() {
|
||||
QRect available = desktop()->availableGeometry();
|
||||
|
||||
QMutexLocker locker(&_settingsMutex);
|
||||
_settings->beginGroup("Window");
|
||||
|
||||
int x = (int)loadSetting(_settings, "x", 0);
|
||||
int y = (int)loadSetting(_settings, "y", 0);
|
||||
_window->move(x, y);
|
||||
|
||||
int width = (int)loadSetting(_settings, "width", available.width());
|
||||
int height = (int)loadSetting(_settings, "height", available.height());
|
||||
_window->resize(width, height);
|
||||
|
||||
_settings->endGroup();
|
||||
}
|
||||
|
||||
void Application::storeSizeAndPosition() {
|
||||
QMutexLocker locker(&_settingsMutex);
|
||||
_settings->beginGroup("Window");
|
||||
|
||||
_settings->setValue("width", _window->rect().width());
|
||||
_settings->setValue("height", _window->rect().height());
|
||||
|
||||
_settings->setValue("x", _window->pos().x());
|
||||
_settings->setValue("y", _window->pos().y());
|
||||
|
||||
_settings->endGroup();
|
||||
}
|
||||
|
||||
void Application::initializeGL() {
|
||||
qDebug( "Created Display Window.");
|
||||
|
||||
|
@ -657,7 +645,7 @@ void Application::paintGL() {
|
|||
_myCamera.update(1.0f / _fps);
|
||||
}
|
||||
|
||||
if (Menu::getInstance()->getShadowsEnabled()) {
|
||||
if (getShadowsEnabled()) {
|
||||
updateShadowMap();
|
||||
}
|
||||
|
||||
|
@ -713,6 +701,24 @@ void Application::paintGL() {
|
|||
_frameCount++;
|
||||
}
|
||||
|
||||
void Application::runTests() {
|
||||
runTimingTests();
|
||||
}
|
||||
|
||||
void Application::audioMuteToggled() {
|
||||
QAction* muteAction = Menu::getInstance()->getActionForOption(MenuOption::MuteAudio);
|
||||
Q_CHECK_PTR(muteAction);
|
||||
muteAction->setChecked(DependencyManager::get<Audio>()->isMuted());
|
||||
}
|
||||
|
||||
void Application::aboutApp() {
|
||||
InfoView::forcedShow(INFO_HELP_PATH);
|
||||
}
|
||||
|
||||
void Application::showEditEntitiesHelp() {
|
||||
InfoView::forcedShow(INFO_EDIT_ENTITIES_PATH);
|
||||
}
|
||||
|
||||
void Application::resetCamerasOnResizeGL(Camera& camera, int width, int height) {
|
||||
if (OculusManager::isConnected()) {
|
||||
OculusManager::configureCamera(camera, width, height);
|
||||
|
@ -720,7 +726,7 @@ void Application::resetCamerasOnResizeGL(Camera& camera, int width, int height)
|
|||
TV3DManager::configureCamera(camera, width, height);
|
||||
} else {
|
||||
camera.setAspectRatio((float)width / height);
|
||||
camera.setFieldOfView(Menu::getInstance()->getFieldOfView());
|
||||
camera.setFieldOfView(_viewFrustum.getFieldOfView());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -773,19 +779,20 @@ void Application::controlledBroadcastToNodes(const QByteArray& packet, const Nod
|
|||
int nReceivingNodes = DependencyManager::get<NodeList>()->broadcastToNodes(packet, NodeSet() << type);
|
||||
|
||||
// Feed number of bytes to corresponding channel of the bandwidth meter, if any (done otherwise)
|
||||
BandwidthMeter::ChannelIndex channel;
|
||||
double bandwidth_amount = nReceivingNodes * packet.size();
|
||||
switch (type) {
|
||||
case NodeType::Agent:
|
||||
case NodeType::AvatarMixer:
|
||||
channel = BandwidthMeter::AVATARS;
|
||||
_bandwidthRecorder.avatarsChannel->output.updateValue(bandwidth_amount);
|
||||
_bandwidthRecorder.totalChannel->input.updateValue(bandwidth_amount);
|
||||
break;
|
||||
case NodeType::EntityServer:
|
||||
channel = BandwidthMeter::OCTREE;
|
||||
_bandwidthRecorder.octreeChannel->output.updateValue(bandwidth_amount);
|
||||
_bandwidthRecorder.totalChannel->output.updateValue(bandwidth_amount);
|
||||
break;
|
||||
default:
|
||||
continue;
|
||||
}
|
||||
_bandwidthMeter.outputStream(channel).updateValue(nReceivingNodes * packet.size());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1260,7 +1267,6 @@ void Application::mouseReleaseEvent(QMouseEvent* event, unsigned int deviceID) {
|
|||
int horizontalOffset = MIRROR_VIEW_WIDTH;
|
||||
Stats::getInstance()->checkClick(getMouseX(), getMouseY(),
|
||||
getMouseDragStartedX(), getMouseDragStartedY(), horizontalOffset);
|
||||
checkBandwidthMeterClick();
|
||||
}
|
||||
|
||||
// fire an action end event
|
||||
|
@ -1388,8 +1394,10 @@ void Application::timer() {
|
|||
|
||||
_fps = (float)_frameCount / diffTime;
|
||||
|
||||
_packetsPerSecond = (float) _datagramProcessor.getPacketCount() / diffTime;
|
||||
_bytesPerSecond = (float) _datagramProcessor.getByteCount() / diffTime;
|
||||
_inPacketsPerSecond = (float) _datagramProcessor.getInPacketCount() / diffTime;
|
||||
_outPacketsPerSecond = (float) _datagramProcessor.getOutPacketCount() / diffTime;
|
||||
_inBytesPerSecond = (float) _datagramProcessor.getInByteCount() / diffTime;
|
||||
_outBytesPerSecond = (float) _datagramProcessor.getOutByteCount() / diffTime;
|
||||
_frameCount = 0;
|
||||
|
||||
_datagramProcessor.resetCounters();
|
||||
|
@ -1443,31 +1451,10 @@ void Application::idle() {
|
|||
|
||||
// After finishing all of the above work, restart the idle timer, allowing 2ms to process events.
|
||||
idleTimer->start(2);
|
||||
|
||||
if (_numChangedSettings > 0) {
|
||||
saveSettings();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Application::checkBandwidthMeterClick() {
|
||||
// ... to be called upon button release
|
||||
auto glCanvas = DependencyManager::get<GLCanvas>();
|
||||
if (Menu::getInstance()->isOptionChecked(MenuOption::Bandwidth) &&
|
||||
Menu::getInstance()->isOptionChecked(MenuOption::Stats) &&
|
||||
Menu::getInstance()->isOptionChecked(MenuOption::UserInterface) &&
|
||||
glm::compMax(glm::abs(glm::ivec2(getMouseX() - getMouseDragStartedX(),
|
||||
getMouseY() - getMouseDragStartedY())))
|
||||
<= BANDWIDTH_METER_CLICK_MAX_DRAG_LENGTH
|
||||
&& _bandwidthMeter.isWithinArea(getMouseX(), getMouseY(), glCanvas->width(), glCanvas->height())) {
|
||||
|
||||
// The bandwidth meter is visible, the click didn't get dragged too far and
|
||||
// we actually hit the bandwidth meter
|
||||
Menu::getInstance()->bandwidthDetails();
|
||||
}
|
||||
}
|
||||
|
||||
void Application::setFullscreen(bool fullscreen) {
|
||||
if (Menu::getInstance()->isOptionChecked(MenuOption::Fullscreen) != fullscreen) {
|
||||
Menu::getInstance()->getActionForOption(MenuOption::Fullscreen)->setChecked(fullscreen);
|
||||
|
@ -1602,6 +1589,20 @@ bool Application::exportEntities(const QString& filename, float x, float y, floa
|
|||
return true;
|
||||
}
|
||||
|
||||
void Application::loadSettings() {
|
||||
DependencyManager::get<Audio>()->loadSettings();
|
||||
DependencyManager::get<LODManager>()->loadSettings();
|
||||
Menu::getInstance()->loadSettings();
|
||||
_myAvatar->loadData();
|
||||
}
|
||||
|
||||
void Application::saveSettings() {
|
||||
DependencyManager::get<Audio>()->saveSettings();
|
||||
DependencyManager::get<LODManager>()->saveSettings();
|
||||
Menu::getInstance()->saveSettings();
|
||||
_myAvatar->saveData();
|
||||
}
|
||||
|
||||
bool Application::importEntities(const QString& filename) {
|
||||
_entityClipboard.eraseAllOctreeElements();
|
||||
bool success = _entityClipboard.readFromSVOFile(filename.toLocal8Bit().constData());
|
||||
|
@ -1652,8 +1653,6 @@ void Application::init() {
|
|||
|
||||
_timerStart.start();
|
||||
_lastTimeUpdated.start();
|
||||
|
||||
Menu::getInstance()->loadSettings();
|
||||
|
||||
// when --url in command line, teleport to location
|
||||
const QString HIFI_URL_COMMAND_LINE_KEY = "--url";
|
||||
|
@ -1671,11 +1670,11 @@ void Application::init() {
|
|||
if (Menu::getInstance()->isOptionChecked(MenuOption::SixenseEnabled)) {
|
||||
// on OS X we only setup sixense if the user wants it on - this allows running without the hid_init crash
|
||||
// if hydra support is temporarily not required
|
||||
Menu::getInstance()->toggleSixense(true);
|
||||
SixenseManager::getInstance().toggleSixense(true);
|
||||
}
|
||||
#else
|
||||
// setup sixense
|
||||
Menu::getInstance()->toggleSixense(true);
|
||||
SixenseManager::getInstance().toggleSixense(true);
|
||||
#endif
|
||||
|
||||
// initialize our face trackers after loading the menu settings
|
||||
|
@ -1714,16 +1713,13 @@ void Application::init() {
|
|||
_metavoxels.init();
|
||||
|
||||
auto glCanvas = DependencyManager::get<GLCanvas>();
|
||||
_rearMirrorTools = new RearMirrorTools(glCanvas.data(), _mirrorViewRect, _settings);
|
||||
_rearMirrorTools = new RearMirrorTools(glCanvas.data(), _mirrorViewRect);
|
||||
|
||||
connect(_rearMirrorTools, SIGNAL(closeView()), SLOT(closeMirrorView()));
|
||||
connect(_rearMirrorTools, SIGNAL(restoreView()), SLOT(restoreMirrorView()));
|
||||
connect(_rearMirrorTools, SIGNAL(shrinkView()), SLOT(shrinkMirrorView()));
|
||||
connect(_rearMirrorTools, SIGNAL(resetView()), SLOT(resetSensors()));
|
||||
|
||||
// save settings when avatar changes
|
||||
connect(_myAvatar, &MyAvatar::transformChanged, this, &Application::bumpSettings);
|
||||
|
||||
// make sure our texture cache knows about window size changes
|
||||
DependencyManager::get<TextureCache>()->associateWithWidget(glCanvas.data());
|
||||
|
||||
|
@ -1765,9 +1761,9 @@ void Application::updateLOD() {
|
|||
PerformanceTimer perfTimer("LOD");
|
||||
// adjust it unless we were asked to disable this feature, or if we're currently in throttleRendering mode
|
||||
if (!Menu::getInstance()->isOptionChecked(MenuOption::DisableAutoAdjustLOD) && !isThrottleRendering()) {
|
||||
Menu::getInstance()->autoAdjustLOD(_fps);
|
||||
DependencyManager::get<LODManager>()->autoAdjustLOD(_fps);
|
||||
} else {
|
||||
Menu::getInstance()->resetLODAdjust();
|
||||
DependencyManager::get<LODManager>()->resetLODAdjust();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1884,7 +1880,7 @@ void Application::updateMyAvatarLookAtPosition() {
|
|||
// deflect using Faceshift gaze data
|
||||
glm::vec3 origin = _myAvatar->getHead()->getEyePosition();
|
||||
float pitchSign = (_myCamera.getMode() == CAMERA_MODE_MIRROR) ? -1.0f : 1.0f;
|
||||
float deflection = Menu::getInstance()->getFaceshiftEyeDeflection();
|
||||
float deflection = DependencyManager::get<Faceshift>()->getEyeDeflection();
|
||||
if (isLookingAtSomeone) {
|
||||
deflection *= GAZE_DEFLECTION_REDUCTION_DURING_EYE_CONTACT;
|
||||
}
|
||||
|
@ -1956,14 +1952,15 @@ void Application::updateDialogs(float deltaTime) {
|
|||
PerformanceTimer perfTimer("updateDialogs");
|
||||
bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings);
|
||||
PerformanceWarning warn(showWarnings, "Application::updateDialogs()");
|
||||
|
||||
auto dialogsManager = DependencyManager::get<DialogsManager>();
|
||||
|
||||
// Update bandwidth dialog, if any
|
||||
BandwidthDialog* bandwidthDialog = Menu::getInstance()->getBandwidthDialog();
|
||||
BandwidthDialog* bandwidthDialog = dialogsManager->getBandwidthDialog();
|
||||
if (bandwidthDialog) {
|
||||
bandwidthDialog->update();
|
||||
}
|
||||
|
||||
OctreeStatsDialog* octreeStatsDialog = Menu::getInstance()->getOctreeStatsDialog();
|
||||
QPointer<OctreeStatsDialog> octreeStatsDialog = dialogsManager->getOctreeStatsDialog();
|
||||
if (octreeStatsDialog) {
|
||||
octreeStatsDialog->update();
|
||||
}
|
||||
|
@ -2234,8 +2231,9 @@ void Application::queryOctree(NodeType_t serverType, PacketType packetType, Node
|
|||
_octreeQuery.setCameraNearClip(_viewFrustum.getNearClip());
|
||||
_octreeQuery.setCameraFarClip(_viewFrustum.getFarClip());
|
||||
_octreeQuery.setCameraEyeOffsetPosition(_viewFrustum.getEyeOffsetPosition());
|
||||
_octreeQuery.setOctreeSizeScale(Menu::getInstance()->getOctreeSizeScale());
|
||||
_octreeQuery.setBoundaryLevelAdjust(Menu::getInstance()->getBoundaryLevelAdjust());
|
||||
auto lodManager = DependencyManager::get<LODManager>();
|
||||
_octreeQuery.setOctreeSizeScale(lodManager->getOctreeSizeScale());
|
||||
_octreeQuery.setBoundaryLevelAdjust(lodManager->getBoundaryLevelAdjust());
|
||||
|
||||
unsigned char queryPacket[MAX_PACKET_SIZE];
|
||||
|
||||
|
@ -2287,7 +2285,7 @@ void Application::queryOctree(NodeType_t serverType, PacketType packetType, Node
|
|||
int perServerPPS = 0;
|
||||
const int SMALL_BUDGET = 10;
|
||||
int perUnknownServer = SMALL_BUDGET;
|
||||
int totalPPS = Menu::getInstance()->getMaxOctreePacketsPerSecond();
|
||||
int totalPPS = _octreeQuery.getMaxOctreePacketsPerSecond();
|
||||
|
||||
// determine PPS based on number of servers
|
||||
if (inViewServers >= 1) {
|
||||
|
@ -2390,7 +2388,8 @@ void Application::queryOctree(NodeType_t serverType, PacketType packetType, Node
|
|||
nodeList->writeUnverifiedDatagram(reinterpret_cast<const char*>(queryPacket), packetLength, node);
|
||||
|
||||
// Feed number of bytes to corresponding channel of the bandwidth meter
|
||||
_bandwidthMeter.outputStream(BandwidthMeter::OCTREE).updateValue(packetLength);
|
||||
_bandwidthRecorder.octreeChannel->output.updateValue(packetLength);
|
||||
_bandwidthRecorder.totalChannel->output.updateValue(packetLength);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -2408,7 +2407,7 @@ QRect Application::getDesirableApplicationGeometry() {
|
|||
|
||||
// If our parent window is on the HMD, then don't use it's geometry, instead use
|
||||
// the "main screen" geometry.
|
||||
HMDToolsDialog* hmdTools = Menu::getInstance()->getHMDToolsDialog();
|
||||
HMDToolsDialog* hmdTools = DependencyManager::get<DialogsManager>()->getHMDToolsDialog();
|
||||
if (hmdTools && hmdTools->hasHMDScreen()) {
|
||||
QScreen* hmdScreen = hmdTools->getHMDScreen();
|
||||
QWindow* appWindow = getWindow()->windowHandle();
|
||||
|
@ -2633,15 +2632,15 @@ void Application::setupWorldLight() {
|
|||
}
|
||||
|
||||
bool Application::shouldRenderMesh(float largestDimension, float distanceToCamera) {
|
||||
return Menu::getInstance()->shouldRenderMesh(largestDimension, distanceToCamera);
|
||||
return DependencyManager::get<LODManager>()->shouldRenderMesh(largestDimension, distanceToCamera);
|
||||
}
|
||||
|
||||
float Application::getSizeScale() const {
|
||||
return Menu::getInstance()->getOctreeSizeScale();
|
||||
return DependencyManager::get<LODManager>()->getOctreeSizeScale();
|
||||
}
|
||||
|
||||
int Application::getBoundaryLevelAdjust() const {
|
||||
return Menu::getInstance()->getBoundaryLevelAdjust();
|
||||
return DependencyManager::get<LODManager>()->getBoundaryLevelAdjust();
|
||||
}
|
||||
|
||||
PickRay Application::computePickRay(float x, float y) {
|
||||
|
@ -2791,8 +2790,7 @@ void Application::displaySide(Camera& theCamera, bool selfAvatarOnly, RenderArgs
|
|||
if (!selfAvatarOnly) {
|
||||
// draw a red sphere
|
||||
float originSphereRadius = 0.05f;
|
||||
glColor3f(1,0,0);
|
||||
DependencyManager::get<GeometryCache>()->renderSphere(originSphereRadius, 15, 15);
|
||||
DependencyManager::get<GeometryCache>()->renderSphere(originSphereRadius, 15, 15, glm::vec4(1.0f, 0.0f, 0.0f, 1.0f));
|
||||
|
||||
// also, metavoxels
|
||||
if (Menu::getInstance()->isOptionChecked(MenuOption::Metavoxels)) {
|
||||
|
@ -2937,8 +2935,10 @@ void Application::computeOffAxisFrustum(float& left, float& right, float& bottom
|
|||
}
|
||||
}
|
||||
|
||||
bool Application::getShadowsEnabled() {
|
||||
return Menu::getInstance()->getShadowsEnabled();
|
||||
bool Application::getShadowsEnabled() {
|
||||
Menu* menubar = Menu::getInstance();
|
||||
return menubar->isOptionChecked(MenuOption::SimpleShadows) ||
|
||||
menubar->isOptionChecked(MenuOption::CascadedShadows);
|
||||
}
|
||||
|
||||
bool Application::getCascadeShadowsEnabled() {
|
||||
|
@ -2983,7 +2983,7 @@ void Application::renderRearViewMirror(const QRect& region, bool billboard) {
|
|||
_mirrorCamera.setPosition(_myAvatar->getPosition() +
|
||||
_myAvatar->getOrientation() * glm::vec3(0.0f, 0.0f, -1.0f) * BILLBOARD_DISTANCE * _myAvatar->getScale());
|
||||
|
||||
} else if (_rearMirrorTools->getZoomLevel() == BODY) {
|
||||
} else if (SettingHandles::rearViewZoomLevel.get() == BODY) {
|
||||
_mirrorCamera.setFieldOfView(MIRROR_FIELD_OF_VIEW); // degrees
|
||||
_mirrorCamera.setPosition(_myAvatar->getChestPosition() +
|
||||
_myAvatar->getOrientation() * glm::vec3(0.0f, 0.0f, -1.0f) * MIRROR_REARVIEW_BODY_DISTANCE * _myAvatar->getScale());
|
||||
|
@ -3377,48 +3377,49 @@ int Application::parseOctreeStats(const QByteArray& packet, const SharedNodePoin
|
|||
}
|
||||
|
||||
void Application::packetSent(quint64 length) {
|
||||
_bandwidthMeter.outputStream(BandwidthMeter::OCTREE).updateValue(length);
|
||||
_bandwidthRecorder.octreeChannel->output.updateValue(length);
|
||||
_bandwidthRecorder.totalChannel->output.updateValue(length);
|
||||
}
|
||||
|
||||
const QString SETTINGS_KEY = "Settings";
|
||||
|
||||
void Application::loadScripts() {
|
||||
// loads all saved scripts
|
||||
int size = lockSettings()->beginReadArray("Settings");
|
||||
unlockSettings();
|
||||
Settings settings;
|
||||
int size = settings.beginReadArray(SETTINGS_KEY);
|
||||
for (int i = 0; i < size; ++i){
|
||||
lockSettings()->setArrayIndex(i);
|
||||
QString string = _settings->value("script").toString();
|
||||
unlockSettings();
|
||||
settings.setArrayIndex(i);
|
||||
QString string = settings.value("script").toString();
|
||||
if (!string.isEmpty()) {
|
||||
loadScript(string);
|
||||
}
|
||||
}
|
||||
|
||||
QMutexLocker locker(&_settingsMutex);
|
||||
_settings->endArray();
|
||||
settings.endArray();
|
||||
}
|
||||
|
||||
void Application::clearScriptsBeforeRunning() {
|
||||
// clears all scripts from the settings
|
||||
QMutexLocker locker(&_settingsMutex);
|
||||
_settings->remove("Settings");
|
||||
// clears all scripts from the settingsSettings settings;
|
||||
Settings settings;
|
||||
settings.beginWriteArray(SETTINGS_KEY);
|
||||
settings.remove("");
|
||||
}
|
||||
|
||||
void Application::saveScripts() {
|
||||
// Saves all currently running user-loaded scripts
|
||||
QMutexLocker locker(&_settingsMutex);
|
||||
_settings->beginWriteArray("Settings");
|
||||
|
||||
Settings settings;
|
||||
settings.beginWriteArray(SETTINGS_KEY);
|
||||
settings.remove("");
|
||||
|
||||
QStringList runningScripts = getRunningScripts();
|
||||
int i = 0;
|
||||
for (QStringList::const_iterator it = runningScripts.begin(); it != runningScripts.end(); it += 1) {
|
||||
for (auto it = runningScripts.begin(); it != runningScripts.end(); ++it) {
|
||||
if (getScriptEngine(*it)->isUserLoaded()) {
|
||||
_settings->setArrayIndex(i);
|
||||
_settings->setValue("script", *it);
|
||||
i += 1;
|
||||
settings.setArrayIndex(i);
|
||||
settings.setValue("script", *it);
|
||||
++i;
|
||||
}
|
||||
}
|
||||
|
||||
_settings->endArray();
|
||||
settings.endArray();
|
||||
}
|
||||
|
||||
QScriptValue joystickToScriptValue(QScriptEngine *engine, Joystick* const &in) {
|
||||
|
@ -3445,7 +3446,7 @@ void Application::registerScriptEngineWithApplicationServices(ScriptEngine* scri
|
|||
scriptEngine->registerGlobalObject("Camera", &_myCamera);
|
||||
|
||||
#if defined(Q_OS_MAC) || defined(Q_OS_WIN)
|
||||
scriptEngine->registerGlobalObject("SpeechRecognizer", Menu::getInstance()->getSpeechRecognizer());
|
||||
scriptEngine->registerGlobalObject("SpeechRecognizer", DependencyManager::get<SpeechRecognizer>().data());
|
||||
#endif
|
||||
|
||||
ClipboardScriptingInterface* clipboardScriptable = new ClipboardScriptingInterface();
|
||||
|
@ -3545,7 +3546,6 @@ ScriptEngine* Application::loadScript(const QString& scriptFilename, bool isUser
|
|||
if (activateMainWindow && !loadScriptFromEditor) {
|
||||
_window->activateWindow();
|
||||
}
|
||||
bumpSettings();
|
||||
|
||||
return scriptEngine;
|
||||
}
|
||||
|
@ -3573,7 +3573,6 @@ void Application::scriptFinished(const QString& scriptName) {
|
|||
_scriptEnginesHash.erase(it);
|
||||
_runningScriptsWidget->scriptStopped(scriptName);
|
||||
_runningScriptsWidget->setRunningScripts(getRunningScripts());
|
||||
bumpSettings();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3669,7 +3668,6 @@ void Application::openUrl(const QUrl& url) {
|
|||
}
|
||||
|
||||
void Application::updateMyAvatarTransform() {
|
||||
bumpSettings();
|
||||
const float SIMULATION_OFFSET_QUANTIZATION = 16.0f; // meters
|
||||
glm::vec3 avatarPosition = _myAvatar->getPosition();
|
||||
glm::vec3 physicsWorldOffset = _physicsEngine.getOriginOffset();
|
||||
|
@ -3686,7 +3684,6 @@ void Application::updateMyAvatarTransform() {
|
|||
}
|
||||
|
||||
void Application::domainSettingsReceived(const QJsonObject& domainSettingsObject) {
|
||||
|
||||
// from the domain-handler, figure out the satoshi cost per voxel and per meter cubed
|
||||
const QString VOXEL_SETTINGS_KEY = "voxels";
|
||||
const QString PER_VOXEL_COST_KEY = "per-voxel-credits";
|
||||
|
@ -3729,9 +3726,7 @@ QString Application::getPreviousScriptLocation() {
|
|||
|
||||
void Application::setPreviousScriptLocation(const QString& previousScriptLocation) {
|
||||
_previousScriptLocation = previousScriptLocation;
|
||||
QMutexLocker locker(&_settingsMutex);
|
||||
_settings->setValue("LastScriptLocation", _previousScriptLocation);
|
||||
bumpSettings();
|
||||
SettingHandles::lastScriptLocation.set(_previousScriptLocation);
|
||||
}
|
||||
|
||||
void Application::loadDialog() {
|
||||
|
@ -3747,7 +3742,6 @@ void Application::loadDialog() {
|
|||
}
|
||||
|
||||
void Application::loadScriptURLDialog() {
|
||||
|
||||
QInputDialog scriptURLDialog(Application::getInstance()->getWindow());
|
||||
scriptURLDialog.setWindowTitle("Open and Run Script URL");
|
||||
scriptURLDialog.setLabelText("Script:");
|
||||
|
@ -3765,11 +3759,16 @@ void Application::loadScriptURLDialog() {
|
|||
}
|
||||
loadScript(newScript);
|
||||
}
|
||||
|
||||
sendFakeEnterEvent();
|
||||
}
|
||||
|
||||
QString Application::getScriptsLocation() const {
|
||||
return SettingHandles::scriptsLocation.get();
|
||||
}
|
||||
|
||||
void Application::setScriptsLocation(const QString& scriptsLocation) {
|
||||
SettingHandles::scriptsLocation.set(scriptsLocation);
|
||||
emit scriptLocationChanged(scriptsLocation);
|
||||
}
|
||||
|
||||
void Application::toggleLogDialog() {
|
||||
if (! _logDialog) {
|
||||
|
@ -3789,6 +3788,7 @@ void Application::initAvatarAndViewFrustum() {
|
|||
|
||||
void Application::checkVersion() {
|
||||
QNetworkRequest latestVersionRequest((QUrl(CHECK_VERSION_URL)));
|
||||
latestVersionRequest.setHeader(QNetworkRequest::UserAgentHeader, HIGH_FIDELITY_USER_AGENT);
|
||||
latestVersionRequest.setAttribute(QNetworkRequest::CacheLoadControlAttribute, QNetworkRequest::PreferCache);
|
||||
QNetworkReply* reply = NetworkAccessManager::getInstance().get(latestVersionRequest);
|
||||
connect(reply, SIGNAL(finished()), SLOT(parseVersionXml()));
|
||||
|
@ -3871,7 +3871,8 @@ void Application::takeSnapshot() {
|
|||
_snapshotShareDialog->show();
|
||||
}
|
||||
|
||||
void Application::setVSyncEnabled(bool vsyncOn) {
|
||||
void Application::setVSyncEnabled() {
|
||||
bool vsyncOn = Menu::getInstance()->isOptionChecked(MenuOption::RenderTargetFramerateVSyncOn);
|
||||
#if defined(Q_OS_WIN)
|
||||
if (wglewGetExtension("WGL_EXT_swap_control")) {
|
||||
wglSwapIntervalEXT(vsyncOn);
|
||||
|
@ -3895,6 +3896,7 @@ void Application::setVSyncEnabled(bool vsyncOn) {
|
|||
#else
|
||||
qDebug("V-Sync is FORCED ON on this system\n");
|
||||
#endif
|
||||
vsyncOn = true; // Turns off unused variable warning
|
||||
}
|
||||
|
||||
bool Application::isVSyncOn() const {
|
||||
|
|
|
@ -19,7 +19,6 @@
|
|||
#include <QImage>
|
||||
#include <QPointer>
|
||||
#include <QSet>
|
||||
#include <QSettings>
|
||||
#include <QStringList>
|
||||
#include <QUndoStack>
|
||||
|
||||
|
@ -34,10 +33,10 @@
|
|||
#include <PacketHeaders.h>
|
||||
#include <PhysicsEngine.h>
|
||||
#include <ScriptEngine.h>
|
||||
#include <StDev.h>
|
||||
#include <TextureCache.h>
|
||||
#include <ViewFrustum.h>
|
||||
|
||||
#include "Audio.h"
|
||||
#include "Bookmarks.h"
|
||||
#include "Camera.h"
|
||||
#include "DatagramProcessor.h"
|
||||
|
@ -56,7 +55,6 @@
|
|||
#include "devices/SixenseManager.h"
|
||||
#include "scripting/ControllerScriptingInterface.h"
|
||||
#include "ui/BandwidthDialog.h"
|
||||
#include "ui/BandwidthMeter.h"
|
||||
#include "ui/HMDToolsDialog.h"
|
||||
#include "ui/ModelsBrowser.h"
|
||||
#include "ui/NodeBounds.h"
|
||||
|
@ -80,7 +78,6 @@
|
|||
class QGLWidget;
|
||||
class QKeyEvent;
|
||||
class QMouseEvent;
|
||||
class QSettings;
|
||||
class QSystemTrayIcon;
|
||||
class QTouchEvent;
|
||||
class QWheelEvent;
|
||||
|
@ -121,6 +118,12 @@ static const quint64 TOO_LONG_SINCE_LAST_SEND_DOWNSTREAM_AUDIO_STATS = 1 * USECS
|
|||
static const QString INFO_HELP_PATH = "html/interface-welcome-allsvg.html";
|
||||
static const QString INFO_EDIT_ENTITIES_PATH = "html/edit-entities-commands.html";
|
||||
|
||||
class Application;
|
||||
#if defined(qApp)
|
||||
#undef qApp
|
||||
#endif
|
||||
#define qApp (static_cast<Application*>(QCoreApplication::instance()))
|
||||
|
||||
class Application : public QApplication, public AbstractViewStateInterface, AbstractScriptingServicesInterface {
|
||||
Q_OBJECT
|
||||
|
||||
|
@ -128,18 +131,16 @@ class Application : public QApplication, public AbstractViewStateInterface, Abst
|
|||
friend class DatagramProcessor;
|
||||
|
||||
public:
|
||||
static Application* getInstance() { return static_cast<Application*>(QCoreApplication::instance()); }
|
||||
static Application* getInstance() { return qApp; } // TODO: replace fully by qApp
|
||||
static const glm::vec3& getPositionForPath() { return getInstance()->_myAvatar->getPosition(); }
|
||||
static glm::quat getOrientationForPath() { return getInstance()->_myAvatar->getOrientation(); }
|
||||
|
||||
Application(int& argc, char** argv, QElapsedTimer &startup_time);
|
||||
~Application();
|
||||
|
||||
void restoreSizeAndPosition();
|
||||
void loadScripts();
|
||||
QString getPreviousScriptLocation();
|
||||
void setPreviousScriptLocation(const QString& previousScriptLocation);
|
||||
void storeSizeAndPosition();
|
||||
void clearScriptsBeforeRunning();
|
||||
void initializeGL();
|
||||
void paintGL();
|
||||
|
@ -180,7 +181,7 @@ public:
|
|||
PrioVR* getPrioVR() { return &_prioVR; }
|
||||
QUndoStack* getUndoStack() { return &_undoStack; }
|
||||
MainWindow* getWindow() { return _window; }
|
||||
|
||||
OctreeQuery& getOctreeQuery() { return _octreeQuery; }
|
||||
EntityTree* getEntityClipboard() { return &_entityClipboard; }
|
||||
EntityTreeRenderer* getEntityClipboardRenderer() { return &_entityClipboardRenderer; }
|
||||
|
||||
|
@ -201,26 +202,22 @@ public:
|
|||
bool getLastMouseMoveWasSimulated() const { return _lastMouseMoveWasSimulated; }
|
||||
|
||||
FaceTracker* getActiveFaceTracker();
|
||||
BandwidthMeter* getBandwidthMeter() { return &_bandwidthMeter; }
|
||||
BandwidthRecorder* getBandwidthRecorder() { return &_bandwidthRecorder; }
|
||||
QSystemTrayIcon* getTrayIcon() { return _trayIcon; }
|
||||
ApplicationOverlay& getApplicationOverlay() { return _applicationOverlay; }
|
||||
Overlays& getOverlays() { return _overlays; }
|
||||
|
||||
float getFps() const { return _fps; }
|
||||
float getPacketsPerSecond() const { return _packetsPerSecond; }
|
||||
float getBytesPerSecond() const { return _bytesPerSecond; }
|
||||
float getInPacketsPerSecond() const { return _inPacketsPerSecond; }
|
||||
float getOutPacketsPerSecond() const { return _outPacketsPerSecond; }
|
||||
float getInBytesPerSecond() const { return _inBytesPerSecond; }
|
||||
float getOutBytesPerSecond() const { return _outBytesPerSecond; }
|
||||
const glm::vec3& getViewMatrixTranslation() const { return _viewMatrixTranslation; }
|
||||
void setViewMatrixTranslation(const glm::vec3& translation) { _viewMatrixTranslation = translation; }
|
||||
|
||||
virtual const Transform& getViewTransform() const { return _viewTransform; }
|
||||
void setViewTransform(const Transform& view);
|
||||
|
||||
/// if you need to access the application settings, use lockSettings()/unlockSettings()
|
||||
QSettings* lockSettings() { _settingsMutex.lock(); return _settings; }
|
||||
void unlockSettings() { _settingsMutex.unlock(); }
|
||||
|
||||
void saveSettings();
|
||||
|
||||
NodeToOctreeSceneStats* getOcteeSceneStats() { return &_octreeServerSceneStats; }
|
||||
void lockOctreeSceneStats() { _octreeSceneStatsLock.lockForRead(); }
|
||||
void unlockOctreeSceneStats() { _octreeSceneStatsLock.unlock(); }
|
||||
|
@ -303,6 +300,9 @@ public:
|
|||
RunningScriptsWidget* getRunningScriptsWidget() { return _runningScriptsWidget; }
|
||||
|
||||
Bookmarks* getBookmarks() const { return _bookmarks; }
|
||||
|
||||
QString getScriptsLocation() const;
|
||||
void setScriptsLocation(const QString& scriptsLocation);
|
||||
|
||||
signals:
|
||||
|
||||
|
@ -317,6 +317,8 @@ signals:
|
|||
|
||||
/// Fired when the import window is closed
|
||||
void importDone();
|
||||
|
||||
void scriptLocationChanged(const QString& newPath);
|
||||
|
||||
public slots:
|
||||
void domainChanged(const QString& domainHostname);
|
||||
|
@ -353,13 +355,17 @@ public slots:
|
|||
void openUrl(const QUrl& url);
|
||||
|
||||
void updateMyAvatarTransform();
|
||||
void bumpSettings() { ++_numChangedSettings; }
|
||||
|
||||
void domainSettingsReceived(const QJsonObject& domainSettingsObject);
|
||||
|
||||
void setVSyncEnabled(bool vsyncOn);
|
||||
void setVSyncEnabled();
|
||||
|
||||
void resetSensors();
|
||||
void aboutApp();
|
||||
void showEditEntitiesHelp();
|
||||
|
||||
void loadSettings();
|
||||
void saveSettings();
|
||||
|
||||
void notifyPacketVersionMismatch();
|
||||
|
||||
|
@ -389,6 +395,10 @@ private slots:
|
|||
void parseVersionXml();
|
||||
|
||||
void manageRunningScriptsWidgetVisibility(bool shown);
|
||||
|
||||
void runTests();
|
||||
|
||||
void audioMuteToggled();
|
||||
|
||||
private:
|
||||
void resetCamerasOnResizeGL(Camera& camera, int width, int height);
|
||||
|
@ -427,7 +437,6 @@ private:
|
|||
|
||||
void updateShadowMap();
|
||||
void renderRearViewMirror(const QRect& region, bool billboard = false);
|
||||
void checkBandwidthMeterClick();
|
||||
void setMenuShortcutsEnabled(bool enabled);
|
||||
|
||||
static void attachNewHeadToNode(Node *newNode);
|
||||
|
@ -440,15 +449,10 @@ private:
|
|||
|
||||
ToolWindow* _toolWindow;
|
||||
|
||||
BandwidthMeter _bandwidthMeter;
|
||||
|
||||
QThread* _nodeThread;
|
||||
DatagramProcessor _datagramProcessor;
|
||||
|
||||
QMutex _settingsMutex;
|
||||
QSettings* _settings;
|
||||
int _numChangedSettings;
|
||||
|
||||
QUndoStack _undoStack;
|
||||
UndoStackScriptingInterface _undoStackScriptingInterface;
|
||||
|
||||
|
@ -482,6 +486,9 @@ private:
|
|||
|
||||
OctreeQuery _octreeQuery; // NodeData derived class for querying octee cells from octree servers
|
||||
|
||||
BandwidthRecorder _bandwidthRecorder;
|
||||
|
||||
|
||||
AvatarManager _avatarManager;
|
||||
MyAvatar* _myAvatar; // TODO: move this and relevant code to AvatarManager (or MyAvatar as the case may be)
|
||||
|
||||
|
@ -530,8 +537,10 @@ private:
|
|||
OctreePacketProcessor _octreeProcessor;
|
||||
EntityEditPacketSender _entityEditSender;
|
||||
|
||||
int _packetsPerSecond;
|
||||
int _bytesPerSecond;
|
||||
int _inPacketsPerSecond;
|
||||
int _outPacketsPerSecond;
|
||||
int _inBytesPerSecond;
|
||||
int _outBytesPerSecond;
|
||||
|
||||
StDev _idleLoopStdev;
|
||||
float _idleLoopMeasuredJitter;
|
||||
|
@ -568,6 +577,7 @@ private:
|
|||
RunningScriptsWidget* _runningScriptsWidget;
|
||||
QHash<QString, ScriptEngine*> _scriptEnginesHash;
|
||||
bool _runningScriptsWidgetWasVisible;
|
||||
QString _scriptsLocation;
|
||||
|
||||
QSystemTrayIcon* _trayIcon;
|
||||
|
||||
|
@ -583,6 +593,9 @@ private:
|
|||
Bookmarks* _bookmarks;
|
||||
|
||||
bool _notifiedPacketVersionMismatchThisDomain;
|
||||
|
||||
QThread _settingsThread;
|
||||
QTimer _settingsTimer;
|
||||
};
|
||||
|
||||
#endif // hifi_Application_h
|
||||
|
|
|
@ -10,9 +10,10 @@
|
|||
//
|
||||
|
||||
#include <cstring>
|
||||
#include <math.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include <math.h>
|
||||
#include <glm/glm.hpp>
|
||||
|
||||
#ifdef __APPLE__
|
||||
#include <CoreAudio/AudioHardware.h>
|
||||
|
@ -28,29 +29,35 @@
|
|||
#include <VersionHelpers.h>
|
||||
#endif
|
||||
|
||||
#include <AudioConstants.h>
|
||||
|
||||
#include <QtCore/QBuffer>
|
||||
#include <QtMultimedia/QAudioInput>
|
||||
#include <QtMultimedia/QAudioOutput>
|
||||
|
||||
#include <glm/glm.hpp>
|
||||
|
||||
#include <AudioConstants.h>
|
||||
#include <AudioInjector.h>
|
||||
#include <NodeList.h>
|
||||
#include <PacketHeaders.h>
|
||||
|
||||
#include <PositionalAudioStream.h>
|
||||
|
||||
#include <Settings.h>
|
||||
#include <SharedUtil.h>
|
||||
#include <UUID.h>
|
||||
|
||||
#include "Application.h"
|
||||
|
||||
#include "Audio.h"
|
||||
|
||||
static const int RECEIVED_AUDIO_STREAM_CAPACITY_FRAMES = 100;
|
||||
|
||||
namespace SettingHandles {
|
||||
const SettingHandle<bool> audioOutputStarveDetectionEnabled("audioOutputStarveDetectionEnabled",
|
||||
DEFAULT_AUDIO_OUTPUT_STARVE_DETECTION_ENABLED);
|
||||
const SettingHandle<int> audioOutputStarveDetectionThreshold("audioOutputStarveDetectionThreshold",
|
||||
DEFAULT_AUDIO_OUTPUT_STARVE_DETECTION_THRESHOLD);
|
||||
const SettingHandle<int> audioOutputStarveDetectionPeriod("audioOutputStarveDetectionPeriod",
|
||||
DEFAULT_AUDIO_OUTPUT_STARVE_DETECTION_PERIOD);
|
||||
const SettingHandle<int> audioOutputBufferSize("audioOutputBufferSize",
|
||||
DEFAULT_MAX_FRAMES_OVER_DESIRED);
|
||||
}
|
||||
|
||||
Audio::Audio() :
|
||||
AbstractAudioInterface(),
|
||||
_audioInput(NULL),
|
||||
|
@ -99,6 +106,15 @@ Audio::Audio() :
|
|||
|
||||
// Initialize GVerb
|
||||
initGverb();
|
||||
|
||||
const qint64 DEVICE_CHECK_INTERVAL_MSECS = 2 * 1000;
|
||||
|
||||
_inputDevices = getDeviceNames(QAudio::AudioInput);
|
||||
_outputDevices = getDeviceNames(QAudio::AudioOutput);
|
||||
|
||||
QTimer* updateTimer = new QTimer(this);
|
||||
connect(updateTimer, &QTimer::timeout, this, &Audio::checkDevices);
|
||||
updateTimer->start(DEVICE_CHECK_INTERVAL_MSECS);
|
||||
}
|
||||
|
||||
void Audio::reset() {
|
||||
|
@ -753,8 +769,8 @@ void Audio::handleAudioInput() {
|
|||
nodeList->writeDatagram(audioDataPacket, packetBytes, audioMixer);
|
||||
_outgoingAvatarAudioSequenceNumber++;
|
||||
|
||||
Application::getInstance()->getBandwidthMeter()->outputStream(BandwidthMeter::AUDIO)
|
||||
.updateValue(packetBytes);
|
||||
Application::getInstance()->getBandwidthRecorder()->audioChannel->output.updateValue(packetBytes);
|
||||
Application::getInstance()->getBandwidthRecorder()->totalChannel->output.updateValue(packetBytes);
|
||||
}
|
||||
delete[] inputAudioSamples;
|
||||
}
|
||||
|
@ -813,7 +829,8 @@ void Audio::addReceivedAudioToStream(const QByteArray& audioByteArray) {
|
|||
_receivedAudioStream.parseData(audioByteArray);
|
||||
}
|
||||
|
||||
Application::getInstance()->getBandwidthMeter()->inputStream(BandwidthMeter::AUDIO).updateValue(audioByteArray.size());
|
||||
Application::getInstance()->getBandwidthRecorder()->audioChannel->input.updateValue(audioByteArray.size());
|
||||
Application::getInstance()->getBandwidthRecorder()->totalChannel->input.updateValue(audioByteArray.size());
|
||||
}
|
||||
|
||||
void Audio::parseAudioEnvironmentData(const QByteArray &packet) {
|
||||
|
@ -1108,3 +1125,40 @@ qint64 Audio::AudioOutputIODevice::readData(char * data, qint64 maxSize) {
|
|||
|
||||
return bytesWritten;
|
||||
}
|
||||
|
||||
void Audio::checkDevices() {
|
||||
QVector<QString> inputDevices = getDeviceNames(QAudio::AudioInput);
|
||||
QVector<QString> outputDevices = getDeviceNames(QAudio::AudioOutput);
|
||||
|
||||
if (inputDevices != _inputDevices || outputDevices != _outputDevices) {
|
||||
_inputDevices = inputDevices;
|
||||
_outputDevices = outputDevices;
|
||||
|
||||
emit deviceChanged();
|
||||
}
|
||||
}
|
||||
|
||||
void Audio::loadSettings() {
|
||||
_receivedAudioStream.loadSettings();
|
||||
|
||||
setOutputStarveDetectionEnabled(SettingHandles::audioOutputStarveDetectionEnabled.get());
|
||||
setOutputStarveDetectionThreshold(SettingHandles::audioOutputStarveDetectionThreshold.get());
|
||||
setOutputStarveDetectionPeriod(SettingHandles::audioOutputStarveDetectionPeriod.get());
|
||||
|
||||
if (QThread::currentThread() != thread()) {
|
||||
QMetaObject::invokeMethod(this, "setOutputBufferSize",
|
||||
Q_ARG(int, SettingHandles::audioOutputBufferSize.get()));
|
||||
} else {
|
||||
setOutputBufferSize(SettingHandles::audioOutputBufferSize.get());
|
||||
}
|
||||
}
|
||||
|
||||
void Audio::saveSettings() {
|
||||
_receivedAudioStream.saveSettings();
|
||||
|
||||
SettingHandles::audioOutputStarveDetectionEnabled.set(getOutputStarveDetectionEnabled());
|
||||
SettingHandles::audioOutputStarveDetectionThreshold.set(getOutputStarveDetectionThreshold());
|
||||
SettingHandles::audioOutputStarveDetectionPeriod.set(getOutputStarveDetectionPeriod());
|
||||
SettingHandles::audioOutputBufferSize.set(getOutputBufferSize());
|
||||
}
|
||||
|
||||
|
|
|
@ -30,7 +30,6 @@
|
|||
#include <DependencyManager.h>
|
||||
#include <StDev.h>
|
||||
|
||||
#include "InterfaceConfig.h"
|
||||
#include "audio/AudioIOStats.h"
|
||||
#include "audio/AudioNoiseGate.h"
|
||||
#include "AudioStreamStats.h"
|
||||
|
@ -96,14 +95,13 @@ public:
|
|||
};
|
||||
|
||||
const MixedProcessedAudioStream& getReceivedAudioStream() const { return _receivedAudioStream; }
|
||||
MixedProcessedAudioStream& getReceivedAudioStream() { return _receivedAudioStream; }
|
||||
|
||||
float getLastInputLoudness() const { return glm::max(_lastInputLoudness - _inputGate.getMeasuredFloor(), 0.0f); }
|
||||
|
||||
float getTimeSinceLastClip() const { return _timeSinceLastClip; }
|
||||
float getAudioAverageInputLoudness() const { return _lastInputLoudness; }
|
||||
|
||||
void setReceivedAudioStreamSettings(const InboundAudioStream::Settings& settings) { _receivedAudioStream.setSettings(settings); }
|
||||
|
||||
int getDesiredJitterBufferFrames() const { return _receivedAudioStream.getDesiredJitterBufferFrames(); }
|
||||
|
||||
bool isMuted() { return _muted; }
|
||||
|
@ -174,9 +172,13 @@ public slots:
|
|||
|
||||
void outputNotify();
|
||||
|
||||
void loadSettings();
|
||||
void saveSettings();
|
||||
|
||||
signals:
|
||||
bool muteToggled();
|
||||
void inputReceived(const QByteArray& inputSamples);
|
||||
void deviceChanged();
|
||||
|
||||
protected:
|
||||
Audio();
|
||||
|
@ -275,6 +277,10 @@ private:
|
|||
AudioIOStats _stats;
|
||||
|
||||
AudioNoiseGate _inputGate;
|
||||
|
||||
QVector<QString> _inputDevices;
|
||||
QVector<QString> _outputDevices;
|
||||
void checkDevices();
|
||||
};
|
||||
|
||||
|
||||
|
|
64
interface/src/BandwidthRecorder.cpp
Normal file
64
interface/src/BandwidthRecorder.cpp
Normal file
|
@ -0,0 +1,64 @@
|
|||
//
|
||||
// BandwidthMeter.cpp
|
||||
// interface/src/ui
|
||||
//
|
||||
// Created by Seth Alves on 2015-1-30
|
||||
// Copyright 2015 High Fidelity, Inc.
|
||||
//
|
||||
// Based on code by Tobias Schwinger
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#include <GeometryCache.h>
|
||||
#include "BandwidthRecorder.h"
|
||||
|
||||
|
||||
BandwidthRecorder::Channel::Channel(char const* const caption,
|
||||
char const* unitCaption,
|
||||
double unitScale,
|
||||
unsigned colorRGBA) :
|
||||
caption(caption),
|
||||
unitCaption(unitCaption),
|
||||
unitScale(unitScale),
|
||||
colorRGBA(colorRGBA)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
|
||||
BandwidthRecorder::BandwidthRecorder() {
|
||||
}
|
||||
|
||||
|
||||
BandwidthRecorder::~BandwidthRecorder() {
|
||||
delete audioChannel;
|
||||
delete avatarsChannel;
|
||||
delete octreeChannel;
|
||||
delete metavoxelsChannel;
|
||||
delete totalChannel;
|
||||
}
|
||||
|
||||
|
||||
BandwidthRecorder::Stream::Stream(float msToAverage) : _value(0.0f), _msToAverage(msToAverage) {
|
||||
_prevTime.start();
|
||||
}
|
||||
|
||||
|
||||
void BandwidthRecorder::Stream::updateValue(double amount) {
|
||||
|
||||
// Determine elapsed time
|
||||
double dt = (double)_prevTime.nsecsElapsed() / 1000000.0; // ns to ms
|
||||
|
||||
// Ignore this value when timer imprecision yields dt = 0
|
||||
if (dt == 0.0) {
|
||||
return;
|
||||
}
|
||||
|
||||
_prevTime.start();
|
||||
|
||||
// Compute approximate average
|
||||
_value = glm::mix(_value, amount / dt,
|
||||
glm::clamp(dt / _msToAverage, 0.0, 1.0));
|
||||
}
|
56
interface/src/BandwidthRecorder.h
Normal file
56
interface/src/BandwidthRecorder.h
Normal file
|
@ -0,0 +1,56 @@
|
|||
//
|
||||
// BandwidthRecorder.h
|
||||
//
|
||||
// Created by Seth Alves on 2015-1-30
|
||||
// Copyright 2015 High Fidelity, Inc.
|
||||
//
|
||||
// Based on code by Tobias Schwinger
|
||||
//
|
||||
// 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_BandwidthRecorder_h
|
||||
#define hifi_BandwidthRecorder_h
|
||||
|
||||
#include <QElapsedTimer>
|
||||
|
||||
class BandwidthRecorder {
|
||||
public:
|
||||
BandwidthRecorder();
|
||||
~BandwidthRecorder();
|
||||
|
||||
// keep track of data rate in one direction
|
||||
class Stream {
|
||||
public:
|
||||
Stream(float msToAverage = 3000.0f);
|
||||
void updateValue(double amount);
|
||||
double getValue() const { return _value; }
|
||||
private:
|
||||
double _value; // Current value.
|
||||
double _msToAverage; // Milliseconds to average.
|
||||
QElapsedTimer _prevTime; // Time of last feed.
|
||||
};
|
||||
|
||||
// keep track of data rate in two directions as well as units and style to use during display
|
||||
class Channel {
|
||||
public:
|
||||
Channel(char const* const caption, char const* unitCaption, double unitScale, unsigned colorRGBA);
|
||||
Stream input;
|
||||
Stream output;
|
||||
char const* const caption;
|
||||
char const* unitCaption;
|
||||
double unitScale;
|
||||
unsigned colorRGBA;
|
||||
};
|
||||
|
||||
// create the channels we keep track of
|
||||
Channel* audioChannel = new Channel("Audio", "Kbps", 8000.0 / 1024.0, 0x33cc99ff);
|
||||
Channel* avatarsChannel = new Channel("Avatars", "Kbps", 8000.0 / 1024.0, 0xffef40c0);
|
||||
Channel* octreeChannel = new Channel("Octree", "Kbps", 8000.0 / 1024.0, 0xd0d0d0a0);
|
||||
Channel* metavoxelsChannel = new Channel("Metavoxels", "Kbps", 8000.0 / 1024.0, 0xd0d0d0a0);
|
||||
Channel* totalChannel = new Channel("Total", "Kbps", 8000.0 / 1024.0, 0xd0d0d0a0);
|
||||
};
|
||||
|
||||
#endif
|
|
@ -9,10 +9,21 @@
|
|||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#include <QAction>
|
||||
#include <QDebug>
|
||||
#include <QJsonObject>
|
||||
#include <QFile>
|
||||
#include <QInputDialog>
|
||||
#include <QJsonDocument>
|
||||
#include <QMessageBox>
|
||||
#include <QStandardPaths>
|
||||
|
||||
#include <AddressManager.h>
|
||||
#include <Application.h>
|
||||
|
||||
#include "MainWindow.h"
|
||||
#include "Menu.h"
|
||||
|
||||
#include "Bookmarks.h"
|
||||
|
||||
Bookmarks::Bookmarks() {
|
||||
|
@ -71,3 +82,125 @@ void Bookmarks::persistToFile() {
|
|||
QByteArray data = json.toJson();
|
||||
saveFile.write(data);
|
||||
}
|
||||
|
||||
void Bookmarks::setupMenus(Menu* menubar, QMenu* menu) {
|
||||
// Add menus/actions
|
||||
menubar->addActionToQMenuAndActionHash(menu, MenuOption::BookmarkLocation, 0,
|
||||
this, SLOT(bookmarkLocation()));
|
||||
_bookmarksMenu = menu->addMenu(MenuOption::Bookmarks);
|
||||
_deleteBookmarksAction = menubar->addActionToQMenuAndActionHash(menu, MenuOption::DeleteBookmark, 0,
|
||||
this, SLOT(deleteBookmark()));
|
||||
|
||||
// Enable/Disable menus as needed
|
||||
enableMenuItems(_bookmarks.count() > 0);
|
||||
|
||||
// Load bookmarks
|
||||
for (auto it = _bookmarks.begin(); it != _bookmarks.end(); ++it ) {
|
||||
QString bookmarkName = it.key();
|
||||
QString bookmarkAddress = it.value().toString();
|
||||
addLocationToMenu(menubar, bookmarkName, bookmarkAddress);
|
||||
}
|
||||
}
|
||||
|
||||
void Bookmarks::bookmarkLocation() {
|
||||
QInputDialog bookmarkLocationDialog(qApp->getWindow());
|
||||
bookmarkLocationDialog.setWindowTitle("Bookmark Location");
|
||||
bookmarkLocationDialog.setLabelText("Name:");
|
||||
bookmarkLocationDialog.setInputMode(QInputDialog::TextInput);
|
||||
bookmarkLocationDialog.resize(400, 200);
|
||||
|
||||
if (bookmarkLocationDialog.exec() == QDialog::Rejected) {
|
||||
return;
|
||||
}
|
||||
|
||||
QString bookmarkName = bookmarkLocationDialog.textValue().trimmed();
|
||||
bookmarkName = bookmarkName.replace(QRegExp("(\r\n|[\r\n\t\v ])+"), " ");
|
||||
if (bookmarkName.length() == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto addressManager = DependencyManager::get<AddressManager>();
|
||||
QString bookmarkAddress = addressManager->currentAddress().toString();
|
||||
|
||||
Menu* menubar = Menu::getInstance();
|
||||
if (contains(bookmarkName)) {
|
||||
QMessageBox duplicateBookmarkMessage;
|
||||
duplicateBookmarkMessage.setIcon(QMessageBox::Warning);
|
||||
duplicateBookmarkMessage.setText("The bookmark name you entered already exists in your list.");
|
||||
duplicateBookmarkMessage.setInformativeText("Would you like to overwrite it?");
|
||||
duplicateBookmarkMessage.setStandardButtons(QMessageBox::Yes | QMessageBox::No);
|
||||
duplicateBookmarkMessage.setDefaultButton(QMessageBox::Yes);
|
||||
if (duplicateBookmarkMessage.exec() == QMessageBox::No) {
|
||||
return;
|
||||
}
|
||||
removeLocationFromMenu(menubar, bookmarkName);
|
||||
}
|
||||
|
||||
addLocationToMenu(menubar, bookmarkName, bookmarkAddress);
|
||||
insert(bookmarkName, bookmarkAddress); // Overwrites any item with the same bookmarkName.
|
||||
|
||||
enableMenuItems(true);
|
||||
}
|
||||
|
||||
void Bookmarks::teleportToBookmark() {
|
||||
QAction* action = qobject_cast<QAction*>(sender());
|
||||
QString address = action->data().toString();
|
||||
DependencyManager::get<AddressManager>()->handleLookupString(address);
|
||||
}
|
||||
|
||||
void Bookmarks::deleteBookmark() {
|
||||
|
||||
QStringList bookmarkList;
|
||||
QList<QAction*> menuItems = _bookmarksMenu->actions();
|
||||
for (int i = 0; i < menuItems.count(); i += 1) {
|
||||
bookmarkList.append(menuItems[i]->text());
|
||||
}
|
||||
|
||||
QInputDialog deleteBookmarkDialog(qApp->getWindow());
|
||||
deleteBookmarkDialog.setWindowTitle("Delete Bookmark");
|
||||
deleteBookmarkDialog.setLabelText("Select the bookmark to delete");
|
||||
deleteBookmarkDialog.resize(400, 400);
|
||||
deleteBookmarkDialog.setOption(QInputDialog::UseListViewForComboBoxItems);
|
||||
deleteBookmarkDialog.setComboBoxItems(bookmarkList);
|
||||
deleteBookmarkDialog.setOkButtonText("Delete");
|
||||
|
||||
if (deleteBookmarkDialog.exec() == QDialog::Rejected) {
|
||||
return;
|
||||
}
|
||||
|
||||
QString bookmarkName = deleteBookmarkDialog.textValue().trimmed();
|
||||
if (bookmarkName.length() == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
removeLocationFromMenu(Menu::getInstance(), bookmarkName);
|
||||
remove(bookmarkName);
|
||||
|
||||
if (_bookmarksMenu->actions().count() == 0) {
|
||||
enableMenuItems(false);
|
||||
}
|
||||
}
|
||||
|
||||
void Bookmarks::enableMenuItems(bool enabled) {
|
||||
if (_bookmarksMenu) {
|
||||
_bookmarksMenu->setEnabled(enabled);
|
||||
}
|
||||
if (_deleteBookmarksAction) {
|
||||
_deleteBookmarksAction->setEnabled(enabled);
|
||||
}
|
||||
}
|
||||
|
||||
void Bookmarks::addLocationToMenu(Menu* menubar, QString& name, QString& address) {
|
||||
QAction* teleportAction = new QAction(_bookmarksMenu);
|
||||
teleportAction->setData(address);
|
||||
connect(teleportAction, SIGNAL(triggered()), this, SLOT(teleportToBookmark()));
|
||||
|
||||
menubar->addActionToQMenuAndActionHash(_bookmarksMenu, teleportAction,
|
||||
name, 0, QAction::NoRole);
|
||||
}
|
||||
|
||||
void Bookmarks::removeLocationFromMenu(Menu* menubar, QString& name) {
|
||||
menubar->removeAction(_bookmarksMenu, name);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -12,10 +12,13 @@
|
|||
#ifndef hifi_Bookmarks_h
|
||||
#define hifi_Bookmarks_h
|
||||
|
||||
#include <QJsonObject>
|
||||
#include <QDebug>
|
||||
#include <QMap>
|
||||
#include <QObject>
|
||||
#include <QPointer>
|
||||
|
||||
class QAction;
|
||||
class QMenu;
|
||||
class Menu;
|
||||
|
||||
class Bookmarks: public QObject {
|
||||
Q_OBJECT
|
||||
|
@ -23,19 +26,32 @@ class Bookmarks: public QObject {
|
|||
public:
|
||||
Bookmarks();
|
||||
|
||||
void setupMenus(Menu* menubar, QMenu* menu);
|
||||
|
||||
private slots:
|
||||
void bookmarkLocation();
|
||||
void teleportToBookmark();
|
||||
void deleteBookmark();
|
||||
|
||||
private:
|
||||
QVariantMap _bookmarks; // { name: address, ... }
|
||||
|
||||
QPointer<QMenu> _bookmarksMenu;
|
||||
QPointer<QAction> _deleteBookmarksAction;
|
||||
|
||||
const QString BOOKMARKS_FILENAME = "bookmarks.json";
|
||||
QString _bookmarksFilename;
|
||||
|
||||
void insert(const QString& name, const QString& address); // Overwrites any existing entry with same name.
|
||||
void remove(const QString& name);
|
||||
bool contains(const QString& name) const;
|
||||
|
||||
QVariantMap* getBookmarks() { return &_bookmarks; };
|
||||
|
||||
private:
|
||||
QVariantMap _bookmarks; // { name: address, ... }
|
||||
|
||||
const QString BOOKMARKS_FILENAME = "bookmarks.json";
|
||||
QString _bookmarksFilename;
|
||||
void readFromFile();
|
||||
void persistToFile();
|
||||
|
||||
void enableMenuItems(bool enabled);
|
||||
void addLocationToMenu(Menu* menubar, QString& name, QString& address);
|
||||
void removeLocationFromMenu(Menu* menubar, QString& name);
|
||||
};
|
||||
|
||||
#endif // hifi_Bookmarks_h
|
|
@ -15,6 +15,7 @@
|
|||
#include <PerfStat.h>
|
||||
|
||||
#include "Application.h"
|
||||
#include "Audio.h"
|
||||
#include "Menu.h"
|
||||
|
||||
#include "DatagramProcessor.h"
|
||||
|
@ -41,8 +42,8 @@ void DatagramProcessor::processDatagrams() {
|
|||
nodeList->getNodeSocket().readDatagram(incomingPacket.data(), incomingPacket.size(),
|
||||
senderSockAddr.getAddressPointer(), senderSockAddr.getPortPointer());
|
||||
|
||||
_packetCount++;
|
||||
_byteCount += incomingPacket.size();
|
||||
_inPacketCount++;
|
||||
_inByteCount += incomingPacket.size();
|
||||
|
||||
if (nodeList->packetVersionAndHashMatch(incomingPacket)) {
|
||||
|
||||
|
@ -81,6 +82,8 @@ void DatagramProcessor::processDatagrams() {
|
|||
// this will keep creatorTokenIDs to IDs mapped correctly
|
||||
EntityItemID::handleAddEntityResponse(incomingPacket);
|
||||
application->getEntities()->getTree()->handleAddEntityResponse(incomingPacket);
|
||||
application->_bandwidthRecorder.octreeChannel->input.updateValue(incomingPacket.size());
|
||||
application->_bandwidthRecorder.totalChannel->input.updateValue(incomingPacket.size());
|
||||
break;
|
||||
case PacketTypeEntityData:
|
||||
case PacketTypeEntityErase:
|
||||
|
@ -94,7 +97,8 @@ void DatagramProcessor::processDatagrams() {
|
|||
// add this packet to our list of octree packets and process them on the octree data processing
|
||||
application->_octreeProcessor.queueReceivedPacket(matchedNode, incomingPacket);
|
||||
}
|
||||
|
||||
application->_bandwidthRecorder.octreeChannel->input.updateValue(incomingPacket.size());
|
||||
application->_bandwidthRecorder.totalChannel->input.updateValue(incomingPacket.size());
|
||||
break;
|
||||
}
|
||||
case PacketTypeMetavoxelData:
|
||||
|
@ -116,7 +120,8 @@ void DatagramProcessor::processDatagrams() {
|
|||
Q_ARG(const QWeakPointer<Node>&, avatarMixer));
|
||||
}
|
||||
|
||||
application->_bandwidthMeter.inputStream(BandwidthMeter::AVATARS).updateValue(incomingPacket.size());
|
||||
application->_bandwidthRecorder.avatarsChannel->input.updateValue(incomingPacket.size());
|
||||
application->_bandwidthRecorder.totalChannel->input.updateValue(incomingPacket.size());
|
||||
break;
|
||||
}
|
||||
case PacketTypeDomainConnectionDenied: {
|
||||
|
|
|
@ -19,16 +19,20 @@ class DatagramProcessor : public QObject {
|
|||
public:
|
||||
DatagramProcessor(QObject* parent = 0);
|
||||
|
||||
int getPacketCount() const { return _packetCount; }
|
||||
int getByteCount() const { return _byteCount; }
|
||||
int getInPacketCount() const { return _inPacketCount; }
|
||||
int getOutPacketCount() const { return _outPacketCount; }
|
||||
int getInByteCount() const { return _inByteCount; }
|
||||
int getOutByteCount() const { return _outByteCount; }
|
||||
|
||||
void resetCounters() { _packetCount = 0; _byteCount = 0; }
|
||||
void resetCounters() { _inPacketCount = 0; _outPacketCount = 0; _inByteCount = 0; _outByteCount = 0; }
|
||||
public slots:
|
||||
void processDatagrams();
|
||||
|
||||
private:
|
||||
int _packetCount;
|
||||
int _byteCount;
|
||||
int _inPacketCount;
|
||||
int _outPacketCount;
|
||||
int _inByteCount;
|
||||
int _outByteCount;
|
||||
};
|
||||
|
||||
#endif // hifi_DatagramProcessor_h
|
||||
|
|
|
@ -263,7 +263,7 @@ void Environment::renderAtmosphere(Camera& camera, const EnvironmentData& data)
|
|||
|
||||
glDepthMask(GL_FALSE);
|
||||
glDisable(GL_DEPTH_TEST);
|
||||
DependencyManager::get<GeometryCache>()->renderSphere(1.0f, 100, 50); //Draw a unit sphere
|
||||
DependencyManager::get<GeometryCache>()->renderSphere(1.0f, 100, 50, glm::vec4(1.0f, 1.0f, 1.0f, 1.0f)); //Draw a unit sphere
|
||||
glDepthMask(GL_TRUE);
|
||||
|
||||
program->release();
|
||||
|
|
210
interface/src/LODManager.cpp
Normal file
210
interface/src/LODManager.cpp
Normal file
|
@ -0,0 +1,210 @@
|
|||
//
|
||||
// LODManager.cpp
|
||||
//
|
||||
//
|
||||
// Created by Clement on 1/16/15.
|
||||
// Copyright 2015 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#include <Util.h>
|
||||
|
||||
#include "Application.h"
|
||||
#include "ui/DialogsManager.h"
|
||||
|
||||
#include "LODManager.h"
|
||||
|
||||
namespace SettingHandles {
|
||||
const SettingHandle<bool> automaticAvatarLOD("automaticAvatarLOD", true);
|
||||
const SettingHandle<float> avatarLODDecreaseFPS("avatarLODDecreaseFPS", DEFAULT_ADJUST_AVATAR_LOD_DOWN_FPS);
|
||||
const SettingHandle<float> avatarLODIncreaseFPS("avatarLODIncreaseFPS", ADJUST_LOD_UP_FPS);
|
||||
const SettingHandle<float> avatarLODDistanceMultiplier("avatarLODDistanceMultiplier",
|
||||
DEFAULT_AVATAR_LOD_DISTANCE_MULTIPLIER);
|
||||
const SettingHandle<int> boundaryLevelAdjust("boundaryLevelAdjust", 0);
|
||||
const SettingHandle<float> octreeSizeScale("octreeSizeScale", DEFAULT_OCTREE_SIZE_SCALE);
|
||||
}
|
||||
|
||||
void LODManager::autoAdjustLOD(float currentFPS) {
|
||||
// NOTE: our first ~100 samples at app startup are completely all over the place, and we don't
|
||||
// really want to count them in our average, so we will ignore the real frame rates and stuff
|
||||
// our moving average with simulated good data
|
||||
const int IGNORE_THESE_SAMPLES = 100;
|
||||
const float ASSUMED_FPS = 60.0f;
|
||||
if (_fpsAverage.getSampleCount() < IGNORE_THESE_SAMPLES) {
|
||||
currentFPS = ASSUMED_FPS;
|
||||
}
|
||||
_fpsAverage.updateAverage(currentFPS);
|
||||
_fastFPSAverage.updateAverage(currentFPS);
|
||||
|
||||
quint64 now = usecTimestampNow();
|
||||
|
||||
const quint64 ADJUST_AVATAR_LOD_DOWN_DELAY = 1000 * 1000;
|
||||
if (_automaticAvatarLOD) {
|
||||
if (_fastFPSAverage.getAverage() < _avatarLODDecreaseFPS) {
|
||||
if (now - _lastAvatarDetailDrop > ADJUST_AVATAR_LOD_DOWN_DELAY) {
|
||||
// attempt to lower the detail in proportion to the fps difference
|
||||
float targetFps = (_avatarLODDecreaseFPS + _avatarLODIncreaseFPS) * 0.5f;
|
||||
float averageFps = _fastFPSAverage.getAverage();
|
||||
const float MAXIMUM_MULTIPLIER_SCALE = 2.0f;
|
||||
_avatarLODDistanceMultiplier = qMin(MAXIMUM_AVATAR_LOD_DISTANCE_MULTIPLIER, _avatarLODDistanceMultiplier *
|
||||
(averageFps < EPSILON ? MAXIMUM_MULTIPLIER_SCALE :
|
||||
qMin(MAXIMUM_MULTIPLIER_SCALE, targetFps / averageFps)));
|
||||
_lastAvatarDetailDrop = now;
|
||||
}
|
||||
} else if (_fastFPSAverage.getAverage() > _avatarLODIncreaseFPS) {
|
||||
// let the detail level creep slowly upwards
|
||||
const float DISTANCE_DECREASE_RATE = 0.05f;
|
||||
_avatarLODDistanceMultiplier = qMax(MINIMUM_AVATAR_LOD_DISTANCE_MULTIPLIER,
|
||||
_avatarLODDistanceMultiplier - DISTANCE_DECREASE_RATE);
|
||||
}
|
||||
}
|
||||
|
||||
bool changed = false;
|
||||
quint64 elapsed = now - _lastAdjust;
|
||||
|
||||
if (elapsed > ADJUST_LOD_DOWN_DELAY && _fpsAverage.getAverage() < ADJUST_LOD_DOWN_FPS
|
||||
&& _octreeSizeScale > ADJUST_LOD_MIN_SIZE_SCALE) {
|
||||
|
||||
_octreeSizeScale *= ADJUST_LOD_DOWN_BY;
|
||||
|
||||
if (_octreeSizeScale < ADJUST_LOD_MIN_SIZE_SCALE) {
|
||||
_octreeSizeScale = ADJUST_LOD_MIN_SIZE_SCALE;
|
||||
}
|
||||
changed = true;
|
||||
_lastAdjust = now;
|
||||
qDebug() << "adjusting LOD down... average fps for last approximately 5 seconds=" << _fpsAverage.getAverage()
|
||||
<< "_octreeSizeScale=" << _octreeSizeScale;
|
||||
}
|
||||
|
||||
if (elapsed > ADJUST_LOD_UP_DELAY && _fpsAverage.getAverage() > ADJUST_LOD_UP_FPS
|
||||
&& _octreeSizeScale < ADJUST_LOD_MAX_SIZE_SCALE) {
|
||||
_octreeSizeScale *= ADJUST_LOD_UP_BY;
|
||||
if (_octreeSizeScale > ADJUST_LOD_MAX_SIZE_SCALE) {
|
||||
_octreeSizeScale = ADJUST_LOD_MAX_SIZE_SCALE;
|
||||
}
|
||||
changed = true;
|
||||
_lastAdjust = now;
|
||||
qDebug() << "adjusting LOD up... average fps for last approximately 5 seconds=" << _fpsAverage.getAverage()
|
||||
<< "_octreeSizeScale=" << _octreeSizeScale;
|
||||
}
|
||||
|
||||
if (changed) {
|
||||
_shouldRenderTableNeedsRebuilding = true;
|
||||
auto lodToolsDialog = DependencyManager::get<DialogsManager>()->getLodToolsDialog();
|
||||
if (lodToolsDialog) {
|
||||
lodToolsDialog->reloadSliders();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void LODManager::resetLODAdjust() {
|
||||
_fpsAverage.reset();
|
||||
_fastFPSAverage.reset();
|
||||
_lastAvatarDetailDrop = _lastAdjust = usecTimestampNow();
|
||||
}
|
||||
|
||||
QString LODManager::getLODFeedbackText() {
|
||||
// determine granularity feedback
|
||||
int boundaryLevelAdjust = getBoundaryLevelAdjust();
|
||||
QString granularityFeedback;
|
||||
|
||||
switch (boundaryLevelAdjust) {
|
||||
case 0: {
|
||||
granularityFeedback = QString("at standard granularity.");
|
||||
} break;
|
||||
case 1: {
|
||||
granularityFeedback = QString("at half of standard granularity.");
|
||||
} break;
|
||||
case 2: {
|
||||
granularityFeedback = QString("at a third of standard granularity.");
|
||||
} break;
|
||||
default: {
|
||||
granularityFeedback = QString("at 1/%1th of standard granularity.").arg(boundaryLevelAdjust + 1);
|
||||
} break;
|
||||
}
|
||||
|
||||
// distance feedback
|
||||
float octreeSizeScale = getOctreeSizeScale();
|
||||
float relativeToDefault = octreeSizeScale / DEFAULT_OCTREE_SIZE_SCALE;
|
||||
QString result;
|
||||
if (relativeToDefault > 1.01) {
|
||||
result = QString("%1 further %2").arg(relativeToDefault,8,'f',2).arg(granularityFeedback);
|
||||
} else if (relativeToDefault > 0.99) {
|
||||
result = QString("the default distance %1").arg(granularityFeedback);
|
||||
} else {
|
||||
result = QString("%1 of default %2").arg(relativeToDefault,8,'f',3).arg(granularityFeedback);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
// TODO: This is essentially the same logic used to render octree cells, but since models are more detailed then octree cells
|
||||
// I've added a voxelToModelRatio that adjusts how much closer to a model you have to be to see it.
|
||||
bool LODManager::shouldRenderMesh(float largestDimension, float distanceToCamera) {
|
||||
const float octreeToMeshRatio = 4.0f; // must be this many times closer to a mesh than a voxel to see it.
|
||||
float octreeSizeScale = getOctreeSizeScale();
|
||||
int boundaryLevelAdjust = getBoundaryLevelAdjust();
|
||||
float maxScale = (float)TREE_SCALE;
|
||||
float visibleDistanceAtMaxScale = boundaryDistanceForRenderLevel(boundaryLevelAdjust, octreeSizeScale) / octreeToMeshRatio;
|
||||
|
||||
if (_shouldRenderTableNeedsRebuilding) {
|
||||
_shouldRenderTable.clear();
|
||||
|
||||
float SMALLEST_SCALE_IN_TABLE = 0.001f; // 1mm is plenty small
|
||||
float scale = maxScale;
|
||||
float visibleDistanceAtScale = visibleDistanceAtMaxScale;
|
||||
|
||||
while (scale > SMALLEST_SCALE_IN_TABLE) {
|
||||
scale /= 2.0f;
|
||||
visibleDistanceAtScale /= 2.0f;
|
||||
_shouldRenderTable[scale] = visibleDistanceAtScale;
|
||||
}
|
||||
_shouldRenderTableNeedsRebuilding = false;
|
||||
}
|
||||
|
||||
float closestScale = maxScale;
|
||||
float visibleDistanceAtClosestScale = visibleDistanceAtMaxScale;
|
||||
QMap<float, float>::const_iterator lowerBound = _shouldRenderTable.lowerBound(largestDimension);
|
||||
if (lowerBound != _shouldRenderTable.constEnd()) {
|
||||
closestScale = lowerBound.key();
|
||||
visibleDistanceAtClosestScale = lowerBound.value();
|
||||
}
|
||||
|
||||
if (closestScale < largestDimension) {
|
||||
visibleDistanceAtClosestScale *= 2.0f;
|
||||
}
|
||||
|
||||
return (distanceToCamera <= visibleDistanceAtClosestScale);
|
||||
}
|
||||
|
||||
void LODManager::setOctreeSizeScale(float sizeScale) {
|
||||
_octreeSizeScale = sizeScale;
|
||||
_shouldRenderTableNeedsRebuilding = true;
|
||||
}
|
||||
|
||||
void LODManager::setBoundaryLevelAdjust(int boundaryLevelAdjust) {
|
||||
_boundaryLevelAdjust = boundaryLevelAdjust;
|
||||
_shouldRenderTableNeedsRebuilding = true;
|
||||
}
|
||||
|
||||
|
||||
void LODManager::loadSettings() {
|
||||
setAutomaticAvatarLOD(SettingHandles::automaticAvatarLOD.get());
|
||||
setAvatarLODDecreaseFPS(SettingHandles::avatarLODDecreaseFPS.get());
|
||||
setAvatarLODIncreaseFPS(SettingHandles::avatarLODIncreaseFPS.get());
|
||||
setAvatarLODDistanceMultiplier(SettingHandles::avatarLODDistanceMultiplier.get());
|
||||
setBoundaryLevelAdjust(SettingHandles::boundaryLevelAdjust.get());
|
||||
setOctreeSizeScale(SettingHandles::octreeSizeScale.get());
|
||||
}
|
||||
|
||||
void LODManager::saveSettings() {
|
||||
SettingHandles::automaticAvatarLOD.set(getAutomaticAvatarLOD());
|
||||
SettingHandles::avatarLODDecreaseFPS.set(getAvatarLODDecreaseFPS());
|
||||
SettingHandles::avatarLODIncreaseFPS.set(getAvatarLODIncreaseFPS());
|
||||
SettingHandles::avatarLODDistanceMultiplier.set(getAvatarLODDistanceMultiplier());
|
||||
SettingHandles::boundaryLevelAdjust.set(getBoundaryLevelAdjust());
|
||||
SettingHandles::octreeSizeScale.set(getOctreeSizeScale());
|
||||
}
|
||||
|
||||
|
91
interface/src/LODManager.h
Normal file
91
interface/src/LODManager.h
Normal file
|
@ -0,0 +1,91 @@
|
|||
//
|
||||
// LODManager.h
|
||||
//
|
||||
//
|
||||
// Created by Clement on 1/16/15.
|
||||
// Copyright 2015 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#ifndef hifi_LODManager_h
|
||||
#define hifi_LODManager_h
|
||||
|
||||
#include <DependencyManager.h>
|
||||
#include <OctreeConstants.h>
|
||||
#include <Settings.h>
|
||||
#include <SharedUtil.h>
|
||||
#include <SimpleMovingAverage.h>
|
||||
|
||||
const float ADJUST_LOD_DOWN_FPS = 40.0;
|
||||
const float ADJUST_LOD_UP_FPS = 55.0;
|
||||
const float DEFAULT_ADJUST_AVATAR_LOD_DOWN_FPS = 30.0f;
|
||||
|
||||
const quint64 ADJUST_LOD_DOWN_DELAY = 1000 * 1000 * 5;
|
||||
const quint64 ADJUST_LOD_UP_DELAY = ADJUST_LOD_DOWN_DELAY * 2;
|
||||
|
||||
const float ADJUST_LOD_DOWN_BY = 0.9f;
|
||||
const float ADJUST_LOD_UP_BY = 1.1f;
|
||||
|
||||
const float ADJUST_LOD_MIN_SIZE_SCALE = DEFAULT_OCTREE_SIZE_SCALE * 0.25f;
|
||||
const float ADJUST_LOD_MAX_SIZE_SCALE = DEFAULT_OCTREE_SIZE_SCALE;
|
||||
|
||||
const float MINIMUM_AVATAR_LOD_DISTANCE_MULTIPLIER = 0.1f;
|
||||
const float MAXIMUM_AVATAR_LOD_DISTANCE_MULTIPLIER = 15.0f;
|
||||
const float DEFAULT_AVATAR_LOD_DISTANCE_MULTIPLIER = 1.0f;
|
||||
|
||||
const int ONE_SECOND_OF_FRAMES = 60;
|
||||
const int FIVE_SECONDS_OF_FRAMES = 5 * ONE_SECOND_OF_FRAMES;
|
||||
|
||||
|
||||
class LODManager : public Dependency {
|
||||
SINGLETON_DEPENDENCY
|
||||
|
||||
public:
|
||||
void setAutomaticAvatarLOD(bool automaticAvatarLOD) { _automaticAvatarLOD = automaticAvatarLOD; }
|
||||
bool getAutomaticAvatarLOD() const { return _automaticAvatarLOD; }
|
||||
void setAvatarLODDecreaseFPS(float avatarLODDecreaseFPS) { _avatarLODDecreaseFPS = avatarLODDecreaseFPS; }
|
||||
float getAvatarLODDecreaseFPS() const { return _avatarLODDecreaseFPS; }
|
||||
void setAvatarLODIncreaseFPS(float avatarLODIncreaseFPS) { _avatarLODIncreaseFPS = avatarLODIncreaseFPS; }
|
||||
float getAvatarLODIncreaseFPS() const { return _avatarLODIncreaseFPS; }
|
||||
void setAvatarLODDistanceMultiplier(float multiplier) { _avatarLODDistanceMultiplier = multiplier; }
|
||||
float getAvatarLODDistanceMultiplier() const { return _avatarLODDistanceMultiplier; }
|
||||
|
||||
// User Tweakable LOD Items
|
||||
QString getLODFeedbackText();
|
||||
void setOctreeSizeScale(float sizeScale);
|
||||
float getOctreeSizeScale() const { return _octreeSizeScale; }
|
||||
|
||||
void setBoundaryLevelAdjust(int boundaryLevelAdjust);
|
||||
int getBoundaryLevelAdjust() const { return _boundaryLevelAdjust; }
|
||||
|
||||
void autoAdjustLOD(float currentFPS);
|
||||
void resetLODAdjust();
|
||||
|
||||
bool shouldRenderMesh(float largestDimension, float distanceToCamera);
|
||||
|
||||
void loadSettings();
|
||||
void saveSettings();
|
||||
|
||||
private:
|
||||
LODManager() {}
|
||||
|
||||
bool _automaticAvatarLOD = true;
|
||||
float _avatarLODDecreaseFPS = DEFAULT_ADJUST_AVATAR_LOD_DOWN_FPS;
|
||||
float _avatarLODIncreaseFPS = ADJUST_LOD_UP_FPS;
|
||||
float _avatarLODDistanceMultiplier = DEFAULT_AVATAR_LOD_DISTANCE_MULTIPLIER;
|
||||
|
||||
float _octreeSizeScale = DEFAULT_OCTREE_SIZE_SCALE;
|
||||
int _boundaryLevelAdjust = 0;
|
||||
|
||||
quint64 _lastAdjust = 0;
|
||||
quint64 _lastAvatarDetailDrop = 0;
|
||||
SimpleMovingAverage _fpsAverage = FIVE_SECONDS_OF_FRAMES;
|
||||
SimpleMovingAverage _fastFPSAverage = ONE_SECOND_OF_FRAMES;
|
||||
|
||||
bool _shouldRenderTableNeedsRebuilding = true;
|
||||
QMap<float, float> _shouldRenderTable;
|
||||
};
|
||||
|
||||
#endif // hifi_LODManager_h
|
|
@ -9,9 +9,8 @@
|
|||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#include "MainWindow.h"
|
||||
#include "Menu.h"
|
||||
|
||||
#include <QApplication>
|
||||
#include <QDesktopWidget>
|
||||
#include <QEvent>
|
||||
#include <QMoveEvent>
|
||||
#include <QResizeEvent>
|
||||
|
@ -19,8 +18,33 @@
|
|||
#include <QHideEvent>
|
||||
#include <QWindowStateChangeEvent>
|
||||
|
||||
MainWindow::MainWindow(QWidget* parent) :
|
||||
QMainWindow(parent) {
|
||||
#include <Settings.h>
|
||||
|
||||
#include "MainWindow.h"
|
||||
#include "Menu.h"
|
||||
#include "Util.h"
|
||||
|
||||
namespace SettingHandles {
|
||||
const SettingHandle<QRect> windowGeometry("WindowGeometry");
|
||||
}
|
||||
|
||||
|
||||
MainWindow::MainWindow(QWidget* parent) : QMainWindow(parent) {
|
||||
}
|
||||
|
||||
void MainWindow::restoreGeometry() {
|
||||
// Did not use setGeometry() on purpose,
|
||||
// see http://doc.qt.io/qt-5/qsettings.html#restoring-the-state-of-a-gui-application
|
||||
QRect geometry = SettingHandles::windowGeometry.get(qApp->desktop()->availableGeometry());
|
||||
move(geometry.topLeft());
|
||||
resize(geometry.size());
|
||||
}
|
||||
|
||||
void MainWindow::saveGeometry() {
|
||||
// Did not use geometry() on purpose,
|
||||
// see http://doc.qt.io/qt-5/qsettings.html#restoring-the-state-of-a-gui-application
|
||||
QRect geometry(pos(), size());
|
||||
SettingHandles::windowGeometry.set(geometry);
|
||||
}
|
||||
|
||||
void MainWindow::moveEvent(QMoveEvent* event) {
|
||||
|
|
|
@ -14,12 +14,15 @@
|
|||
|
||||
#include <QMainWindow>
|
||||
|
||||
class MainWindow : public QMainWindow
|
||||
{
|
||||
class MainWindow : public QMainWindow {
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit MainWindow(QWidget* parent = NULL);
|
||||
|
||||
|
||||
public slots:
|
||||
void restoreGeometry();
|
||||
void saveGeometry();
|
||||
|
||||
signals:
|
||||
void windowGeometryChanged(QRect geometry);
|
||||
void windowShown(bool shown);
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -19,128 +19,23 @@
|
|||
#include <QPointer>
|
||||
#include <QStandardPaths>
|
||||
|
||||
#include <EventTypes.h>
|
||||
#include <MenuItemProperties.h>
|
||||
#include <OctreeConstants.h>
|
||||
|
||||
#if defined(Q_OS_MAC) || defined(Q_OS_WIN)
|
||||
#include "SpeechRecognizer.h"
|
||||
#endif
|
||||
|
||||
#include "devices/Faceshift.h"
|
||||
#include "devices/SixenseManager.h"
|
||||
#include "ui/ChatWindow.h"
|
||||
#include "ui/JSConsole.h"
|
||||
#include "ui/ScriptEditorWindow.h"
|
||||
|
||||
// Make an LOD handler class and move everything overthere
|
||||
const float ADJUST_LOD_DOWN_FPS = 40.0;
|
||||
const float ADJUST_LOD_UP_FPS = 55.0;
|
||||
const float DEFAULT_ADJUST_AVATAR_LOD_DOWN_FPS = 30.0f;
|
||||
|
||||
const quint64 ADJUST_LOD_DOWN_DELAY = 1000 * 1000 * 5;
|
||||
const quint64 ADJUST_LOD_UP_DELAY = ADJUST_LOD_DOWN_DELAY * 2;
|
||||
|
||||
const float ADJUST_LOD_DOWN_BY = 0.9f;
|
||||
const float ADJUST_LOD_UP_BY = 1.1f;
|
||||
|
||||
const float ADJUST_LOD_MIN_SIZE_SCALE = DEFAULT_OCTREE_SIZE_SCALE * 0.25f;
|
||||
const float ADJUST_LOD_MAX_SIZE_SCALE = DEFAULT_OCTREE_SIZE_SCALE;
|
||||
|
||||
const float MINIMUM_AVATAR_LOD_DISTANCE_MULTIPLIER = 0.1f;
|
||||
const float MAXIMUM_AVATAR_LOD_DISTANCE_MULTIPLIER = 15.0f;
|
||||
const float DEFAULT_AVATAR_LOD_DISTANCE_MULTIPLIER = 1.0f;
|
||||
|
||||
const int ONE_SECOND_OF_FRAMES = 60;
|
||||
const int FIVE_SECONDS_OF_FRAMES = 5 * ONE_SECOND_OF_FRAMES;
|
||||
//////////////////////////////////////////////////////////
|
||||
|
||||
const float DEFAULT_OCULUS_UI_ANGULAR_SIZE = 72.0f;
|
||||
|
||||
const QString SETTINGS_ADDRESS_KEY = "address";
|
||||
class QSettings;
|
||||
|
||||
class AddressBarDialog;
|
||||
class AnimationsDialog;
|
||||
class AttachmentsDialog;
|
||||
class CachesSizeDialog;
|
||||
class BandwidthDialog;
|
||||
class DataWebDialog;
|
||||
class HMDToolsDialog;
|
||||
class LodToolsDialog;
|
||||
class LoginDialog;
|
||||
class OctreeStatsDialog;
|
||||
class PreferencesDialog;
|
||||
class MetavoxelEditor;
|
||||
class MetavoxelNetworkSimulator;
|
||||
class ChatWindow;
|
||||
class MenuItemProperties;
|
||||
class Settings;
|
||||
|
||||
class Menu : public QMenuBar {
|
||||
Q_OBJECT
|
||||
public:
|
||||
static Menu* getInstance();
|
||||
|
||||
void loadSettings();
|
||||
void saveSettings();
|
||||
|
||||
QMenu* getMenu(const QString& menuName);
|
||||
|
||||
void triggerOption(const QString& menuOption);
|
||||
QAction* getActionForOption(const QString& menuOption);
|
||||
|
||||
const InboundAudioStream::Settings& getReceivedAudioStreamSettings() const { return _receivedAudioStreamSettings; }
|
||||
void setReceivedAudioStreamSettings(const InboundAudioStream::Settings& receivedAudioStreamSettings) { _receivedAudioStreamSettings = receivedAudioStreamSettings; }
|
||||
float getFieldOfView() const { return _fieldOfView; }
|
||||
void setFieldOfView(float fieldOfView) { _fieldOfView = fieldOfView; bumpSettings(); }
|
||||
float getRealWorldFieldOfView() const { return _realWorldFieldOfView; }
|
||||
void setRealWorldFieldOfView(float realWorldFieldOfView) { _realWorldFieldOfView = realWorldFieldOfView; bumpSettings(); }
|
||||
float getOculusUIAngularSize() const { return _oculusUIAngularSize; }
|
||||
void setOculusUIAngularSize(float oculusUIAngularSize) { _oculusUIAngularSize = oculusUIAngularSize; bumpSettings(); }
|
||||
float getSixenseReticleMoveSpeed() const { return _sixenseReticleMoveSpeed; }
|
||||
void setSixenseReticleMoveSpeed(float sixenseReticleMoveSpeed) { _sixenseReticleMoveSpeed = sixenseReticleMoveSpeed; bumpSettings(); }
|
||||
bool getInvertSixenseButtons() const { return _invertSixenseButtons; }
|
||||
void setInvertSixenseButtons(bool invertSixenseButtons) { _invertSixenseButtons = invertSixenseButtons; bumpSettings(); }
|
||||
|
||||
float getFaceshiftEyeDeflection() const { return _faceshiftEyeDeflection; }
|
||||
void setFaceshiftEyeDeflection(float faceshiftEyeDeflection) { _faceshiftEyeDeflection = faceshiftEyeDeflection; bumpSettings(); }
|
||||
const QString& getFaceshiftHostname() const { return _faceshiftHostname; }
|
||||
void setFaceshiftHostname(const QString& hostname) { _faceshiftHostname = hostname; bumpSettings(); }
|
||||
QString getSnapshotsLocation() const;
|
||||
void setSnapshotsLocation(QString snapshotsLocation) { _snapshotsLocation = snapshotsLocation; bumpSettings(); }
|
||||
|
||||
const QString& getScriptsLocation() const { return _scriptsLocation; }
|
||||
void setScriptsLocation(const QString& scriptsLocation);
|
||||
|
||||
BandwidthDialog* getBandwidthDialog() const { return _bandwidthDialog; }
|
||||
OctreeStatsDialog* getOctreeStatsDialog() const { return _octreeStatsDialog; }
|
||||
LodToolsDialog* getLodToolsDialog() const { return _lodToolsDialog; }
|
||||
HMDToolsDialog* getHMDToolsDialog() const { return _hmdToolsDialog; }
|
||||
|
||||
bool getShadowsEnabled() const;
|
||||
|
||||
// User Tweakable LOD Items
|
||||
QString getLODFeedbackText();
|
||||
void autoAdjustLOD(float currentFPS);
|
||||
void resetLODAdjust();
|
||||
void setOctreeSizeScale(float sizeScale);
|
||||
float getOctreeSizeScale() const { return _octreeSizeScale; }
|
||||
void setAutomaticAvatarLOD(bool automaticAvatarLOD) { _automaticAvatarLOD = automaticAvatarLOD; bumpSettings(); }
|
||||
bool getAutomaticAvatarLOD() const { return _automaticAvatarLOD; }
|
||||
void setAvatarLODDecreaseFPS(float avatarLODDecreaseFPS) { _avatarLODDecreaseFPS = avatarLODDecreaseFPS; bumpSettings(); }
|
||||
float getAvatarLODDecreaseFPS() const { return _avatarLODDecreaseFPS; }
|
||||
void setAvatarLODIncreaseFPS(float avatarLODIncreaseFPS) { _avatarLODIncreaseFPS = avatarLODIncreaseFPS; bumpSettings(); }
|
||||
float getAvatarLODIncreaseFPS() const { return _avatarLODIncreaseFPS; }
|
||||
void setAvatarLODDistanceMultiplier(float multiplier) { _avatarLODDistanceMultiplier = multiplier; bumpSettings(); }
|
||||
float getAvatarLODDistanceMultiplier() const { return _avatarLODDistanceMultiplier; }
|
||||
void setBoundaryLevelAdjust(int boundaryLevelAdjust);
|
||||
int getBoundaryLevelAdjust() const { return _boundaryLevelAdjust; }
|
||||
|
||||
bool shouldRenderMesh(float largestDimension, float distanceToCamera);
|
||||
|
||||
#if defined(Q_OS_MAC) || defined(Q_OS_WIN)
|
||||
SpeechRecognizer* getSpeechRecognizer() { return &_speechRecognizer; }
|
||||
#endif
|
||||
|
||||
// User Tweakable PPS from Voxel Server
|
||||
int getMaxOctreePacketsPerSecond() const { return _maxOctreePacketsPerSecond; }
|
||||
void setMaxOctreePacketsPerSecond(int value) { _maxOctreePacketsPerSecond = value; bumpSettings(); }
|
||||
|
||||
|
||||
QAction* addActionToQMenuAndActionHash(QMenu* destinationMenu,
|
||||
const QString& actionName,
|
||||
const QKeySequence& shortcut = 0,
|
||||
|
@ -154,35 +49,10 @@ public:
|
|||
const QKeySequence& shortcut = 0,
|
||||
QAction::MenuRole role = QAction::NoRole,
|
||||
int menuItemLocation = UNSPECIFIED_POSITION);
|
||||
|
||||
|
||||
void removeAction(QMenu* menu, const QString& actionName);
|
||||
|
||||
const QByteArray& getWalletPrivateKey() const { return _walletPrivateKey; }
|
||||
|
||||
signals:
|
||||
void scriptLocationChanged(const QString& newPath);
|
||||
|
||||
public slots:
|
||||
|
||||
void clearLoginDialogDisplayedFlag();
|
||||
void loginForCurrentDomain();
|
||||
void showLoginForCurrentDomain();
|
||||
void bandwidthDetails();
|
||||
void octreeStatsDetails();
|
||||
void cachesSizeDialog();
|
||||
void lodTools();
|
||||
void hmdTools(bool showTools);
|
||||
void loadSettings(QSettings* settings = NULL);
|
||||
void saveSettings(QSettings* settings = NULL);
|
||||
void importSettings();
|
||||
void exportSettings();
|
||||
void toggleAddressBar();
|
||||
void copyAddress();
|
||||
void copyPath();
|
||||
|
||||
void toggleLoginMenuItem();
|
||||
void toggleSixense(bool shouldEnable);
|
||||
|
||||
QMenu* addMenu(const QString& menuName);
|
||||
void removeMenu(const QString& menuName);
|
||||
bool menuExists(const QString& menuName);
|
||||
|
@ -193,47 +63,21 @@ public slots:
|
|||
bool menuItemExists(const QString& menuName, const QString& menuitem);
|
||||
bool isOptionChecked(const QString& menuOption) const;
|
||||
void setIsOptionChecked(const QString& menuOption, bool isChecked);
|
||||
|
||||
private slots:
|
||||
void aboutApp();
|
||||
void showEditEntitiesHelp();
|
||||
void bumpSettings();
|
||||
void editPreferences();
|
||||
void editAttachments();
|
||||
void editAnimations();
|
||||
void changePrivateKey();
|
||||
void bookmarkLocation();
|
||||
void teleportToBookmark();
|
||||
void deleteBookmark();
|
||||
void hmdToolsClosed();
|
||||
void runTests();
|
||||
void showMetavoxelEditor();
|
||||
void showMetavoxelNetworkSimulator();
|
||||
void showScriptEditor();
|
||||
void showChat();
|
||||
void toggleConsole();
|
||||
void toggleToolWindow();
|
||||
void toggleChat();
|
||||
void audioMuteToggled();
|
||||
void displayNameLocationResponse(const QString& errorString);
|
||||
void changeVSync();
|
||||
void loadRSSDKFile();
|
||||
|
||||
|
||||
private:
|
||||
static Menu* _instance;
|
||||
|
||||
Menu();
|
||||
|
||||
typedef void(*settingsAction)(QSettings*, QAction*);
|
||||
static void loadAction(QSettings* set, QAction* action);
|
||||
static void saveAction(QSettings* set, QAction* action);
|
||||
void scanMenuBar(settingsAction modifySetting, QSettings* set);
|
||||
void scanMenu(QMenu* menu, settingsAction modifySetting, QSettings* set);
|
||||
|
||||
|
||||
typedef void(*settingsAction)(Settings&, QAction&);
|
||||
static void loadAction(Settings& settings, QAction& action);
|
||||
static void saveAction(Settings& settings, QAction& action);
|
||||
void scanMenuBar(settingsAction modifySetting);
|
||||
void scanMenu(QMenu& menu, settingsAction modifySetting, Settings& settings);
|
||||
|
||||
/// helper method to have separators with labels that are also compatible with OS X
|
||||
void addDisabledActionAndSeparator(QMenu* destinationMenu, const QString& actionName,
|
||||
int menuItemLocation = UNSPECIFIED_POSITION);
|
||||
|
||||
int menuItemLocation = UNSPECIFIED_POSITION);
|
||||
|
||||
QAction* addCheckableActionToQMenuAndActionHash(QMenu* destinationMenu,
|
||||
const QString& actionName,
|
||||
const QKeySequence& shortcut = 0,
|
||||
|
@ -241,78 +85,17 @@ private:
|
|||
const QObject* receiver = NULL,
|
||||
const char* member = NULL,
|
||||
int menuItemLocation = UNSPECIFIED_POSITION);
|
||||
|
||||
|
||||
QAction* getActionFromName(const QString& menuName, QMenu* menu);
|
||||
QMenu* getSubMenuFromName(const QString& menuName, QMenu* menu);
|
||||
QMenu* getMenuParent(const QString& menuName, QString& finalMenuPart);
|
||||
|
||||
|
||||
QAction* getMenuAction(const QString& menuName);
|
||||
int findPositionOfMenuItem(QMenu* menu, const QString& searchMenuItem);
|
||||
int positionBeforeSeparatorIfNeeded(QMenu* menu, int requestedPosition);
|
||||
QMenu* getMenu(const QString& menuName);
|
||||
|
||||
|
||||
|
||||
|
||||
QHash<QString, QAction*> _actionHash;
|
||||
InboundAudioStream::Settings _receivedAudioStreamSettings;
|
||||
// in Degrees, doesn't apply to HMD like Oculus
|
||||
float _fieldOfView = DEFAULT_FIELD_OF_VIEW_DEGREES;
|
||||
// The actual FOV set by the user's monitor size and view distance
|
||||
float _realWorldFieldOfView = DEFAULT_REAL_WORLD_FIELD_OF_VIEW_DEGREES;
|
||||
float _faceshiftEyeDeflection = DEFAULT_FACESHIFT_EYE_DEFLECTION;
|
||||
QString _faceshiftHostname = DEFAULT_FACESHIFT_HOSTNAME;
|
||||
|
||||
QDialog* _jsConsole = nullptr;
|
||||
#if defined(Q_OS_MAC) || defined(Q_OS_WIN)
|
||||
SpeechRecognizer _speechRecognizer;
|
||||
#endif
|
||||
float _octreeSizeScale = DEFAULT_OCTREE_SIZE_SCALE;
|
||||
float _oculusUIAngularSize = DEFAULT_OCULUS_UI_ANGULAR_SIZE;
|
||||
float _sixenseReticleMoveSpeed = DEFAULT_SIXENSE_RETICLE_MOVE_SPEED;
|
||||
bool _invertSixenseButtons = DEFAULT_INVERT_SIXENSE_MOUSE_BUTTONS;
|
||||
bool _hasLoginDialogDisplayed = false;
|
||||
|
||||
bool _automaticAvatarLOD = true;
|
||||
float _avatarLODDecreaseFPS = DEFAULT_ADJUST_AVATAR_LOD_DOWN_FPS;
|
||||
float _avatarLODIncreaseFPS = ADJUST_LOD_UP_FPS;
|
||||
float _avatarLODDistanceMultiplier = DEFAULT_AVATAR_LOD_DISTANCE_MULTIPLIER;
|
||||
|
||||
int _boundaryLevelAdjust = 0;
|
||||
int _maxOctreePacketsPerSecond = DEFAULT_MAX_OCTREE_PPS;
|
||||
|
||||
quint64 _lastAdjust;
|
||||
quint64 _lastAvatarDetailDrop;
|
||||
|
||||
SimpleMovingAverage _fpsAverage = FIVE_SECONDS_OF_FRAMES;
|
||||
SimpleMovingAverage _fastFPSAverage = ONE_SECOND_OF_FRAMES;
|
||||
|
||||
QPointer<AddressBarDialog> _addressBarDialog;
|
||||
QPointer<AnimationsDialog> _animationsDialog;
|
||||
QPointer<AttachmentsDialog> _attachmentsDialog;
|
||||
QPointer<BandwidthDialog> _bandwidthDialog;
|
||||
QPointer<CachesSizeDialog> _cachesSizeDialog;
|
||||
QPointer<HMDToolsDialog> _hmdToolsDialog;
|
||||
QPointer<LodToolsDialog> _lodToolsDialog;
|
||||
QPointer<LoginDialog> _loginDialog;
|
||||
QPointer<OctreeStatsDialog> _octreeStatsDialog;
|
||||
QPointer<PreferencesDialog> _preferencesDialog;
|
||||
|
||||
QPointer<MetavoxelEditor> _MetavoxelEditor;
|
||||
QPointer<MetavoxelNetworkSimulator> _metavoxelNetworkSimulator;
|
||||
QPointer<ScriptEditorWindow> _ScriptEditor;
|
||||
QPointer<ChatWindow> _chatWindow;
|
||||
|
||||
QAction* _loginAction = nullptr;
|
||||
QAction* _chatAction = nullptr;
|
||||
QString _snapshotsLocation;
|
||||
QString _scriptsLocation;
|
||||
QByteArray _walletPrivateKey;
|
||||
|
||||
bool _shouldRenderTableNeedsRebuilding = true;
|
||||
QMap<float, float> _shouldRenderTable;
|
||||
|
||||
void loadBookmarks();
|
||||
QMenu* _bookmarksMenu;
|
||||
QAction* _deleteBookmarksMenu;
|
||||
};
|
||||
|
||||
namespace MenuOption {
|
||||
|
@ -337,7 +120,6 @@ namespace MenuOption {
|
|||
const QString AudioSourcePinkNoise = "Pink Noise";
|
||||
const QString AudioSourceSine440 = "Sine 440hz";
|
||||
const QString Avatars = "Avatars";
|
||||
const QString Bandwidth = "Bandwidth Display";
|
||||
const QString BandwidthDetails = "Bandwidth Details";
|
||||
const QString BlueSpeechSphere = "Blue Sphere While Speaking";
|
||||
const QString BookmarkLocation = "Bookmark Location";
|
||||
|
@ -402,7 +184,6 @@ namespace MenuOption {
|
|||
const QString LodTools = "LOD Tools";
|
||||
const QString Login = "Login";
|
||||
const QString Log = "Log";
|
||||
const QString Logout = "Logout";
|
||||
const QString LowVelocityFilter = "Low Velocity Filter";
|
||||
const QString MetavoxelEditor = "Metavoxel Editor...";
|
||||
const QString Metavoxels = "Metavoxels";
|
||||
|
@ -484,10 +265,7 @@ namespace MenuOption {
|
|||
const QString UploadSkeleton = "Upload Skeleton Model";
|
||||
const QString UserInterface = "User Interface";
|
||||
const QString Visage = "Visage";
|
||||
const QString WalletPrivateKey = "Wallet Private Key...";
|
||||
const QString Wireframe = "Wireframe";
|
||||
}
|
||||
|
||||
void sendFakeEnterEvent();
|
||||
|
||||
#endif // hifi_Menu_h
|
||||
|
|
|
@ -899,7 +899,8 @@ int MetavoxelSystemClient::parseData(const QByteArray& packet) {
|
|||
} else {
|
||||
QMetaObject::invokeMethod(&_sequencer, "receivedDatagram", Q_ARG(const QByteArray&, packet));
|
||||
}
|
||||
Application::getInstance()->getBandwidthMeter()->inputStream(BandwidthMeter::METAVOXELS).updateValue(packet.size());
|
||||
Application::getInstance()->getBandwidthRecorder()->metavoxelsChannel->input.updateValue(packet.size());
|
||||
Application::getInstance()->getBandwidthRecorder()->totalChannel->input.updateValue(packet.size());
|
||||
}
|
||||
return packet.size();
|
||||
}
|
||||
|
@ -1015,7 +1016,8 @@ void MetavoxelSystemClient::sendDatagram(const QByteArray& data) {
|
|||
} else {
|
||||
DependencyManager::get<NodeList>()->writeDatagram(data, _node);
|
||||
}
|
||||
Application::getInstance()->getBandwidthMeter()->outputStream(BandwidthMeter::METAVOXELS).updateValue(data.size());
|
||||
Application::getInstance()->getBandwidthRecorder()->metavoxelsChannel->output.updateValue(data.size());
|
||||
Application::getInstance()->getBandwidthRecorder()->totalChannel->output.updateValue(data.size());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1251,7 +1253,6 @@ SphereRenderer::SphereRenderer() {
|
|||
void SphereRenderer::render(const MetavoxelLOD& lod, bool contained, bool cursor) {
|
||||
Sphere* sphere = static_cast<Sphere*>(_spanner);
|
||||
const QColor& color = sphere->getColor();
|
||||
glColor4f(color.redF(), color.greenF(), color.blueF(), color.alphaF());
|
||||
|
||||
glPushMatrix();
|
||||
const glm::vec3& translation = sphere->getTranslation();
|
||||
|
@ -1260,7 +1261,8 @@ void SphereRenderer::render(const MetavoxelLOD& lod, bool contained, bool cursor
|
|||
glm::vec3 axis = glm::axis(rotation);
|
||||
glRotatef(glm::degrees(glm::angle(rotation)), axis.x, axis.y, axis.z);
|
||||
|
||||
DependencyManager::get<DeferredLightingEffect>()->renderSolidSphere(sphere->getScale(), 32, 32);
|
||||
DependencyManager::get<DeferredLightingEffect>()->renderSolidSphere(sphere->getScale(), 32, 32,
|
||||
glm::vec4(color.redF(), color.greenF(), color.blueF(), color.alphaF()));
|
||||
|
||||
glPopMatrix();
|
||||
}
|
||||
|
@ -1271,7 +1273,6 @@ CuboidRenderer::CuboidRenderer() {
|
|||
void CuboidRenderer::render(const MetavoxelLOD& lod, bool contained, bool cursor) {
|
||||
Cuboid* cuboid = static_cast<Cuboid*>(_spanner);
|
||||
const QColor& color = cuboid->getColor();
|
||||
glColor4f(color.redF(), color.greenF(), color.blueF(), color.alphaF());
|
||||
|
||||
glPushMatrix();
|
||||
const glm::vec3& translation = cuboid->getTranslation();
|
||||
|
@ -1281,7 +1282,8 @@ void CuboidRenderer::render(const MetavoxelLOD& lod, bool contained, bool cursor
|
|||
glRotatef(glm::degrees(glm::angle(rotation)), axis.x, axis.y, axis.z);
|
||||
glScalef(1.0f, cuboid->getAspectY(), cuboid->getAspectZ());
|
||||
|
||||
DependencyManager::get<DeferredLightingEffect>()->renderSolidCube(cuboid->getScale() * 2.0f);
|
||||
DependencyManager::get<DeferredLightingEffect>()->renderSolidCube(cuboid->getScale() * 2.0f,
|
||||
glm::vec4(color.redF(), color.greenF(), color.blueF(), color.alphaF()));
|
||||
|
||||
glPopMatrix();
|
||||
}
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#include <QBuffer>
|
||||
#include <QCheckBox>
|
||||
#include <QComboBox>
|
||||
#include <QDebug>
|
||||
|
@ -21,6 +22,7 @@
|
|||
#include <QHBoxLayout>
|
||||
#include <QHttpMultiPart>
|
||||
#include <QImage>
|
||||
#include <QJsonDocument>
|
||||
#include <QLineEdit>
|
||||
#include <QMessageBox>
|
||||
#include <QProgressBar>
|
||||
|
@ -28,12 +30,17 @@
|
|||
#include <QStandardPaths>
|
||||
#include <QTemporaryFile>
|
||||
#include <QTextStream>
|
||||
#include <QThread>
|
||||
#include <QVBoxLayout>
|
||||
#include <QVariant>
|
||||
|
||||
#include <AccountManager.h>
|
||||
#include <GeometryCache.h>
|
||||
#include <GLMHelpers.h>
|
||||
#include <ResourceCache.h>
|
||||
#include <Settings.h>
|
||||
#include <TextureCache.h>
|
||||
|
||||
#include "Application.h"
|
||||
#include "ModelUploader.h"
|
||||
|
||||
|
||||
|
@ -53,8 +60,6 @@ static const QString BLENDSHAPE_FIELD = "bs";
|
|||
static const QString S3_URL = "http://public.highfidelity.io";
|
||||
static const QString MODEL_URL = "/api/v1/models";
|
||||
|
||||
static const QString SETTING_NAME = "LastModelUploadLocation";
|
||||
|
||||
static const unsigned long long MAX_SIZE = 50 * 1024 * BYTES_PER_MEGABYTES; // 50 GB (Virtually remove limit)
|
||||
static const int MAX_TEXTURE_SIZE = 1024;
|
||||
static const int TIMEOUT = 1000;
|
||||
|
@ -63,6 +68,11 @@ static const int MAX_CHECK = 30;
|
|||
static const int QCOMPRESS_HEADER_POSITION = 0;
|
||||
static const int QCOMPRESS_HEADER_SIZE = 4;
|
||||
|
||||
namespace SettingHandles {
|
||||
const SettingHandle<QString> lastModelUploadLocation("LastModelUploadLocation",
|
||||
QStandardPaths::writableLocation(QStandardPaths::DownloadLocation));
|
||||
}
|
||||
|
||||
void ModelUploader::uploadModel(ModelType modelType) {
|
||||
ModelUploader* uploader = new ModelUploader(modelType);
|
||||
QThread* thread = new QThread();
|
||||
|
@ -107,8 +117,7 @@ ModelUploader::~ModelUploader() {
|
|||
|
||||
bool ModelUploader::zip() {
|
||||
// File Dialog
|
||||
QSettings* settings = Application::getInstance()->lockSettings();
|
||||
QString lastLocation = settings->value(SETTING_NAME).toString();
|
||||
QString lastLocation = SettingHandles::lastModelUploadLocation.get();
|
||||
|
||||
if (lastLocation.isEmpty()) {
|
||||
lastLocation = QStandardPaths::writableLocation(QStandardPaths::DownloadLocation);
|
||||
|
@ -123,11 +132,9 @@ bool ModelUploader::zip() {
|
|||
lastLocation, "Model files (*.fst *.fbx)");
|
||||
if (filename == "") {
|
||||
// If the user canceled we return.
|
||||
Application::getInstance()->unlockSettings();
|
||||
return false;
|
||||
}
|
||||
settings->setValue(SETTING_NAME, filename);
|
||||
Application::getInstance()->unlockSettings();
|
||||
SettingHandles::lastModelUploadLocation.set(filename);
|
||||
|
||||
// First we check the FST file (if any)
|
||||
QFile* fst;
|
||||
|
@ -487,6 +494,7 @@ void ModelUploader::uploadFailed(QNetworkReply& errorReply) {
|
|||
void ModelUploader::checkS3() {
|
||||
qDebug() << "Checking S3 for " << _url;
|
||||
QNetworkRequest request(_url);
|
||||
request.setHeader(QNetworkRequest::UserAgentHeader, HIGH_FIDELITY_USER_AGENT);
|
||||
QNetworkReply* reply = NetworkAccessManager::getInstance().head(request);
|
||||
connect(reply, SIGNAL(finished()), SLOT(processCheck()));
|
||||
}
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
|
||||
#include <NetworkAccessManager.h>
|
||||
|
||||
#include "Application.h"
|
||||
#include "Menu.h"
|
||||
|
||||
#include "ScriptsModel.h"
|
||||
|
@ -33,8 +34,8 @@ static const QString KEY_NAME = "Key";
|
|||
|
||||
TreeNodeBase::TreeNodeBase(TreeNodeFolder* parent, const QString& name, TreeNodeType type) :
|
||||
_parent(parent),
|
||||
_name(name),
|
||||
_type(type) {
|
||||
_type(type),
|
||||
_name(name) {
|
||||
};
|
||||
|
||||
TreeNodeScript::TreeNodeScript(const QString& localPath, const QString& fullPath, ScriptOrigin origin) :
|
||||
|
@ -58,10 +59,10 @@ ScriptsModel::ScriptsModel(QObject* parent) :
|
|||
_localDirectory.setFilter(QDir::Files | QDir::Readable);
|
||||
_localDirectory.setNameFilters(QStringList("*.js"));
|
||||
|
||||
updateScriptsLocation(Menu::getInstance()->getScriptsLocation());
|
||||
updateScriptsLocation(qApp->getScriptsLocation());
|
||||
|
||||
connect(&_fsWatcher, &QFileSystemWatcher::directoryChanged, this, &ScriptsModel::reloadLocalFiles);
|
||||
connect(Menu::getInstance(), &Menu::scriptLocationChanged, this, &ScriptsModel::updateScriptsLocation);
|
||||
connect(qApp, &Application::scriptLocationChanged, this, &ScriptsModel::updateScriptsLocation);
|
||||
|
||||
reloadLocalFiles();
|
||||
reloadRemoteFiles();
|
||||
|
@ -165,6 +166,7 @@ void ScriptsModel::requestRemoteFiles(QString marker) {
|
|||
|
||||
QNetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance();
|
||||
QNetworkRequest request(url);
|
||||
request.setHeader(QNetworkRequest::UserAgentHeader, HIGH_FIDELITY_USER_AGENT);
|
||||
QNetworkReply* reply = networkAccessManager.get(request);
|
||||
connect(reply, SIGNAL(finished()), SLOT(downloadFinished()));
|
||||
}
|
||||
|
|
|
@ -20,12 +20,13 @@
|
|||
#include <QWinEventNotifier>
|
||||
#endif
|
||||
|
||||
class SpeechRecognizer : public QObject {
|
||||
Q_OBJECT
|
||||
public:
|
||||
SpeechRecognizer();
|
||||
~SpeechRecognizer();
|
||||
#include <DependencyManager.h>
|
||||
|
||||
class SpeechRecognizer : public QObject, public Dependency {
|
||||
Q_OBJECT
|
||||
SINGLETON_DEPENDENCY
|
||||
|
||||
public:
|
||||
void handleCommandRecognized(const char* command);
|
||||
bool getEnabled() const { return _enabled; }
|
||||
|
||||
|
@ -42,6 +43,9 @@ protected:
|
|||
void reloadCommands();
|
||||
|
||||
private:
|
||||
SpeechRecognizer();
|
||||
virtual ~SpeechRecognizer();
|
||||
|
||||
bool _enabled;
|
||||
QSet<QString> _commands;
|
||||
#if defined(Q_OS_MAC)
|
||||
|
|
|
@ -36,22 +36,18 @@ void renderWorldBox() {
|
|||
auto geometryCache = DependencyManager::get<GeometryCache>();
|
||||
|
||||
// Show edge of world
|
||||
float red[] = {1, 0, 0};
|
||||
float green[] = {0, 1, 0};
|
||||
float blue[] = {0, 0, 1};
|
||||
float gray[] = {0.5, 0.5, 0.5};
|
||||
glm::vec3 red(1.0f, 0.0f, 0.0f);
|
||||
glm::vec3 green(0.0f, 1.0f, 0.0f);
|
||||
glm::vec3 blue(0.0f, 0.0f, 1.0f);
|
||||
glm::vec3 grey(0.5f, 0.5f, 0.5f);
|
||||
|
||||
glDisable(GL_LIGHTING);
|
||||
glLineWidth(1.0);
|
||||
glColor3fv(red);
|
||||
geometryCache->renderLine(glm::vec3(0, 0, 0), glm::vec3(TREE_SCALE, 0, 0));
|
||||
glColor3fv(green);
|
||||
geometryCache->renderLine(glm::vec3(0, 0, 0), glm::vec3(0, TREE_SCALE, 0));
|
||||
glColor3fv(blue);
|
||||
geometryCache->renderLine(glm::vec3(0, 0, 0), glm::vec3(0, 0, TREE_SCALE));
|
||||
glColor3fv(gray);
|
||||
geometryCache->renderLine(glm::vec3(0, 0, TREE_SCALE), glm::vec3(TREE_SCALE, 0, TREE_SCALE));
|
||||
geometryCache->renderLine(glm::vec3(TREE_SCALE, 0, TREE_SCALE), glm::vec3(TREE_SCALE, 0, 0));
|
||||
geometryCache->renderLine(glm::vec3(0, 0, 0), glm::vec3(TREE_SCALE, 0, 0), red);
|
||||
geometryCache->renderLine(glm::vec3(0, 0, 0), glm::vec3(0, TREE_SCALE, 0), green);
|
||||
geometryCache->renderLine(glm::vec3(0, 0, 0), glm::vec3(0, 0, TREE_SCALE), blue);
|
||||
geometryCache->renderLine(glm::vec3(0, 0, TREE_SCALE), glm::vec3(TREE_SCALE, 0, TREE_SCALE), grey);
|
||||
geometryCache->renderLine(glm::vec3(TREE_SCALE, 0, TREE_SCALE), glm::vec3(TREE_SCALE, 0, 0), grey);
|
||||
|
||||
|
||||
// Draw meter markers along the 3 axis to help with measuring things
|
||||
|
@ -60,23 +56,19 @@ void renderWorldBox() {
|
|||
glEnable(GL_LIGHTING);
|
||||
glPushMatrix();
|
||||
glTranslatef(MARKER_DISTANCE, 0, 0);
|
||||
glColor3fv(red);
|
||||
geometryCache->renderSphere(MARKER_RADIUS, 10, 10);
|
||||
geometryCache->renderSphere(MARKER_RADIUS, 10, 10, red);
|
||||
glPopMatrix();
|
||||
glPushMatrix();
|
||||
glTranslatef(0, MARKER_DISTANCE, 0);
|
||||
glColor3fv(green);
|
||||
geometryCache->renderSphere(MARKER_RADIUS, 10, 10);
|
||||
geometryCache->renderSphere(MARKER_RADIUS, 10, 10, green);
|
||||
glPopMatrix();
|
||||
glPushMatrix();
|
||||
glTranslatef(0, 0, MARKER_DISTANCE);
|
||||
glColor3fv(blue);
|
||||
geometryCache->renderSphere(MARKER_RADIUS, 10, 10);
|
||||
geometryCache->renderSphere(MARKER_RADIUS, 10, 10, blue);
|
||||
glPopMatrix();
|
||||
glPushMatrix();
|
||||
glColor3fv(gray);
|
||||
glTranslatef(MARKER_DISTANCE, 0, MARKER_DISTANCE);
|
||||
geometryCache->renderSphere(MARKER_RADIUS, 10, 10);
|
||||
geometryCache->renderSphere(MARKER_RADIUS, 10, 10, grey);
|
||||
glPopMatrix();
|
||||
|
||||
}
|
||||
|
@ -114,25 +106,23 @@ void drawText(int x, int y, float scale, float radians, int mono,
|
|||
//
|
||||
glPushMatrix();
|
||||
glTranslatef(static_cast<float>(x), static_cast<float>(y), 0.0f);
|
||||
glColor3fv(color);
|
||||
|
||||
|
||||
glRotated(double(radians * DEGREES_PER_RADIAN), 0.0, 0.0, 1.0);
|
||||
glScalef(scale / 0.1f, scale / 0.1f, 1.0f);
|
||||
textRenderer(mono)->draw(0, 0, string);
|
||||
|
||||
glm::vec4 colorV4 = {color[0], color[1], color[3], 1.0f };
|
||||
textRenderer(mono)->draw(0, 0, string, colorV4);
|
||||
glPopMatrix();
|
||||
}
|
||||
|
||||
void renderCollisionOverlay(int width, int height, float magnitude, float red, float blue, float green) {
|
||||
const float MIN_VISIBLE_COLLISION = 0.01f;
|
||||
if (magnitude > MIN_VISIBLE_COLLISION) {
|
||||
glColor4f(red, blue, green, magnitude);
|
||||
DependencyManager::get<GeometryCache>()->renderQuad(0, 0, width, height);
|
||||
DependencyManager::get<GeometryCache>()->renderQuad(0, 0, width, height, glm::vec4(red, blue, green, magnitude));
|
||||
}
|
||||
}
|
||||
|
||||
void renderBevelCornersRect(int x, int y, int width, int height, int bevelDistance) {
|
||||
DependencyManager::get<GeometryCache>()->renderBevelCornersRect(x, y, width, height, bevelDistance);
|
||||
}
|
||||
|
||||
// Do some basic timing tests and report the results
|
||||
void runTimingTests() {
|
||||
// How long does it take to make a call to get the time?
|
||||
|
@ -238,14 +228,6 @@ void runTimingTests() {
|
|||
qDebug("vec3 assign and dot() usecs: %f, last result:%f", elapsedUsecs / (float) numTests, result);
|
||||
}
|
||||
|
||||
float loadSetting(QSettings* settings, const char* name, float defaultValue) {
|
||||
float value = settings->value(name, defaultValue).toFloat();
|
||||
if (glm::isnan(value)) {
|
||||
value = defaultValue;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
bool rayIntersectsSphere(const glm::vec3& rayStarting, const glm::vec3& rayNormalizedDirection,
|
||||
const glm::vec3& sphereCenter, float sphereRadius, float& distance) {
|
||||
glm::vec3 relativeOrigin = rayStarting - sphereCenter;
|
||||
|
|
|
@ -27,12 +27,8 @@ void drawText(int x, int y, float scale, float radians, int mono,
|
|||
|
||||
void renderCollisionOverlay(int width, int height, float magnitude, float red = 0, float blue = 0, float green = 0);
|
||||
|
||||
void renderBevelCornersRect(int x, int y, int width, int height, int bevelDistance);
|
||||
|
||||
void runTimingTests();
|
||||
|
||||
float loadSetting(QSettings* settings, const char* name, float defaultValue);
|
||||
|
||||
bool rayIntersectsSphere(const glm::vec3& rayStarting, const glm::vec3& rayNormalizedDirection,
|
||||
const glm::vec3& sphereCenter, float sphereRadius, float& distance);
|
||||
|
||||
|
|
|
@ -50,14 +50,12 @@ void AudioIOStatsRenderer::render(const float* color, int width, int height) {
|
|||
int statsHeight = STATS_HEIGHT_PER_LINE * lines;
|
||||
|
||||
|
||||
static const float backgroundColor[4] = { 0.2f, 0.2f, 0.2f, 0.6f };
|
||||
static const glm::vec4 backgroundColor = { 0.2f, 0.2f, 0.2f, 0.6f };
|
||||
int x = std::max((width - (int)STATS_WIDTH) / 2, 0);
|
||||
int y = std::max((height - CENTERED_BACKGROUND_HEIGHT) / 2, 0);
|
||||
int w = STATS_WIDTH;
|
||||
int h = statsHeight;
|
||||
glColor4fv(backgroundColor);
|
||||
DependencyManager::get<GeometryCache>()->renderQuad(x, y, w, h);
|
||||
glColor4f(1, 1, 1, 1);
|
||||
DependencyManager::get<GeometryCache>()->renderQuad(x, y, w, h, backgroundColor);
|
||||
|
||||
int horizontalOffset = x + 5;
|
||||
int verticalOffset = y;
|
||||
|
|
|
@ -111,11 +111,11 @@ void AudioScope::render(int width, int height) {
|
|||
return;
|
||||
}
|
||||
|
||||
static const float backgroundColor[4] = { 0.4f, 0.4f, 0.4f, 0.6f };
|
||||
static const float gridColor[4] = { 0.7f, 0.7f, 0.7f, 1.0f };
|
||||
static const float inputColor[4] = { 0.3f, 1.0f, 0.3f, 1.0f };
|
||||
static const float outputLeftColor[4] = { 1.0f, 0.3f, 0.3f, 1.0f };
|
||||
static const float outputRightColor[4] = { 0.3f, 0.3f, 1.0f, 1.0f };
|
||||
static const glm::vec4 backgroundColor = { 0.4f, 0.4f, 0.4f, 0.6f };
|
||||
static const glm::vec4 gridColor = { 0.7f, 0.7f, 0.7f, 1.0f };
|
||||
static const glm::vec4 inputColor = { 0.3f, 1.0f, 0.3f, 1.0f };
|
||||
static const glm::vec4 outputLeftColor = { 1.0f, 0.3f, 0.3f, 1.0f };
|
||||
static const glm::vec4 outputRightColor = { 0.3f, 0.3f, 1.0f, 1.0f };
|
||||
static const int gridRows = 2;
|
||||
int gridCols = _framesPerScope;
|
||||
|
||||
|
@ -132,21 +132,15 @@ void AudioScope::render(int width, int height) {
|
|||
renderLineStrip(_outputRightD, outputRightColor, x, y, _samplesPerScope, _scopeOutputOffset, _scopeOutputRight);
|
||||
}
|
||||
|
||||
void AudioScope::renderBackground(const float* color, int x, int y, int width, int height) {
|
||||
glColor4fv(color);
|
||||
DependencyManager::get<GeometryCache>()->renderQuad(x, y, width, height);
|
||||
glColor4f(1, 1, 1, 1);
|
||||
void AudioScope::renderBackground(const glm::vec4& color, int x, int y, int width, int height) {
|
||||
DependencyManager::get<GeometryCache>()->renderQuad(x, y, width, height, color);
|
||||
}
|
||||
|
||||
void AudioScope::renderGrid(const float* color, int x, int y, int width, int height, int rows, int cols) {
|
||||
glColor4fv(color);
|
||||
DependencyManager::get<GeometryCache>()->renderGrid(x, y, width, height, rows, cols, _audioScopeGrid);
|
||||
glColor4f(1, 1, 1, 1);
|
||||
void AudioScope::renderGrid(const glm::vec4& color, int x, int y, int width, int height, int rows, int cols) {
|
||||
DependencyManager::get<GeometryCache>()->renderGrid(x, y, width, height, rows, cols, color, _audioScopeGrid);
|
||||
}
|
||||
|
||||
void AudioScope::renderLineStrip(int id, const float* color, int x, int y, int n, int offset, const QByteArray* byteArray) {
|
||||
|
||||
glColor4fv(color);
|
||||
void AudioScope::renderLineStrip(int id, const glm::vec4& color, int x, int y, int n, int offset, const QByteArray* byteArray) {
|
||||
|
||||
int16_t sample;
|
||||
int16_t* samples = ((int16_t*) byteArray->data()) + offset;
|
||||
|
@ -200,10 +194,8 @@ void AudioScope::renderLineStrip(int id, const float* color, int x, int y, int n
|
|||
}
|
||||
|
||||
|
||||
geometryCache->updateVertices(id, points);
|
||||
geometryCache->renderVertices(GL_LINE_STRIP, id);
|
||||
|
||||
glColor4f(1, 1, 1, 1);
|
||||
geometryCache->updateVertices(id, points, color);
|
||||
geometryCache->renderVertices(gpu::LINE_STRIP, id);
|
||||
}
|
||||
|
||||
int AudioScope::addBufferToScope(QByteArray* byteArray, int frameOffset, const int16_t* source, int sourceSamplesPerChannel,
|
||||
|
|
|
@ -12,6 +12,8 @@
|
|||
#ifndef hifi_AudioScope_h
|
||||
#define hifi_AudioScope_h
|
||||
|
||||
#include <glm/glm.hpp>
|
||||
|
||||
#include <DependencyManager.h>
|
||||
|
||||
#include <QByteArray>
|
||||
|
@ -46,9 +48,9 @@ private slots:
|
|||
|
||||
private:
|
||||
// Audio scope methods for rendering
|
||||
static void renderBackground(const float* color, int x, int y, int width, int height);
|
||||
void renderGrid(const float* color, int x, int y, int width, int height, int rows, int cols);
|
||||
void renderLineStrip(int id, const float* color, int x, int y, int n, int offset, const QByteArray* byteArray);
|
||||
static void renderBackground(const glm::vec4& color, int x, int y, int width, int height);
|
||||
void renderGrid(const glm::vec4& color, int x, int y, int width, int height, int rows, int cols);
|
||||
void renderLineStrip(int id, const glm::vec4& color, int x, int y, int n, int offset, const QByteArray* byteArray);
|
||||
|
||||
// Audio scope methods for data acquisition
|
||||
int addBufferToScope(QByteArray* byteArray, int frameOffset, const int16_t* source, int sourceSamples,
|
||||
|
|
|
@ -62,17 +62,19 @@ void AudioToolBox::render(int x, int y, bool boxed) {
|
|||
|
||||
glBindTexture(GL_TEXTURE_2D, _boxTextureId);
|
||||
|
||||
glm::vec4 quadColor;
|
||||
|
||||
if (isClipping) {
|
||||
glColor3f(1.0f, 0.0f, 0.0f);
|
||||
quadColor = glm::vec4(1.0f, 0.0f, 0.0f, 1.0f);
|
||||
} else {
|
||||
glColor3f(0.41f, 0.41f, 0.41f);
|
||||
quadColor = glm::vec4(0.41f, 0.41f, 0.41f, 1.0f);
|
||||
}
|
||||
glm::vec2 topLeft(boxBounds.left(), boxBounds.top());
|
||||
glm::vec2 bottomRight(boxBounds.right(), boxBounds.bottom());
|
||||
glm::vec2 texCoordTopLeft(1,1);
|
||||
glm::vec2 texCoordBottomRight(0,0);
|
||||
|
||||
DependencyManager::get<GeometryCache>()->renderQuad(topLeft, bottomRight, texCoordTopLeft, texCoordBottomRight);
|
||||
DependencyManager::get<GeometryCache>()->renderQuad(topLeft, bottomRight, texCoordTopLeft, texCoordBottomRight, quadColor);
|
||||
}
|
||||
|
||||
float iconColor = 1.0f;
|
||||
|
@ -98,14 +100,14 @@ void AudioToolBox::render(int x, int y, bool boxed) {
|
|||
iconColor = PULSE_MIN + (PULSE_MAX - PULSE_MIN) * pulseFactor;
|
||||
}
|
||||
|
||||
glColor3f(iconColor, iconColor, iconColor);
|
||||
glm::vec4 quadColor(iconColor, iconColor, iconColor, 1.0f);
|
||||
|
||||
glm::vec2 topLeft(_iconBounds.left(), _iconBounds.top());
|
||||
glm::vec2 bottomRight(_iconBounds.right(), _iconBounds.bottom());
|
||||
glm::vec2 texCoordTopLeft(1,1);
|
||||
glm::vec2 texCoordBottomRight(0,0);
|
||||
|
||||
DependencyManager::get<GeometryCache>()->renderQuad(topLeft, bottomRight, texCoordTopLeft, texCoordBottomRight);
|
||||
DependencyManager::get<GeometryCache>()->renderQuad(topLeft, bottomRight, texCoordTopLeft, texCoordBottomRight, quadColor);
|
||||
|
||||
glDisable(GL_TEXTURE_2D);
|
||||
}
|
|
@ -25,6 +25,7 @@
|
|||
#include <DeferredLightingEffect.h>
|
||||
#include <GeometryUtil.h>
|
||||
#include <GlowEffect.h>
|
||||
#include <LODManager.h>
|
||||
#include <NodeList.h>
|
||||
#include <PacketHeaders.h>
|
||||
#include <PathUtils.h>
|
||||
|
@ -114,8 +115,8 @@ glm::quat Avatar::getWorldAlignedOrientation () const {
|
|||
}
|
||||
|
||||
float Avatar::getLODDistance() const {
|
||||
return Menu::getInstance()->getAvatarLODDistanceMultiplier() *
|
||||
glm::distance(Application::getInstance()->getCamera()->getPosition(), _position) / _scale;
|
||||
return DependencyManager::get<LODManager>()->getAvatarLODDistanceMultiplier() *
|
||||
glm::distance(qApp->getCamera()->getPosition(), _position) / _scale;
|
||||
}
|
||||
|
||||
void Avatar::simulate(float deltaTime) {
|
||||
|
@ -301,8 +302,7 @@ void Avatar::render(const glm::vec3& cameraPosition, RenderMode renderMode, bool
|
|||
glm::vec3 axis = glm::axis(rotation);
|
||||
glRotatef(angle, axis.x, axis.y, axis.z);
|
||||
|
||||
glColor3f(laserColor.x, laserColor.y, laserColor.z);
|
||||
geometryCache->renderLine(glm::vec3(0.0f, 0.0f, 0.0f), glm::vec3(0.0f, laserLength, 0.0f));
|
||||
geometryCache->renderLine(glm::vec3(0.0f, 0.0f, 0.0f), glm::vec3(0.0f, laserLength, 0.0f), laserColor);
|
||||
|
||||
} glPopMatrix();
|
||||
}
|
||||
|
@ -327,8 +327,7 @@ void Avatar::render(const glm::vec3& cameraPosition, RenderMode renderMode, bool
|
|||
float angle = glm::degrees(glm::angle(rotation));
|
||||
glm::vec3 axis = glm::axis(rotation);
|
||||
glRotatef(angle, axis.x, axis.y, axis.z);
|
||||
glColor3f(laserColor.x, laserColor.y, laserColor.z);
|
||||
geometryCache->renderLine(glm::vec3(0.0f, 0.0f, 0.0f), glm::vec3(0.0f, laserLength, 0.0f));
|
||||
geometryCache->renderLine(glm::vec3(0.0f, 0.0f, 0.0f), glm::vec3(0.0f, laserLength, 0.0f), laserColor);
|
||||
|
||||
} glPopMatrix();
|
||||
}
|
||||
|
@ -404,15 +403,14 @@ void Avatar::render(const glm::vec3& cameraPosition, RenderMode renderMode, bool
|
|||
if (_isLookAtTarget && Menu::getInstance()->isOptionChecked(MenuOption::RenderFocusIndicator)) {
|
||||
const float LOOK_AT_INDICATOR_RADIUS = 0.03f;
|
||||
const float LOOK_AT_INDICATOR_OFFSET = 0.22f;
|
||||
const float LOOK_AT_INDICATOR_COLOR[] = { 0.8f, 0.0f, 0.0f, 0.75f };
|
||||
const glm::vec4 LOOK_AT_INDICATOR_COLOR = { 0.8f, 0.0f, 0.0f, 0.75f };
|
||||
glPushMatrix();
|
||||
glColor4fv(LOOK_AT_INDICATOR_COLOR);
|
||||
if (_displayName.isEmpty() || _displayNameAlpha == 0.0f) {
|
||||
glTranslatef(_position.x, getDisplayNamePosition().y, _position.z);
|
||||
} else {
|
||||
glTranslatef(_position.x, getDisplayNamePosition().y + LOOK_AT_INDICATOR_OFFSET, _position.z);
|
||||
}
|
||||
DependencyManager::get<GeometryCache>()->renderSphere(LOOK_AT_INDICATOR_RADIUS, 15, 15);
|
||||
DependencyManager::get<GeometryCache>()->renderSphere(LOOK_AT_INDICATOR_RADIUS, 15, 15, LOOK_AT_INDICATOR_COLOR);
|
||||
glPopMatrix();
|
||||
}
|
||||
}
|
||||
|
@ -436,11 +434,11 @@ void Avatar::render(const glm::vec3& cameraPosition, RenderMode renderMode, bool
|
|||
|
||||
if (renderMode == NORMAL_RENDER_MODE && (sphereRadius > MIN_SPHERE_SIZE) &&
|
||||
(angle < MAX_SPHERE_ANGLE) && (angle > MIN_SPHERE_ANGLE)) {
|
||||
glColor4f(SPHERE_COLOR[0], SPHERE_COLOR[1], SPHERE_COLOR[2], 1.0f - angle / MAX_SPHERE_ANGLE);
|
||||
glPushMatrix();
|
||||
glTranslatef(_position.x, _position.y, _position.z);
|
||||
glScalef(height, height, height);
|
||||
DependencyManager::get<GeometryCache>()->renderSphere(sphereRadius, 15, 15);
|
||||
DependencyManager::get<GeometryCache>()->renderSphere(sphereRadius, 15, 15,
|
||||
glm::vec4(SPHERE_COLOR[0], SPHERE_COLOR[1], SPHERE_COLOR[2], 1.0f - angle / MAX_SPHERE_ANGLE));
|
||||
|
||||
glPopMatrix();
|
||||
}
|
||||
|
@ -571,15 +569,12 @@ void Avatar::renderBillboard() {
|
|||
float size = getBillboardSize();
|
||||
glScalef(size, size, size);
|
||||
|
||||
glColor3f(1.0f, 1.0f, 1.0f);
|
||||
|
||||
glm::vec2 topLeft(-1.0f, -1.0f);
|
||||
glm::vec2 bottomRight(1.0f, 1.0f);
|
||||
glm::vec2 texCoordTopLeft(0.0f, 0.0f);
|
||||
glm::vec2 texCoordBottomRight(1.0f, 1.0f);
|
||||
|
||||
DependencyManager::get<GeometryCache>()->renderQuad(topLeft, bottomRight, texCoordTopLeft, texCoordBottomRight);
|
||||
|
||||
DependencyManager::get<GeometryCache>()->renderQuad(topLeft, bottomRight, texCoordTopLeft, texCoordBottomRight, glm::vec4(1.0f, 1.0f, 1.0f, 1.0f));
|
||||
|
||||
glPopMatrix();
|
||||
|
||||
|
@ -705,15 +700,15 @@ void Avatar::renderDisplayName() {
|
|||
glEnable(GL_POLYGON_OFFSET_FILL);
|
||||
glPolygonOffset(1.0f, 1.0f);
|
||||
|
||||
glColor4f(0.2f, 0.2f, 0.2f, _displayNameAlpha * DISPLAYNAME_BACKGROUND_ALPHA / DISPLAYNAME_ALPHA);
|
||||
renderBevelCornersRect(left, bottom, right - left, top - bottom, 3);
|
||||
DependencyManager::get<GeometryCache>()->renderBevelCornersRect(left, bottom, right - left, top - bottom, 3,
|
||||
glm::vec4(0.2f, 0.2f, 0.2f, _displayNameAlpha * DISPLAYNAME_BACKGROUND_ALPHA / DISPLAYNAME_ALPHA));
|
||||
|
||||
glColor4f(0.93f, 0.93f, 0.93f, _displayNameAlpha);
|
||||
glm::vec4 color(0.93f, 0.93f, 0.93f, _displayNameAlpha);
|
||||
QByteArray ba = _displayName.toLocal8Bit();
|
||||
const char* text = ba.data();
|
||||
|
||||
glDisable(GL_POLYGON_OFFSET_FILL);
|
||||
textRenderer(DISPLAYNAME)->draw(text_x, text_y, text);
|
||||
textRenderer(DISPLAYNAME)->draw(text_x, text_y, text, color);
|
||||
|
||||
glPopMatrix();
|
||||
|
||||
|
@ -948,7 +943,8 @@ int Avatar::parseDataAtOffset(const QByteArray& packet, int offset) {
|
|||
int Avatar::_jointConesID = GeometryCache::UNKNOWN_ID;
|
||||
|
||||
// render a makeshift cone section that serves as a body part connecting joint spheres
|
||||
void Avatar::renderJointConnectingCone(glm::vec3 position1, glm::vec3 position2, float radius1, float radius2) {
|
||||
void Avatar::renderJointConnectingCone(glm::vec3 position1, glm::vec3 position2,
|
||||
float radius1, float radius2, const glm::vec4& color) {
|
||||
|
||||
auto geometryCache = DependencyManager::get<GeometryCache>();
|
||||
|
||||
|
@ -993,8 +989,8 @@ void Avatar::renderJointConnectingCone(glm::vec3 position1, glm::vec3 position2,
|
|||
|
||||
// TODO: this is really inefficient constantly recreating these vertices buffers. It would be
|
||||
// better if the avatars cached these buffers for each of the joints they are rendering
|
||||
geometryCache->updateVertices(_jointConesID, points);
|
||||
geometryCache->renderVertices(GL_TRIANGLES, _jointConesID);
|
||||
geometryCache->updateVertices(_jointConesID, points, color);
|
||||
geometryCache->renderVertices(gpu::TRIANGLES, _jointConesID);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -133,7 +133,8 @@ public:
|
|||
|
||||
virtual int parseDataAtOffset(const QByteArray& packet, int offset);
|
||||
|
||||
static void renderJointConnectingCone(glm::vec3 position1, glm::vec3 position2, float radius1, float radius2);
|
||||
static void renderJointConnectingCone(glm::vec3 position1, glm::vec3 position2,
|
||||
float radius1, float radius2, const glm::vec4& color);
|
||||
|
||||
virtual void applyCollision(const glm::vec3& contactPoint, const glm::vec3& penetration) { }
|
||||
|
||||
|
|
|
@ -115,8 +115,7 @@ void Hand::render(bool isMine, Model::RenderMode renderMode) {
|
|||
glm::vec3 position = palm.getPosition();
|
||||
glPushMatrix();
|
||||
glTranslatef(position.x, position.y, position.z);
|
||||
glColor3f(0.0f, 1.0f, 0.0f);
|
||||
DependencyManager::get<GeometryCache>()->renderSphere(PALM_COLLISION_RADIUS * _owningAvatar->getScale(), 10, 10);
|
||||
DependencyManager::get<GeometryCache>()->renderSphere(PALM_COLLISION_RADIUS * _owningAvatar->getScale(), 10, 10, glm::vec3(0.0f, 1.0f, 0.0f));
|
||||
glPopMatrix();
|
||||
}
|
||||
}
|
||||
|
@ -132,7 +131,6 @@ void Hand::render(bool isMine, Model::RenderMode renderMode) {
|
|||
void Hand::renderHandTargets(bool isMine) {
|
||||
glPushMatrix();
|
||||
|
||||
MyAvatar* myAvatar = Application::getInstance()->getAvatar();
|
||||
const float avatarScale = Application::getInstance()->getAvatar()->getScale();
|
||||
|
||||
const float alpha = 1.0f;
|
||||
|
@ -152,8 +150,7 @@ void Hand::renderHandTargets(bool isMine) {
|
|||
glTranslatef(targetPosition.x, targetPosition.y, targetPosition.z);
|
||||
|
||||
const float collisionRadius = 0.05f;
|
||||
glColor4f(0.5f,0.5f,0.5f, alpha);
|
||||
DependencyManager::get<GeometryCache>()->renderSphere(collisionRadius, 10, 10, false);
|
||||
DependencyManager::get<GeometryCache>()->renderSphere(collisionRadius, 10, 10, glm::vec4(0.5f,0.5f,0.5f, alpha), false);
|
||||
glPopMatrix();
|
||||
}
|
||||
}
|
||||
|
@ -167,17 +164,17 @@ void Hand::renderHandTargets(bool isMine) {
|
|||
for (size_t i = 0; i < getNumPalms(); ++i) {
|
||||
PalmData& palm = getPalms()[i];
|
||||
if (palm.isActive()) {
|
||||
glColor4f(handColor.r, handColor.g, handColor.b, alpha);
|
||||
glm::vec3 tip = palm.getTipPosition();
|
||||
glm::vec3 root = palm.getPosition();
|
||||
|
||||
Avatar::renderJointConnectingCone(root, tip, PALM_FINGER_ROD_RADIUS, PALM_FINGER_ROD_RADIUS);
|
||||
Avatar::renderJointConnectingCone(root, tip, PALM_FINGER_ROD_RADIUS, PALM_FINGER_ROD_RADIUS, glm::vec4(handColor.r, handColor.g, handColor.b, alpha));
|
||||
|
||||
// Render sphere at palm/finger root
|
||||
glm::vec3 offsetFromPalm = root + palm.getNormal() * PALM_DISK_THICKNESS;
|
||||
Avatar::renderJointConnectingCone(root, offsetFromPalm, PALM_DISK_RADIUS, 0.0f);
|
||||
Avatar::renderJointConnectingCone(root, offsetFromPalm, PALM_DISK_RADIUS, 0.0f, glm::vec4(handColor.r, handColor.g, handColor.b, alpha));
|
||||
glPushMatrix();
|
||||
glTranslatef(root.x, root.y, root.z);
|
||||
DependencyManager::get<GeometryCache>()->renderSphere(PALM_BALL_RADIUS, 20.0f, 20.0f);
|
||||
DependencyManager::get<GeometryCache>()->renderSphere(PALM_BALL_RADIUS, 20.0f, 20.0f, glm::vec4(handColor.r, handColor.g, handColor.b, alpha));
|
||||
glPopMatrix();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -344,11 +344,10 @@ void Head::renderLookatVectors(glm::vec3 leftEyePosition, glm::vec3 rightEyePosi
|
|||
|
||||
glLineWidth(2.0);
|
||||
|
||||
// TODO: implement support for lines with gradient colors
|
||||
// glColor4f(0.2f, 0.2f, 0.2f, 1.0f); --> to --> glColor4f(1.0f, 1.0f, 1.0f, 0.0f);
|
||||
glColor4f(0.5f, 0.5f, 0.5f, 0.5f);
|
||||
geometryCache->renderLine(leftEyePosition, lookatPosition, _leftEyeLookAtID);
|
||||
geometryCache->renderLine(rightEyePosition, lookatPosition, _rightEyeLookAtID);
|
||||
glm::vec4 startColor(0.2f, 0.2f, 0.2f, 1.0f);
|
||||
glm::vec4 endColor(1.0f, 1.0f, 1.0f, 0.0f);
|
||||
geometryCache->renderLine(leftEyePosition, lookatPosition, startColor, endColor, _leftEyeLookAtID);
|
||||
geometryCache->renderLine(rightEyePosition, lookatPosition, startColor, endColor, _rightEyeLookAtID);
|
||||
|
||||
DependencyManager::get<GlowEffect>()->end();
|
||||
}
|
||||
|
|
|
@ -28,6 +28,7 @@
|
|||
#include <NodeList.h>
|
||||
#include <PacketHeaders.h>
|
||||
#include <PerfStat.h>
|
||||
#include <Settings.h>
|
||||
#include <ShapeCollider.h>
|
||||
#include <SharedUtil.h>
|
||||
#include <TextRenderer.h>
|
||||
|
@ -338,7 +339,8 @@ void MyAvatar::updateFromTrackers(float deltaTime) {
|
|||
head->setDeltaPitch(estimatedRotation.x);
|
||||
head->setDeltaYaw(estimatedRotation.y);
|
||||
} else {
|
||||
float magnifyFieldOfView = Menu::getInstance()->getFieldOfView() / Menu::getInstance()->getRealWorldFieldOfView();
|
||||
float magnifyFieldOfView = qApp->getViewFrustum()->getFieldOfView() /
|
||||
qApp->getViewFrustum()->getRealWorldFieldOfView();
|
||||
head->setDeltaPitch(estimatedRotation.x * magnifyFieldOfView);
|
||||
head->setDeltaYaw(estimatedRotation.y * magnifyFieldOfView);
|
||||
}
|
||||
|
@ -381,17 +383,15 @@ void MyAvatar::renderDebugBodyPoints() {
|
|||
// Torso Sphere
|
||||
position = torsoPosition;
|
||||
glPushMatrix();
|
||||
glColor4f(0, 1, 0, .5f);
|
||||
glTranslatef(position.x, position.y, position.z);
|
||||
DependencyManager::get<GeometryCache>()->renderSphere(0.2f, 10.0f, 10.0f);
|
||||
DependencyManager::get<GeometryCache>()->renderSphere(0.2f, 10.0f, 10.0f, glm::vec4(0, 1, 0, .5f));
|
||||
glPopMatrix();
|
||||
|
||||
// Head Sphere
|
||||
position = headPosition;
|
||||
glPushMatrix();
|
||||
glColor4f(0, 1, 0, .5f);
|
||||
glTranslatef(position.x, position.y, position.z);
|
||||
DependencyManager::get<GeometryCache>()->renderSphere(0.15f, 10.0f, 10.0f);
|
||||
DependencyManager::get<GeometryCache>()->renderSphere(0.15f, 10.0f, 10.0f, glm::vec4(0, 1, 0, .5f));
|
||||
glPopMatrix();
|
||||
}
|
||||
|
||||
|
@ -677,60 +677,70 @@ AnimationDetails MyAvatar::getAnimationDetails(const QString& url) {
|
|||
return result;
|
||||
}
|
||||
|
||||
void MyAvatar::saveData(QSettings* settings) {
|
||||
settings->beginGroup("Avatar");
|
||||
void MyAvatar::saveData() {
|
||||
Settings settings;
|
||||
settings.beginGroup("Avatar");
|
||||
|
||||
settings->setValue("headPitch", getHead()->getBasePitch());
|
||||
settings.setValue("headPitch", getHead()->getBasePitch());
|
||||
|
||||
settings->setValue("pupilDilation", getHead()->getPupilDilation());
|
||||
settings.setValue("pupilDilation", getHead()->getPupilDilation());
|
||||
|
||||
settings->setValue("leanScale", _leanScale);
|
||||
settings->setValue("scale", _targetScale);
|
||||
settings.setValue("leanScale", _leanScale);
|
||||
settings.setValue("scale", _targetScale);
|
||||
|
||||
settings->setValue("faceModelURL", _faceModelURL);
|
||||
settings->setValue("skeletonModelURL", _skeletonModelURL);
|
||||
settings.setValue("faceModelURL", _faceModelURL);
|
||||
settings.setValue("skeletonModelURL", _skeletonModelURL);
|
||||
|
||||
settings->beginWriteArray("attachmentData");
|
||||
settings.beginWriteArray("attachmentData");
|
||||
for (int i = 0; i < _attachmentData.size(); i++) {
|
||||
settings->setArrayIndex(i);
|
||||
settings.setArrayIndex(i);
|
||||
const AttachmentData& attachment = _attachmentData.at(i);
|
||||
settings->setValue("modelURL", attachment.modelURL);
|
||||
settings->setValue("jointName", attachment.jointName);
|
||||
settings->setValue("translation_x", attachment.translation.x);
|
||||
settings->setValue("translation_y", attachment.translation.y);
|
||||
settings->setValue("translation_z", attachment.translation.z);
|
||||
settings.setValue("modelURL", attachment.modelURL);
|
||||
settings.setValue("jointName", attachment.jointName);
|
||||
settings.setValue("translation_x", attachment.translation.x);
|
||||
settings.setValue("translation_y", attachment.translation.y);
|
||||
settings.setValue("translation_z", attachment.translation.z);
|
||||
glm::vec3 eulers = safeEulerAngles(attachment.rotation);
|
||||
settings->setValue("rotation_x", eulers.x);
|
||||
settings->setValue("rotation_y", eulers.y);
|
||||
settings->setValue("rotation_z", eulers.z);
|
||||
settings->setValue("scale", attachment.scale);
|
||||
settings.setValue("rotation_x", eulers.x);
|
||||
settings.setValue("rotation_y", eulers.y);
|
||||
settings.setValue("rotation_z", eulers.z);
|
||||
settings.setValue("scale", attachment.scale);
|
||||
}
|
||||
settings->endArray();
|
||||
settings.endArray();
|
||||
|
||||
settings->beginWriteArray("animationHandles");
|
||||
settings.beginWriteArray("animationHandles");
|
||||
for (int i = 0; i < _animationHandles.size(); i++) {
|
||||
settings->setArrayIndex(i);
|
||||
settings.setArrayIndex(i);
|
||||
const AnimationHandlePointer& pointer = _animationHandles.at(i);
|
||||
settings->setValue("role", pointer->getRole());
|
||||
settings->setValue("url", pointer->getURL());
|
||||
settings->setValue("fps", pointer->getFPS());
|
||||
settings->setValue("priority", pointer->getPriority());
|
||||
settings->setValue("loop", pointer->getLoop());
|
||||
settings->setValue("hold", pointer->getHold());
|
||||
settings->setValue("startAutomatically", pointer->getStartAutomatically());
|
||||
settings->setValue("firstFrame", pointer->getFirstFrame());
|
||||
settings->setValue("lastFrame", pointer->getLastFrame());
|
||||
settings->setValue("maskedJoints", pointer->getMaskedJoints());
|
||||
settings.setValue("role", pointer->getRole());
|
||||
settings.setValue("url", pointer->getURL());
|
||||
settings.setValue("fps", pointer->getFPS());
|
||||
settings.setValue("priority", pointer->getPriority());
|
||||
settings.setValue("loop", pointer->getLoop());
|
||||
settings.setValue("hold", pointer->getHold());
|
||||
settings.setValue("startAutomatically", pointer->getStartAutomatically());
|
||||
settings.setValue("firstFrame", pointer->getFirstFrame());
|
||||
settings.setValue("lastFrame", pointer->getLastFrame());
|
||||
settings.setValue("maskedJoints", pointer->getMaskedJoints());
|
||||
}
|
||||
settings->endArray();
|
||||
settings.endArray();
|
||||
|
||||
settings->setValue("displayName", _displayName);
|
||||
settings.setValue("displayName", _displayName);
|
||||
|
||||
settings->endGroup();
|
||||
settings.endGroup();
|
||||
}
|
||||
|
||||
void MyAvatar::loadData(QSettings* settings) {
|
||||
settings->beginGroup("Avatar");
|
||||
float loadSetting(QSettings& settings, const char* name, float defaultValue) {
|
||||
float value = settings.value(name, defaultValue).toFloat();
|
||||
if (glm::isnan(value)) {
|
||||
value = defaultValue;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
void MyAvatar::loadData() {
|
||||
Settings settings;
|
||||
settings.beginGroup("Avatar");
|
||||
|
||||
getHead()->setBasePitch(loadSetting(settings, "headPitch", 0.0f));
|
||||
|
||||
|
@ -741,16 +751,16 @@ void MyAvatar::loadData(QSettings* settings) {
|
|||
setScale(_scale);
|
||||
Application::getInstance()->getCamera()->setScale(_scale);
|
||||
|
||||
setFaceModelURL(settings->value("faceModelURL", DEFAULT_HEAD_MODEL_URL).toUrl());
|
||||
setSkeletonModelURL(settings->value("skeletonModelURL").toUrl());
|
||||
setFaceModelURL(settings.value("faceModelURL", DEFAULT_HEAD_MODEL_URL).toUrl());
|
||||
setSkeletonModelURL(settings.value("skeletonModelURL").toUrl());
|
||||
|
||||
QVector<AttachmentData> attachmentData;
|
||||
int attachmentCount = settings->beginReadArray("attachmentData");
|
||||
int attachmentCount = settings.beginReadArray("attachmentData");
|
||||
for (int i = 0; i < attachmentCount; i++) {
|
||||
settings->setArrayIndex(i);
|
||||
settings.setArrayIndex(i);
|
||||
AttachmentData attachment;
|
||||
attachment.modelURL = settings->value("modelURL").toUrl();
|
||||
attachment.jointName = settings->value("jointName").toString();
|
||||
attachment.modelURL = settings.value("modelURL").toUrl();
|
||||
attachment.jointName = settings.value("jointName").toString();
|
||||
attachment.translation.x = loadSetting(settings, "translation_x", 0.0f);
|
||||
attachment.translation.y = loadSetting(settings, "translation_y", 0.0f);
|
||||
attachment.translation.z = loadSetting(settings, "translation_z", 0.0f);
|
||||
|
@ -762,10 +772,10 @@ void MyAvatar::loadData(QSettings* settings) {
|
|||
attachment.scale = loadSetting(settings, "scale", 1.0f);
|
||||
attachmentData.append(attachment);
|
||||
}
|
||||
settings->endArray();
|
||||
settings.endArray();
|
||||
setAttachmentData(attachmentData);
|
||||
|
||||
int animationCount = settings->beginReadArray("animationHandles");
|
||||
int animationCount = settings.beginReadArray("animationHandles");
|
||||
while (_animationHandles.size() > animationCount) {
|
||||
_animationHandles.takeLast()->stop();
|
||||
}
|
||||
|
@ -773,65 +783,64 @@ void MyAvatar::loadData(QSettings* settings) {
|
|||
addAnimationHandle();
|
||||
}
|
||||
for (int i = 0; i < animationCount; i++) {
|
||||
settings->setArrayIndex(i);
|
||||
settings.setArrayIndex(i);
|
||||
const AnimationHandlePointer& handle = _animationHandles.at(i);
|
||||
handle->setRole(settings->value("role", "idle").toString());
|
||||
handle->setURL(settings->value("url").toUrl());
|
||||
handle->setRole(settings.value("role", "idle").toString());
|
||||
handle->setURL(settings.value("url").toUrl());
|
||||
handle->setFPS(loadSetting(settings, "fps", 30.0f));
|
||||
handle->setPriority(loadSetting(settings, "priority", 1.0f));
|
||||
handle->setLoop(settings->value("loop", true).toBool());
|
||||
handle->setHold(settings->value("hold", false).toBool());
|
||||
handle->setStartAutomatically(settings->value("startAutomatically", true).toBool());
|
||||
handle->setFirstFrame(settings->value("firstFrame", 0.0f).toFloat());
|
||||
handle->setLastFrame(settings->value("lastFrame", INT_MAX).toFloat());
|
||||
handle->setMaskedJoints(settings->value("maskedJoints").toStringList());
|
||||
handle->setLoop(settings.value("loop", true).toBool());
|
||||
handle->setHold(settings.value("hold", false).toBool());
|
||||
handle->setStartAutomatically(settings.value("startAutomatically", true).toBool());
|
||||
handle->setFirstFrame(settings.value("firstFrame", 0.0f).toFloat());
|
||||
handle->setLastFrame(settings.value("lastFrame", INT_MAX).toFloat());
|
||||
handle->setMaskedJoints(settings.value("maskedJoints").toStringList());
|
||||
}
|
||||
settings->endArray();
|
||||
settings.endArray();
|
||||
|
||||
setDisplayName(settings->value("displayName").toString());
|
||||
setDisplayName(settings.value("displayName").toString());
|
||||
|
||||
settings->endGroup();
|
||||
settings.endGroup();
|
||||
}
|
||||
|
||||
void MyAvatar::saveAttachmentData(const AttachmentData& attachment) const {
|
||||
QSettings* settings = Application::getInstance()->lockSettings();
|
||||
settings->beginGroup("savedAttachmentData");
|
||||
settings->beginGroup(_skeletonModel.getURL().toString());
|
||||
settings->beginGroup(attachment.modelURL.toString());
|
||||
settings->setValue("jointName", attachment.jointName);
|
||||
Settings settings;
|
||||
settings.beginGroup("savedAttachmentData");
|
||||
settings.beginGroup(_skeletonModel.getURL().toString());
|
||||
settings.beginGroup(attachment.modelURL.toString());
|
||||
settings.setValue("jointName", attachment.jointName);
|
||||
|
||||
settings->beginGroup(attachment.jointName);
|
||||
settings->setValue("translation_x", attachment.translation.x);
|
||||
settings->setValue("translation_y", attachment.translation.y);
|
||||
settings->setValue("translation_z", attachment.translation.z);
|
||||
settings.beginGroup(attachment.jointName);
|
||||
settings.setValue("translation_x", attachment.translation.x);
|
||||
settings.setValue("translation_y", attachment.translation.y);
|
||||
settings.setValue("translation_z", attachment.translation.z);
|
||||
glm::vec3 eulers = safeEulerAngles(attachment.rotation);
|
||||
settings->setValue("rotation_x", eulers.x);
|
||||
settings->setValue("rotation_y", eulers.y);
|
||||
settings->setValue("rotation_z", eulers.z);
|
||||
settings->setValue("scale", attachment.scale);
|
||||
settings.setValue("rotation_x", eulers.x);
|
||||
settings.setValue("rotation_y", eulers.y);
|
||||
settings.setValue("rotation_z", eulers.z);
|
||||
settings.setValue("scale", attachment.scale);
|
||||
|
||||
settings->endGroup();
|
||||
settings->endGroup();
|
||||
settings->endGroup();
|
||||
settings->endGroup();
|
||||
Application::getInstance()->unlockSettings();
|
||||
settings.endGroup();
|
||||
settings.endGroup();
|
||||
settings.endGroup();
|
||||
settings.endGroup();
|
||||
}
|
||||
|
||||
AttachmentData MyAvatar::loadAttachmentData(const QUrl& modelURL, const QString& jointName) const {
|
||||
QSettings* settings = Application::getInstance()->lockSettings();
|
||||
settings->beginGroup("savedAttachmentData");
|
||||
settings->beginGroup(_skeletonModel.getURL().toString());
|
||||
settings->beginGroup(modelURL.toString());
|
||||
Settings settings;
|
||||
settings.beginGroup("savedAttachmentData");
|
||||
settings.beginGroup(_skeletonModel.getURL().toString());
|
||||
settings.beginGroup(modelURL.toString());
|
||||
|
||||
AttachmentData attachment;
|
||||
attachment.modelURL = modelURL;
|
||||
if (jointName.isEmpty()) {
|
||||
attachment.jointName = settings->value("jointName").toString();
|
||||
attachment.jointName = settings.value("jointName").toString();
|
||||
} else {
|
||||
attachment.jointName = jointName;
|
||||
}
|
||||
settings->beginGroup(attachment.jointName);
|
||||
if (settings->contains("translation_x")) {
|
||||
settings.beginGroup(attachment.jointName);
|
||||
if (settings.contains("translation_x")) {
|
||||
attachment.translation.x = loadSetting(settings, "translation_x", 0.0f);
|
||||
attachment.translation.y = loadSetting(settings, "translation_y", 0.0f);
|
||||
attachment.translation.z = loadSetting(settings, "translation_z", 0.0f);
|
||||
|
@ -845,11 +854,10 @@ AttachmentData MyAvatar::loadAttachmentData(const QUrl& modelURL, const QString&
|
|||
attachment = AttachmentData();
|
||||
}
|
||||
|
||||
settings->endGroup();
|
||||
settings->endGroup();
|
||||
settings->endGroup();
|
||||
settings->endGroup();
|
||||
Application::getInstance()->unlockSettings();
|
||||
settings.endGroup();
|
||||
settings.endGroup();
|
||||
settings.endGroup();
|
||||
settings.endGroup();
|
||||
|
||||
return attachment;
|
||||
}
|
||||
|
@ -1940,14 +1948,13 @@ void MyAvatar::renderLaserPointers() {
|
|||
for (size_t i = 0; i < getHand()->getNumPalms(); ++i) {
|
||||
PalmData& palm = getHand()->getPalms()[i];
|
||||
if (palm.isActive()) {
|
||||
glColor4f(0, 1, 1, 1);
|
||||
glm::vec3 tip = getLaserPointerTipPosition(&palm);
|
||||
glm::vec3 root = palm.getPosition();
|
||||
|
||||
//Scale the root vector with the avatar scale
|
||||
scaleVectorRelativeToPosition(root);
|
||||
|
||||
Avatar::renderJointConnectingCone(root, tip, PALM_TIP_ROD_RADIUS, PALM_TIP_ROD_RADIUS);
|
||||
Avatar::renderJointConnectingCone(root, tip, PALM_TIP_ROD_RADIUS, PALM_TIP_ROD_RADIUS, glm::vec4(0, 1, 1, 1));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -51,7 +51,7 @@ public:
|
|||
// getters
|
||||
float getLeanScale() const { return _leanScale; }
|
||||
glm::vec3 getGravity() const { return _gravity; }
|
||||
glm::vec3 getDefaultEyePosition() const;
|
||||
Q_INVOKABLE glm::vec3 getDefaultEyePosition() const;
|
||||
bool getShouldRenderLocally() const { return _shouldRender; }
|
||||
|
||||
const QList<AnimationHandlePointer>& getAnimationHandles() const { return _animationHandles; }
|
||||
|
@ -78,8 +78,8 @@ public:
|
|||
Q_INVOKABLE AnimationDetails getAnimationDetails(const QString& url);
|
||||
|
||||
// get/set avatar data
|
||||
void saveData(QSettings* settings);
|
||||
void loadData(QSettings* settings);
|
||||
void saveData();
|
||||
void loadData();
|
||||
|
||||
void saveAttachmentData(const AttachmentData& attachment) const;
|
||||
AttachmentData loadAttachmentData(const QUrl& modelURL, const QString& jointName = QString()) const;
|
||||
|
|
|
@ -354,7 +354,7 @@ void SkeletonModel::renderJointConstraints(int jointIndex) {
|
|||
} else {
|
||||
otherAxis.x = 1.0f;
|
||||
}
|
||||
glColor4f(otherAxis.r, otherAxis.g, otherAxis.b, 0.75f);
|
||||
glm::vec4 color(otherAxis.r, otherAxis.g, otherAxis.b, 0.75f);
|
||||
|
||||
QVector<glm::vec3> points;
|
||||
points << glm::vec3(0.0f, 0.0f, 0.0f);
|
||||
|
@ -366,8 +366,8 @@ void SkeletonModel::renderJointConstraints(int jointIndex) {
|
|||
}
|
||||
// TODO: this is really inefficient constantly recreating these vertices buffers. It would be
|
||||
// better if the skeleton model cached these buffers for each of the joints they are rendering
|
||||
geometryCache->updateVertices(_triangleFanID, points);
|
||||
geometryCache->renderVertices(GL_TRIANGLE_FAN, _triangleFanID);
|
||||
geometryCache->updateVertices(_triangleFanID, points, color);
|
||||
geometryCache->renderVertices(gpu::TRIANGLE_FAN, _triangleFanID);
|
||||
|
||||
}
|
||||
glPopMatrix();
|
||||
|
@ -396,14 +396,14 @@ void SkeletonModel::renderOrientationDirections(int jointIndex, glm::vec3 positi
|
|||
glm::vec3 pUp = position + orientation * IDENTITY_UP * size;
|
||||
glm::vec3 pFront = position + orientation * IDENTITY_FRONT * size;
|
||||
|
||||
glColor3f(1.0f, 0.0f, 0.0f);
|
||||
geometryCache->renderLine(position, pRight, jointLineIDs._right);
|
||||
glm::vec3 red(1.0f, 0.0f, 0.0f);
|
||||
geometryCache->renderLine(position, pRight, red, jointLineIDs._right);
|
||||
|
||||
glColor3f(0.0f, 1.0f, 0.0f);
|
||||
geometryCache->renderLine(position, pUp, jointLineIDs._up);
|
||||
glm::vec3 green(0.0f, 1.0f, 0.0f);
|
||||
geometryCache->renderLine(position, pUp, green, jointLineIDs._up);
|
||||
|
||||
glColor3f(0.0f, 0.0f, 1.0f);
|
||||
geometryCache->renderLine(position, pFront, jointLineIDs._front);
|
||||
glm::vec3 blue(0.0f, 0.0f, 1.0f);
|
||||
geometryCache->renderLine(position, pFront, blue, jointLineIDs._front);
|
||||
}
|
||||
|
||||
|
||||
|
@ -601,10 +601,8 @@ void SkeletonModel::renderRagdoll() {
|
|||
glm::vec3 position = points[i]._position - simulationTranslation;
|
||||
glTranslatef(position.x, position.y, position.z);
|
||||
// draw each point as a yellow hexagon with black border
|
||||
glColor4f(0.0f, 0.0f, 0.0f, alpha);
|
||||
geometryCache->renderSphere(radius2, BALL_SUBDIVISIONS, BALL_SUBDIVISIONS);
|
||||
glColor4f(1.0f, 1.0f, 0.0f, alpha);
|
||||
geometryCache->renderSphere(radius1, BALL_SUBDIVISIONS, BALL_SUBDIVISIONS);
|
||||
geometryCache->renderSphere(radius2, BALL_SUBDIVISIONS, BALL_SUBDIVISIONS, glm::vec4(0.0f, 0.0f, 0.0f, alpha));
|
||||
geometryCache->renderSphere(radius1, BALL_SUBDIVISIONS, BALL_SUBDIVISIONS, glm::vec4(1.0f, 1.0f, 0.0f, alpha));
|
||||
glPopMatrix();
|
||||
}
|
||||
glPopMatrix();
|
||||
|
@ -953,9 +951,8 @@ void SkeletonModel::renderBoundingCollisionShapes(float alpha) {
|
|||
_boundingShape.getEndPoint(endPoint);
|
||||
endPoint = endPoint - _translation;
|
||||
glTranslatef(endPoint.x, endPoint.y, endPoint.z);
|
||||
glColor4f(0.6f, 0.6f, 0.8f, alpha);
|
||||
auto geometryCache = DependencyManager::get<GeometryCache>();
|
||||
geometryCache->renderSphere(_boundingShape.getRadius(), BALL_SUBDIVISIONS, BALL_SUBDIVISIONS);
|
||||
geometryCache->renderSphere(_boundingShape.getRadius(), BALL_SUBDIVISIONS, BALL_SUBDIVISIONS, glm::vec4(0.6f, 0.6f, 0.8f, alpha));
|
||||
|
||||
// draw a yellow sphere at the capsule startpoint
|
||||
glm::vec3 startPoint;
|
||||
|
@ -963,13 +960,11 @@ void SkeletonModel::renderBoundingCollisionShapes(float alpha) {
|
|||
startPoint = startPoint - _translation;
|
||||
glm::vec3 axis = endPoint - startPoint;
|
||||
glTranslatef(-axis.x, -axis.y, -axis.z);
|
||||
glColor4f(0.8f, 0.8f, 0.6f, alpha);
|
||||
geometryCache->renderSphere(_boundingShape.getRadius(), BALL_SUBDIVISIONS, BALL_SUBDIVISIONS);
|
||||
geometryCache->renderSphere(_boundingShape.getRadius(), BALL_SUBDIVISIONS, BALL_SUBDIVISIONS, glm::vec4(0.8f, 0.8f, 0.6f, alpha));
|
||||
|
||||
// draw a green cylinder between the two points
|
||||
glm::vec3 origin(0.0f);
|
||||
glColor4f(0.6f, 0.8f, 0.6f, alpha);
|
||||
Avatar::renderJointConnectingCone( origin, axis, _boundingShape.getRadius(), _boundingShape.getRadius());
|
||||
Avatar::renderJointConnectingCone( origin, axis, _boundingShape.getRadius(), _boundingShape.getRadius(), glm::vec4(0.6f, 0.8f, 0.6f, alpha));
|
||||
|
||||
glPopMatrix();
|
||||
}
|
||||
|
@ -998,8 +993,7 @@ void SkeletonModel::renderJointCollisionShapes(float alpha) {
|
|||
glm::vec3 position = shape->getTranslation() - simulationTranslation;
|
||||
glTranslatef(position.x, position.y, position.z);
|
||||
// draw a grey sphere at shape position
|
||||
glColor4f(0.75f, 0.75f, 0.75f, alpha);
|
||||
geometryCache->renderSphere(shape->getBoundingRadius(), BALL_SUBDIVISIONS, BALL_SUBDIVISIONS);
|
||||
geometryCache->renderSphere(shape->getBoundingRadius(), BALL_SUBDIVISIONS, BALL_SUBDIVISIONS, glm::vec4(0.75f, 0.75f, 0.75f, alpha));
|
||||
} else if (shape->getType() == CAPSULE_SHAPE) {
|
||||
CapsuleShape* capsule = static_cast<CapsuleShape*>(shape);
|
||||
|
||||
|
@ -1008,8 +1002,7 @@ void SkeletonModel::renderJointCollisionShapes(float alpha) {
|
|||
capsule->getEndPoint(endPoint);
|
||||
endPoint = endPoint - simulationTranslation;
|
||||
glTranslatef(endPoint.x, endPoint.y, endPoint.z);
|
||||
glColor4f(0.6f, 0.6f, 0.8f, alpha);
|
||||
geometryCache->renderSphere(capsule->getRadius(), BALL_SUBDIVISIONS, BALL_SUBDIVISIONS);
|
||||
geometryCache->renderSphere(capsule->getRadius(), BALL_SUBDIVISIONS, BALL_SUBDIVISIONS, glm::vec4(0.6f, 0.6f, 0.8f, alpha));
|
||||
|
||||
// draw a yellow sphere at the capsule startpoint
|
||||
glm::vec3 startPoint;
|
||||
|
@ -1017,13 +1010,11 @@ void SkeletonModel::renderJointCollisionShapes(float alpha) {
|
|||
startPoint = startPoint - simulationTranslation;
|
||||
glm::vec3 axis = endPoint - startPoint;
|
||||
glTranslatef(-axis.x, -axis.y, -axis.z);
|
||||
glColor4f(0.8f, 0.8f, 0.6f, alpha);
|
||||
geometryCache->renderSphere(capsule->getRadius(), BALL_SUBDIVISIONS, BALL_SUBDIVISIONS);
|
||||
geometryCache->renderSphere(capsule->getRadius(), BALL_SUBDIVISIONS, BALL_SUBDIVISIONS, glm::vec4(0.8f, 0.8f, 0.6f, alpha));
|
||||
|
||||
// draw a green cylinder between the two points
|
||||
glm::vec3 origin(0.0f);
|
||||
glColor4f(0.6f, 0.8f, 0.6f, alpha);
|
||||
Avatar::renderJointConnectingCone( origin, axis, capsule->getRadius(), capsule->getRadius());
|
||||
Avatar::renderJointConnectingCone( origin, axis, capsule->getRadius(), capsule->getRadius(), glm::vec4(0.6f, 0.8f, 0.6f, alpha));
|
||||
}
|
||||
glPopMatrix();
|
||||
}
|
||||
|
|
|
@ -11,7 +11,9 @@
|
|||
|
||||
#include <QTimer>
|
||||
|
||||
#include <GLMHelpers.h>
|
||||
#include <PerfStat.h>
|
||||
#include <Settings.h>
|
||||
#include <SharedUtil.h>
|
||||
|
||||
#include "Faceshift.h"
|
||||
|
@ -27,6 +29,11 @@ using namespace std;
|
|||
const quint16 FACESHIFT_PORT = 33433;
|
||||
float STARTING_FACESHIFT_FRAME_TIME = 0.033f;
|
||||
|
||||
namespace SettingHandles {
|
||||
const SettingHandle<float> faceshiftEyeDeflection("faceshiftEyeDeflection", DEFAULT_FACESHIFT_EYE_DEFLECTION);
|
||||
const SettingHandle<QString> faceshiftHostname("faceshiftHostname", DEFAULT_FACESHIFT_HOSTNAME);
|
||||
}
|
||||
|
||||
Faceshift::Faceshift() :
|
||||
_tcpEnabled(true),
|
||||
_tcpRetryCount(0),
|
||||
|
@ -66,6 +73,9 @@ Faceshift::Faceshift() :
|
|||
|
||||
_udpSocket.bind(FACESHIFT_PORT);
|
||||
#endif
|
||||
|
||||
_eyeDeflection = SettingHandles::faceshiftEyeDeflection.get();
|
||||
_hostname = SettingHandles::faceshiftHostname.get();
|
||||
}
|
||||
|
||||
void Faceshift::init() {
|
||||
|
@ -159,7 +169,7 @@ void Faceshift::connectSocket() {
|
|||
qDebug("Faceshift: Connecting...");
|
||||
}
|
||||
|
||||
_tcpSocket.connectToHost(Menu::getInstance()->getFaceshiftHostname(), FACESHIFT_PORT);
|
||||
_tcpSocket.connectToHost(_hostname, FACESHIFT_PORT);
|
||||
_tracking = false;
|
||||
}
|
||||
}
|
||||
|
@ -309,3 +319,13 @@ void Faceshift::receive(const QByteArray& buffer) {
|
|||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void Faceshift::setEyeDeflection(float faceshiftEyeDeflection) {
|
||||
_eyeDeflection = faceshiftEyeDeflection;
|
||||
SettingHandles::faceshiftEyeDeflection.set(_eyeDeflection);
|
||||
}
|
||||
|
||||
void Faceshift::setHostname(const QString& hostname) {
|
||||
_hostname = hostname;
|
||||
SettingHandles::faceshiftHostname.set(_hostname);
|
||||
}
|
||||
|
|
|
@ -61,6 +61,12 @@ public:
|
|||
float getMouthSize() const { return getBlendshapeCoefficient(_jawOpenIndex); }
|
||||
float getMouthSmileLeft() const { return getBlendshapeCoefficient(_mouthSmileLeftIndex); }
|
||||
float getMouthSmileRight() const { return getBlendshapeCoefficient(_mouthSmileRightIndex); }
|
||||
|
||||
float getEyeDeflection() const { return _eyeDeflection; }
|
||||
void setEyeDeflection(float faceshiftEyeDeflection);
|
||||
|
||||
const QString& getHostname() const { return _hostname; }
|
||||
void setHostname(const QString& hostname);
|
||||
|
||||
void update();
|
||||
void reset();
|
||||
|
@ -145,6 +151,9 @@ private:
|
|||
float _longTermAverageEyeYaw;
|
||||
bool _longTermAverageInitialized;
|
||||
|
||||
float _eyeDeflection = DEFAULT_FACESHIFT_EYE_DEFLECTION;
|
||||
QString _hostname = DEFAULT_FACESHIFT_HOSTNAME;
|
||||
|
||||
};
|
||||
|
||||
#endif // hifi_Faceshift_h
|
||||
|
|
|
@ -218,6 +218,6 @@ void PrioVR::renderCalibrationCountdown() {
|
|||
auto glCanvas = DependencyManager::get<GLCanvas>();
|
||||
textRenderer->draw((glCanvas->width() - textRenderer->computeWidth(text.constData())) / 2,
|
||||
glCanvas->height() / 2,
|
||||
text);
|
||||
text, glm::vec4(1,1,1,1));
|
||||
#endif
|
||||
}
|
||||
|
|
|
@ -8,6 +8,8 @@
|
|||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#include "Application.h"
|
||||
#include "RealSense.h"
|
||||
#include "MainWindow.h"
|
||||
#include "Menu.h"
|
||||
|
|
|
@ -40,6 +40,7 @@ public:
|
|||
|
||||
virtual void update();
|
||||
|
||||
public slots:
|
||||
void loadRSSDKFile();
|
||||
|
||||
protected:
|
||||
|
|
|
@ -301,7 +301,16 @@ const float RANGE_MULT = (MAX_PIXEL_RANGE_MULT - MIN_PIXEL_RANGE_MULT) * 0.01;
|
|||
//Returns a multiplier to be applied to the cursor range for the controllers
|
||||
float SixenseManager::getCursorPixelRangeMult() const {
|
||||
//scales (0,100) to (MINIMUM_PIXEL_RANGE_MULT, MAXIMUM_PIXEL_RANGE_MULT)
|
||||
return Menu::getInstance()->getSixenseReticleMoveSpeed() * RANGE_MULT + MIN_PIXEL_RANGE_MULT;
|
||||
return _reticleMoveSpeed * RANGE_MULT + MIN_PIXEL_RANGE_MULT;
|
||||
}
|
||||
|
||||
void SixenseManager::toggleSixense(bool shouldEnable) {
|
||||
if (shouldEnable && !isInitialized()) {
|
||||
initialize();
|
||||
setFilter(Menu::getInstance()->isOptionChecked(MenuOption::FilterSixense));
|
||||
setLowVelocityFilter(Menu::getInstance()->isOptionChecked(MenuOption::LowVelocityFilter));
|
||||
}
|
||||
setIsEnabled(shouldEnable);
|
||||
}
|
||||
|
||||
#ifdef HAVE_SIXENSE
|
||||
|
@ -459,7 +468,7 @@ void SixenseManager::emulateMouse(PalmData* palm, int index) {
|
|||
|
||||
unsigned int deviceID = index == 0 ? CONTROLLER_0_EVENT : CONTROLLER_1_EVENT;
|
||||
|
||||
if (Menu::getInstance()->getInvertSixenseButtons()) {
|
||||
if (_invertButtons) {
|
||||
bumperButton = Qt::LeftButton;
|
||||
triggerButton = Qt::RightButton;
|
||||
} else {
|
||||
|
|
|
@ -55,8 +55,13 @@ public:
|
|||
void update(float deltaTime);
|
||||
float getCursorPixelRangeMult() const;
|
||||
|
||||
public slots:
|
||||
float getReticleMoveSpeed() const { return _reticleMoveSpeed; }
|
||||
void setReticleMoveSpeed(float sixenseReticleMoveSpeed) { _reticleMoveSpeed = sixenseReticleMoveSpeed; }
|
||||
bool getInvertButtons() const { return _invertButtons; }
|
||||
void setInvertButtons(bool invertSixenseButtons) { _invertButtons = invertSixenseButtons; }
|
||||
|
||||
public slots:
|
||||
void toggleSixense(bool shouldEnable);
|
||||
void setFilter(bool filter);
|
||||
void setLowVelocityFilter(bool lowVelocityFilter) { _lowVelocityFilter = lowVelocityFilter; };
|
||||
|
||||
|
@ -102,6 +107,9 @@ private:
|
|||
|
||||
bool _lowVelocityFilter;
|
||||
bool _controllersAtBase;
|
||||
|
||||
float _reticleMoveSpeed = DEFAULT_SIXENSE_RETICLE_MOVE_SPEED;
|
||||
bool _invertButtons = DEFAULT_INVERT_SIXENSE_MOUSE_BUTTONS;
|
||||
};
|
||||
|
||||
#endif // hifi_SixenseManager_h
|
||||
|
|
|
@ -8,13 +8,15 @@
|
|||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#include "Application.h"
|
||||
|
||||
#include <QDebug>
|
||||
#include <QDir>
|
||||
#include <QSettings>
|
||||
#include <QTranslator>
|
||||
|
||||
#include <SharedUtil.h>
|
||||
|
||||
#include "Application.h"
|
||||
|
||||
int main(int argc, const char * argv[]) {
|
||||
QElapsedTimer startupTime;
|
||||
startupTime.start();
|
||||
|
|
|
@ -43,12 +43,11 @@ void OctreeFade::render() {
|
|||
glDisable(GL_LIGHTING);
|
||||
glPushMatrix();
|
||||
glScalef(TREE_SCALE, TREE_SCALE, TREE_SCALE);
|
||||
glColor4f(red, green, blue, opacity);
|
||||
glTranslatef(voxelDetails.x + voxelDetails.s * 0.5f,
|
||||
voxelDetails.y + voxelDetails.s * 0.5f,
|
||||
voxelDetails.z + voxelDetails.s * 0.5f);
|
||||
glLineWidth(1.0f);
|
||||
DependencyManager::get<GeometryCache>()->renderSolidCube(voxelDetails.s);
|
||||
DependencyManager::get<GeometryCache>()->renderSolidCube(voxelDetails.s, glm::vec4(red, green, blue, opacity));
|
||||
glLineWidth(1.0f);
|
||||
glPopMatrix();
|
||||
glEnable(GL_LIGHTING);
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#include "Application.h"
|
||||
#include "Audio.h"
|
||||
#include "AudioDeviceScriptingInterface.h"
|
||||
|
||||
|
||||
|
@ -21,6 +21,8 @@ AudioDeviceScriptingInterface* AudioDeviceScriptingInterface::getInstance() {
|
|||
AudioDeviceScriptingInterface::AudioDeviceScriptingInterface() {
|
||||
connect(DependencyManager::get<Audio>().data(), &Audio::muteToggled,
|
||||
this, &AudioDeviceScriptingInterface::muteToggled);
|
||||
connect(DependencyManager::get<Audio>().data(), &Audio::deviceChanged,
|
||||
this, &AudioDeviceScriptingInterface::deviceChanged);
|
||||
}
|
||||
|
||||
bool AudioDeviceScriptingInterface::setInputDevice(const QString& deviceName) {
|
||||
|
|
|
@ -12,11 +12,11 @@
|
|||
#ifndef hifi_AudioDeviceScriptingInterface_h
|
||||
#define hifi_AudioDeviceScriptingInterface_h
|
||||
|
||||
#include <QDebug>
|
||||
#include <QObject>
|
||||
#include <QString>
|
||||
#include <QVector>
|
||||
|
||||
#include "Application.h"
|
||||
class AudioEffectOptions;
|
||||
|
||||
class AudioDeviceScriptingInterface : public QObject {
|
||||
Q_OBJECT
|
||||
|
@ -49,6 +49,7 @@ private:
|
|||
|
||||
signals:
|
||||
void muteToggled();
|
||||
void deviceChanged();
|
||||
};
|
||||
|
||||
#endif // hifi_AudioDeviceScriptingInterface_h
|
||||
|
|
|
@ -9,7 +9,8 @@
|
|||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#include "Application.h"
|
||||
#include <Settings.h>
|
||||
|
||||
#include "SettingsScriptingInterface.h"
|
||||
|
||||
|
||||
|
@ -19,9 +20,7 @@ SettingsScriptingInterface* SettingsScriptingInterface::getInstance() {
|
|||
}
|
||||
|
||||
QVariant SettingsScriptingInterface::getValue(const QString& setting) {
|
||||
QSettings* settings = Application::getInstance()->lockSettings();
|
||||
QVariant value = settings->value(setting);
|
||||
Application::getInstance()->unlockSettings();
|
||||
QVariant value = SettingHandles::SettingHandle<QVariant>(setting).get();
|
||||
if (!value.isValid()) {
|
||||
value = "";
|
||||
}
|
||||
|
@ -29,9 +28,7 @@ QVariant SettingsScriptingInterface::getValue(const QString& setting) {
|
|||
}
|
||||
|
||||
QVariant SettingsScriptingInterface::getValue(const QString& setting, const QVariant& defaultValue) {
|
||||
QSettings* settings = Application::getInstance()->lockSettings();
|
||||
QVariant value = settings->value(setting, defaultValue);
|
||||
Application::getInstance()->unlockSettings();
|
||||
QVariant value = SettingHandles::SettingHandle<QVariant>(setting, defaultValue).get();
|
||||
if (!value.isValid()) {
|
||||
value = "";
|
||||
}
|
||||
|
@ -39,7 +36,5 @@ QVariant SettingsScriptingInterface::getValue(const QString& setting, const QVar
|
|||
}
|
||||
|
||||
void SettingsScriptingInterface::setValue(const QString& setting, const QVariant& value) {
|
||||
QSettings* settings = Application::getInstance()->lockSettings();
|
||||
settings->setValue(setting, value);
|
||||
Application::getInstance()->unlockSettings();
|
||||
SettingHandles::SettingHandle<QVariant>(setting).set(value);
|
||||
}
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
#include <QInputDialog>
|
||||
#include <QMessageBox>
|
||||
#include <QScriptValue>
|
||||
#include <QScrollArea>
|
||||
|
||||
#include "Application.h"
|
||||
#include "MainWindow.h"
|
||||
|
|
|
@ -21,8 +21,8 @@
|
|||
const QString ADDRESSBAR_GO_BUTTON_ICON = "images/address-bar-submit.svg";
|
||||
const QString ADDRESSBAR_GO_BUTTON_ACTIVE_ICON = "images/address-bar-submit-active.svg";
|
||||
|
||||
AddressBarDialog::AddressBarDialog() :
|
||||
FramelessDialog(Application::getInstance()->getWindow(), 0, FramelessDialog::POSITION_TOP)
|
||||
AddressBarDialog::AddressBarDialog(QWidget* parent) :
|
||||
FramelessDialog(parent, 0, FramelessDialog::POSITION_TOP)
|
||||
{
|
||||
setAttribute(Qt::WA_DeleteOnClose, false);
|
||||
setupUI();
|
||||
|
|
|
@ -23,7 +23,7 @@ class AddressBarDialog : public FramelessDialog {
|
|||
Q_OBJECT
|
||||
|
||||
public:
|
||||
AddressBarDialog();
|
||||
AddressBarDialog(QWidget* parent);
|
||||
|
||||
private:
|
||||
void setupUI();
|
||||
|
|
|
@ -20,12 +20,18 @@
|
|||
#include <QScrollArea>
|
||||
#include <QVBoxLayout>
|
||||
|
||||
#include <Settings.h>
|
||||
|
||||
#include "AnimationsDialog.h"
|
||||
#include "Application.h"
|
||||
#include "MainWindow.h"
|
||||
|
||||
AnimationsDialog::AnimationsDialog() :
|
||||
QDialog(Application::getInstance()->getWindow()) {
|
||||
namespace SettingHandles {
|
||||
const SettingHandle<QString> animationDirectory("animation_directory", QString());
|
||||
}
|
||||
|
||||
AnimationsDialog::AnimationsDialog(QWidget* parent) :
|
||||
QDialog(parent) {
|
||||
|
||||
setWindowTitle("Edit Animations");
|
||||
setAttribute(Qt::WA_DeleteOnClose);
|
||||
|
@ -157,14 +163,12 @@ AnimationPanel::AnimationPanel(AnimationsDialog* dialog, const AnimationHandlePo
|
|||
}
|
||||
|
||||
void AnimationPanel::chooseURL() {
|
||||
QString directory = Application::getInstance()->lockSettings()->value("animation_directory").toString();
|
||||
Application::getInstance()->unlockSettings();
|
||||
QString directory = SettingHandles::animationDirectory.get();
|
||||
QString filename = QFileDialog::getOpenFileName(this, "Choose Animation", directory, "Animation files (*.fbx)");
|
||||
if (filename.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
Application::getInstance()->lockSettings()->setValue("animation_directory", QFileInfo(filename).path());
|
||||
Application::getInstance()->unlockSettings();
|
||||
SettingHandles::animationDirectory.set(QFileInfo(filename).path());
|
||||
_url->setText(QUrl::fromLocalFile(filename).toString());
|
||||
emit _url->returnPressed();
|
||||
}
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
#define hifi_AnimationsDialog_h
|
||||
|
||||
#include <QDialog>
|
||||
#include <QDoubleSpinBox>
|
||||
#include <QFrame>
|
||||
|
||||
#include "avatar/MyAvatar.h"
|
||||
|
@ -30,7 +31,7 @@ class AnimationsDialog : public QDialog {
|
|||
|
||||
public:
|
||||
|
||||
AnimationsDialog();
|
||||
AnimationsDialog(QWidget* parent = nullptr);
|
||||
|
||||
virtual void setVisible(bool visible);
|
||||
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
#include <PathUtils.h>
|
||||
#include <PerfStat.h>
|
||||
|
||||
#include "Audio.h"
|
||||
#include "audio/AudioIOStatsRenderer.h"
|
||||
#include "audio/AudioScope.h"
|
||||
#include "audio/AudioToolBox.h"
|
||||
|
@ -117,10 +118,16 @@ void ApplicationOverlay::renderReticle(glm::quat orientation, float alpha) {
|
|||
glm::vec3 topRight = getPoint(-reticleSize / 2.0f, -reticleSize / 2.0f);
|
||||
glm::vec3 bottomLeft = getPoint(reticleSize / 2.0f, reticleSize / 2.0f);
|
||||
glm::vec3 bottomRight = getPoint(-reticleSize / 2.0f, reticleSize / 2.0f);
|
||||
glColor4f(RETICLE_COLOR[0], RETICLE_COLOR[1], RETICLE_COLOR[2], alpha);
|
||||
|
||||
// TODO: this version of renderQuad() needs to take a color
|
||||
glm::vec4 reticleColor = { RETICLE_COLOR[0], RETICLE_COLOR[1], RETICLE_COLOR[2], alpha };
|
||||
|
||||
|
||||
|
||||
DependencyManager::get<GeometryCache>()->renderQuad(topLeft, bottomLeft, bottomRight, topRight,
|
||||
glm::vec2(0.0f, 0.0f), glm::vec2(1.0f, 0.0f),
|
||||
glm::vec2(1.0f, 1.0f), glm::vec2(0.0f, 1.0f), _reticleQuad);
|
||||
glm::vec2(1.0f, 1.0f), glm::vec2(0.0f, 1.0f),
|
||||
reticleColor, _reticleQuad);
|
||||
} glPopMatrix();
|
||||
}
|
||||
|
||||
|
@ -164,7 +171,7 @@ void ApplicationOverlay::renderOverlay(bool renderToTexture) {
|
|||
Overlays& overlays = application->getOverlays();
|
||||
auto glCanvas = DependencyManager::get<GLCanvas>();
|
||||
|
||||
_textureFov = glm::radians(Menu::getInstance()->getOculusUIAngularSize());
|
||||
_textureFov = glm::radians(_oculusUIAngularSize);
|
||||
_textureAspectRatio = (float)glCanvas->getDeviceWidth() / (float)glCanvas->getDeviceHeight();
|
||||
|
||||
//Handle fading and deactivation/activation of UI
|
||||
|
@ -245,13 +252,13 @@ void ApplicationOverlay::displayOverlayTexture() {
|
|||
glDisable(GL_LIGHTING);
|
||||
glEnable(GL_BLEND);
|
||||
|
||||
glColor4f(1.0f, 1.0f, 1.0f, _alpha);
|
||||
glm::vec2 topLeft(0.0f, 0.0f);
|
||||
glm::vec2 bottomRight(glCanvas->getDeviceWidth(), glCanvas->getDeviceHeight());
|
||||
glm::vec2 texCoordTopLeft(0.0f, 1.0f);
|
||||
glm::vec2 texCoordBottomRight(1.0f, 0.0f);
|
||||
|
||||
DependencyManager::get<GeometryCache>()->renderQuad(topLeft, bottomRight, texCoordTopLeft, texCoordBottomRight);
|
||||
DependencyManager::get<GeometryCache>()->renderQuad(topLeft, bottomRight, texCoordTopLeft, texCoordBottomRight,
|
||||
glm::vec4(1.0f, 1.0f, 1.0f, _alpha));
|
||||
|
||||
} glPopMatrix();
|
||||
|
||||
|
@ -314,8 +321,6 @@ void ApplicationOverlay::displayOverlayTextureOculus(Camera& whichCamera) {
|
|||
glDepthMask(GL_FALSE);
|
||||
glDisable(GL_ALPHA_TEST);
|
||||
|
||||
glColor4f(1.0f, 1.0f, 1.0f, _alpha);
|
||||
|
||||
static float textureFOV = 0.0f, textureAspectRatio = 1.0f;
|
||||
if (textureFOV != _textureFov ||
|
||||
textureAspectRatio != _textureAspectRatio) {
|
||||
|
@ -374,7 +379,7 @@ void ApplicationOverlay::displayOverlayTexture3DTV(Camera& whichCamera, float as
|
|||
glTranslatef(pos.x, pos.y, pos.z);
|
||||
glRotatef(glm::degrees(glm::angle(rot)), axis.x, axis.y, axis.z);
|
||||
|
||||
glColor4f(1.0f, 1.0f, 1.0f, _alpha);
|
||||
glm::vec4 overlayColor = {1.0f, 1.0f, 1.0f, _alpha};
|
||||
|
||||
//Render
|
||||
const GLfloat distance = 1.0f;
|
||||
|
@ -393,7 +398,8 @@ void ApplicationOverlay::displayOverlayTexture3DTV(Camera& whichCamera, float as
|
|||
glm::vec3(x + quadWidth, y, -distance),
|
||||
glm::vec3(x, y, -distance),
|
||||
glm::vec2(0.0f, 1.0f), glm::vec2(1.0f, 1.0f),
|
||||
glm::vec2(1.0f, 0.0f), glm::vec2(0.0f, 0.0f));
|
||||
glm::vec2(1.0f, 0.0f), glm::vec2(0.0f, 0.0f),
|
||||
overlayColor);
|
||||
|
||||
auto glCanvas = DependencyManager::get<GLCanvas>();
|
||||
if (_crosshairTexture == 0) {
|
||||
|
@ -409,7 +415,7 @@ void ApplicationOverlay::displayOverlayTexture3DTV(Camera& whichCamera, float as
|
|||
const float mouseX = (application->getMouseX() / (float)glCanvas->width()) * quadWidth;
|
||||
const float mouseY = (1.0 - (application->getMouseY() / (float)glCanvas->height())) * quadHeight;
|
||||
|
||||
glColor3f(RETICLE_COLOR[0], RETICLE_COLOR[1], RETICLE_COLOR[2]);
|
||||
glm::vec4 reticleColor = { RETICLE_COLOR[0], RETICLE_COLOR[1], RETICLE_COLOR[2], 1.0f };
|
||||
|
||||
DependencyManager::get<GeometryCache>()->renderQuad(glm::vec3(x + mouseX, y + mouseY, -distance),
|
||||
glm::vec3(x + mouseX + reticleSize, y + mouseY, -distance),
|
||||
|
@ -417,7 +423,7 @@ void ApplicationOverlay::displayOverlayTexture3DTV(Camera& whichCamera, float as
|
|||
glm::vec3(x + mouseX, y + mouseY - reticleSize, -distance),
|
||||
glm::vec2(0.0f, 0.0f), glm::vec2(1.0f, 0.0f),
|
||||
glm::vec2(1.0f, 1.0f), glm::vec2(0.0f, 1.0f),
|
||||
_reticleQuad);
|
||||
reticleColor, _reticleQuad);
|
||||
|
||||
glEnable(GL_DEPTH_TEST);
|
||||
|
||||
|
@ -429,8 +435,6 @@ void ApplicationOverlay::displayOverlayTexture3DTV(Camera& whichCamera, float as
|
|||
|
||||
glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_CONSTANT_ALPHA, GL_ONE);
|
||||
glEnable(GL_LIGHTING);
|
||||
|
||||
glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
|
||||
}
|
||||
|
||||
void ApplicationOverlay::computeOculusPickRay(float x, float y, glm::vec3& origin, glm::vec3& direction) const {
|
||||
|
@ -673,14 +677,13 @@ void ApplicationOverlay::renderControllerPointers() {
|
|||
mouseY += reticleSize / 2.0f;
|
||||
|
||||
|
||||
glColor3f(RETICLE_COLOR[0], RETICLE_COLOR[1], RETICLE_COLOR[2]);
|
||||
|
||||
glm::vec2 topLeft(mouseX, mouseY);
|
||||
glm::vec2 bottomRight(mouseX + reticleSize, mouseY - reticleSize);
|
||||
glm::vec2 texCoordTopLeft(0.0f, 0.0f);
|
||||
glm::vec2 texCoordBottomRight(1.0f, 1.0f);
|
||||
|
||||
DependencyManager::get<GeometryCache>()->renderQuad(topLeft, bottomRight, texCoordTopLeft, texCoordBottomRight);
|
||||
DependencyManager::get<GeometryCache>()->renderQuad(topLeft, bottomRight, texCoordTopLeft, texCoordBottomRight,
|
||||
glm::vec4(RETICLE_COLOR[0], RETICLE_COLOR[1], RETICLE_COLOR[2], 1.0f));
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -756,7 +759,7 @@ void ApplicationOverlay::renderMagnifier(glm::vec2 magPos, float sizeMult, bool
|
|||
border << bottomRight;
|
||||
border << topRight;
|
||||
border << topLeft;
|
||||
geometryCache->updateVertices(_magnifierBorder, border);
|
||||
geometryCache->updateVertices(_magnifierBorder, border, glm::vec4(1.0f, 0.0f, 0.0f, _alpha));
|
||||
|
||||
_previousMagnifierBottomLeft = bottomLeft;
|
||||
_previousMagnifierBottomRight = bottomRight;
|
||||
|
@ -769,18 +772,17 @@ void ApplicationOverlay::renderMagnifier(glm::vec2 magPos, float sizeMult, bool
|
|||
glDisable(GL_TEXTURE_2D);
|
||||
glLineWidth(1.0f);
|
||||
//Outer Line
|
||||
glColor4f(1.0f, 0.0f, 0.0f, _alpha);
|
||||
geometryCache->renderVertices(GL_LINE_STRIP, _magnifierBorder);
|
||||
geometryCache->renderVertices(gpu::LINE_STRIP, _magnifierBorder);
|
||||
glEnable(GL_TEXTURE_2D);
|
||||
}
|
||||
glColor4f(1.0f, 1.0f, 1.0f, _alpha);
|
||||
glm::vec4 magnifierColor = { 1.0f, 1.0f, 1.0f, _alpha };
|
||||
|
||||
DependencyManager::get<GeometryCache>()->renderQuad(bottomLeft, bottomRight, topRight, topLeft,
|
||||
glm::vec2(magnifyULeft, magnifyVBottom),
|
||||
glm::vec2(magnifyURight, magnifyVBottom),
|
||||
glm::vec2(magnifyURight, magnifyVTop),
|
||||
glm::vec2(magnifyULeft, magnifyVTop),
|
||||
_magnifierQuad);
|
||||
magnifierColor, _magnifierQuad);
|
||||
|
||||
} glPopMatrix();
|
||||
}
|
||||
|
@ -809,9 +811,9 @@ void ApplicationOverlay::renderAudioMeter() {
|
|||
audioMeterY = AUDIO_METER_GAP + MUTE_ICON_PADDING;
|
||||
}
|
||||
|
||||
const float AUDIO_METER_BLUE[] = { 0.0, 0.0, 1.0 };
|
||||
const float AUDIO_METER_GREEN[] = { 0.0, 1.0, 0.0 };
|
||||
const float AUDIO_METER_RED[] = { 1.0, 0.0, 0.0 };
|
||||
const glm::vec4 AUDIO_METER_BLUE = { 0.0, 0.0, 1.0, 1.0 };
|
||||
const glm::vec4 AUDIO_METER_GREEN = { 0.0, 1.0, 0.0, 1.0 };
|
||||
const glm::vec4 AUDIO_METER_RED = { 1.0, 0.0, 0.0, 1.0 };
|
||||
const float AUDIO_GREEN_START = 0.25 * AUDIO_METER_SCALE_WIDTH;
|
||||
const float AUDIO_RED_START = 0.80 * AUDIO_METER_SCALE_WIDTH;
|
||||
const float CLIPPING_INDICATOR_TIME = 1.0f;
|
||||
|
@ -846,59 +848,56 @@ void ApplicationOverlay::renderAudioMeter() {
|
|||
DependencyManager::get<AudioScope>()->render(glCanvas->width(), glCanvas->height());
|
||||
DependencyManager::get<AudioIOStatsRenderer>()->render(WHITE_TEXT, glCanvas->width(), glCanvas->height());
|
||||
|
||||
if (isClipping) {
|
||||
glColor3f(1, 0, 0);
|
||||
} else {
|
||||
glColor3f(0.475f, 0.475f, 0.475f);
|
||||
}
|
||||
|
||||
audioMeterY += AUDIO_METER_HEIGHT;
|
||||
|
||||
glColor3f(0, 0, 0);
|
||||
// Draw audio meter background Quad
|
||||
DependencyManager::get<GeometryCache>()->renderQuad(AUDIO_METER_X, audioMeterY, AUDIO_METER_WIDTH, AUDIO_METER_HEIGHT);
|
||||
DependencyManager::get<GeometryCache>()->renderQuad(AUDIO_METER_X, audioMeterY, AUDIO_METER_WIDTH, AUDIO_METER_HEIGHT,
|
||||
glm::vec4(0, 0, 0, 1));
|
||||
|
||||
if (audioLevel > AUDIO_RED_START) {
|
||||
glm::vec4 quadColor;
|
||||
if (!isClipping) {
|
||||
glColor3fv(AUDIO_METER_RED);
|
||||
quadColor = AUDIO_METER_RED;
|
||||
} else {
|
||||
glColor3f(1, 1, 1);
|
||||
quadColor = glm::vec4(1, 1, 1, 1);
|
||||
}
|
||||
// Draw Red Quad
|
||||
DependencyManager::get<GeometryCache>()->renderQuad(AUDIO_METER_X + AUDIO_METER_INSET + AUDIO_RED_START,
|
||||
audioMeterY + AUDIO_METER_INSET,
|
||||
audioLevel - AUDIO_RED_START,
|
||||
AUDIO_METER_HEIGHT - AUDIO_METER_INSET,
|
||||
AUDIO_METER_HEIGHT - AUDIO_METER_INSET, quadColor,
|
||||
_audioRedQuad);
|
||||
|
||||
audioLevel = AUDIO_RED_START;
|
||||
}
|
||||
|
||||
if (audioLevel > AUDIO_GREEN_START) {
|
||||
glm::vec4 quadColor;
|
||||
if (!isClipping) {
|
||||
glColor3fv(AUDIO_METER_GREEN);
|
||||
quadColor = AUDIO_METER_GREEN;
|
||||
} else {
|
||||
glColor3f(1, 1, 1);
|
||||
quadColor = glm::vec4(1, 1, 1, 1);
|
||||
}
|
||||
// Draw Green Quad
|
||||
DependencyManager::get<GeometryCache>()->renderQuad(AUDIO_METER_X + AUDIO_METER_INSET + AUDIO_GREEN_START,
|
||||
audioMeterY + AUDIO_METER_INSET,
|
||||
audioLevel - AUDIO_GREEN_START,
|
||||
AUDIO_METER_HEIGHT - AUDIO_METER_INSET,
|
||||
AUDIO_METER_HEIGHT - AUDIO_METER_INSET, quadColor,
|
||||
_audioGreenQuad);
|
||||
|
||||
audioLevel = AUDIO_GREEN_START;
|
||||
}
|
||||
// Draw Blue Quad
|
||||
glm::vec4 quadColor;
|
||||
if (!isClipping) {
|
||||
glColor3fv(AUDIO_METER_BLUE);
|
||||
quadColor = AUDIO_METER_BLUE;
|
||||
} else {
|
||||
glColor3f(1, 1, 1);
|
||||
quadColor = glm::vec4(1, 1, 1, 1);
|
||||
}
|
||||
// Draw Blue (low level) quad
|
||||
DependencyManager::get<GeometryCache>()->renderQuad(AUDIO_METER_X + AUDIO_METER_INSET,
|
||||
audioMeterY + AUDIO_METER_INSET,
|
||||
audioLevel, AUDIO_METER_HEIGHT - AUDIO_METER_INSET,
|
||||
audioLevel, AUDIO_METER_HEIGHT - AUDIO_METER_INSET, quadColor,
|
||||
_audioBlueQuad);
|
||||
}
|
||||
|
||||
|
@ -908,7 +907,6 @@ void ApplicationOverlay::renderStatsAndLogs() {
|
|||
|
||||
auto glCanvas = DependencyManager::get<GLCanvas>();
|
||||
const OctreePacketProcessor& octreePacketProcessor = application->getOctreePacketProcessor();
|
||||
BandwidthMeter* bandwidthMeter = application->getBandwidthMeter();
|
||||
NodeBounds& nodeBoundsDisplay = application->getNodeBoundsDisplay();
|
||||
|
||||
// Display stats and log text onscreen
|
||||
|
@ -921,12 +919,11 @@ void ApplicationOverlay::renderStatsAndLogs() {
|
|||
int voxelPacketsToProcess = octreePacketProcessor.packetsToProcessCount();
|
||||
// Onscreen text about position, servers, etc
|
||||
Stats::getInstance()->display(WHITE_TEXT, horizontalOffset, application->getFps(),
|
||||
application->getPacketsPerSecond(), application->getBytesPerSecond(), voxelPacketsToProcess);
|
||||
// Bandwidth meter
|
||||
if (Menu::getInstance()->isOptionChecked(MenuOption::Bandwidth)) {
|
||||
Stats::drawBackground(0x33333399, glCanvas->width() - 296, glCanvas->height() - 68, 296, 68);
|
||||
bandwidthMeter->render(glCanvas->width(), glCanvas->height());
|
||||
}
|
||||
application->getInPacketsPerSecond(),
|
||||
application->getOutPacketsPerSecond(),
|
||||
application->getInBytesPerSecond(),
|
||||
application->getOutBytesPerSecond(),
|
||||
voxelPacketsToProcess);
|
||||
}
|
||||
|
||||
// Show on-screen msec timer
|
||||
|
@ -935,8 +932,7 @@ void ApplicationOverlay::renderStatsAndLogs() {
|
|||
quint64 mSecsNow = floor(usecTimestampNow() / 1000.0 + 0.5);
|
||||
sprintf(frameTimer, "%d\n", (int)(mSecsNow % 1000));
|
||||
int timerBottom =
|
||||
(Menu::getInstance()->isOptionChecked(MenuOption::Stats) &&
|
||||
Menu::getInstance()->isOptionChecked(MenuOption::Bandwidth))
|
||||
(Menu::getInstance()->isOptionChecked(MenuOption::Stats))
|
||||
? 80 : 20;
|
||||
drawText(glCanvas->width() - 100, glCanvas->height() - timerBottom,
|
||||
0.30f, 0.0f, 0, frameTimer, WHITE_TEXT);
|
||||
|
@ -954,23 +950,24 @@ void ApplicationOverlay::renderDomainConnectionStatusBorder() {
|
|||
int height = glCanvas->height();
|
||||
|
||||
if (width != _previousBorderWidth || height != _previousBorderHeight) {
|
||||
glm::vec4 color(CONNECTION_STATUS_BORDER_COLOR[0],
|
||||
CONNECTION_STATUS_BORDER_COLOR[1],
|
||||
CONNECTION_STATUS_BORDER_COLOR[2], 1.0f);
|
||||
|
||||
QVector<glm::vec2> border;
|
||||
border << glm::vec2(0, 0);
|
||||
border << glm::vec2(0, height);
|
||||
border << glm::vec2(width, height);
|
||||
border << glm::vec2(width, 0);
|
||||
border << glm::vec2(0, 0);
|
||||
geometryCache->updateVertices(_domainStatusBorder, border);
|
||||
geometryCache->updateVertices(_domainStatusBorder, border, color);
|
||||
_previousBorderWidth = width;
|
||||
_previousBorderHeight = height;
|
||||
}
|
||||
|
||||
glColor3f(CONNECTION_STATUS_BORDER_COLOR[0],
|
||||
CONNECTION_STATUS_BORDER_COLOR[1],
|
||||
CONNECTION_STATUS_BORDER_COLOR[2]);
|
||||
glLineWidth(CONNECTION_STATUS_BORDER_LINE_WIDTH);
|
||||
|
||||
geometryCache->renderVertices(GL_LINE_STRIP, _domainStatusBorder);
|
||||
geometryCache->renderVertices(gpu::LINE_STRIP, _domainStatusBorder);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -20,6 +20,8 @@ const float MAGNIFY_WIDTH = 220.0f;
|
|||
const float MAGNIFY_HEIGHT = 100.0f;
|
||||
const float MAGNIFY_MULT = 2.0f;
|
||||
|
||||
const float DEFAULT_OCULUS_UI_ANGULAR_SIZE = 72.0f;
|
||||
|
||||
// Handles the drawing of the overlays to the screen
|
||||
class ApplicationOverlay {
|
||||
public:
|
||||
|
@ -35,6 +37,9 @@ public:
|
|||
QPoint getPalmClickLocation(const PalmData *palm) const;
|
||||
bool calculateRayUICollisionPoint(const glm::vec3& position, const glm::vec3& direction, glm::vec3& result) const;
|
||||
|
||||
float getOculusUIAngularSize() const { return _oculusUIAngularSize; }
|
||||
void setOculusUIAngularSize(float oculusUIAngularSize) { _oculusUIAngularSize = oculusUIAngularSize; }
|
||||
|
||||
// Converter from one frame of reference to another.
|
||||
// Frame of reference:
|
||||
// Screen: Position on the screen (x,y)
|
||||
|
@ -80,6 +85,8 @@ private:
|
|||
VerticesIndices _vbo;
|
||||
};
|
||||
|
||||
float _oculusUIAngularSize = DEFAULT_OCULUS_UI_ANGULAR_SIZE;
|
||||
|
||||
void renderReticle(glm::quat orientation, float alpha);
|
||||
void renderPointers();;
|
||||
void renderMagnifier(glm::vec2 magPos, float sizeMult, bool showBorder);
|
||||
|
|
|
@ -22,8 +22,8 @@
|
|||
#include "AttachmentsDialog.h"
|
||||
#include "MainWindow.h"
|
||||
|
||||
AttachmentsDialog::AttachmentsDialog() :
|
||||
QDialog(Application::getInstance()->getWindow()) {
|
||||
AttachmentsDialog::AttachmentsDialog(QWidget* parent) :
|
||||
QDialog(parent) {
|
||||
|
||||
setWindowTitle("Edit Attachments");
|
||||
setAttribute(Qt::WA_DeleteOnClose);
|
||||
|
|
|
@ -27,8 +27,7 @@ class AttachmentsDialog : public QDialog {
|
|||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
||||
AttachmentsDialog();
|
||||
AttachmentsDialog(QWidget* parent = nullptr);
|
||||
|
||||
virtual void setVisible(bool visible);
|
||||
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
|
||||
#include <cstdio>
|
||||
|
||||
#include "BandwidthRecorder.h"
|
||||
#include "ui/BandwidthDialog.h"
|
||||
|
||||
#include <QFormLayout>
|
||||
|
@ -19,56 +20,73 @@
|
|||
#include <QPalette>
|
||||
#include <QColor>
|
||||
|
||||
BandwidthDialog::BandwidthDialog(QWidget* parent, BandwidthMeter* model) :
|
||||
|
||||
BandwidthDialog::ChannelDisplay::ChannelDisplay(BandwidthRecorder::Channel *ch, QFormLayout* form) {
|
||||
this->ch = ch;
|
||||
this->label = setupLabel(form);
|
||||
}
|
||||
|
||||
|
||||
QLabel* BandwidthDialog::ChannelDisplay::setupLabel(QFormLayout* form) {
|
||||
QLabel* label = new QLabel();
|
||||
|
||||
label->setAlignment(Qt::AlignRight);
|
||||
|
||||
QPalette palette = label->palette();
|
||||
unsigned rgb = ch->colorRGBA >> 8;
|
||||
rgb = ((rgb & 0xfefefeu) >> 1) + ((rgb & 0xf8f8f8) >> 3);
|
||||
palette.setColor(QPalette::WindowText, QColor::fromRgb(rgb));
|
||||
label->setPalette(palette);
|
||||
|
||||
form->addRow((std::string(" ") + ch->caption + " Bandwidth In/Out:").c_str(), label);
|
||||
|
||||
return label;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void BandwidthDialog::ChannelDisplay::setLabelText() {
|
||||
std::string strBuf =
|
||||
std::to_string ((int) (ch->input.getValue() * ch->unitScale)) + "/" +
|
||||
std::to_string ((int) (ch->output.getValue() * ch->unitScale)) + " " + ch->unitCaption;
|
||||
label->setText(strBuf.c_str());
|
||||
}
|
||||
|
||||
|
||||
|
||||
BandwidthDialog::BandwidthDialog(QWidget* parent, BandwidthRecorder* model) :
|
||||
QDialog(parent, Qt::Window | Qt::WindowCloseButtonHint | Qt::WindowStaysOnTopHint),
|
||||
_model(model) {
|
||||
|
||||
char strBuf[64];
|
||||
|
||||
this->setWindowTitle("Bandwidth Details");
|
||||
|
||||
// Create layouter
|
||||
QFormLayout* form = new QFormLayout();
|
||||
this->QDialog::setLayout(form);
|
||||
|
||||
// Setup labels
|
||||
for (size_t i = 0; i < BandwidthMeter::N_STREAMS; ++i) {
|
||||
bool input = i % 2 == 0;
|
||||
BandwidthMeter::ChannelInfo& ch = _model->channelInfo(BandwidthMeter::ChannelIndex(i / 2));
|
||||
QLabel* label = _labels[i] = new QLabel();
|
||||
label->setAlignment(Qt::AlignRight);
|
||||
|
||||
// Set foreground color to 62.5% brightness of the meter (otherwise will be hard to read on the bright background)
|
||||
QPalette palette = label->palette();
|
||||
unsigned rgb = ch.colorRGBA >> 8;
|
||||
rgb = ((rgb & 0xfefefeu) >> 1) + ((rgb & 0xf8f8f8) >> 3);
|
||||
palette.setColor(QPalette::WindowText, QColor::fromRgb(rgb));
|
||||
label->setPalette(palette);
|
||||
|
||||
snprintf(strBuf, sizeof(strBuf), " %s %s Bandwidth:", input ? "Input" : "Output", ch.caption);
|
||||
form->addRow(strBuf, label);
|
||||
}
|
||||
audioChannelDisplay = new ChannelDisplay(_model->audioChannel, form);
|
||||
avatarsChannelDisplay = new ChannelDisplay(_model->avatarsChannel, form);
|
||||
octreeChannelDisplay = new ChannelDisplay(_model->octreeChannel, form);
|
||||
metavoxelsChannelDisplay = new ChannelDisplay(_model->metavoxelsChannel, form);
|
||||
totalChannelDisplay = new ChannelDisplay(_model->totalChannel, form);
|
||||
}
|
||||
|
||||
|
||||
BandwidthDialog::~BandwidthDialog() {
|
||||
for (size_t i = 0; i < BandwidthMeter::N_STREAMS; ++i) {
|
||||
delete _labels[i];
|
||||
}
|
||||
delete audioChannelDisplay;
|
||||
delete avatarsChannelDisplay;
|
||||
delete octreeChannelDisplay;
|
||||
delete metavoxelsChannelDisplay;
|
||||
delete totalChannelDisplay;
|
||||
}
|
||||
|
||||
void BandwidthDialog::paintEvent(QPaintEvent* event) {
|
||||
|
||||
// Update labels
|
||||
char strBuf[64];
|
||||
for (size_t i = 0; i < BandwidthMeter::N_STREAMS; ++i) {
|
||||
BandwidthMeter::ChannelIndex chIdx = BandwidthMeter::ChannelIndex(i / 2);
|
||||
bool input = i % 2 == 0;
|
||||
BandwidthMeter::ChannelInfo& ch = _model->channelInfo(chIdx);
|
||||
BandwidthMeter::Stream& s = input ? _model->inputStream(chIdx) : _model->outputStream(chIdx);
|
||||
QLabel* label = _labels[i];
|
||||
snprintf(strBuf, sizeof(strBuf), "%0.2f %s", s.getValue() * ch.unitScale, ch.unitCaption);
|
||||
label->setText(strBuf);
|
||||
}
|
||||
void BandwidthDialog::paintEvent(QPaintEvent* event) {
|
||||
audioChannelDisplay->setLabelText();
|
||||
avatarsChannelDisplay->setLabelText();
|
||||
octreeChannelDisplay->setLabelText();
|
||||
metavoxelsChannelDisplay->setLabelText();
|
||||
totalChannelDisplay->setLabelText();
|
||||
|
||||
this->QDialog::paintEvent(event);
|
||||
this->setFixedSize(this->width(), this->height());
|
||||
|
|
|
@ -14,17 +14,38 @@
|
|||
|
||||
#include <QDialog>
|
||||
#include <QLabel>
|
||||
#include <QFormLayout>
|
||||
|
||||
#include "BandwidthMeter.h"
|
||||
#include "BandwidthRecorder.h"
|
||||
|
||||
|
||||
class BandwidthDialog : public QDialog {
|
||||
Q_OBJECT
|
||||
public:
|
||||
// Sets up the UI based on the configuration of the BandwidthMeter
|
||||
BandwidthDialog(QWidget* parent, BandwidthMeter* model);
|
||||
// Sets up the UI based on the configuration of the BandwidthRecorder
|
||||
BandwidthDialog(QWidget* parent, BandwidthRecorder* model);
|
||||
~BandwidthDialog();
|
||||
|
||||
class ChannelDisplay {
|
||||
public:
|
||||
ChannelDisplay(BandwidthRecorder::Channel *ch, QFormLayout* form);
|
||||
QLabel* setupLabel(QFormLayout* form);
|
||||
void setLabelText();
|
||||
|
||||
private:
|
||||
BandwidthRecorder::Channel *ch;
|
||||
|
||||
QLabel* label;
|
||||
};
|
||||
|
||||
ChannelDisplay* audioChannelDisplay;
|
||||
ChannelDisplay* avatarsChannelDisplay;
|
||||
ChannelDisplay* octreeChannelDisplay;
|
||||
ChannelDisplay* metavoxelsChannelDisplay;
|
||||
|
||||
// sums of all the other channels
|
||||
ChannelDisplay* totalChannelDisplay;
|
||||
|
||||
signals:
|
||||
|
||||
void closed();
|
||||
|
@ -34,16 +55,13 @@ public slots:
|
|||
void reject();
|
||||
|
||||
protected:
|
||||
|
||||
// State <- data model held by BandwidthMeter
|
||||
void paintEvent(QPaintEvent*);
|
||||
|
||||
// Emits a 'closed' signal when this dialog is closed.
|
||||
void closeEvent(QCloseEvent*);
|
||||
|
||||
private:
|
||||
BandwidthMeter* _model;
|
||||
QLabel* _labels[BandwidthMeter::N_STREAMS];
|
||||
BandwidthRecorder* _model;
|
||||
};
|
||||
|
||||
#endif // hifi_BandwidthDialog_h
|
||||
|
|
|
@ -1,243 +0,0 @@
|
|||
//
|
||||
// BandwidthMeter.cpp
|
||||
// interface/src/ui
|
||||
//
|
||||
// Created by Tobias Schwinger on 6/20/13.
|
||||
// Copyright 2013 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#include <cstdio>
|
||||
|
||||
#include <DependencyManager.h>
|
||||
#include <GeometryCache.h>
|
||||
|
||||
#include "BandwidthMeter.h"
|
||||
#include "InterfaceConfig.h"
|
||||
|
||||
#include "Util.h"
|
||||
|
||||
namespace { // .cpp-local
|
||||
|
||||
int const AREA_WIDTH = -280; // Width of the area used. Aligned to the right when negative.
|
||||
int const AREA_HEIGHT = -40; // Height of the area used. Aligned to the bottom when negative.
|
||||
int const BORDER_DISTANCE_HORIZ = -10; // Distance to edge of screen (use negative value when width is negative).
|
||||
int const BORDER_DISTANCE_VERT = -15; // Distance to edge of screen (use negative value when height is negative).
|
||||
|
||||
int SPACING_VERT_BARS = 2; // Vertical distance between input and output bar
|
||||
int SPACING_RIGHT_CAPTION_IN_OUT = 4; // IN/OUT <--> |######## : |
|
||||
int SPACING_LEFT_CAPTION_UNIT = 4; // |######## : | <--> UNIT
|
||||
int PADDING_HORIZ_VALUE = 2; // |<-->X.XX<:-># |
|
||||
|
||||
unsigned const COLOR_TEXT = 0xedededff; // ^ ^ ^ ^ ^ ^
|
||||
unsigned const COLOR_FRAME = 0xe0e0e0b0; // | | |
|
||||
unsigned const COLOR_INDICATOR = 0xc0c0c0b0; // |
|
||||
|
||||
char const* CAPTION_IN = "In";
|
||||
char const* CAPTION_OUT = "Out";
|
||||
char const* CAPTION_UNIT = "Mbps";
|
||||
|
||||
double const UNIT_SCALE = 8000.0 / (1024.0 * 1024.0); // Bytes/ms -> Mbps
|
||||
int const INITIAL_SCALE_MAXIMUM_INDEX = 250; // / 9: exponent, % 9: mantissa - 2, 0 o--o 2 * 10^-10
|
||||
int const MIN_METER_SCALE = 10; // 10Mbps
|
||||
int const NUMBER_OF_MARKERS = 10;
|
||||
}
|
||||
|
||||
BandwidthMeter::ChannelInfo BandwidthMeter::_CHANNELS[] = {
|
||||
{ "Audio" , "Kbps", 8000.0 / 1024.0, 0x33cc99ff },
|
||||
{ "Avatars" , "Kbps", 8000.0 / 1024.0, 0xffef40c0 },
|
||||
{ "Octree" , "Kbps", 8000.0 / 1024.0, 0xd0d0d0a0 },
|
||||
{ "Metavoxels", "Kbps", 8000.0 / 1024.0, 0xd0d0d0a0 }
|
||||
};
|
||||
|
||||
BandwidthMeter::BandwidthMeter() :
|
||||
_textRenderer(TextRenderer::getInstance(INCONSOLATA_FONT_FAMILY, -1, INCONSOLATA_FONT_WEIGHT, false)),
|
||||
_scaleMaxIndex(INITIAL_SCALE_MAXIMUM_INDEX) {
|
||||
|
||||
_channels = static_cast<ChannelInfo*>( malloc(sizeof(_CHANNELS)) );
|
||||
memcpy(_channels, _CHANNELS, sizeof(_CHANNELS));
|
||||
}
|
||||
|
||||
BandwidthMeter::~BandwidthMeter() {
|
||||
|
||||
free(_channels);
|
||||
}
|
||||
|
||||
BandwidthMeter::Stream::Stream(float msToAverage) : _value(0.0f), _msToAverage(msToAverage) {
|
||||
_prevTime.start();
|
||||
}
|
||||
|
||||
void BandwidthMeter::Stream::updateValue(double amount) {
|
||||
|
||||
// Determine elapsed time
|
||||
double dt = (double)_prevTime.nsecsElapsed() / 1000000.0; // ns to ms
|
||||
|
||||
// Ignore this value when timer imprecision yields dt = 0
|
||||
if (dt == 0.0) {
|
||||
return;
|
||||
}
|
||||
|
||||
_prevTime.start();
|
||||
|
||||
// Compute approximate average
|
||||
_value = glm::mix(_value, amount / dt,
|
||||
glm::clamp(dt / _msToAverage, 0.0, 1.0));
|
||||
}
|
||||
|
||||
void BandwidthMeter::setColorRGBA(unsigned c) {
|
||||
|
||||
glColor4ub(GLubyte( c >> 24),
|
||||
GLubyte((c >> 16) & 0xff),
|
||||
GLubyte((c >> 8) & 0xff),
|
||||
GLubyte( c & 0xff));
|
||||
}
|
||||
|
||||
void BandwidthMeter::renderBox(int x, int y, int w, int h) {
|
||||
DependencyManager::get<GeometryCache>()->renderQuad(x, y, w, h);
|
||||
}
|
||||
|
||||
void BandwidthMeter::renderVerticalLine(int x, int y, int h) {
|
||||
DependencyManager::get<GeometryCache>()->renderLine(glm::vec2(x, y), glm::vec2(x, y + h));
|
||||
}
|
||||
|
||||
inline int BandwidthMeter::centered(int subject, int object) {
|
||||
return (object - subject) / 2;
|
||||
}
|
||||
|
||||
bool BandwidthMeter::isWithinArea(int x, int y, int screenWidth, int screenHeight) {
|
||||
|
||||
int minX = BORDER_DISTANCE_HORIZ + (AREA_WIDTH >= 0 ? 0 : screenWidth + AREA_WIDTH);
|
||||
int minY = BORDER_DISTANCE_VERT + (AREA_HEIGHT >= 0 ? 0 : screenHeight + AREA_HEIGHT);
|
||||
|
||||
return x >= minX && x < minX + glm::abs(AREA_WIDTH) &&
|
||||
y >= minY && y < minY + glm::abs(AREA_HEIGHT);
|
||||
}
|
||||
|
||||
void BandwidthMeter::render(int screenWidth, int screenHeight) {
|
||||
|
||||
int x = BORDER_DISTANCE_HORIZ + (AREA_WIDTH >= 0 ? 0 : screenWidth + AREA_WIDTH);
|
||||
int y = BORDER_DISTANCE_VERT + (AREA_HEIGHT >= 0 ? 0 : screenHeight + AREA_HEIGHT);
|
||||
int w = glm::abs(AREA_WIDTH), h = glm::abs(AREA_HEIGHT);
|
||||
|
||||
// Determine total
|
||||
float totalIn = 0.0f, totalOut = 0.0f;
|
||||
for (size_t i = 0; i < N_CHANNELS; ++i) {
|
||||
|
||||
totalIn += inputStream(ChannelIndex(i)).getValue();
|
||||
totalOut += outputStream(ChannelIndex(i)).getValue();
|
||||
}
|
||||
totalIn *= UNIT_SCALE;
|
||||
totalOut *= UNIT_SCALE;
|
||||
float totalMax = glm::max(totalIn, totalOut);
|
||||
|
||||
// Get font / caption metrics
|
||||
QFontMetrics const& fontMetrics = _textRenderer->metrics();
|
||||
int fontDescent = fontMetrics.descent();
|
||||
int labelWidthIn = fontMetrics.width(CAPTION_IN);
|
||||
int labelWidthOut = fontMetrics.width(CAPTION_OUT);
|
||||
int labelWidthInOut = glm::max(labelWidthIn, labelWidthOut);
|
||||
int labelHeight = fontMetrics.ascent() + fontDescent;
|
||||
int labelWidthUnit = fontMetrics.width(CAPTION_UNIT);
|
||||
int labelsWidth = labelWidthInOut + SPACING_RIGHT_CAPTION_IN_OUT + SPACING_LEFT_CAPTION_UNIT + labelWidthUnit;
|
||||
|
||||
// Calculate coordinates and dimensions
|
||||
int barX = x + labelWidthInOut + SPACING_RIGHT_CAPTION_IN_OUT;
|
||||
int barWidth = w - labelsWidth;
|
||||
int barHeight = (h - SPACING_VERT_BARS) / 2;
|
||||
int textYcenteredLine = h - centered(labelHeight, h) - fontDescent;
|
||||
int textYupperLine = barHeight - centered(labelHeight, barHeight) - fontDescent;
|
||||
int textYlowerLine = h - centered(labelHeight, barHeight) - fontDescent;
|
||||
|
||||
// Center of coordinate system -> upper left of bar
|
||||
glPushMatrix();
|
||||
glTranslatef((float)barX, (float)y, 0.0f);
|
||||
|
||||
// Render captions
|
||||
setColorRGBA(COLOR_TEXT);
|
||||
_textRenderer->draw(barWidth + SPACING_LEFT_CAPTION_UNIT, textYcenteredLine, CAPTION_UNIT);
|
||||
_textRenderer->draw(-labelWidthIn - SPACING_RIGHT_CAPTION_IN_OUT, textYupperLine, CAPTION_IN);
|
||||
_textRenderer->draw(-labelWidthOut - SPACING_RIGHT_CAPTION_IN_OUT, textYlowerLine, CAPTION_OUT);
|
||||
|
||||
// Render vertical lines for the frame
|
||||
setColorRGBA(COLOR_FRAME);
|
||||
renderVerticalLine(0, 0, h);
|
||||
renderVerticalLine(barWidth, 0, h);
|
||||
|
||||
// Adjust scale
|
||||
int steps;
|
||||
double step, scaleMax;
|
||||
bool commit = false;
|
||||
do {
|
||||
steps = (_scaleMaxIndex % 9) + 2;
|
||||
step = pow(10.0, (_scaleMaxIndex / 9) - 10);
|
||||
scaleMax = step * steps;
|
||||
if (commit) {
|
||||
// printLog("Bandwidth meter scale: %d\n", _scaleMaxIndex);
|
||||
break;
|
||||
}
|
||||
if (totalMax < scaleMax * 0.5) {
|
||||
_scaleMaxIndex = glm::max(0, _scaleMaxIndex - 1);
|
||||
commit = true;
|
||||
} else if (totalMax > scaleMax) {
|
||||
_scaleMaxIndex += 1;
|
||||
commit = true;
|
||||
}
|
||||
} while (commit);
|
||||
|
||||
step = scaleMax / NUMBER_OF_MARKERS;
|
||||
if (scaleMax < MIN_METER_SCALE) {
|
||||
scaleMax = MIN_METER_SCALE;
|
||||
}
|
||||
|
||||
// Render scale indicators
|
||||
setColorRGBA(COLOR_INDICATOR);
|
||||
for (int j = NUMBER_OF_MARKERS; --j > 0;) {
|
||||
renderVerticalLine((barWidth * j) / NUMBER_OF_MARKERS, 0, h);
|
||||
}
|
||||
|
||||
// Render bars
|
||||
int xIn = 0, xOut = 0;
|
||||
for (size_t i = 0; i < N_CHANNELS; ++i) {
|
||||
|
||||
ChannelIndex chIdx = ChannelIndex(i);
|
||||
int wIn = (int)(barWidth * inputStream(chIdx).getValue() * UNIT_SCALE / scaleMax);
|
||||
int wOut = (int)(barWidth * outputStream(chIdx).getValue() * UNIT_SCALE / scaleMax);
|
||||
|
||||
setColorRGBA(channelInfo(chIdx).colorRGBA);
|
||||
|
||||
if (wIn > 0) {
|
||||
renderBox(xIn, 0, wIn, barHeight);
|
||||
}
|
||||
xIn += wIn;
|
||||
|
||||
if (wOut > 0) {
|
||||
renderBox(xOut, h - barHeight, wOut, barHeight);
|
||||
}
|
||||
xOut += wOut;
|
||||
}
|
||||
|
||||
// Render numbers
|
||||
char fmtBuf[8];
|
||||
setColorRGBA(COLOR_TEXT);
|
||||
sprintf(fmtBuf, "%0.1f", totalIn);
|
||||
_textRenderer->draw(glm::max(xIn - fontMetrics.width(fmtBuf) - PADDING_HORIZ_VALUE,
|
||||
PADDING_HORIZ_VALUE),
|
||||
textYupperLine, fmtBuf);
|
||||
sprintf(fmtBuf, "%0.1f", totalOut);
|
||||
_textRenderer->draw(glm::max(xOut - fontMetrics.width(fmtBuf) - PADDING_HORIZ_VALUE,
|
||||
PADDING_HORIZ_VALUE),
|
||||
textYlowerLine, fmtBuf);
|
||||
|
||||
glPopMatrix();
|
||||
|
||||
// After rendering, indicate that no data has been sent/received since the last feed.
|
||||
// This way, the meters fall when not continuously fed.
|
||||
for (size_t i = 0; i < N_CHANNELS; ++i) {
|
||||
inputStream(ChannelIndex(i)).updateValue(0);
|
||||
outputStream(ChannelIndex(i)).updateValue(0);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1,87 +0,0 @@
|
|||
//
|
||||
// BandwidthMeter.h
|
||||
// interface/src/ui
|
||||
//
|
||||
// Created by Tobias Schwinger on 6/20/13.
|
||||
// Copyright 2013 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#ifndef hifi_BandwidthMeter_h
|
||||
#define hifi_BandwidthMeter_h
|
||||
|
||||
#include <QElapsedTimer>
|
||||
|
||||
#include <glm/glm.hpp>
|
||||
|
||||
#include <TextRenderer.h>
|
||||
|
||||
|
||||
class BandwidthMeter {
|
||||
|
||||
public:
|
||||
|
||||
BandwidthMeter();
|
||||
~BandwidthMeter();
|
||||
|
||||
void render(int screenWidth, int screenHeight);
|
||||
bool isWithinArea(int x, int y, int screenWidth, int screenHeight);
|
||||
|
||||
// Number of channels / streams.
|
||||
static size_t const N_CHANNELS = 4;
|
||||
static size_t const N_STREAMS = N_CHANNELS * 2;
|
||||
|
||||
// Channel usage.
|
||||
enum ChannelIndex { AUDIO, AVATARS, OCTREE, METAVOXELS };
|
||||
|
||||
// Meta information held for a communication channel (bidirectional).
|
||||
struct ChannelInfo {
|
||||
|
||||
char const* const caption;
|
||||
char const* unitCaption;
|
||||
double unitScale;
|
||||
unsigned colorRGBA;
|
||||
};
|
||||
|
||||
// Representation of a data stream (unidirectional; input or output).
|
||||
class Stream {
|
||||
|
||||
public:
|
||||
|
||||
Stream(float msToAverage = 3000.0f);
|
||||
void updateValue(double amount);
|
||||
double getValue() const { return _value; }
|
||||
|
||||
private:
|
||||
double _value; // Current value.
|
||||
double _msToAverage; // Milliseconds to average.
|
||||
QElapsedTimer _prevTime; // Time of last feed.
|
||||
};
|
||||
|
||||
// Data model accessors
|
||||
Stream& inputStream(ChannelIndex i) { return _streams[i * 2]; }
|
||||
Stream const& inputStream(ChannelIndex i) const { return _streams[i * 2]; }
|
||||
Stream& outputStream(ChannelIndex i) { return _streams[i * 2 + 1]; }
|
||||
Stream const& outputStream(ChannelIndex i) const { return _streams[i * 2 + 1]; }
|
||||
ChannelInfo& channelInfo(ChannelIndex i) { return _channels[i]; }
|
||||
ChannelInfo const& channelInfo(ChannelIndex i) const { return _channels[i]; }
|
||||
|
||||
private:
|
||||
static void setColorRGBA(unsigned c);
|
||||
static void renderBox(int x, int y, int w, int h);
|
||||
static void renderVerticalLine(int x, int y, int h);
|
||||
|
||||
static inline int centered(int subject, int object);
|
||||
|
||||
|
||||
static ChannelInfo _CHANNELS[];
|
||||
|
||||
TextRenderer* _textRenderer;
|
||||
ChannelInfo* _channels;
|
||||
Stream _streams[N_STREAMS];
|
||||
int _scaleMaxIndex;
|
||||
};
|
||||
|
||||
#endif // hifi_BandwidthMeter_h
|
|
@ -22,6 +22,7 @@
|
|||
#include <AddressManager.h>
|
||||
#include <AccountManager.h>
|
||||
#include <PathUtils.h>
|
||||
#include <Settings.h>
|
||||
|
||||
#include "Application.h"
|
||||
#include "ChatMessageArea.h"
|
||||
|
@ -41,6 +42,10 @@ const QRegularExpression regexHifiLinks("([#@]\\S+)");
|
|||
const QString mentionSoundsPath("/mention-sounds/");
|
||||
const QString mentionRegex("@(\\b%1\\b)");
|
||||
|
||||
namespace SettingHandles {
|
||||
const SettingHandle<QDateTime> usernameMentionTimestamp("MentionTimestamp", QDateTime());
|
||||
}
|
||||
|
||||
ChatWindow::ChatWindow(QWidget* parent) :
|
||||
QWidget(parent, Qt::Window | Qt::CustomizeWindowHint | Qt::WindowTitleHint | Qt::WindowMinMaxButtonsHint |
|
||||
Qt::WindowCloseButtonHint),
|
||||
|
@ -377,12 +382,10 @@ void ChatWindow::messageReceived(const QXmppMessage& message) {
|
|||
if (message.body().contains(usernameMention)) {
|
||||
|
||||
// Don't show messages already seen in icon tray at start-up.
|
||||
QSettings* settings = Application::getInstance()->lockSettings();
|
||||
bool showMessage = settings->value("usernameMentionTimestamp").toDateTime() < _lastMessageStamp;
|
||||
bool showMessage = SettingHandles::usernameMentionTimestamp.get() < _lastMessageStamp;
|
||||
if (showMessage) {
|
||||
settings->setValue("usernameMentionTimestamp", _lastMessageStamp);
|
||||
SettingHandles::usernameMentionTimestamp.set(_lastMessageStamp);
|
||||
}
|
||||
Application::getInstance()->unlockSettings();
|
||||
|
||||
if (isHidden() && showMessage) {
|
||||
|
||||
|
|
215
interface/src/ui/DialogsManager.cpp
Normal file
215
interface/src/ui/DialogsManager.cpp
Normal file
|
@ -0,0 +1,215 @@
|
|||
//
|
||||
// DialogsManager.cpp
|
||||
//
|
||||
//
|
||||
// Created by Clement on 1/18/15.
|
||||
// Copyright 2015 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#include <AccountManager.h>
|
||||
#include <MainWindow.h>
|
||||
#include <PathUtils.h>
|
||||
#include <XmppClient.h>
|
||||
|
||||
#include "AddressBarDialog.h"
|
||||
#include "AnimationsDialog.h"
|
||||
#include "AttachmentsDialog.h"
|
||||
#include "BandwidthDialog.h"
|
||||
#include "CachesSizeDialog.h"
|
||||
#include "ChatWindow.h"
|
||||
#include "HMDToolsDialog.h"
|
||||
#include "LodToolsDialog.h"
|
||||
#include "LoginDialog.h"
|
||||
#include "MetavoxelEditor.h"
|
||||
#include "MetavoxelNetworkSimulator.h"
|
||||
#include "OctreeStatsDialog.h"
|
||||
#include "PreferencesDialog.h"
|
||||
#include "ScriptEditorWindow.h"
|
||||
|
||||
#include "DialogsManager.h"
|
||||
|
||||
void DialogsManager::toggleAddressBar() {
|
||||
maybeCreateDialog(_addressBarDialog);
|
||||
|
||||
if (!_addressBarDialog->isVisible()) {
|
||||
_addressBarDialog->show();
|
||||
}
|
||||
}
|
||||
|
||||
void DialogsManager::toggleLoginDialog() {
|
||||
maybeCreateDialog(_loginDialog);
|
||||
_loginDialog->toggleQAction();
|
||||
}
|
||||
|
||||
void DialogsManager::showLoginDialog() {
|
||||
maybeCreateDialog(_loginDialog);
|
||||
_loginDialog->showLoginForCurrentDomain();
|
||||
}
|
||||
|
||||
void DialogsManager::octreeStatsDetails() {
|
||||
if (!_octreeStatsDialog) {
|
||||
_octreeStatsDialog = new OctreeStatsDialog(qApp->getWindow(), qApp->getOcteeSceneStats());
|
||||
|
||||
if (_hmdToolsDialog) {
|
||||
_hmdToolsDialog->watchWindow(_octreeStatsDialog->windowHandle());
|
||||
}
|
||||
connect(_octreeStatsDialog, SIGNAL(closed()), _octreeStatsDialog, SLOT(deleteLater()));
|
||||
_octreeStatsDialog->show();
|
||||
}
|
||||
_octreeStatsDialog->raise();
|
||||
}
|
||||
|
||||
void DialogsManager::cachesSizeDialog() {
|
||||
qDebug() << "Caches size:" << _cachesSizeDialog.isNull();
|
||||
if (!_cachesSizeDialog) {
|
||||
maybeCreateDialog(_cachesSizeDialog);
|
||||
|
||||
connect(_cachesSizeDialog, SIGNAL(closed()), _cachesSizeDialog, SLOT(deleteLater()));
|
||||
_cachesSizeDialog->show();
|
||||
}
|
||||
_cachesSizeDialog->raise();
|
||||
}
|
||||
|
||||
void DialogsManager::editPreferences() {
|
||||
if (!_preferencesDialog) {
|
||||
maybeCreateDialog(_preferencesDialog);
|
||||
_preferencesDialog->show();
|
||||
} else {
|
||||
_preferencesDialog->close();
|
||||
}
|
||||
}
|
||||
|
||||
void DialogsManager::editAttachments() {
|
||||
if (!_attachmentsDialog) {
|
||||
maybeCreateDialog(_attachmentsDialog);
|
||||
_attachmentsDialog->show();
|
||||
} else {
|
||||
_attachmentsDialog->close();
|
||||
}
|
||||
}
|
||||
|
||||
void DialogsManager::editAnimations() {
|
||||
if (!_animationsDialog) {
|
||||
maybeCreateDialog(_animationsDialog);
|
||||
_animationsDialog->show();
|
||||
} else {
|
||||
_animationsDialog->close();
|
||||
}
|
||||
}
|
||||
|
||||
void DialogsManager::bandwidthDetails() {
|
||||
if (! _bandwidthDialog) {
|
||||
_bandwidthDialog = new BandwidthDialog(qApp->getWindow(), qApp->getBandwidthRecorder());
|
||||
connect(_bandwidthDialog, SIGNAL(closed()), _bandwidthDialog, SLOT(deleteLater()));
|
||||
|
||||
if (_hmdToolsDialog) {
|
||||
_hmdToolsDialog->watchWindow(_bandwidthDialog->windowHandle());
|
||||
}
|
||||
|
||||
_bandwidthDialog->show();
|
||||
}
|
||||
_bandwidthDialog->raise();
|
||||
}
|
||||
|
||||
void DialogsManager::lodTools() {
|
||||
if (!_lodToolsDialog) {
|
||||
maybeCreateDialog(_lodToolsDialog);
|
||||
|
||||
connect(_lodToolsDialog, SIGNAL(closed()), _lodToolsDialog, SLOT(deleteLater()));
|
||||
_lodToolsDialog->show();
|
||||
}
|
||||
_lodToolsDialog->raise();
|
||||
}
|
||||
|
||||
void DialogsManager::toggleToolWindow() {
|
||||
QMainWindow* toolWindow = qApp->getToolWindow();
|
||||
toolWindow->setVisible(!toolWindow->isVisible());
|
||||
}
|
||||
|
||||
void DialogsManager::hmdTools(bool showTools) {
|
||||
if (showTools) {
|
||||
if (!_hmdToolsDialog) {
|
||||
maybeCreateDialog(_hmdToolsDialog);
|
||||
connect(_hmdToolsDialog, SIGNAL(closed()), SLOT(hmdToolsClosed()));
|
||||
}
|
||||
_hmdToolsDialog->show();
|
||||
_hmdToolsDialog->raise();
|
||||
} else {
|
||||
hmdToolsClosed();
|
||||
}
|
||||
qApp->getWindow()->activateWindow();
|
||||
}
|
||||
|
||||
void DialogsManager::hmdToolsClosed() {
|
||||
Menu::getInstance()->getActionForOption(MenuOption::HMDTools)->setChecked(false);
|
||||
_hmdToolsDialog->hide();
|
||||
}
|
||||
|
||||
void DialogsManager::showMetavoxelEditor() {
|
||||
maybeCreateDialog(_metavoxelEditor);
|
||||
_metavoxelEditor->raise();
|
||||
}
|
||||
|
||||
void DialogsManager::showMetavoxelNetworkSimulator() {
|
||||
maybeCreateDialog(_metavoxelNetworkSimulator);
|
||||
_metavoxelNetworkSimulator->raise();
|
||||
}
|
||||
|
||||
void DialogsManager::showScriptEditor() {
|
||||
maybeCreateDialog(_scriptEditor);
|
||||
_scriptEditor->raise();
|
||||
}
|
||||
|
||||
void DialogsManager::setupChat() {
|
||||
#ifdef HAVE_QXMPP
|
||||
const QXmppClient& xmppClient = XmppClient::getInstance().getXMPPClient();
|
||||
connect(&xmppClient, &QXmppClient::connected, this, &DialogsManager::toggleChat);
|
||||
connect(&xmppClient, &QXmppClient::disconnected, this, &DialogsManager::toggleChat);
|
||||
|
||||
QDir::setCurrent(PathUtils::resourcesPath());
|
||||
// init chat window to listen chat
|
||||
maybeCreateDialog(_chatWindow);
|
||||
#endif
|
||||
}
|
||||
|
||||
void DialogsManager::showChat() {
|
||||
if (AccountManager::getInstance().isLoggedIn()) {
|
||||
maybeCreateDialog(_chatWindow);
|
||||
|
||||
if (_chatWindow->isHidden()) {
|
||||
_chatWindow->show();
|
||||
}
|
||||
_chatWindow->raise();
|
||||
_chatWindow->activateWindow();
|
||||
_chatWindow->setFocus();
|
||||
} else {
|
||||
qApp->getTrayIcon()->showMessage("Interface",
|
||||
"You need to login to be able to chat with others on this domain.");
|
||||
}
|
||||
}
|
||||
|
||||
void DialogsManager::toggleChat() {
|
||||
#ifdef HAVE_QXMPP
|
||||
QAction* chatAction = Menu::getInstance()->getActionForOption(MenuOption::Login);
|
||||
Q_CHECK_PTR(chatAction);
|
||||
|
||||
chatAction->setEnabled(XmppClient::getInstance().getXMPPClient().isConnected());
|
||||
if (!chatAction->isEnabled() && _chatWindow && AccountManager::getInstance().isLoggedIn()) {
|
||||
if (_chatWindow->isHidden()) {
|
||||
_chatWindow->show();
|
||||
_chatWindow->raise();
|
||||
_chatWindow->activateWindow();
|
||||
_chatWindow->setFocus();
|
||||
} else {
|
||||
_chatWindow->hide();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
105
interface/src/ui/DialogsManager.h
Normal file
105
interface/src/ui/DialogsManager.h
Normal file
|
@ -0,0 +1,105 @@
|
|||
//
|
||||
// DialogsManager.h
|
||||
//
|
||||
//
|
||||
// Created by Clement on 1/18/15.
|
||||
// Copyright 2015 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#ifndef hifi_DialogsManager_h
|
||||
#define hifi_DialogsManager_h
|
||||
|
||||
#include <QPointer>
|
||||
|
||||
#include <Application.h>
|
||||
#include <DependencyManager.h>
|
||||
|
||||
#include "HMDToolsDialog.h"
|
||||
|
||||
class QAction;
|
||||
|
||||
class AddressBarDialog;
|
||||
class AnimationsDialog;
|
||||
class AttachmentsDialog;
|
||||
class CachesSizeDialog;
|
||||
class ChatWindow;
|
||||
class BandwidthDialog;
|
||||
class LodToolsDialog;
|
||||
class LoginDialog;
|
||||
class MetavoxelEditor;
|
||||
class MetavoxelNetworkSimulator;
|
||||
class OctreeStatsDialog;
|
||||
class PreferencesDialog;
|
||||
class ScriptEditorWindow;
|
||||
|
||||
class DialogsManager : public QObject, public Dependency {
|
||||
Q_OBJECT
|
||||
SINGLETON_DEPENDENCY
|
||||
|
||||
public:
|
||||
QPointer<BandwidthDialog> getBandwidthDialog() const { return _bandwidthDialog; }
|
||||
QPointer<HMDToolsDialog> getHMDToolsDialog() const { return _hmdToolsDialog; }
|
||||
QPointer<LodToolsDialog> getLodToolsDialog() const { return _lodToolsDialog; }
|
||||
QPointer<OctreeStatsDialog> getOctreeStatsDialog() const { return _octreeStatsDialog; }
|
||||
|
||||
void setupChat();
|
||||
|
||||
public slots:
|
||||
void toggleAddressBar();
|
||||
void toggleLoginDialog();
|
||||
void showLoginDialog();
|
||||
void octreeStatsDetails();
|
||||
void cachesSizeDialog();
|
||||
void editPreferences();
|
||||
void editAttachments();
|
||||
void editAnimations();
|
||||
void bandwidthDetails();
|
||||
void lodTools();
|
||||
void hmdTools(bool showTools);
|
||||
void showMetavoxelEditor();
|
||||
void showMetavoxelNetworkSimulator();
|
||||
void showScriptEditor();
|
||||
void showChat();
|
||||
|
||||
private slots:
|
||||
void toggleToolWindow();
|
||||
void hmdToolsClosed();
|
||||
void toggleChat();
|
||||
|
||||
private:
|
||||
DialogsManager() {}
|
||||
|
||||
template<typename T>
|
||||
void maybeCreateDialog(QPointer<T>& member) {
|
||||
if (!member) {
|
||||
MainWindow* parent = qApp->getWindow();
|
||||
Q_CHECK_PTR(parent);
|
||||
member = new T(parent);
|
||||
Q_CHECK_PTR(member);
|
||||
|
||||
if (_hmdToolsDialog) {
|
||||
_hmdToolsDialog->watchWindow(member->windowHandle());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
QPointer<AddressBarDialog> _addressBarDialog;
|
||||
QPointer<AnimationsDialog> _animationsDialog;
|
||||
QPointer<AttachmentsDialog> _attachmentsDialog;
|
||||
QPointer<BandwidthDialog> _bandwidthDialog;
|
||||
QPointer<CachesSizeDialog> _cachesSizeDialog;
|
||||
QPointer<ChatWindow> _chatWindow;
|
||||
QPointer<HMDToolsDialog> _hmdToolsDialog;
|
||||
QPointer<LodToolsDialog> _lodToolsDialog;
|
||||
QPointer<LoginDialog> _loginDialog;
|
||||
QPointer<MetavoxelEditor> _metavoxelEditor;
|
||||
QPointer<MetavoxelNetworkSimulator> _metavoxelNetworkSimulator;
|
||||
QPointer<OctreeStatsDialog> _octreeStatsDialog;
|
||||
QPointer<PreferencesDialog> _preferencesDialog;
|
||||
QPointer<ScriptEditorWindow> _scriptEditor;
|
||||
};
|
||||
|
||||
#endif // hifi_DialogsManager_h
|
|
@ -19,11 +19,13 @@
|
|||
#include <QScreen>
|
||||
#include <QWindow>
|
||||
|
||||
|
||||
#include "MainWindow.h"
|
||||
#include "Menu.h"
|
||||
#include "devices/OculusManager.h"
|
||||
#include "ui/DialogsManager.h"
|
||||
#include "ui/HMDToolsDialog.h"
|
||||
|
||||
#include "devices/OculusManager.h"
|
||||
|
||||
HMDToolsDialog::HMDToolsDialog(QWidget* parent) :
|
||||
QDialog(parent, Qt::Window | Qt::WindowCloseButtonHint | Qt::WindowStaysOnTopHint) ,
|
||||
|
@ -67,20 +69,21 @@ HMDToolsDialog::HMDToolsDialog(QWidget* parent) :
|
|||
// watch for our dialog window moving screens. If it does we want to enforce our rules about
|
||||
// what screens we're allowed on
|
||||
watchWindow(windowHandle());
|
||||
auto dialogsManager = DependencyManager::get<DialogsManager>();
|
||||
if (Application::getInstance()->getRunningScriptsWidget()) {
|
||||
watchWindow(Application::getInstance()->getRunningScriptsWidget()->windowHandle());
|
||||
}
|
||||
if (Application::getInstance()->getToolWindow()) {
|
||||
watchWindow(Application::getInstance()->getToolWindow()->windowHandle());
|
||||
}
|
||||
if (Menu::getInstance()->getBandwidthDialog()) {
|
||||
watchWindow(Menu::getInstance()->getBandwidthDialog()->windowHandle());
|
||||
if (dialogsManager->getBandwidthDialog()) {
|
||||
watchWindow(dialogsManager->getBandwidthDialog()->windowHandle());
|
||||
}
|
||||
if (Menu::getInstance()->getOctreeStatsDialog()) {
|
||||
watchWindow(Menu::getInstance()->getOctreeStatsDialog()->windowHandle());
|
||||
if (dialogsManager->getOctreeStatsDialog()) {
|
||||
watchWindow(dialogsManager->getOctreeStatsDialog()->windowHandle());
|
||||
}
|
||||
if (Menu::getInstance()->getLodToolsDialog()) {
|
||||
watchWindow(Menu::getInstance()->getLodToolsDialog()->windowHandle());
|
||||
if (dialogsManager->getLodToolsDialog()) {
|
||||
watchWindow(dialogsManager->getLodToolsDialog()->windowHandle());
|
||||
}
|
||||
|
||||
// when the application is about to quit, leave HDM mode
|
||||
|
|
|
@ -10,18 +10,21 @@
|
|||
//
|
||||
|
||||
#include <QApplication>
|
||||
|
||||
#include <QDesktopWidget>
|
||||
#include <QFileInfo>
|
||||
#include <QtWebKitWidgets/QWebFrame>
|
||||
#include <QtWebKit/QWebElement>
|
||||
#include <QDesktopWidget>
|
||||
|
||||
#include <PathUtils.h>
|
||||
#include <Settings.h>
|
||||
|
||||
#include "Application.h"
|
||||
#include "InfoView.h"
|
||||
|
||||
#define SETTINGS_VERSION_KEY "info-version"
|
||||
#define MAX_DIALOG_HEIGHT_RATIO 0.9
|
||||
static const float MAX_DIALOG_HEIGHT_RATIO = 0.9f;
|
||||
|
||||
namespace SettingHandles {
|
||||
const SettingHandle<QString> infoVersion("info-version", QString());
|
||||
}
|
||||
|
||||
InfoView::InfoView(bool forced, QString path) :
|
||||
_forced(forced)
|
||||
|
@ -49,20 +52,17 @@ bool InfoView::shouldShow() {
|
|||
return true;
|
||||
}
|
||||
|
||||
QSettings* settings = Application::getInstance()->lockSettings();
|
||||
|
||||
QString lastVersion = settings->value(SETTINGS_VERSION_KEY).toString();
|
||||
QString lastVersion = SettingHandles::infoVersion.get();
|
||||
|
||||
QWebElement versionTag = page()->mainFrame()->findFirstElement("#version");
|
||||
QString version = versionTag.attribute("value");
|
||||
|
||||
if (version != QString::null && (lastVersion == QString::null || lastVersion != version)) {
|
||||
settings->setValue(SETTINGS_VERSION_KEY, version);
|
||||
SettingHandles::infoVersion.set(version);
|
||||
shouldShow = true;
|
||||
} else {
|
||||
shouldShow = false;
|
||||
}
|
||||
Application::getInstance()->unlockSettings();
|
||||
return shouldShow;
|
||||
}
|
||||
|
||||
|
@ -72,7 +72,7 @@ void InfoView::loaded(bool ok) {
|
|||
return;
|
||||
}
|
||||
|
||||
QDesktopWidget* desktop = Application::getInstance()->desktop();
|
||||
QDesktopWidget* desktop = qApp->desktop();
|
||||
QWebFrame* mainFrame = page()->mainFrame();
|
||||
|
||||
int height = mainFrame->contentsSize().height() > desktop->height() ?
|
||||
|
|
|
@ -9,17 +9,19 @@
|
|||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#include <QFormLayout>
|
||||
#include <QDialogButtonBox>
|
||||
|
||||
#include <QPalette>
|
||||
#include <QCheckBox>
|
||||
#include <QColor>
|
||||
#include <QDialogButtonBox>
|
||||
#include <QDoubleSpinBox>
|
||||
#include <QSlider>
|
||||
#include <QFormLayout>
|
||||
#include <QLabel>
|
||||
#include <QPalette>
|
||||
#include <QPushButton>
|
||||
#include <QSlider>
|
||||
#include <QString>
|
||||
|
||||
#include <LODManager.h>
|
||||
|
||||
#include "Menu.h"
|
||||
#include "ui/LodToolsDialog.h"
|
||||
|
||||
|
@ -28,6 +30,7 @@ LodToolsDialog::LodToolsDialog(QWidget* parent) :
|
|||
QDialog(parent, Qt::Window | Qt::WindowCloseButtonHint | Qt::WindowStaysOnTopHint)
|
||||
{
|
||||
this->setWindowTitle("LOD Tools");
|
||||
auto lodManager = DependencyManager::get<LODManager>();
|
||||
|
||||
// Create layouter
|
||||
QFormLayout* form = new QFormLayout(this);
|
||||
|
@ -45,7 +48,7 @@ LodToolsDialog::LodToolsDialog(QWidget* parent) :
|
|||
_lodSize->setTickPosition(QSlider::TicksBelow);
|
||||
_lodSize->setFixedWidth(SLIDER_WIDTH);
|
||||
_lodSize->setPageStep(PAGE_STEP_LOD_SIZE);
|
||||
int sliderValue = Menu::getInstance()->getOctreeSizeScale() / TREE_SCALE;
|
||||
int sliderValue = lodManager->getOctreeSizeScale() / TREE_SCALE;
|
||||
_lodSize->setValue(sliderValue);
|
||||
form->addRow("LOD Size Scale:", _lodSize);
|
||||
connect(_lodSize,SIGNAL(valueChanged(int)),this,SLOT(sizeScaleValueChanged(int)));
|
||||
|
@ -60,7 +63,7 @@ LodToolsDialog::LodToolsDialog(QWidget* parent) :
|
|||
_boundaryLevelAdjust->setTickInterval(STEP_ADJUST);
|
||||
_boundaryLevelAdjust->setTickPosition(QSlider::TicksBelow);
|
||||
_boundaryLevelAdjust->setFixedWidth(SLIDER_WIDTH);
|
||||
sliderValue = Menu::getInstance()->getBoundaryLevelAdjust();
|
||||
sliderValue = lodManager->getBoundaryLevelAdjust();
|
||||
_boundaryLevelAdjust->setValue(sliderValue);
|
||||
form->addRow("Boundary Level Adjust:", _boundaryLevelAdjust);
|
||||
connect(_boundaryLevelAdjust,SIGNAL(valueChanged(int)),this,SLOT(boundaryLevelValueChanged(int)));
|
||||
|
@ -71,22 +74,22 @@ LodToolsDialog::LodToolsDialog(QWidget* parent) :
|
|||
const unsigned redish = 0xfff00000;
|
||||
palette.setColor(QPalette::WindowText, QColor::fromRgb(redish));
|
||||
_feedback->setPalette(palette);
|
||||
_feedback->setText(Menu::getInstance()->getLODFeedbackText());
|
||||
_feedback->setText(lodManager->getLODFeedbackText());
|
||||
const int FEEDBACK_WIDTH = 350;
|
||||
_feedback->setFixedWidth(FEEDBACK_WIDTH);
|
||||
form->addRow("You can see... ", _feedback);
|
||||
|
||||
|
||||
form->addRow("Automatic Avatar LOD Adjustment:", _automaticAvatarLOD = new QCheckBox(this));
|
||||
_automaticAvatarLOD->setChecked(Menu::getInstance()->getAutomaticAvatarLOD());
|
||||
_automaticAvatarLOD->setChecked(lodManager->getAutomaticAvatarLOD());
|
||||
connect(_automaticAvatarLOD, SIGNAL(toggled(bool)), SLOT(updateAvatarLODControls()));
|
||||
|
||||
form->addRow("Decrease Avatar LOD Below FPS:", _avatarLODDecreaseFPS = new QDoubleSpinBox(this));
|
||||
_avatarLODDecreaseFPS->setValue(Menu::getInstance()->getAvatarLODDecreaseFPS());
|
||||
_avatarLODDecreaseFPS->setValue(lodManager->getAvatarLODDecreaseFPS());
|
||||
_avatarLODDecreaseFPS->setDecimals(0);
|
||||
connect(_avatarLODDecreaseFPS, SIGNAL(valueChanged(double)), SLOT(updateAvatarLODValues()));
|
||||
|
||||
form->addRow("Increase Avatar LOD Above FPS:", _avatarLODIncreaseFPS = new QDoubleSpinBox(this));
|
||||
_avatarLODIncreaseFPS->setValue(Menu::getInstance()->getAvatarLODIncreaseFPS());
|
||||
_avatarLODIncreaseFPS->setValue(lodManager->getAvatarLODIncreaseFPS());
|
||||
_avatarLODIncreaseFPS->setDecimals(0);
|
||||
connect(_avatarLODIncreaseFPS, SIGNAL(valueChanged(double)), SLOT(updateAvatarLODValues()));
|
||||
|
||||
|
@ -94,7 +97,7 @@ LodToolsDialog::LodToolsDialog(QWidget* parent) :
|
|||
_avatarLOD->setDecimals(3);
|
||||
_avatarLOD->setRange(1.0 / MAXIMUM_AVATAR_LOD_DISTANCE_MULTIPLIER, 1.0 / MINIMUM_AVATAR_LOD_DISTANCE_MULTIPLIER);
|
||||
_avatarLOD->setSingleStep(0.001);
|
||||
_avatarLOD->setValue(1.0 / Menu::getInstance()->getAvatarLODDistanceMultiplier());
|
||||
_avatarLOD->setValue(1.0 / lodManager->getAvatarLODDistanceMultiplier());
|
||||
connect(_avatarLOD, SIGNAL(valueChanged(double)), SLOT(updateAvatarLODValues()));
|
||||
|
||||
// Add a button to reset
|
||||
|
@ -108,15 +111,17 @@ LodToolsDialog::LodToolsDialog(QWidget* parent) :
|
|||
}
|
||||
|
||||
void LodToolsDialog::reloadSliders() {
|
||||
_lodSize->setValue(Menu::getInstance()->getOctreeSizeScale() / TREE_SCALE);
|
||||
_boundaryLevelAdjust->setValue(Menu::getInstance()->getBoundaryLevelAdjust());
|
||||
_feedback->setText(Menu::getInstance()->getLODFeedbackText());
|
||||
auto lodManager = DependencyManager::get<LODManager>();
|
||||
_lodSize->setValue(lodManager->getOctreeSizeScale() / TREE_SCALE);
|
||||
_boundaryLevelAdjust->setValue(lodManager->getBoundaryLevelAdjust());
|
||||
_feedback->setText(lodManager->getLODFeedbackText());
|
||||
}
|
||||
|
||||
void LodToolsDialog::updateAvatarLODControls() {
|
||||
QFormLayout* form = static_cast<QFormLayout*>(layout());
|
||||
|
||||
Menu::getInstance()->setAutomaticAvatarLOD(_automaticAvatarLOD->isChecked());
|
||||
auto lodManager = DependencyManager::get<LODManager>();
|
||||
lodManager->setAutomaticAvatarLOD(_automaticAvatarLOD->isChecked());
|
||||
|
||||
_avatarLODDecreaseFPS->setVisible(_automaticAvatarLOD->isChecked());
|
||||
form->labelForField(_avatarLODDecreaseFPS)->setVisible(_automaticAvatarLOD->isChecked());
|
||||
|
@ -128,7 +133,7 @@ void LodToolsDialog::updateAvatarLODControls() {
|
|||
form->labelForField(_avatarLOD)->setVisible(!_automaticAvatarLOD->isChecked());
|
||||
|
||||
if (!_automaticAvatarLOD->isChecked()) {
|
||||
_avatarLOD->setValue(1.0 / Menu::getInstance()->getAvatarLODDistanceMultiplier());
|
||||
_avatarLOD->setValue(1.0 / lodManager->getAvatarLODDistanceMultiplier());
|
||||
}
|
||||
|
||||
if (isVisible()) {
|
||||
|
@ -137,25 +142,28 @@ void LodToolsDialog::updateAvatarLODControls() {
|
|||
}
|
||||
|
||||
void LodToolsDialog::updateAvatarLODValues() {
|
||||
auto lodManager = DependencyManager::get<LODManager>();
|
||||
if (_automaticAvatarLOD->isChecked()) {
|
||||
Menu::getInstance()->setAvatarLODDecreaseFPS(_avatarLODDecreaseFPS->value());
|
||||
Menu::getInstance()->setAvatarLODIncreaseFPS(_avatarLODIncreaseFPS->value());
|
||||
lodManager->setAvatarLODDecreaseFPS(_avatarLODDecreaseFPS->value());
|
||||
lodManager->setAvatarLODIncreaseFPS(_avatarLODIncreaseFPS->value());
|
||||
|
||||
} else {
|
||||
Menu::getInstance()->setAvatarLODDistanceMultiplier(1.0 / _avatarLOD->value());
|
||||
lodManager->setAvatarLODDistanceMultiplier(1.0 / _avatarLOD->value());
|
||||
}
|
||||
}
|
||||
|
||||
void LodToolsDialog::sizeScaleValueChanged(int value) {
|
||||
auto lodManager = DependencyManager::get<LODManager>();
|
||||
float realValue = value * TREE_SCALE;
|
||||
Menu::getInstance()->setOctreeSizeScale(realValue);
|
||||
lodManager->setOctreeSizeScale(realValue);
|
||||
|
||||
_feedback->setText(Menu::getInstance()->getLODFeedbackText());
|
||||
_feedback->setText(lodManager->getLODFeedbackText());
|
||||
}
|
||||
|
||||
void LodToolsDialog::boundaryLevelValueChanged(int value) {
|
||||
Menu::getInstance()->setBoundaryLevelAdjust(value);
|
||||
_feedback->setText(Menu::getInstance()->getLODFeedbackText());
|
||||
auto lodManager = DependencyManager::get<LODManager>();
|
||||
lodManager->setBoundaryLevelAdjust(value);
|
||||
_feedback->setText(lodManager->getLODFeedbackText());
|
||||
}
|
||||
|
||||
void LodToolsDialog::resetClicked(bool checked) {
|
||||
|
|
|
@ -29,12 +29,9 @@ LoginDialog::LoginDialog(QWidget* parent) :
|
|||
_ui(new Ui::LoginDialog) {
|
||||
|
||||
_ui->setupUi(this);
|
||||
_ui->errorLabel->hide();
|
||||
_ui->emailLineEdit->setFocus();
|
||||
_ui->logoLabel->setPixmap(QPixmap(PathUtils::resourcesPath() + "images/hifi-logo.svg"));
|
||||
_ui->loginButton->setIcon(QIcon(PathUtils::resourcesPath() + "images/login.svg"));
|
||||
_ui->infoLabel->setVisible(false);
|
||||
_ui->errorLabel->setVisible(false);
|
||||
reset();
|
||||
|
||||
setAttribute(Qt::WA_DeleteOnClose, false);
|
||||
|
||||
connect(&AccountManager::getInstance(), &AccountManager::loginComplete,
|
||||
this, &LoginDialog::handleLoginCompleted);
|
||||
|
@ -50,9 +47,21 @@ LoginDialog::~LoginDialog() {
|
|||
delete _ui;
|
||||
};
|
||||
|
||||
void LoginDialog::handleLoginCompleted(const QUrl& authURL) {
|
||||
void LoginDialog::reset() {
|
||||
_ui->errorLabel->hide();
|
||||
_ui->emailLineEdit->setFocus();
|
||||
_ui->logoLabel->setPixmap(QPixmap(PathUtils::resourcesPath() + "images/hifi-logo.svg"));
|
||||
_ui->loginButton->setIcon(QIcon(PathUtils::resourcesPath() + "images/login.svg"));
|
||||
_ui->infoLabel->setVisible(false);
|
||||
_ui->errorLabel->setVisible(false);
|
||||
|
||||
_ui->emailLineEdit->setText("");
|
||||
_ui->passwordLineEdit->setText("");
|
||||
_ui->loginArea->setDisabled(false);
|
||||
}
|
||||
|
||||
void LoginDialog::handleLoginCompleted(const QUrl& authURL) {
|
||||
reset();
|
||||
close();
|
||||
};
|
||||
|
||||
|
@ -87,3 +96,27 @@ void LoginDialog::moveEvent(QMoveEvent* event) {
|
|||
// Modal dialogs seemed to get repositioned automatically. Combat this by moving the window if needed.
|
||||
resizeAndPosition();
|
||||
};
|
||||
|
||||
|
||||
void LoginDialog::toggleQAction() {
|
||||
AccountManager& accountManager = AccountManager::getInstance();
|
||||
QAction* loginAction = Menu::getInstance()->getActionForOption(MenuOption::Login);
|
||||
Q_CHECK_PTR(loginAction);
|
||||
|
||||
disconnect(loginAction, 0, 0, 0);
|
||||
|
||||
if (accountManager.isLoggedIn()) {
|
||||
// change the menu item to logout
|
||||
loginAction->setText("Logout " + accountManager.getAccountInfo().getUsername());
|
||||
connect(loginAction, &QAction::triggered, &accountManager, &AccountManager::logout);
|
||||
} else {
|
||||
// change the menu item to login
|
||||
loginAction->setText("Login");
|
||||
connect(loginAction, &QAction::triggered, this, &LoginDialog::showLoginForCurrentDomain);
|
||||
}
|
||||
}
|
||||
|
||||
void LoginDialog::showLoginForCurrentDomain() {
|
||||
show();
|
||||
resizeAndPosition(false);
|
||||
}
|
||||
|
|
|
@ -27,6 +27,11 @@ public:
|
|||
~LoginDialog();
|
||||
|
||||
public slots:
|
||||
void toggleQAction();
|
||||
void showLoginForCurrentDomain();
|
||||
|
||||
protected slots:
|
||||
void reset();
|
||||
void handleLoginClicked();
|
||||
void handleLoginCompleted(const QUrl& authURL);
|
||||
void handleLoginFailed();
|
||||
|
@ -35,8 +40,7 @@ protected:
|
|||
void moveEvent(QMoveEvent* event);
|
||||
|
||||
private:
|
||||
Ui::LoginDialog* _ui;
|
||||
|
||||
Ui::LoginDialog* _ui = nullptr;
|
||||
};
|
||||
|
||||
#endif // hifi_LoginDialog_h
|
||||
|
|
|
@ -50,8 +50,8 @@ enum GridPlane {
|
|||
|
||||
const glm::vec2 INVALID_VECTOR(FLT_MAX, FLT_MAX);
|
||||
|
||||
MetavoxelEditor::MetavoxelEditor() :
|
||||
QWidget(Application::getInstance()->getWindow(), Qt::Tool) {
|
||||
MetavoxelEditor::MetavoxelEditor(QWidget* parent) :
|
||||
QWidget(parent, Qt::Tool) {
|
||||
|
||||
setWindowTitle("Metavoxel Editor");
|
||||
setAttribute(Qt::WA_DeleteOnClose);
|
||||
|
@ -356,11 +356,9 @@ void MetavoxelEditor::render() {
|
|||
float scale = GRID_DIVISIONS * spacing;
|
||||
glScalef(scale, scale, scale);
|
||||
|
||||
glColor3f(GRID_BRIGHTNESS, GRID_BRIGHTNESS, GRID_BRIGHTNESS);
|
||||
|
||||
_gridProgram.bind();
|
||||
|
||||
DependencyManager::get<GeometryCache>()->renderGrid(GRID_DIVISIONS, GRID_DIVISIONS);
|
||||
DependencyManager::get<GeometryCache>()->renderGrid(GRID_DIVISIONS, GRID_DIVISIONS, glm::vec4(GRID_BRIGHTNESS, GRID_BRIGHTNESS, GRID_BRIGHTNESS, 1.0f));
|
||||
|
||||
_gridProgram.release();
|
||||
|
||||
|
@ -492,17 +490,17 @@ void BoxTool::render() {
|
|||
if (_state != HOVERING_STATE) {
|
||||
const float BOX_ALPHA = 0.25f;
|
||||
QColor color = getColor();
|
||||
glm::vec4 cubeColor;
|
||||
if (color.isValid()) {
|
||||
glColor4f(color.redF(), color.greenF(), color.blueF(), BOX_ALPHA);
|
||||
cubeColor = glm::vec4(color.redF(), color.greenF(), color.blueF(), BOX_ALPHA);
|
||||
} else {
|
||||
glColor4f(GRID_BRIGHTNESS, GRID_BRIGHTNESS, GRID_BRIGHTNESS, BOX_ALPHA);
|
||||
cubeColor = glm::vec4(GRID_BRIGHTNESS, GRID_BRIGHTNESS, GRID_BRIGHTNESS, BOX_ALPHA);
|
||||
}
|
||||
glEnable(GL_CULL_FACE);
|
||||
DependencyManager::get<GeometryCache>()->renderSolidCube(1.0f);
|
||||
DependencyManager::get<GeometryCache>()->renderSolidCube(1.0f, cubeColor);
|
||||
glDisable(GL_CULL_FACE);
|
||||
}
|
||||
glColor3f(GRID_BRIGHTNESS, GRID_BRIGHTNESS, GRID_BRIGHTNESS);
|
||||
DependencyManager::get<GeometryCache>()->renderWireCube(1.0f);
|
||||
DependencyManager::get<GeometryCache>()->renderWireCube(1.0f, glm::vec4(GRID_BRIGHTNESS, GRID_BRIGHTNESS, GRID_BRIGHTNESS, 1.0f));
|
||||
glPopMatrix();
|
||||
}
|
||||
|
||||
|
@ -822,6 +820,12 @@ HeightfieldBrushTool::HeightfieldBrushTool(MetavoxelEditor* editor, const QStrin
|
|||
_radius->setSingleStep(0.01);
|
||||
_radius->setMaximum(FLT_MAX);
|
||||
_radius->setValue(5.0);
|
||||
|
||||
_form->addRow("Granularity:", _granularity = new QDoubleSpinBox());
|
||||
_granularity->setMinimum(-FLT_MAX);
|
||||
_granularity->setMaximum(FLT_MAX);
|
||||
_granularity->setPrefix("2^");
|
||||
_granularity->setValue(8.0);
|
||||
}
|
||||
|
||||
bool HeightfieldBrushTool::appliesTo(const AttributePointer& attribute) const {
|
||||
|
@ -851,7 +855,7 @@ bool HeightfieldBrushTool::eventFilter(QObject* watched, QEvent* event) {
|
|||
if (event->type() == QEvent::Wheel) {
|
||||
float angle = static_cast<QWheelEvent*>(event)->angleDelta().y();
|
||||
const float ANGLE_SCALE = 1.0f / 1000.0f;
|
||||
_radius->setValue(_radius->value() * glm::pow(2.0f, angle * ANGLE_SCALE));
|
||||
_radius->setValue(_radius->value() * pow(2.0f, angle * ANGLE_SCALE));
|
||||
return true;
|
||||
|
||||
} else if (event->type() == QEvent::MouseButtonPress && _positionValid) {
|
||||
|
@ -881,7 +885,7 @@ QVariant HeightfieldHeightBrushTool::createEdit(bool alternate) {
|
|||
const int ERASE_MODE_INDEX = 2;
|
||||
return QVariant::fromValue(PaintHeightfieldHeightEdit(_position, _radius->value(),
|
||||
alternate ? -_height->value() : _height->value(), _mode->currentIndex() == SET_MODE_INDEX,
|
||||
_mode->currentIndex() == ERASE_MODE_INDEX));
|
||||
_mode->currentIndex() == ERASE_MODE_INDEX, pow(2.0f, _granularity->value())));
|
||||
}
|
||||
|
||||
MaterialControl::MaterialControl(QWidget* widget, QFormLayout* form, bool clearable) :
|
||||
|
@ -956,10 +960,11 @@ QVariant HeightfieldMaterialBrushTool::createEdit(bool alternate) {
|
|||
sphere->setScale(_radius->value());
|
||||
if (alternate) {
|
||||
return QVariant::fromValue(HeightfieldMaterialSpannerEdit(SharedObjectPointer(sphere),
|
||||
SharedObjectPointer(), QColor(0, 0, 0, 0), true));
|
||||
SharedObjectPointer(), QColor(0, 0, 0, 0), true, false, pow(2.0f, _granularity->value())));
|
||||
} else {
|
||||
return QVariant::fromValue(HeightfieldMaterialSpannerEdit(SharedObjectPointer(sphere),
|
||||
_materialControl->getMaterial(), _materialControl->getColor(), true));
|
||||
_materialControl->getMaterial(), _materialControl->getColor(),
|
||||
true, false, pow(2.0f, _granularity->value())));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -974,10 +979,11 @@ QVariant HeightfieldSculptBrushTool::createEdit(bool alternate) {
|
|||
sphere->setScale(_radius->value());
|
||||
if (alternate) {
|
||||
return QVariant::fromValue(HeightfieldMaterialSpannerEdit(SharedObjectPointer(sphere),
|
||||
SharedObjectPointer(), QColor(0, 0, 0, 0)));
|
||||
SharedObjectPointer(), QColor(0, 0, 0, 0), false, false, pow(2.0f, _granularity->value())));
|
||||
} else {
|
||||
return QVariant::fromValue(HeightfieldMaterialSpannerEdit(SharedObjectPointer(sphere),
|
||||
_materialControl->getMaterial(), _materialControl->getColor()));
|
||||
_materialControl->getMaterial(), _materialControl->getColor(),
|
||||
false, false, pow(2.0f, _granularity->value())));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -992,13 +998,14 @@ HeightfieldFillBrushTool::HeightfieldFillBrushTool(MetavoxelEditor* editor) :
|
|||
QVariant HeightfieldFillBrushTool::createEdit(bool alternate) {
|
||||
const int FILL_MODE_INDEX = 0;
|
||||
if (_mode->currentIndex() == FILL_MODE_INDEX) {
|
||||
return QVariant::fromValue(FillHeightfieldHeightEdit(_position, _radius->value()));
|
||||
return QVariant::fromValue(FillHeightfieldHeightEdit(_position, _radius->value(),
|
||||
pow(2.0f, _granularity->value())));
|
||||
}
|
||||
Sphere* sphere = new Sphere();
|
||||
sphere->setTranslation(_position);
|
||||
sphere->setScale(_radius->value());
|
||||
return QVariant::fromValue(HeightfieldMaterialSpannerEdit(SharedObjectPointer(sphere),
|
||||
SharedObjectPointer(), QColor(), false, true));
|
||||
SharedObjectPointer(), QColor(), false, true, pow(2.0f, _granularity->value())));
|
||||
}
|
||||
|
||||
HeightfieldMaterialBoxTool::HeightfieldMaterialBoxTool(MetavoxelEditor* editor) :
|
||||
|
@ -1017,6 +1024,12 @@ HeightfieldMaterialBoxTool::HeightfieldMaterialBoxTool(MetavoxelEditor* editor)
|
|||
_snapToGrid->setChecked(true);
|
||||
|
||||
_materialControl = new MaterialControl(this, form, true);
|
||||
|
||||
form->addRow("Granularity:", _granularity = new QDoubleSpinBox());
|
||||
_granularity->setMinimum(-FLT_MAX);
|
||||
_granularity->setMaximum(FLT_MAX);
|
||||
_granularity->setPrefix("2^");
|
||||
_granularity->setValue(8.0);
|
||||
}
|
||||
|
||||
bool HeightfieldMaterialBoxTool::appliesTo(const AttributePointer& attribute) const {
|
||||
|
@ -1039,7 +1052,7 @@ void HeightfieldMaterialBoxTool::applyValue(const glm::vec3& minimum, const glm:
|
|||
cuboid->setAspectY(vector.y / vector.x);
|
||||
cuboid->setAspectZ(vector.z / vector.x);
|
||||
MetavoxelEditMessage message = { QVariant::fromValue(HeightfieldMaterialSpannerEdit(SharedObjectPointer(cuboid),
|
||||
_materialControl->getMaterial(), _materialControl->getColor())) };
|
||||
_materialControl->getMaterial(), _materialControl->getColor(), false, false, pow(2.0f, _granularity->value()))) };
|
||||
Application::getInstance()->getMetavoxels()->applyEdit(message, true);
|
||||
}
|
||||
|
||||
|
@ -1056,6 +1069,12 @@ HeightfieldMaterialSpannerTool::HeightfieldMaterialSpannerTool(MetavoxelEditor*
|
|||
|
||||
_materialControl = new MaterialControl(this, form, true);
|
||||
|
||||
form->addRow("Granularity:", _granularity = new QDoubleSpinBox());
|
||||
_granularity->setMinimum(-FLT_MAX);
|
||||
_granularity->setMaximum(FLT_MAX);
|
||||
_granularity->setPrefix("2^");
|
||||
_granularity->setValue(8.0);
|
||||
|
||||
QPushButton* place = new QPushButton("Set");
|
||||
layout()->addWidget(place);
|
||||
connect(place, &QPushButton::clicked, this, &HeightfieldMaterialSpannerTool::place);
|
||||
|
@ -1076,7 +1095,7 @@ QColor HeightfieldMaterialSpannerTool::getColor() {
|
|||
void HeightfieldMaterialSpannerTool::applyEdit(const AttributePointer& attribute, const SharedObjectPointer& spanner) {
|
||||
static_cast<Spanner*>(spanner.data())->setWillBeVoxelized(true);
|
||||
MetavoxelEditMessage message = { QVariant::fromValue(HeightfieldMaterialSpannerEdit(spanner,
|
||||
_materialControl->getMaterial(), _materialControl->getColor())) };
|
||||
_materialControl->getMaterial(), _materialControl->getColor(), false, false, pow(2.0f, _granularity->value()))) };
|
||||
Application::getInstance()->getMetavoxels()->applyEdit(message, true);
|
||||
}
|
||||
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
#ifndef hifi_MetavoxelEditor_h
|
||||
#define hifi_MetavoxelEditor_h
|
||||
|
||||
#include <QFormLayout>
|
||||
#include <QList>
|
||||
#include <QWidget>
|
||||
|
||||
|
@ -38,7 +39,7 @@ class MetavoxelEditor : public QWidget {
|
|||
|
||||
public:
|
||||
|
||||
MetavoxelEditor();
|
||||
MetavoxelEditor(QWidget* parent = nullptr);
|
||||
|
||||
QString getSelectedAttribute() const;
|
||||
|
||||
|
@ -326,6 +327,7 @@ protected:
|
|||
|
||||
QFormLayout* _form;
|
||||
QDoubleSpinBox* _radius;
|
||||
QDoubleSpinBox* _granularity;
|
||||
|
||||
glm::vec3 _position;
|
||||
bool _positionValid;
|
||||
|
@ -448,6 +450,7 @@ private:
|
|||
|
||||
QCheckBox* _snapToGrid;
|
||||
MaterialControl* _materialControl;
|
||||
QDoubleSpinBox* _granularity;
|
||||
};
|
||||
|
||||
/// Allows setting heightfield materials by placing a spanner.
|
||||
|
@ -470,6 +473,7 @@ private:
|
|||
|
||||
SharedObjectEditor* _spannerEditor;
|
||||
MaterialControl* _materialControl;
|
||||
QDoubleSpinBox* _granularity;
|
||||
};
|
||||
|
||||
#endif // hifi_MetavoxelEditor_h
|
||||
|
|
|
@ -20,8 +20,8 @@
|
|||
|
||||
const int BYTES_PER_KILOBYTE = 1024;
|
||||
|
||||
MetavoxelNetworkSimulator::MetavoxelNetworkSimulator() :
|
||||
QWidget(DependencyManager::get<GLCanvas>().data(), Qt::Dialog) {
|
||||
MetavoxelNetworkSimulator::MetavoxelNetworkSimulator(QWidget* parent) :
|
||||
QWidget(parent, Qt::Dialog) {
|
||||
|
||||
setWindowTitle("Metavoxel Network Simulator");
|
||||
setAttribute(Qt::WA_DeleteOnClose);
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue